@voltro/protocol 0.67.0 → 0.69.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/dist/index.d.ts CHANGED
@@ -806,6 +806,13 @@ export declare interface ClientTarget {
806
806
  readonly relations?: TargetRelations | undefined;
807
807
  }
808
808
 
809
+ /**
810
+ * Compare two shape maps. Tags present only HERE are not reported: a browser
811
+ * client group legitimately omits server-only routes, and reporting that as a
812
+ * mismatch is how a check earns the reputation that gets it turned off.
813
+ */
814
+ export declare const compareSurfaces: (mine: Readonly<Record<string, string>>, theirs: Readonly<Record<string, string>>) => SurfaceMismatch;
815
+
809
816
  export declare const composeAuthStrategies: (strategies: ReadonlyArray<AuthStrategy>, options?: {
810
817
  /** Fallback when no strategy matched. Default: returns the input's
811
818
  * tenant from `x-tenant` header or null. */
@@ -2243,6 +2250,18 @@ export declare const getResourceScopeResolver: () => ResourceScopeResolver | und
2243
2250
  */
2244
2251
  export declare const getWorkflowAccess: (definition: unknown) => WorkflowAccess;
2245
2252
 
2253
+ /**
2254
+ * Per-rpc-tag shape digests for a whole group.
2255
+ *
2256
+ * Per TAG rather than one digest for the group, for two reasons. A server's
2257
+ * bound group and a browser's client group are not the same set — server-only
2258
+ * routes exist — so a single digest would differ by construction and prove
2259
+ * nothing. And a mismatch is far more useful when it can name the procedure.
2260
+ */
2261
+ export declare const groupShapeDigests: (group: {
2262
+ readonly requests?: unknown;
2263
+ }) => Readonly<Record<string, string>>;
2264
+
2246
2265
  /** Ask for default-deny semantics on one `checkGuards` call. */
2247
2266
  export declare interface GuardCheckOptions {
2248
2267
  /** Refuse a procedure that declares no access decision at all. */
@@ -2822,6 +2841,46 @@ export declare interface OpenAccessSpec {
2822
2841
  * `openAccess: '<why>'` on the descriptor and never sees the spec. */
2823
2842
  export declare const openAccessSpec: (reason: string) => OpenAccessSpec;
2824
2843
 
2844
+ /**
2845
+ * Order the chain so a strategy that DECLARES a bearer prefix gets first
2846
+ * refusal on a token carrying it.
2847
+ *
2848
+ * WHY THIS EXISTS. The chain is first-non-skip-wins, and a `failed` ENDS it —
2849
+ * deliberately, because a credential another IdP rejected could be an attack
2850
+ * masquerading as ours. Two reasonable pieces then combined into a third thing
2851
+ * nobody chose:
2852
+ *
2853
+ * 1. `apiKeys:` appends the framework key strategy LAST.
2854
+ * 2. `jwtBearerStrategy` — and therefore all six catalog strategies
2855
+ * (supabase, auth0, clerk, kinde, oidc, workos) — claims EVERY
2856
+ * `Authorization: Bearer`. A token it cannot verify is `failed`, not
2857
+ * `skip`.
2858
+ *
2859
+ * So a valid API key was rejected by the JWT verifier before the key strategy
2860
+ * was ever asked. Nothing logged an error; the key simply never worked. A
2861
+ * consumer measured the chain as `['skip', 'failed', 'skip']` — device,
2862
+ * supabase, anonymous — with the key strategy never reached, and worked around
2863
+ * it by wrapping their own verifier to skip tokens carrying the prefix
2864
+ * `apiKeys.prefix` already declares.
2865
+ *
2866
+ * The existing boot check cannot see this: it warns when TWO strategies declare
2867
+ * the SAME prefix, and the JWT strategy declares none while claiming
2868
+ * everything. `claimsBearerPrefix`'s own doc says a JWKS strategy "claims no
2869
+ * prefix and omits it" — that combination IS the bug.
2870
+ *
2871
+ * The rule, and why it is this one rather than "continue past a failure":
2872
+ * `failed` ending the chain is a security property and stays untouched. A
2873
+ * declared prefix is a strategy saying "this token shape is MINE", which is
2874
+ * strictly more specific than a strategy that claims everything by declaring
2875
+ * nothing — so specificity decides who is asked first, and a token matching no
2876
+ * declared prefix leaves the order exactly as the app wrote it.
2877
+ *
2878
+ * Stable within each group, so two strategies sharing a prefix keep their
2879
+ * declared relative order and `assertNoBearerPrefixCollision`'s warning still
2880
+ * describes what happens.
2881
+ */
2882
+ export declare const orderByBearerPrefix: (strategies: ReadonlyArray<AuthStrategy>, headers: Readonly<Record<string, string | undefined>>) => ReadonlyArray<AuthStrategy>;
2883
+
2825
2884
  /** Split a route back into its three parts. */
2826
2885
  export declare const parseEventRoute: (route: string) => {
2827
2886
  readonly tenantId: string | null;
@@ -3493,6 +3552,10 @@ export declare interface PluginInspectEndpoint {
3493
3552
  * optional. `health` → `/_voltro/inspect/plugins/<slug>/health`.
3494
3553
  */
3495
3554
  readonly path: string;
3555
+ /** Evidence scope for successful JSON reads. When declared, the inspect
3556
+ * router attaches origin, capture time and completeness. Omit only when the
3557
+ * endpoint supplies its own observation metadata. */
3558
+ readonly scope?: 'process' | 'shared-store' | 'declaration';
3496
3559
  /** Optional human-readable description; surfaced in the dashboard. */
3497
3560
  readonly description?: string;
3498
3561
  /**
@@ -3991,6 +4054,22 @@ export declare interface PolicyGuardSpec<Input = unknown> {
3991
4054
 
3992
4055
  export declare type ProcedureDescriptor = QueryProcedureDescriptor<string, Schema.Schema.Any, Schema.Schema.Any, Schema.Schema.All> | MutationProcedureDescriptor<string, Schema.Schema.Any, Schema.Schema.Any, Schema.Schema.All> | ActionProcedureDescriptor<string, Schema.Schema.Any, Schema.Schema.Any, Schema.Schema.All> | StreamProcedureDescriptor<string, Schema.Schema.Any, Schema.Schema.Any, Schema.Schema.All>;
3993
4056
 
4057
+ /** The shape of one procedure, as the pair of peers must agree on it. */
4058
+ export declare interface ProcedureLike {
4059
+ readonly _tag: string;
4060
+ readonly payloadSchema?: {
4061
+ readonly ast?: unknown;
4062
+ } | undefined;
4063
+ readonly successSchema?: {
4064
+ readonly ast?: unknown;
4065
+ } | undefined;
4066
+ readonly errorSchema?: {
4067
+ readonly ast?: unknown;
4068
+ } | undefined;
4069
+ }
4070
+
4071
+ export declare const procedureShapeDigest: (rpc: ProcedureLike) => string;
4072
+
3994
4073
  export declare const PROTOCOL_VERSION: 1;
3995
4074
 
3996
4075
  export declare type ProtocolVersion = typeof PROTOCOL_VERSION;
@@ -4541,6 +4620,15 @@ export declare interface ScheduleFireContext {
4541
4620
  */
4542
4621
  export declare type ScheduleFireInterceptor = (next: () => Promise<void>, ctx: ScheduleFireContext) => Promise<void>;
4543
4622
 
4623
+ /**
4624
+ * A structural rendering of one schema's AST: property names, optionality and
4625
+ * nested shape, with declared names deliberately NOT standing in for content.
4626
+ *
4627
+ * Stable across two identical declarations, and it moves for any change to the
4628
+ * shape a peer would decode against.
4629
+ */
4630
+ export declare const schemaShape: (ast: unknown, depth?: number) => string;
4631
+
4544
4632
  export declare interface ScopeCache {
4545
4633
  /** The effective window in milliseconds. */
4546
4634
  readonly ttlMs: number;
@@ -4700,6 +4788,13 @@ export declare const setPolicyGuardResolver: (resolver: PolicyGuardResolver | un
4700
4788
  */
4701
4789
  export declare const setResourceScopeResolver: (resolver: ResourceScopeResolver | undefined) => void;
4702
4790
 
4791
+ /**
4792
+ * FNV-1a, 32-bit, hex. Synchronous, dependency-free, works identically in a
4793
+ * browser and in node — see the header for why a cryptographic digest is the
4794
+ * wrong tool here.
4795
+ */
4796
+ export declare const shapeDigest: (text: string) => string;
4797
+
4703
4798
  /**
4704
4799
  * Every routing key a `source:` names, flattened.
4705
4800
  *
@@ -5048,6 +5143,13 @@ export declare const subscriptionEvent: <D extends Schema.Schema.Any>(data: D) =
5048
5143
  revision: Schema.optional<typeof Schema.Number>;
5049
5144
  }>]>;
5050
5145
 
5146
+ export declare interface SurfaceMismatch {
5147
+ /** Tags both sides carry whose shapes disagree — the stale-bundle signal. */
5148
+ readonly differing: ReadonlyArray<string>;
5149
+ /** Tags the peer binds that this side does not have. */
5150
+ readonly missingHere: ReadonlyArray<string>;
5151
+ }
5152
+
5051
5153
  export declare const systemSubject: (id: string, scopes?: ReadonlyArray<string>) => Subject;
5052
5154
 
5053
5155
  /**
@@ -6469,11 +6571,11 @@ export declare type WorkflowStepInterceptor = <Success, ErrorE, R>(next: Effect.
6469
6571
  * error union with `ScopeError` / `Unauthenticated`, exactly as it does for a
6470
6572
  * mutation, and labels the strict-input refusal as a guarded procedure's.
6471
6573
  */
6472
- export declare const workflowToRpc: (workflow: {
6473
- readonly name: string;
6474
- readonly payloadSchema: Schema.Schema.Any;
6574
+ export declare const workflowToRpc: <const Name extends string, Payload extends Schema.Schema.Any>(workflow: {
6575
+ readonly name: Name;
6576
+ readonly payloadSchema: Payload;
6475
6577
  readonly errorSchema: Schema.Schema.All;
6476
- }, extraErrors?: ExtraErrors) => Rpc.Rpc<string, Schema.Schema.Any, Schema.Struct<{
6578
+ }, extraErrors?: ExtraErrors) => Rpc.Rpc<Name, Payload extends Schema.Struct.Fields ? Schema.Struct<Payload> : Payload, Schema.Struct<{
6477
6579
  /** Stable handle callers pass to `useWorkflowRun(...)`. The durable execution
6478
6580
  * id for a started run; the pending-intent id for a queued one. */
6479
6581
  id: typeof Schema.String;