Skip to content

Complete ObjectStack Protocol implementation in MSW plugin#414

Merged
hotlong merged 3 commits intomainfrom
copilot/develop-object-stack-protocol
Jan 31, 2026
Merged

Complete ObjectStack Protocol implementation in MSW plugin#414
hotlong merged 3 commits intomainfrom
copilot/develop-object-stack-protocol

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Jan 31, 2026

MSW plugin had 10/20 protocol methods implemented. Hono plugin was already complete.

Changes

MSW Plugin (@objectstack/plugin-msw)

Added 10 missing protocol handlers:

  • Batch operations (4): batchData, createManyData, updateManyData, deleteManyData
  • Cached metadata (1): getMetaItemCached with ETag/Last-Modified/Cache-Control support
  • View storage (5): createView, getView, listViews, updateView, deleteView

Type safety improvements:

  • Added parseInt() validation to prevent NaN in pagination parameters
  • Proper type assertions for request body parsing

Example

// Batch create with error handling
http.post(`${baseUrl}/data/:object/createMany`, async ({ params, request }) => {
  const body = await request.json();
  const records = Array.isArray(body) ? body : [];
  const result = await protocol.createManyData({ object: params.object as string, records });
  return HttpResponse.json(result, { status: 201 });
});

// Metadata with HTTP cache validation
http.get(`${baseUrl}/meta/:type/:name`, async ({ params, request }) => {
  const cacheRequest = {
    ifNoneMatch: request.headers.get('if-none-match') || undefined,
    ifModifiedSince: request.headers.get('if-modified-since') || undefined,
  };
  const result = await protocol.getMetaItemCached({ type, name, cacheRequest });
  return result.notModified ? new HttpResponse(null, { status: 304 }) : HttpResponse.json(result.data);
});

Both plugins now provide full protocol coverage for testing and production use.

Original prompt

继续开发 hono, msw,完善ObjectStackProtocol协议要求的所有api


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

@vercel
Copy link
Copy Markdown

vercel bot commented Jan 31, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
spec Canceled Canceled Jan 31, 2026 1:21am

Request Review

Copilot AI and others added 2 commits January 31, 2026 01:13
Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
Copilot AI changed the title [WIP] Continue development of ObjectStackProtocol APIs in hono and msw Complete ObjectStack Protocol implementation in MSW plugin Jan 31, 2026
Copilot AI requested a review from hotlong January 31, 2026 01:20
@hotlong hotlong marked this pull request as ready for review January 31, 2026 01:24
Copilot AI review requested due to automatic review settings January 31, 2026 01:24
@hotlong hotlong merged commit 2b5a1f9 into main Jan 31, 2026
5 checks passed
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Completes protocol coverage in the MSW plugin by adding the remaining ObjectStackProtocol handlers so the MSW and Hono plugins expose the same API surface for testing/usage.

Changes:

  • Added missing batch/bulk data endpoints (batchData, createManyData, updateManyData, deleteManyData).
  • Added cached metadata endpoint behavior via getMetaItemCached (ETag/Last-Modified/Cache-Control).
  • Added view storage CRUD endpoints (createView, getView, listViews, updateView, deleteView) and basic query parsing for pagination.

Comment on lines +419 to +420
// Enhanced Metadata with Cache Support
http.get(`${baseUrl}/meta/:type/:name`, async ({ params, request }) => {
Copy link

Copilot AI Jan 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are now two handlers registered for the exact same route (GET ${baseUrl}/meta/:type/:name). MSW matches handlers in order, so the earlier non-cached handler will intercept requests and this new cache-aware handler will never run. Please remove/replace the earlier getMetaItem handler (around lines 279–288) and keep a single implementation that supports cache validation.

Suggested change
// Enhanced Metadata with Cache Support
http.get(`${baseUrl}/meta/:type/:name`, async ({ params, request }) => {
// Enhanced Metadata with Cache Support (separate endpoint to avoid route conflicts)
http.get(`${baseUrl}/meta-cached/:type/:name`, async ({ params, request }) => {

Copilot uses AI. Check for mistakes.
Comment on lines +447 to +449
const directives = result.cacheControl.directives.join(', ');
const maxAge = result.cacheControl.maxAge ? `, max-age=${result.cacheControl.maxAge}` : '';
headers['Cache-Control'] = directives + maxAge;
Copy link

Copilot AI Jan 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cache-Control header formatting is incorrect when directives includes 'max-age' and maxAge is also provided. With the current logic this can emit public, max-age, max-age=3600 (duplicated/invalid). Consider rendering directives that take values (max-age, stale-while-revalidate, stale-if-error) as name=value and omitting the bare token when the numeric value is present.

Suggested change
const directives = result.cacheControl.directives.join(', ');
const maxAge = result.cacheControl.maxAge ? `, max-age=${result.cacheControl.maxAge}` : '';
headers['Cache-Control'] = directives + maxAge;
const allDirectives = result.cacheControl.directives || [];
const hasMaxAge = result.cacheControl.maxAge !== undefined && result.cacheControl.maxAge !== null;
const normalizedDirectives = allDirectives.filter(
(directive) => !(directive === 'max-age' && hasMaxAge)
);
if (hasMaxAge) {
normalizedDirectives.push(`max-age=${result.cacheControl.maxAge}`);
}
headers['Cache-Control'] = normalizedDirectives.join(', ');

Copilot uses AI. Check for mistakes.
Comment on lines +377 to +411
http.post(`${baseUrl}/data/:object/createMany`, async ({ params, request }) => {
try {
const body = await request.json();
const records = Array.isArray(body) ? body : [];
const result = await protocol.createManyData({ object: params.object as string, records });
return HttpResponse.json(result, { status: 201 });
} catch (error) {
const message = error instanceof Error ? error.message : 'Unknown error';
return HttpResponse.json({ error: message }, { status: 400 });
}
}),

http.post(`${baseUrl}/data/:object/updateMany`, async ({ params, request }) => {
try {
const body = await request.json() as any;
const result = await protocol.updateManyData({
object: params.object as string,
records: body?.records || [],
options: body?.options
});
return HttpResponse.json(result);
} catch (error) {
const message = error instanceof Error ? error.message : 'Unknown error';
return HttpResponse.json({ error: message }, { status: 400 });
}
}),

http.post(`${baseUrl}/data/:object/deleteMany`, async ({ params, request }) => {
try {
const body = await request.json() as any;
const result = await protocol.deleteManyData({
object: params.object as string,
ids: body?.ids || [],
options: body?.options
});
Copy link

Copilot AI Jan 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These bulk endpoints silently coerce invalid request bodies into empty operations (e.g., non-array body becomes records = [], missing ids/records becomes []). That can mask client/test bugs and diverges from the protocol schemas which require records/ids. Please validate the body shape and return a 400 when it doesn't match (array for createMany, object containing records/ids arrays for updateMany/deleteMany).

Copilot uses AI. Check for mistakes.
Comment on lines +433 to +435
if (result.notModified) {
return new HttpResponse(null, { status: 304 });
}
Copy link

Copilot AI Jan 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When returning 304 (not modified), the response drops cache validators (e.g., ETag, Last-Modified) even though getMetaItemCached returns them. For standards-compliant caching and intermediary caches, include the relevant headers on the 304 response as well.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants