@calimero-network/mero-js 2.2.1 → 2.4.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/index.cjs CHANGED
@@ -34,6 +34,7 @@ __export(index_exports, {
34
34
  WsClient: () => WsClient,
35
35
  buildAuthLoginUrl: () => buildAuthLoginUrl,
36
36
  combineSignals: () => combineSignals,
37
+ compareSemver: () => compareSemver,
37
38
  createAdminApiClient: () => createAdminApiClient,
38
39
  createAdminApiClientFromHttpClient: () => createAdminApiClientFromHttpClient,
39
40
  createAuthApiClient: () => createAuthApiClient,
@@ -697,6 +698,24 @@ function createAuthApiClientFromHttpClient(httpClient, _config) {
697
698
  function unwrap(response) {
698
699
  return response.data;
699
700
  }
701
+ function compareSemver(a, b) {
702
+ const pa = a.split(".");
703
+ const pb = b.split(".");
704
+ const n = Math.max(pa.length, pb.length);
705
+ for (let i = 0; i < n; i++) {
706
+ const sa = pa[i] ?? "0";
707
+ const sb = pb[i] ?? "0";
708
+ const na = Number.parseInt(sa, 10);
709
+ const nb = Number.parseInt(sb, 10);
710
+ if (Number.isNaN(na) || Number.isNaN(nb)) {
711
+ const c = sa.localeCompare(sb);
712
+ if (c !== 0) return c;
713
+ } else if (na !== nb) {
714
+ return na - nb;
715
+ }
716
+ }
717
+ return 0;
718
+ }
700
719
  var AdminApiClient = class {
701
720
  constructor(httpClient) {
702
721
  this.httpClient = httpClient;
@@ -712,6 +731,57 @@ var AdminApiClient = class {
712
731
  async installApplication(request) {
713
732
  return unwrap(await this.httpClient.post("/admin-api/install-application", request));
714
733
  }
734
+ /**
735
+ * Resolve a `package@version` to its registry artifact URL and install it.
736
+ * Node install is URL-based (no node-side package+version resolution), so this
737
+ * fetches the bundle manifest from the registry, derives the `.mpk` artifact
738
+ * URL, then calls {@link installApplication}. `registryUrl` is the registry
739
+ * origin. This is the discrete "download" step an Updates flow pairs with a
740
+ * subsequent `upgradeGroup`.
741
+ */
742
+ async installFromRegistry(registryUrl, packageName, version) {
743
+ const base = new URL(registryUrl).origin;
744
+ const manifestUrl = new URL(
745
+ `/api/v2/bundles/${encodeURIComponent(packageName)}/${encodeURIComponent(version)}`,
746
+ base
747
+ ).toString();
748
+ const resp = await fetch(manifestUrl);
749
+ if (!resp.ok) {
750
+ throw new Error(
751
+ `registry manifest fetch failed (${resp.status}) for ${packageName}@${version}`
752
+ );
753
+ }
754
+ const bundle = await resp.json();
755
+ const pkg = encodeURIComponent(bundle.package);
756
+ const ver = encodeURIComponent(bundle.appVersion);
757
+ const artifactUrl = `${base}/artifacts/${pkg}/${ver}/${pkg}-${ver}.mpk`;
758
+ return this.installApplication({
759
+ url: artifactUrl,
760
+ package: bundle.package,
761
+ version: bundle.appVersion,
762
+ metadata: []
763
+ });
764
+ }
765
+ /**
766
+ * List a package's published versions from the registry, newest-first by
767
+ * semver. Reads the registry's V2 bundle listing
768
+ * (`GET {registry}/api/v2/bundles?package={package}`), taking each bundle's
769
+ * `appVersion`. Registry-side data — distinct from the node's
770
+ * installed-version list — and the source an Updates view compares against
771
+ * the running `Context.applicationVersion` to detect "a new version exists".
772
+ */
773
+ async getRegistryVersions(registryUrl, packageName) {
774
+ const url = new URL("/api/v2/bundles", new URL(registryUrl).origin);
775
+ url.searchParams.set("package", packageName);
776
+ const resp = await fetch(url.toString());
777
+ if (!resp.ok) {
778
+ throw new Error(
779
+ `registry versions fetch failed (${resp.status}) for ${packageName}`
780
+ );
781
+ }
782
+ const bundles = await resp.json();
783
+ return (Array.isArray(bundles) ? bundles : []).map((b) => b.appVersion).filter((v) => typeof v === "string").sort((a, b) => compareSemver(b, a));
784
+ }
715
785
  async installDevApplication(request) {
716
786
  return unwrap(await this.httpClient.post("/admin-api/install-dev-application", request));
717
787
  }
@@ -1064,6 +1134,22 @@ var AdminApiClient = class {
1064
1134
  await this.httpClient.get(`/admin-api/groups/${groupId}/upgrade/status`)
1065
1135
  );
1066
1136
  }
1137
+ /**
1138
+ * The operator-facing "have all peers migrated?" rollup for a namespace.
1139
+ * The handler serializes the payload directly, so there is no `{ data }`
1140
+ * envelope to unwrap here (unlike most admin reads).
1141
+ */
1142
+ async getMigrationStatus(namespaceId) {
1143
+ const id = encodeURIComponent(namespaceId);
1144
+ return this.httpClient.get(`/admin-api/groups/${id}/migration-status`);
1145
+ }
1146
+ /** Per-group cascade-migration snapshots for a namespace. */
1147
+ async getCascadeStatus(namespaceId) {
1148
+ const id = encodeURIComponent(namespaceId);
1149
+ return unwrap(
1150
+ await this.httpClient.get(`/admin-api/groups/${id}/cascade-status`)
1151
+ );
1152
+ }
1067
1153
  async retryGroupUpgrade(groupId, request) {
1068
1154
  return unwrap(
1069
1155
  await this.httpClient.post(
@@ -1262,6 +1348,19 @@ var RpcClient = class {
1262
1348
  }
1263
1349
  return response.result;
1264
1350
  }
1351
+ /**
1352
+ * One-tap owner-driven convert: re-signs the caller's identity-gated entries
1353
+ * to the current schema. The export converts all of the caller's
1354
+ * below-target entries in a single sweep, so this issues one call and returns
1355
+ * the resulting summary — it does not loop.
1356
+ */
1357
+ async migrateMyEntries(contextId) {
1358
+ return this.execute({ contextId, method: "migrate_my_entries" });
1359
+ }
1360
+ /** Read-only count of the caller's entries still below the target schema. */
1361
+ async countMyPending(contextId) {
1362
+ return this.execute({ contextId, method: "count_my_pending" });
1363
+ }
1265
1364
  };
1266
1365
 
1267
1366
  // src/events/sse.ts
@@ -1292,6 +1391,20 @@ var SseClient = class {
1292
1391
  if (idx !== -1) arr.splice(idx, 1);
1293
1392
  }
1294
1393
  }
1394
+ /**
1395
+ * Typed convenience over the generic `'event'` stream: invokes `handler` only
1396
+ * for `AppVersionChanged` context events, with the payload already parsed.
1397
+ * Returns an unsubscribe closure (so callers need not retain the listener).
1398
+ */
1399
+ onAppVersionChanged(handler) {
1400
+ const listener = (ev) => {
1401
+ const d = ev.data;
1402
+ if (d?.type !== "AppVersionChanged") return;
1403
+ handler({ contextId: ev.contextId, fromVersion: d.data?.fromVersion, toVersion: d.data?.toVersion });
1404
+ };
1405
+ this.on("event", listener);
1406
+ return () => this.off("event", listener);
1407
+ }
1295
1408
  emit(event, arg) {
1296
1409
  const key = event;
1297
1410
  if (key in this.listeners) {