feat: adopt shared wasm wire schemas; resurrect collab e2e bundle (ysync 0008 A)
- standalone wasm/collab/types.ts: the CollabItem/CollabDelta data shapes now
come from MIT @pcbjam/shared (collab-wire zod schemas) via re-export; the
RUNTIME adapter interface (CollabBridge) stays here. emptyDelta/isEmptyDelta
alias the shared helpers — reconciler untouched.
- tests/collab/browser-entry.ts: fix the import path stale since the repo
restructure (web/apps/frontend → web/standalone) — the collab bundle had been
silently unbuildable; its opts type now tracks startCollab's real signature.
- tests/kicad/*-collab.spec.ts: update KicadCollab.start calls from the
pre-ysync-0004 { channel, settleMs } API to { provider: { kind:
"broadcastchannel", settleMs }, room } — the drift the broken bundle hid.
Verified: pl_editor 2/2, eeschema 2 passed, pcbnew 7 passed (skips pre-existing);
shared 47 unit tests; both typechecks clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
c98e88c33b
commit
b69ba09ebd
7 changed files with 28 additions and 26 deletions
|
|
@ -16,11 +16,12 @@ import {
|
|||
function start(
|
||||
mod: CollabModule,
|
||||
win: CollabWindow,
|
||||
opts: { channel: string; settleMs?: number },
|
||||
// Same opts as startCollab itself (ysync 0004: { provider, room }).
|
||||
opts: Parameters<typeof startCollab>[2],
|
||||
): ReturnType<typeof startCollab> {
|
||||
return startCollab(mod, win, {
|
||||
provider: { kind: "broadcastchannel", settleMs: opts.settleMs },
|
||||
room: opts.channel,
|
||||
room: opts.room,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -240,7 +240,7 @@ test.describe("eeschema collab bridge — two tabs (BroadcastChannel)", () => {
|
|||
KicadCollab: { start: (m: unknown, win: unknown, o: unknown) => Promise<unknown> };
|
||||
Module: unknown;
|
||||
};
|
||||
await w.KicadCollab.start(w.Module, window, { channel: ch, settleMs: 500 });
|
||||
await w.KicadCollab.start(w.Module, window, { provider: { kind: "broadcastchannel", settleMs: 500 }, room: ch });
|
||||
}, channel);
|
||||
await startCollab(tabA);
|
||||
await startCollab(tabB);
|
||||
|
|
|
|||
|
|
@ -414,7 +414,7 @@ test.describe("pcbnew collab bridge — two tabs (BroadcastChannel)", () => {
|
|||
KicadCollab: { start: (m: unknown, win: unknown, o: unknown) => Promise<unknown> };
|
||||
Module: unknown;
|
||||
};
|
||||
await w.KicadCollab.start(w.Module, window, { channel: ch, settleMs: 500 });
|
||||
await w.KicadCollab.start(w.Module, window, { provider: { kind: "broadcastchannel", settleMs: 500 }, room: ch });
|
||||
}, channel);
|
||||
await startCollab(tabA);
|
||||
await startCollab(tabB);
|
||||
|
|
|
|||
|
|
@ -195,7 +195,7 @@ test.describe("pl_editor collab bridge — two tabs (BroadcastChannel)", () => {
|
|||
Module: unknown;
|
||||
__collab?: unknown;
|
||||
};
|
||||
w.__collab = await w.KicadCollab.start(w.Module, window, { channel: ch, settleMs: 500 });
|
||||
w.__collab = await w.KicadCollab.start(w.Module, window, { provider: { kind: "broadcastchannel", settleMs: 500 }, room: ch });
|
||||
}, channel);
|
||||
await startCollab(tabA);
|
||||
await startCollab(tabB);
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit 011962c0992c5c30eba5487033f0c3609712dd28
|
||||
Subproject commit 26d2d7951ba6a9574ff5149fb1a29a2a69d9176c
|
||||
3
web/pnpm-lock.yaml
generated
3
web/pnpm-lock.yaml
generated
|
|
@ -45,6 +45,9 @@ importers:
|
|||
'@ts-rest/core':
|
||||
specifier: ^3.52.1
|
||||
version: 3.52.1(@types/node@22.19.19)(zod@3.25.76)
|
||||
yjs:
|
||||
specifier: ^13.6.18
|
||||
version: 13.6.31
|
||||
zod:
|
||||
specifier: ^3.24.1
|
||||
version: 3.25.76
|
||||
|
|
|
|||
|
|
@ -1,18 +1,21 @@
|
|||
// Wire contract shared with the C++ bridge (wasm/bindings/pl_editor_embind.cpp).
|
||||
// Schema-agnostic by design: an item is just { id, type, …arbitrary fields }. The
|
||||
// reconciler hardcodes no field names — it diffs values keyed by field name.
|
||||
// Wire contract shared with the C++ bridge (wasm/bindings/*_embind.cpp).
|
||||
//
|
||||
// The data shapes (CollabItem / CollabDelta) and their zod schemas now live in
|
||||
// MIT `@pcbjam/shared` (collab-wire.ts, ysync 0008) so any consumer — this GPL
|
||||
// editor, tests, a backend — can validate the wasm from-to JSON against one
|
||||
// source of truth. This module re-exports them under the established local names
|
||||
// and keeps the RUNTIME adapter interface (CollabBridge), which is about how this
|
||||
// app talks to a live wasm Module, not about the data.
|
||||
|
||||
export type CollabItem = {
|
||||
id: string;
|
||||
type: string;
|
||||
[field: string]: unknown;
|
||||
};
|
||||
import {
|
||||
emptyCollabDelta,
|
||||
isEmptyCollabDelta,
|
||||
type CollabDelta,
|
||||
type CollabItem,
|
||||
} from "@pcbjam/shared";
|
||||
|
||||
export type CollabDelta = {
|
||||
added: CollabItem[];
|
||||
changed: CollabItem[];
|
||||
removed: string[]; // uuids
|
||||
};
|
||||
export { collabDeltaSchema, collabItemSchema, parseCollabDelta } from "@pcbjam/shared";
|
||||
export type { CollabDelta, CollabItem };
|
||||
|
||||
/**
|
||||
* The two C++ bridge entry points + the emit hook, abstracted so the reconciler is
|
||||
|
|
@ -27,10 +30,5 @@ export interface CollabBridge {
|
|||
onDelta(cb: (deltaJson: string) => void): void;
|
||||
}
|
||||
|
||||
export function emptyDelta(): CollabDelta {
|
||||
return { added: [], changed: [], removed: [] };
|
||||
}
|
||||
|
||||
export function isEmptyDelta(d: CollabDelta): boolean {
|
||||
return d.added.length === 0 && d.changed.length === 0 && d.removed.length === 0;
|
||||
}
|
||||
export const emptyDelta = emptyCollabDelta;
|
||||
export const isEmptyDelta = isEmptyCollabDelta;
|
||||
|
|
|
|||
Loading…
Reference in a new issue