@voltro/protocol 0.24.0 → 0.26.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/rest.d.ts CHANGED
@@ -31,6 +31,28 @@ declare interface ActionProcedureDescriptor<Name extends string, Input extends S
31
31
  readonly exposeAsTool: ExposeAsTool | undefined;
32
32
  /** True when the procedure is kept OFF the wire — no client-group entry and no
33
33
  * route in dev or serve. See `internal` on the definer's options. */
34
+ /**
35
+ * Replace a PLUGIN route that answers to this same tag.
36
+ *
37
+ * Without it, a user route and a plugin route sharing a tag is a hard error,
38
+ * and correctly so — two handlers behind one name is not a thing a caller can
39
+ * reason about. But refusing is the wrong answer when the app deliberately
40
+ * wants its own version: the two escapes available otherwise are to rename
41
+ * your procedure (so the split runs along "who built it" rather than along a
42
+ * domain boundary) or to `alias` the whole plugin away (same, one level up).
43
+ * For a frontend developer that is the worst possible partition.
44
+ *
45
+ * A reporter wanted exactly this: adopt `@voltro/plugin-notifications`, whose
46
+ * surface is richer than theirs, add `archive`/`unarchive` beside it — which
47
+ * already composes, since the collision check compares FULL tags and not
48
+ * prefixes — and replace `markRead`, because theirs maintains archive state.
49
+ *
50
+ * Explicit, never inferred. Silently letting the app win would mean a plugin
51
+ * upgrade that adds a route could shadow an app procedure with no diff to
52
+ * read; declaring it makes the intent reviewable and puts the override in the
53
+ * file that performs it.
54
+ */
55
+ readonly overridesPlugin: boolean | undefined;
34
56
  readonly internal: boolean | undefined;
35
57
  }
36
58
 
@@ -209,6 +231,28 @@ declare interface MutationProcedureDescriptor<Name extends string, Input extends
209
231
  readonly exposeAsTool: ExposeAsTool | undefined;
210
232
  /** True when the procedure is kept OFF the wire — no client-group entry and no
211
233
  * route in dev or serve. See `internal` on the definer's options. */
234
+ /**
235
+ * Replace a PLUGIN route that answers to this same tag.
236
+ *
237
+ * Without it, a user route and a plugin route sharing a tag is a hard error,
238
+ * and correctly so — two handlers behind one name is not a thing a caller can
239
+ * reason about. But refusing is the wrong answer when the app deliberately
240
+ * wants its own version: the two escapes available otherwise are to rename
241
+ * your procedure (so the split runs along "who built it" rather than along a
242
+ * domain boundary) or to `alias` the whole plugin away (same, one level up).
243
+ * For a frontend developer that is the worst possible partition.
244
+ *
245
+ * A reporter wanted exactly this: adopt `@voltro/plugin-notifications`, whose
246
+ * surface is richer than theirs, add `archive`/`unarchive` beside it — which
247
+ * already composes, since the collision check compares FULL tags and not
248
+ * prefixes — and replace `markRead`, because theirs maintains archive state.
249
+ *
250
+ * Explicit, never inferred. Silently letting the app win would mean a plugin
251
+ * upgrade that adds a route could shadow an app procedure with no diff to
252
+ * read; declaring it makes the intent reviewable and puts the override in the
253
+ * file that performs it.
254
+ */
255
+ readonly overridesPlugin: boolean | undefined;
212
256
  readonly internal: boolean | undefined;
213
257
  }
214
258
 
@@ -517,6 +561,28 @@ declare interface QueryProcedureDescriptor<Name extends string, Input extends Sc
517
561
  readonly exposeAsTool: ExposeAsTool | undefined;
518
562
  /** True when the procedure is kept OFF the wire — no client-group entry and no
519
563
  * route in dev or serve. See `internal` on the definer's options. */
564
+ /**
565
+ * Replace a PLUGIN route that answers to this same tag.
566
+ *
567
+ * Without it, a user route and a plugin route sharing a tag is a hard error,
568
+ * and correctly so — two handlers behind one name is not a thing a caller can
569
+ * reason about. But refusing is the wrong answer when the app deliberately
570
+ * wants its own version: the two escapes available otherwise are to rename
571
+ * your procedure (so the split runs along "who built it" rather than along a
572
+ * domain boundary) or to `alias` the whole plugin away (same, one level up).
573
+ * For a frontend developer that is the worst possible partition.
574
+ *
575
+ * A reporter wanted exactly this: adopt `@voltro/plugin-notifications`, whose
576
+ * surface is richer than theirs, add `archive`/`unarchive` beside it — which
577
+ * already composes, since the collision check compares FULL tags and not
578
+ * prefixes — and replace `markRead`, because theirs maintains archive state.
579
+ *
580
+ * Explicit, never inferred. Silently letting the app win would mean a plugin
581
+ * upgrade that adds a route could shadow an app procedure with no diff to
582
+ * read; declaring it makes the intent reviewable and puts the override in the
583
+ * file that performs it.
584
+ */
585
+ readonly overridesPlugin: boolean | undefined;
520
586
  readonly internal: boolean | undefined;
