Skip to content
Merged
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
10 changes: 10 additions & 0 deletions .changeset/client-provenance-anchors.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
'@objectstack/client': patch
---

Provenance comments in `@objectstack/client` were re-anchored

Comment and docblock lines under `src/` that cited tracker numbers which no
longer resolve on GitHub now cite the commit in this repository's history that
decided the matter, and say in their own words what was decided. Comments
only: no request, route, error code, type, export or runtime behaviour changes.
2 changes: 1 addition & 1 deletion packages/client/src/client.data-prefix.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.

/**
* `crud.dataPrefix` is honoured by the SDK, not restated by it (#14879).
* `crud.dataPrefix` is honoured by the SDK, not restated by it (commit cf74a1128).
*
* THE CONTRACT. `crud.dataPrefix` is a live `RestServerConfig` key: REST mounts
* every CRUD route under `dataPath = ${basePath}${crud.dataPrefix}` and the
Expand Down
2 changes: 1 addition & 1 deletion packages/client/src/client.metadata-prefix.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* `metadata.prefix` is honoured by the SDK, not restated by it (#16675).
*
* THE CONTRACT. `metadata.prefix` is a live `RestServerConfig` key, the exact
* sibling of the `crud.dataPrefix` #14879 fixed: REST mounts every metadata
* sibling of the `crud.dataPrefix` defect commit cf74a1128 fixed: REST mounts every metadata
* route under `metaPath = ${basePath}${metadata.prefix}` and the discovery
* handler advertises the same value as
* `routes.metadata = ${realBase}${metadata.prefix}`. Three surfaces describe
Expand Down
20 changes: 10 additions & 10 deletions packages/client/src/client.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ function createMockClient(body: any, status = 200) {
return { client, fetchMock };
}

// [#9934] The producer-marked user-facing refusal text (`userMessage`) — the
// [commit 79c46da90] The producer-marked user-facing refusal text (`userMessage`) — the
// SDK surfaces it from BOTH live envelopes' declared spots, the same
// two-dialect rule as `code`/`fields`, so the console can render a marked hook
// refusal and keep its generic #3821 substitution for everything unmarked.
Expand Down Expand Up @@ -354,10 +354,10 @@ describe('ObjectStackClient', () => {
// card. It used to require the slash to survive UNENCODED, so the
// request would reach the compound handler
// `/meta/:type/:section/:name` instead of collapsing onto the
// two-segment route. #12176 retired compound-name addressing: that
// two-segment route. Commit 7986d973f retired compound-name addressing: that
// handler is gone, so `%2F` is now the correct and only spelling.
//
// Encoding is a no-op for every name #12194's grammar admits (snake
// Encoding is a no-op for every name commit 311433f6b's grammar admits (snake
// case, optionally dot-qualified), so this changes nothing a legal
// caller sends. What it changes is a pre-grammar residue name: it now
// reaches the surviving door with its slash intact as `%2F`, which Hono
Expand Down Expand Up @@ -509,7 +509,7 @@ describe('Security explain & global search (#3587 gap closure)', () => {
});

it('security.explain accepts the recordIds batch spelling and forwards it verbatim (#8480)', async () => {
// [#8480] Typed-client completion of #8326's batch spelling. The
// [commit caaae2cca] Typed-client completion of #8326's batch spelling. The
// client does NOT validate the cap or the recordId/recordIds
// mutual exclusion — that stays the server's job
// (`ExplainRequestSchema`); this pins that the body goes over the
Expand Down Expand Up @@ -875,7 +875,7 @@ describe('Notifications namespace', () => {
});

it('[#6361] never puts a `cursor` on the query string — the SDK producer is gone', async () => {
// The retired half of #6361 asserted where it was PRODUCED. `cursor` was
// The retired half of commit 90bbf2510 asserted where it was PRODUCED. `cursor` was
// never a server-read filter; what made it harmful rather than inert is
// that this method appended it, so a caller paginating by the published
// contract re-read the first window forever with no error.
Expand Down Expand Up @@ -1387,7 +1387,7 @@ describe('ObjectStackClient.automation', () => {
// TS2353 excess-property error, which a runtime assertion cannot reach.
// This pins the RUNTIME half, which tsc cannot: an untyped caller
// (plain JS, a `Record` spread, a hand-built options object) must not
// smuggle the parameter through. The same shape #6361 left behind one
// smuggle the parameter through. The same shape commit 90bbf2510 left behind one
// door over.
//
// All THREE surfaces are swept, because all three appended it and a
Expand Down Expand Up @@ -2162,7 +2162,7 @@ describe('ScopedEnvironmentClient', () => {

it('[#14879] a custom dataPrefix no longer makes the base underivable — `routes.metadata` is the second equation (case B1)', async () => {
const { client, fetchMock } = createMockClient({ types: [] });
// WAS pinned the other way. Until #14879 this case asserted the
// WAS pinned the other way. Until commit cf74a1128 this case asserted the
// convention `/api/v1/...`, because the only suffix `_apiBase()` knew
// how to strip was the literal `/data`, so a custom `crud.dataPrefix`
// made the base undetectable and the client fell back.
Expand Down Expand Up @@ -2194,8 +2194,8 @@ describe('ScopedEnvironmentClient', () => {
// with the conventional `/data` AND there is no `routes.metadata` to
// supply the missing equation, so `{realBase}{dataPrefix}` stays one
// string with two unknowns. The client must NOT guess a split — it
// falls back to the convention, byte-identical to the pre-#14879
// behavior.
// falls back to the convention, byte-identical to the behavior before
// commit cf74a1128.
(client as any)['discoveryInfo'] = {
routes: { data: '/backend/api/v9/records' },
};
Expand Down Expand Up @@ -2866,7 +2866,7 @@ describe('[#11391] meta.saveItem query string (unscoped client)', () => {
it('[#12195] a slash-bearing name is ENCODED and still gets the query string', async () => {
const { client, fetchMock } = createMockClient({ success: true });
await client.meta.saveItem('object', 'views/all_leads', { label: 'All leads' }, { force: true });
// Inverted by #12195: the slash used to be required to survive raw so
// Inverted by commit 7986d973f: the slash used to be required to survive raw so
// the request reached `PUT /meta/:type/:section/:name`, which had read
// `?force` since #11095. That door is retired; `%2F` reaches the
// surviving door, which has always read `?force`.
Expand Down
38 changes: 19 additions & 19 deletions packages/client/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -681,7 +681,7 @@ export interface SaveMetaItemOptions {
* empty spelling would pin the write against the empty string and refuse
* every save with a 409 the caller never asked for.
*
* [#12195] There is ONE door now. The compound-name twin
* [commit 7986d973f] There is ONE door now. The compound-name twin
* `PUT /meta/:type/:section/:name` — which this note used to pair with —
* is retired, and every name reaches `PUT /meta/:type/:name`
* percent-encoded, so `if-match` behaviour no longer varies by how the
Expand Down Expand Up @@ -725,7 +725,7 @@ export interface SaveMetaItemOptions {
* on the wire that the server ignores. Same shape the first-party
* `@object-ui/data-objectstack` `MetadataClient.save` already uses.
*
* [#12195] REACHES EVERY SAVE — the carve-out this note used to carry is
* [commit 7986d973f] REACHES EVERY SAVE — the carve-out this note used to carry is
* GONE, and it is worth recording why rather than deleting it silently.
*
* `mode` used to reach only the single-segment `PUT /meta/:type/:name`.
Expand All @@ -735,7 +735,7 @@ export interface SaveMetaItemOptions {
* answered 200, with no signal at the call site (objectstack#11712).
*
* Two changes closed it at the source rather than from this side. Stage 1
* (#12194) made a slash-bearing name unwritable at all, and this stage
* (commit 311433f6b) made a slash-bearing name unwritable at all, and this stage
* retired the twin and unified this file on `encodeURIComponent`, so every
* save now arrives at the one door that reads `mode`. A name that would
* once have forked to the silent-publish door is now refused `400
Expand Down Expand Up @@ -796,7 +796,7 @@ function metaSaveHeaders(options?: SaveMetaItemOptions): Record<string, string>

/**
* Request options for `meta.deleteItem` — the carriers the REST reset door
* reads, made reachable from the SDK (#12181).
* reads, made reachable from the SDK (commit cf71d73f8).
*
* `DELETE /meta/:type/:name` ("reset metadata item to artifact default")
* reads THREE carriers. This bag declares TWO of them, and the third's
Expand All @@ -817,7 +817,7 @@ function metaSaveHeaders(options?: SaveMetaItemOptions): Record<string, string>
* ADDS destructive reach — it drops the object's physical table after the
* metadata row goes — no caller was measured needing it from this client,
* and the door's repeated-parameter refusal exists because of that
* destructiveness. Maintainer-seat ruling on #12181: a destructive surface
* destructiveness. Maintainer-seat ruling, landed by commit cf71d73f8: a destructive surface
* with no measured pull is not published. A caller that needs it is a
* separate, separately reviewable widening.
*
Expand Down Expand Up @@ -908,7 +908,7 @@ function metaDeleteQuery(options?: DeleteMetaItemOptions): string {
*
* Deliberately a sibling of {@link metaSaveHeaders} rather than a call into
* it: the two methods carry two separately-ruled option bags (#11713 for
* `saveItem`, #12181 for this one), so neither type may quietly acquire the
* `saveItem`, commit cf71d73f8 for this one), so neither type may quietly acquire the
* other's members. The two builders are pinned IN STEP by a test instead —
* one token in, identical header bytes out.
*/
Expand Down Expand Up @@ -1831,11 +1831,11 @@ export class ObjectStackClient {
// omits the `headers` key altogether, so a save without `ifMatch`
// hands `fetch` the same `init` it always did.
const headers = metaSaveHeaders(options);
// [#12195] ENCODED, like every other `/meta` item address in this file.
// [commit 7986d973f] ENCODED, like every other `/meta` item address in this file.
// This site used to leave `type`/`name` RAW so a compound name's slash
// would survive into a separate path segment and reach
// `PUT /meta/:type/:section/:name`. That door is retired, and encoding
// is now the single spelling: a legal name (#12194's grammar — snake
// is now the single spelling: a legal name (commit 311433f6b's grammar — snake
// case, optionally dot-qualified) contains nothing `encodeURIComponent`
// alters, so this is byte-identical for every name that can be written,
// and a pre-grammar residue name reaches the single-segment door with
Expand Down Expand Up @@ -1863,7 +1863,7 @@ export class ObjectStackClient {
* resolved as `options.ifMatch` and the same situation answers `409
* metadata_conflict` instead — the door has always read the header
* (`DeleteMetaItemRequest.parentVersion` describes it), this client just
* had no argument for it until #12181.
* had no argument for it until commit cf71d73f8.
*
* [#13023] READ `reset`, NEVER `deleted`. This method used to declare
* `{ type, name, deleted }` — an UNINHABITED shape: the door answers
Expand Down Expand Up @@ -2018,12 +2018,12 @@ export class ObjectStackClient {
/**
* ADR-0033: the published version of a metadata item.
*
* [#12195] The name is percent-encoded, like every other `/meta` item
* [commit 7986d973f] The name is percent-encoded, like every other `/meta` item
* address in this file. This docblock used to promise the opposite — that
* a compound name passed through UNENCODED, `getPublished('lead',
* 'views/all_leads')`, so its slash would reach the compound arity
* `GET /meta/:type/:section/:name/published`. That arity is retired and a
* slash-bearing name is refused at the publish door (#12194), so there is
* slash-bearing name is refused at the publish door (commit 311433f6b), so there is
* one spelling and one door.
*/
getPublished: async (type: string, name: string): Promise<GetPublishedMetaItemResponse> => {
Expand Down Expand Up @@ -3476,7 +3476,7 @@ export class ObjectStackClient {

/**
* @internal The CRUD data prefix this client's server actually mounts, read
* off the advertised routes (#14879).
* off the advertised routes (commit cf74a1128).
*
* `crud.dataPrefix` moves the mounted CRUD paths and the advertised
* discovery document TOGETHER — REST builds every data route as
Expand Down Expand Up @@ -3549,7 +3549,7 @@ export class ObjectStackClient {
* @internal The metadata prefix this client's server actually mounts, read
* off the advertised routes (#16675).
*
* The same defect as #14879 one key over, so deliberately the same
* The defect commit cf74a1128 fixed, one key over, so deliberately the same
* derivation shape as {@link ObjectStackClient._dataPrefix}, fallback
* discipline included. `metadata.prefix` moves the mounted metadata paths
* and the advertised discovery document TOGETHER — REST builds every
Expand Down Expand Up @@ -3632,7 +3632,7 @@ export class ObjectStackClient {
* `routes.data`: the REST discovery endpoint advertises it as
* `{realBase}{dataPrefix}` with `dataPrefix` defaulting to `/data`. This
* derivation strips that advertised suffix — `_dataPrefix()` reads which
* suffix it is (#14879), so a deployment that moves `crud.dataPrefix` off
* suffix it is (commit cf74a1128), so a deployment that moves `crud.dataPrefix` off
* the default no longer forces this derivation to decline. When the suffix
* is not derivable either, the caller falls back to the `/api/v1`
* convention — exactly today's behavior, so the change is strictly "follow
Expand Down Expand Up @@ -4908,7 +4908,7 @@ export class ObjectStackClient {
* Server policy decides which is required; pass whichever you have.
*
* ⚠️ NOT BOUND, and deliberately so — the one member of the `auth.*`
* family #14313 left at `Promise<any>`, with its
* family commit b1b978c8d left at `Promise<any>`, with its
* `exported-any-returns.json` entry still open.
*
* The maintainer's ruling of 2026-08-12 on #7735 keeps better-auth's
Expand Down Expand Up @@ -6376,7 +6376,7 @@ export class ObjectStackClient {
* List notifications for the current user.
*
* Returns the newest `limit` notifications — a WINDOW, not a page. The
* `cursor` parameter was removed in protocol 17 (#6361): it was appended to
* `cursor` parameter was removed in protocol 17 (commit 90bbf2510): it was appended to
* the query string here and read by nothing on the server, so a caller
* paginating by it re-read the first window forever. Omit `limit` to take
* the server's window (the platform inbox answers 50, clamped to 1..200);
Expand Down Expand Up @@ -7403,7 +7403,7 @@ export class ObjectStackClient {
// actually carries.
error.details = errorBody?.details ?? errorBody?.error?.details ?? errorBody;
if (fieldErrors) error.fields = fieldErrors;
// [#9934] The producer-marked user-facing refusal text
// [commit 79c46da90] The producer-marked user-facing refusal text
// (`ApiErrorSchema.userMessage`) — read from both live envelopes'
// declared spots, same two-dialect rule as `code`/`fields` above: the
// flat body carries it at the top level, the wrapped one inside
Expand Down Expand Up @@ -7533,7 +7533,7 @@ export class ScopedEnvironmentClient {
}

/**
* URL for a route mounted under the deployment's CRUD data prefix (#14879).
* URL for a route mounted under the deployment's CRUD data prefix (commit cf74a1128).
*
* Every route reached through here is mounted by REST as
* `${dataPath}/...` with `dataPath = ${basePath}${crud.dataPrefix}`, so the
Expand Down Expand Up @@ -8119,7 +8119,7 @@ export type {
GetPresenceResponse,
// Workflow re-exports removed (#4451, v17): the types were deleted from
// @objectstack/spec/api with the retired workflow slot.
// View-management re-exports removed (#6239, v17): the five viewId-addressed
// View-management re-exports removed (commit f549a0d4a, v17): the five viewId-addressed
// methods and their ten schemas were deleted from @objectstack/spec/api with
// the retired `ViewProtocol` — no host implemented them and no route reached
// them. A view's stored definition travels on the metadata types
Expand Down
6 changes: 3 additions & 3 deletions packages/client/src/meta-automation-descriptors.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ function createMockClient(body: any, status = 200) {

describe('client.meta (#3563 PR-5)', () => {
it('[#12195] getPublished ENCODES the name — one spelling, one door', async () => {
// ⚠️ Inverted by #12195. This required the slash to pass through RAW so
// ⚠️ Inverted by commit 7986d973f. This required the slash to pass through RAW so
// the request reached the compound arity
// `GET /meta/:type/:section/:name/published`. #12176 retired
// `GET /meta/:type/:section/:name/published`. Commit 7986d973f retired
// compound-name addressing and that arity is un-mounted, so `%2F` —
// which Hono decodes back to `views/all_leads` on the surviving
// `/:type/:name/published` route — is the correct spelling now.
Expand All @@ -40,7 +40,7 @@ describe('client.meta (#3563 PR-5)', () => {
});

it('[#12195] a LEGAL name reaches getPublished byte-identically', async () => {
// The control: encoding must be a no-op for every name #12194's
// The control: encoding must be a no-op for every name commit 311433f6b's
// grammar admits, so no working caller moved.
const { client, fetchMock } = createMockClient({ success: true, data: {} });
await client.meta.getPublished('lead', 'all_leads');
Expand Down
4 changes: 2 additions & 2 deletions packages/client/src/meta-delete-item-carriers.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.

/**
* [#12181] `meta.deleteItem` sends the carriers the REST reset door reads —
* [commit cf71d73f8] `meta.deleteItem` sends the carriers the REST reset door reads —
* the `If-Match` OCC pin and `?state=draft` — on BOTH declarations.
*
* ## The defect
Expand Down Expand Up @@ -262,7 +262,7 @@ describe('[#12181] the withheld third carrier', () => {
const { client, fetchMock } = createMockClient(RESET_OK);
await client.meta.deleteItem('view', 'shared_grid', {
// `dropStorage` is deliberately NOT a member of
// `DeleteMetaItemOptions` (2026-08-28 ruling on #12181: the one
// `DeleteMetaItemOptions` (2026-08-28 ruling, landed by commit cf71d73f8: the one
// carrier that ADDS destructive reach, with no measured caller).
// This is the type-level half of the withholding; the runtime half
// is below. Adding the member turns the directive on the next line
Expand Down
Loading
Loading