@spooky-sync/core 0.0.1-canary.86 → 0.0.1-canary.88

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
@@ -414,7 +414,7 @@ var DataModule = class {
414
414
  onDeregister;
415
415
  sessionId = "";
416
416
  currentUserId = null;
417
- constructor(cache, local, schema, logger, streamDebounceTime = 100) {
417
+ constructor(cache, local, schema, logger, streamDebounceTime = 50) {
418
418
  this.cache = cache;
419
419
  this.local = local;
420
420
  this.schema = schema;
@@ -3484,14 +3484,15 @@ function parseBackendInfo(raw) {
3484
3484
 
3485
3485
  //#endregion
3486
3486
  //#region src/modules/devtools/index.ts
3487
- const CORE_VERSION = "0.0.1-canary.86";
3488
- const WASM_VERSION = "0.0.1-canary.86";
3487
+ const CORE_VERSION = "0.0.1-canary.88";
3488
+ const WASM_VERSION = "0.0.1-canary.88";
3489
3489
  const SURREAL_VERSION = "3.0.3";
3490
3490
  var DevToolsService = class {
3491
3491
  eventsHistory = [];
3492
3492
  eventIdCounter = 0;
3493
3493
  version = CORE_VERSION;
3494
3494
  backendInfo = emptyBackendInfo();
3495
+ enabled = false;
3495
3496
  constructor(databaseService, remoteDatabaseService, logger, schema, authService, dataManager) {
3496
3497
  this.databaseService = databaseService;
3497
3498
  this.remoteDatabaseService = remoteDatabaseService;
@@ -3500,6 +3501,14 @@ var DevToolsService = class {
3500
3501
  this.authService = authService;
3501
3502
  this.dataManager = dataManager;
3502
3503
  this.exposeToWindow();
3504
+ if (typeof window !== "undefined") window.addEventListener("message", (e) => {
3505
+ if (e.source !== window) return;
3506
+ const type = e.data?.type;
3507
+ if (type === "SP00KY_DEVTOOLS_CONNECT") {
3508
+ this.enabled = true;
3509
+ this.notifyDevTools();
3510
+ } else if (type === "SP00KY_DEVTOOLS_DISCONNECT") this.enabled = false;
3511
+ });
3503
3512
  this.authService.eventSystem.subscribe(AuthEventTypes.AuthStateChanged, () => {
3504
3513
  this.notifyDevTools();
3505
3514
  });
@@ -3606,6 +3615,7 @@ var DevToolsService = class {
3606
3615
  this.notifyDevTools();
3607
3616
  }
3608
3617
  addEvent(eventType, payload) {
3618
+ if (!this.enabled) return;
3609
3619
  this.eventsHistory.push({
3610
3620
  id: this.eventIdCounter++,
3611
3621
  timestamp: Date.now(),
@@ -3639,6 +3649,7 @@ var DevToolsService = class {
3639
3649
  });
3640
3650
  }
3641
3651
  notifyDevTools() {
3652
+ if (!this.enabled) return;
3642
3653
  if (typeof window !== "undefined") window.postMessage({
3643
3654
  type: "SP00KY_STATE_CHANGED",
3644
3655
  source: "sp00ky-devtools-page",
package/dist/types.d.ts CHANGED
@@ -263,8 +263,10 @@ interface Sp00kyConfig<S extends SchemaStructure> {
263
263
  /** A pino browser transmit object for forwarding logs (e.g. via @spooky-sync/core/otel). */
264
264
  otelTransmit?: PinoTransmit;
265
265
  /**
266
- * Debounce time in milliseconds for stream updates.
267
- * Defaults to 100ms.
266
+ * Debounce time in milliseconds for stream updates (the client-side SSP
267
+ * aggregation throttle — coalesces the in-browser StreamProcessor's
268
+ * per-record updates per query before notifying readers).
269
+ * Defaults to 50ms.
268
270
  */
269
271
  streamDebounceTime?: number;
270
272
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spooky-sync/core",
3
- "version": "0.0.1-canary.86",
3
+ "version": "0.0.1-canary.88",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -59,8 +59,8 @@
59
59
  }
60
60
  },
61
61
  "dependencies": {
62
- "@spooky-sync/query-builder": "0.0.1-canary.86",
63
- "@spooky-sync/ssp-wasm": "0.0.1-canary.86",
62
+ "@spooky-sync/query-builder": "0.0.1-canary.88",
63
+ "@spooky-sync/ssp-wasm": "0.0.1-canary.88",
64
64
  "@surrealdb/wasm": "^3.0.3",
65
65
  "fast-json-patch": "^3.1.1",
66
66
  "loro-crdt": "^1.5.6",
@@ -116,7 +116,12 @@ export class DataModule<S extends SchemaStructure> {
116
116
  private local: LocalDatabaseService,
117
117
  private schema: S,
118
118
  logger: Logger,
119
- private streamDebounceTime: number = 100
119
+ // Client-side SSP aggregation throttle: coalesces the in-browser
120
+ // StreamProcessor's per-record stream updates per query before notifying
121
+ // readers, so a burst of synced records repaints the UI once per window
122
+ // rather than row-by-row. 50ms keeps it responsive while still batching the
123
+ // initial-sync stream. Override via `SyncedDbConfig.streamDebounceTime`.
124
+ private streamDebounceTime: number = 50
120
125
  ) {
121
126
  this.logger = logger.child({ service: 'DataModule' });
122
127
  }
@@ -42,6 +42,12 @@ export class DevToolsService implements StreamUpdateReceiver {
42
42
  // Backend stack info (versions + per-entity status), read via the
43
43
  // `fn::spooky::info()` SurrealQL function; empty/'unavailable' until resolved.
44
44
  private backendInfo: BackendInfo = emptyBackendInfo();
45
+ // Dormant until a devtools consumer (extension panel or MCP) handshakes via
46
+ // `SP00KY_DEVTOOLS_CONNECT`. While false, `notifyDevTools()`/`addEvent()` do no
47
+ // work, so prod pays zero serialization/postMessage cost for an unwatched panel.
48
+ // `window.__00__.getState()` stays live regardless, so the panel's first paint
49
+ // (the on-demand GET_STATE pull) still works before the push channel turns on.
50
+ private enabled = false;
45
51
 
46
52
  constructor(
47
53
  private databaseService: LocalDatabaseService,
@@ -53,6 +59,22 @@ export class DevToolsService implements StreamUpdateReceiver {
53
59
  ) {
54
60
  this.exposeToWindow();
55
61
 
62
+ // Stay dormant until a devtools consumer announces itself. The extension's
63
+ // page-script posts this once it detects `window.__00__`; the panel can also
64
+ // disconnect to return us to dormant. Until then we skip all serialization.
65
+ if (typeof window !== 'undefined') {
66
+ window.addEventListener('message', (e) => {
67
+ if (e.source !== window) return;
68
+ const type = (e.data as { type?: string } | undefined)?.type;
69
+ if (type === 'SP00KY_DEVTOOLS_CONNECT') {
70
+ this.enabled = true;
71
+ this.notifyDevTools();
72
+ } else if (type === 'SP00KY_DEVTOOLS_DISCONNECT') {
73
+ this.enabled = false;
74
+ }
75
+ });
76
+ }
77
+
56
78
  // Subscribe to auth events
57
79
  this.authService.eventSystem.subscribe(AuthEventTypes.AuthStateChanged, () => {
58
80
  this.notifyDevTools();
@@ -197,6 +219,8 @@ export class DevToolsService implements StreamUpdateReceiver {
197
219
  }
198
220
 
199
221
  private addEvent(eventType: string, payload: any) {
222
+ // No consumer attached → skip recording (and the recursive serialize it does).
223
+ if (!this.enabled) return;
200
224
  this.eventsHistory.push({
201
225
  id: this.eventIdCounter++,
202
226
  timestamp: Date.now(),
@@ -232,6 +256,8 @@ export class DevToolsService implements StreamUpdateReceiver {
232
256
  }
233
257
 
234
258
  private notifyDevTools() {
259
+ // No consumer attached → no getState() serialization, no postMessage broadcast.
260
+ if (!this.enabled) return;
235
261
  if (typeof window !== 'undefined') {
236
262
  window.postMessage(
237
263
  {
package/src/types.ts CHANGED
@@ -113,8 +113,10 @@ export interface Sp00kyConfig<S extends SchemaStructure> {
113
113
  /** A pino browser transmit object for forwarding logs (e.g. via @spooky-sync/core/otel). */
114
114
  otelTransmit?: PinoTransmit;
115
115
  /**
116
- * Debounce time in milliseconds for stream updates.
117
- * Defaults to 100ms.
116
+ * Debounce time in milliseconds for stream updates (the client-side SSP
117
+ * aggregation throttle — coalesces the in-browser StreamProcessor's
118
+ * per-record updates per query before notifying readers).
119
+ * Defaults to 50ms.
118
120
  */
119
121
  streamDebounceTime?: number;
120
122
  /**