@registrystack/client 0.39.0 → 0.41.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,7 @@
1
1
  # @registrystack/client
2
2
 
3
3
  One versioned Node.js package for the Discovery, Evidence, Base Registry
4
- Engine, Casework, and Messaging client APIs in Registry Stack.
4
+ Engine, Casework, Messaging, and Scheduling client APIs in Registry Stack.
5
5
 
6
6
  ## Install
7
7
 
@@ -9,15 +9,15 @@ Engine, Casework, and Messaging client APIs in Registry Stack.
9
9
  npm install "@registrystack/client@<version>"
10
10
  ```
11
11
 
12
- Requires Node.js 22.12 or newer. Supported targets are macOS arm64, Linux
12
+ Requires Node.js 24.11 or newer. Supported targets are macOS arm64, Linux
13
13
  arm64 with glibc, and Linux x64 with glibc; installing the package pulls in
14
- one platform-specific optional dependency containing all five native
14
+ one platform-specific optional dependency containing all six native
15
15
  bindings.
16
16
 
17
17
  ## Usage
18
18
 
19
19
  ```js
20
- const { discovery, evidence, breg, casework, messaging } = require('@registrystack/client');
20
+ const { discovery, evidence, breg, casework, messaging, scheduling } = require('@registrystack/client');
21
21
 
