@artenx/dshb 0.1.17 → 0.1.19

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.
Files changed (103) hide show
  1. package/README.md +1 -1
  2. package/lib/client.js +2171 -581
  3. package/lib/client.js.map +1 -1
  4. package/lib/core/index.js +72 -4
  5. package/lib/core/index.js.map +1 -1
  6. package/lib/core/node-registry.d.ts +2 -108
  7. package/lib/core/node-registry.js +43 -2
  8. package/lib/core/node-registry.js.map +1 -1
  9. package/lib/core/routes.d.ts +4 -3
  10. package/lib/core/routes.js +67 -23
  11. package/lib/core/routes.js.map +1 -1
  12. package/lib/core/sync/coordinator.d.ts +48 -0
  13. package/lib/core/sync/coordinator.js +247 -0
  14. package/lib/core/sync/coordinator.js.map +1 -0
  15. package/lib/core/sync/host-key.d.ts +2 -0
  16. package/lib/core/sync/host-key.js +71 -0
  17. package/lib/core/sync/host-key.js.map +1 -0
  18. package/lib/core/sync/internal-routes.d.ts +9 -0
  19. package/lib/core/sync/internal-routes.js +236 -0
  20. package/lib/core/sync/internal-routes.js.map +1 -0
  21. package/lib/core/sync/model.d.ts +2 -0
  22. package/lib/core/sync/model.js +106 -0
  23. package/lib/core/sync/model.js.map +1 -0
  24. package/lib/core/sync/node-sync.d.ts +2 -0
  25. package/lib/core/sync/node-sync.js +660 -0
  26. package/lib/core/sync/node-sync.js.map +1 -0
  27. package/lib/core/sync/offline-archive.d.ts +55 -0
  28. package/lib/core/sync/offline-archive.js +673 -0
  29. package/lib/core/sync/offline-archive.js.map +1 -0
  30. package/lib/core/sync/offline-journal.d.ts +22 -0
  31. package/lib/core/sync/offline-journal.js +74 -0
  32. package/lib/core/sync/offline-journal.js.map +1 -0
  33. package/lib/core/sync/offline-routes.d.ts +7 -0
  34. package/lib/core/sync/offline-routes.js +192 -0
  35. package/lib/core/sync/offline-routes.js.map +1 -0
  36. package/lib/core/sync/peer-manager.d.ts +56 -0
  37. package/lib/core/sync/peer-manager.js +258 -0
  38. package/lib/core/sync/peer-manager.js.map +1 -0
  39. package/lib/core/sync/protocol.d.ts +2 -0
  40. package/lib/core/sync/protocol.js +124 -0
  41. package/lib/core/sync/protocol.js.map +1 -0
  42. package/lib/core/sync/remote-helper.d.ts +5 -0
  43. package/lib/core/sync/remote-helper.js +160 -0
  44. package/lib/core/sync/remote-helper.js.map +1 -0
  45. package/lib/core/sync/revision.d.ts +2 -0
  46. package/lib/core/sync/revision.js +77 -0
  47. package/lib/core/sync/revision.js.map +1 -0
  48. package/lib/core/sync/routes.d.ts +9 -0
  49. package/lib/core/sync/routes.js +339 -0
  50. package/lib/core/sync/routes.js.map +1 -0
  51. package/lib/core/sync/scheduler.d.ts +14 -0
  52. package/lib/core/sync/scheduler.js +81 -0
  53. package/lib/core/sync/scheduler.js.map +1 -0
  54. package/lib/core/sync/session-journal.d.ts +2 -0
  55. package/lib/core/sync/session-journal.js +191 -0
  56. package/lib/core/sync/session-journal.js.map +1 -0
  57. package/lib/core/sync/session-routes.d.ts +7 -0
  58. package/lib/core/sync/session-routes.js +67 -0
  59. package/lib/core/sync/session-routes.js.map +1 -0
  60. package/lib/core/sync/session-sync.d.ts +2 -0
  61. package/lib/core/sync/session-sync.js +2 -0
  62. package/lib/core/sync/ssh-transport.d.ts +2 -0
  63. package/lib/core/sync/ssh-transport.js +408 -0
  64. package/lib/core/sync/ssh-transport.js.map +1 -0
  65. package/lib/core/sync/stores.d.ts +3 -0
  66. package/lib/core/sync/stores.js +385 -0
  67. package/lib/core/sync/stores.js.map +1 -0
  68. package/lib/core/test.d.ts +1 -1
  69. package/lib/core/workspace-bindings.d.ts +2 -28
  70. package/lib/core/workspace-bindings.js +14 -14
  71. package/lib/core/workspace-bindings.js.map +1 -1
  72. package/lib/core/workspace-instruction-context.d.ts +3 -2260
  73. package/lib/core/workspace-instruction-context.js +104 -2
  74. package/lib/core/workspace-instruction-context.js.map +1 -0
  75. package/lib/core/workspace-instruction-routes.d.ts +1 -1
  76. package/lib/core/workspace-instructions.d.ts +2 -68
  77. package/lib/core/workspace-instructions.js +13 -0
  78. package/lib/core/workspace-instructions.js.map +1 -1
  79. package/lib/core/workspaces.d.ts +4 -3
  80. package/lib/core/workspaces.js +17 -1
  81. package/lib/core/workspaces.js.map +1 -1
  82. package/lib/host-key-C5afhAUd.d.ts +30 -0
  83. package/lib/index-VF8bcBeX.d.ts +2293 -0
  84. package/lib/{workspace-instruction-context-DytAmaPY.js → lib-gdtU_WKT.js} +159 -102
  85. package/lib/lib-gdtU_WKT.js.map +1 -0
  86. package/lib/model-BP7Gw1yk.d.ts +104 -0
  87. package/lib/node-registry-BTnnM5-k.d.ts +112 -0
  88. package/lib/node-sync-3Z9QLz2n.d.ts +89 -0
  89. package/lib/protocol-CV7LGE44.d.ts +35 -0
  90. package/lib/revision-C9sOlDZ6.d.ts +25 -0
  91. package/lib/router/router-fs.d.ts +12 -3
  92. package/lib/router/router-fs.js.map +1 -1
  93. package/lib/session-journal-pgPqcWn9.d.ts +40 -0
  94. package/lib/session-sync-EdfwUON5.js +2177 -0
  95. package/lib/session-sync-EdfwUON5.js.map +1 -0
  96. package/lib/session-sync-g6qKZzjV.d.ts +1252 -0
  97. package/lib/ssh-transport-BcIiLxsX.d.ts +55 -0
  98. package/lib/stores-CKyEt0yk.d.ts +31 -0
  99. package/lib/workspace-bindings-CsB0TIJB.d.ts +28 -0
  100. package/lib/workspace-instructions-DirYYiku.d.ts +69 -0
  101. package/package.json +27 -8
  102. package/LICENSE +0 -21
  103. package/lib/workspace-instruction-context-DytAmaPY.js.map +0 -1
