@ultimat3/realtime 25.2.0 → 26.1.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/CLAUDE.md CHANGED
@@ -284,7 +284,7 @@ Tier 3 package. Channels, live queries, local-first sync. One protocol for all t
284
284
 
285
285
  ## The page boot
286
286
 
287
- - **The disk boot is ONE page script (`boot.ts`, `./boot`)**, served at `/_x/page-boot/<hash>.js`
287
+ - **The disk boot is ONE page script (`boot.ts`)**, at `/_x/assets/page-boot/<hash>.js`
288
288
  on a document with the scope tag and a realtime island; it installs the runtime, wipes every other
289
289
  principal's stored scope (read at the wipe), then restores. `booted` reads its promise off
290
290
  `Symbol.for('ultimate.page-boot')`. No boot: islands load its chunk.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ultimat3/realtime",
3
- "version": "25.2.0",
3
+ "version": "26.1.0",
4
4
  "description": "Three-tier realtime: channels, live queries, local-first sync — one protocol, one mutator shape",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -40,10 +40,10 @@
40
40
  "test": "bun test"
41
41
  },
42
42
  "dependencies": {
43
- "@ultimat3/core": "25.2.0",
44
- "@ultimat3/entity": "25.2.0",
45
- "@ultimat3/policy": "25.2.0",
46
- "@ultimat3/query": "25.2.0",
43
+ "@ultimat3/core": "26.1.0",
44
+ "@ultimat3/entity": "26.1.0",
45
+ "@ultimat3/policy": "26.1.0",
46
+ "@ultimat3/query": "26.1.0",
47
47
  "nats": "2.29.3"
48
48
  }
49
49
  }
package/src/errors.ts CHANGED
@@ -282,7 +282,7 @@ export class LiveRowUnidentifiedError extends RealtimeError {
282
282
  cause: `live query "${args.query}" returned a row whose id is a ${args.idType}, not text or a safe integer — a live row is addressed by a text id, so project the key as text (a uuid or text column) or drop live: true from the query`,
283
283
  // A name the shell would not read verbatim does not travel: the list names it instead.
284
284
  fix: isFixShellSafe(args.query)
285
- ? `x queries describe ${renderFixShellArg(args.query, 'name')} --json`
285
+ ? `x queries show ${renderFixShellArg(args.query, 'name')} --json`
286
286
  : 'x queries list --json',
287
287
  },
288
288
  );
@@ -72,7 +72,7 @@ export class RecordRejectedError extends RealtimeError {
72
72
  super({
73
73
  code: 'X_RECORD_REJECTED',
74
74
  cause: `a ${args.type === '' ? 'record' : `"${args.type}" record`} was rejected by the page's record store: ${args.reason}`,
75
- fix: `x entities describe ${renderFixShellArg(args.type, '<entity>')} --json # the primary key every row of it must carry; return whole rows from the handler that built this one`,
75
+ fix: `x entities show ${renderFixShellArg(args.type, '<entity>')} --json # the primary key every row of it must carry; return whole rows from the handler that built this one`,
76
76
  });
77
77
  }
78
78
  }
@@ -7,8 +7,8 @@ import { deferredScriptsPending, peekPageRealtime } from './page-store';
7
7
 
8
8
  export interface AwaitPageRuntimeOptions {
9
9
  /**
10
- * The path every page boot is served under (`/_x/page-boot/`). A `<script>` whose `src` starts
11
- * with it is the boot this document carries, and the runtime is coming with it.
10
+ * The path every page boot is served under (`/_x/assets/page-boot/`). A `<script>` whose `src`
11
+ * starts with it is the boot this document carries, and the runtime is coming with it.
12
12
  */
13
13
  readonly boot: string;
14
14
  /** Imports the runtime chunk — only on a page whose boot is absent, or never ran. */
@@ -115,11 +115,28 @@ export interface UpgradeDeps {
115
115
  /**
116
116
  * `undefined` means the upgrade took and Bun owns the connection now. Async because `authenticate`
117
117
  * is: the credential is decided *before* `server.upgrade`, so a refused one never costs a websocket.
118
+ *
119
+ * Every answer that is NOT a socket is `no-store`, whatever it is: a response with no
120
+ * `cache-control` is one a CDN applies its own default TTL to, and this role sits behind an
121
+ * operator's routing rule that can send it what it does not serve — a page asset misrouted here
122
+ * came back `404 not found`, and the edge kept that miss for four hours after the fix.
118
123
  */
119
124
  export async function handleUpgrade(
120
125
  deps: UpgradeDeps,
121
126
  request: Request,
122
127
  server: UpgradeTarget,
128
+ ): Promise<Response | undefined> {
129
+ const response = await answerUpgrade(deps, request, server);
130
+ if (response !== undefined && !response.headers.has('cache-control')) {
131
+ response.headers.set('cache-control', 'no-store');
132
+ }
133
+ return response;
134
+ }
135
+
136
+ async function answerUpgrade(
137
+ deps: UpgradeDeps,
138
+ request: Request,
139
+ server: UpgradeTarget,
123
140
  ): Promise<Response | undefined> {
124
141
  const url = new URL(request.url);
125
142
  // Health is the process's, readiness is this node's: a draining node stays healthy while it hands
@@ -1,6 +1,6 @@
1
1
  // The SharedWorker entry (plan 101, slice 11): every tab of this origin and principal connects a
2
2
  // port, and the one engine behind them holds the one socket. `x build` bundles this file as a
3
- // classic script at `/_x/sync-worker/<hash>.js`. No other code lives here.
3
+ // classic script at `/_x/assets/sync-worker/<hash>.js`. No other code lives here.
4
4
 
5
5
  import { browserSocket, dialUrl } from './browser-socket';
6
6
  import { messagePort, SocketEngine } from './socket-engine';