@spooky-sync/core 0.0.1-canary.155 → 0.0.1-canary.156

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.js CHANGED
@@ -5694,8 +5694,8 @@ async function walkOpfs(maxEntries = 2e3, maxDepth = 8) {
5694
5694
 
5695
5695
  //#endregion
5696
5696
  //#region src/modules/devtools/index.ts
5697
- const CORE_VERSION = "0.0.1-canary.155";
5698
- const WASM_VERSION = "0.0.1-canary.155";
5697
+ const CORE_VERSION = "0.0.1-canary.156";
5698
+ const WASM_VERSION = "0.0.1-canary.156";
5699
5699
  const SURREAL_VERSION = "3.0.3";
5700
5700
  var DevToolsService = class {
5701
5701
  eventsHistory = [];
@@ -5703,7 +5703,8 @@ var DevToolsService = class {
5703
5703
  version = CORE_VERSION;
5704
5704
  backendInfo = emptyBackendInfo();
5705
5705
  enabled = false;
5706
- /** Shared-tabs snapshot for the panel, wired by Sp00kyClient when active. */
5706
+ /** Shared-tabs snapshot for the panel, wired by Sp00kyClient whenever the
5707
+ * feature was REQUESTED (so an inactive/degraded tab still reports why). */
5707
5708
  tabsInfoProvider = null;
5708
5709
  setTabsInfoProvider(provider) {
5709
5710
  this.tabsInfoProvider = provider;
@@ -5925,6 +5926,7 @@ var DevToolsService = class {
5925
5926
  status: "unknown",
5926
5927
  fallback: false
5927
5928
  },
5929
+ tabs: this.tabsInfoProvider?.() ?? null,
5928
5930
  browser: {},
5929
5931
  opfs: {
5930
5932
  supported: false,
@@ -8784,24 +8786,33 @@ var Sp00kyClient = class {
8784
8786
  this.devTools = new DevToolsService(this.local, this.remote, logger, this.config.schema, this.auth, this.dataModule);
8785
8787
  this.streamProcessor.addReceiver(this.devTools);
8786
8788
  this.setupCallbacks();
8787
- if (tabsSupport.supported) {
8788
- this.tabsCoordinator = this.buildTabsCoordinator();
8789
+ if (tabsSupport.supported) this.tabsCoordinator = this.buildTabsCoordinator();
8790
+ else if (this.config.sharedTabs) this.logger.info({
8791
+ reason: tabsSupport.reason,
8792
+ Category: "sp00ky-client::Sp00kyClient::tabs"
8793
+ }, "sharedTabs requested but unsupported here; running solo");
8794
+ if (this.config.sharedTabs) {
8795
+ const unsupportedReason = tabsSupport.supported ? void 0 : tabsSupport.reason;
8789
8796
  this.devTools.setTabsInfoProvider(() => {
8790
- if (!this.sharedActive || !this.tabsCoordinator) return null;
8791
8797
  const c = this.tabsCoordinator;
8798
+ if (!this.sharedActive || !c) return {
8799
+ active: false,
8800
+ reason: unsupportedReason ?? "fell-back"
8801
+ };
8802
+ const hub = c.syncHub;
8792
8803
  return {
8804
+ active: true,
8793
8805
  role: c.role,
8794
8806
  tabId: c.tabId,
8795
8807
  leadershipId: c.leadershipId,
8796
- leaderTabId: c.leaderTabId,
8797
- followers: c.syncHub?.followerCount ?? null,
8798
- relayedBatches: c.syncHub?.relayedBatches ?? null
8808
+ leaderTabId: c.role === "leader" ? c.tabId : c.leaderTabId,
8809
+ ...hub ? {
8810
+ followers: hub.followerCount,
8811
+ relayedBatches: hub.relayedBatches
8812
+ } : {}
8799
8813
  };
8800
8814
  });
8801
- } else if (this.config.sharedTabs) this.logger.info({
8802
- reason: tabsSupport.reason,
8803
- Category: "sp00ky-client::Sp00kyClient::tabs"
8804
- }, "sharedTabs requested but unsupported here; running solo");
8815
+ }
8805
8816
  }
8806
8817
  /** The shared-tabs role machinery, wired to this client's modules. */
8807
8818
  buildTabsCoordinator() {
@@ -8810,7 +8821,7 @@ var Sp00kyClient = class {
8810
8821
  return new TabsCoordinator({
8811
8822
  tabId,
8812
8823
  fingerprint: computeTabsFingerprint({
8813
- coreVersion: "0.0.1-canary.155",
8824
+ coreVersion: "0.0.1-canary.156",
8814
8825
  schemaHash: hash53(this.config.schemaSurql),
8815
8826
  endpoint: this.config.database.endpoint ?? "",
8816
8827
  namespace: this.config.database.namespace,
package/dist/types.d.ts CHANGED
@@ -199,6 +199,13 @@ interface EngineStorageDiagnostics {
199
199
  }[];
200
200
  error?: string;
201
201
  }
202
+ /**
203
+ * Shared-tabs coordination state. Reported ONLY when `sharedTabs: true` was
204
+ * configured (apps that never asked for it get `null`, so the panel shows
205
+ * nothing). `active: false` with a `reason` is itself the useful signal: the
206
+ * app asked to share one store and this tab is not, so it owns or contends for
207
+ * the OPFS pool alone.
208
+ */
202
209
  //#endregion
203
210
  //#region src/services/database/cache-engine.d.ts
204
211
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spooky-sync/core",
3
- "version": "0.0.1-canary.155",
3
+ "version": "0.0.1-canary.156",
4
4
  "type": "module",
5
5
  "sideEffects": false,
6
6
  "main": "./dist/index.js",
@@ -60,8 +60,8 @@
60
60
  }
61
61
  },
62
62
  "dependencies": {
63
- "@spooky-sync/query-builder": "0.0.1-canary.155",
64
- "@spooky-sync/ssp-wasm": "0.0.1-canary.155",
63
+ "@spooky-sync/query-builder": "0.0.1-canary.156",
64
+ "@spooky-sync/ssp-wasm": "0.0.1-canary.156",
65
65
  "@sqlite.org/sqlite-wasm": "3.53.0-build1",
66
66
  "@surrealdb/wasm": "^3.0.3",
67
67
  "fast-json-patch": "^3.1.1",
@@ -22,7 +22,7 @@ import {
22
22
  parseBackendInfo,
23
23
  UNAVAILABLE,
24
24
  } from './versions';
25
- import { walkOpfs, type StorageInfo } from './storage-info';
25
+ import { walkOpfs, type SharedTabsInfo, type StorageInfo } from './storage-info';
26
26
 
27
27
  // Real bundled frontend versions, injected at build time by tsdown's
28
28
  // version-define plugin (see tsdown.config.ts). The `typeof` guard keeps these
@@ -51,10 +51,11 @@ export class DevToolsService implements StreamUpdateReceiver {
51
51
  // (the on-demand GET_STATE pull) still works before the push channel turns on.
52
52
  private enabled = false;
53
53
 
54
- /** Shared-tabs snapshot for the panel, wired by Sp00kyClient when active. */
55
- private tabsInfoProvider: (() => Record<string, unknown> | null) | null = null;
54
+ /** Shared-tabs snapshot for the panel, wired by Sp00kyClient whenever the
55
+ * feature was REQUESTED (so an inactive/degraded tab still reports why). */
56
+ private tabsInfoProvider: (() => SharedTabsInfo | null) | null = null;
56
57
 
57
- setTabsInfoProvider(provider: () => Record<string, unknown> | null): void {
58
+ setTabsInfoProvider(provider: () => SharedTabsInfo | null): void {
58
59
  this.tabsInfoProvider = provider;
59
60
  }
60
61
 
@@ -357,6 +358,7 @@ export class DevToolsService implements StreamUpdateReceiver {
357
358
  bucketId: this.databaseService.currentBucketId,
358
359
  },
359
360
  health: this.databaseService.storageHealth ?? { status: 'unknown', fallback: false },
361
+ tabs: this.tabsInfoProvider?.() ?? null,
360
362
  browser: {},
361
363
  opfs: { supported: false, entries: [], totalBytes: 0, truncated: false },
362
364
  };
@@ -31,10 +31,37 @@ export interface EngineStorageDiagnostics {
31
31
  error?: string;
32
32
  }
33
33
 
34
+ /**
35
+ * Shared-tabs coordination state. Reported ONLY when `sharedTabs: true` was
36
+ * configured (apps that never asked for it get `null`, so the panel shows
37
+ * nothing). `active: false` with a `reason` is itself the useful signal: the
38
+ * app asked to share one store and this tab is not, so it owns or contends for
39
+ * the OPFS pool alone.
40
+ */
41
+ export interface SharedTabsInfo {
42
+ active: boolean;
43
+ /** Why inactive: a capability gate reason, or 'fell-back' when the broker
44
+ * was reachable but no role landed (election timeout, rejected tab). */
45
+ reason?: string;
46
+ role?: 'solo' | 'leader' | 'follower';
47
+ /** This tab's id (also the suffix of every mutation id it mints). */
48
+ tabId?: string;
49
+ /** Monotonic id of the current leadership term; embedded in the worker lock. */
50
+ leadershipId?: number;
51
+ /** Who owns the store: this tab when leader, else the leader's tab id. */
52
+ leaderTabId?: string | null;
53
+ /** Leader only: attached follower tabs. */
54
+ followers?: number;
55
+ /** Leader only: ingest batches relayed to followers so far. */
56
+ relayedBatches?: number;
57
+ }
58
+
34
59
  export interface StorageInfo {
35
60
  at: number;
36
61
  engine: { kind: 'surrealdb' | 'sqlite' | 'custom'; store: string; bucketId: string };
37
62
  health: { status: 'unknown' | 'persistent' | 'memory'; fallback: boolean; error?: string };
63
+ /** Shared-tabs state, or null when the feature was never requested. */
64
+ tabs?: SharedTabsInfo | null;
38
65
  browser: {
39
66
  /** `navigator.storage.persisted()` — whether the origin's storage is
40
67
  * exempt from eviction (unrelated to the OPFS pool lock). */
package/src/sp00ky.ts CHANGED
@@ -368,23 +368,35 @@ export class Sp00kyClient<S extends SchemaStructure> {
368
368
  // every module. Nothing starts until init() calls coordinator.start().
369
369
  if (tabsSupport.supported) {
370
370
  this.tabsCoordinator = this.buildTabsCoordinator();
371
+ } else if (this.config.sharedTabs) {
372
+ this.logger.info(
373
+ { reason: (tabsSupport as { reason: string }).reason, Category: 'sp00ky-client::Sp00kyClient::tabs' },
374
+ 'sharedTabs requested but unsupported here; running solo'
375
+ );
376
+ }
377
+ // Report shared-tabs state whenever the feature was REQUESTED, active or
378
+ // not: "asked to share one store, running alone because X" is exactly the
379
+ // thing you need to see in the panel. Apps that never set the flag report
380
+ // null and the panel shows no section at all.
381
+ if (this.config.sharedTabs) {
382
+ const unsupportedReason = tabsSupport.supported
383
+ ? undefined
384
+ : (tabsSupport as { reason: string }).reason;
371
385
  this.devTools.setTabsInfoProvider(() => {
372
- if (!this.sharedActive || !this.tabsCoordinator) return null;
373
386
  const c = this.tabsCoordinator;
387
+ if (!this.sharedActive || !c) {
388
+ return { active: false, reason: unsupportedReason ?? 'fell-back' };
389
+ }
390
+ const hub = c.syncHub;
374
391
  return {
392
+ active: true,
375
393
  role: c.role,
376
394
  tabId: c.tabId,
377
395
  leadershipId: c.leadershipId,
378
- leaderTabId: c.leaderTabId,
379
- followers: c.syncHub?.followerCount ?? null,
380
- relayedBatches: c.syncHub?.relayedBatches ?? null,
396
+ leaderTabId: c.role === 'leader' ? c.tabId : c.leaderTabId,
397
+ ...(hub ? { followers: hub.followerCount, relayedBatches: hub.relayedBatches } : {}),
381
398
  };
382
399
  });
383
- } else if (this.config.sharedTabs) {
384
- this.logger.info(
385
- { reason: (tabsSupport as { reason: string }).reason, Category: 'sp00ky-client::Sp00kyClient::tabs' },
386
- 'sharedTabs requested but unsupported here; running solo'
387
- );
388
400
  }
389
401
  }
390
402