Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .changeset/30710-meta-list-names-filter.md
Original file line number Diff line number Diff line change
@@ -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
35 changes: 15 additions & 20 deletions skills/objectstack-api/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -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** |
Expand All @@ -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
Expand All @@ -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

Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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.

---
Expand Down
10 changes: 10 additions & 0 deletions skills/objectstack-api/evals/endpoints-auth-routes.json
Original file line number Diff line number Diff line change
Expand Up @@ -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="]
}
}
]
}
Loading