diff --git a/docs/qa/platform-checklist/areas/attachments-storage.json b/docs/qa/platform-checklist/areas/attachments-storage.json index aa4621d589..fd0dc8812b 100644 --- a/docs/qa/platform-checklist/areas/attachments-storage.json +++ b/docs/qa/platform-checklist/areas/attachments-storage.json @@ -24,21 +24,21 @@ }, { "step": 2, - "call": "PUT /api/v1/meta/objects/qa_vault?package=com.objectstack.qa.attachments", + "call": "PUT /api/v1/meta/object/qa_vault?package=com.objectstack.qa.attachments", "body": { "name": "qa_vault", "label": "QA Vault", "sharingModel": "private", "enable": { "files": true }, "fields": { "name": { "type": "text", "label": "Name", "required": true } } }, "expect": "2xx. This is THE object the area was missing: private OWD (owner-only) AND attachments-enabled, so a member who is not the owner genuinely cannot read the parent and the 403 deny side becomes provable.", "source": "`sharingModel` is a TOP-LEVEL object key, enum ['private','public_read','public_read_write','controlled_by_parent'] (packages/spec/src/data/object.zod.ts:1827; ADR-0090 D4 — legacy aliases removed). `enable.files` is the #2727 attachments opt-in, default false (object.zod.ts:281). `?package=` is read as `query.package` and threaded to saveMetaItem as packageId (packages/runtime/src/domains/meta.ts:262,319)" }, { "step": 3, - "call": "PUT /api/v1/meta/objects/qa_shared?package=com.objectstack.qa.attachments", + "call": "PUT /api/v1/meta/object/qa_shared?package=com.objectstack.qa.attachments", "body": { "name": "qa_shared", "label": "QA Shared", "sharingModel": "public_read", "enable": { "files": true }, "fields": { "name": { "type": "text", "label": "Name", "required": true } } }, "expect": "2xx. The entitled-member contrast: every member reads the parent, only the owner writes it — so a 403 here would be a real finding rather than a fixture artifact.", "source": "same citations as step 2" }, { "step": 4, - "call": "PUT /api/v1/meta/objects/qa_nofiles?package=com.objectstack.qa.attachments", + "call": "PUT /api/v1/meta/object/qa_nofiles?package=com.objectstack.qa.attachments", "body": { "name": "qa_nofiles", "label": "QA No Files", "sharingModel": "public_read", "fields": { "name": { "type": "text", "label": "Name", "required": true } } }, "expect": "2xx. `enable.files` is OMITTED deliberately (it defaults to false) — this is the FILES_DISABLED probe target, purpose-built rather than borrowed from showcase_account, so the negative keeps holding if showcase ever enables files on its own objects.", "source": "packages/spec/src/data/object.zod.ts:281 — enable.files defaults to false; 'Opt-in: true surfaces the panel and permits attachments to target this object; otherwise any write that makes an attachment target it is rejected (403 FILES_DISABLED) — a create and an update that re-points an existing attachment alike' (re-quoted post-#10733; the prior citation ended at 'creation is rejected', which #10170 made stale — see attach-requires-parent-edit clause 5)" @@ -81,7 +81,7 @@ }, { "step": 2, - "call": "PUT /api/v1/meta/objects/qa_media?package=com.objectstack.qa.media", + "call": "PUT /api/v1/meta/object/qa_media?package=com.objectstack.qa.media", "body": { "name": "qa_media", "label": "QA Media", "sharingModel": "public_read_write", "fields": { "name": { "type": "text", "label": "Name", "required": true }, "poster": { "type": "image", "label": "Poster", "accept": ["image/png", "image/jpeg"], "maxSize": 1048576 }, "doc": { "type": "file", "label": "Doc", "accept": [".pdf"] } } }, "expect": "2xx. `poster` is the MIME-entry + maxSize probe; `doc` (accept = ['.pdf'] ONLY, no maxSize) is the extension-entry probe whose dotless-filename hole is a documented boundary of the enforcement. `enable.files` is deliberately ABSENT: field-owned files ride file-reference-lifecycle.ts (activeFileFields keys on file-class field types), not the #2727 sys_attachment opt-in gate, so the object needs no attachments enablement.", "source": "accept/maxSize are declared FieldSchema keys since ADR-0104 D3 wave 2 (packages/spec/src/data/field.zod.ts:876-883 — 'Offered to the file picker AND enforced on write'); authoring-call shape identical to qa-scratch-authz step 2 (meta.ts:262,319 for ?package=); file-class field set is FILE_REFERENCE_TYPES = image/file/avatar/video/audio (packages/spec/src/data/field-value.zod.ts:146-148)" diff --git a/packages/client/src/client.hono.test.ts b/packages/client/src/client.hono.test.ts index f85abf7f89..5731a3e54e 100644 --- a/packages/client/src/client.hono.test.ts +++ b/packages/client/src/client.hono.test.ts @@ -167,7 +167,7 @@ describe('ObjectStackClient (with Hono Server)', () => { expect(endpoints?.metadata).toContain('/api/v1/meta'); // Enforced, not just declared — the pairing #4018 exists to hold. - expect((await fetch(`${baseUrl}/api/v1/meta/objects`)).status).not.toBe(404); + expect((await fetch(`${baseUrl}/api/v1/meta/object`)).status).not.toBe(404); }); it('should create and retrieve data via hono', async () => { diff --git a/packages/spec/liveness/object.json b/packages/spec/liveness/object.json index 6dab1226a0..fcb7feceb3 100644 --- a/packages/spec/liveness/object.json +++ b/packages/spec/liveness/object.json @@ -101,7 +101,7 @@ "status": "live", "verifiedAt": "2026-08-28", "evidence": "packages/runtime/src/app-plugin.ts#collectBundleActions (walks `bundle.objects[*].actions` and `bundle.manifest.objects[*].actions`, stamping each entry with its parent object name — the list the action body-runner binding and the /meta surface are both built from)", - "note": "served on /meta/objects/:name. 2026-08-28: RE-ANCHORED (#13003) and REPOINTED — the citation was `app-plugin.ts:929`, in range of this 1840-line file but landing in the JOB scheduling block (`svc.schedule(...)`), which reads nothing of this key. The file mentions `actions` on plenty of lines, so the #11457 key-mention check anchors and passes; only a hand read separates the per-object action walk from the unrelated `bundle.actions` and job paths. Re-closed by hand against c459da6bc." + "note": "served on /meta/object/:name. 2026-08-28: RE-ANCHORED (#13003) and REPOINTED — the citation was `app-plugin.ts:929`, in range of this 1840-line file but landing in the JOB scheduling block (`svc.schedule(...)`), which reads nothing of this key. The file mentions `actions` on plenty of lines, so the #11457 key-mention check anchors and passes; only a hand read separates the per-object action walk from the unrelated `bundle.actions` and job paths. Re-closed by hand against c459da6bc." }, "managedBy": { "status": "live", diff --git a/packages/spec/src/api/http-cache.zod.ts b/packages/spec/src/api/http-cache.zod.ts index 0afef1c93a..eff738b9df 100644 --- a/packages/spec/src/api/http-cache.zod.ts +++ b/packages/spec/src/api/http-cache.zod.ts @@ -105,7 +105,7 @@ export type ETagParsed = z.infer; * Request with cache validation headers * * @example - * // GET /api/v1/metadata/objects/account + * // GET /api/v1/metadata/object/account * // Headers: * // If-None-Match: "686897696a7c876b7e" * // If-Modified-Since: Wed, 21 Oct 2015 07:28:00 GMT