capnweb-experimental-hibernation 0.6.3 → 0.6.5

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.
@@ -2853,15 +2853,16 @@ var RpcSessionImpl = class {
2853
2853
  }
2854
2854
  sendCall(id, path, args) {
2855
2855
  if (this.abortReason) throw this.abortReason;
2856
- let entry = new ImportTableEntry(this, this.imports.length, false);
2857
- this.imports.push(entry);
2858
2856
  let value = ["pipeline", id, path];
2859
2857
  if (args) {
2860
2858
  let devalue = Devaluator.devaluate(args.value, void 0, this, args);
2861
2859
  value.push(devalue[0]);
2862
2860
  }
2863
- this.send(["push", entry.importId, value]);
2864
- this.trace("sendCall", { importId: entry.importId, targetImportId: id, pathLength: path.length, hasArgs: !!args });
2861
+ const importId = this.imports.length;
2862
+ this.send(["push", importId, value]);
2863
+ const entry = new ImportTableEntry(this, importId, false);
2864
+ this.imports.push(entry);
2865
+ this.trace("sendCall", { importId, targetImportId: id, pathLength: path.length, hasArgs: !!args });
2865
2866
  return new RpcImportHook(
2866
2867
  /*isPromise=*/
2867
2868
  true,
@@ -2870,7 +2871,11 @@ var RpcSessionImpl = class {
2870
2871
  }
2871
2872
  sendStream(id, path, args) {
2872
2873
  if (this.abortReason) throw this.abortReason;
2873
- let importId = this.imports.length;
2874
+ let value = ["pipeline", id, path];
2875
+ let devalue = Devaluator.devaluate(args.value, void 0, this, args);
2876
+ value.push(devalue[0]);
2877
+ const importId = this.imports.length;
2878
+ let size = this.send(["stream", importId, value]);
2874
2879
  let entry = new ImportTableEntry(
2875
2880
  this,
2876
2881
  importId,
@@ -2880,10 +2885,6 @@ var RpcSessionImpl = class {
2880
2885
  entry.remoteRefcount = 0;
2881
2886
  entry.localRefcount = 1;
2882
2887
  this.imports.push(entry);
2883
- let value = ["pipeline", id, path];
2884
- let devalue = Devaluator.devaluate(args.value, void 0, this, args);
2885
- value.push(devalue[0]);
2886
- let size = this.send(["stream", importId, value]);
2887
2888
  this.trace("sendStream", { importId, targetImportId: id, pathLength: path.length, size });
2888
2889
  let promise = entry.awaitResolution().then(
2889
2890
  (p) => {
@@ -2905,18 +2906,19 @@ var RpcSessionImpl = class {
2905
2906
  throw this.abortReason;
2906
2907
  }
2907
2908
  let devaluedCaptures = captures.map((hook) => {
2908
- let importId = this.getImport(hook);
2909
- if (importId !== void 0) {
2910
- return ["import", importId];
2909
+ let importId2 = this.getImport(hook);
2910
+ if (importId2 !== void 0) {
2911
+ return ["import", importId2];
2911
2912
  } else {
2912
2913
  return ["export", this.exportStub(hook)];
2913
2914
  }
2914
2915
  });
2915
2916
  let value = ["remap", id, path, devaluedCaptures, instructions];
2916
- let entry = new ImportTableEntry(this, this.imports.length, false);
2917
+ const importId = this.imports.length;
2918
+ this.send(["push", importId, value]);
2919
+ const entry = new ImportTableEntry(this, importId, false);
2917
2920
  this.imports.push(entry);
2918
- this.send(["push", entry.importId, value]);
2919
- this.trace("sendMap", { importId: entry.importId, targetImportId: id, pathLength: path.length, captureCount: captures.length });
2921
+ this.trace("sendMap", { importId, targetImportId: id, pathLength: path.length, captureCount: captures.length });
2920
2922
  return new RpcImportHook(
2921
2923
  /*isPromise=*/
2922
2924
  true,
@@ -2989,8 +2991,9 @@ var RpcSessionImpl = class {
2989
2991
  case "push":
2990
2992
  if (msg.length > 2 && typeof msg[1] === "number") {
2991
2993
  let exportId = msg[1];
2994
+ let sourceExpr = cloneRpcExpr(msg[2]);
2992
2995
  if (containsImportedCapabilityReference(msg[2])) {
2993
- this.importReplays.push({ expr: cloneRpcExpr(msg[2]) });
2996
+ this.importReplays.push({ expr: sourceExpr });
2994
2997
  this.trace("readLoop.push.recordImportReplay", {
2995
2998
  exportId,
2996
2999
  replayCount: this.importReplays.length
@@ -3002,7 +3005,7 @@ var RpcSessionImpl = class {
3002
3005
  this.replacePositiveExport(exportId, {
3003
3006
  hook,
3004
3007
  refcount: 1,
3005
- sourceExpr: cloneRpcExpr(msg[2])
3008
+ sourceExpr
3006
3009
  });
3007
3010
  this.trace("readLoop.push", { exportId, hookType: hook.constructor?.name ?? null });
3008
3011
  continue;
@@ -3011,13 +3014,14 @@ var RpcSessionImpl = class {
3011
3014
  case "stream": {
3012
3015
  if (msg.length > 2 && typeof msg[1] === "number") {
3013
3016
  let exportId = msg[1];
3017
+ let sourceExpr = cloneRpcExpr(msg[2]);
3014
3018
  let payload = this.evaluateWithCurrentProvenance(msg[2]);
3015
3019
  let hook = new PayloadStubHook(payload);
3016
3020
  hook.ignoreUnhandledRejections();
3017
3021
  this.replacePositiveExport(exportId, {
3018
3022
  hook,
3019
3023
  refcount: 1,
3020
- sourceExpr: cloneRpcExpr(msg[2]),
3024
+ sourceExpr,
3021
3025
  autoRelease: true
3022
3026
  });
3023
3027
  this.trace("readLoop.stream", { exportId, hookType: hook.constructor?.name ?? null });
@@ -3386,7 +3390,10 @@ async function __experimental_newHibernatableWebSocketRpcSession(webSocket, loca
3386
3390
  webSocket.close(1011, "stale session");
3387
3391
  } catch {
3388
3392
  }
3389
- throw err;
3393
+ if (options.sessionStore) {
3394
+ await options.sessionStore.delete(sessionId);
3395
+ }
3396
+ return void 0;
3390
3397
  }
3391
3398
  throw err;
3392
3399
  }
@@ -3410,6 +3417,11 @@ async function __experimental_newHibernatableWebSocketRpcSession(webSocket, loca
3410
3417
  },
3411
3418
  handleClose(code, reason, wasClean) {
3412
3419
  transport.notifyClosed(code, reason, wasClean);
3420
+ if (options.sessionStore) {
3421
+ options.sessionStore.delete(sessionId).catch((err) => {
3422
+ console.error(`[capnweb] Failed to delete session ${sessionId} from store:`, err);
3423
+ });
3424
+ }
3413
3425
  },
3414
3426
  handleError(error) {
3415
3427
  transport.notifyError(error);
@@ -3418,24 +3430,35 @@ async function __experimental_newHibernatableWebSocketRpcSession(webSocket, loca
3418
3430
  async function persistSnapshot() {
3419
3431
  try {
3420
3432
  let snap = rpc.__experimental_snapshot();
3421
- webSocket.serializeAttachment?.({
3422
- sessionId,
3423
- version: 1,
3424
- snapshot: snap
3425
- });
3426
3433
  if (options.sessionStore) {
3427
3434
  await options.sessionStore.save(sessionId, snap);
3428
3435
  }
3436
+ let capnwebData = options.sessionStore ? { sessionId, version: 1 } : { sessionId, version: 1, snapshot: snap };
3437
+ let existing = webSocket.deserializeAttachment?.() ?? {};
3438
+ if (typeof existing !== "object" || existing === null) existing = {};
3439
+ webSocket.serializeAttachment?.({ ...existing, __capnweb: capnwebData });
3429
3440
  } catch (err) {
3430
3441
  transport.abort?.(err);
3431
3442
  }
3432
3443
  }
3433
3444
  }
3445
+ async function __experimental_cleanupOrphanedSessions(webSockets, sessionStore) {
3446
+ if (!sessionStore.deleteOrphans) return 0;
3447
+ const liveIds = /* @__PURE__ */ new Set();
3448
+ for (const ws of webSockets) {
3449
+ const attachment = getAttachment(ws);
3450
+ if (attachment?.sessionId) {
3451
+ liveIds.add(attachment.sessionId);
3452
+ }
3453
+ }
3454
+ return sessionStore.deleteOrphans(liveIds);
3455
+ }
3434
3456
  async function __experimental_resumeHibernatableWebSocketRpcSession(webSocket, localMain, options) {
3435
3457
  return __experimental_newHibernatableWebSocketRpcSession(webSocket, localMain, options);
3436
3458
  }
3437
3459
  function getAttachment(webSocket) {
3438
- let attachment = webSocket.deserializeAttachment?.();
3460
+ let raw = webSocket.deserializeAttachment?.();
3461
+ let attachment = raw?.__capnweb ?? raw;
3439
3462
  if (attachment?.version === 1 && typeof attachment.sessionId === "string") {
3440
3463
  return attachment;
3441
3464
  }
@@ -3514,7 +3537,11 @@ var WebSocketTransport = class {
3514
3537
  if (reason instanceof Error) {
3515
3538
  message = reason.message;
3516
3539
  } else {
3517
- message = `${reason}`;
3540
+ try {
3541
+ message = JSON.stringify(reason);
3542
+ } catch {
3543
+ message = `${reason}`;
3544
+ }
3518
3545
  }
3519
3546
  this.#webSocket.close(3e3, message);
3520
3547
  if (!this.#error) {
@@ -3599,7 +3626,11 @@ var HibernatableWebSocketTransport = class {
3599
3626
  if (reason instanceof Error) {
3600
3627
  message = reason.message;
3601
3628
  } else {
3602
- message = `${reason}`;
3629
+ try {
3630
+ message = JSON.stringify(reason);
3631
+ } catch {
3632
+ message = `${reason}`;
3633
+ }
3603
3634
  }
3604
3635
  try {
3605
3636
  this.webSocket.close(3e3, message);
@@ -4190,7 +4221,22 @@ function __experimental_newDurableObjectSessionStore(storage, prefix = "capnweb:
4190
4221
  await storage.put(`${prefix}${sessionId}`, snapshot);
4191
4222
  },
4192
4223
  async delete(sessionId) {
4193
- await storage.delete?.(`${prefix}${sessionId}`);
4224
+ await storage.delete(`${prefix}${sessionId}`);
4225
+ },
4226
+ async deleteOrphans(liveSessionIds) {
4227
+ if (!storage.list) return 0;
4228
+ const stored = await storage.list({ prefix });
4229
+ const orphanKeys = [];
4230
+ for (const key of stored.keys()) {
4231
+ const sessionId = key.slice(prefix.length);
4232
+ if (!liveSessionIds.has(sessionId)) {
4233
+ orphanKeys.push(key);
4234
+ }
4235
+ }
4236
+ if (orphanKeys.length > 0) {
4237
+ await storage.delete(orphanKeys);
4238
+ }
4239
+ return orphanKeys.length;
4194
4240
  }
4195
4241
  };
4196
4242
  }
@@ -4203,6 +4249,7 @@ var newHttpBatchRpcSession2 = newHttpBatchRpcSession;
4203
4249
  var newMessagePortRpcSession2 = newMessagePortRpcSession;
4204
4250
  var __experimental_newHibernatableWebSocketRpcSession2 = __experimental_newHibernatableWebSocketRpcSession;
4205
4251
  var __experimental_resumeHibernatableWebSocketRpcSession2 = __experimental_resumeHibernatableWebSocketRpcSession;
4252
+ var __experimental_cleanupOrphanedSessions2 = __experimental_cleanupOrphanedSessions;
4206
4253
  var __experimental_debugRpcReference2 = __experimental_debugRpcReference;
4207
4254
  async function newWorkersRpcResponse(request, localMain) {
4208
4255
  if (request.method === "POST") {
@@ -4220,6 +4267,7 @@ exports.RpcPromise = RpcPromise2;
4220
4267
  exports.RpcSession = RpcSession2;
4221
4268
  exports.RpcStub = RpcStub2;
4222
4269
  exports.RpcTarget = RpcTarget4;
4270
+ exports.__experimental_cleanupOrphanedSessions = __experimental_cleanupOrphanedSessions2;
4223
4271
  exports.__experimental_debugRpcReference = __experimental_debugRpcReference2;
4224
4272
  exports.__experimental_newDurableObjectSessionStore = __experimental_newDurableObjectSessionStore;
4225
4273
  exports.__experimental_newHibernatableWebSocketRpcSession = __experimental_newHibernatableWebSocketRpcSession2;