@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 +31 -7
- package/breg/client.d.ts +100 -10
- package/breg/client.js +41 -34
- package/breg/index.d.ts +56 -2
- package/casework/client.d.ts +90 -30
- package/casework/client.js +22 -17
- package/casework/index.d.ts +7 -0
- package/discovery/client.d.ts +7 -7
- package/discovery/client.js +1 -1
- package/evidence/client.d.ts +1 -1
- package/evidence/index.d.ts +3 -6
- package/index.d.ts +2 -1
- package/index.js +2 -1
- package/messaging/client.d.ts +26 -4
- package/messaging/client.js +33 -21
- package/messaging/index.d.ts +2 -10
- package/native.js +2 -2
- package/package.json +10 -8
- package/scheduling/client.d.ts +229 -0
- package/scheduling/client.js +142 -0
- package/scheduling/index.d.ts +28 -0
- package/scheduling/index.js +3 -0
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
|
|
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
|
|
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
|
|
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.
|
|
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
|
|
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
|
-
| '
|
|
12
|
-
| '
|
|
13
|
-
| '
|
|
14
|
-
| '
|
|
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<{
|
|
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
|
|
464
|
-
readonly
|
|
465
|
-
readonly
|
|
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: '
|
|
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('
|
|
64
|
+
throw inputError('invalid-request');
|
|
64
65
|
}
|
|
65
66
|
const prototype = Object.getPrototypeOf(value);
|
|
66
|
-
if (prototype !== Object.prototype && prototype !== null) throw inputError('
|
|
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('
|
|
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('
|
|
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('
|
|
85
|
+
throw inputError('invalid-request');
|
|
85
86
|
}
|
|
86
87
|
const prototype = Object.getPrototypeOf(value);
|
|
87
|
-
if (prototype !== Object.prototype && prototype !== null) throw inputError('
|
|
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('
|
|
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('
|
|
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('
|
|
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, '
|
|
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('
|
|
188
|
+
if (requiredIndexes.has(index)) throw inputError('invalid-request');
|
|
188
189
|
return value;
|
|
189
190
|
}
|
|
190
|
-
return cloneJson(value, budget, 0, '
|
|
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, '
|
|
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
|
-
['
|
|
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, '
|
|
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('
|
|
276
|
+
if (!Buffer.isBuffer(bytes)) throw inputError('invalid-request');
|
|
273
277
|
return Class.fromBytes(bytes);
|
|
274
278
|
} catch (error) {
|
|
275
|
-
throw normalize(error, '
|
|
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('
|
|
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, '
|
|
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, '
|
|
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, '
|
|
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, '
|
|
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('
|
|
340
|
+
throw inputError('invalid-request');
|
|
336
341
|
}
|
|
337
342
|
return original.apply(this, args);
|
|
338
343
|
} catch (error) {
|
|
339
|
-
throw normalize(error, '
|
|
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, '
|
|
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, '
|
|
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, '
|
|
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('
|
|
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, '
|
|
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('
|
|
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, '
|
|
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('
|
|
411
|
+
throw inputError('invalid-request');
|
|
407
412
|
}
|
|
408
413
|
return ingestionPrefixDigestUpdate.call(this, data);
|
|
409
414
|
} catch (error) {
|
|
410
|
-
throw normalize(error, '
|
|
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
|
-
/**
|
|
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
|
-
/**
|
|
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.
|