@voltro/protocol 0.79.1 → 0.81.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/CHANGELOG.md +169 -0
- package/dist/apikey.d.ts +8 -0
- package/dist/index.d.ts +394 -14
- package/dist/index.js +601 -556
- package/dist/jwt.d.ts +8 -0
- package/dist/rest.d.ts +84 -16
- package/dist/rest.js +228 -218
- package/dist/{restFormat-ChSVyufA.js → restFormat-CzdGVkuB.js} +72 -60
- package/dist/{scopes-BbIyym8y.js → scopes-CvU5QBQ4.js} +110 -79
- package/dist/session.d.ts +20 -0
- package/dist/session.js +6 -6
- package/package.json +3 -3
package/dist/jwt.d.ts
CHANGED
|
@@ -339,6 +339,14 @@ declare const Subject: Schema.Union<[Schema.Struct<{
|
|
|
339
339
|
tenantId: typeof Schema.Null;
|
|
340
340
|
scopes: Schema.optional<Schema.Array$<typeof Schema.String>>;
|
|
341
341
|
metadata: Schema.optional<Schema.Record$<typeof Schema.String, typeof Schema.Unknown>>;
|
|
342
|
+
}>, Schema.Struct<{
|
|
343
|
+
type: Schema.Literal<["service"]>;
|
|
344
|
+
id: typeof Schema.String;
|
|
345
|
+
/** The calling app's name, as the callee lists it in `serviceCallers`. */
|
|
346
|
+
service: typeof Schema.String;
|
|
347
|
+
tenantId: typeof Schema.Null;
|
|
348
|
+
scopes: Schema.optional<Schema.Array$<typeof Schema.String>>;
|
|
349
|
+
metadata: Schema.optional<Schema.Record$<typeof Schema.String, typeof Schema.Unknown>>;
|
|
342
350
|
}>]>;
|
|
343
351
|
|
|
344
352
|
declare type Subject = typeof Subject.Type;
|
package/dist/rest.d.ts
CHANGED
|
@@ -30,6 +30,9 @@ declare interface ActionProcedureDescriptor<Name extends string, Input extends S
|
|
|
30
30
|
* `openAccess: '<why>'`. Mutually exclusive with `guards`; together they are
|
|
31
31
|
* the only two shapes `security.defaultDeny` accepts. */
|
|
32
32
|
readonly openAccess: string | undefined;
|
|
33
|
+
/** Only these apps of the project may call this procedure — see `service` on
|
|
34
|
+
* the definer's options. Absent → the app's own clients call it. */
|
|
35
|
+
readonly service: ServiceSpec | undefined;
|
|
33
36
|
/** Opt this action into a public REST endpoint (innovation/11). */
|
|
34
37
|
readonly publicApi: PublicApiSpec | undefined;
|
|
35
38
|
/** Opt this action into the auto-synthesized agent toolset (innovation/07). */
|
|
@@ -138,7 +141,7 @@ export declare const collectPublicApiRoutes: (entries: ReadonlyArray<PublicApiEn
|
|
|
138
141
|
* because that is where the normalised decision lands, and because every
|
|
139
142
|
* enforcement path reads the descriptor's array and nothing else.
|
|
140
143
|
*/
|
|
141
|
-
declare type DeclaredAccess<Input = unknown> = ReadonlyArray<AnyGuardSpec<Input> | OpenAccessSpec>;
|
|
144
|
+
declare type DeclaredAccess<Input = unknown> = ReadonlyArray<AnyGuardSpec<Input> | OpenAccessSpec | ServiceAccessSpec>;
|
|
142
145
|
|
|
143
146
|
/** The `_tag` literals a descriptor's `error:` union declares (empty for none). */
|
|
144
147
|
export declare const declaredErrorTags: (error: Schema.Schema.All | undefined) => ReadonlySet<string>;
|
|
@@ -178,15 +181,16 @@ export declare const deriveResource: (tag: string, spec: PublicApiSpec, descript
|
|
|
178
181
|
|
|
179
182
|
/**
|
|
180
183
|
* Dispatch a request across REST routes that SHARE a path. Every REST route
|
|
181
|
-
*
|
|
182
|
-
*
|
|
183
|
-
*
|
|
184
|
-
*
|
|
185
|
-
*
|
|
186
|
-
*
|
|
187
|
-
*
|
|
188
|
-
*
|
|
189
|
-
*
|
|
184
|
+
* gates its own method, returning a precise 405 BEFORE any side effect when the
|
|
185
|
+
* method isn't its own — so probing the group in order and taking the FIRST
|
|
186
|
+
* non-405 result yields the route that owns the request's method. This is what
|
|
187
|
+
* lets the standard GET + POST on one resource path coexist: `rpcServer.ts` in
|
|
188
|
+
* `@voltro/runtime` mounts ONE dispatcher per
|
|
189
|
+
* path (the underlying router rejects two mounts on the same
|
|
190
|
+
* `(method, path)`). A single-route group returns that route's result directly
|
|
191
|
+
* (its own 405 included); when no route in the group owns the method, the last
|
|
192
|
+
* 405 stands — its `Allow` names every method the path serves, because
|
|
193
|
+
* `restRoutesToHttpRoutes` gives each route its path's full set.
|
|
190
194
|
*
|
|
191
195
|
* `group` must be non-empty (the serve pipeline only builds a dispatcher for a
|
|
192
196
|
* path that has at least one route).
|
|
@@ -283,14 +287,24 @@ declare interface IdempotencyStore {
|
|
|
283
287
|
/** Current record for (scope, key), or null. Read-side (inspect/dashboard). */
|
|
284
288
|
readonly get: (scope: string, key: string) => Promise<IdempotencyRecord | null>;
|
|
285
289
|
/**
|
|
286
|
-
* Atomically claim (scope, key) IF absent OR stale
|
|
290
|
+
* Atomically claim (scope, key) IF absent OR stale — a COMPLETED record older
|
|
291
|
+
* than `ttlMs` (the replay window), or an IN-FLIGHT one whose lease
|
|
292
|
+
* (`inFlightLeaseMs`, renewed by the live handler) lapsed:
|
|
287
293
|
* write a fresh `in_flight` row and return `'claimed'`. Otherwise return the
|
|
288
294
|
* EXISTING (still-fresh) record. The atomicity here is the whole game — two
|
|
289
295
|
* concurrent same-key requests both hit this, exactly one gets `'claimed'`,
|
|
290
296
|
* the loser reads the winner's record. In SQL this is one
|
|
291
297
|
* `INSERT … ON CONFLICT DO UPDATE … WHERE existing.createdAt < now - ttl`.
|
|
292
298
|
*/
|
|
293
|
-
readonly claim: (scope: string, key: string, now: number, ttlMs: number) => Promise<'claimed' | IdempotencyRecord>;
|
|
299
|
+
readonly claim: (scope: string, key: string, now: number, ttlMs: number, inFlightLeaseMs: number) => Promise<'claimed' | IdempotencyRecord>;
|
|
300
|
+
/**
|
|
301
|
+
* Extend a RUNNING claim's lease: bump its timestamp while it is still
|
|
302
|
+
* `in_flight` (a completed or released claim is left alone). The server calls
|
|
303
|
+
* it while the handler runs; a process that dies stops calling it, and its
|
|
304
|
+
* claim goes stale after `inFlightLeaseMs` instead of after the whole replay
|
|
305
|
+
* window.
|
|
306
|
+
*/
|
|
307
|
+
readonly renew: (scope: string, key: string, now: number) => Promise<void>;
|
|
294
308
|
/** Flip the claim to `completed` and store the response. */
|
|
295
309
|
readonly complete: (scope: string, key: string, response: IdempotencyResponse, now: number) => Promise<void>;
|
|
296
310
|
/** Drop the claim (handler errored → a retry may re-process). */
|
|
@@ -370,6 +384,9 @@ declare interface MutationProcedureDescriptor<Name extends string, Input extends
|
|
|
370
384
|
* `openAccess: '<why>'`. Mutually exclusive with `guards`; together they are
|
|
371
385
|
* the only two shapes `security.defaultDeny` accepts. */
|
|
372
386
|
readonly openAccess: string | undefined;
|
|
387
|
+
/** Only these apps of the project may call this procedure — see `service` on
|
|
388
|
+
* the definer's options. Absent → the app's own clients call it. */
|
|
389
|
+
readonly service: ServiceSpec | undefined;
|
|
373
390
|
/** Opt this mutation into a public REST endpoint (innovation/11). */
|
|
374
391
|
readonly publicApi: PublicApiSpec | undefined;
|
|
375
392
|
/** Opt this mutation into the auto-synthesized agent toolset (innovation/07). */
|
|
@@ -504,11 +521,17 @@ declare interface PluginErrorSchema {
|
|
|
504
521
|
|
|
505
522
|
/** A public raw-HTTP route a plugin serves on the framework listener. */
|
|
506
523
|
declare interface PluginHttpRoute {
|
|
507
|
-
/** HTTP method, or `'*'` for any (the handler decides).
|
|
508
|
-
*
|
|
509
|
-
*
|
|
510
|
-
*
|
|
524
|
+
/** HTTP method, or `'*'` for any (the handler decides). The server mounts the
|
|
525
|
+
* path for exactly the methods its routes declare; `'*'` mounts it for every
|
|
526
|
+
* method the router knows (34), so keep that for a route that really serves
|
|
527
|
+
* them — see `answersOtherMethods` for one that only wants to refuse them. */
|
|
511
528
|
readonly method: '*' | 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'HEAD' | 'OPTIONS';
|
|
529
|
+
/** `true`: the handler gates its own method, so a request with a method the
|
|
530
|
+
* path does not declare is still handed to it — to answer with a precise
|
|
531
|
+
* `405` and `Allow` instead of the router's `404`. The path is still mounted
|
|
532
|
+
* only for `method`. A REST route sets it. Without it, a route that declares
|
|
533
|
+
* one method never sees another. */
|
|
534
|
+
readonly answersOtherMethods?: boolean | undefined;
|
|
512
535
|
/** Absolute path, e.g. `/_voltro/storage`. Matched byte for byte: the
|
|
513
536
|
* router folds case and a trailing slash to FIND the route, the dispatcher
|
|
514
537
|
* then asks whether the request's path is one the route declared — so
|
|
@@ -1052,6 +1075,9 @@ declare interface QueryProcedureDescriptor<Name extends string, Input extends Sc
|
|
|
1052
1075
|
* `openAccess: '<why>'`. Mutually exclusive with `guards`; together they are
|
|
1053
1076
|
* the only two shapes `security.defaultDeny` accepts. */
|
|
1054
1077
|
readonly openAccess: string | undefined;
|
|
1078
|
+
/** Only these apps of the project may call this procedure — see `service` on
|
|
1079
|
+
* the definer's options. Absent → the app's own clients call it. */
|
|
1080
|
+
readonly service: ServiceSpec | undefined;
|
|
1055
1081
|
/** Opt this query into a public REST endpoint (innovation/11). */
|
|
1056
1082
|
readonly publicApi: PublicApiSpec | undefined;
|
|
1057
1083
|
/** Opt this query into the auto-synthesized agent toolset (innovation/07). */
|
|
@@ -1289,6 +1315,9 @@ export declare interface RestRouteContext {
|
|
|
1289
1315
|
* REST handlers on the same capability surface as query/mutation/action
|
|
1290
1316
|
* handlers without creating a protocol-to-runtime package dependency. */
|
|
1291
1317
|
readonly app?: unknown;
|
|
1318
|
+
/** The caller's address, resolved through `security.trustedProxies` — the
|
|
1319
|
+
* value the listener's per-IP shield counts. Absent when unknown. */
|
|
1320
|
+
readonly remoteAddr?: string;
|
|
1292
1321
|
}
|
|
1293
1322
|
|
|
1294
1323
|
export declare interface RestRouteDescriptor<I, O> {
|
|
@@ -1487,6 +1516,37 @@ export declare const routeAcceptsPath: (route: {
|
|
|
1487
1516
|
readonly match?: "prefix" | "exact" | undefined;
|
|
1488
1517
|
}, path: string) => boolean;
|
|
1489
1518
|
|
|
1519
|
+
/**
|
|
1520
|
+
* The runtime-erased form of a procedure's `service: { callers }` — "only these
|
|
1521
|
+
* apps of the project may call this, and nobody else".
|
|
1522
|
+
*
|
|
1523
|
+
* A guard entry for the reason `OpenAccessSpec` is one: every enforcement path
|
|
1524
|
+
* is handed the `guards` array and nothing else, so a decision that lived on a
|
|
1525
|
+
* separate descriptor field would be enforced by the paths somebody remembered
|
|
1526
|
+
* and skipped by the rest.
|
|
1527
|
+
*
|
|
1528
|
+
* It admits exactly a `service` subject whose name is listed. `admin:full` does
|
|
1529
|
+
* NOT bypass it: a service procedure is a machine contract between two apps,
|
|
1530
|
+
* and a browser session holding the admin scope is not one of the parties.
|
|
1531
|
+
*/
|
|
1532
|
+
declare interface ServiceAccessSpec {
|
|
1533
|
+
/** The calling apps' names, as the callee declares them in `serviceCallers`.
|
|
1534
|
+
* Non-empty by construction — the definers refuse an empty list. */
|
|
1535
|
+
readonly service: ReadonlyArray<string>;
|
|
1536
|
+
}
|
|
1537
|
+
|
|
1538
|
+
/**
|
|
1539
|
+
* A service procedure's declaration: which apps of the project may call it.
|
|
1540
|
+
*
|
|
1541
|
+
* service: { callers: ['worker'] }
|
|
1542
|
+
*
|
|
1543
|
+
* The names are the CALLING apps' names as this app lists them in
|
|
1544
|
+
* `serviceCallers` — the same name the caller's credential resolves to.
|
|
1545
|
+
*/
|
|
1546
|
+
declare interface ServiceSpec {
|
|
1547
|
+
readonly callers: ReadonlyArray<string>;
|
|
1548
|
+
}
|
|
1549
|
+
|
|
1490
1550
|
/**
|
|
1491
1551
|
* Build a streaming (Server-Sent Events) handler result. `subscribe` gets an
|
|
1492
1552
|
* `emit` for one already-framed SSE chunk and MUST return an unsubscribe, which
|
|
@@ -1555,6 +1615,14 @@ declare const Subject: Schema.Union<[Schema.Struct<{
|
|
|
1555
1615
|
tenantId: typeof Schema.Null;
|
|
1556
1616
|
scopes: Schema.optional<Schema.Array$<typeof Schema.String>>;
|
|
1557
1617
|
metadata: Schema.optional<Schema.Record$<typeof Schema.String, typeof Schema.Unknown>>;
|
|
1618
|
+
}>, Schema.Struct<{
|
|
1619
|
+
type: Schema.Literal<["service"]>;
|
|
1620
|
+
id: typeof Schema.String;
|
|
1621
|
+
/** The calling app's name, as the callee lists it in `serviceCallers`. */
|
|
1622
|
+
service: typeof Schema.String;
|
|
1623
|
+
tenantId: typeof Schema.Null;
|
|
1624
|
+
scopes: Schema.optional<Schema.Array$<typeof Schema.String>>;
|
|
1625
|
+
metadata: Schema.optional<Schema.Record$<typeof Schema.String, typeof Schema.Unknown>>;
|
|
1558
1626
|
}>]>;
|
|
1559
1627
|
|
|
1560
1628
|
declare type Subject = typeof Subject.Type;
|