diff --git a/.changeset/30710-meta-list-names-filter.md b/.changeset/30710-meta-list-names-filter.md new file mode 100644 index 00000000000..11e3708926e --- /dev/null +++ b/.changeset/30710-meta-list-names-filter.md @@ -0,0 +1,8 @@ +--- +'@objectstack/skills': patch +--- + +docs(skills): objectstack-api's Metadata API section teaches the `/meta/:type` list door's `?names=a,b,c` filter (one comma-separated value; an unknown name absent, an empty value refused `400`, the `package` list refuses the key) and its closed query set (`package`, `preview`, `object`, `include`, `id`, `names`, `locale`; any other key `400 VALIDATION_ERROR`) + +Clause-②: no +Metadata-protocol: none diff --git a/skills/objectstack-api/SKILL.md b/skills/objectstack-api/SKILL.md index ee551eb0d46..2012bb558ce 100644 --- a/skills/objectstack-api/SKILL.md +++ b/skills/objectstack-api/SKILL.md @@ -25,7 +25,8 @@ metadata: | Need | Use instead | |:-----|:------------| -| Model objects, fields, permissions, or datasources | **objectstack-data** | +| Model objects, fields, permissions, or datasources (`rules/datasources.md`) | **objectstack-data** | +| Pick a driver package | **objectstack-platform** → Driver Selection Guide | | Filter, sort, paginate, or aggregate a request | **objectstack-query** | | Register a kernel service, or read one from a plugin | **objectstack-platform** | | CEL in a route guard or auth predicate | **objectstack-formula** | @@ -50,10 +51,8 @@ POST /api/v1/data/{object}/batch # Per-object batch operations POST /api/v1/batch # Cross-object atomic batch ``` -Data CRUD lives under the `/data` prefix. There is no `/bulk` route and no -`GET .../aggregate` route — batch writes go through the `batch` endpoints, and -aggregation goes through `POST /api/v1/data/{object}/query` with -`groupBy`/`aggregations` in the body. +There is no `/bulk` route and no `GET .../aggregate` route — batch writes go +through the `batch` endpoints, aggregation through the `query` one. > **Key rule:** If your object defines `apiMethods`, only those operations (and > what derives from them) are exposed; `[]` means deny-all. The authorable @@ -69,8 +68,13 @@ GET /api/v1/meta/:type # List metadata items of a type (object, view, GET /api/v1/meta/:type/:name # Read a single metadata item ``` -The read-side query params (`?preview=draft`, `?package=`, `?include=content`) -are **client** contracts — nothing in a stack declares them. +The list reads a closed query set — `package`, `preview` (`draft`), `object`, +`include` (`content`, `grants`), `id`, `names`, `locale` — and refuses any other key with +`400 VALIDATION_ERROR` instead of ignoring it. `?names=a,b,c` (one +comma-separated value) narrows the list to the named items the caller may see: +an unknown name is simply absent, an empty value is refused `400`, and the +`package` list (keyed by id) refuses the key. These are **client** contracts — +nothing in a stack declares them. ### Public (anonymous) Form Endpoints @@ -315,8 +319,8 @@ Realtime contracts are pointer-style — read the spec source for exact shapes: ## Authentication & Authorization -RBAC (`definePermissionSet`) and RLS are objectstack-data's surface, not this -one; this section is the endpoint's own auth keys. +RBAC and RLS are objectstack-data's surface; this section is the endpoint's +own auth keys. ### Auth Configuration @@ -350,15 +354,6 @@ session and token response shapes before wiring an auth flow. --- -## Datasources - -`defineDatasource`, `schemaMode`, the `external` write gate and -`credentialsRef` are objectstack-data → `rules/datasources.md`; driver packages -and the Turso Cloud/EE caveat are objectstack-platform → **Driver Selection -Guide**; the `driver` id vocabulary is `data/driver/config-registry.zod.ts`. - ---- - ## Error Envelopes & the Code Ledger (ADR-0112) `error.code` is **two-tier**: the closed `StandardErrorCode` catalog plus the @@ -414,8 +409,8 @@ keys mean the run produced none — never invent an empty. `CONCURRENT_UPDATE`**; the quoted-empty entity-tag (`""`) is refused **400 `VALIDATION_FAILED`**, not treated as omitted. 2. **Assuming `DELETE` is recoverable.** ObjectStack `DELETE` is a hard - delete — there is no recycle bin (the dead `enable.trash` flag was removed - in 16.x). For recoverability, use per-field `trackHistory` (audit + delete — there is no recycle bin. + For recoverability, use per-field `trackHistory` (audit trail) or a `lifecycle` archive policy instead of custom soft-delete logic. --- diff --git a/skills/objectstack-api/evals/endpoints-auth-routes.json b/skills/objectstack-api/evals/endpoints-auth-routes.json index 9871640ba78..b49417304ed 100644 --- a/skills/objectstack-api/evals/endpoints-auth-routes.json +++ b/skills/objectstack-api/evals/endpoints-auth-routes.json @@ -60,6 +60,16 @@ "must_contain": ["applyOn", "'create'", "sourceField", "targetField"], "must_not_contain": ["writeMode: 'insert'"] } + }, + { + "id": 7, + "prompt": "Our integration boots by reading the `account`, `contact` and `lead` object definitions from the runtime's metadata API. Today it sends three requests; our `?name=account,contact,lead` attempt came back 400. Make it one request.", + "expected_output": "One `GET /api/v1/meta/object?names=account,contact,lead` — the list door's `?names=` filter takes one comma-separated value and answers only the named items the caller may see; a name that matches no item is simply absent (no 404), and an empty value is refused `400`. Does not spell the filter `?name=`, `?ids=` or `?filter=`: the list reads a closed query set (`package`, `preview`, `object`, `include`, `id`, `names`, `locale`) and refuses any other key with `400 VALIDATION_ERROR` instead of ignoring it, so a misspelt filter never silently answers the whole list.", + "files": [], + "assertions": { + "must_contain": ["?names=", "/api/v1/meta/object", "VALIDATION_ERROR"], + "must_not_contain": ["?ids=", "?filter="] + } } ] }