@registrystack/client 0.42.0 → 0.44.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,7 +1,12 @@
1
1
  # @registrystack/client
2
2
 
3
3
  One versioned Node.js package for the Discovery, Evidence, Base Registry
4
- Engine, Casework, Messaging, and Scheduling client APIs in Registry Stack.
4
+ Engine, Casework, Messaging, Scheduling, and Coordinator client APIs in Registry Stack.
5
+
6
+ Coordinator joins the client roster at v0.44.0. Its imports below require a
7
+ Coordinator-enabled v0.44.0 candidate or published package; published v0.43.0
8
+ contains the earlier six products. Check the version-specific release assets
9
+ before installing. Source integration does not establish publication.
5
10
 
6
11
  ## Install
7
12
 
@@ -11,13 +16,13 @@ npm install "@registrystack/client@<version>"
11
16
 
12
17
  Requires Node.js 24.11 or newer. Supported targets are macOS arm64, Linux
13
18
  arm64 with glibc, and Linux x64 with glibc; installing the package pulls in
14
- one platform-specific optional dependency containing all six native
19
+ one platform-specific optional dependency containing all seven native
15
20
  bindings.
16
21
 
17
22
  ## Usage
18
23
 
19
24
  ```js
20
- const { discovery, evidence, breg, casework, messaging, scheduling } = require('@registrystack/client');
25
+ const { discovery, evidence, breg, casework, messaging, scheduling, coordinator } = require('@registrystack/client');
21
26
 
22
27
  const registry = new breg.BaseRegistryClient({
23
28
  baseUrl: 'https://registry.example.invalid/',
@@ -31,6 +36,9 @@ const messages = new messaging.MessagingClient({
31
36
  const appointments = new scheduling.SchedulingClient({
32
37
  baseUrl: 'https://scheduling.example.invalid/',
33
38
  });
39
+ const workflows = new coordinator.CoordinatorClient({
40
+ baseUrl: 'https://coordinator.example.invalid/',
41
+ });
34
42
  ```
35
43
 
36
44
  ## Products
