diff --git a/.changeset/client-provenance-anchors.md b/.changeset/client-provenance-anchors.md new file mode 100644 index 00000000000..8c594e58321 --- /dev/null +++ b/.changeset/client-provenance-anchors.md @@ -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. diff --git a/packages/client/src/client.data-prefix.test.ts b/packages/client/src/client.data-prefix.test.ts index c8a4755c1b2..0dea38ea507 100644 --- a/packages/client/src/client.data-prefix.test.ts +++ b/packages/client/src/client.data-prefix.test.ts @@ -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 diff --git a/packages/client/src/client.metadata-prefix.test.ts b/packages/client/src/client.metadata-prefix.test.ts index 98b7e18da34..ae447d9a227 100644 --- a/packages/client/src/client.metadata-prefix.test.ts +++ b/packages/client/src/client.metadata-prefix.test.ts @@ -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 diff --git a/packages/client/src/client.test.ts b/packages/client/src/client.test.ts index 7e0abd0c230..4dfc73bd8c3 100644 --- a/packages/client/src/client.test.ts +++ b/packages/client/src/client.test.ts @@ -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. @@ -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 @@ -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 @@ -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. @@ -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 @@ -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. @@ -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' }, }; @@ -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`. diff --git a/packages/client/src/index.ts b/packages/client/src/index.ts index d8c27571bae..19305adddbf 100644 --- a/packages/client/src/index.ts +++ b/packages/client/src/index.ts @@ -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 @@ -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`. @@ -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 @@ -796,7 +796,7 @@ function metaSaveHeaders(options?: SaveMetaItemOptions): Record /** * 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 @@ -817,7 +817,7 @@ function metaSaveHeaders(options?: SaveMetaItemOptions): Record * 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. * @@ -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. */ @@ -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 @@ -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 @@ -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 => { @@ -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 @@ -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 @@ -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 @@ -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`, with its + * family commit b1b978c8d left at `Promise`, with its * `exported-any-returns.json` entry still open. * * The maintainer's ruling of 2026-08-12 on #7735 keeps better-auth's @@ -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); @@ -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 @@ -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 @@ -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 diff --git a/packages/client/src/meta-automation-descriptors.test.ts b/packages/client/src/meta-automation-descriptors.test.ts index 64a5459495e..7dfce63e7d8 100644 --- a/packages/client/src/meta-automation-descriptors.test.ts +++ b/packages/client/src/meta-automation-descriptors.test.ts @@ -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. @@ -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'); diff --git a/packages/client/src/meta-delete-item-carriers.test.ts b/packages/client/src/meta-delete-item-carriers.test.ts index ad222aa4c63..7950f3f1d6d 100644 --- a/packages/client/src/meta-delete-item-carriers.test.ts +++ b/packages/client/src/meta-delete-item-carriers.test.ts @@ -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 @@ -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 diff --git a/packages/client/src/return-type-precision.test.ts b/packages/client/src/return-type-precision.test.ts index bc04ff849bc..a7eec8aef45 100644 --- a/packages/client/src/return-type-precision.test.ts +++ b/packages/client/src/return-type-precision.test.ts @@ -888,7 +888,7 @@ export async function returnTypePrecisionPins12104(): Promise { } /** - * [#14312 — the `oauth.*` family, card 1 of 3 of #12104] The five better-auth + * [commit e944fdb24 — the `oauth.*` family, card 1 of 3 of #12104] The five better-auth * -backed methods #12104 deliberately left alone. FOUR are bound here. The * fifth — `oauth.applications.delete` — was left at `Promise< any >` by this * card on purpose and was bound afterwards by #15451; its pins live in @@ -970,7 +970,7 @@ export async function returnTypePrecisionPins14312(): Promise { // ── the method this card deliberately left open ────────────────────── // `delete` used to be pinned here as `toEqualTypeOf< any >`, with the note - // that the line would have to be replaced when #14312's open decision + // that the line would have to be replaced when commit e944fdb24's open decision // landed. It landed as #15451, and the replacement is a whole function of // its own rather than a rewritten line, because binding this method was // not a narrowing — see `returnTypePrecisionPins15451`. @@ -978,7 +978,7 @@ export async function returnTypePrecisionPins14312(): Promise { /** * [#15451] `oauth.applications.delete` — the fifth member of the `oauth.*` - * family, and the one #14312 could not reach. + * family, and the one commit e944fdb24 could not reach. * * ## This is NOT the narrowing its four siblings were * @@ -1028,7 +1028,7 @@ export async function returnTypePrecisionPins15451(): Promise { /** - * [#14313 — the `auth.*` family, card 2 of 3 of #12104] The fourteen + * [commit b1b978c8d — the `auth.*` family, card 2 of 3 of #12104] The fourteen * better-auth-backed methods #12104 censused under `auth.*`. THIRTEEN are * bound here; the fourteenth is named below and is still `Promise< any >` * on purpose. @@ -1127,7 +1127,7 @@ export async function returnTypePrecisionPins14313(): Promise { // ── the method deliberately left open ──────────────────────────────── // `deleteUser` still resolves to `any`, so `.anythingAtAll` compiles. - // Pinned as an EQUALITY rather than a suppression, exactly as #14312 did + // Pinned as an EQUALITY rather than a suppression, exactly as commit e944fdb24 did // for `oauth.applications.delete`: when the ruling that keeps the route // off is revisited, this line is the one that must be replaced. expectTypeOf(await client.auth.deleteUser({ password: 'p' })).toEqualTypeOf(); @@ -1135,7 +1135,7 @@ export async function returnTypePrecisionPins14313(): Promise { /** - * [#14314 — the `organizations.*` family, card 3 of 3 of #12104] The twenty + * [commit 7092d63e4 — the `organizations.*` family, card 3 of 3 of #12104] The twenty * ledger entries of the family: NINETEEN unannotated `return res.json()` * members (organizations 11 · invitations 3 · teams 5) bound here, plus * `invitations.resend`, which carries no annotation of its own and inherits @@ -1391,7 +1391,7 @@ export async function returnTypePrecisionPins13023(): Promise { * close. * * 2. THE GAP THIS BLOCK USED TO PIN AS UNDECLARED IS NOW CLOSED, on the spec - * side, which is the only side allowed to close it: #13208 (issue #13155) + * side, which is the only side allowed to close it: commit 74049254d (issue #13155) * widened `DeleteMetaItemResponseSchema` to declare `seq` and * `projectionApplied` — the two wire-receipt keys `deleteMetaItem`'s * repository-delete branch always sent. This file's two `@ts-expect-error` @@ -1412,7 +1412,7 @@ export function deleteDataResponseIsNotTheMetaResetShape(): void { } export function metaResetResponseDeclaresTheWireReceipt(): void { - // #13208 declared both wire-receipt keys on the schema; these positive + // Commit 74049254d declared both wire-receipt keys on the schema; these positive // reads red as TS2339 if either is ever dropped from the bound type. void metaResetBody.seq; void metaResetBody.projectionApplied;