memeloop 0.2.8 → 0.2.9

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.
Files changed (36) hide show
  1. package/dist/{chunk-NVJCRIEK.js → chunk-34B7MUI6.js} +2 -2
  2. package/dist/{chunk-DACM5AMS.js → chunk-7W4FMKMO.js} +190 -56
  3. package/dist/chunk-7W4FMKMO.js.map +1 -0
  4. package/dist/{chunk-OD6U6VAR.js → chunk-GH5RDPLJ.js} +2 -2
  5. package/dist/{chunk-OD6U6VAR.js.map → chunk-GH5RDPLJ.js.map} +1 -1
  6. package/dist/device-network/cloudDeviceFetchClient.d.ts +9 -7
  7. package/dist/device-network/cloudDeviceFetchClient.d.ts.map +1 -1
  8. package/dist/device-network/deviceCloudConnectionCoordinator.d.ts +5 -5
  9. package/dist/device-network/deviceCloudConnectionCoordinator.d.ts.map +1 -1
  10. package/dist/device-network/deviceOrchestrationTransport.d.ts +7 -0
  11. package/dist/device-network/deviceOrchestrationTransport.d.ts.map +1 -1
  12. package/dist/device-network/standardDeviceCloudConnectionAdapter.d.ts +16 -8
  13. package/dist/device-network/standardDeviceCloudConnectionAdapter.d.ts.map +1 -1
  14. package/dist/device-network/types.d.ts +4 -2
  15. package/dist/device-network/types.d.ts.map +1 -1
  16. package/dist/device-network-portable.cjs +190 -55
  17. package/dist/device-network-portable.cjs.map +1 -1
  18. package/dist/device-network-portable.js +189 -55
  19. package/dist/device-network-portable.js.map +1 -1
  20. package/dist/device-network.cjs +190 -55
  21. package/dist/device-network.cjs.map +1 -1
  22. package/dist/device-network.js +4 -2
  23. package/dist/index.cjs +488 -180
  24. package/dist/index.cjs.map +1 -1
  25. package/dist/index.js +302 -127
  26. package/dist/index.js.map +1 -1
  27. package/dist/loop-api.cjs +1 -1
  28. package/dist/loop-api.cjs.map +1 -1
  29. package/dist/loop-api.js +1 -1
  30. package/dist/mobile.cjs.map +1 -1
  31. package/dist/orchestration/externalOrchestrationController.d.ts.map +1 -1
  32. package/dist/orchestration/workloadExecutionController.d.ts.map +1 -1
  33. package/dist/plugin/loader.d.ts +1 -1
  34. package/package.json +2 -1
  35. package/dist/chunk-DACM5AMS.js.map +0 -1
  36. /package/dist/{chunk-NVJCRIEK.js.map → chunk-34B7MUI6.js.map} +0 -0
