@registrystack/client 0.31.0 → 0.32.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/breg/client.d.ts CHANGED
@@ -87,9 +87,47 @@ export class PrivateKeyJwt {
87
87
  bearerToken(): Promise<string>
88
88
  }
89
89
 
90
+ /** One immutable verified person or grant context. Reconstruct after host source facts change. */
91
+ export interface ExchangeContext {
92
+ issuer: string
93
+ subject: string
94
+ audience: string
95
+ generation: string
96
+ deadlineSeconds: SafeInteger
97
+ grantId?: string | null
98
+ }
99
+
100
+ export type ExchangePrivateKeyJwtConfig = PrivateKeyJwtConfig & {
101
+ resource: string
102
+ scopes: ReadonlyArray<string>
103
+ }
104
+
105
+ export interface FirstPartyExchangeSource {
106
+ key: PrivateJwk
107
+ /** Reviewed host attributes; registry_actor_kind must be human and grant claims are refused. */
108
+ attributes: Readonly<Record<string, JsonValue>>
109
+ }
110
+
111
+ export interface RemoteExchangeSource {
112
+ /** Exact assertion URL supplied by the authority client, such as Casework.taskAssertionEndpoint. */
113
+ endpoint: string
114
+ bootstrap: ExchangePrivateKeyJwtConfig
115
+ bootstrapResource: string
116
+ bootstrapScope: string
117
+ requestTimeoutMilliseconds?: SafeInteger | null
118
+ connectTimeoutMilliseconds?: SafeInteger | null
119
+ userAgent?: string | null
120
+ trustedRootCertificates?: string | null
121
+ }
122
+
123
+ export type ExchangeAuthorizationConfig =
124
+ | { client: ExchangePrivateKeyJwtConfig; context: ExchangeContext; firstParty: FirstPartyExchangeSource }
125
+ | { client: ExchangePrivateKeyJwtConfig; context: ExchangeContext; remote: RemoteExchangeSource }
126
+
90
127
  export type BaseRegistryAuthorization =
91
128
  | { static: string }
92
129
  | { privateKeyJwt: PrivateKeyJwtConfig }
130
+ | { exchange: ExchangeAuthorizationConfig }
93
131
 
94
132
  export interface BaseRegistryClientConfig {
95
133
  baseUrl: string
@@ -440,6 +440,8 @@ export class CaseworkClient {
440
440
  approveTaskGrant(token: string, profile: string, sourceProfile: string, itemId: string, expectedRevision: SafeInteger, idempotencyKey: string, approval: TaskApprovalRequest): Promise<CaseworkOutcome<TaskGrantView>>
441
441
  revokeTaskGrant(token: string, profile: string, sourceProfile: string, itemId: string, grantId: string): Promise<CaseworkOutcome<TaskGrantRevocation>>
442
442
  taskAssertion(token: string, grantId: string): Promise<CaseworkOutcome<TaskAssertionResponse>>
443
+ /** Exact empty-POST authority route for the shared remote exchange provider. */
444
+ taskAssertionEndpoint(grantId: string): string
443
445
  taskGrantStatus(token: string, grantId: string): Promise<CaseworkOutcome<TaskGrantStatus>>
444
446
  claimWorkItem(token: string, profile: string, sourceProfile: string, action: CaseworkAction, idempotencyKey: string): Promise<CaseworkOutcome<MutationResponse>>
445
447
  releaseWorkItem(token: string, profile: string, sourceProfile: string, action: CaseworkAction, idempotencyKey: string): Promise<CaseworkOutcome<MutationResponse>>
@@ -92,6 +92,14 @@ class CaseworkClient {
92
92
  throw normalized(error, 'configuration');
93
93
  }
94
94
  }
95
+
96
+ taskAssertionEndpoint(grantId) {
97
+ try {
98
+ return this.native.taskAssertionEndpoint(grantId);
99
+ } catch (error) {
100
+ throw normalized(error, 'invalid_request');
101
+ }
102
+ }
95
103
  }
96
104
 
