From 72c307a0ea8ce1ee7d91a7d2e24867b068b5558b Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 12 Sep 2026 02:00:41 +0000 Subject: [PATCH 1/2] docs(client): say where a plain `name` IS honoured when registering an OAuth client MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `oauth.applications.register` posts the vendor route `/oauth2/create-client`, which strips a body member spelled `name` and requires `redirect_uris` already split. The one door that honours the plain spelling — `POST /api/v1/auth/sys-oauth-application/register`, the Console's session-required wrapper — is `disposition: server-only` in the auth route ledger and stays that way: no SDK method builds it. Prose only. The JSDoc on the method and the `create_oauth_application` example in the objectui actions page each state that asymmetry where their own reader meets it. No SDK method is added, no request or response type moves, and the ledger row is untouched. Claude-Session: https://claude.ai/code/session_01TSf4DV7ziu4V5j73e46b7c Co-authored-by: Claude --- content/docs/protocol/objectui/actions.mdx | 6 +++++ packages/client/src/index.ts | 27 ++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/content/docs/protocol/objectui/actions.mdx b/content/docs/protocol/objectui/actions.mdx index 0e44483483..77c2a7e242 100644 --- a/content/docs/protocol/objectui/actions.mdx +++ b/content/docs/protocol/objectui/actions.mdx @@ -435,6 +435,12 @@ resultDialog: Each `fields[].path` is a dot path into `result.data`. The per-field `format` (`qrcode`, `code-list`, `secret`, `text`, `json`) controls rendering. +#### ⚠️ That `target` is not interchangeable with the SDK's registration door + +`POST /api/v1/auth/sys-oauth-application/register` is an **ObjectStack mount written for this form**, and it is what keeps the YAML above this short. It accepts the application's display name as a plain `name` body key — the spelling an author writes as a param — and it splits a newline-separated redirect-URL **textarea** into the `redirect_uris` array the underlying provider schema requires. Both are form-shaped conveniences the mount performs on the action's behalf; the route ledger carries it as `disposition: server-only` (`packages/plugins/plugin-auth/src/auth-route-ledger.ts`) for exactly that reason, and [#17210](https://github.com/objectstack-ai/objectstack/issues/17210) ruled that it stays that way — no SDK method builds this URL. + +So do **not** re-point this `target` at the provider's own registration route, `/api/v1/auth/oauth2/create-client` (what `@objectstack/client`'s `oauth.applications.register` posts). Driven on a real socket, the two doors answer the same body differently: the mount above returned **200**, mapped `name` onto `client_name`, and set the `sys_oauth_application` row's `name`; the provider route returned **201** with the value **stripped** — absent from the response, from `oauth.applications.get`, from `oauth.applications.list`, and `null` in that column. An action retargeted there needs its name param renamed to `client_name`, and its redirect URLs split into an array before the post — the textarea param would arrive as one unsplit string. + ## Action Parameters `params` declares inputs collected from the user before execution. Each entry is an `ActionParam` with two modes: diff --git a/packages/client/src/index.ts b/packages/client/src/index.ts index fa47e56119..4a2030cf86 100644 --- a/packages/client/src/index.ts +++ b/packages/client/src/index.ts @@ -4038,6 +4038,33 @@ export class ObjectStackClient { * router skips SERVER_ONLY endpoints, so over HTTP it answers 404 with a * zero-byte body. * + * ## ⚠️ A plain `name` IS honoured somewhere — not here (#17210) + * + * There is exactly one door that reads a body member spelled `name`, and + * this method does not build it: + * `POST /api/v1/auth/sys-oauth-application/register`, the ObjectStack + * mount behind the Console's *Setup → OAuth Applications* create form. + * The same #15447 round drove both doors on one real socket: that mount + * answered **200** to a body spelled `name`, mapped it onto + * `client_name`, and the `sys_oauth_application` row's `name` column was + * set; this method's route, `/oauth2/create-client`, answered **201** + * with the value **stripped** — absent from the response, absent from + * `applications.get`, absent from `applications.list`, and `null` in + * that same column. + * + * ⛔ That mount is **not** an SDK door, and it is not withheld by + * oversight: it is `disposition: 'server-only'` in the auth route ledger + * (`packages/plugins/plugin-auth/src/auth-route-ledger.ts`), a + * session-required self-service wrapper written to serve the Console's + * form — and #17210 ruled that it **stays** `server-only`, so no SDK + * method builds its URL. To name a client from here, post `client_name`. + * + * The wrapper's other Console-shaped convenience is the same asymmetry's + * second half: it splits that form's newline-separated redirect-URL + * **textarea** into the array the vendor schema requires. ⛔ This route + * performs no such split — `redirect_uris` must arrive **pre-split**, + * one entry per URL, which is what an SDK caller holds anyway. + * * Pinned by `oauth-applications-register-request-members.test.ts`. */ register: async (req: { From ae5f9fe257b8fd70a1d4fdbe83f0d95b5240ab09 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 12 Sep 2026 02:26:04 +0000 Subject: [PATCH 2/2] =?UTF-8?q?chore(changeset):=20patch=20`@objectstack/c?= =?UTF-8?q?lient`=20=E2=80=94=20the=20docblock=20ships=20in=20dist/*.d.ts?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Measured rather than assumed: `@objectstack/client`'s `files[]` is ["dist","README.md","CHANGELOG.md"], and after `pnpm --filter @objectstack/client build` the new docblock prose is present in both dist/index.d.ts and dist/index.d.mts (positive control: the pre-existing "the vendor's RECORD vocabulary" prose, same files, same grep; negative control: an absent marker, 0 hits). Published bytes move, so `patch`, not `skip-changeset`. Claude-Session: https://claude.ai/code/session_01TSf4DV7ziu4V5j73e46b7c Co-authored-by: Claude --- .../17210-oauth-register-name-trap-prose.md | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 .changeset/17210-oauth-register-name-trap-prose.md diff --git a/.changeset/17210-oauth-register-name-trap-prose.md b/.changeset/17210-oauth-register-name-trap-prose.md new file mode 100644 index 0000000000..986ddc0ea5 --- /dev/null +++ b/.changeset/17210-oauth-register-name-trap-prose.md @@ -0,0 +1,28 @@ +--- +'@objectstack/client': patch +--- + +`oauth.applications.register`'s docblock says where a plain `name` IS honoured, and that it is not this route + +A caller who wants to name an OAuth client reaches for `name`. On the route this +method posts — the provider's `/oauth2/create-client` — that member is not in +the body schema and is stripped: driven on a real socket, the call answered +**201** and the value was absent from the response, from `applications.get`, +from `applications.list`, and `null` in the `sys_oauth_application` row's `name` +column. Nothing in the answer says so. + +The spelling is not wrong everywhere, which is what made it worth writing down: +`POST /api/v1/auth/sys-oauth-application/register` — the session-required +ObjectStack mount behind the Console's *Setup → OAuth Applications* form — +answered **200** to the same body, mapped `name` onto `client_name`, and set +that column. That mount is `disposition: 'server-only'` in the auth route ledger +and objectstack#17210 ruled it stays that way, so no SDK method builds its URL. + +The docblock now states both halves where the caller reads them: post +`client_name` to name a client from here, and `redirect_uris` must arrive +pre-split — the newline-separated-textarea split is the Console wrapper's, not +this route's. + +Docblock only. No method is added, no request or response type changes, and the +ledger row is untouched — but the text ships inside `dist/*.d.ts` as editor +hover, so it is a `patch` rather than a no-publish change.