521
587
  }
522
588
 
package/dist/session.d.ts CHANGED
@@ -108,6 +108,33 @@ export declare const resolveSessionSecret: () => string;
108
108
  */
109
109
  export declare const resolveSessionSecrets: () => SessionSecrets;
110
110
 
111
+ /**
112
+ * The cookie the framework's own session strategy writes and reads.
113
+ *
114
+ * Exported and single-sourced because two readers now need it — the auth
115
+ * strategy in `dev.ts` and `sessionExpiryFromHeaders` below. Two copies of one
116
+ * env expression is the "derived twice" shape: both sites look correct and
117
+ * they disagree the moment someone sets the variable.
118
+ */
119
+ export declare const SESSION_COOKIE_NAME: string;
120
+
121
+ /**
122
+ * The verified expiry of the session cookie in `headers`, in unix SECONDS, or
123
+ * `undefined` when there is no session or it does not verify.
124
+ *
125
+ * It VERIFIES rather than decoding. An unverified read would be worse than
126
+ * nothing here: the value bounds how long a subscription may live, so a client
127
+ * that could forge a far-future `exp` would lift exactly the ceiling this
128
+ * exists to impose. The cost is one HMAC check on a call that already carries
129
+ * the cookie.
130
+ *
131
+ * A SHARED builder on purpose. `voltro dev` and `voltro serve` assemble their
132
+ * middleware independently, and a value derived twice is the shape this repo
133
+ * has been bitten by — dev and serve agreeing on a field while disagreeing on
134
+ * what it contains. Both call this.
135
+ */
136
+ export declare const sessionExpiryFromHeaders: (headers: Record<string, string | undefined>) => number | undefined;
137
+
111
138
  export declare type SessionPayload = typeof SessionPayload_2.Type;
112
139
 
113
140
  declare const SessionPayload_2: Schema.Struct<{
package/dist/session.js CHANGED
@@ -106,6 +106,11 @@ var i = t.Struct({
106
106
  e >= 0 && r.splice(e, 1);
107
107
  }
108
108
  return r.push(`SameSite=${n.sameSite ?? "Lax"}`), (n.secure ?? !0) && r.push("Secure"), n.domain && r.push(`Domain=${n.domain}`), r.join("; ");
109
+ }, A = process.env.VOLTRO_SESSION_COOKIE ?? "voltro:session", j = (e) => {
110
+ let t = O(e.cookie ?? e.Cookie, A);
111
+ if (!t) return;
112
+ let n = d();
113
+ if (n) return T(t, n)?.exp;
109
114
  };
110
115
  //#endregion
111
- export { o as DEFAULT_PREVIOUS_SESSION_KID, a as DEFAULT_SESSION_KID, f as MIN_SESSION_SECRET_LENGTH, p as assertProductionSessionSecret, k as buildSetCookie, D as checkBearer, O as readCookie, d as resolveOptionalSessionSecrets, c as resolveSessionSecret, l as resolveSessionSecrets, S as signSession, E as timingSafeStringEqual, w as verifySession, T as verifySessionKeyed };
116
+ export { o as DEFAULT_PREVIOUS_SESSION_KID, a as DEFAULT_SESSION_KID, f as MIN_SESSION_SECRET_LENGTH, A as SESSION_COOKIE_NAME, p as assertProductionSessionSecret, k as buildSetCookie, D as checkBearer, O as readCookie, d as resolveOptionalSessionSecrets, c as resolveSessionSecret, l as resolveSessionSecrets, j as sessionExpiryFromHeaders, S as signSession, E as timingSafeStringEqual, w as verifySession, T as verifySessionKeyed };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@voltro/protocol",
3
- "version": "0.24.0",
3
+ "version": "0.26.0",
4
4
  "description": "The Voltro wire + plugin contract — defineQuery/Mutation/Action/Stream, definePlugin, sessions / JWT / API-keys, and the RPC protocol.",
5
5
  "keywords": [
6
6
  "voltro",
@@ -53,7 +53,7 @@
53
53
  },
54
54
  "dependencies": {
55
55
  "@effect/sql": "^0.52.0",
56
- "@voltro/database": "0.24.0",
56
+ "@voltro/database": "0.26.0",
57
57
  "jose": "^6.2.4"
58
58
  },
59
59
  "peerDependencies": {