@@ -48,9 +56,22 @@ const appointments = new scheduling.SchedulingClient({
48
56
  - `scheduling`: Registry Scheduling, published offerings, availability,
49
57
  holds, and appointments over operator-anchored supply.
50
58
 
59
+ - `coordinator`: Registry Coordinator, workflow contracts, admission, run status,
60
+ inspection, and operator recovery. It is optional for direct product composition.
61
+
51
62
  Each product remains in its own namespace because its routing,
52
63
  authentication, errors, and verification rules are different.
53
64
 
65
+ ## Compatibility metadata
66
+
67
+ The package includes the tested server baseline and compatible patch line for
68
+ the Discovery namespace. Read the version-matched record through the exported
69
+ JSON path:
70
+
71
+ ```js
72
+ const compatibility = require('@registrystack/client/compatibility.json');
73
+ ```
74
+
54
75
  ## TypeScript
55
76
 
56
77
  A TypeScript consumer also needs the Node type definitions, and must name
@@ -90,7 +111,7 @@ for the full rules.
90
111
 
91
112
  A keyed BReg, Casework, Messaging, or Scheduling mutation whose outcome is
92
113
  unknown is resent identically under the same idempotency key up to
93
- `maxMutationRetries` times, a client option: 0 to 2, default 2, and 0 sends it
114
+ `maximumMutationRetries` times, a client option: 0 to 2, default 2, and 0 sends it
94
115
  once. Casework review-request create and cancel are excluded from this retry.
95
116
  Reads, unkeyed calls, and every 4xx refusal are never resent. When the returned error
96
117
  still reports `outcomeUnknown`, the mutation may have taken effect: recover by
@@ -100,12 +121,12 @@ attempt under the key was answered and may have committed: reconcile that
100
121
  attempt before choosing a new key.
101
122
  See [Unknown outcomes](https://docs.registrystack.org/reference/client-api/#unknown-outcomes-and-the-same-key-retry).
102
123
 
103
- `breg.verifyWebhookDelivery({ method, path, headers, body, key })` authenticates
104
- the exact bytes of one Version 1 webhook delivery. The result returns
124
+ `breg.verifyHookDelivery({ method, path, headers, body, key })` authenticates
125
+ the exact bytes of one Version 1 hook delivery. The result returns
105
126
  `deliveryTime` and `idempotencyKey`; the receiver must bound clock skew and
106
127
  deduplicate once-only effects on authenticated `source` plus `id`, or on an
107
128
  application business key. See
108
- [Verify a webhook delivery](https://docs.registrystack.org/reference/client-api/#verify-a-webhook-delivery)
129
+ [Verify a hook delivery](https://docs.registrystack.org/reference/client-api/#verify-a-hook-delivery)
109
130
  for a receiver example.
110
131
 
111
132
  ## Versioning
@@ -163,3 +184,12 @@ without the cursor after `410 review.result-expired`.
163
184
  ## License
164
185
 
165
186
  Apache-2.0
187
+
188
+ Coordinator joins the seven-product roster at v0.44.0. The source facade also
189
+ contains held `render` and `@registrystack/client/render` namespaces. Default
190
+ assembly omits Render; `--include-render` adds it to an explicit local candidate
191
+ and does not authorize publication. Render takes a token or a resource-bound provider with
192
+ `bearerToken()` and performs one bounded render exchange. A correlation key is
193
+ not a durable idempotency promise. `outcomeUnknown` and `transportKind` preserve
194
+ whether an exchange may have completed; provider errors keep their own class.
195
+ Coordinator is optional.
package/breg/client.d.ts CHANGED
@@ -7,7 +7,7 @@ export type JsonObject = { readonly [key: string]: JsonValue }
7
7
  /** An integer that satisfies `Number.isSafeInteger` and the option's documented bounds. */
8
8
  export type SafeInteger = number
9
9
 
10
- export type WebhookVerificationRefusalCode =
10
+ export type HookVerificationRefusalCode =
11
11
  | 'missing-header'
12
12
  | 'invalid-delivery-time'
13
13
  | 'duplicate-header'
@@ -17,7 +17,7 @@ export type WebhookVerificationRefusalCode =
17
17
  | 'signature-mismatch'
18
18
  | 'unsupported-version'
19
19
 
20
- export interface WebhookDeliveryInput {
20
+ export interface HookDeliveryInput {
21
21
  method: string
22
22
  path: string
23
23
  headers: Readonly<Record<string, string>>
@@ -27,7 +27,7 @@ export interface WebhookDeliveryInput {
27
27
  key: Buffer
28
28
  }
29
29
 
30
- export interface VerifiedWebhookDelivery {
30
+ export interface VerifiedHookDelivery {
31
31
  readonly id: string
32
32
  readonly source: string
33
33
  readonly type: string
@@ -41,10 +41,21 @@ export interface VerifiedWebhookDelivery {
41
41
  }
42
42
 
43
43
  /**
44
- * Authenticate one exact Base Registry Engine Version 1 webhook delivery.
44
+ * Authenticate one exact Base Registry Engine Version 1 hook delivery.
45
45
  * Apply delivery-time skew and idempotency policy before acting on the body.
46
46
  */
47
- export declare function verifyWebhookDelivery(input: WebhookDeliveryInput): VerifiedWebhookDelivery
47
+ export declare function verifyHookDelivery(input: HookDeliveryInput): VerifiedHookDelivery
48
+
49
+ /**
50
+ * Project one record revision into the event record view. `argumentsJson` is a
51
+ * JSON object with `registryRevision`, `recordType`, `descriptor`, `record`
52
+ * and optional `creationRevision`, `actionReceipts` and
53
+ * `proposalApplications`. The result is the view document as JSON text.
54
+ * Failures carry kind `event-record` and one of the codes `not-an-event-record`,
55
+ * `unsupported-version`, `malformed-descriptor`, `wrong-record-evidence`,
56
+ * `revision-mismatch`, `incompatible-metadata` or `invalid-input`.
57
+ */
58
+ export declare function eventRecordView(argumentsJson: string): string
48
59
 
49
60
  export interface PrivateJwk {
50
61
  readonly kty: string
@@ -62,24 +73,24 @@ export interface PrivateKeyJwtConfig {
62
73
  * authentication). Defaults to the token endpoint URL. This is not the
63
74
  * `resource` of the token request.
64
75
  */
65
- audience?: string | null
76
+ audience?: string
66
77
  /**
67
78
  * The RFC 8707 resource indicator the token is requested for: the resource
68
79
  * server's registered identifier, not a URL to fetch.
69
80
  */
70
- resource?: string | null
81
+ resource?: string
71
82
  /**
72
83
  * The scopes requested for the token, sent as one space-delimited `scope`
73
84
  * parameter. A requested scope may narrow the client's registered
74
85
  * permission set; it can never widen it.
75
86
  */
76
- scopes?: ReadonlyArray<string> | null
77
- assertionLifetimeSeconds?: SafeInteger | null
78
- refreshMarginSeconds?: SafeInteger | null
79
- requestTimeoutMilliseconds?: SafeInteger | null
80
- connectTimeoutMilliseconds?: SafeInteger | null
81
- userAgent?: string | null
82
- trustedRootCertificates?: string | null
87
+ scopes?: ReadonlyArray<string>
88
+ assertionLifetimeSeconds?: SafeInteger
89
+ refreshMarginSeconds?: SafeInteger
90
+ attemptTimeoutMilliseconds?: SafeInteger
91
+ connectTimeoutMilliseconds?: SafeInteger
92
+ userAgent?: string
93
+ trustedRootCertificates?: string
83
94
  }
84
95
 
85
96
  /** OAuth credentials are returned to the caller. Keep them out of logs and persistence. */
@@ -98,7 +109,7 @@ export interface ExchangeContext {
98
109
  audience: string
99
110
  generation: string
100
111
  deadlineSeconds: SafeInteger
101
- grantId?: string | null
112
+ grantId?: string
102
113
  }
103
114
 
104
115
  export type ExchangePrivateKeyJwtConfig = PrivateKeyJwtConfig & {
@@ -118,10 +129,10 @@ export interface RemoteExchangeSource {
118
129
  bootstrap: ExchangePrivateKeyJwtConfig
119
130
  bootstrapResource: string
120
131
  bootstrapScope: string
121
- requestTimeoutMilliseconds?: SafeInteger | null
122
- connectTimeoutMilliseconds?: SafeInteger | null
123
- userAgent?: string | null
124
- trustedRootCertificates?: string | null
132
+ attemptTimeoutMilliseconds?: SafeInteger
133
+ connectTimeoutMilliseconds?: SafeInteger
134
+ userAgent?: string
135
+ trustedRootCertificates?: string
125
136
  }
126
137
 
127
138
  export type ExchangeAuthorizationConfig =
@@ -135,12 +146,12 @@ export type BaseRegistryAuthorization =
135
146
 
136
147
  export interface BaseRegistryClientConfig {
137
148
  baseUrl: string
138
- authorization?: BaseRegistryAuthorization | null
139
- requestTimeoutMilliseconds?: SafeInteger | null
140
- connectTimeoutMilliseconds?: SafeInteger | null
141
- maxResponseBytes?: SafeInteger | null
142
- userAgent?: string | null
143
- trustedRootCertificates?: string | null
149
+ authorization?: BaseRegistryAuthorization
150
+ attemptTimeoutMilliseconds?: SafeInteger
151
+ connectTimeoutMilliseconds?: SafeInteger
152
+ maximumResponseBytes?: SafeInteger
153
+ userAgent?: string
154
+ trustedRootCertificates?: string
144
155
  /**
145
156
  * How many times a keyed mutation (create, patch, attachment upload or
146
157
  * delete, lifecycle action, immediate action, batch, tombstone, statistics
@@ -149,7 +160,7 @@ export interface BaseRegistryClientConfig {
149
160
  * number from 0 to 2, default 2; 0 sends it once. Any other value is a
150
161
  * `configuration` error.
151
162
  */
152
- maxMutationRetries?: SafeInteger | null
163
+ maximumMutationRetries?: SafeInteger
153
164
  }
154
165
 
155
166
  export type RecordFormat = 'json' | 'json-ld'
@@ -473,6 +484,7 @@ export interface BRegProposalActionDescriptor {
473
484
  readonly accessProfile: string
474
485
  readonly operations: ReadonlyArray<string>
475
486
  readonly readableInputs: ReadonlyArray<string>
487
+ readonly readableContextFields: ReadonlyArray<string>
476
488
  }
477
489
 
478
490
  export interface BRegActionAttachmentDescriptor {
@@ -536,7 +548,7 @@ export interface BRegActionReceipt {
536
548
 
537
549
  export type BRegActionAvailability =
538
550
  | { readonly available: true; readonly observedRevision: number }
539
- | { readonly available: false; readonly observedRevision: number; readonly reason: 'guard-not-satisfied'; readonly recovery: 'none' }
551
+ | { readonly available: false; readonly observedRevision: number; readonly reason: 'guard-not-satisfied'; readonly guardReason?: string; readonly recovery: 'none' }
540
552
  | { readonly available: null; readonly observedRevision: number; readonly reason: 'input-required'; readonly recovery: 'correct-input'; readonly missingInputs: ReadonlyArray<string> }
541
553
  | { readonly available: null; readonly observedRevision: null; readonly reason: 'not-disclosed'; readonly recovery: 'none' }
542
554
 
@@ -795,6 +807,8 @@ export declare class BRegMetadata {
795
807
  selectAction(actionIdentifier: string, expectedProfile: string): BRegActionBinding
796
808
  selectTombstone(recordTypeIdentifier: string, expectedProfile: string): BRegTombstoneBinding
797
809
  selectBatch(recordTypeIdentifier: string, expectedProfile: string): BRegBatchBinding
810
+ /** The event record descriptor declared for a record type, as JSON text. */
811
+ eventRecordDescriptor(recordType: string): string
798
812
  }
799
813
 
800
814
  /** Bounded declared identifiers; absent when any referenced field is unreadable. */
@@ -815,6 +829,7 @@ export interface BaseRegistryClientFailure extends Error {
815
829
  readonly code?: string
816
830
  readonly refusalCode?: string
817
831
  readonly reasonCode?: string
832
+ readonly guardReason?: string
818
833
  readonly fieldPath?: string
819
834
  readonly constraint?: BRegConstraintViolation
820
835
  readonly status?: number
@@ -842,6 +857,7 @@ export declare class BaseRegistryClientError extends Error implements BaseRegist
842
857
  readonly code?: string
843
858
  readonly refusalCode?: string
844
859
  readonly reasonCode?: string
860
+ readonly guardReason?: string
845
861
  readonly fieldPath?: string
846
862
  readonly constraint?: BRegConstraintViolation
847
863
  readonly status?: number
@@ -879,6 +895,12 @@ export declare class BaseRegistryClient {
879
895
  ready(): Promise<CompleteOutcome<ProbeStatus>>
880
896
  openapi(accessProfile?: string | null): Promise<RawOutcome>
881
897
  registryMetadata(accessProfile?: string | null): Promise<RawOutcome>
898
+ /**
899
+ * The first revision of a record as
900
+ * `{recordType, recordId, revision, createdAt}` JSON text, or null when the
901
+ * caller may not read it (403 or 404).
902
+ */
903
+ eventRecordCreationRevision(entityRoute: string, recordIdentifier: string, accessProfile?: string | null): Promise<string | null>
882
904
  statisticsLive(dataset: string, from?: string | null, to?: string | null, accessProfile?: string | null, format?: StatisticsFormat | null): Promise<RawOutcome>
883
905
  statisticsReleases(dataset: string, top?: SafeInteger | null, skipToken?: string | null, accessProfile?: string | null): Promise<RawOutcome>
884
906
  statisticsLatestRelease(dataset: string, period: string, selection: StatisticsReleaseSelection, accessProfile?: string | null, format?: StatisticsFormat | null): Promise<RawOutcome>
package/breg/client.js CHANGED
@@ -16,7 +16,7 @@ class BaseRegistryClientError extends Error {
16
16
  for (const field of ['code', 'refusalCode', 'reasonCode', 'status', 'traceId', 'transportKind', 'tokenKind']) {
17
17
  if (envelope[field] !== undefined && envelope[field] !== null) this[field] = envelope[field];
18
18
  }
19
- for (const field of ['fieldPath', 'constraint']) {
19
+ for (const field of ['fieldPath', 'constraint', 'guardReason']) {
20
20
  if (envelope[field] !== undefined && envelope[field] !== null) {
21
21
  Object.defineProperty(this, field, {
22
22
  value: envelope[field],
@@ -82,7 +82,7 @@ function plainDataObject(value, expectedFields) {
82
82
  return result;
83
83
  }
84
84
 
85
- function webhookHeaders(value) {
85
+ function hookHeaders(value) {
86
86
  if (value === null || typeof value !== 'object' || Array.isArray(value) || isProxy(value)) {
87
87
  throw inputError('invalid-request');
88
88
  }
@@ -102,7 +102,7 @@ function webhookHeaders(value) {
102
102
  return result;
103
103
  }
104
104
 
105
- function verifyWebhookDelivery(value) {
105
+ function verifyHookDelivery(value) {
106
106
  try {
107
107
  const input = plainDataObject(value, ['method', 'path', 'headers', 'body', 'key']);
108
108
  if (typeof input.method !== 'string' || typeof input.path !== 'string'
@@ -110,10 +110,19 @@ function verifyWebhookDelivery(value) {
110
110
  || isSharedArrayBuffer(input.body.buffer) || isSharedArrayBuffer(input.key.buffer)) {
111
111
  throw inputError('invalid-request');
112
112
  }
113
- input.headers = webhookHeaders(input.headers);
113
+ input.headers = hookHeaders(input.headers);
114
114
  input.body = Buffer.from(input.body);
115
115
  input.key = Buffer.from(input.key);
116
- return native.verifyWebhookDelivery(input);
116
+ return native.verifyHookDelivery(input);
117
+ } catch (error) {
118
+ throw normalize(error, 'invalid-request');
119
+ }
120
+ }
121
+
122
+ function eventRecordView(argumentsJson) {
123
+ try {
124
+ if (typeof argumentsJson !== 'string') throw inputError('invalid-request');
125
+ return native.eventRecordView(argumentsJson);
117
126
  } catch (error) {
118
127
  throw normalize(error, 'invalid-request');
119
128
  }
@@ -211,7 +220,7 @@ for (const [method, jsonIndexes, requiredIndexes] of [
211
220
  ['statisticsLive'], ['statisticsReleases'], ['statisticsLatestRelease'],
212
221
  ['statisticsReleaseVersion'], ['statisticsReleaseSeries'], ['statisticsPublish'],
213
222
  ['statisticsWithdraw'],
214
- ['recordRevisions'], ['getRecordRevision', [3]],
223
+ ['recordRevisions'], ['getRecordRevision', [3]], ['eventRecordCreationRevision'],
215
224
  ['getRecord', [2]], ['listRecords', [1]], ['continueList', [0], [0]],
216
225
  ['getGeoJsonRecord', [2]], ['listGeoJsonRecords', [1]], ['continueGeoJsonList', [0], [0]],
217
226
  ['listCurrentRecords', [1]], ['continueCurrentList', [0], [0]],
@@ -298,7 +307,7 @@ const BRegPreparedProposal = preparedClass(native.BRegPreparedProposal, 'BRegPre
298
307
  for (const name of [
299
308
  'selectCreate', 'selectPatch',
300
309
  'selectAction', 'selectTombstone', 'selectBatch', 'selectProposals', 'selectProposalGet',
301
- 'selectProposalReviewContext', 'selectProposalReviewStatus',
310
+ 'selectProposalReviewContext', 'selectProposalReviewStatus', 'eventRecordDescriptor',
302
311
  ]) {
303
312
  const original = native.BRegMetadata.prototype[name];
304
313
  native.BRegMetadata.prototype[name] = function (...args) {
@@ -373,7 +382,8 @@ class PrivateKeyJwt {
373
382
  }
374
383
 
375
384
  module.exports = {
376
- verifyWebhookDelivery,
385
+ verifyHookDelivery,
386
+ eventRecordView,
377
387
  PrivateKeyJwt,
378
388
  BaseRegistryClient,
379
389
  BaseRegistryClientError,
package/breg/index.d.ts CHANGED
@@ -20,6 +20,12 @@ export declare class BaseRegistryClient {
20
20
  recordRevisions(entityRoute: string, recordIdentifier: string, accessProfile?: string | undefined | null): Promise<RawOutcome>
21
21
  /** Retrieve one exact retained revision as validated inert record JSON. */
22
22
  getRecordRevision(entityRoute: string, recordIdentifier: string, revision: number, options?: any | undefined | null): Promise<RawOutcome>
23
+ /**
24
+ * Read the first revision of one record as the compact
25
+ * `{recordType, recordId, revision, createdAt}` JSON, or null when the
26
+ * caller may not read it.
27
+ */
28
+ eventRecordCreationRevision(entityRoute: string, recordIdentifier: string, accessProfile?: string | undefined | null): Promise<string | null>
23
29
  getRecord(entityRoute: string, recordIdentifier: string, options?: any | undefined | null): Promise<CompleteOutcome>
24
30
  listRecords(entityRoute: string, options?: any | undefined | null): Promise<PageOutcome>
25
31
  continueList(value: any): Promise<PageOutcome>
@@ -58,7 +64,7 @@ export declare class BaseRegistryClient {
58
64
  /**
59
65
  * Invoke one metadata-selected immediate action. An invocation whose
60
66
  * outcome is unknown is resent identically under the same key, at most
61
- * `maxMutationRetries` times.
67
+ * `maximumMutationRetries` times.
62
68
  */
63
69
  invokeAction(binding: BRegActionBinding, inputs: any, idempotencyKey: string, conditions?: BRegActionTargetConditions | undefined | null): Promise<CompleteOutcome>
64
70
  /**
@@ -75,7 +81,7 @@ export declare class BaseRegistryClient {
75
81
  /**
76
82
  * Explicitly send a recovered invocation under its original key. An
77
83
  * invocation whose outcome is unknown is resent identically under that
78
- * key, at most `maxMutationRetries` times.
84
+ * key, at most `maximumMutationRetries` times.
79
85
  */
80
86
  executeRecoveredAction(binding: BRegActionBinding, recovered: BRegRecoveredAction): Promise<CompleteOutcome>
81
87
  /** Execute a recovered proposal start with its exact original request and key. */
@@ -91,7 +97,7 @@ export declare class BaseRegistryClient {
91
97
  /**
92
98
  * Execute one metadata-selected atomic batch. A batch whose outcome is
93
99
  * unknown is resent identically under the same key, at most
94
- * `maxMutationRetries` times.
100
+ * `maximumMutationRetries` times.
95
101
  */
96
102
  batchRecords(binding: BRegBatchBinding, request: any, idempotencyKey: string): Promise<CompleteOutcome>
97
103
  /**
@@ -207,6 +213,8 @@ export declare class BRegIngestionPrefixDigest {
207
213
  export type IngestionPrefixDigest = BRegIngestionPrefixDigest
208
214
 
209
215
  export declare class BRegMetadata {
216
+ /** The event record descriptor declared for one record type, as JSON text. */
217
+ eventRecordDescriptor(recordType: string): string
210
218
  /** Read-only capability inventory for each exact Action/profile pair. */
211
219
  get proposalActions(): any
212
220
  /** Caller-filtered inert descriptors. Selectors below remain the only authority constructors. */
@@ -328,6 +336,22 @@ export interface CompleteOutcome {
328
336
  */
329
337
  export declare function encodeIngestionChunk(chunkIndex: number, items: any, prefixDigest: string): BRegIngestionChunk
330
338
 
339
+ /**
340
+ * Project one record revision into the event record view. The input is the
341
+ * JSON arguments document of the Rust projection; the result is the view
342
+ * document as JSON text.
343
+ */
344
+ export declare function eventRecordView(argumentsJson: string): string
345
+
346
+ /** Exact BReg hook request supplied by a receiver. */
347
+ export interface HookDeliveryInput {
348
+ method: string
349
+ path: string
350
+ headers: Record<string, string>
351
+ body: Buffer
352
+ key: Buffer
353
+ }
354
+
331
355
  /** Validated product result serialized before the JavaScript number boundary. */
332
356
  export interface JsonOutcome {
333
357
  kind: string
@@ -364,8 +388,8 @@ export interface RawOutcome {
364
388
  reprDigest?: string
365
389
  }
366
390
 
367
- /** Authenticated BReg webhook metadata and exact body. */
368
- export interface VerifiedWebhookDelivery {
391
+ /** Authenticated BReg hook metadata and exact body. */
392
+ export interface VerifiedHookDelivery {
369
393
  id: string
370
394
  source: string
371
395
  type: string
@@ -378,14 +402,5 @@ export interface VerifiedWebhookDelivery {
378
402
  body: Buffer
379
403
  }
380
404
 
381
- /** Verify a BReg Version 1 webhook signature without applying receiver policy. */
382
- export declare function verifyWebhookDelivery(input: WebhookDeliveryInput): VerifiedWebhookDelivery
383
-
384
- /** Exact BReg webhook request supplied by a receiver. */
385
- export interface WebhookDeliveryInput {
386
- method: string
387
- path: string
388
- headers: Record<string, string>
389
- body: Buffer
390
- key: Buffer
391
- }
405
+ /** Verify a BReg Version 1 hook signature without applying receiver policy. */
406
+ export declare function verifyHookDelivery(input: HookDeliveryInput): VerifiedHookDelivery
@@ -8,11 +8,11 @@ export type JsonObject = { readonly [key: string]: JsonValue }
8
8
 
9
9
  export interface CaseworkClientConfig {
10
10
  baseUrl: string
11
- requestTimeoutMilliseconds?: SafeInteger | null
12
- connectTimeoutMilliseconds?: SafeInteger | null
13
- maxResponseBytes?: SafeInteger | null
14
- userAgent?: string | null
15
- trustedRootCertificates?: string | null
11
+ attemptTimeoutMilliseconds?: SafeInteger
12
+ connectTimeoutMilliseconds?: SafeInteger
13
+ maximumResponseBytes?: SafeInteger
14
+ userAgent?: string
15
+ trustedRootCertificates?: string
16
16
  /**
17
17
  * How many times an idempotency-keyed mutation whose outcome is unknown is
18
18
  * resent, identically and under the same key, before its error is
@@ -20,7 +20,7 @@ export interface CaseworkClientConfig {
20
20
  * unkeyed operations, and review request create and cancel are never
21
21
  * resent. Any other value is a `configuration` error.
22
22
  */
23
- maxMutationRetries?: SafeInteger | null
23
+ maximumMutationRetries?: SafeInteger
24
24
  }
25
25
 
26
26
  export type PageStatus = 'complete' | 'budget-exhausted' | 'source-unavailable'
@@ -72,7 +72,7 @@ export type DirectoryTargetPage = Page<DirectoryMember>
72
72
  export interface QueueRecord { id: string; label: string }
73
73
  export type RoutingPredicate = { equals: JsonValue } | { oneOf: ReadonlyArray<JsonValue> }
74
74
  export interface RoutingCondition { stage?: string; fields?: Readonly<Record<string, RoutingPredicate>> }
75
- export interface RoutingRule { id: string; because: string; when: RoutingCondition; queue: string }
75
+ export interface RoutingRule { id: string; label?: string; because: string; when: RoutingCondition; queue: string }
76
76
  export type WorkingWeekday = 'monday' | 'tuesday' | 'wednesday' | 'thursday' | 'friday' | 'saturday' | 'sunday'
77
77
  export interface CalendarPolicy { id: string; timezone: string; workingWeekdays: ReadonlyArray<WorkingWeekday>; holidaySet: string }
78
78
  export interface WorkingDays { workingDays: SafeInteger }
@@ -189,7 +189,7 @@ export class CaseworkClientError extends Error {
189
189
  readonly traceId?: string
190
190
  readonly validation?: {
191
191
  readonly path: string
192
- readonly reason: 'policy-not-allowed' | 'reference-invalid' | 'object-required' | 'maximum-bytes-exceeded' | 'maximum-depth-exceeded' | 'schema-mismatch' | 'outcome-not-declared' | 'reason-required' | 'text-invalid' | 'result-not-declared' | 'result-required' | 'field-not-declared' | 'constraint-invalid' | 'constraint-violated' | 'public-reason-required' | 'public-reason-not-declared' | 'approval-outcome-differs'
192
+ readonly reason: 'binding-invalid' | 'field-required' | 'policy-not-allowed' | 'reference-invalid' | 'object-required' | 'maximum-bytes-exceeded' | 'maximum-depth-exceeded' | 'schema-mismatch' | 'outcome-not-declared' | 'reason-required' | 'text-invalid' | 'result-not-declared' | 'result-required' | 'field-not-declared' | 'constraint-invalid' | 'constraint-violated' | 'public-reason-required' | 'public-reason-not-declared' | 'approval-outcome-differs'
193
193
  /** Outcome identifiers the review policy declares for the requested settlement when an outcome is refused; empty otherwise. */
194
194
  readonly allowed: ReadonlyArray<string>
195
195
  }
@@ -364,15 +364,16 @@ export interface ReviewAccountabilityRecord {
364
364
  occurredAt: string; retainedUntil: string
365
365
  decisionReceipt?: ReviewDecisionReceipt
366
366
  }
367
- export interface ReviewStagePolicy { id: string; queue: string; decidingProfiles: ReadonlyArray<string>; requiredApprovals: SafeInteger; excludeInitiator?: boolean; excludePreviousStageReviewers?: boolean }
367
+ export interface ReviewStagePolicy { id: string; label?: string; queue: string; decidingProfiles: ReadonlyArray<string>; requiredApprovals: SafeInteger; negativeDecisions?: 'settle' | 'advise'; excludeInitiator?: boolean; excludePreviousStageReviewers?: boolean }
368
368
  export interface ReviewRetentionPolicy { terminalRetentionDays: SafeInteger; accountabilityRetentionDays: SafeInteger }
369
369
  export interface ReviewContextContract { id: string; revision: ContentDigest; schemaDigest: ContentDigest }
370
370
  export type ReviewContextPolicy = { mode: 'submitted' } | { mode: 'current-source'; provider: string; contract: ReviewContextContract }
371
371
  export type ReviewContextCapability = 'human-display' | 'service-status' | 'task-grant-context' | 'routing-context'
372
372
  export interface ReviewContextProviderPolicy { id: string; capabilities: ReadonlyArray<ReviewContextCapability>; sourceNamespace: string; deploymentRef: string; serviceProfiles?: Partial<Record<ReviewContextCapability, string>> }
373
- export interface ReviewPolicy { id: string; version: string; purpose: 'approval' | 'answer'; context: ReviewContextPolicy; routing?: ReadonlyArray<RoutingRule>; stages: ReadonlyArray<ReviewStagePolicy>; clocks?: ReadonlyArray<string>; retention: ReviewRetentionPolicy; displaySchema: JsonValue; resultSchema?: JsonValue; outcomes?: ReadonlyArray<{ id: string; label: string; settlement: 'approved' | 'rejected' | 'changes-requested' | 'answered'; reasonRequired: boolean; publicReason: 'required' | 'optional' | 'none'; resultRequired?: boolean }> }
373
+ export interface ReviewPolicy { id: string; label?: string; version: string; purpose: 'approval' | 'answer'; context: ReviewContextPolicy; routing?: ReadonlyArray<RoutingRule>; stages: ReadonlyArray<ReviewStagePolicy>; clocks?: ReadonlyArray<string>; retention: ReviewRetentionPolicy; displaySchema: JsonValue; resultSchema?: JsonValue; outcomes?: ReadonlyArray<{ id: string; label: string; settlement: 'approved' | 'rejected' | 'changes-requested' | 'answered'; reasonRequired: boolean; publicReason: 'required' | 'optional' | 'none'; resultRequired?: boolean }> }
374
374
  export interface ReviewPolicyClosure {
375
375
  identity: PolicyBinding
376
+ label?: string
376
377
  purpose: 'approval' | 'answer'
377
378
  context: ReviewContextPolicy
378
379
  routing?: ReadonlyArray<RoutingRule>
@@ -85,12 +85,50 @@ function sanitize(value, kind) {
85
85
  return cloneJson(value, { nodes: 0, bytes: 0, active: new WeakSet() }, 0, kind);
86
86
  }
87
87
 
88
+ function configurationValue(config) {
89
+ if (!config || typeof config !== 'object' || Array.isArray(config) || isProxy(config)) {
90
+ throw normalized({}, 'configuration');
91
+ }
92
+ const prototype = Object.getPrototypeOf(config);
93
+ if (prototype !== Object.prototype && prototype !== null) {
94
+ throw normalized({}, 'configuration');
95
+ }
96
+ const allowed = new Set([
97
+ 'baseUrl',
98
+ 'attemptTimeoutMilliseconds',
99
+ 'connectTimeoutMilliseconds',
100
+ 'maximumResponseBytes',
101
+ 'userAgent',
102
+ 'trustedRootCertificates',
103
+ 'maximumMutationRetries',
104
+ ]);
105
+ const copy = Object.create(null);
106
+ for (const key of Reflect.ownKeys(config)) {
107
+ if (typeof key !== 'string' || !allowed.has(key)) throw normalized({}, 'configuration');
108
+ const descriptor = Object.getOwnPropertyDescriptor(config, key);
109
+ if (!descriptor || !descriptor.enumerable || !Object.hasOwn(descriptor, 'value')) {
110
+ throw normalized({}, 'configuration');
111
+ }
112
+ const value = descriptor.value;
113
+ if (key === 'baseUrl' || key === 'userAgent' || key === 'trustedRootCertificates') {
114
+ if (typeof value !== 'string') throw normalized({}, 'configuration');
115
+ copy[key] = value;
116
+ } else {
117
+ if (!Number.isSafeInteger(value) || value < 0 || value > 0xffff_ffff) {
118
+ throw normalized({}, 'configuration');
119
+ }
120
+ copy[key] = value;
121
+ }
122
+ }
123
+ return copy;
124
+ }
125
+
88
126
  const NativeCaseworkClient = native.CaseworkClient;
89
127
 
90
128
  class CaseworkClient {
91
129
  constructor(config) {
92
130
  try {
93
- this.native = new NativeCaseworkClient(sanitize(config, 'configuration'));
131
+ this.native = new NativeCaseworkClient(configurationValue(config));
94
132
  } catch (error) {
95
133
  throw normalized(error, 'configuration');
96
134
  }
@@ -55,16 +55,16 @@ export declare class CaseworkClient {
55
55
 
56
56
  export interface CaseworkClientConfig {
57
57
  baseUrl: string
58
- requestTimeoutMilliseconds?: number
58
+ attemptTimeoutMilliseconds?: number
59
59
  connectTimeoutMilliseconds?: number
60
- maxResponseBytes?: number
60
+ maximumResponseBytes?: number
61
61
  userAgent?: string
62
62
  trustedRootCertificates?: string
63
63
  /**
64
64
  * How many times a keyed mutation whose outcome is unknown is resent under
65
65
  * the same idempotency key: 0 to 2, default 2, and 0 disables the resend.
66
66
  */
67
- maxMutationRetries?: number
67
+ maximumMutationRetries?: number
68
68
  }
69
69
 
70
70
  export interface CaseworkOutcome {
@@ -0,0 +1,18 @@
1
+ {
2
+ "schemaVersion": "registry-stack.sdk-compatibility.v1",
3
+ "sdkPackage": {
4
+ "name": "registry-stack-client",
5
+ "version": "0.44.0"
6
+ },
7
+ "namespaces": {
8
+ "discovery": {
9
+ "testedServerBaseline": "0.44.0",
10
+ "compatibleServerPatchLine": "0.44.x",
11
+ "responseCompatibility": {
12
+ "additiveObjectMembers": "ignored-after-duplicate-key-rejection",
13
+ "unknownProblemCodes": "http-status-only",
14
+ "proof": "registry-discovery-client::client::tests::real_client_ignores_additive_response_members_at_every_response_level"
15
+ }
16
+ }
17
+ }
18
+ }