package/dist/index.cjs CHANGED
@@ -16496,10 +16496,54 @@ function createExternalOrchestrationController(store, options) {
16496
16496
  const now = options.now ?? (() => /* @__PURE__ */ new Date());
16497
16497
  const onError = options.onError ?? (() => {
16498
16498
  });
16499
- const active = /* @__PURE__ */ new Set();
16499
+ const active = /* @__PURE__ */ new Map();
16500
16500
  const activeByDriver = /* @__PURE__ */ new Map();
16501
16501
  const watchAbort = new AbortController();
16502
+ const stoppedError = new OrchestrationError({
16503
+ code: "CANCELLED",
16504
+ message: "external orchestration controller stopped",
16505
+ retryable: false
16506
+ });
16507
+ let resolveStopped;
16508
+ const stoppedBoundary = new Promise((resolve) => {
16509
+ resolveStopped = resolve;
16510
+ });
16502
16511
  let stopped = false;
16512
+ let stopPromise;
16513
+ function throwIfStopped() {
16514
+ if (stopped) throw stoppedError;
16515
+ }
16516
+ async function whileRunning(operation) {
16517
+ throwIfStopped();
16518
+ const operationResult = Promise.resolve().then(operation).then(
16519
+ (value) => ({ kind: "value", value }),
16520
+ (error2) => ({
16521
+ kind: "error",
16522
+ error: error2 instanceof Error ? error2 : new Error(safeErrorMessageFromUnknown(error2))
16523
+ })
16524
+ );
16525
+ const result = await Promise.race([operationResult, stoppedBoundary]);
16526
+ if (result.kind === "stopped") throw stoppedError;
16527
+ if (result.kind === "error") throw result.error;
16528
+ return result.value;
16529
+ }
16530
+ function reportUnlessStopped(error2) {
16531
+ if (!stopped && error2 !== stoppedError) onError(error2);
16532
+ }
16533
+ async function drainWithDeadline(tasks) {
16534
+ let timeout;
16535
+ try {
16536
+ await Promise.race([
16537
+ Promise.allSettled(tasks).then(() => {
16538
+ }),
16539
+ new Promise((resolve) => {
16540
+ timeout = setTimeout(resolve, 1e3);
16541
+ })
16542
+ ]);
16543
+ } finally {
16544
+ if (timeout) clearTimeout(timeout);
16545
+ }
16546
+ }
16503
16547
  async function acquireDriverSlot(entry) {
16504
16548
  const limit = entry.capabilities.maxConcurrency;
16505
16549
  while (!stopped) {
@@ -16508,7 +16552,7 @@ function createExternalOrchestrationController(store, options) {
16508
16552
  activeByDriver.set(entry.name, current + 1);
16509
16553
  return true;
16510
16554
  }
16511
- await sleep(pollIntervalMs);
16555
+ await whileRunning(() => sleep(pollIntervalMs));
16512
16556
  }
16513
16557
  return false;
16514
16558
  }
@@ -16538,7 +16582,7 @@ function createExternalOrchestrationController(store, options) {
16538
16582
  }
16539
16583
  async function ensureRun(workload) {
16540
16584
  const reference = runReferenceOf(workload);
16541
- if (await store.get(reference)) return reference;
16585
+ if (await whileRunning(() => store.get(reference))) return reference;
16542
16586
  const manifest2 = createAgentRunManifest(reference.name, {
16543
16587
  workloadRef: {
16544
16588
  apiVersion: workload.apiVersion,
@@ -16550,7 +16594,7 @@ function createExternalOrchestrationController(store, options) {
16550
16594
  });
16551
16595
  manifest2.metadata.namespace = workload.metadata.namespace;
16552
16596
  try {
16553
- await store.create(options.actor, manifest2);
16597
+ await whileRunning(() => store.create(options.actor, manifest2));
16554
16598
  } catch (error2) {
16555
16599
  if (!(error2 instanceof OrchestrationError) || error2.code !== "CONFLICT") throw error2;
16556
16600
  }
@@ -16558,12 +16602,14 @@ function createExternalOrchestrationController(store, options) {
16558
16602
  }
16559
16603
  async function updateStatus(reference, patch) {
16560
16604
  for (let attempt = 0; attempt < statusWriteAttempts; attempt += 1) {
16561
- const current = await store.get(reference);
16605
+ const current = await whileRunning(() => store.get(reference));
16562
16606
  if (!current) return;
16563
16607
  try {
16564
- await store.updateStatus(options.actor, reference, patch(current.status), {
16565
- resourceVersion: current.metadata.resourceVersion
16566
- });
16608
+ await whileRunning(
16609
+ () => store.updateStatus(options.actor, reference, patch(current.status), {
16610
+ resourceVersion: current.metadata.resourceVersion
16611
+ })
16612
+ );
16567
16613
  return;
16568
16614
  } catch (error2) {
16569
16615
  if (error2 instanceof OrchestrationError && error2.code === "CONFLICT") continue;
@@ -16603,6 +16649,7 @@ function createExternalOrchestrationController(store, options) {
16603
16649
  return entry;
16604
16650
  }
16605
16651
  async function fail5(resource, error2) {
16652
+ throwIfStopped();
16606
16653
  const message = safeErrorMessageFromUnknown(error2, { fallback: "External orchestration failed" });
16607
16654
  if (resource.kind === AGENT_WORKLOAD_KIND) {
16608
16655
  await updateStatus(runReferenceOf(resource), () => ({
@@ -16675,6 +16722,7 @@ function createExternalOrchestrationController(store, options) {
16675
16722
  return terminal;
16676
16723
  }
16677
16724
  async function reconcileWorkload(resource) {
16725
+ throwIfStopped();
16678
16726
  const entry = findDriver(resource);
16679
16727
  const runtime = resolveExternalWorkloadRuntime(
16680
16728
  resource,
@@ -16683,7 +16731,7 @@ function createExternalOrchestrationController(store, options) {
16683
16731
  resolveExternalWorkloadResources(resource, runtime);
16684
16732
  const reference = referenceOf(resource);
16685
16733
  const runReference = await ensureRun(resource);
16686
- const latest = await store.get(reference);
16734
+ const latest = await whileRunning(() => store.get(reference));
16687
16735
  let externalId = latest?.status?.externalId ?? resource.status?.externalId;
16688
16736
  if (!externalId) {
16689
16737
  if (!options.authorizeWorkloadPlacement) {
@@ -16693,8 +16741,8 @@ function createExternalOrchestrationController(store, options) {
16693
16741
  retryable: false
16694
16742
  });
16695
16743
  }
16696
- const authorization = await options.authorizeWorkloadPlacement(resource, entry);
16697
- const health = await entry.driver.getHealth();
16744
+ const authorization = await whileRunning(() => options.authorizeWorkloadPlacement(resource, entry, watchAbort.signal));
16745
+ const health = await whileRunning(() => entry.driver.getHealth());
16698
16746
  if (!health.healthy) {
16699
16747
  throw new OrchestrationError({ code: "UNAVAILABLE", message: `external orchestrator '${entry.name}' is unhealthy`, retryable: true });
16700
16748
  }
@@ -16707,21 +16755,25 @@ function createExternalOrchestrationController(store, options) {
16707
16755
  placementPolicyDigest: authorization.policyDigest
16708
16756
  }));
16709
16757
  let scriptSource;
16710
- if (resource.spec.scriptReference) {
16711
- scriptSource = await options.resolveScriptSource?.(resource.spec.scriptReference);
16758
+ const scriptReference = resource.spec.scriptReference;
16759
+ if (scriptReference) {
16760
+ scriptSource = await whileRunning(async () => options.resolveScriptSource?.(scriptReference));
16712
16761
  if (scriptSource === void 0) {
16713
16762
  throw new OrchestrationError({
16714
16763
  code: "NOT_FOUND",
16715
- message: `script artifact '${resource.spec.scriptReference}' is unavailable for external placement`,
16764
+ message: `script artifact '${scriptReference}' is unavailable for external placement`,
16716
16765
  retryable: false
16717
16766
  });
16718
16767
  }
16719
16768
  }
16720
- const workerBootstrap = await options.createWorkerBootstrap?.(resource, runReference);
16721
- const placed = await entry.driver.placeWorkload(resource, options.actor, {
16722
- ...scriptSource !== void 0 ? { scriptSource } : {},
16723
- ...workerBootstrap !== void 0 ? { workerBootstrap } : {}
16724
- });
16769
+ const workerBootstrap = await whileRunning(async () => options.createWorkerBootstrap?.(resource, runReference));
16770
+ const placed = await whileRunning(
16771
+ () => entry.driver.placeWorkload(resource, options.actor, {
16772
+ ...scriptSource !== void 0 ? { scriptSource } : {},
16773
+ ...workerBootstrap !== void 0 ? { workerBootstrap } : {},
16774
+ signal: watchAbort.signal
16775
+ })
16776
+ );
16725
16777
  externalId = placed.externalId;
16726
16778
  await updateStatus(reference, (current) => ({
16727
16779
  ...current,
@@ -16735,12 +16787,13 @@ function createExternalOrchestrationController(store, options) {
16735
16787
  await updateStatus(runReference, () => ({ phase: "Running" }));
16736
16788
  }
16737
16789
  while (!stopped) {
16738
- const external = await entry.driver.getWorkloadStatus(externalId);
16790
+ const external = await whileRunning(() => entry.driver.getWorkloadStatus(externalId));
16739
16791
  if (await reflectWorkloadStatus(resource, external)) return;
16740
- await sleep(pollIntervalMs);
16792
+ await whileRunning(() => sleep(pollIntervalMs));
16741
16793
  }
16742
16794
  }
16743
16795
  async function reconcileToolOperation(resource) {
16796
+ throwIfStopped();
16744
16797
  const entry = findDriver(resource);
16745
16798
  const runtimeImage = resource.metadata.annotations?.["memeloop.io/runtime-image"];
16746
16799
  const contract = assertExternalToolOperationContract(
@@ -16749,10 +16802,10 @@ function createExternalOrchestrationController(store, options) {
16749
16802
  runtimeImage
16750
16803
  );
16751
16804
  const reference = referenceOf(resource);
16752
- const latest = await store.get(reference);
16805
+ const latest = await whileRunning(() => store.get(reference));
16753
16806
  let externalId = latest?.status?.externalId ?? resource.status?.externalId;
16754
16807
  if (!externalId) {
16755
- const health = await entry.driver.getHealth();
16808
+ const health = await whileRunning(() => entry.driver.getHealth());
16756
16809
  if (!health.healthy) {
16757
16810
  throw new OrchestrationError({ code: "UNAVAILABLE", message: `external orchestrator '${entry.name}' is unhealthy`, retryable: true });
16758
16811
  }
@@ -16768,14 +16821,14 @@ function createExternalOrchestrationController(store, options) {
16768
16821
  retryable: false
16769
16822
  });
16770
16823
  }
16771
- const authorization = await options.authorizeToolOperation(resource);
16824
+ const authorization = await whileRunning(() => options.authorizeToolOperation(resource, watchAbort.signal));
16772
16825
  if (authorization.approval) {
16773
16826
  await updateStatus(reference, (current) => ({
16774
16827
  ...current,
16775
16828
  approval: authorization.approval
16776
16829
  }));
16777
16830
  }
16778
- const placed = await entry.driver.executeToolOperation(resource, options.actor);
16831
+ const placed = await whileRunning(() => entry.driver.executeToolOperation(resource, options.actor));
16779
16832
  externalId = placed.externalId;
16780
16833
  await updateStatus(reference, (current) => ({
16781
16834
  ...current,
@@ -16788,27 +16841,28 @@ function createExternalOrchestrationController(store, options) {
16788
16841
  }));
16789
16842
  }
16790
16843
  while (!stopped) {
16791
- const external = await entry.driver.getToolOperationStatus(externalId);
16844
+ const external = await whileRunning(() => entry.driver.getToolOperationStatus(externalId));
16792
16845
  if (await reflectToolStatus(resource, external, contract)) return;
16793
- await sleep(pollIntervalMs);
16846
+ await whileRunning(() => sleep(pollIntervalMs));
16794
16847
  }
16795
16848
  }
16796
16849
  function maybeStart(resource) {
16850
+ if (stopped) return;
16797
16851
  const routed = resource;
16798
16852
  if (!routeOf(routed)) return;
16799
16853
  const phase = routed.status?.phase;
16800
16854
  if (phase === "Completed" || phase === "Failed" || phase === "Cancelled") return;
16801
16855
  if (active.has(routed.metadata.uid)) return;
16802
- active.add(routed.metadata.uid);
16803
- void (async () => {
16856
+ const task = (async () => {
16804
16857
  let slot;
16805
16858
  try {
16806
16859
  const entry = findDriver(routed);
16807
16860
  if (!await acquireDriverSlot(entry)) return;
16808
16861
  slot = entry.name;
16809
16862
  } catch (error2) {
16863
+ if (stopped || error2 === stoppedError) return;
16810
16864
  onError(error2);
16811
- await fail5(routed, error2).catch(onError);
16865
+ await fail5(routed, error2).catch(reportUnlessStopped);
16812
16866
  return;
16813
16867
  }
16814
16868
  try {
@@ -16821,18 +16875,25 @@ function createExternalOrchestrationController(store, options) {
16821
16875
  }
16822
16876
  return;
16823
16877
  } catch (error2) {
16878
+ if (stopped || error2 === stoppedError) return;
16824
16879
  onError(error2);
16825
16880
  if (!(error2 instanceof OrchestrationError) || !error2.retryable) {
16826
- await fail5(routed, error2).catch(onError);
16881
+ await fail5(routed, error2).catch(reportUnlessStopped);
16827
16882
  return;
16828
16883
  }
16829
- await sleep(pollIntervalMs);
16884
+ await whileRunning(() => sleep(pollIntervalMs));
16830
16885
  }
16831
16886
  }
16832
16887
  } finally {
16833
16888
  if (slot) releaseDriverSlot(slot);
16834
16889
  }
16835
- })().finally(() => active.delete(routed.metadata.uid));
16890
+ })();
16891
+ active.set(routed.metadata.uid, task);
16892
+ void task.finally(() => {
16893
+ if (active.get(routed.metadata.uid) === task) active.delete(routed.metadata.uid);
16894
+ }).catch((error2) => {
16895
+ if (!stopped && error2 !== stoppedError) onError(error2);
16896
+ });
16836
16897
  }
16837
16898
  async function cancelDeleted(resource) {
16838
16899
  const driverName = resource.status?.assignedDriver ?? routeOf(resource);
@@ -16853,7 +16914,7 @@ function createExternalOrchestrationController(store, options) {
16853
16914
  { apiVersion, kind },
16854
16915
  { signal: watchAbort.signal }
16855
16916
  )[Symbol.asyncIterator]();
16856
- const existing = await store.list({ apiVersion, kind });
16917
+ const existing = await whileRunning(() => store.list({ apiVersion, kind }));
16857
16918
  for (const resource of existing.items) maybeStart(resource);
16858
16919
  while (!stopped) {
16859
16920
  const next = await iterator.next();
@@ -16861,30 +16922,35 @@ function createExternalOrchestrationController(store, options) {
16861
16922
  const event = next.value;
16862
16923
  if (stopped) break;
16863
16924
  if (event.type === "DELETED") {
16864
- await cancelDeleted(event.resource).catch(onError);
16925
+ await cancelDeleted(event.resource).catch(reportUnlessStopped);
16865
16926
  } else if (event.type === "ADDED" || event.type === "MODIFIED") {
16866
16927
  maybeStart(event.resource);
16867
16928
  }
16868
16929
  }
16869
16930
  } catch (error2) {
16870
- onError(error2);
16931
+ if (!stopped && error2 !== stoppedError) onError(error2);
16932
+ }
16933
+ if (!stopped) {
16934
+ await whileRunning(() => sleep(1e3)).catch((error2) => {
16935
+ if (!stopped && error2 !== stoppedError) onError(error2);
16936
+ });
16871
16937
  }
16872
- if (!stopped) await sleep(1e3);
16873
16938
  }
16874
16939
  }
16875
16940
  const watchers = [
16876
16941
  runKind(AGENT_WORKLOAD_API_VERSION, AGENT_WORKLOAD_KIND),
16877
16942
  runKind(TOOL_OPERATION_API_VERSION, TOOL_OPERATION_KIND)
16878
16943
  ];
16879
- for (const watcher of watchers) void watcher.catch(onError);
16944
+ for (const watcher of watchers) void watcher.catch(reportUnlessStopped);
16880
16945
  return {
16881
16946
  async stop() {
16882
- stopped = true;
16883
- watchAbort.abort();
16884
- await Promise.race([
16885
- Promise.allSettled(watchers),
16886
- new Promise((resolve) => setTimeout(resolve, 50))
16887
- ]);
16947
+ if (!stopPromise) {
16948
+ stopped = true;
16949
+ resolveStopped({ kind: "stopped" });
16950
+ watchAbort.abort(stoppedError);
16951
+ stopPromise = drainWithDeadline([...watchers, ...active.values()]);
16952
+ }
16953
+ await stopPromise;
16888
16954
  }
16889
16955
  };
16890
16956
  }
@@ -37656,15 +37722,64 @@ function createWorkloadExecutionController(store, driver, options) {
37656
37722
  });
37657
37723
  }
37658
37724
  const active = /* @__PURE__ */ new Map();
37725
+ const executions = /* @__PURE__ */ new Map();
37726
+ const cancellationRequested = /* @__PURE__ */ new Set();
37727
+ const watchAbort = new AbortController();
37728
+ const stoppedError = new OrchestrationError({
37729
+ code: "CANCELLED",
37730
+ message: "workload execution controller stopped",
37731
+ retryable: false
37732
+ });
37733
+ let resolveStopped;
37734
+ const stoppedBoundary = new Promise((resolve) => {
37735
+ resolveStopped = resolve;
37736
+ });
37659
37737
  let stopped = false;
37738
+ let stopPromise;
37739
+ function throwIfStopped() {
37740
+ if (stopped) throw stoppedError;
37741
+ }
37742
+ async function whileRunning(operation) {
37743
+ throwIfStopped();
37744
+ const operationResult = Promise.resolve().then(operation).then(
37745
+ (value) => ({ kind: "value", value }),
37746
+ (error2) => ({
37747
+ kind: "error",
37748
+ error: error2 instanceof Error ? error2 : new Error(safeErrorMessageFromUnknown(error2))
37749
+ })
37750
+ );
37751
+ const result = await Promise.race([operationResult, stoppedBoundary]);
37752
+ if (result.kind === "stopped") throw stoppedError;
37753
+ if (result.kind === "error") throw result.error;
37754
+ return result.value;
37755
+ }
37756
+ function reportUnlessStopped(error2) {
37757
+ if (!stopped && error2 !== stoppedError) onError(error2);
37758
+ }
37759
+ async function drainWithDeadline(tasks) {
37760
+ let timeout;
37761
+ try {
37762
+ await Promise.race([
37763
+ Promise.allSettled(tasks).then(() => {
37764
+ }),
37765
+ new Promise((resolve) => {
37766
+ timeout = setTimeout(resolve, 1e3);
37767
+ })
37768
+ ]);
37769
+ } finally {
37770
+ if (timeout) clearTimeout(timeout);
37771
+ }
37772
+ }
37660
37773
  async function updateStatusWithRetry(reference, patch) {
37661
37774
  for (let attempt = 0; attempt < statusWriteAttempts; attempt += 1) {
37662
- const current = await store.get(reference);
37775
+ const current = await whileRunning(() => store.get(reference));
37663
37776
  if (!current) return;
37664
37777
  try {
37665
- await store.updateStatus(options.actor, reference, patch(current.status), {
37666
- resourceVersion: current.metadata.resourceVersion
37667
- });
37778
+ await whileRunning(
37779
+ () => store.updateStatus(options.actor, reference, patch(current.status), {
37780
+ resourceVersion: current.metadata.resourceVersion
37781
+ })
37782
+ );
37668
37783
  return;
37669
37784
  } catch (error2) {
37670
37785
  if (error2 instanceof OrchestrationError && error2.code === "CONFLICT") continue;
@@ -37699,22 +37814,26 @@ function createWorkloadExecutionController(store, driver, options) {
37699
37814
  }
37700
37815
  async function claimRuntimeExecution(reference) {
37701
37816
  for (let attempt = 0; attempt < statusWriteAttempts; attempt += 1) {
37702
- const current = await store.get(reference);
37817
+ const current = await whileRunning(
37818
+ () => store.get(reference)
37819
+ );
37703
37820
  if (!current) return null;
37704
37821
  if (current.status?.runtimeExecutionClaim) return null;
37705
37822
  try {
37706
- return await store.updateStatus(
37707
- options.actor,
37708
- reference,
37709
- {
37710
- ...current.status,
37711
- phase: "Starting",
37712
- runtimeExecutionClaim: {
37713
- controllerInstanceId,
37714
- claimedAt: (/* @__PURE__ */ new Date()).toISOString()
37715
- }
37716
- },
37717
- { resourceVersion: current.metadata.resourceVersion }
37823
+ return await whileRunning(
37824
+ () => store.updateStatus(
37825
+ options.actor,
37826
+ reference,
37827
+ {
37828
+ ...current.status,
37829
+ phase: "Starting",
37830
+ runtimeExecutionClaim: {
37831
+ controllerInstanceId,
37832
+ claimedAt: (/* @__PURE__ */ new Date()).toISOString()
37833
+ }
37834
+ },
37835
+ { resourceVersion: current.metadata.resourceVersion }
37836
+ )
37718
37837
  );
37719
37838
  } catch (error2) {
37720
37839
  if (error2 instanceof OrchestrationError && error2.code === "CONFLICT") {
@@ -37739,8 +37858,10 @@ function createWorkloadExecutionController(store, driver, options) {
37739
37858
  retryable: false
37740
37859
  });
37741
37860
  }
37742
- const current = await store.get(
37743
- runReference
37861
+ const current = await whileRunning(
37862
+ () => store.get(
37863
+ runReference
37864
+ )
37744
37865
  );
37745
37866
  if (!current) {
37746
37867
  throw new OrchestrationError({
@@ -37752,12 +37873,14 @@ function createWorkloadExecutionController(store, driver, options) {
37752
37873
  if (!workload.spec.modelPolicy?.modelClass) return { run: current };
37753
37874
  const binding = current.status?.assignedModelEndpoint;
37754
37875
  if (binding) {
37755
- const endpoint = await store.get({
37756
- apiVersion: binding.apiVersion || MODEL_ENDPOINT_API_VERSION,
37757
- kind: binding.kind || MODEL_ENDPOINT_KIND,
37758
- name: binding.name,
37759
- namespace: binding.namespace
37760
- });
37876
+ const endpoint = await whileRunning(
37877
+ () => store.get({
37878
+ apiVersion: binding.apiVersion || MODEL_ENDPOINT_API_VERSION,
37879
+ kind: binding.kind || MODEL_ENDPOINT_KIND,
37880
+ name: binding.name,
37881
+ namespace: binding.namespace
37882
+ })
37883
+ );
37761
37884
  if (endpoint && endpoint.metadata.uid === binding.uid && endpoint.status?.healthy === true && Number.isFinite(Date.parse(endpoint.status.heartbeat ?? "")) && Date.now() - Date.parse(endpoint.status.heartbeat ?? "") <= modelEndpointHeartbeatTtlMs && endpoint.spec.modelClassRef.name === workload.spec.modelPolicy.modelClass) {
37762
37885
  return { run: current, endpoint };
37763
37886
  }
@@ -37769,7 +37892,7 @@ function createWorkloadExecutionController(store, driver, options) {
37769
37892
  retryable: true
37770
37893
  });
37771
37894
  }
37772
- await sleep(dependencyPollIntervalMs);
37895
+ await whileRunning(() => sleep(dependencyPollIntervalMs));
37773
37896
  }
37774
37897
  }
37775
37898
  async function ensureNetworkAttachment(workload, runReference, runUid) {
@@ -37782,7 +37905,9 @@ function createWorkloadExecutionController(store, driver, options) {
37782
37905
  name: attachmentName,
37783
37906
  namespace: workload.metadata.namespace
37784
37907
  };
37785
- let attachment = await store.get(reference);
37908
+ let attachment = await whileRunning(
37909
+ () => store.get(reference)
37910
+ );
37786
37911
  if (!attachment) {
37787
37912
  const manifest2 = createNetworkAttachmentManifest(attachmentName, {
37788
37913
  networkClassRef: {
@@ -37806,7 +37931,7 @@ function createWorkloadExecutionController(store, driver, options) {
37806
37931
  nodeId: options.nodeId
37807
37932
  });
37808
37933
  manifest2.metadata.namespace = workload.metadata.namespace;
37809
- attachment = await store.create(options.actor, manifest2);
37934
+ attachment = await whileRunning(() => store.create(options.actor, manifest2));
37810
37935
  }
37811
37936
  await updateStatusWithRetry(runReference, (current) => ({
37812
37937
  ...current,
@@ -37827,7 +37952,9 @@ function createWorkloadExecutionController(store, driver, options) {
37827
37952
  retryable: false
37828
37953
  });
37829
37954
  }
37830
- const current = await store.get(reference);
37955
+ const current = await whileRunning(
37956
+ () => store.get(reference)
37957
+ );
37831
37958
  if (!current || current.metadata.uid !== attachment.metadata.uid) {
37832
37959
  throw new OrchestrationError({
37833
37960
  code: "NOT_FOUND",
@@ -37843,7 +37970,9 @@ function createWorkloadExecutionController(store, driver, options) {
37843
37970
  });
37844
37971
  }
37845
37972
  if (current.status?.phase === "Attached" && current.status.handle) {
37846
- const networkClass = await store.get(current.spec.networkClassRef);
37973
+ const networkClass = await whileRunning(
37974
+ () => store.get(current.spec.networkClassRef)
37975
+ );
37847
37976
  if (networkClass && current.status.binding?.networkClassResourceVersion === networkClass.metadata.resourceVersion && current.status.assignedNode === options.nodeId && current.status.assignedDriver === networkClass.spec.driver) {
37848
37977
  return current;
37849
37978
  }
@@ -37855,14 +37984,16 @@ function createWorkloadExecutionController(store, driver, options) {
37855
37984
  retryable: true
37856
37985
  });
37857
37986
  }
37858
- await sleep(dependencyPollIntervalMs);
37987
+ await whileRunning(() => sleep(dependencyPollIntervalMs));
37859
37988
  }
37860
37989
  }
37861
37990
  async function waitForVolumeBindings(workload, runReference) {
37862
37991
  const expected = workload.spec.storagePolicy?.volumes ?? [];
37863
37992
  if (expected.length === 0) {
37864
- const run5 = await store.get(
37865
- runReference
37993
+ const run5 = await whileRunning(
37994
+ () => store.get(
37995
+ runReference
37996
+ )
37866
37997
  );
37867
37998
  return { run: run5 };
37868
37999
  }
@@ -37875,8 +38006,10 @@ function createWorkloadExecutionController(store, driver, options) {
37875
38006
  retryable: false
37876
38007
  });
37877
38008
  }
37878
- const run5 = await store.get(
37879
- runReference
38009
+ const run5 = await whileRunning(
38010
+ () => store.get(
38011
+ runReference
38012
+ )
37880
38013
  );
37881
38014
  if (!run5) {
37882
38015
  throw new OrchestrationError({
@@ -37903,7 +38036,7 @@ function createWorkloadExecutionController(store, driver, options) {
37903
38036
  retryable: false
37904
38037
  });
37905
38038
  }
37906
- return { run: run5, mounts: await options.resolveVolumeMounts(workload, run5) };
38039
+ return { run: run5, mounts: await whileRunning(() => options.resolveVolumeMounts(workload, run5)) };
37907
38040
  }
37908
38041
  if (Date.now() >= deadline) {
37909
38042
  throw new OrchestrationError({
@@ -37912,12 +38045,14 @@ function createWorkloadExecutionController(store, driver, options) {
37912
38045
  retryable: true
37913
38046
  });
37914
38047
  }
37915
- await sleep(dependencyPollIntervalMs);
38048
+ await whileRunning(() => sleep(dependencyPollIntervalMs));
37916
38049
  }
37917
38050
  }
37918
38051
  async function requestDependencyRelease(runReference) {
37919
- const run5 = await store.get(
37920
- runReference
38052
+ const run5 = await whileRunning(
38053
+ () => store.get(
38054
+ runReference
38055
+ )
37921
38056
  );
37922
38057
  if (!run5) return;
37923
38058
  const requestedAt = (/* @__PURE__ */ new Date()).toISOString();
@@ -37944,6 +38079,7 @@ function createWorkloadExecutionController(store, driver, options) {
37944
38079
  }
37945
38080
  }
37946
38081
  async function execute(workload) {
38082
+ throwIfStopped();
37947
38083
  const workloadReference_ = workloadReference(workload);
37948
38084
  const runName = `${workload.metadata.name}-run`;
37949
38085
  const runReference = {
@@ -37955,18 +38091,19 @@ function createWorkloadExecutionController(store, driver, options) {
37955
38091
  let runtimeClaimed = false;
37956
38092
  try {
37957
38093
  let scriptSource;
37958
- if (workload.spec.scriptReference) {
37959
- scriptSource = await options.resolveScriptSource?.(workload.spec.scriptReference);
38094
+ const scriptReference = workload.spec.scriptReference;
38095
+ if (scriptReference) {
38096
+ scriptSource = await whileRunning(async () => options.resolveScriptSource?.(scriptReference));
37960
38097
  if (!scriptSource) {
37961
38098
  await updateStatusWithRetry(workloadReference_, (current) => ({
37962
38099
  ...current,
37963
38100
  phase: "Failed",
37964
- lastRunResult: `script artifact '${workload.spec.scriptReference}' unavailable`
38101
+ lastRunResult: `script artifact '${scriptReference}' unavailable`
37965
38102
  }));
37966
38103
  return;
37967
38104
  }
37968
38105
  }
37969
- let run5 = await store.get(runReference);
38106
+ let run5 = await whileRunning(() => store.get(runReference));
37970
38107
  if (!run5) {
37971
38108
  const manifest2 = createAgentRunManifest(runName, {
37972
38109
  workloadRef: {
@@ -37979,15 +38116,19 @@ function createWorkloadExecutionController(store, driver, options) {
37979
38116
  });
37980
38117
  manifest2.metadata.namespace = workload.metadata.namespace;
37981
38118
  try {
37982
- run5 = await store.create(
37983
- options.actor,
37984
- manifest2
38119
+ run5 = await whileRunning(
38120
+ () => store.create(
38121
+ options.actor,
38122
+ manifest2
38123
+ )
37985
38124
  );
37986
38125
  } catch (error2) {
37987
38126
  if (!(error2 instanceof OrchestrationError) || error2.code !== "CONFLICT") {
37988
38127
  throw error2;
37989
38128
  }
37990
- run5 = await store.get(runReference);
38129
+ run5 = await whileRunning(
38130
+ () => store.get(runReference)
38131
+ );
37991
38132
  if (!run5) throw error2;
37992
38133
  }
37993
38134
  }
@@ -38007,8 +38148,10 @@ function createWorkloadExecutionController(store, driver, options) {
38007
38148
  waitForVolumeBindings(workload, runReference)
38008
38149
  ]);
38009
38150
  run5 = volumeDependencies.run;
38010
- run5 = await store.get(
38011
- runReference
38151
+ run5 = await whileRunning(
38152
+ () => store.get(
38153
+ runReference
38154
+ )
38012
38155
  ) ?? run5;
38013
38156
  await updateStatusWithRetry(workloadReference_, (current) => ({
38014
38157
  ...current,
@@ -38019,21 +38162,27 @@ function createWorkloadExecutionController(store, driver, options) {
38019
38162
  if (!claimedRun) return;
38020
38163
  runtimeClaimed = true;
38021
38164
  run5 = claimedRun;
38022
- const handle = await driver.start({
38023
- workload,
38024
- run: run5,
38025
- ...dependencies.endpoint ? { modelEndpoint: dependencies.endpoint } : {},
38026
- ...networkAttachment ? { networkAttachment } : {},
38027
- ...volumeDependencies.mounts ? { volumeMounts: volumeDependencies.mounts } : {},
38028
- scriptSource,
38029
- message: options.messageForWorkload?.(workload) ?? workload.metadata.name
38030
- });
38165
+ const handle = await whileRunning(
38166
+ () => driver.start({
38167
+ workload,
38168
+ run: run5,
38169
+ ...dependencies.endpoint ? { modelEndpoint: dependencies.endpoint } : {},
38170
+ ...networkAttachment ? { networkAttachment } : {},
38171
+ ...volumeDependencies.mounts ? { volumeMounts: volumeDependencies.mounts } : {},
38172
+ scriptSource,
38173
+ message: options.messageForWorkload?.(workload) ?? workload.metadata.name
38174
+ })
38175
+ );
38031
38176
  active.set(workload.metadata.uid, handle);
38177
+ if (cancellationRequested.has(workload.metadata.uid)) {
38178
+ await handle.cancel().catch(reportUnlessStopped);
38179
+ return;
38180
+ }
38032
38181
  await updateStatusWithRetry(runReference, (current) => ({
38033
38182
  ...current,
38034
38183
  phase: "Running"
38035
38184
  }));
38036
- const outcome = await handle.wait();
38185
+ const outcome = await whileRunning(() => handle.wait());
38037
38186
  await requestDependencyRelease(runReference);
38038
38187
  await updateStatusWithRetry(runReference, (current) => ({
38039
38188
  ...current,
@@ -38047,7 +38196,8 @@ function createWorkloadExecutionController(store, driver, options) {
38047
38196
  lastRunResult: outcome.summary ?? outcome.error?.message
38048
38197
  }));
38049
38198
  } catch (error2) {
38050
- await requestDependencyRelease(runReference).catch(onError);
38199
+ if (stopped || error2 === stoppedError) return;
38200
+ await requestDependencyRelease(runReference).catch(reportUnlessStopped);
38051
38201
  const cause = safeErrorMessageFromUnknown(error2, { fallback: "Runtime execution failed" });
38052
38202
  const message = runtimeClaimed ? `UNKNOWN_EFFECT: runtime execution failed after the durable pre-effect claim; verify external state before retrying: ${cause}` : cause;
38053
38203
  await updateStatusWithRetry(runReference, (current) => ({
@@ -38057,19 +38207,20 @@ function createWorkloadExecutionController(store, driver, options) {
38057
38207
  summary: message,
38058
38208
  exitCode: 1
38059
38209
  }
38060
- })).catch(onError);
38061
- if (stopped) return;
38210
+ })).catch(reportUnlessStopped);
38062
38211
  onError(error2);
38063
38212
  await updateStatusWithRetry(workloadReference_, (current) => ({
38064
38213
  ...current,
38065
38214
  phase: "Failed",
38066
38215
  lastRunResult: message
38067
- })).catch(onError);
38216
+ })).catch(reportUnlessStopped);
38068
38217
  } finally {
38069
38218
  active.delete(workload.metadata.uid);
38219
+ cancellationRequested.delete(workload.metadata.uid);
38070
38220
  }
38071
38221
  }
38072
38222
  async function recoverRunning(workload) {
38223
+ throwIfStopped();
38073
38224
  const runReference = {
38074
38225
  apiVersion: AGENT_RUN_API_VERSION,
38075
38226
  kind: AGENT_RUN_KIND,
@@ -38077,8 +38228,10 @@ function createWorkloadExecutionController(store, driver, options) {
38077
38228
  namespace: workload.metadata.namespace
38078
38229
  };
38079
38230
  try {
38080
- const run5 = await store.get(
38081
- runReference
38231
+ const run5 = await whileRunning(
38232
+ () => store.get(
38233
+ runReference
38234
+ )
38082
38235
  );
38083
38236
  if (run5) {
38084
38237
  try {
@@ -38136,12 +38289,14 @@ function createWorkloadExecutionController(store, driver, options) {
38136
38289
  })
38137
38290
  );
38138
38291
  } catch (error2) {
38139
- onError(error2);
38292
+ if (!stopped && error2 !== stoppedError) onError(error2);
38140
38293
  } finally {
38141
38294
  active.delete(workload.metadata.uid);
38295
+ cancellationRequested.delete(workload.metadata.uid);
38142
38296
  }
38143
38297
  }
38144
38298
  function maybeStart(resource) {
38299
+ if (stopped) return;
38145
38300
  const workload = resource;
38146
38301
  const status = workload.status;
38147
38302
  if (!status || status.phase !== "Scheduling" && status.phase !== "Running") return;
@@ -38149,39 +38304,57 @@ function createWorkloadExecutionController(store, driver, options) {
38149
38304
  if (active.has(workload.metadata.uid)) return;
38150
38305
  active.set(workload.metadata.uid, { cancel: async () => {
38151
38306
  } });
38152
- if (status.phase === "Running") {
38153
- void recoverRunning(workload);
38154
- } else {
38155
- void execute(workload).catch(onError);
38156
- }
38307
+ const execution = status.phase === "Running" ? recoverRunning(workload) : execute(workload);
38308
+ executions.set(workload.metadata.uid, execution);
38309
+ void execution.finally(() => {
38310
+ if (executions.get(workload.metadata.uid) === execution) {
38311
+ executions.delete(workload.metadata.uid);
38312
+ }
38313
+ }).catch((error2) => {
38314
+ if (!stopped && error2 !== stoppedError) onError(error2);
38315
+ });
38157
38316
  }
38158
- void (async () => {
38317
+ const watcher = (async () => {
38159
38318
  while (!stopped) {
38160
38319
  try {
38161
38320
  for await (const event of store.watch(
38162
38321
  { apiVersion: AGENT_WORKLOAD_API_VERSION, kind: AGENT_WORKLOAD_KIND },
38163
- { sendInitialEvents: true }
38322
+ { sendInitialEvents: true, signal: watchAbort.signal }
38164
38323
  )) {
38165
38324
  if (stopped) break;
38166
38325
  if (event.type === "ADDED" || event.type === "MODIFIED") {
38167
38326
  maybeStart(event.resource);
38168
38327
  } else if (event.type === "DELETED") {
38169
38328
  const workload = event.resource;
38170
- await active.get(workload.metadata.uid)?.cancel().catch(onError);
38329
+ cancellationRequested.add(workload.metadata.uid);
38330
+ await active.get(workload.metadata.uid)?.cancel().catch(reportUnlessStopped);
38171
38331
  }
38172
38332
  }
38173
38333
  } catch (error2) {
38174
- onError(error2);
38334
+ if (!stopped && error2 !== stoppedError) onError(error2);
38335
+ }
38336
+ if (!stopped) {
38337
+ await whileRunning(() => sleep(1e3)).catch((error2) => {
38338
+ if (!stopped && error2 !== stoppedError) onError(error2);
38339
+ });
38175
38340
  }
38176
- if (!stopped) await sleep(1e3);
38177
38341
  }
38178
- })().catch(onError);
38342
+ })();
38343
+ void watcher.catch((error2) => {
38344
+ if (!stopped && error2 !== stoppedError) onError(error2);
38345
+ });
38179
38346
  return {
38180
38347
  async stop() {
38181
- stopped = true;
38182
- for (const handle of active.values()) {
38183
- await handle.cancel().catch(() => void 0);
38348
+ if (!stopPromise) {
38349
+ stopped = true;
38350
+ resolveStopped({ kind: "stopped" });
38351
+ watchAbort.abort(stoppedError);
38352
+ const cancellations = [...active.values()].map(async (handle) => {
38353
+ await handle.cancel().catch(() => void 0);
38354
+ });
38355
+ stopPromise = drainWithDeadline([...cancellations, watcher, ...executions.values()]);
38184
38356
  }
38357
+ await stopPromise;
38185
38358
  }
38186
38359
  };
38187
38360
  }
@@ -38955,6 +39128,7 @@ __export(src_exports, {
38955
39128
  DEVICE_HEARTBEAT_DEFAULT_MAX_CLOCK_SKEW_MS: () => DEVICE_HEARTBEAT_DEFAULT_MAX_CLOCK_SKEW_MS,
38956
39129
  DEVICE_HEARTBEAT_LIMITS: () => DEVICE_HEARTBEAT_LIMITS,
38957
39130
  DEVICE_HEARTBEAT_SIGNATURE_DOMAIN: () => DEVICE_HEARTBEAT_SIGNATURE_DOMAIN,
39131
+ DEVICE_ORCHESTRATION_FRAME_LIMITS: () => DEVICE_ORCHESTRATION_FRAME_LIMITS,
38958
39132
  DEVICE_ORCHESTRATION_PROTOCOL: () => DEVICE_ORCHESTRATION_PROTOCOL,
38959
39133
  DEVICE_PAIRING_INVITE_MAX_CLOCK_SKEW_MS: () => DEVICE_PAIRING_INVITE_MAX_CLOCK_SKEW_MS,
38960
39134
  DEVICE_PAIRING_INVITE_PROTOCOL: () => DEVICE_PAIRING_INVITE_PROTOCOL,
@@ -48296,14 +48470,28 @@ var MemoryDeviceCloudTokenStorage = class {
48296
48470
  loadConnectionGrant(input) {
48297
48471
  return this.grants.get(connectionGrantCacheKey(input));
48298
48472
  }
48299
- saveConnectionGrant(input, grant) {
48300
- this.grants.set(connectionGrantCacheKey(input), grant);
48473
+ saveConnectionGrant(input, grant, fence) {
48474
+ const write = () => {
48475
+ this.grants.set(connectionGrantCacheKey(input), grant);
48476
+ };
48477
+ if (!fence) {
48478
+ write();
48479
+ return;
48480
+ }
48481
+ if (!fence.commitSynchronous(write)) fence.throwIfStale();
48301
48482
  }
48302
48483
  loadRelayReservation(peerId) {
48303
48484
  return this.relayReservations.get(peerId);
48304
48485
  }
48305
- saveRelayReservation(peerId, token) {
48306
- this.relayReservations.set(peerId, token);
48486
+ saveRelayReservation(peerId, token, fence) {
48487
+ const write = () => {
48488
+ this.relayReservations.set(peerId, token);
48489
+ };
48490
+ if (!fence) {
48491
+ write();
48492
+ return;
48493
+ }
48494
+ if (!fence.commitSynchronous(write)) fence.throwIfStale();
48307
48495
  }
48308
48496
  clear() {
48309
48497
  this.grants.clear();
@@ -48418,13 +48606,16 @@ var CloudDeviceFetchClient = class {
48418
48606
  }
48419
48607
  return { issuer: value.issuer, publicKeyMultibase: value.publicKeyMultibase };
48420
48608
  }
48421
- async createConnectionGrant(input, signal) {
48609
+ async createConnectionGrant(input, signal, fence) {
48610
+ assertFenceSignal(signal, fence);
48611
+ fence?.throwIfStale();
48422
48612
  if (!isCanonicalConnectionGrantRequest(input)) {
48423
48613
  throw new TypeError("invalid_connection_grant_scope");
48424
48614
  }
48425
48615
  const cacheInput = normalizedConnectionGrantRequest(input);
48426
48616
  const cached = await this.loadCachedGrant(cacheInput);
48427
48617
  throwIfAborted(signal);
48618
+ fence?.throwIfStale();
48428
48619
  if (isUsableConnectionGrant(cached, cacheInput, this.now() + this.tokenSafetyMarginMs)) {
48429
48620
  return cached;
48430
48621
  }
@@ -48433,12 +48624,17 @@ var CloudDeviceFetchClient = class {
48433
48624
  body: JSON.stringify(input)
48434
48625
  }, signal);
48435
48626
  if (!isUsableConnectionGrant(value, cacheInput, this.now())) throw invalidShape();
48436
- await this.saveCachedGrant(cacheInput, value);
48627
+ fence?.throwIfStale();
48628
+ await this.saveCachedGrant(cacheInput, value, fence);
48629
+ fence?.throwIfStale();
48437
48630
  return value;
48438
48631
  }
48439
- async createRelayReservation(input, signal) {
48632
+ async createRelayReservation(input, signal, fence) {
48633
+ assertFenceSignal(signal, fence);
48634
+ fence?.throwIfStale();
48440
48635
  const cached = await this.loadCachedRelayReservation(input.peerId);
48441
48636
  throwIfAborted(signal);
48637
+ fence?.throwIfStale();
48442
48638
  if (isUsableRelayReservation(cached, input.peerId, this.now() + this.tokenSafetyMarginMs)) {
48443
48639
  return cached;
48444
48640
  }
@@ -48447,7 +48643,9 @@ var CloudDeviceFetchClient = class {
48447
48643
  body: JSON.stringify(input)
48448
48644
  }, signal);
48449
48645
  if (!isUsableRelayReservation(value, input.peerId, this.now())) throw invalidShape();
48450
- await this.saveCachedRelayReservation(input.peerId, value);
48646
+ fence?.throwIfStale();
48647
+ await this.saveCachedRelayReservation(input.peerId, value, fence);
48648
+ fence?.throwIfStale();
48451
48649
  return value;
48452
48650
  }
48453
48651
  async heartbeat(input, signal) {
@@ -48521,10 +48719,11 @@ var CloudDeviceFetchClient = class {
48521
48719
  return void 0;
48522
48720
  }
48523
48721
  }
48524
- async saveCachedGrant(input, grant) {
48722
+ async saveCachedGrant(input, grant, fence) {
48525
48723
  try {
48526
- await this.tokenStorage.saveConnectionGrant(input, grant);
48724
+ await this.tokenStorage.saveConnectionGrant(input, grant, fence);
48527
48725
  } catch (error2) {
48726
+ if (fence && !fence.isCurrent()) fence.throwIfStale();
48528
48727
  this.options.onTokenStorageError?.("save", error2);
48529
48728
  }
48530
48729
  }
@@ -48536,14 +48735,20 @@ var CloudDeviceFetchClient = class {
48536
48735
  return void 0;
48537
48736
  }
48538
48737
  }
48539
- async saveCachedRelayReservation(peerId, token) {
48738
+ async saveCachedRelayReservation(peerId, token, fence) {
48540
48739
  try {
48541
- await this.tokenStorage.saveRelayReservation(peerId, token);
48740
+ await this.tokenStorage.saveRelayReservation(peerId, token, fence);
48542
48741
  } catch (error2) {
48742
+ if (fence && !fence.isCurrent()) fence.throwIfStale();
48543
48743
  this.options.onTokenStorageError?.("save", error2);
48544
48744
  }
48545
48745
  }
48546
48746
  };
48747
+ function assertFenceSignal(signal, fence) {
48748
+ if (fence && signal && fence.signal !== signal) {
48749
+ throw new TypeError("device_cloud_generation_signal_mismatch");
48750
+ }
48751
+ }
48547
48752
  function normalizeCloudDeviceBaseUrl(value) {
48548
48753
  const baseUrl = value.trim();
48549
48754
  if (!baseUrl || baseUrl.length > CLOUD_URL_MAX_CHARACTERS) throw new Error("invalid_cloud_url");
@@ -48970,16 +49175,16 @@ var DeviceCloudConnectionCoordinator = class {
48970
49175
  try {
48971
49176
  if (this.snapshotValue.components.authorizer !== "ready") {
48972
49177
  activeComponent = "authorizer";
48973
- await this.runStep(activeComponent, generation, signal, () => this.options.adapter.ensureAuthorizer(configuration, signal));
49178
+ await this.runStep(activeComponent, generation, signal, (fence) => this.options.adapter.ensureAuthorizer(configuration, signal, fence));
48974
49179
  }
48975
49180
  if (this.snapshotValue.components.registration !== "ready") {
48976
49181
  activeComponent = "registration";
48977
- await this.runStep(activeComponent, generation, signal, () => this.options.adapter.registerDevice(configuration, signal));
49182
+ await this.runStep(activeComponent, generation, signal, (fence) => this.options.adapter.registerDevice(configuration, signal, fence));
48978
49183
  }
48979
49184
  let relayFailure;
48980
49185
  try {
48981
49186
  activeComponent = "relay";
48982
- await this.runStep(activeComponent, generation, signal, () => this.options.adapter.ensureRelay(configuration, signal));
49187
+ await this.runStep(activeComponent, generation, signal, (fence) => this.options.adapter.ensureRelay(configuration, signal, fence));
48983
49188
  } catch (error2) {
48984
49189
  const classification = this.classify(error2);
48985
49190
  if (classification === "registration-invalid") throw error2;
@@ -48987,11 +49192,11 @@ var DeviceCloudConnectionCoordinator = class {
48987
49192
  this.warn("Device Cloud relay maintenance failed", relayFailure);
48988
49193
  }
48989
49194
  activeComponent = "heartbeat";
48990
- await this.runStep(activeComponent, generation, signal, () => this.options.adapter.heartbeat(configuration, signal));
49195
+ await this.runStep(activeComponent, generation, signal, (fence) => this.options.adapter.heartbeat(configuration, signal, fence));
48991
49196
  let directoryFailure;
48992
49197
  try {
48993
49198
  activeComponent = "directory";
48994
- await this.runStep(activeComponent, generation, signal, () => this.options.adapter.syncDirectory(configuration, signal));
49199
+ await this.runStep(activeComponent, generation, signal, (fence) => this.options.adapter.syncDirectory(configuration, signal, fence));
48995
49200
  } catch (error2) {
48996
49201
  const classification = this.classify(error2);
48997
49202
  if (classification === "registration-invalid") throw error2;
@@ -49031,9 +49236,9 @@ var DeviceCloudConnectionCoordinator = class {
49031
49236
  if (!this.isCurrent(generation, signal)) return;
49032
49237
  await this.setComponent(component, "pending", generation);
49033
49238
  try {
49034
- const result = await operation();
49035
- if (!this.isCurrent(generation, signal)) return;
49036
49239
  const fence = this.createCommitFence(generation, signal);
49240
+ const result = await operation(fence);
49241
+ if (!this.isCurrent(generation, signal)) return;
49037
49242
  await result?.commit?.(fence);
49038
49243
  if (!this.isCurrent(generation, signal)) return;
49039
49244
  await this.setComponent(component, "ready", generation);
@@ -49737,11 +49942,18 @@ function createJsonFrameReader(source, options) {
49737
49942
 
49738
49943
  // src/device-network/deviceOrchestrationTransport.ts
49739
49944
  var DEVICE_ORCHESTRATION_PROTOCOL = "/memeloop/orchestration/2.0.0";
49740
- var DEFAULT_MAX_FRAME_BYTES = 1024 * 1024;
49741
- var REQUEST_IDLE_TIMEOUT_MS = 1e4;
49742
- var REQUEST_TOTAL_TIMEOUT_MS = 3e4;
49743
- var WATCH_IDLE_TIMEOUT_MS = 9e4;
49744
- var WATCH_BOOKMARK_INTERVAL_MS = 3e4;
49945
+ var DEVICE_ORCHESTRATION_FRAME_LIMITS = Object.freeze({
49946
+ maxPayloadBytes: 1024 * 1024,
49947
+ requestIdleTimeoutMs: 1e4,
49948
+ requestTotalTimeoutMs: 3e4,
49949
+ watchIdleTimeoutMs: 9e4,
49950
+ watchBookmarkIntervalMs: 3e4
49951
+ });
49952
+ var DEFAULT_MAX_FRAME_BYTES = DEVICE_ORCHESTRATION_FRAME_LIMITS.maxPayloadBytes;
49953
+ var REQUEST_IDLE_TIMEOUT_MS = DEVICE_ORCHESTRATION_FRAME_LIMITS.requestIdleTimeoutMs;
49954
+ var REQUEST_TOTAL_TIMEOUT_MS = DEVICE_ORCHESTRATION_FRAME_LIMITS.requestTotalTimeoutMs;
49955
+ var WATCH_IDLE_TIMEOUT_MS = DEVICE_ORCHESTRATION_FRAME_LIMITS.watchIdleTimeoutMs;
49956
+ var WATCH_BOOKMARK_INTERVAL_MS = DEVICE_ORCHESTRATION_FRAME_LIMITS.watchBookmarkIntervalMs;
49745
49957
  function orchestrationTransportError(code, message) {
49746
49958
  return new OrchestrationError({
49747
49959
  code,
@@ -50022,6 +50234,13 @@ function createDeviceOrchestrationStreamHandler(options) {
50022
50234
  assertFrameLimit(maxFrameBytes);
50023
50235
  return async ({ remotePeerId, stream, authorize }) => {
50024
50236
  const abort = new AbortController();
50237
+ const abortFromStream = () => {
50238
+ if (!abort.signal.aborted) {
50239
+ abort.abort(stream.signal?.reason ?? new Error("device orchestration stream closed"));
50240
+ }
50241
+ };
50242
+ stream.signal?.addEventListener("abort", abortFromStream, { once: true });
50243
+ if (stream.signal?.aborted) abortFromStream();
50025
50244
  try {
50026
50245
  const envelope = await readSingleRequest(stream, maxFrameBytes);
50027
50246
  if (authorize && !await authorize(envelope.grant)) {
@@ -50045,7 +50264,8 @@ function createDeviceOrchestrationStreamHandler(options) {
50045
50264
  await stream.sink(encodeJsonFrames([response], maxFrameBytes));
50046
50265
  }
50047
50266
  } finally {
50048
- abort.abort();
50267
+ stream.signal?.removeEventListener("abort", abortFromStream);
50268
+ if (!abort.signal.aborted) abort.abort();
50049
50269
  await stream.close().catch(() => void 0);
50050
50270
  }
50051
50271
  };
@@ -50777,6 +50997,23 @@ function sameTrustedDevice(left, right) {
50777
50997
 
50778
50998
  // src/device-network/standardDeviceCloudConnectionAdapter.ts
50779
50999
  var DEFAULT_RELAY_TOKEN_SAFETY_MARGIN_MS = 2 * 6e4;
51000
+ var REGISTRATION_INVALID_ERROR_CODES = /* @__PURE__ */ new Set([
51001
+ "device_not_found",
51002
+ "device_registration_invalid",
51003
+ "device_registration_not_found",
51004
+ "invalid_device_registration",
51005
+ "registration_invalid"
51006
+ ]);
51007
+ var DeviceCloudRegistrationInvalidError = class extends Error {
51008
+ code = "DEVICE_CLOUD_REGISTRATION_INVALID";
51009
+ constructor(cause) {
51010
+ super(
51011
+ "cloud device heartbeat rejected",
51012
+ cause === void 0 ? void 0 : { cause }
51013
+ );
51014
+ this.name = "DeviceCloudRegistrationInvalidError";
51015
+ }
51016
+ };
50780
51017
  var StandardDeviceCloudConnectionAdapter = class {
50781
51018
  constructor(options) {
50782
51019
  this.options = options;
@@ -50796,9 +51033,9 @@ var StandardDeviceCloudConnectionAdapter = class {
50796
51033
  }
50797
51034
  relayRequiredForOnline(_configuration) {
50798
51035
  const addresses = this.options.network.getMultiaddrs();
50799
- return this.options.relayRequiredForOnline?.(addresses) ?? !hasValidDirectCloudDeviceAddress(addresses);
51036
+ return this.options.relayRequiredForOnline?.(addresses) ?? !hasValidDirectCloudDeviceAddress(addresses, this.options.identity.peerId);
50800
51037
  }
50801
- async ensureAuthorizer(client, signal) {
51038
+ async ensureAuthorizer(client, signal, _fence) {
50802
51039
  const publicKey = await client.getConnectionGrantPublicKey(signal);
50803
51040
  return {
50804
51041
  commit: async (fence) => {
@@ -50808,7 +51045,7 @@ var StandardDeviceCloudConnectionAdapter = class {
50808
51045
  }
50809
51046
  };
50810
51047
  }
50811
- async registerDevice(client, signal) {
51048
+ async registerDevice(client, signal, _fence) {
50812
51049
  const nonce = await client.createBindingNonce(signal);
50813
51050
  throwIfAborted3(signal);
50814
51051
  const signature = await this.options.signDeviceBinding({
@@ -50836,27 +51073,28 @@ var StandardDeviceCloudConnectionAdapter = class {
50836
51073
  }
50837
51074
  return void 0;
50838
51075
  }
50839
- async ensureRelay(client, signal) {
51076
+ async ensureRelay(client, signal, fence) {
50840
51077
  if (this.relayReservationClient === client && this.relayReservation && this.relayReservation.expiresAt > this.now() + this.relayTokenSafetyMarginMs) {
50841
51078
  return void 0;
50842
51079
  }
50843
51080
  const relayReservation = await client.createRelayReservation(
50844
51081
  { peerId: this.options.identity.peerId },
50845
- signal
51082
+ signal,
51083
+ fence
50846
51084
  );
50847
51085
  return {
50848
- commit: async (fence) => {
50849
- fence.throwIfStale();
50850
- await this.options.network.configureRelayReservation(relayReservation, signal, fence);
50851
- fence.throwIfStale();
50852
- fence.commitSynchronous(() => {
51086
+ commit: async (fence2) => {
51087
+ fence2.throwIfStale();
51088
+ await this.options.network.configureRelayReservation(relayReservation, signal, fence2);
51089
+ fence2.throwIfStale();
51090
+ fence2.commitSynchronous(() => {
50853
51091
  this.relayReservation = relayReservation;
50854
51092
  this.relayReservationClient = client;
50855
51093
  });
50856
51094
  }
50857
51095
  };
50858
51096
  }
50859
- async heartbeat(client, signal) {
51097
+ async heartbeat(client, signal, _fence) {
50860
51098
  throwIfAborted3(signal);
50861
51099
  const capabilities = await this.options.capabilities();
50862
51100
  throwIfAborted3(signal);
@@ -50874,8 +51112,16 @@ var StandardDeviceCloudConnectionAdapter = class {
50874
51112
  if (!boundedProofSignature(heartbeat.signature)) {
50875
51113
  throw new Error("invalid device heartbeat signature");
50876
51114
  }
50877
- const result = await client.heartbeat(heartbeat, signal);
50878
- if (!result.ok) throw new Error("cloud device heartbeat rejected");
51115
+ let result;
51116
+ try {
51117
+ result = await client.heartbeat(heartbeat, signal);
51118
+ } catch (error2) {
51119
+ if (isHeartbeatRegistrationInvalid(error2)) {
51120
+ throw new DeviceCloudRegistrationInvalidError(error2);
51121
+ }
51122
+ throw error2;
51123
+ }
51124
+ if (!result.ok) throw new DeviceCloudRegistrationInvalidError();
50879
51125
  return void 0;
50880
51126
  }
50881
51127
  async dispose(client, signal) {
@@ -50911,7 +51157,7 @@ var StandardDeviceCloudConnectionAdapter = class {
50911
51157
  throw new AggregateError(errors, "device cloud generation cleanup failed");
50912
51158
  }
50913
51159
  }
50914
- async syncDirectory(client, signal) {
51160
+ async syncDirectory(client, signal, _fence) {
50915
51161
  const cloudDevices = await client.listDevices(signal);
50916
51162
  return {
50917
51163
  commit: async (fence) => {
@@ -50939,6 +51185,7 @@ var StandardDeviceCloudConnectionAdapter = class {
50939
51185
  return this.options.syncDevice(client, peerId, signal);
50940
51186
  }
50941
51187
  classifyError(error2) {
51188
+ if (error2 instanceof DeviceCloudRegistrationInvalidError) return "registration-invalid";
50942
51189
  if (error2 instanceof CloudDeviceFetchError) {
50943
51190
  return error2.code === "cloud_request_failed" ? "offline" : "error";
50944
51191
  }
@@ -50949,6 +51196,35 @@ var StandardDeviceCloudConnectionAdapter = class {
50949
51196
  return active.length > 0 ? [...active] : [...this.relayReservation?.relayMultiaddrs ?? []];
50950
51197
  }
50951
51198
  };
51199
+ function isHeartbeatRegistrationInvalid(error2) {
51200
+ if (!(error2 instanceof CloudDeviceFetchError) || error2.code !== "cloud_http_error") {
51201
+ return false;
51202
+ }
51203
+ if (error2.status === 404) return true;
51204
+ return error2.status === 401 && hasExplicitRegistrationInvalidCode(error2.responseBody);
51205
+ }
51206
+ function hasExplicitRegistrationInvalidCode(responseBody) {
51207
+ const body = responseBody?.trim();
51208
+ if (!body) return false;
51209
+ let value;
51210
+ try {
51211
+ value = JSON.parse(body);
51212
+ } catch {
51213
+ return REGISTRATION_INVALID_ERROR_CODES.has(normalizeErrorCode(body));
51214
+ }
51215
+ return registrationInvalidCodeFromValue(value);
51216
+ }
51217
+ function registrationInvalidCodeFromValue(value) {
51218
+ if (typeof value === "string") {
51219
+ return REGISTRATION_INVALID_ERROR_CODES.has(normalizeErrorCode(value));
51220
+ }
51221
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
51222
+ const record2 = value;
51223
+ return registrationInvalidCodeFromValue(record2.code) || registrationInvalidCodeFromValue(record2.errorCode) || registrationInvalidCodeFromValue(record2.error);
51224
+ }
51225
+ function normalizeErrorCode(value) {
51226
+ return value.trim().toLowerCase().replaceAll("-", "_");
51227
+ }
50952
51228
  function toPublicDeviceIdentity(identity) {
50953
51229
  return {
50954
51230
  peerId: identity.peerId,
@@ -50958,21 +51234,42 @@ function toPublicDeviceIdentity(identity) {
50958
51234
  platform: identity.platform
50959
51235
  };
50960
51236
  }
50961
- function hasValidDirectCloudDeviceAddress(addresses) {
50962
- return addresses.some((address) => {
50963
- if (address.includes("/p2p-circuit")) return false;
50964
- const parts = address.split("/");
50965
- const protocolIndex = parts.findIndex(
50966
- (part) => part === "ip4" || part === "ip6" || part === "dns" || part === "dns4" || part === "dns6"
50967
- );
50968
- if (protocolIndex < 0) return false;
50969
- const host = parts[protocolIndex + 1]?.toLowerCase();
50970
- if (!host) return false;
50971
- const protocol = parts[protocolIndex];
50972
- if (protocol === "ip4") return isPublicIpv4(host);
50973
- if (protocol === "ip6") return isPublicIpv6(host);
50974
- return isPlausiblePublicDnsHost(host);
50975
- });
51237
+ function hasValidDirectCloudDeviceAddress(addresses, expectedPeerId) {
51238
+ return addresses.some((address) => isDialableDirectMultiaddr(address, expectedPeerId));
51239
+ }
51240
+ function isDialableDirectMultiaddr(address, expectedPeerId) {
51241
+ if (address.length === 0 || address.length > 4096 || address !== address.trim() || !address.startsWith("/") || address.endsWith("/") || address.includes("//") || address.includes("/p2p-circuit")) return false;
51242
+ const parts = address.split("/").slice(1);
51243
+ if (parts.some((part) => part.length === 0 || containsAsciiControlOrSpace4(part))) return false;
51244
+ const hostProtocol = parts[0];
51245
+ const host = parts[1]?.toLowerCase();
51246
+ if (host === void 0 || hostProtocol !== "ip4" && hostProtocol !== "ip6" && hostProtocol !== "dns" && hostProtocol !== "dns4" && hostProtocol !== "dns6") return false;
51247
+ const publicHost = hostProtocol === "ip4" ? isPublicIpv4(host) : hostProtocol === "ip6" ? isPublicIpv6(host) : isPlausiblePublicDnsHost(host);
51248
+ if (!publicHost) return false;
51249
+ const transport = parts[2];
51250
+ const port = parsePort(parts[3]);
51251
+ if (transport !== "tcp" || port === void 0) return false;
51252
+ let index = 4;
51253
+ if (parts[index] === "ws" || parts[index] === "wss") index += 1;
51254
+ if (parts[index] === "p2p") {
51255
+ const peerId = parts[index + 1];
51256
+ if (!peerId || containsAsciiControlOrSpace4(peerId)) return false;
51257
+ if (expectedPeerId !== void 0 && peerId !== expectedPeerId) return false;
51258
+ index += 2;
51259
+ }
51260
+ return index === parts.length;
51261
+ }
51262
+ function parsePort(value) {
51263
+ if (value === void 0 || !/^\d{1,5}$/u.test(value)) return void 0;
51264
+ const port = Number(value);
51265
+ return port >= 1 && port <= 65535 ? port : void 0;
51266
+ }
51267
+ function containsAsciiControlOrSpace4(value) {
51268
+ for (let index = 0; index < value.length; index += 1) {
51269
+ const code = value.charCodeAt(index);
51270
+ if (code <= 32 || code === 127) return true;
51271
+ }
51272
+ return false;
50976
51273
  }
50977
51274
  function isPublicIpv4(host) {
50978
51275
  const octets = host.split(".").map((part) => Number(part));
@@ -51012,7 +51309,17 @@ function isPlausiblePublicDnsHost(host) {
51012
51309
  const normalized = host.endsWith(".") ? host.slice(0, -1) : host;
51013
51310
  if (isIpv4Syntax(normalized)) return isPublicIpv4(normalized);
51014
51311
  if (normalized.includes(":")) return isPublicIpv6(normalized);
51015
- if (normalized === "localhost" || normalized.endsWith(".localhost") || normalized.endsWith(".local") || normalized.endsWith(".internal")) return false;
51312
+ const specialUseSuffixes = [
51313
+ "example",
51314
+ "home.arpa",
51315
+ "internal",
51316
+ "invalid",
51317
+ "local",
51318
+ "localhost",
51319
+ "onion",
51320
+ "test"
51321
+ ];
51322
+ if (specialUseSuffixes.some((suffix) => normalized === suffix || normalized.endsWith(`.${suffix}`))) return false;
51016
51323
  const labels = normalized.split(".");
51017
51324
  return labels.length > 1 && labels.every(
51018
51325
  (label) => label.length > 0 && label.length <= 63 && /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/u.test(label)
@@ -51840,7 +52147,7 @@ function readDataIdentifier(value, property, field) {
51840
52147
  }
51841
52148
 
51842
52149
  // src/plugin/loader.ts
51843
- var MEMELOOP_PLUGIN_API_VERSION = "0.2.8";
52150
+ var MEMELOOP_PLUGIN_API_VERSION = "0.2.9";
51844
52151
  var dangerousManifestKeys = /* @__PURE__ */ new Set(["__proto__", "prototype", "constructor"]);
51845
52152
  var manifestKeys = /* @__PURE__ */ new Set(["name", "version", "description", "exports", "author", "minMemeloopVersion"]);
51846
52153
  var exportKeys = /* @__PURE__ */ new Set([
@@ -53359,6 +53666,7 @@ var ToolDefinitionRegistry = class {
53359
53666
  DEVICE_HEARTBEAT_DEFAULT_MAX_CLOCK_SKEW_MS,
53360
53667
  DEVICE_HEARTBEAT_LIMITS,
53361
53668
  DEVICE_HEARTBEAT_SIGNATURE_DOMAIN,
53669
+ DEVICE_ORCHESTRATION_FRAME_LIMITS,
53362
53670
  DEVICE_ORCHESTRATION_PROTOCOL,
53363
53671
  DEVICE_PAIRING_INVITE_MAX_CLOCK_SKEW_MS,
53364
53672
  DEVICE_PAIRING_INVITE_PROTOCOL,