@@ -0,0 +1,236 @@
1
+ import { isLoopbackRequest } from "../../auth/loopback.js";
2
+ import { SyncNodeManifestError } from "./node-sync.js";
3
+ import { t as SyncSessionError } from "../../session-sync-EdfwUON5.js";
4
+ import { MAX_SYNC_TRANSFER_BYTES } from "./protocol.js";
5
+ //#region src/core/sync/internal-routes.ts
6
+ const MAX_APPLY_BODY_BYTES = MAX_SYNC_TRANSFER_BYTES;
7
+ function sendJson(res, status, body) {
8
+ res.writeHead(status, {
9
+ "content-type": "application/json",
10
+ "cache-control": "no-store"
11
+ });
12
+ res.end(JSON.stringify(body));
13
+ }
14
+ function pathSegments(req) {
15
+ return new URL(req.url ?? "/", "http://x").pathname.split("/").filter(Boolean);
16
+ }
17
+ function readJsonBody(req) {
18
+ return new Promise((resolve) => {
19
+ if (req.headers["content-type"]?.split(";", 1)[0]?.trim().toLowerCase() !== "application/json") {
20
+ resolve(null);
21
+ return;
22
+ }
23
+ const chunks = [];
24
+ let size = 0;
25
+ let settled = false;
26
+ const fail = () => {
27
+ if (settled) return;
28
+ settled = true;
29
+ resolve(null);
30
+ };
31
+ req.on("data", (chunk) => {
32
+ if (settled) return;
33
+ size += chunk.length;
34
+ if (size > MAX_APPLY_BODY_BYTES) {
35
+ fail();
36
+ req.destroy();
37
+ return;
38
+ }
39
+ chunks.push(chunk);
40
+ });
41
+ req.on("end", () => {
42
+ if (settled) return;
43
+ try {
44
+ const value = JSON.parse(Buffer.concat(chunks).toString("utf8"));
45
+ if (value === null || typeof value !== "object" || Array.isArray(value)) {
46
+ fail();
47
+ return;
48
+ }
49
+ settled = true;
50
+ resolve(value);
51
+ } catch {
52
+ fail();
53
+ }
54
+ });
55
+ req.on("error", fail);
56
+ });
57
+ }
58
+ function registerSyncInternalRoutes(ctx, state, nodeSync, sessionSync) {
59
+ ctx.effect(() => ctx.webServer.register({
60
+ kind: "exact",
61
+ path: "/api/dshb/sync/internal/handshake",
62
+ handler: (req, res) => {
63
+ if (!isLoopbackRequest(req.socket.remoteAddress, req.headers.host)) {
64
+ sendJson(res, 403, {
65
+ ok: false,
66
+ error: "loopback access required"
67
+ });
68
+ return;
69
+ }
70
+ if (req.method !== "GET") {
71
+ sendJson(res, 405, {
72
+ ok: false,
73
+ error: "method not allowed"
74
+ });
75
+ return;
76
+ }
77
+ try {
78
+ sendJson(res, 200, {
79
+ ok: true,
80
+ protocolVersion: 1,
81
+ instanceId: state.instanceId(),
82
+ capabilities: [
83
+ "peer-handshake",
84
+ ...nodeSync ? ["node-sync"] : [],
85
+ ...sessionSync ? ["session-sync"] : []
86
+ ]
87
+ });
88
+ } catch {
89
+ sendJson(res, 503, {
90
+ ok: false,
91
+ error: "sync identity unavailable"
92
+ });
93
+ }
94
+ }
95
+ }));
96
+ if (nodeSync) ctx.effect(() => ctx.webServer.register({
97
+ kind: "prefix",
98
+ path: "/api/dshb/sync/internal/nodes",
99
+ handler: async (req, res) => {
100
+ if (!isLoopbackRequest(req.socket.remoteAddress, req.headers.host)) {
101
+ sendJson(res, 403, {
102
+ ok: false,
103
+ error: "loopback access required"
104
+ });
105
+ return;
106
+ }
107
+ const segments = pathSegments(req);
108
+ const action = segments[5];
109
+ if (segments.length !== 6) {
110
+ sendJson(res, 404, {
111
+ ok: false,
112
+ error: "not found"
113
+ });
114
+ return;
115
+ }
116
+ if (req.method === "GET" && action === "manifest") {
117
+ try {
118
+ sendJson(res, 200, {
119
+ ok: true,
120
+ manifest: await nodeSync.exportManifest()
121
+ });
122
+ } catch {
123
+ sendJson(res, 500, {
124
+ ok: false,
125
+ error: "node manifest export failed"
126
+ });
127
+ }
128
+ return;
129
+ }
130
+ if (req.method === "POST" && action === "apply") {
131
+ const body = await readJsonBody(req);
132
+ if (!body || !Array.isArray(body.records) || typeof body.sourceName !== "string") {
133
+ sendJson(res, 400, {
134
+ ok: false,
135
+ error: "records and sourceName are required"
136
+ });
137
+ return;
138
+ }
139
+ try {
140
+ sendJson(res, 200, {
141
+ ok: true,
142
+ result: await nodeSync.applyManifest(body.records, body.sourceName)
143
+ });
144
+ } catch (error) {
145
+ const status = error instanceof SyncNodeManifestError ? 400 : 500;
146
+ sendJson(res, status, {
147
+ ok: false,
148
+ error: status === 400 ? "node manifest rejected" : "node manifest apply failed"
149
+ });
150
+ }
151
+ return;
152
+ }
153
+ sendJson(res, 404, {
154
+ ok: false,
155
+ error: "not found"
156
+ });
157
+ }
158
+ }));
159
+ if (!sessionSync) return;
160
+ ctx.effect(() => ctx.webServer.register({
161
+ kind: "prefix",
162
+ path: "/api/dshb/sync/internal/sessions",
163
+ handler: async (req, res) => {
164
+ if (!isLoopbackRequest(req.socket.remoteAddress, req.headers.host)) {
165
+ sendJson(res, 403, {
166
+ ok: false,
167
+ error: "loopback access required"
168
+ });
169
+ return;
170
+ }
171
+ const segments = pathSegments(req);
172
+ const action = segments[5];
173
+ if (segments.length !== 6) {
174
+ sendJson(res, 404, {
175
+ ok: false,
176
+ error: "not found"
177
+ });
178
+ return;
179
+ }
180
+ if (req.method === "GET" && action === "bundle") {
181
+ try {
182
+ sendJson(res, 200, {
183
+ ok: true,
184
+ bundle: await sessionSync.exportBundle()
185
+ });
186
+ } catch (error) {
187
+ const code = error instanceof SyncSessionError ? error.code : "session-export-failed";
188
+ sendJson(res, code === "bundle-too-large" ? 413 : 500, {
189
+ ok: false,
190
+ code,
191
+ error: error instanceof SyncSessionError ? error.message : "session bundle export failed"
192
+ });
193
+ }
194
+ return;
195
+ }
196
+ if (req.method === "POST" && action === "apply") {
197
+ const body = await readJsonBody(req);
198
+ if (!body || body.bundle === null || typeof body.bundle !== "object" || typeof body.sourceName !== "string" || typeof body.peerId !== "string" || !/^p-[a-f0-9]{24}$/.test(body.peerId)) {
199
+ sendJson(res, 400, {
200
+ ok: false,
201
+ code: "session-request-invalid",
202
+ error: "bundle, sourceName, and peerId are required"
203
+ });
204
+ return;
205
+ }
206
+ try {
207
+ sendJson(res, 200, {
208
+ ok: true,
209
+ result: await sessionSync.applyBundle(body.bundle, body.sourceName, body.peerId)
210
+ });
211
+ } catch (error) {
212
+ const code = error instanceof SyncSessionError ? error.code : "session-apply-failed";
213
+ sendJson(res, code === "bundle-too-large" ? 413 : [
214
+ "manifest-invalid",
215
+ "manifest-digest",
216
+ "object-invalid",
217
+ "session-format"
218
+ ].includes(code) ? 400 : code === "workspace-unmapped" ? 409 : 500, {
219
+ ok: false,
220
+ code,
221
+ error: error instanceof SyncSessionError ? error.message : "session bundle apply failed"
222
+ });
223
+ }
224
+ return;
225
+ }
226
+ sendJson(res, 404, {
227
+ ok: false,
228
+ error: "not found"
229
+ });
230
+ }
231
+ }));
232
+ }
233
+ //#endregion
234
+ export { registerSyncInternalRoutes };
235
+
236
+ //# sourceMappingURL=internal-routes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"internal-routes.js","names":[],"sources":["../../../src/core/sync/internal-routes.ts"],"sourcesContent":["import type { IncomingMessage, ServerResponse } from 'node:http'\nimport type { Context } from '@deepseek-ai/cordis'\nimport type {} from '@deepseek-ai/dsh-host-webserver'\nimport { isLoopbackRequest } from '../../auth/loopback.js'\nimport { SyncNodeManifestError, type SyncNodeService } from './node-sync.js'\nimport { SyncSessionError, type SyncSessionService } from './session-sync.js'\nimport { MAX_SYNC_TRANSFER_BYTES, SYNC_PROTOCOL_VERSION } from './protocol.js'\nimport type { SyncStateStore } from './stores.js'\n\nconst MAX_APPLY_BODY_BYTES = MAX_SYNC_TRANSFER_BYTES\n\nfunction sendJson(res: ServerResponse, status: number, body: unknown): void {\n res.writeHead(status, { 'content-type': 'application/json', 'cache-control': 'no-store' })\n res.end(JSON.stringify(body))\n}\n\nfunction pathSegments(req: IncomingMessage): string[] {\n return new URL(req.url ?? '/', 'http://x').pathname.split('/').filter(Boolean)\n}\n\nfunction readJsonBody(req: IncomingMessage): Promise<Record<string, unknown> | null> {\n return new Promise((resolve) => {\n if (req.headers['content-type']?.split(';', 1)[0]?.trim().toLowerCase() !== 'application/json') {\n resolve(null)\n return\n }\n const chunks: Buffer[] = []\n let size = 0\n let settled = false\n const fail = (): void => {\n if (settled) return\n settled = true\n resolve(null)\n }\n req.on('data', (chunk: Buffer) => {\n if (settled) return\n size += chunk.length\n if (size > MAX_APPLY_BODY_BYTES) {\n fail()\n req.destroy()\n return\n }\n chunks.push(chunk)\n })\n req.on('end', () => {\n if (settled) return\n try {\n const value: unknown = JSON.parse(Buffer.concat(chunks).toString('utf8'))\n if (value === null || typeof value !== 'object' || Array.isArray(value)) {\n fail()\n return\n }\n settled = true\n resolve(value as Record<string, unknown>)\n } catch {\n fail()\n }\n })\n req.on('error', fail)\n })\n}\n\nexport function registerSyncInternalRoutes(\n ctx: Context,\n state: SyncStateStore,\n nodeSync?: SyncNodeService,\n sessionSync?: SyncSessionService,\n): void {\n ctx.effect(() =>\n ctx.webServer.register({\n kind: 'exact',\n path: '/api/dshb/sync/internal/handshake',\n handler: (req: IncomingMessage, res: ServerResponse) => {\n if (!isLoopbackRequest(req.socket.remoteAddress, req.headers.host)) {\n sendJson(res, 403, { ok: false, error: 'loopback access required' })\n return\n }\n if (req.method !== 'GET') {\n sendJson(res, 405, { ok: false, error: 'method not allowed' })\n return\n }\n try {\n sendJson(res, 200, {\n ok: true,\n protocolVersion: SYNC_PROTOCOL_VERSION,\n instanceId: state.instanceId(),\n capabilities: [\n 'peer-handshake',\n ...(nodeSync ? ['node-sync'] : []),\n ...(sessionSync ? ['session-sync'] : []),\n ],\n })\n } catch {\n sendJson(res, 503, { ok: false, error: 'sync identity unavailable' })\n }\n },\n }),\n )\n\n if (nodeSync) ctx.effect(() =>\n ctx.webServer.register({\n kind: 'prefix',\n path: '/api/dshb/sync/internal/nodes',\n handler: async (req, res) => {\n if (!isLoopbackRequest(req.socket.remoteAddress, req.headers.host)) {\n sendJson(res, 403, { ok: false, error: 'loopback access required' })\n return\n }\n const segments = pathSegments(req)\n const action = segments[5]\n if (segments.length !== 6) {\n sendJson(res, 404, { ok: false, error: 'not found' })\n return\n }\n if (req.method === 'GET' && action === 'manifest') {\n try {\n sendJson(res, 200, { ok: true, manifest: await nodeSync.exportManifest() })\n } catch {\n sendJson(res, 500, { ok: false, error: 'node manifest export failed' })\n }\n return\n }\n if (req.method === 'POST' && action === 'apply') {\n const body = await readJsonBody(req)\n if (!body || !Array.isArray(body.records) || typeof body.sourceName !== 'string') {\n sendJson(res, 400, { ok: false, error: 'records and sourceName are required' })\n return\n }\n try {\n sendJson(res, 200, { ok: true, result: await nodeSync.applyManifest(body.records, body.sourceName) })\n } catch (error) {\n const status = error instanceof SyncNodeManifestError ? 400 : 500\n sendJson(res, status, { ok: false, error: status === 400 ? 'node manifest rejected' : 'node manifest apply failed' })\n }\n return\n }\n sendJson(res, 404, { ok: false, error: 'not found' })\n },\n }),\n )\n\n if (!sessionSync) return\n ctx.effect(() =>\n ctx.webServer.register({\n kind: 'prefix',\n path: '/api/dshb/sync/internal/sessions',\n handler: async (req, res) => {\n if (!isLoopbackRequest(req.socket.remoteAddress, req.headers.host)) {\n sendJson(res, 403, { ok: false, error: 'loopback access required' })\n return\n }\n const segments = pathSegments(req)\n const action = segments[5]\n if (segments.length !== 6) {\n sendJson(res, 404, { ok: false, error: 'not found' })\n return\n }\n if (req.method === 'GET' && action === 'bundle') {\n try {\n sendJson(res, 200, { ok: true, bundle: await sessionSync.exportBundle() })\n } catch (error) {\n const code = error instanceof SyncSessionError ? error.code : 'session-export-failed'\n const status = code === 'bundle-too-large' ? 413 : 500\n sendJson(res, status, { ok: false, code, error: error instanceof SyncSessionError ? error.message : 'session bundle export failed' })\n }\n return\n }\n if (req.method === 'POST' && action === 'apply') {\n const body = await readJsonBody(req)\n if (!body || body.bundle === null || typeof body.bundle !== 'object' ||\n typeof body.sourceName !== 'string' || typeof body.peerId !== 'string' || !/^p-[a-f0-9]{24}$/.test(body.peerId)) {\n sendJson(res, 400, { ok: false, code: 'session-request-invalid', error: 'bundle, sourceName, and peerId are required' })\n return\n }\n try {\n sendJson(res, 200, {\n ok: true,\n result: await sessionSync.applyBundle(body.bundle, body.sourceName, body.peerId),\n })\n } catch (error) {\n const code = error instanceof SyncSessionError ? error.code : 'session-apply-failed'\n const status = code === 'bundle-too-large' ? 413\n : ['manifest-invalid', 'manifest-digest', 'object-invalid', 'session-format'].includes(code) ? 400\n : code === 'workspace-unmapped' ? 409 : 500\n sendJson(res, status, { ok: false, code, error: error instanceof SyncSessionError ? error.message : 'session bundle apply failed' })\n }\n return\n }\n sendJson(res, 404, { ok: false, error: 'not found' })\n },\n }),\n )\n}\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { _ as parseSyncPeerDraft, a as SyncPeer, c as SyncProvenance, d as SyncSessionArchive, f as SyncState, g as parseSyncPeer, h as isRecord, i as SyncOrigin, l as SyncRecordMetadata, m as isNonNegativeSafeInteger, n as SyncEntityKind, o as SyncPeerDraft, p as SyncWorkspaceMapping, r as SyncImportMethod, s as SyncPeerProgress, t as SyncDirection, u as SyncSchedule, v as syncRecordKey, y as syncWorkspaceKey } from "../../model-BP7Gw1yk.js";
2
+ export { SyncDirection, SyncEntityKind, SyncImportMethod, SyncOrigin, SyncPeer, SyncPeerDraft, SyncPeerProgress, SyncProvenance, SyncRecordMetadata, SyncSchedule, SyncSessionArchive, SyncState, SyncWorkspaceMapping, isNonNegativeSafeInteger, isRecord, parseSyncPeer, parseSyncPeerDraft, syncRecordKey, syncWorkspaceKey };
@@ -0,0 +1,106 @@
1
+ import { posix } from "node:path";
2
+ //#region src/core/sync/model.ts
3
+ const PEER_FIELDS = /* @__PURE__ */ new Set([
4
+ "id",
5
+ "name",
6
+ "host",
7
+ "port",
8
+ "username",
9
+ "authKind",
10
+ "remoteDshHome",
11
+ "remoteProfile",
12
+ "remoteWebPort",
13
+ "direction",
14
+ "schedule",
15
+ "syncSessions",
16
+ "enabled",
17
+ "hostKeyFingerprint"
18
+ ]);
19
+ const PEER_DRAFT_FIELDS = new Set([...PEER_FIELDS].filter((field) => field !== "id" && field !== "hostKeyFingerprint"));
20
+ function record(value, label) {
21
+ if (value === null || typeof value !== "object" || Array.isArray(value)) throw new Error(`${label} must be an object`);
22
+ return value;
23
+ }
24
+ function text(value, label, maxLength) {
25
+ if (typeof value !== "string") throw new Error(`${label} must be a string`);
26
+ const result = value.trim();
27
+ if (!result || result.length > maxLength || /[\u0000-\u001f\u007f]/.test(result)) throw new Error(`${label} is invalid`);
28
+ return result;
29
+ }
30
+ function optionalText(value, label, maxLength) {
31
+ return value === void 0 ? void 0 : text(value, label, maxLength);
32
+ }
33
+ function port(value, label) {
34
+ if (!Number.isSafeInteger(value) || value < 1 || value > 65535) throw new Error(`${label} must be an integer between 1 and 65535`);
35
+ return value;
36
+ }
37
+ function parseSyncPeer(value) {
38
+ const input = record(value, "sync peer");
39
+ for (const key of Object.keys(input)) if (!PEER_FIELDS.has(key)) throw new Error(`sync peer contains unsupported field: ${key}`);
40
+ const id = text(input.id, "id", 128);
41
+ if (!/^[a-z][a-z0-9-]*$/.test(id)) throw new Error("id is invalid");
42
+ const name = text(input.name, "name", 128);
43
+ const host = text(input.host, "host", 255);
44
+ if (/\s/.test(host)) throw new Error("host is invalid");
45
+ const username = text(input.username, "username", 128);
46
+ if (/\s/.test(username)) throw new Error("username is invalid");
47
+ if (input.authKind !== "password" && input.authKind !== "key") throw new Error("authKind must be password or key");
48
+ if (input.direction !== "pull" && input.direction !== "bidirectional") throw new Error("direction must be pull or bidirectional");
49
+ if (input.schedule !== "manual" && input.schedule !== "every-5m") throw new Error("schedule must be manual or every-5m");
50
+ if (typeof input.syncSessions !== "boolean" || typeof input.enabled !== "boolean") throw new Error("syncSessions and enabled must be booleans");
51
+ const remoteDshHome = optionalText(input.remoteDshHome, "remoteDshHome", 4096);
52
+ if (remoteDshHome !== void 0) {
53
+ if (!posix.isAbsolute(remoteDshHome) || remoteDshHome.split("/").includes("..") || remoteDshHome.includes("\\")) throw new Error("remoteDshHome must be a normalized absolute path");
54
+ }
55
+ const remoteProfile = optionalText(input.remoteProfile, "remoteProfile", 256);
56
+ const hostKeyFingerprint = optionalText(input.hostKeyFingerprint, "hostKeyFingerprint", 512);
57
+ return {
58
+ id,
59
+ name,
60
+ host,
61
+ port: port(input.port, "port"),
62
+ username,
63
+ authKind: input.authKind,
64
+ ...remoteDshHome === void 0 ? {} : { remoteDshHome: posix.normalize(remoteDshHome) },
65
+ ...remoteProfile === void 0 ? {} : { remoteProfile },
66
+ ...input.remoteWebPort === void 0 ? {} : { remoteWebPort: port(input.remoteWebPort, "remoteWebPort") },
67
+ direction: input.direction,
68
+ schedule: input.schedule,
69
+ syncSessions: input.syncSessions,
70
+ enabled: input.enabled,
71
+ ...hostKeyFingerprint === void 0 ? {} : { hostKeyFingerprint }
72
+ };
73
+ }
74
+ function parseSyncPeerDraft(value) {
75
+ const input = record(value, "sync peer draft");
76
+ for (const key of Object.keys(input)) if (!PEER_DRAFT_FIELDS.has(key)) throw new Error(`sync peer draft contains unsupported field: ${key}`);
77
+ const { id, ...draft } = parseSyncPeer({
78
+ ...input,
79
+ id: `p-${"0".repeat(24)}`
80
+ });
81
+ return draft;
82
+ }
83
+ function syncRecordKey(kind, origin) {
84
+ return JSON.stringify([
85
+ kind,
86
+ origin.originInstanceId,
87
+ origin.originEntityId
88
+ ]);
89
+ }
90
+ function syncWorkspaceKey(originInstanceId, originWorkspaceId, remotePath) {
91
+ return JSON.stringify([
92
+ originInstanceId,
93
+ originWorkspaceId,
94
+ remotePath
95
+ ]);
96
+ }
97
+ function isRecord(value) {
98
+ return value !== null && typeof value === "object" && !Array.isArray(value);
99
+ }
100
+ function isNonNegativeSafeInteger(value) {
101
+ return Number.isSafeInteger(value) && value >= 0;
102
+ }
103
+ //#endregion
104
+ export { isNonNegativeSafeInteger, isRecord, parseSyncPeer, parseSyncPeerDraft, syncRecordKey, syncWorkspaceKey };
105
+
106
+ //# sourceMappingURL=model.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model.js","names":[],"sources":["../../../src/core/sync/model.ts"],"sourcesContent":["import { posix } from 'node:path'\nimport type { SyncRevision } from './revision.js'\n\nexport type SyncDirection = 'pull' | 'bidirectional'\nexport type SyncSchedule = 'manual' | 'every-5m'\nexport type SyncEntityKind = 'node' | 'session'\nexport type SyncImportMethod = 'peer' | 'offline'\n\nexport interface SyncPeer {\n id: string\n name: string\n host: string\n port: number\n username: string\n authKind: 'password' | 'key'\n remoteDshHome?: string\n remoteProfile?: string\n remoteWebPort?: number\n direction: SyncDirection\n schedule: SyncSchedule\n syncSessions: boolean\n enabled: boolean\n hostKeyFingerprint?: string\n}\n\nexport type SyncPeerDraft = Omit<SyncPeer, 'id' | 'hostKeyFingerprint'>\n\nexport interface SyncOrigin {\n originInstanceId: string\n originEntityId: string\n}\n\nexport interface SyncProvenance extends SyncOrigin {\n localEntityId: string\n importedVia?: SyncImportMethod\n sourceName?: string\n}\n\nexport interface SyncRecordMetadata extends SyncProvenance {\n kind: SyncEntityKind\n revision: SyncRevision\n contentDigest: string\n stateDigest?: string\n workspaceOrigin?: SyncOrigin\n deleted?: boolean\n pendingRemoval?: boolean\n credentialsRequired?: boolean\n}\n\nexport interface SyncPeerProgress {\n lastRunAt?: string\n lastRunStatus?: 'running' | 'succeeded' | 'failed'\n lastSuccessAt?: string\n lastManifestDigest?: string\n watermark?: string\n lastErrorCode?: string\n lastErrorMessage?: string\n lastResult?: {\n imported: number\n exported: number\n skipped: number\n pendingRemoval: number\n importedSessions: number\n exportedSessions: number\n skippedSessions: number\n }\n}\n\nexport interface SyncWorkspaceMapping {\n originInstanceId: string\n originWorkspaceId: string\n localWorkspaceId: string\n localPath: string\n localNodeId: string\n remotePath: string\n title: string\n revision: SyncRevision\n contentDigest: string\n}\n\nexport interface SyncSessionArchive {\n branchId: string\n originInstanceId: string\n originSessionId: string\n localSessionId: string\n revision: SyncRevision\n contentDigest: string\n stateDigest: string\n workspacePosition: number\n workspaceId?: string\n workspaceOrigin?: SyncOrigin\n archivedAt: string\n}\n\nexport interface SyncState {\n version: 1\n clock: { physicalTimeMs: number; logicalCounter: number }\n peers: Record<string, SyncPeerProgress>\n records: Record<string, SyncRecordMetadata>\n workspaces: Record<string, SyncWorkspaceMapping>\n archives: Record<string, SyncSessionArchive>\n}\n\nconst PEER_FIELDS = new Set([\n 'id',\n 'name',\n 'host',\n 'port',\n 'username',\n 'authKind',\n 'remoteDshHome',\n 'remoteProfile',\n 'remoteWebPort',\n 'direction',\n 'schedule',\n 'syncSessions',\n 'enabled',\n 'hostKeyFingerprint',\n])\n\nconst PEER_DRAFT_FIELDS = new Set([...PEER_FIELDS].filter((field) => field !== 'id' && field !== 'hostKeyFingerprint'))\n\nfunction record(value: unknown, label: string): Record<string, unknown> {\n if (value === null || typeof value !== 'object' || Array.isArray(value)) {\n throw new Error(`${label} must be an object`)\n }\n return value as Record<string, unknown>\n}\n\nfunction text(value: unknown, label: string, maxLength: number): string {\n if (typeof value !== 'string') throw new Error(`${label} must be a string`)\n const result = value.trim()\n if (!result || result.length > maxLength || /[\\u0000-\\u001f\\u007f]/.test(result)) {\n throw new Error(`${label} is invalid`)\n }\n return result\n}\n\nfunction optionalText(value: unknown, label: string, maxLength: number): string | undefined {\n return value === undefined ? undefined : text(value, label, maxLength)\n}\n\nfunction port(value: unknown, label: string): number {\n if (!Number.isSafeInteger(value) || (value as number) < 1 || (value as number) > 65535) {\n throw new Error(`${label} must be an integer between 1 and 65535`)\n }\n return value as number\n}\n\nexport function parseSyncPeer(value: unknown): SyncPeer {\n const input = record(value, 'sync peer')\n for (const key of Object.keys(input)) {\n if (!PEER_FIELDS.has(key)) throw new Error(`sync peer contains unsupported field: ${key}`)\n }\n\n const id = text(input.id, 'id', 128)\n if (!/^[a-z][a-z0-9-]*$/.test(id)) throw new Error('id is invalid')\n\n const name = text(input.name, 'name', 128)\n const host = text(input.host, 'host', 255)\n if (/\\s/.test(host)) throw new Error('host is invalid')\n\n const username = text(input.username, 'username', 128)\n if (/\\s/.test(username)) throw new Error('username is invalid')\n\n if (input.authKind !== 'password' && input.authKind !== 'key') {\n throw new Error('authKind must be password or key')\n }\n if (input.direction !== 'pull' && input.direction !== 'bidirectional') {\n throw new Error('direction must be pull or bidirectional')\n }\n if (input.schedule !== 'manual' && input.schedule !== 'every-5m') {\n throw new Error('schedule must be manual or every-5m')\n }\n if (typeof input.syncSessions !== 'boolean' || typeof input.enabled !== 'boolean') {\n throw new Error('syncSessions and enabled must be booleans')\n }\n\n const remoteDshHome = optionalText(input.remoteDshHome, 'remoteDshHome', 4096)\n if (remoteDshHome !== undefined) {\n if (!posix.isAbsolute(remoteDshHome) || remoteDshHome.split('/').includes('..') || remoteDshHome.includes('\\\\')) {\n throw new Error('remoteDshHome must be a normalized absolute path')\n }\n }\n\n const remoteProfile = optionalText(input.remoteProfile, 'remoteProfile', 256)\n const hostKeyFingerprint = optionalText(input.hostKeyFingerprint, 'hostKeyFingerprint', 512)\n\n return {\n id,\n name,\n host,\n port: port(input.port, 'port'),\n username,\n authKind: input.authKind,\n ...(remoteDshHome === undefined ? {} : { remoteDshHome: posix.normalize(remoteDshHome) }),\n ...(remoteProfile === undefined ? {} : { remoteProfile }),\n ...(input.remoteWebPort === undefined ? {} : { remoteWebPort: port(input.remoteWebPort, 'remoteWebPort') }),\n direction: input.direction,\n schedule: input.schedule,\n syncSessions: input.syncSessions,\n enabled: input.enabled,\n ...(hostKeyFingerprint === undefined ? {} : { hostKeyFingerprint }),\n }\n}\n\nexport function parseSyncPeerDraft(value: unknown): SyncPeerDraft {\n const input = record(value, 'sync peer draft')\n for (const key of Object.keys(input)) {\n if (!PEER_DRAFT_FIELDS.has(key)) throw new Error(`sync peer draft contains unsupported field: ${key}`)\n }\n const { id, ...draft } = parseSyncPeer({ ...input, id: `p-${'0'.repeat(24)}` })\n void id\n return draft\n}\n\nexport function syncRecordKey(kind: SyncEntityKind, origin: SyncOrigin): string {\n return JSON.stringify([kind, origin.originInstanceId, origin.originEntityId])\n}\n\nexport function syncWorkspaceKey(originInstanceId: string, originWorkspaceId: string, remotePath: string): string {\n return JSON.stringify([originInstanceId, originWorkspaceId, remotePath])\n}\n\nexport function isRecord(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === 'object' && !Array.isArray(value)\n}\n\nexport function isNonNegativeSafeInteger(value: unknown): value is number {\n return Number.isSafeInteger(value) && (value as number) >= 0\n}\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { a as SyncNodeManifestError, c as SyncNodeView, i as SyncNodeManifest, n as SyncNodeEntry, o as SyncNodeProfile, r as SyncNodeInUseError, s as SyncNodeService, t as SyncNodeApplyResult } from "../../node-sync-3Z9QLz2n.js";
2
+ export { SyncNodeApplyResult, SyncNodeEntry, SyncNodeInUseError, SyncNodeManifest, SyncNodeManifestError, SyncNodeProfile, SyncNodeService, SyncNodeView };