@peers-app/peers-sdk 0.28.8 → 0.28.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.
@@ -91,8 +91,15 @@ export declare class ToolCatalog {
91
91
  })[]): Promise<void>;
92
92
  /** Reject quarantined or conflicting retained evidence before a contract tool call. */
93
93
  assertTargetUsable(target: ToolCatalogTarget): Promise<void>;
94
- /** Serialize host removal with pending publications while retaining all catalog rows. */
95
- removeProvider(provider: string, deactivate: () => void): Promise<void>;
94
+ /**
95
+ * Serialize host removal with pending publications while retaining all catalog rows.
96
+ * An optional load-generation guard runs before any live registration is changed.
97
+ *
98
+ * @param provider - Package whose registrations are being removed.
99
+ * @param deactivate - Synchronously retire its host endpoints and bookkeeping.
100
+ * @param assertCurrent - Reject a superseded removal without changing the active provider.
101
+ */
102
+ removeProvider(provider: string, deactivate: () => void, assertCurrent?: () => void): Promise<void>;
96
103
  /** Stop subscriptions and queued lifecycle work; permanent rows are retained. */
97
104
  dispose(): Promise<void>;
98
105
  }
@@ -605,12 +605,20 @@ class ToolCatalog {
605
605
  validateToolCatalogWrite({ toolId, ...resolvedFields(target, toolId) }, row);
606
606
  }
607
607
  }
608
- /** Serialize host removal with pending publications while retaining all catalog rows. */
609
- async removeProvider(provider, deactivate) {
608
+ /**
609
+ * Serialize host removal with pending publications while retaining all catalog rows.
610
+ * An optional load-generation guard runs before any live registration is changed.
611
+ *
612
+ * @param provider - Package whose registrations are being removed.
613
+ * @param deactivate - Synchronously retire its host endpoints and bookkeeping.
614
+ * @param assertCurrent - Reject a superseded removal without changing the active provider.
615
+ */
616
+ async removeProvider(provider, deactivate, assertCurrent) {
610
617
  // Join the same readiness boundary as publish(), including on a cold context,
611
618
  // so an earlier install cannot enqueue its activation behind this removal.
612
619
  await this.ready();
613
620
  await this.enqueue(async () => {
621
+ assertCurrent?.();
614
622
  this.registry.unregister(provider);
615
623
  deactivate();
616
624
  });
@@ -92,11 +92,13 @@ export interface IIsolatedPackageUninstallOptions {
92
92
  /**
93
93
  * Host-owned supervisor for isolated package providers.
94
94
  *
95
- * `peers-sdk` defines the interface only. Electron (or a future PWA host)
95
+ * `peers-sdk` defines the interface only. Each Electron, headless or browser host
96
96
  * registers a factory that constructs an implementation backed by
97
97
  * `peers-isolate` workers. The SDK never depends on Node or SES.
98
98
  */
99
99
  export interface IIsolatedPackageRuntime {
100
+ /** Supported provider execution modes. Omitted by older hosts that support both modes. */
101
+ readonly supportedExecutionModes?: readonly ("sandbox" | "privileged")[];
100
102
  /**
101
103
  * Register a validated artifact. Provider source is stored, not evaluated
102
104
  * on the host.
@@ -955,13 +955,50 @@ class PackageLoader {
955
955
  throw wrapIsolatedArtifactError(new Error(`Isolated package version mismatch: artifact has "${artifact.manifest.version}" but selected PackageVersion has "${selectedPackageVersion.version}"`));
956
956
  }
957
957
  }
958
+ const hasProvider = artifact.providerSource.trim() !== "";
959
+ const executionMode = artifact.manifest.executionMode ?? "sandbox";
960
+ const unsupportedReason = hasProvider
961
+ ? !this.isolatedRuntime
962
+ ? "This host has no isolated package runtime"
963
+ : this.isolatedRuntime.supportedExecutionModes &&
964
+ !this.isolatedRuntime.supportedExecutionModes.includes(executionMode)
965
+ ? "This package runs only on desktop or headless"
966
+ : undefined
967
+ : undefined;
968
+ if (unsupportedReason) {
969
+ await this.unloadPackage(pkg.packageId, { status: "unsupported", reason: unsupportedReason });
970
+ console.warn(!this.isolatedRuntime
971
+ ? `[PackageLoader] Skipping isolated package "${pkg.name}" because this host does not provide an isolated runtime.`
972
+ : `[PackageLoader] Skipping isolated package "${pkg.name}": ${unsupportedReason}`);
973
+ return undefined;
974
+ }
975
+ // Empty provider source is the validated screen-only artifact shape. A host with
976
+ // no runtime still publishes its navigation, just as a desktop runtime does.
958
977
  if (!this.isolatedRuntime) {
959
- await this.unloadPackage(pkg.packageId, {
960
- status: "unsupported",
961
- reason: "This host has no isolated package runtime",
978
+ await this.toolCatalog.removeProvider(pkg.packageId, () => {
979
+ this.retireHostEndpoints(pkg.packageId);
980
+ (0, contract_resolvers_1.unregisterPackageContractResolvers)(this.dataContext, pkg.packageId);
981
+ this.hostConsumes.delete(pkg.packageId);
982
+ this.contractInstalledPackages.delete(pkg.packageId);
983
+ }, assertCurrent);
984
+ assertCurrent();
985
+ const instance = {
986
+ packageId: artifact.manifest.packageId,
987
+ appNavs: artifact.manifest.appNavs,
988
+ };
989
+ this.packageInstances[pkg.packageId] = instance;
990
+ this.recordRunning(pkg.packageId, {
991
+ ...runningVersionFields(selectedPackageVersion),
992
+ kind: "isolated",
993
+ executionMode,
994
+ provides: [],
995
+ consumes: artifact.manifest.consumes.map(({ contractId, version }) => ({
996
+ contractId,
997
+ version,
998
+ satisfied: !!this.contractRegistry.getProviderPackageId(contractId, version),
999
+ })),
962
1000
  });
963
- console.warn(`[PackageLoader] Skipping isolated package "${pkg.name}" because this host does not provide an isolated runtime.`);
964
- return undefined;
1001
+ return instance;
965
1002
  }
966
1003
  assertCurrent();
967
1004
  if (this.isolatedPackageNames.get(pkg.packageId) !== pkg.name) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@peers-app/peers-sdk",
3
- "version": "0.28.8",
3
+ "version": "0.28.9",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/peers-app/peers-sdk.git"