22
22
  const registry = new breg.BaseRegistryClient({
23
23
  baseUrl: 'https://registry.example.invalid/',
@@ -28,6 +28,9 @@ const work = new casework.CaseworkClient({
28
28
  const messages = new messaging.MessagingClient({
29
29
  baseUrl: 'https://messaging.example.invalid/',
30
30
  });
31
+ const appointments = new scheduling.SchedulingClient({
32
+ baseUrl: 'https://scheduling.example.invalid/',
33
+ });
31
34
  ```
32
35
 
33
36
  ## Products
@@ -42,6 +45,8 @@ const messages = new messaging.MessagingClient({
42
45
  recovery, history, holdings, and directory bootstrap.
43
46
  - `messaging`: Registry Messaging, submit, inspect, cancel, and preview
44
47
  institution-owned messages.
48
+ - `scheduling`: Registry Scheduling, published offerings, availability,
49
+ holds, and appointments over operator-anchored supply.
45
50
 
46
51
  Each product remains in its own namespace because its routing,
47
52
  authentication, errors, and verification rules are different.
@@ -79,11 +84,21 @@ descriptions grant no authority, so select the opaque create, patch, and
79
84
  lifecycle authorities from that same contract before executing a mutation.
80
85
  Methods ending in `Json` keep values exact across the Node number boundary:
81
86
  they accept domain JSON text and return `valueJson` alongside the usual
82
- trace, ETag, location, and opaque continuation. The client never retries a
83
- mutation automatically. See
87
+ trace, ETag, location, and opaque continuation. See
84
88
  [Exact JSON in Node](https://docs.registrystack.org/reference/client-api/#exact-json-in-node)
85
89
  for the full rules.
86
90
 
91
+ A keyed BReg, Casework, Messaging, or Scheduling mutation whose outcome is
92
+ 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
94
+ once. Reads, unkeyed calls, and every 4xx refusal are never resent. When the returned error
95
+ still reports `outcomeUnknown`, the mutation may have taken effect: recover by
96
+ sending it again under the same key, because a new key could apply it twice.
97
+ `outcomeUnknown` is false for `410 idempotency.expired`, but there an earlier
98
+ attempt under the key was answered and may have committed: reconcile that
99
+ attempt before choosing a new key.
100
+ See [Unknown outcomes](https://docs.registrystack.org/reference/client-api/#unknown-outcomes-and-the-same-key-retry).
101
+
87
102
  `breg.verifyWebhookDelivery({ method, path, headers, body, key })` authenticates
88
103
  the exact bytes of one Version 1 webhook delivery. The result returns
89
104
  `deliveryTime` and `idempotencyKey`; the receiver must bound clock skew and
@@ -106,6 +121,9 @@ Registry Stack v0.30.0.
106
121
  The `messaging` namespace is part of the unified package beginning with
107
122
  Registry Stack v0.38.0.
108
123
 
124
+ The `scheduling` namespace is part of the unified package beginning with
125
+ Registry Stack v0.40.0.
126
+
109
127
  ## Casework notes
110
128
 
111
129
  The Casework module is for a trusted server host. Each call takes that request's
@@ -114,9 +132,15 @@ selected source profile. The client does not retain them. Browsers should send
114
132
  only the host's session cookie. Claim, release, and decide consume the
115
133
  caller-filtered action returned on the item, including its exact route and
116
134
  `ifMatch` revision. Mutations require a caller-controlled idempotency key and
117
- are never retried automatically. After a lost response, use
135
+ are resent only under the bounded same-key retry above; review request create
136
+ and cancel are never resent. After a lost response, use
118
137
  `recoverDecisionByKey` with the original key so recovery does not depend on the
119
138
  attempt identifier being received.
139
+ Reviewer inboxes accept an `ownership` filter before pagination.
140
+ `supervisoryReviewTasks` returns only task and accountability references for
141
+ queues the selected supervisor currently serves; its state is a holder-free
142
+ string. A single decided-task read
143
+ includes `decisionReceipt` only for the caller who recorded that decision.
120
144
 
121
145
  ## Documentation
122
146
 
package/breg/client.d.ts CHANGED
@@ -8,10 +8,10 @@ export type JsonObject = { readonly [key: string]: JsonValue }
8
8
  export type SafeInteger = number
9
9
 
10
10
  export type WebhookVerificationRefusalCode =
11
- | 'missing_header'
12
- | 'malformed_signature'
13
- | 'signature_mismatch'
14
- | 'unsupported_version'
11
+ | 'missing-header'
12
+ | 'malformed-signature'
13
+ | 'signature-mismatch'
14
+ | 'unsupported-version'
15
15
 
16
16
  export interface WebhookDeliveryInput {
17
17
  method: string
@@ -137,10 +137,44 @@ export interface BaseRegistryClientConfig {
137
137
  maxResponseBytes?: SafeInteger | null
138
138
  userAgent?: string | null
139
139
  trustedRootCertificates?: string | null
140
+ /**
141
+ * How many times a keyed mutation (create, patch, attachment upload or
142
+ * delete, lifecycle action, immediate action, batch, tombstone, statistics
143
+ * publish or withdraw) whose outcome is unknown is resent, identically and
144
+ * under the same idempotency key, before its error is returned: a whole
145
+ * number from 0 to 2, default 2; 0 sends it once. Any other value is a
146
+ * `configuration` error.
147
+ */
148
+ maxMutationRetries?: SafeInteger | null
140
149
  }
141
150
 
142
151
  export type RecordFormat = 'json' | 'json-ld'
143
152
 
153
+ export interface BRegStatisticalDimensionDescriptor {
154
+ readonly field: string
155
+ readonly vocabulary: string
156
+ readonly codes: ReadonlyArray<string>
157
+ }
158
+
159
+ export interface BRegStatisticalDatasetDescriptor {
160
+ readonly id: string
161
+ readonly unit: string
162
+ readonly periodKind: 'flow' | 'stock'
163
+ readonly granularity: 'day' | 'month' | 'quarter' | 'year'
164
+ readonly firstPeriod: string
165
+ readonly dimensions: ReadonlyArray<BRegStatisticalDimensionDescriptor>
166
+ readonly definitionDigest: string
167
+ readonly operations: ReadonlyArray<
168
+ | 'read-live'
169
+ | 'list-releases'
170
+ | 'read-released-series'
171
+ | 'read-latest-release'
172
+ | 'read-release-version'
173
+ | 'publish-release'
174
+ | 'withdraw-release'
175
+ >
176
+ }
177
+
144
178
  export interface RecordProjectionOptions {
145
179
  select?: ReadonlyArray<string> | null
146
180
  accessProfile?: string | null
@@ -224,8 +258,8 @@ export type BRegRequestResultReferenceData = JsonObject & {
224
258
  }
225
259
  export type BRegRequestState = 'draft' | 'submitted' | 'cancelled' | 'applied'
226
260
  export type BRegRequestReviewRequirement =
227
- | Readonly<{ mode: 'none' }>
228
- | Readonly<{ authority: string; policyId: string }>
261
+ | Readonly<{ type: 'none' }>
262
+ | Readonly<{ type: 'required'; authority: string; policyId: string }>
229
263
  export type BRegExternalReviewStatus = Readonly<{
230
264
  submission: Readonly<{
231
265
  state: 'pending' | 'accepted' | 'uncertain' | 'cancelling' | 'cancelled' | 'failed'
@@ -460,9 +494,9 @@ export interface BRegQueryDescriptor {
460
494
  readonly sortableFields: ReadonlyArray<BRegQueryField>
461
495
  readonly allowCount: boolean
462
496
  readonly defaultPageSize: number
463
- readonly maxPageSize: number
464
- readonly maxFilterClauses: number
465
- readonly maxInValues: number
497
+ readonly maximumPageSize: number
498
+ readonly maximumFilterClauses: number
499
+ readonly maximumInValues: number
466
500
  readonly pagination: { readonly parameter: string; readonly responsePath: string; readonly exclusive: boolean }
467
501
  readonly temporal: JsonObject | null
468
502
  readonly spatialQueries?: {
@@ -820,7 +854,7 @@ export interface BRegAttachmentState {
820
854
 
821
855
  /** What one record projection says about one slot. */
822
856
  export type BRegAttachmentSlotValue =
823
- | { readonly kind: 'not_selected'; readonly value: null }
857
+ | { readonly kind: 'not-selected'; readonly value: null }
824
858
  | { readonly kind: 'empty'; readonly value: null }
825
859
  | { readonly kind: 'filled'; readonly value: BRegAttachmentState }
826
860
 
@@ -940,6 +974,18 @@ export declare class BRegLifecycleAction {
940
974
  readonly body: JsonObject
941
975
  }
942
976
 
977
+ /**
978
+ * Inert bounded immediate-action evidence: inputs, saved target conditions,
979
+ * and the idempotency key. Persist these bytes with owner-only access before
980
+ * invoking.
981
+ */
982
+ export declare class BRegPreparedAction {
983
+ private constructor()
984
+ private readonly __opaque: void
985
+ static fromBytes(bytes: Buffer): BRegPreparedAction
986
+ toBytes(): Buffer
987
+ }
988
+
943
989
  /** Inert bounded Create evidence. Persist these bytes with owner-only access. */
944
990
  export declare class BRegPreparedCreate {
945
991
  private constructor()
@@ -956,6 +1002,12 @@ export declare class BRegPreparedLifecycle {
956
1002
  toBytes(): Buffer
957
1003
  }
958
1004
 
1005
+ /** Revalidated action invocation and key. It still requires fresh metadata authority to send. */
1006
+ export declare class BRegRecoveredAction {
1007
+ private constructor()
1008
+ private readonly __opaque: void
1009
+ }
1010
+
959
1011
  /** Revalidated Create request. It still requires fresh metadata authority to send. */
960
1012
  export declare class BRegRecoveredCreate {
961
1013
  private constructor()
@@ -975,6 +1027,8 @@ export declare class BRegMetadata {
975
1027
  readonly operations: ReadonlyArray<BRegOperationDescriptor>
976
1028
  readonly immediateActions: ReadonlyArray<BRegImmediateActionDescriptor>
977
1029
  readonly actionsJson: string | null
1030
+ /** Validated caller-filtered inert descriptions. They never grant entity authority. */
1031
+ readonly statisticalDatasets: ReadonlyArray<BRegStatisticalDatasetDescriptor> | null
978
1032
  readonly registryIdentifier: string
979
1033
  readonly registryVersion: string
980
1034
  readonly registryRevision: string
@@ -1001,6 +1055,20 @@ export interface BaseRegistryClientFailure extends Error {
1001
1055
  readonly traceId?: string
1002
1056
  readonly transportKind?: string
1003
1057
  readonly tokenKind?: string
1058
+ /**
1059
+ * Whether the request may have taken effect although this error was raised:
1060
+ * a timeout or broken exchange after sending, an unusable answer, or a 5xx
1061
+ * other than `action.handler_failed` and
1062
+ * `statistical_dataset.domain_violation`, which the engine returns only with
1063
+ * the attempt rolled back. When true, recover a keyed mutation by sending it
1064
+ * again under the same idempotency key; a new key could apply it twice.
1065
+ * False for a configuration or request defect, a credential the token
1066
+ * provider could not supply, a connection never established, and every 4xx
1067
+ * refusal. It is false for `410 idempotency.expired` too, but there an
1068
+ * earlier attempt under the key committed and only its held response is
1069
+ * gone: read the resource before choosing a new key.
1070
+ */
1071
+ readonly outcomeUnknown: boolean
1004
1072
  }
1005
1073
 
1006
1074
  export declare class BaseRegistryClientError extends Error implements BaseRegistryClientFailure {
@@ -1014,6 +1082,20 @@ export declare class BaseRegistryClientError extends Error implements BaseRegist
1014
1082
  readonly traceId?: string
1015
1083
  readonly transportKind?: string
1016
1084
  readonly tokenKind?: string
1085
+ /**
1086
+ * Whether the request may have taken effect although this error was raised:
1087
+ * a timeout or broken exchange after sending, an unusable answer, or a 5xx
1088
+ * other than `action.handler_failed` and
1089
+ * `statistical_dataset.domain_violation`, which the engine returns only with
1090
+ * the attempt rolled back. When true, recover a keyed mutation by sending it
1091
+ * again under the same idempotency key; a new key could apply it twice.
1092
+ * False for a configuration or request defect, a credential the token
1093
+ * provider could not supply, a connection never established, and every 4xx
1094
+ * refusal. It is false for `410 idempotency.expired` too, but there an
1095
+ * earlier attempt under the key committed and only its held response is
1096
+ * gone: read the resource before choosing a new key.
1097
+ */
1098
+ readonly outcomeUnknown: boolean
1017
1099
  }
1018
1100
 
1019
1101
  export declare class BaseRegistryClient {
@@ -1052,6 +1134,14 @@ export declare class BaseRegistryClient {
1052
1134
  actionTargetConditionsJson(binding: BRegImmediateActionBinding, inputsJson: string): Promise<BRegActionTargetConditions>
1053
1135
  invokeAction(binding: BRegImmediateActionBinding, inputs: JsonObject, idempotencyKey: string, conditions?: BRegActionTargetConditions | null): Promise<CompleteOutcome<BRegActionReceipt>>
1054
1136
  invokeActionJson(binding: BRegImmediateActionBinding, inputsJson: string, idempotencyKey: string, conditions?: BRegActionTargetConditions | null): Promise<JsonOutcome>
1137
+ /** Validate and retain one invocation before any I/O, for recovery after a lost response. */
1138
+ prepareAction(binding: BRegImmediateActionBinding, inputs: JsonObject, idempotencyKey: string, conditions?: BRegActionTargetConditions | null): BRegPreparedAction
1139
+ prepareActionJson(binding: BRegImmediateActionBinding, inputsJson: string, idempotencyKey: string, conditions?: BRegActionTargetConditions | null): BRegPreparedAction
1140
+ /** Revalidate saved evidence against fresh authority and the original inputs and key. Performs no I/O. */
1141
+ recoverAction(binding: BRegImmediateActionBinding, prepared: BRegPreparedAction, inputs: JsonObject, idempotencyKey: string): BRegRecoveredAction
1142
+ recoverActionJson(binding: BRegImmediateActionBinding, prepared: BRegPreparedAction, inputsJson: string, idempotencyKey: string): BRegRecoveredAction
1143
+ executeRecoveredAction(binding: BRegImmediateActionBinding, recovered: BRegRecoveredAction): Promise<CompleteOutcome<BRegActionReceipt>>
1144
+ executeRecoveredActionJson(binding: BRegImmediateActionBinding, recovered: BRegRecoveredAction): Promise<JsonOutcome>
1055
1145
  createRecord(binding: BRegCreateBinding, data: JsonObject, idempotencyKey: string, format?: RecordFormat | null): Promise<CompleteOutcome<RecordEnvelope>>
1056
1146
  prepareCreate(binding: BRegCreateBinding, data: JsonObject, idempotencyKey: string, format?: RecordFormat | null): BRegPreparedCreate
1057
1147
  prepareCreateJson(binding: BRegCreateBinding, dataJson: string, idempotencyKey: string, format?: RecordFormat | null): BRegPreparedCreate
package/breg/client.js CHANGED
@@ -12,6 +12,7 @@ class BaseRegistryClientError extends Error {
12
12
  super(envelope.message);
13
13
  this.name = 'BaseRegistryClientError';
14
14
  this.kind = envelope.kind;
15
+ this.outcomeUnknown = envelope.outcomeUnknown === true;
15
16
  for (const field of ['code', 'planRefusal', 'refusalCode', 'reasonCode', 'status', 'traceId', 'transportKind', 'tokenKind']) {
16
17
  if (envelope[field] !== undefined && envelope[field] !== null) this[field] = envelope[field];
17
18
  }
@@ -60,19 +61,19 @@ function inputError(kind) {
60
61
 
61
62
  function plainDataObject(value, expectedFields) {
62
63
  if (value === null || typeof value !== 'object' || Array.isArray(value) || isProxy(value)) {
63
- throw inputError('invalid_request');
64
+ throw inputError('invalid-request');
64
65
  }
65
66
  const prototype = Object.getPrototypeOf(value);
66
- if (prototype !== Object.prototype && prototype !== null) throw inputError('invalid_request');
67
+ if (prototype !== Object.prototype && prototype !== null) throw inputError('invalid-request');
67
68
  const keys = Reflect.ownKeys(value);
68
69
  if (keys.some((key) => typeof key !== 'string')
69
70
  || keys.length !== expectedFields.length
70
- || keys.some((key) => !expectedFields.includes(key))) throw inputError('invalid_request');
71
+ || keys.some((key) => !expectedFields.includes(key))) throw inputError('invalid-request');
71
72
  const result = Object.create(null);
72
73
  for (const field of expectedFields) {
73
74
  const descriptor = Object.getOwnPropertyDescriptor(value, field);
74
75
  if (!descriptor || !descriptor.enumerable || !Object.hasOwn(descriptor, 'value')) {
75
- throw inputError('invalid_request');
76
+ throw inputError('invalid-request');
76
77
  }
77
78
  result[field] = descriptor.value;
78
79
  }
@@ -81,19 +82,19 @@ function plainDataObject(value, expectedFields) {
81
82
 
82
83
  function webhookHeaders(value) {
83
84
  if (value === null || typeof value !== 'object' || Array.isArray(value) || isProxy(value)) {
84
- throw inputError('invalid_request');
85
+ throw inputError('invalid-request');
85
86
  }
86
87
  const prototype = Object.getPrototypeOf(value);
87
- if (prototype !== Object.prototype && prototype !== null) throw inputError('invalid_request');
88
+ if (prototype !== Object.prototype && prototype !== null) throw inputError('invalid-request');
88
89
  const keys = Reflect.ownKeys(value);
89
90
  if (keys.some((key) => typeof key !== 'string')) {
90
- throw inputError('invalid_request');
91
+ throw inputError('invalid-request');
91
92
  }
92
93
  const result = Object.create(null);
93
94
  for (const name of keys) {
94
95
  const descriptor = Object.getOwnPropertyDescriptor(value, name);
95
96
  if (!descriptor || !descriptor.enumerable || !Object.hasOwn(descriptor, 'value')
96
- || typeof descriptor.value !== 'string') throw inputError('invalid_request');
97
+ || typeof descriptor.value !== 'string') throw inputError('invalid-request');
97
98
  result[name] = descriptor.value;
98
99
  }
99
100
  return result;
@@ -105,14 +106,14 @@ function verifyWebhookDelivery(value) {
105
106
  if (typeof input.method !== 'string' || typeof input.path !== 'string'
106
107
  || !Buffer.isBuffer(input.body) || !Buffer.isBuffer(input.key)
107
108
  || isSharedArrayBuffer(input.body.buffer) || isSharedArrayBuffer(input.key.buffer)) {
108
- throw inputError('invalid_request');
109
+ throw inputError('invalid-request');
109
110
  }
110
111
  input.headers = webhookHeaders(input.headers);
111
112
  input.body = Buffer.from(input.body);
112
113
  input.key = Buffer.from(input.key);
113
114
  return native.verifyWebhookDelivery(input);
114
115
  } catch (error) {
115
- throw normalize(error, 'invalid_request');
116
+ throw normalize(error, 'invalid-request');
116
117
  }
117
118
  }
118
119
 
@@ -184,10 +185,10 @@ function sanitizeArguments(args, jsonIndexes, requiredIndexes) {
184
185
  return args.map((value, index) => {
185
186
  if (!jsonIndexes.has(index)) return value;
186
187
  if (value === undefined || value === null) {
187
- if (requiredIndexes.has(index)) throw inputError('invalid_request');
188
+ if (requiredIndexes.has(index)) throw inputError('invalid-request');
188
189
  return value;
189
190
  }
190
- return cloneJson(value, budget, 0, 'invalid_request');
191
+ return cloneJson(value, budget, 0, 'invalid-request');
191
192
  });
192
193
  }
193
194
 
@@ -198,7 +199,7 @@ function wrapAsync(name, jsonIndexes = [], requiredIndexes = []) {
198
199
  const sanitized = sanitizeArguments(args, new Set(jsonIndexes), new Set(requiredIndexes));
199
200
  return original.apply(this, sanitized).catch((error) => { throw normalize(error); });
200
201
  } catch (error) {
201
- throw normalize(error, 'invalid_request');
202
+ throw normalize(error, 'invalid-request');
202
203
  }
203
204
  };
204
205
  }
@@ -217,7 +218,7 @@ for (const [method, jsonIndexes, requiredIndexes] of [
217
218
  ['listRelationshipRecords', [3]], ['continueRelationshipList', [0], [0]],
218
219
  ['lookupRecord', [2, 3]], ['createRecord', [1], [1]],
219
220
  ['actionTargetConditions', [1], [1]], ['invokeAction', [1], [1]],
220
- ['executeRecoveredCreate'],
221
+ ['executeRecoveredAction'], ['executeRecoveredCreate'],
221
222
  ['patchRecord', [3], [3]], ['batchRecords', [1], [1]], ['tombstoneRecord'],
222
223
  ['executeLifecycleAction'],
223
224
  ['executeRecoveredLifecycleAction'],
@@ -231,13 +232,16 @@ for (const [method, jsonIndexes, requiredIndexes] of [
231
232
  ['listRelationshipRecordsJson', [3]], ['continueRelationshipListJson', [0], [0]],
232
233
  ['lookupRecordJson', [3]], ['createRecordJson'], ['patchRecordJson'], ['executeLifecycleActionJson'],
233
234
  ['actionTargetConditionsJson'], ['invokeActionJson'], ['batchRecordsJson'], ['tombstoneRecordJson'],
234
- ['executeRecoveredCreateJson'], ['executeRecoveredLifecycleActionJson'],
235
+ ['executeRecoveredActionJson'], ['executeRecoveredCreateJson'],
236
+ ['executeRecoveredLifecycleActionJson'],
235
237
  ['uploadAttachmentJson'], ['deleteAttachmentJson'],
236
238
  ['createIngestionRun', [1], [1]], ['listIngestionRuns', [1]],
237
239
  ['readIngestionRun'], ['submitIngestionChunk'], ['cancelIngestionRun'],
238
240
  ]) wrapAsync(method, jsonIndexes, requiredIndexes);
239
241
 
240
242
  for (const [method, jsonIndexes, requiredIndexes] of [
243
+ ['prepareAction', [1], [1]], ['prepareActionJson'],
244
+ ['recoverAction', [2], [2]], ['recoverActionJson'],
241
245
  ['prepareCreate', [1], [1]], ['prepareCreateJson'], ['recoverCreate'],
242
246
  ['prepareLifecycleAction', [1], [1]], ['prepareLifecycleActionJson'],
243
247
  ['recoverLifecycleAction'],
@@ -249,7 +253,7 @@ for (const [method, jsonIndexes, requiredIndexes] of [
249
253
  args, new Set(jsonIndexes), new Set(requiredIndexes),
250
254
  ));
251
255
  } catch (error) {
252
- throw normalize(error, 'invalid_request');
256
+ throw normalize(error, 'invalid-request');
253
257
  }
254
258
  };
255
259
  }
@@ -269,10 +273,10 @@ function preparedClass(Class, label) {
269
273
  fromBytes: {
270
274
  value(bytes) {
271
275
  try {
272
- if (!Buffer.isBuffer(bytes)) throw inputError('invalid_request');
276
+ if (!Buffer.isBuffer(bytes)) throw inputError('invalid-request');
273
277
  return Class.fromBytes(bytes);
274
278
  } catch (error) {
275
- throw normalize(error, 'invalid_request');
279
+ throw normalize(error, 'invalid-request');
276
280
  }
277
281
  },
278
282
  },
@@ -284,6 +288,7 @@ function preparedClass(Class, label) {
284
288
  return Facade;
285
289
  }
286
290
 
291
+ const BRegPreparedAction = preparedClass(native.BRegPreparedAction, 'BRegPreparedAction');
287
292
  const BRegPreparedCreate = preparedClass(native.BRegPreparedCreate, 'BRegPreparedCreate');
288
293
  const BRegPreparedLifecycle = preparedClass(
289
294
  native.BRegPreparedLifecycle, 'BRegPreparedLifecycle',
@@ -292,17 +297,17 @@ const BRegPreparedLifecycle = preparedClass(
292
297
  const withReason = native.BRegLifecycleAction.prototype.withReason;
293
298
  native.BRegLifecycleAction.prototype.withReason = function (reason) {
294
299
  try {
295
- if (typeof reason !== 'string' || !reason.isWellFormed()) throw inputError('invalid_request');
300
+ if (typeof reason !== 'string' || !reason.isWellFormed()) throw inputError('invalid-request');
296
301
  return withReason.call(this, reason);
297
302
  } catch (error) {
298
- throw normalize(error, 'invalid_request');
303
+ throw normalize(error, 'invalid-request');
299
304
  }
300
305
  };
301
306
 
302
307
  const lifecycleActionsJson = native.BaseRegistryClient.prototype.lifecycleActionsJson;
303
308
  native.BaseRegistryClient.prototype.lifecycleActionsJson = function (...args) {
304
309
  try { return lifecycleActionsJson.apply(this, args); }
305
- catch (error) { throw normalize(error, 'invalid_request'); }
310
+ catch (error) { throw normalize(error, 'invalid-request'); }
306
311
  };
307
312
 
308
313
  const lifecycleActions = native.BaseRegistryClient.prototype.lifecycleActions;
@@ -311,7 +316,7 @@ native.BaseRegistryClient.prototype.lifecycleActions = function (...args) {
311
316
  const sanitized = sanitizeArguments(args, new Set([1]), new Set([1]));
312
317
  return lifecycleActions.apply(this, sanitized);
313
318
  } catch (error) {
314
- throw normalize(error, 'invalid_request');
319
+ throw normalize(error, 'invalid-request');
315
320
  }
316
321
  };
317
322
 
@@ -321,7 +326,7 @@ native.BaseRegistryClient.prototype.requestHistory = function (...args) {
321
326
  const sanitized = sanitizeArguments(args, new Set([0]), new Set([0]));
322
327
  return requestHistory.apply(this, sanitized);
323
328
  } catch (error) {
324
- throw normalize(error, 'invalid_request');
329
+ throw normalize(error, 'invalid-request');
325
330
  }
326
331
  };
327
332
 
@@ -332,11 +337,11 @@ for (const name of ['findProposal', 'findApplication']) {
332
337
  const proposalVersion = args[2];
333
338
  if (!Number.isSafeInteger(proposalVersion)
334
339
  || proposalVersion < 1 || proposalVersion > 0xffff_ffff) {
335
- throw inputError('invalid_request');
340
+ throw inputError('invalid-request');
336
341
  }
337
342
  return original.apply(this, args);
338
343
  } catch (error) {
339
- throw normalize(error, 'invalid_request');
344
+ throw normalize(error, 'invalid-request');
340
345
  }
341
346
  };
342
347
  }
@@ -346,7 +351,7 @@ native.BRegAttachmentSlot.prototype.valueIn = function (...args) {
346
351
  try {
347
352
  return valueIn.apply(this, sanitizeArguments(args, new Set([0]), new Set([0])));
348
353
  } catch (error) {
349
- throw normalize(error, 'invalid_request');
354
+ throw normalize(error, 'invalid-request');
350
355
  }
351
356
  };
352
357
 
@@ -356,7 +361,7 @@ for (const name of ['prepareUpload', 'acceptsContentType']) {
356
361
  try {
357
362
  return original.apply(this, args);
358
363
  } catch (error) {
359
- throw normalize(error, 'invalid_request');
364
+ throw normalize(error, 'invalid-request');
360
365
  }
361
366
  };
362
367
  }
@@ -370,20 +375,20 @@ for (const name of [
370
375
  try {
371
376
  return original.apply(this, args);
372
377
  } catch (error) {
373
- throw normalize(error, 'invalid_request');
378
+ throw normalize(error, 'invalid-request');
374
379
  }
375
380
  };
376
381
  }
377
382
 
378
383
  function encodeIngestionChunk(chunkIndex, items, prefixDigest) {
379
384
  try {
380
- if (!Number.isSafeInteger(chunkIndex)) throw inputError('invalid_request');
385
+ if (!Number.isSafeInteger(chunkIndex)) throw inputError('invalid-request');
381
386
  const sanitized = sanitizeArguments(
382
387
  [chunkIndex, items, prefixDigest], new Set([1]), new Set([1]),
383
388
  );
384
389
  return native.encodeIngestionChunk(...sanitized);
385
390
  } catch (error) {
386
- throw normalize(error, 'invalid_request');
391
+ throw normalize(error, 'invalid-request');
387
392
  }
388
393
  }
389
394
 
@@ -392,10 +397,10 @@ function encodeIngestionChunk(chunkIndex, items, prefixDigest) {
392
397
  const ingestionChunkReceipt = native.BaseRegistryClient.prototype.ingestionChunkReceipt;
393
398
  native.BaseRegistryClient.prototype.ingestionChunkReceipt = function (...args) {
394
399
  try {
395
- if (!Number.isSafeInteger(args[2])) throw inputError('invalid_request');
400
+ if (!Number.isSafeInteger(args[2])) throw inputError('invalid-request');
396
401
  return ingestionChunkReceipt.apply(this, args).catch((error) => { throw normalize(error); });
397
402
  } catch (error) {
398
- throw normalize(error, 'invalid_request');
403
+ throw normalize(error, 'invalid-request');
399
404
  }
400
405
  };
401
406
 
@@ -403,11 +408,11 @@ const ingestionPrefixDigestUpdate = native.BRegIngestionPrefixDigest.prototype.u
403
408
  native.BRegIngestionPrefixDigest.prototype.update = function (data) {
404
409
  try {
405
410
  if (!Buffer.isBuffer(data) || isSharedArrayBuffer(data.buffer)) {
406
- throw inputError('invalid_request');
411
+ throw inputError('invalid-request');
407
412
  }
408
413
  return ingestionPrefixDigestUpdate.call(this, data);
409
414
  } catch (error) {
410
- throw normalize(error, 'invalid_request');
415
+ throw normalize(error, 'invalid-request');
411
416
  }
412
417
  };
413
418
 
@@ -456,8 +461,10 @@ module.exports = {
456
461
  BRegActionTargetConditions: native.BRegActionTargetConditions,
457
462
  BRegTombstoneBinding: native.BRegTombstoneBinding,
458
463
  BRegBatchBinding: native.BRegBatchBinding,
464
+ BRegPreparedAction,
459
465
  BRegPreparedCreate,
460
466
  BRegPreparedLifecycle,
467
+ BRegRecoveredAction: native.BRegRecoveredAction,
461
468
  BRegRecoveredCreate: native.BRegRecoveredCreate,
462
469
  BRegRecoveredLifecycle: native.BRegRecoveredLifecycle,
463
470
  BRegIngestionChunk: native.BRegIngestionChunk,
package/breg/index.d.ts CHANGED
@@ -37,8 +37,29 @@ export declare class BaseRegistryClient {
37
37
  lookupRecord(entityRoute: string, selector: string, values?: any | undefined | null, options?: any | undefined | null): Promise<CompleteOutcome>
38
38
  /** Fetch opaque target conditions for one metadata-selected action. */
39
39
  actionTargetConditions(binding: BRegImmediateActionBinding, inputs: any): Promise<BRegActionTargetConditions>
40
- /** Invoke one metadata-selected immediate action without automatic retry. */
40
+ /**
41
+ * Invoke one metadata-selected immediate action. An invocation whose
42
+ * outcome is unknown is resent identically under the same key, at most
43
+ * `maxMutationRetries` times.
44
+ */
41
45
  invokeAction(binding: BRegImmediateActionBinding, inputs: any, idempotencyKey: string, conditions?: BRegActionTargetConditions | undefined | null): Promise<CompleteOutcome>
46
+ /**
47
+ * Prepare inert invocation evidence before any token acquisition or I/O.
48
+ * Persist `toBytes` before invoking so a lost response can be recovered.
49
+ */
50
+ prepareAction(binding: BRegImmediateActionBinding, inputs: any, idempotencyKey: string, conditions?: BRegActionTargetConditions | undefined | null): BRegPreparedAction
51
+ /**
52
+ * Revalidate saved invocation evidence against freshly selected authority
53
+ * and the caller's original inputs and key. The saved target conditions
54
+ * are reused exactly; this never fetches conditions or sends a request.
55
+ */
56
+ recoverAction(binding: BRegImmediateActionBinding, prepared: BRegPreparedAction, inputs: any, idempotencyKey: string): BRegRecoveredAction
57
+ /**
58
+ * Explicitly send a recovered invocation under its original key. An
59
+ * invocation whose outcome is unknown is resent identically under that
60
+ * key, at most `maxMutationRetries` times.
61
+ */
62
+ executeRecoveredAction(binding: BRegImmediateActionBinding, recovered: BRegRecoveredAction): Promise<CompleteOutcome>
42
63
  createRecord(binding: BRegCreateBinding, data: any, idempotencyKey: string, formatValue?: string | undefined | null): Promise<CompleteOutcome>
43
64
  /** Prepare inert Create evidence before any token acquisition or I/O. */
44
65
  prepareCreate(binding: BRegCreateBinding, data: any, idempotencyKey: string, formatValue?: string | undefined | null): BRegPreparedCreate
@@ -47,7 +68,11 @@ export declare class BaseRegistryClient {
47
68
  /** Explicitly send a recovered Create request with fresh authority. */
48
69
  executeRecoveredCreate(binding: BRegCreateBinding, recovered: BRegRecoveredCreate): Promise<CompleteOutcome>
49
70
  patchRecord(binding: BRegPatchBinding, recordIdentifier: string, etag: string, operations: any, idempotencyKey: string, formatValue?: string | undefined | null): Promise<CompleteOutcome>
50
- /** Execute one metadata-selected atomic batch without automatic retry. */
71
+ /**
72
+ * Execute one metadata-selected atomic batch. A batch whose outcome is
73
+ * unknown is resent identically under the same key, at most
74
+ * `maxMutationRetries` times.
75
+ */
51
76
  batchRecords(binding: BRegBatchBinding, request: any, idempotencyKey: string): Promise<CompleteOutcome>
52
77
  /**
53
78
  * Announce one whole input and open a durable ingestion run for it. The
@@ -116,6 +141,12 @@ export declare class BaseRegistryClient {
116
141
  actionTargetConditionsJson(binding: BRegImmediateActionBinding, inputsJson: string): Promise<BRegActionTargetConditions>
117
142
  /** Invoke an action from exact JSON and preserve exact receipt values. */
118
143
  invokeActionJson(binding: BRegImmediateActionBinding, inputsJson: string, idempotencyKey: string, conditions?: BRegActionTargetConditions | undefined | null): Promise<JsonOutcome>
144
+ /** Prepare inert invocation evidence from exact action-input JSON. */
145
+ prepareActionJson(binding: BRegImmediateActionBinding, inputsJson: string, idempotencyKey: string, conditions?: BRegActionTargetConditions | undefined | null): BRegPreparedAction
146
+ /** Revalidate saved invocation evidence against exact original input JSON. */
147
+ recoverActionJson(binding: BRegImmediateActionBinding, prepared: BRegPreparedAction, inputsJson: string, idempotencyKey: string): BRegRecoveredAction
148
+ /** Explicitly send a recovered invocation and preserve exact receipt values. */
149
+ executeRecoveredActionJson(binding: BRegImmediateActionBinding, recovered: BRegRecoveredAction): Promise<JsonOutcome>
119
150
  createRecordJson(binding: BRegCreateBinding, dataJson: string, idempotencyKey: string, formatValue?: string | undefined | null): Promise<JsonOutcome>
120
151
  /** Prepare inert Create evidence from exact JSON text. */
121
152
  prepareCreateJson(binding: BRegCreateBinding, dataJson: string, idempotencyKey: string, formatValue?: string | undefined | null): BRegPreparedCreate
@@ -231,6 +262,8 @@ export declare class BRegMetadata {
231
262
  get immediateActions(): any
232
263
  /** Original caller-filtered action metadata as exact JSON text. */
233
264
  get actionsJson(): string | null
265
+ /** Validated caller-filtered statistical dataset descriptions, without entity authority. */
266
+ get statisticalDatasets(): any | null
234
267
  /** Descriptive change-request capability for one entity, when advertised. */
235
268
  changeRequestCapability(entityIdentifier: string): any | null
236
269
  get registryIdentifier(): string
@@ -251,6 +284,19 @@ export type Metadata = BRegMetadata
251
284
  export declare class BRegPatchBinding {}
252
285
  export type PatchBinding = BRegPatchBinding
253
286
 
287
+ /**
288
+ * Inert original immediate-action invocation evidence. The bytes carry the
289
+ * inputs, saved target conditions, and idempotency key, but no token or
290
+ * executable metadata authority.
291
+ */
292
+ export declare class BRegPreparedAction {
293
+ /** Restore bounded inert evidence previously returned by `toBytes`. */
294
+ static fromBytes(bytes: Buffer): BRegPreparedAction
295
+ /** Copy the exact evidence bytes for owner-protected persistence. */
296
+ toBytes(): Buffer
297
+ }
298
+ export type PreparedAction = BRegPreparedAction
299
+
254
300
  /**
255
301
  * Inert original Create request evidence. The bytes carry values and an
256
302
  * idempotency key, but no token or executable metadata authority.
@@ -275,6 +321,14 @@ export declare class BRegPreparedLifecycle {
275
321
  }
276
322
  export type PreparedLifecycle = BRegPreparedLifecycle
277
323
 
324
+ /**
325
+ * A recovered immediate-action invocation and key. This remains inert until
326
+ * `executeRecoveredAction` is explicitly called with freshly selected
327
+ * authority.
328
+ */
329
+ export declare class BRegRecoveredAction {}
330
+ export type RecoveredAction = BRegRecoveredAction
331
+
278
332
  /**
279
333
  * A recovered Create request, key, and representation. This remains inert
280
334
  * until `executeRecoveredCreate` is explicitly called with fresh authority.