@skaile/connector-yjs 0.1.1 → 0.1.3

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/CHANGELOG.md CHANGED
@@ -1,5 +1,24 @@
1
1
  # @skaile/connector-yjs
2
2
 
3
+ ## 0.1.3
4
+
5
+ ### Patch Changes
6
+
7
+ - [#1100](https://github.com/skaile-ai/workspaces/pull/1100) [`3a3aa72`](https://github.com/skaile-ai/workspaces/commit/3a3aa72a169904ebc758a7d029ffa95b2c8178a7) Thanks [@mortegro](https://github.com/mortegro)! - Peer range for `@skaile/workspaces` is now `^6.0.0` (harness replaces driver in 6.0.0; these plugins use no renamed API).
8
+
9
+ ## 0.1.2
10
+
11
+ ### Patch Changes
12
+
13
+ - [#115](https://github.com/skaile-ai/workspaces/pull/115) [`ed78a7d`](https://github.com/skaile-ai/workspaces/commit/ed78a7d1f9e9de7cca8be861c6198b600aa85ba1) Thanks [@mortegro](https://github.com/mortegro)! - Internal code-quality cleanup guided by `fallow`: removed dead code (3 orphan dev
14
+ scripts, an unused integration test setup, ~15 internal-only exports/re-exports, 2
15
+ unused private methods, and the unused `picomatch` dependency) and reduced cognitive
16
+ complexity across 48 source files via behavior-preserving extract-function refactors
17
+ (e.g. `serve.ts` `handleCommand` 336→thin dispatcher; `workspace-config.ts`,
18
+ `publish-manifest.ts`, `claude-sdk.ts`, and many others). No public API, exported
19
+ signatures, or runtime behavior changed; the full test suite (3121 tests) passes
20
+ unchanged.
21
+
3
22
  ## 0.1.1
4
23
 
5
24
  ### Patch Changes
package/dist/index.d.ts CHANGED
@@ -35,6 +35,13 @@ declare class YjsConnector extends AbstractConnector {
35
35
  private _search;
36
36
  private _describeOperations;
37
37
  private _executeOp;
38
+ private _opSnapshot;
39
+ private _opGet;
40
+ private _opKeys;
41
+ private _opHistory;
42
+ private _opSet;
43
+ private _opMerge;
44
+ private _opDel;
38
45
  private _getY;
39
46
  /** Convert a JS value to a Yjs-compatible value. */
40
47
  private _toYjsValue;
package/dist/index.js CHANGED
@@ -193,69 +193,85 @@ var YjsConnector = class extends AbstractConnector {
193
193
  const Y = await this._getY();
194
194
  switch (operation) {
195
195
  case "snapshot":
196
- return JSON.stringify(s.root.toJSON(), null, 2);
197
- case "get": {
198
- const key = String(args.key ?? "");
199
- const value = s.root.get(key);
200
- return value !== void 0 ? JSON.stringify(this._fromYjsValue(value)) : "";
201
- }
196
+ return this._opSnapshot(s);
197
+ case "get":
198
+ return this._opGet(s, args);
202
199
  case "keys":
203
- return JSON.stringify([...s.root.keys()]);
204
- case "history": {
205
- const limit = Number(args.limit ?? 50);
206
- return JSON.stringify(s.history.slice(-limit), null, 2);
207
- }
208
- case "set": {
209
- const key = String(args.key ?? "");
210
- let value = args.value;
211
- if (typeof value === "string") {
212
- try {
213
- value = JSON.parse(value);
214
- } catch {
215
- }
216
- }
217
- const hadKey = s.root.has(key);
218
- s.doc.transact(() => {
219
- s.root.set(key, this._toYjsValue(Y, value));
220
- });
221
- this._recordHistory(handle, "set", key);
222
- this.emitChange?.({ path: key, action: hadKey ? "edit" : "create", source: "operation" });
223
- return "OK";
224
- }
225
- case "merge": {
226
- let data = args.data;
227
- if (typeof data === "string") data = JSON.parse(data);
228
- if (typeof data !== "object" || data === null) return "Error: data must be a JSON object";
229
- const existed = new Set(
230
- Object.keys(data).filter((k) => s.root.has(k))
231
- );
232
- s.doc.transact(() => {
233
- for (const [key, value] of Object.entries(data)) {
234
- s.root.set(key, this._toYjsValue(Y, value));
235
- }
236
- });
237
- for (const key of Object.keys(data)) {
238
- this._recordHistory(handle, "set", key);
239
- this.emitChange?.({
240
- path: key,
241
- action: existed.has(key) ? "edit" : "create",
242
- source: "operation"
243
- });
244
- }
245
- return "OK";
246
- }
247
- case "del": {
248
- const key = String(args.key ?? "");
249
- if (!s.root.has(key)) return "Not found";
250
- s.root.delete(key);
251
- this._recordHistory(handle, "delete", key);
252
- this.emitChange?.({ path: key, action: "delete", source: "operation" });
253
- return "Deleted";
254
- }
200
+ return this._opKeys(s);
201
+ case "history":
202
+ return this._opHistory(s, args);
203
+ case "set":
204
+ return this._opSet(handle, s, Y, args);
205
+ case "merge":
206
+ return this._opMerge(handle, s, Y, args);
207
+ case "del":
208
+ return this._opDel(handle, s, args);
255
209
  default:
256
210
  throw new Error(`YjsConnector has no operation: ${operation}`);
257
211
  }
258
212
  }
213
+ _opSnapshot(s) {
214
+ return JSON.stringify(s.root.toJSON(), null, 2);
215
+ }
216
+ _opGet(s, args) {
217
+ const key = String(args.key ?? "");
218
+ const value = s.root.get(key);
219
+ return value !== void 0 ? JSON.stringify(this._fromYjsValue(value)) : "";
220
+ }
221
+ _opKeys(s) {
222
+ return JSON.stringify([...s.root.keys()]);
223
+ }
224
+ _opHistory(s, args) {
225
+ const limit = Number(args.limit ?? 50);
226
+ return JSON.stringify(s.history.slice(-limit), null, 2);
227
+ }
228
+ _opSet(handle, s, Y, args) {
229
+ const key = String(args.key ?? "");
230
+ let value = args.value;
231
+ if (typeof value === "string") {
232
+ try {
233
+ value = JSON.parse(value);
234
+ } catch {
235
+ }
236
+ }
237
+ const hadKey = s.root.has(key);
238
+ s.doc.transact(() => {
239
+ s.root.set(key, this._toYjsValue(Y, value));
240
+ });
241
+ this._recordHistory(handle, "set", key);
242
+ this.emitChange?.({ path: key, action: hadKey ? "edit" : "create", source: "operation" });
243
+ return "OK";
244
+ }
245
+ _opMerge(handle, s, Y, args) {
246
+ let data = args.data;
247
+ if (typeof data === "string") data = JSON.parse(data);
248
+ if (typeof data !== "object" || data === null) return "Error: data must be a JSON object";
249
+ const existed = new Set(
250
+ Object.keys(data).filter((k) => s.root.has(k))
251
+ );
252
+ s.doc.transact(() => {
253
+ for (const [key, value] of Object.entries(data)) {
254
+ s.root.set(key, this._toYjsValue(Y, value));
255
+ }
256
+ });
257
+ for (const key of Object.keys(data)) {
258
+ this._recordHistory(handle, "set", key);
259
+ this.emitChange?.({
260
+ path: key,
261
+ action: existed.has(key) ? "edit" : "create",
262
+ source: "operation"
263
+ });
264
+ }
265
+ return "OK";
266
+ }
267
+ _opDel(handle, s, args) {
268
+ const key = String(args.key ?? "");
269
+ if (!s.root.has(key)) return "Not found";
270
+ s.root.delete(key);
271
+ this._recordHistory(handle, "delete", key);
272
+ this.emitChange?.({ path: key, action: "delete", source: "operation" });
273
+ return "Deleted";
274
+ }
259
275
  // ── Private helpers ────────────────────────────────────────────────────────
260
276
  async _getY() {
261
277
  const yjsPkg = "yjs";
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/target.ts","../src/index.ts"],"sourcesContent":["/**\n * YjsConnector — CRDT-based shared document state via Yjs.\n * Not mountable. Provides real-time collaborative state that merges\n * concurrent edits from multiple agents and UI clients.\n *\n * Requires `yjs` (a runtime dependency of this package).\n */\n\nimport { AbstractConnector } from \"@skaile/workspaces/connectors\";\nimport type {\n ConnectContext,\n ConnectorDeclaration,\n ConnectorHandle,\n ToolFace,\n} from \"@skaile/workspaces/connectors\";\nimport type {\n ConnectorContent,\n ConnectorEntry,\n ListOptions,\n OperationDescriptor,\n SearchOptions,\n SearchResult,\n} from \"@skaile/workspaces/connectors\";\nimport type { ConnectorTarget } from \"@skaile/workspaces/plugin-registry\";\nimport * as z from \"zod\";\n\ninterface YjsState {\n doc: any; // Y.Doc\n root: any; // Y.Map (root map)\n history: Array<{ op: string; key: string; at: string }>;\n onChange?: (snapshot: Record<string, unknown>, changed: string[]) => void;\n}\n\n/**\n * Connector for Yjs CRDT-based shared document state — enables real-time collaborative state that merges concurrent edits from multiple agents and UI clients.\n * Compatible with Hocuspocus and y-websocket provider connections via `getDoc()`. Requires the `yjs` package.\n */\nexport class YjsConnector extends AbstractConnector {\n readonly name = \"yjs\";\n\n tools: ToolFace;\n\n constructor() {\n super();\n this.tools = {\n read: (handle, path) => this._read(handle, path),\n write: (handle, path, content) => this._write(handle, path, content),\n delete: (handle, path) => this._delete(handle, path),\n list: (handle, path, options) => this._list(handle, path, options),\n search: (handle, query, options) => this._search(handle, query, options),\n describeOperations: (handle) => this._describeOperations(handle),\n executeOp: (handle, operation, args) => this._executeOp(handle, operation, args),\n };\n }\n\n async connect(declaration: ConnectorDeclaration, _ctx: ConnectContext): Promise<ConnectorHandle> {\n this.log.info(\"connect\", { id: declaration.id });\n const yjsPkg = \"yjs\";\n const Y = (await import(/* @vite-ignore */ yjsPkg)) as any;\n\n const doc = new Y.Doc();\n const root = doc.getMap(\"root\");\n\n // Apply initial values\n const initial = declaration.options?.initial as Record<string, unknown> | undefined;\n if (initial) {\n doc.transact(() => {\n for (const [key, value] of Object.entries(initial)) {\n root.set(key, this._toYjsValue(Y, value));\n }\n });\n }\n\n const state: YjsState = { doc, root, history: [] };\n\n // Observe changes\n root.observe((event: any) => {\n const changed: string[] = [];\n event.changes.keys.forEach((_change: any, key: string) => {\n changed.push(key);\n });\n if (changed.length > 0 && state.onChange) {\n state.onChange(root.toJSON(), changed);\n }\n });\n\n return this.makeHandle(declaration, state);\n }\n\n async disconnect(handle: ConnectorHandle): Promise<void> {\n this.log.info(\"disconnect\");\n const s = handle.state as YjsState;\n try {\n s.doc.destroy();\n } finally {\n handle.status = \"disconnected\";\n }\n }\n\n private s(handle: ConnectorHandle): YjsState {\n return handle.state as YjsState;\n }\n\n /**\n * Get the Y.Doc for external provider connections (Hocuspocus, y-websocket).\n */\n getDoc(handle: ConnectorHandle): unknown {\n return this.s(handle).doc;\n }\n\n /**\n * Register a callback fired on every change to the root map.\n */\n onDocChange(\n handle: ConnectorHandle,\n cb: (snapshot: Record<string, unknown>, changedKeys: string[]) => void,\n ): void {\n this.s(handle).onChange = cb;\n }\n\n // ── Tool face methods (private, wired in constructor) ─────────────────────\n\n private async _read(handle: ConnectorHandle, path: string): Promise<ConnectorContent | null> {\n const root = this.s(handle).root;\n const value = root.get(path);\n if (value === undefined) return null;\n const resolved = this._fromYjsValue(value);\n return { data: JSON.stringify(resolved), contentType: \"application/json\" };\n }\n\n private async _write(\n handle: ConnectorHandle,\n path: string,\n content: ConnectorContent,\n ): Promise<void> {\n const data = typeof content.data === \"string\" ? content.data : content.data.toString(\"utf-8\");\n let value: unknown;\n try {\n value = JSON.parse(data);\n } catch {\n value = data;\n }\n\n const Y = await this._getY();\n const root = this.s(handle).root;\n // Capture existence before the transact so we report create vs edit correctly.\n const hadKey = root.has(path);\n this.s(handle).doc.transact(() => {\n root.set(path, this._toYjsValue(Y, value));\n });\n this._recordHistory(handle, \"set\", path);\n this.emitChange?.({ path, action: hadKey ? \"edit\" : \"create\", source: \"operation\" });\n }\n\n private async _delete(handle: ConnectorHandle, path: string): Promise<boolean> {\n const root = this.s(handle).root;\n if (!root.has(path)) return false;\n root.delete(path);\n this._recordHistory(handle, \"delete\", path);\n return true;\n }\n\n private async _list(\n handle: ConnectorHandle,\n _path?: string,\n options?: ListOptions,\n ): Promise<ConnectorEntry[]> {\n const root = this.s(handle).root;\n const entries: ConnectorEntry[] = [];\n for (const key of root.keys()) {\n if (options?.limit && entries.length >= options.limit) break;\n entries.push({ name: key, path: key, type: \"key\" });\n }\n return entries;\n }\n\n private async _search(\n handle: ConnectorHandle,\n query: string,\n options?: SearchOptions,\n ): Promise<SearchResult[]> {\n const root = this.s(handle).root;\n const results: SearchResult[] = [];\n for (const key of root.keys()) {\n if (options?.maxResults && results.length >= options.maxResults) break;\n const value = root.get(key);\n const str = JSON.stringify(this._fromYjsValue(value));\n if (key.includes(query) || str.includes(query)) {\n results.push({ path: key, snippet: str.slice(0, 200) });\n }\n }\n return results;\n }\n\n private _describeOperations(handle: ConnectorHandle): OperationDescriptor[] {\n const ops: OperationDescriptor[] = [\n {\n name: \"snapshot\",\n description: \"Get the full document snapshot (all keys and values).\",\n accessLevel: \"read\",\n args: [],\n },\n {\n name: \"get\",\n description: \"Get a single value by key.\",\n accessLevel: \"read\",\n args: [{ name: \"key\", type: \"string\", required: true, description: \"Key name\" }],\n },\n {\n name: \"keys\",\n description: \"List all keys in the document.\",\n accessLevel: \"read\",\n args: [],\n },\n {\n name: \"history\",\n description: \"Get the local operation history.\",\n accessLevel: \"read\",\n args: [{ name: \"limit\", type: \"number\", required: false, description: \"Max entries\" }],\n },\n ];\n\n if (handle.access === \"read-write\") {\n ops.push(\n {\n name: \"set\",\n description: \"Set a key to a value. Merges with concurrent writes via CRDT.\",\n accessLevel: \"write\",\n args: [\n { name: \"key\", type: \"string\", required: true, description: \"Key name\" },\n {\n name: \"value\",\n type: \"string\",\n required: true,\n description: \"Value (JSON-encoded for objects)\",\n },\n ],\n examples: [\n \"set --key theme --value '\\\"dark\\\"'\",\n \"set --key config --value '{\\\"debug\\\":true}'\",\n ],\n },\n {\n name: \"merge\",\n description: \"Merge an object into the document (each key set independently via CRDT).\",\n accessLevel: \"write\",\n args: [\n { name: \"data\", type: \"json\", required: true, description: \"JSON object to merge\" },\n ],\n },\n {\n name: \"del\",\n description: \"Delete a key from the document.\",\n accessLevel: \"write\",\n args: [{ name: \"key\", type: \"string\", required: true, description: \"Key to delete\" }],\n },\n );\n }\n\n return ops;\n }\n\n private async _executeOp(\n handle: ConnectorHandle,\n operation: string,\n args: Record<string, unknown>,\n ): Promise<string> {\n const s = this.s(handle);\n const Y = await this._getY();\n\n switch (operation) {\n case \"snapshot\":\n return JSON.stringify(s.root.toJSON(), null, 2);\n\n case \"get\": {\n const key = String(args.key ?? \"\");\n const value = s.root.get(key);\n return value !== undefined ? JSON.stringify(this._fromYjsValue(value)) : \"\";\n }\n\n case \"keys\":\n return JSON.stringify([...s.root.keys()]);\n\n case \"history\": {\n const limit = Number(args.limit ?? 50);\n return JSON.stringify(s.history.slice(-limit), null, 2);\n }\n\n case \"set\": {\n const key = String(args.key ?? \"\");\n let value: unknown = args.value;\n if (typeof value === \"string\") {\n try {\n value = JSON.parse(value);\n } catch {\n /* keep as string */\n }\n }\n const hadKey = s.root.has(key);\n s.doc.transact(() => {\n s.root.set(key, this._toYjsValue(Y, value));\n });\n this._recordHistory(handle, \"set\", key);\n this.emitChange?.({ path: key, action: hadKey ? \"edit\" : \"create\", source: \"operation\" });\n return \"OK\";\n }\n\n case \"merge\": {\n let data = args.data;\n if (typeof data === \"string\") data = JSON.parse(data);\n if (typeof data !== \"object\" || data === null) return \"Error: data must be a JSON object\";\n // Snapshot existence before the transact: the write loop populates every\n // key, so a post-write has() check would always report \"edit\".\n const existed = new Set(\n Object.keys(data as Record<string, unknown>).filter((k) => s.root.has(k)),\n );\n s.doc.transact(() => {\n for (const [key, value] of Object.entries(data as Record<string, unknown>)) {\n s.root.set(key, this._toYjsValue(Y, value));\n }\n });\n for (const key of Object.keys(data as Record<string, unknown>)) {\n this._recordHistory(handle, \"set\", key);\n this.emitChange?.({\n path: key,\n action: existed.has(key) ? \"edit\" : \"create\",\n source: \"operation\",\n });\n }\n return \"OK\";\n }\n\n case \"del\": {\n const key = String(args.key ?? \"\");\n if (!s.root.has(key)) return \"Not found\";\n s.root.delete(key);\n this._recordHistory(handle, \"delete\", key);\n this.emitChange?.({ path: key, action: \"delete\", source: \"operation\" });\n return \"Deleted\";\n }\n\n default:\n throw new Error(`YjsConnector has no operation: ${operation}`);\n }\n }\n\n // ── Private helpers ────────────────────────────────────────────────────────\n\n private async _getY(): Promise<any> {\n const yjsPkg = \"yjs\";\n return import(/* @vite-ignore */ yjsPkg);\n }\n\n /** Convert a JS value to a Yjs-compatible value. */\n private _toYjsValue(Y: any, value: unknown): any {\n if (value === null || value === undefined) return value;\n if (typeof value !== \"object\") return value;\n if (Array.isArray(value)) {\n const arr = new Y.Array();\n for (const item of value) arr.push([this._toYjsValue(Y, item)]);\n return arr;\n }\n const map = new Y.Map();\n for (const [k, v] of Object.entries(value as Record<string, unknown>)) {\n map.set(k, this._toYjsValue(Y, v));\n }\n return map;\n }\n\n /** Convert a Yjs value back to plain JS. */\n private _fromYjsValue(value: any): unknown {\n if (value === null || value === undefined) return value;\n if (typeof value?.toJSON === \"function\") return value.toJSON();\n return value;\n }\n\n private _recordHistory(handle: ConnectorHandle, op: string, key: string): void {\n const s = this.s(handle);\n s.history.push({ op, key, at: new Date().toISOString() });\n if (s.history.length > 500) s.history = s.history.slice(-500);\n }\n}\n\n/**\n * Creates a new YjsConnector instance.\n * @returns Configured YjsConnector ready to be registered in the connector registry.\n */\nexport function createConnector(): YjsConnector {\n return new YjsConnector();\n}\n\n/**\n * Plugin-registry target wrapping the Yjs connector factory. Connectors take no\n * construct-time config, so `configSchema` is a passthrough and `create()`\n * returns a fresh instance; lifecycle config arrives via `Connector.connect()`.\n */\nexport const yjsConnectorTarget: ConnectorTarget = {\n id: \"yjs\",\n displayName: \"Yjs\",\n apiVersion: 1,\n configSchema: z.unknown(),\n create: (_config, _ctx) => new YjsConnector(),\n};\n","/**\n * `@skaile/connector-yjs` — Yjs CRDT connector for `@skaile/workspaces`.\n *\n * Install via `skaile plugin install @skaile/connector-yjs`; the plugin loader\n * calls `register(pluginRegistry)` at startup so `yjs` becomes resolvable as a\n * connector driver.\n */\n\nimport type { PluginRegistry } from \"@skaile/workspaces/plugin-registry\";\nimport { yjsConnectorTarget } from \"./target.js\";\n\nexport { yjsConnectorTarget, YjsConnector, createConnector } from \"./target.js\";\n\n/** Register this plugin's connector target with a registry. */\nexport function register(registry: PluginRegistry): void {\n registry.register(\"connector\", yjsConnectorTarget);\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/target.ts","../src/index.ts"],"sourcesContent":["/**\n * YjsConnector — CRDT-based shared document state via Yjs.\n * Not mountable. Provides real-time collaborative state that merges\n * concurrent edits from multiple agents and UI clients.\n *\n * Requires `yjs` (a runtime dependency of this package).\n */\n\nimport type {\n ConnectContext,\n ConnectorContent,\n ConnectorDeclaration,\n ConnectorEntry,\n ConnectorHandle,\n ListOptions,\n OperationDescriptor,\n SearchOptions,\n SearchResult,\n ToolFace,\n} from \"@skaile/workspaces/connectors\";\nimport { AbstractConnector } from \"@skaile/workspaces/connectors\";\nimport type { ConnectorTarget } from \"@skaile/workspaces/plugin-registry\";\nimport * as z from \"zod\";\n\ninterface YjsState {\n doc: any; // Y.Doc\n root: any; // Y.Map (root map)\n history: Array<{ op: string; key: string; at: string }>;\n onChange?: (snapshot: Record<string, unknown>, changed: string[]) => void;\n}\n\n/**\n * Connector for Yjs CRDT-based shared document state — enables real-time collaborative state that merges concurrent edits from multiple agents and UI clients.\n * Compatible with Hocuspocus and y-websocket provider connections via `getDoc()`. Requires the `yjs` package.\n */\nexport class YjsConnector extends AbstractConnector {\n readonly name = \"yjs\";\n\n tools: ToolFace;\n\n constructor() {\n super();\n this.tools = {\n read: (handle, path) => this._read(handle, path),\n write: (handle, path, content) => this._write(handle, path, content),\n delete: (handle, path) => this._delete(handle, path),\n list: (handle, path, options) => this._list(handle, path, options),\n search: (handle, query, options) => this._search(handle, query, options),\n describeOperations: (handle) => this._describeOperations(handle),\n executeOp: (handle, operation, args) => this._executeOp(handle, operation, args),\n };\n }\n\n async connect(declaration: ConnectorDeclaration, _ctx: ConnectContext): Promise<ConnectorHandle> {\n this.log.info(\"connect\", { id: declaration.id });\n const yjsPkg = \"yjs\";\n const Y = (await import(/* @vite-ignore */ yjsPkg)) as any;\n\n const doc = new Y.Doc();\n const root = doc.getMap(\"root\");\n\n // Apply initial values\n const initial = declaration.options?.initial as Record<string, unknown> | undefined;\n if (initial) {\n doc.transact(() => {\n for (const [key, value] of Object.entries(initial)) {\n root.set(key, this._toYjsValue(Y, value));\n }\n });\n }\n\n const state: YjsState = { doc, root, history: [] };\n\n // Observe changes\n root.observe((event: any) => {\n const changed: string[] = [];\n event.changes.keys.forEach((_change: any, key: string) => {\n changed.push(key);\n });\n if (changed.length > 0 && state.onChange) {\n state.onChange(root.toJSON(), changed);\n }\n });\n\n return this.makeHandle(declaration, state);\n }\n\n async disconnect(handle: ConnectorHandle): Promise<void> {\n this.log.info(\"disconnect\");\n const s = handle.state as YjsState;\n try {\n s.doc.destroy();\n } finally {\n handle.status = \"disconnected\";\n }\n }\n\n private s(handle: ConnectorHandle): YjsState {\n return handle.state as YjsState;\n }\n\n /**\n * Get the Y.Doc for external provider connections (Hocuspocus, y-websocket).\n */\n getDoc(handle: ConnectorHandle): unknown {\n return this.s(handle).doc;\n }\n\n /**\n * Register a callback fired on every change to the root map.\n */\n onDocChange(\n handle: ConnectorHandle,\n cb: (snapshot: Record<string, unknown>, changedKeys: string[]) => void,\n ): void {\n this.s(handle).onChange = cb;\n }\n\n // ── Tool face methods (private, wired in constructor) ─────────────────────\n\n private async _read(handle: ConnectorHandle, path: string): Promise<ConnectorContent | null> {\n const root = this.s(handle).root;\n const value = root.get(path);\n if (value === undefined) return null;\n const resolved = this._fromYjsValue(value);\n return { data: JSON.stringify(resolved), contentType: \"application/json\" };\n }\n\n private async _write(\n handle: ConnectorHandle,\n path: string,\n content: ConnectorContent,\n ): Promise<void> {\n const data = typeof content.data === \"string\" ? content.data : content.data.toString(\"utf-8\");\n let value: unknown;\n try {\n value = JSON.parse(data);\n } catch {\n value = data;\n }\n\n const Y = await this._getY();\n const root = this.s(handle).root;\n // Capture existence before the transact so we report create vs edit correctly.\n const hadKey = root.has(path);\n this.s(handle).doc.transact(() => {\n root.set(path, this._toYjsValue(Y, value));\n });\n this._recordHistory(handle, \"set\", path);\n this.emitChange?.({ path, action: hadKey ? \"edit\" : \"create\", source: \"operation\" });\n }\n\n private async _delete(handle: ConnectorHandle, path: string): Promise<boolean> {\n const root = this.s(handle).root;\n if (!root.has(path)) return false;\n root.delete(path);\n this._recordHistory(handle, \"delete\", path);\n return true;\n }\n\n private async _list(\n handle: ConnectorHandle,\n _path?: string,\n options?: ListOptions,\n ): Promise<ConnectorEntry[]> {\n const root = this.s(handle).root;\n const entries: ConnectorEntry[] = [];\n for (const key of root.keys()) {\n if (options?.limit && entries.length >= options.limit) break;\n entries.push({ name: key, path: key, type: \"key\" });\n }\n return entries;\n }\n\n private async _search(\n handle: ConnectorHandle,\n query: string,\n options?: SearchOptions,\n ): Promise<SearchResult[]> {\n const root = this.s(handle).root;\n const results: SearchResult[] = [];\n for (const key of root.keys()) {\n if (options?.maxResults && results.length >= options.maxResults) break;\n const value = root.get(key);\n const str = JSON.stringify(this._fromYjsValue(value));\n if (key.includes(query) || str.includes(query)) {\n results.push({ path: key, snippet: str.slice(0, 200) });\n }\n }\n return results;\n }\n\n private _describeOperations(handle: ConnectorHandle): OperationDescriptor[] {\n const ops: OperationDescriptor[] = [\n {\n name: \"snapshot\",\n description: \"Get the full document snapshot (all keys and values).\",\n accessLevel: \"read\",\n args: [],\n },\n {\n name: \"get\",\n description: \"Get a single value by key.\",\n accessLevel: \"read\",\n args: [{ name: \"key\", type: \"string\", required: true, description: \"Key name\" }],\n },\n {\n name: \"keys\",\n description: \"List all keys in the document.\",\n accessLevel: \"read\",\n args: [],\n },\n {\n name: \"history\",\n description: \"Get the local operation history.\",\n accessLevel: \"read\",\n args: [{ name: \"limit\", type: \"number\", required: false, description: \"Max entries\" }],\n },\n ];\n\n if (handle.access === \"read-write\") {\n ops.push(\n {\n name: \"set\",\n description: \"Set a key to a value. Merges with concurrent writes via CRDT.\",\n accessLevel: \"write\",\n args: [\n { name: \"key\", type: \"string\", required: true, description: \"Key name\" },\n {\n name: \"value\",\n type: \"string\",\n required: true,\n description: \"Value (JSON-encoded for objects)\",\n },\n ],\n examples: [\n \"set --key theme --value '\\\"dark\\\"'\",\n \"set --key config --value '{\\\"debug\\\":true}'\",\n ],\n },\n {\n name: \"merge\",\n description: \"Merge an object into the document (each key set independently via CRDT).\",\n accessLevel: \"write\",\n args: [\n { name: \"data\", type: \"json\", required: true, description: \"JSON object to merge\" },\n ],\n },\n {\n name: \"del\",\n description: \"Delete a key from the document.\",\n accessLevel: \"write\",\n args: [{ name: \"key\", type: \"string\", required: true, description: \"Key to delete\" }],\n },\n );\n }\n\n return ops;\n }\n\n private async _executeOp(\n handle: ConnectorHandle,\n operation: string,\n args: Record<string, unknown>,\n ): Promise<string> {\n const s = this.s(handle);\n const Y = await this._getY();\n\n switch (operation) {\n case \"snapshot\":\n return this._opSnapshot(s);\n\n case \"get\":\n return this._opGet(s, args);\n\n case \"keys\":\n return this._opKeys(s);\n\n case \"history\":\n return this._opHistory(s, args);\n\n case \"set\":\n return this._opSet(handle, s, Y, args);\n\n case \"merge\":\n return this._opMerge(handle, s, Y, args);\n\n case \"del\":\n return this._opDel(handle, s, args);\n\n default:\n throw new Error(`YjsConnector has no operation: ${operation}`);\n }\n }\n\n private _opSnapshot(s: YjsState): string {\n return JSON.stringify(s.root.toJSON(), null, 2);\n }\n\n private _opGet(s: YjsState, args: Record<string, unknown>): string {\n const key = String(args.key ?? \"\");\n const value = s.root.get(key);\n return value !== undefined ? JSON.stringify(this._fromYjsValue(value)) : \"\";\n }\n\n private _opKeys(s: YjsState): string {\n return JSON.stringify([...s.root.keys()]);\n }\n\n private _opHistory(s: YjsState, args: Record<string, unknown>): string {\n const limit = Number(args.limit ?? 50);\n return JSON.stringify(s.history.slice(-limit), null, 2);\n }\n\n private _opSet(\n handle: ConnectorHandle,\n s: YjsState,\n Y: any,\n args: Record<string, unknown>,\n ): string {\n const key = String(args.key ?? \"\");\n let value: unknown = args.value;\n if (typeof value === \"string\") {\n try {\n value = JSON.parse(value);\n } catch {\n /* keep as string */\n }\n }\n const hadKey = s.root.has(key);\n s.doc.transact(() => {\n s.root.set(key, this._toYjsValue(Y, value));\n });\n this._recordHistory(handle, \"set\", key);\n this.emitChange?.({ path: key, action: hadKey ? \"edit\" : \"create\", source: \"operation\" });\n return \"OK\";\n }\n\n private _opMerge(\n handle: ConnectorHandle,\n s: YjsState,\n Y: any,\n args: Record<string, unknown>,\n ): string {\n let data = args.data;\n if (typeof data === \"string\") data = JSON.parse(data);\n if (typeof data !== \"object\" || data === null) return \"Error: data must be a JSON object\";\n // Snapshot existence before the transact: the write loop populates every\n // key, so a post-write has() check would always report \"edit\".\n const existed = new Set(\n Object.keys(data as Record<string, unknown>).filter((k) => s.root.has(k)),\n );\n s.doc.transact(() => {\n for (const [key, value] of Object.entries(data as Record<string, unknown>)) {\n s.root.set(key, this._toYjsValue(Y, value));\n }\n });\n for (const key of Object.keys(data as Record<string, unknown>)) {\n this._recordHistory(handle, \"set\", key);\n this.emitChange?.({\n path: key,\n action: existed.has(key) ? \"edit\" : \"create\",\n source: \"operation\",\n });\n }\n return \"OK\";\n }\n\n private _opDel(handle: ConnectorHandle, s: YjsState, args: Record<string, unknown>): string {\n const key = String(args.key ?? \"\");\n if (!s.root.has(key)) return \"Not found\";\n s.root.delete(key);\n this._recordHistory(handle, \"delete\", key);\n this.emitChange?.({ path: key, action: \"delete\", source: \"operation\" });\n return \"Deleted\";\n }\n\n // ── Private helpers ────────────────────────────────────────────────────────\n\n private async _getY(): Promise<any> {\n const yjsPkg = \"yjs\";\n return import(/* @vite-ignore */ yjsPkg);\n }\n\n /** Convert a JS value to a Yjs-compatible value. */\n private _toYjsValue(Y: any, value: unknown): any {\n if (value === null || value === undefined) return value;\n if (typeof value !== \"object\") return value;\n if (Array.isArray(value)) {\n const arr = new Y.Array();\n for (const item of value) arr.push([this._toYjsValue(Y, item)]);\n return arr;\n }\n const map = new Y.Map();\n for (const [k, v] of Object.entries(value as Record<string, unknown>)) {\n map.set(k, this._toYjsValue(Y, v));\n }\n return map;\n }\n\n /** Convert a Yjs value back to plain JS. */\n private _fromYjsValue(value: any): unknown {\n if (value === null || value === undefined) return value;\n if (typeof value?.toJSON === \"function\") return value.toJSON();\n return value;\n }\n\n private _recordHistory(handle: ConnectorHandle, op: string, key: string): void {\n const s = this.s(handle);\n s.history.push({ op, key, at: new Date().toISOString() });\n if (s.history.length > 500) s.history = s.history.slice(-500);\n }\n}\n\n/**\n * Creates a new YjsConnector instance.\n * @returns Configured YjsConnector ready to be registered in the connector registry.\n */\nexport function createConnector(): YjsConnector {\n return new YjsConnector();\n}\n\n/**\n * Plugin-registry target wrapping the Yjs connector factory. Connectors take no\n * construct-time config, so `configSchema` is a passthrough and `create()`\n * returns a fresh instance; lifecycle config arrives via `Connector.connect()`.\n */\nexport const yjsConnectorTarget: ConnectorTarget = {\n id: \"yjs\",\n displayName: \"Yjs\",\n apiVersion: 1,\n configSchema: z.unknown(),\n create: (_config, _ctx) => new YjsConnector(),\n};\n","/**\n * `@skaile/connector-yjs` — Yjs CRDT connector for `@skaile/workspaces`.\n *\n * Install via `skaile plugin install @skaile/connector-yjs`; the plugin loader\n * calls `register(pluginRegistry)` at startup so `yjs` becomes resolvable as a\n * connector driver.\n */\n\nimport type { PluginRegistry } from \"@skaile/workspaces/plugin-registry\";\nimport { yjsConnectorTarget } from \"./target.js\";\n\nexport { createConnector, YjsConnector, yjsConnectorTarget } from \"./target.js\";\n\n/** Register this plugin's connector target with a registry. */\nexport function register(registry: PluginRegistry): void {\n registry.register(\"connector\", yjsConnectorTarget);\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skaile/connector-yjs",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "Yjs CRDT connector for @skaile/workspaces",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -22,10 +22,10 @@
22
22
  "node": ">=20"
23
23
  },
24
24
  "peerDependencies": {
25
- "@skaile/workspaces": ">=0.22.0-0"
25
+ "@skaile/workspaces": "^6.0.0"
26
26
  },
27
27
  "devDependencies": {
28
- "@skaile/workspaces": "^0.26.0"
28
+ "@skaile/workspaces": "^6.0.0"
29
29
  },
30
30
  "scripts": {
31
31
  "build": "tsup",