97
105
  for (const [method, jsonIndexes] of [
@@ -24,6 +24,7 @@ export declare class CaseworkClient {
24
24
  approveTaskGrant(token: string, profile: string, sourceProfile: string, itemId: string, expectedRevision: number, idempotencyKey: string, approval: any): Promise<CaseworkOutcome>
25
25
  revokeTaskGrant(token: string, profile: string, sourceProfile: string, itemId: string, grantId: string): Promise<CaseworkOutcome>
26
26
  taskAssertion(token: string, grantId: string): Promise<CaseworkOutcome>
27
+ taskAssertionEndpoint(grantId: string): string
27
28
  taskGrantStatus(token: string, grantId: string): Promise<CaseworkOutcome>
28
29
  claimWorkItem(token: string, profile: string, sourceProfile: string, action: any, idempotencyKey: string): Promise<CaseworkOutcome>
29
30
  releaseWorkItem(token: string, profile: string, sourceProfile: string, action: any, idempotencyKey: string): Promise<CaseworkOutcome>
@@ -35,6 +35,8 @@ export interface ProgressiveVerifiedResult {
35
35
  readonly values: Readonly<Record<string, unknown>>
36
36
  readonly value: unknown
37
37
  readonly subjectContinuity: ProgressiveSubjectContinuity
38
+ /** Pre-response trust and policy snapshot. Retain with the exact artifact. */
39
+ readonly retainedVerification: Buffer
38
40
  }
39
41
 
40
42
  /** A signed-JWS result. The credential member of the native result is `null`. */
@@ -116,12 +118,91 @@ export type EvidenceTokenConfig =
116
118
  | { static: string }
117
119
  | { privateKeyJwt: PrivateKeyJwtConfig }
118
120
 
121
+ /** A verified actor/grant generation with a bounded authorization lifetime. */
122
+ export interface EvidenceExchangeContext {
123
+ issuer: string
124
+ subject: string
125
+ audience: string
126
+ generation: string
127
+ deadlineSeconds: number
128
+ grantId?: string
129
+ }
130
+
131
+ /**
132
+ * The client half of an exchange authorization.
133
+ *
134
+ * This is not a `PrivateKeyJwtConfig`, even though the two describe the same
135
+ * kind of client: an exchange is pinned to one resource and scope set, so both
136
+ * are required here, and the object is read by the shared exchange
137
+ * configuration parser rather than by the binding's own reader, so its timeout
138
+ * members are the full-word ones that parser accepts. State at most one of
139
+ * `requestTimeoutMilliseconds` and `requestTimeoutSeconds`, and at most one of
140
+ * `connectTimeoutMilliseconds` and `connectTimeoutSeconds`; naming both of a
141
+ * pair is refused.
142
+ */
143
+ export interface EvidenceExchangeClientConfig {
144
+ tokenEndpoint: string
145
+ clientId: string
146
+ /** The client's private key, as a JWK. */
147
+ clientKey: Readonly<Record<string, unknown>>
148
+ /**
149
+ * The audience of the client assertion, when the authorization server
150
+ * expects something other than its own token endpoint.
151
+ */
152
+ audience?: string
153
+ /**
154
+ * The RFC 8707 resource indicator the token is requested for: the resource
155
+ * server's registered identifier, not a URL to fetch.
156
+ */
157
+ resource: string
158
+ /**
159
+ * The scopes requested for the token, sent as one space-delimited `scope`
160
+ * parameter. A requested scope may narrow the client's registered
161
+ * permission set; it can never widen it.
162
+ */
163
+ scopes: ReadonlyArray<string>
164
+ assertionLifetimeSeconds?: number
165
+ refreshMarginSeconds?: number
166
+ requestTimeoutMilliseconds?: number
167
+ requestTimeoutSeconds?: number
168
+ connectTimeoutMilliseconds?: number
169
+ connectTimeoutSeconds?: number
170
+ userAgent?: string
171
+ /** Additional trust roots for the token endpoint, as a PEM bundle. */
172
+ trustedRootCertificates?: string
173
+ }
174
+
175
+ /** The owning authority a remote-sourced exchange obtains assertions from. */
176
+ export interface EvidenceExchangeRemoteSourceConfig {
177
+ endpoint: string
178
+ bootstrap: EvidenceExchangeClientConfig
179
+ bootstrapResource: string
180
+ bootstrapScope: string
181
+ requestTimeoutMilliseconds?: number
182
+ requestTimeoutSeconds?: number
183
+ connectTimeoutMilliseconds?: number
184
+ connectTimeoutSeconds?: number
185
+ userAgent?: string
186
+ /** Additional trust roots for the authority, as a PEM bundle. */
187
+ trustedRootCertificates?: string
188
+ }
189
+
190
+ export type EvidenceExchangeAuthorizationConfig = {
191
+ client: EvidenceExchangeClientConfig
192
+ context: EvidenceExchangeContext
193
+ } & (
194
+ | { firstParty: { key: Readonly<Record<string, unknown>>, attributes: Readonly<Record<string, unknown>> }, remote?: never }
195
+ | { firstParty?: never, remote: EvidenceExchangeRemoteSourceConfig }
196
+ )
197
+
119
198
  /** The configuration `new EvidenceClient(...)` reads. */
120
199
  export interface EvidenceClientConfig {
121
200
  baseUrl: string
122
201
  trustedJwks: TrustedJwks
123
202
  revokedKeyIds: ReadonlyArray<string>
124
- token: EvidenceTokenConfig
203
+ /** Configure exactly one of `token` or `authorization`. */
204
+ token?: EvidenceTokenConfig
205
+ authorization?: { exchange: EvidenceExchangeAuthorizationConfig }
125
206
  requestTimeoutMs?: number
126
207
  connectTimeoutMs?: number
127
208
  userAgent?: string
@@ -152,6 +233,10 @@ export declare class EvidenceClient extends NativeEvidenceClient {
152
233
  * the JavaScript wrapper.
153
234
  */
154
235
  static fromProfile(path: string, privateKeyJwk?: Readonly<Record<string, unknown>>): EvidenceClient
236
+ static fromProfileWithAuthorization(
237
+ path: string,
238
+ authorization: { exchange: EvidenceExchangeAuthorizationConfig },
239
+ ): EvidenceClient
155
240
  }
156
241
 
157
242
  /**
@@ -166,6 +166,7 @@ for (const name of [
166
166
  'values',
167
167
  'value',
168
168
  'subjectContinuity',
169
+ 'retainedVerification',
169
170
  ]) {
170
171
  wrapGetter(native.AudienceScopedResult.prototype, name);
171
172
  }
@@ -215,6 +216,16 @@ class EvidenceClient extends native.EvidenceClient {
215
216
  throw normalize(error);
216
217
  }
217
218
  }
219
+
220
+ static fromProfileWithAuthorization(path, authorization) {
221
+ try {
222
+ const client = native.EvidenceClient.fromProfileWithAuthorization(path, authorization);
223
+ Object.setPrototypeOf(client, this.prototype);
224
+ return client;
225
+ } catch (error) {
226
+ throw normalize(error);
227
+ }
228
+ }
218
229
  }
219
230
 
220
231
  class SdJwtVcBatchResponse extends native.SdJwtVcBatchResponse {
@@ -236,4 +247,18 @@ module.exports = {
236
247
  RawEvidenceRequestBatchResponse: native.RawEvidenceRequestBatchResponse,
237
248
  AudienceScopedResult: native.AudienceScopedResult,
238
249
  SdJwtVcBatchResponse,
250
+ verifyRetained(context, response) {
251
+ try {
252
+ return native.verifyRetained(context, response);
253
+ } catch (error) {
254
+ throw normalize(error);
255
+ }
256
+ },
257
+ verifyRetainedAsOf(context, response, asOfMillis) {
258
+ try {
259
+ return native.verifyRetainedAsOf(context, response, asOfMillis);
260
+ } catch (error) {
261
+ throw normalize(error);
262
+ }
263
+ },
239
264
  };
@@ -6,6 +6,8 @@
6
6
  * FFI boundary until the caller asks for it.
7
7
  */
8
8
  export declare class AudienceScopedResult {
9
+ /** Exact serialized pre-response trust snapshot for offline re-verification. */
10
+ get retainedVerification(): Buffer
9
11
  get responseFormat(): string
10
12
  get evidence(): any
11
13
  get traceId(): string | null
@@ -36,6 +38,12 @@ export declare class EvidenceClient {
36
38
  * client and are likewise redacted there.
37
39
  */
38
40
  static fromProfile(path: string, privateKeyJwk?: any): EvidenceClient
41
+ /**
42
+ * Build a profile-driven client with a context-bound staff exchange.
43
+ * The profile's discovered authority and pinned OAuth request parameters
44
+ * must match the immutable provider before the first token is acquired.
45
+ */
46
+ static fromProfileWithAuthorization(path: string, authorization: any): EvidenceClient
39
47
  /**
40
48
  * Close the expectations for one request and generate its nonce. No I/O
41
49
  * happens here. The returned request is good for exactly one exchange:
@@ -300,3 +308,15 @@ export interface VerifiedEvidenceRequestBatch {
300
308
  export type VerifiedEvidenceRequestBatchItem =
301
309
  | { status: 'available', verified: VerifiedEvidence }
302
310
  | { status: 'notAvailable' }
311
+
312
+ /**
313
+ * Verify exact retained response bytes against a bounded pre-response trust
314
+ * snapshot without constructing a client or performing network I/O.
315
+ */
316
+ export declare function verifyRetained(context: Buffer, response: Buffer): VerifiedEvidence
317
+
318
+ /**
319
+ * Replay an earlier decision at its recorded instant. Current decisions use
320
+ * `verify_retained` so expired assertions cannot be accepted as current.
321
+ */
322
+ export declare function verifyRetainedAsOf(context: Buffer, response: Buffer, asOfMillis: number): VerifiedEvidence
package/native.js CHANGED
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- const PACKAGE_VERSION = '0.31.0';
3
+ const PACKAGE_VERSION = '0.32.0';
4
4
  const PRODUCTS = new Set(['discovery', 'evidence', 'relay', 'breg', 'casework']);
5
5
 
6
6
  function target() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@registrystack/client",
3
- "version": "0.31.0",
3
+ "version": "0.32.0",
4
4
  "description": "Unified Node.js client for Registry Stack products.",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://docs.registrystack.org/reference/client-api/",
@@ -57,8 +57,8 @@
57
57
  "typescript": "6.0.3"
58
58
  },
59
59
  "optionalDependencies": {
60
- "@registrystack/client-darwin-arm64": "0.31.0",
61
- "@registrystack/client-linux-arm64-gnu": "0.31.0",
62
- "@registrystack/client-linux-x64-gnu": "0.31.0"
60
+ "@registrystack/client-darwin-arm64": "0.32.0",
61
+ "@registrystack/client-linux-arm64-gnu": "0.32.0",
62
+ "@registrystack/client-linux-x64-gnu": "0.32.0"
63
63
  }
64
64
  }
package/relay/client.d.ts CHANGED
@@ -39,9 +39,45 @@ export interface PrivateKeyJwtConfig {
39
39
  trustedRootCertificates?: string | null
40
40
  }
41
41
 
42
+ /** One immutable verified person or grant context. Reconstruct after host source facts change. */
43
+ export interface ExchangeContext {
44
+ issuer: string
45
+ subject: string
46
+ audience: string
47
+ generation: string
48
+ deadlineSeconds: SafeInteger
49
+ grantId?: string | null
50
+ }
51
+
52
+ export type ExchangePrivateKeyJwtConfig = PrivateKeyJwtConfig & {
53
+ resource: string
54
+ scopes: ReadonlyArray<string>
55
+ }
56
+
57
+ export interface FirstPartyExchangeSource {
58
+ key: PrivateJwk
59
+ attributes: Readonly<Record<string, JsonValue>>
60
+ }
61
+
62
+ export interface RemoteExchangeSource {
63
+ endpoint: string
64
+ bootstrap: ExchangePrivateKeyJwtConfig
65
+ bootstrapResource: string
66
+ bootstrapScope: string
67
+ requestTimeoutMilliseconds?: SafeInteger | null
68
+ connectTimeoutMilliseconds?: SafeInteger | null
69
+ userAgent?: string | null
70
+ trustedRootCertificates?: string | null
71
+ }
72
+
73
+ export type ExchangeAuthorizationConfig =
74
+ | { client: ExchangePrivateKeyJwtConfig; context: ExchangeContext; firstParty: FirstPartyExchangeSource }
75
+ | { client: ExchangePrivateKeyJwtConfig; context: ExchangeContext; remote: RemoteExchangeSource }
76
+
42
77
  export type RelayAuthorization =
43
78
  | { static: string }
44
79
  | { privateKeyJwt: PrivateKeyJwtConfig }
80
+ | { exchange: ExchangeAuthorizationConfig }
45
81
 
46
82
  export interface RelayClientConfig {
47
83
  baseUrl: string