silosdk 0.0.1 → 0.0.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.
Files changed (92) hide show
  1. package/dist/settings.cjs +70 -0
  2. package/dist/settings.d.cts +20 -0
  3. package/dist/settings.d.mts +20 -0
  4. package/dist/settings.mjs +68 -0
  5. package/dist/source.cjs +162 -0
  6. package/dist/source.d.cts +29 -0
  7. package/dist/source.d.mts +29 -0
  8. package/dist/source.mjs +161 -0
  9. package/package.json +23 -20
  10. package/README.md +0 -3
  11. package/dist/cli/d1.cjs +0 -93
  12. package/dist/cli/d1.mjs +0 -92
  13. package/dist/cli/index.cjs +0 -93
  14. package/dist/cli/index.d.cts +0 -1
  15. package/dist/cli/index.d.mts +0 -1
  16. package/dist/cli/index.mjs +0 -94
  17. package/dist/cli/init.cjs +0 -134
  18. package/dist/cli/init.mjs +0 -133
  19. package/dist/cli/kv.cjs +0 -63
  20. package/dist/cli/kv.mjs +0 -60
  21. package/dist/cli/r2.cjs +0 -83
  22. package/dist/cli/r2.mjs +0 -82
  23. package/dist/cli/wrangler.cjs +0 -93
  24. package/dist/cli/wrangler.mjs +0 -89
  25. package/dist/local/adapters/cloudflare.cjs +0 -200
  26. package/dist/local/adapters/cloudflare.d.cts +0 -50
  27. package/dist/local/adapters/cloudflare.d.mts +0 -50
  28. package/dist/local/adapters/cloudflare.mjs +0 -200
  29. package/dist/local/auth-context.cjs +0 -14
  30. package/dist/local/auth-context.d.cts +0 -7
  31. package/dist/local/auth-context.d.mts +0 -7
  32. package/dist/local/auth-context.mjs +0 -12
  33. package/dist/local/auth.cjs +0 -109
  34. package/dist/local/auth.d.cts +0 -26
  35. package/dist/local/auth.d.mts +0 -26
  36. package/dist/local/auth.mjs +0 -99
  37. package/dist/local/commit.cjs +0 -350
  38. package/dist/local/commit.d.cts +0 -59
  39. package/dist/local/commit.d.mts +0 -59
  40. package/dist/local/commit.mjs +0 -349
  41. package/dist/local/config.cjs +0 -17
  42. package/dist/local/config.mjs +0 -15
  43. package/dist/local/index.cjs +0 -16
  44. package/dist/local/index.d.cts +0 -10
  45. package/dist/local/index.d.mts +0 -10
  46. package/dist/local/index.mjs +0 -9
  47. package/dist/local/provider.cjs +0 -204
  48. package/dist/local/provider.d.cts +0 -25
  49. package/dist/local/provider.d.mts +0 -25
  50. package/dist/local/provider.mjs +0 -203
  51. package/dist/local/query-store.cjs +0 -276
  52. package/dist/local/query-store.mjs +0 -274
  53. package/dist/local/storage.cjs +0 -71
  54. package/dist/local/storage.d.cts +0 -7
  55. package/dist/local/storage.d.mts +0 -7
  56. package/dist/local/storage.mjs +0 -68
  57. package/dist/local/sync.cjs +0 -124
  58. package/dist/local/sync.d.cts +0 -36
  59. package/dist/local/sync.d.mts +0 -36
  60. package/dist/local/sync.mjs +0 -122
  61. package/dist/local/view.cjs +0 -257
  62. package/dist/local/view.d.cts +0 -24
  63. package/dist/local/view.d.mts +0 -24
  64. package/dist/local/view.mjs +0 -254
  65. package/dist/package.cjs +0 -11
  66. package/dist/package.mjs +0 -5
  67. package/dist/schema/index.cjs +0 -276
  68. package/dist/schema/index.d.cts +0 -207
  69. package/dist/schema/index.d.mts +0 -207
  70. package/dist/schema/index.mjs +0 -265
  71. package/dist/server/auth.cjs +0 -132
  72. package/dist/server/auth.d.cts +0 -49
  73. package/dist/server/auth.d.mts +0 -49
  74. package/dist/server/auth.mjs +0 -122
  75. package/dist/server/d1.cjs +0 -120
  76. package/dist/server/d1.mjs +0 -116
  77. package/dist/server/do.cjs +0 -132
  78. package/dist/server/do.d.cts +0 -21
  79. package/dist/server/do.d.mts +0 -21
  80. package/dist/server/do.mjs +0 -131
  81. package/dist/server/index.cjs +0 -355
  82. package/dist/server/index.d.cts +0 -65
  83. package/dist/server/index.d.mts +0 -65
  84. package/dist/server/index.mjs +0 -348
  85. package/dist/server/protect.cjs +0 -34
  86. package/dist/server/protect.d.cts +0 -32
  87. package/dist/server/protect.d.mts +0 -32
  88. package/dist/server/protect.mjs +0 -33
  89. package/dist/server/r2.cjs +0 -58
  90. package/dist/server/r2.d.cts +0 -4
  91. package/dist/server/r2.d.mts +0 -4
  92. package/dist/server/r2.mjs +0 -53
@@ -1,120 +0,0 @@
1
-
2
- //#region src/server/d1.ts
3
- function jex(field) {
4
- return `json_extract(data, '$.${field}')`;
5
- }
6
- function compileWhere(where) {
7
- const params = [];
8
- const compileObject = (obj) => {
9
- const parts = [];
10
- for (const field of Object.keys(obj)) {
11
- const value = obj[field];
12
- if (Array.isArray(value)) {
13
- const placeholders = value.map(() => "?").join(", ");
14
- parts.push(`${jex(field)} IN (${placeholders})`);
15
- params.push(...value);
16
- } else if (value && typeof value === "object") for (const op of Object.keys(value)) {
17
- parts.push(`${jex(field)} ${op} ?`);
18
- params.push(value[op]);
19
- }
20
- else {
21
- parts.push(`${jex(field)} = ?`);
22
- params.push(value);
23
- }
24
- }
25
- return parts.join(" AND ");
26
- };
27
- if (Array.isArray(where)) return {
28
- clause: where.map((o) => `(${compileObject(o)})`).join(" OR "),
29
- params
30
- };
31
- return {
32
- clause: compileObject(where),
33
- params
34
- };
35
- }
36
- async function d1GetRow(db, viewName, options) {
37
- const row = await db.prepare(`SELECT id, view, data, createdAt, updatedAt, version
38
- FROM views WHERE view = ? AND id = ?`).bind(viewName, options.id).first();
39
- if (!row) return null;
40
- return {
41
- ...row,
42
- data: JSON.parse(row.data)
43
- };
44
- }
45
- async function d1GetRows(db, viewName, options) {
46
- const parentView = options.parentView;
47
- const parentId = options.parentId;
48
- const childView = options.childView;
49
- const childId = options.childId;
50
- let statement = `SELECT id, view, data, createdAt, updatedAt, version FROM views WHERE view = ?`;
51
- const params = [viewName];
52
- if (parentView && parentId) {
53
- statement += ` AND id IN (SELECT cid FROM relations WHERE child = ? AND parent = ? AND pid = ?)`;
54
- params.push(viewName, parentView, parentId);
55
- }
56
- if (childView && childId) {
57
- statement += ` AND id IN (SELECT pid FROM relations WHERE parent = ? AND child = ? AND cid = ?)`;
58
- params.push(viewName, childView, childId);
59
- }
60
- if (options.where) {
61
- const { clause, params: wp } = compileWhere(options.where);
62
- statement += ` AND (${clause})`;
63
- params.push(...wp);
64
- }
65
- if (options.order) {
66
- const orderClauses = [];
67
- for (const [field, direction] of Object.entries(options.order)) orderClauses.push(`${jex(field)} ${String(direction).toUpperCase()}`);
68
- if (orderClauses.length > 0) statement += ` ORDER BY ${orderClauses.join(", ")}`;
69
- }
70
- if (options.take !== void 0) {
71
- statement += ` LIMIT ?`;
72
- params.push(options.take);
73
- }
74
- return ((await db.prepare(statement).bind(...params).all()).results ?? []).map((row) => ({
75
- ...row,
76
- data: JSON.parse(row.data)
77
- }));
78
- }
79
- async function d1ApplyOps(db, ops) {
80
- const timestamp = (/* @__PURE__ */ new Date()).toISOString();
81
- const stmts = [];
82
- for (const op of ops) if (op.kind === "add") stmts.push(db.prepare(`INSERT INTO views (id, view, data, createdAt, updatedAt, version)
83
- VALUES (?, ?, ?, ?, ?, ?)
84
- ON CONFLICT(id) DO NOTHING`).bind(op.id, op.view.name, JSON.stringify(op.value), timestamp, timestamp, 1));
85
- else if (op.kind === "update") stmts.push(db.prepare(`UPDATE views
86
- SET data = json_patch(data, ?), updatedAt = ?, version = version + 1
87
- WHERE id = ? AND view = ?`).bind(JSON.stringify(op.value), timestamp, op.id, op.view.name));
88
- else if (op.kind === "remove") {
89
- stmts.push(db.prepare(`DELETE FROM views WHERE id = ? AND view = ?`).bind(op.id, op.view.name));
90
- stmts.push(db.prepare(`DELETE FROM relations
91
- WHERE (parent = ? AND pid = ?) OR (child = ? AND cid = ?)`).bind(op.view.name, op.id, op.view.name, op.id));
92
- } else if (op.kind === "link") stmts.push(db.prepare(`INSERT INTO relations (parent, pid, child, cid)
93
- VALUES (?, ?, ?, ?)
94
- ON CONFLICT DO NOTHING`).bind(op.parent.view.name, op.parent.id, op.child.view.name, op.child.id));
95
- else if (op.kind === "unlink") stmts.push(db.prepare(`DELETE FROM relations
96
- WHERE parent = ? AND pid = ? AND child = ? AND cid = ?`).bind(op.parent.view.name, op.parent.id, op.child.view.name, op.child.id));
97
- if (stmts.length > 0) await db.batch(stmts);
98
- }
99
- async function d1EnsureSchema(db) {
100
- await db.prepare(`CREATE TABLE IF NOT EXISTS views (
101
- id TEXT PRIMARY KEY,
102
- view TEXT NOT NULL,
103
- data BLOB NOT NULL,
104
- createdAt TEXT NOT NULL,
105
- updatedAt TEXT NOT NULL,
106
- version INTEGER DEFAULT 0
107
- )`).run();
108
- await db.prepare(`CREATE TABLE IF NOT EXISTS relations (
109
- parent TEXT NOT NULL,
110
- pid TEXT NOT NULL,
111
- child TEXT NOT NULL,
112
- cid TEXT NOT NULL
113
- )`).run();
114
- }
115
-
116
- //#endregion
117
- exports.d1ApplyOps = d1ApplyOps;
118
- exports.d1EnsureSchema = d1EnsureSchema;
119
- exports.d1GetRow = d1GetRow;
120
- exports.d1GetRows = d1GetRows;
@@ -1,116 +0,0 @@
1
- //#region src/server/d1.ts
2
- function jex(field) {
3
- return `json_extract(data, '$.${field}')`;
4
- }
5
- function compileWhere(where) {
6
- const params = [];
7
- const compileObject = (obj) => {
8
- const parts = [];
9
- for (const field of Object.keys(obj)) {
10
- const value = obj[field];
11
- if (Array.isArray(value)) {
12
- const placeholders = value.map(() => "?").join(", ");
13
- parts.push(`${jex(field)} IN (${placeholders})`);
14
- params.push(...value);
15
- } else if (value && typeof value === "object") for (const op of Object.keys(value)) {
16
- parts.push(`${jex(field)} ${op} ?`);
17
- params.push(value[op]);
18
- }
19
- else {
20
- parts.push(`${jex(field)} = ?`);
21
- params.push(value);
22
- }
23
- }
24
- return parts.join(" AND ");
25
- };
26
- if (Array.isArray(where)) return {
27
- clause: where.map((o) => `(${compileObject(o)})`).join(" OR "),
28
- params
29
- };
30
- return {
31
- clause: compileObject(where),
32
- params
33
- };
34
- }
35
- async function d1GetRow(db, viewName, options) {
36
- const row = await db.prepare(`SELECT id, view, data, createdAt, updatedAt, version
37
- FROM views WHERE view = ? AND id = ?`).bind(viewName, options.id).first();
38
- if (!row) return null;
39
- return {
40
- ...row,
41
- data: JSON.parse(row.data)
42
- };
43
- }
44
- async function d1GetRows(db, viewName, options) {
45
- const parentView = options.parentView;
46
- const parentId = options.parentId;
47
- const childView = options.childView;
48
- const childId = options.childId;
49
- let statement = `SELECT id, view, data, createdAt, updatedAt, version FROM views WHERE view = ?`;
50
- const params = [viewName];
51
- if (parentView && parentId) {
52
- statement += ` AND id IN (SELECT cid FROM relations WHERE child = ? AND parent = ? AND pid = ?)`;
53
- params.push(viewName, parentView, parentId);
54
- }
55
- if (childView && childId) {
56
- statement += ` AND id IN (SELECT pid FROM relations WHERE parent = ? AND child = ? AND cid = ?)`;
57
- params.push(viewName, childView, childId);
58
- }
59
- if (options.where) {
60
- const { clause, params: wp } = compileWhere(options.where);
61
- statement += ` AND (${clause})`;
62
- params.push(...wp);
63
- }
64
- if (options.order) {
65
- const orderClauses = [];
66
- for (const [field, direction] of Object.entries(options.order)) orderClauses.push(`${jex(field)} ${String(direction).toUpperCase()}`);
67
- if (orderClauses.length > 0) statement += ` ORDER BY ${orderClauses.join(", ")}`;
68
- }
69
- if (options.take !== void 0) {
70
- statement += ` LIMIT ?`;
71
- params.push(options.take);
72
- }
73
- return ((await db.prepare(statement).bind(...params).all()).results ?? []).map((row) => ({
74
- ...row,
75
- data: JSON.parse(row.data)
76
- }));
77
- }
78
- async function d1ApplyOps(db, ops) {
79
- const timestamp = (/* @__PURE__ */ new Date()).toISOString();
80
- const stmts = [];
81
- for (const op of ops) if (op.kind === "add") stmts.push(db.prepare(`INSERT INTO views (id, view, data, createdAt, updatedAt, version)
82
- VALUES (?, ?, ?, ?, ?, ?)
83
- ON CONFLICT(id) DO NOTHING`).bind(op.id, op.view.name, JSON.stringify(op.value), timestamp, timestamp, 1));
84
- else if (op.kind === "update") stmts.push(db.prepare(`UPDATE views
85
- SET data = json_patch(data, ?), updatedAt = ?, version = version + 1
86
- WHERE id = ? AND view = ?`).bind(JSON.stringify(op.value), timestamp, op.id, op.view.name));
87
- else if (op.kind === "remove") {
88
- stmts.push(db.prepare(`DELETE FROM views WHERE id = ? AND view = ?`).bind(op.id, op.view.name));
89
- stmts.push(db.prepare(`DELETE FROM relations
90
- WHERE (parent = ? AND pid = ?) OR (child = ? AND cid = ?)`).bind(op.view.name, op.id, op.view.name, op.id));
91
- } else if (op.kind === "link") stmts.push(db.prepare(`INSERT INTO relations (parent, pid, child, cid)
92
- VALUES (?, ?, ?, ?)
93
- ON CONFLICT DO NOTHING`).bind(op.parent.view.name, op.parent.id, op.child.view.name, op.child.id));
94
- else if (op.kind === "unlink") stmts.push(db.prepare(`DELETE FROM relations
95
- WHERE parent = ? AND pid = ? AND child = ? AND cid = ?`).bind(op.parent.view.name, op.parent.id, op.child.view.name, op.child.id));
96
- if (stmts.length > 0) await db.batch(stmts);
97
- }
98
- async function d1EnsureSchema(db) {
99
- await db.prepare(`CREATE TABLE IF NOT EXISTS views (
100
- id TEXT PRIMARY KEY,
101
- view TEXT NOT NULL,
102
- data BLOB NOT NULL,
103
- createdAt TEXT NOT NULL,
104
- updatedAt TEXT NOT NULL,
105
- version INTEGER DEFAULT 0
106
- )`).run();
107
- await db.prepare(`CREATE TABLE IF NOT EXISTS relations (
108
- parent TEXT NOT NULL,
109
- pid TEXT NOT NULL,
110
- child TEXT NOT NULL,
111
- cid TEXT NOT NULL
112
- )`).run();
113
- }
114
-
115
- //#endregion
116
- export { d1ApplyOps, d1EnsureSchema, d1GetRow, d1GetRows };
@@ -1,132 +0,0 @@
1
-
2
- //#region src/server/do.ts
3
- var SyncObject = class {
4
- constructor(state, env) {
5
- this.state = state;
6
- this.env = env;
7
- this.sessions = /* @__PURE__ */ new Map();
8
- this.sql = state.storage.sql;
9
- this.sql.exec(`
10
- CREATE TABLE IF NOT EXISTS views (
11
- id TEXT PRIMARY KEY,
12
- view TEXT NOT NULL,
13
- data BLOB NOT NULL,
14
- createdAt TEXT NOT NULL,
15
- updatedAt TEXT NOT NULL,
16
- version INTEGER DEFAULT 0
17
- );
18
- CREATE TABLE IF NOT EXISTS relations (
19
- parent TEXT NOT NULL,
20
- pid TEXT NOT NULL,
21
- child TEXT NOT NULL,
22
- cid TEXT NOT NULL
23
- );
24
- `);
25
- }
26
- async fetch(request) {
27
- const upgradeHeader = request.headers.get("Upgrade");
28
- if (!upgradeHeader || upgradeHeader !== "websocket") return new Response("Expected WebSocket", { status: 426 });
29
- const { 0: client, 1: server } = new WebSocketPair();
30
- this.state.acceptWebSocket(server);
31
- return new Response(null, {
32
- status: 101,
33
- webSocket: client
34
- });
35
- }
36
- async webSocketMessage(ws, message) {
37
- let msg;
38
- try {
39
- msg = JSON.parse(typeof message === "string" ? message : "");
40
- } catch {
41
- this.send(ws, {
42
- type: "error",
43
- message: "Invalid JSON"
44
- });
45
- return;
46
- }
47
- if (msg.type === "subscribe") await this.handleSubscribe(ws, msg.views);
48
- else if (msg.type === "commit") await this.handleCommit(ws, msg.ops, msg.requestId);
49
- }
50
- async webSocketClose(ws) {
51
- this.sessions.delete(ws);
52
- }
53
- async webSocketError(ws) {
54
- this.sessions.delete(ws);
55
- ws.close();
56
- }
57
- async handleSubscribe(ws, views) {
58
- this.sessions.set(ws, { views });
59
- for (const viewName of views) {
60
- const parsed = this.sql.exec(`SELECT id, view, data, createdAt, updatedAt, version
61
- FROM views WHERE view = ?`, viewName).toArray().map((row) => ({
62
- ...row,
63
- data: JSON.parse(row.data)
64
- }));
65
- this.send(ws, {
66
- type: "hydrate",
67
- view: viewName,
68
- rows: parsed
69
- });
70
- }
71
- }
72
- async handleCommit(ws, ops, requestId) {
73
- try {
74
- const timestamp = (/* @__PURE__ */ new Date()).toISOString();
75
- this.sql.exec("BEGIN");
76
- try {
77
- for (const op of ops) if (op.kind === "add") this.sql.exec(`INSERT INTO views (id, view, data, createdAt, updatedAt, version)
78
- VALUES (?, ?, ?, ?, ?, ?)
79
- ON CONFLICT(id) DO NOTHING`, op.id, op.view.name, JSON.stringify(op.value), timestamp, timestamp, 1);
80
- else if (op.kind === "update") this.sql.exec(`UPDATE views
81
- SET data = json_patch(data, ?), updatedAt = ?, version = version + 1
82
- WHERE id = ? AND view = ?`, JSON.stringify(op.value), timestamp, op.id, op.view.name);
83
- else if (op.kind === "remove") {
84
- this.sql.exec(`DELETE FROM views WHERE id = ? AND view = ?`, op.id, op.view.name);
85
- this.sql.exec(`DELETE FROM relations
86
- WHERE (parent = ? AND pid = ?) OR (child = ? AND cid = ?)`, op.view.name, op.id, op.view.name, op.id);
87
- } else if (op.kind === "link") this.sql.exec(`INSERT OR IGNORE INTO relations (parent, pid, child, cid)
88
- VALUES (?, ?, ?, ?)`, op.parent.view.name, op.parent.id, op.child.view.name, op.child.id);
89
- else if (op.kind === "unlink") this.sql.exec(`DELETE FROM relations
90
- WHERE parent = ? AND pid = ? AND child = ? AND cid = ?`, op.parent.view.name, op.parent.id, op.child.view.name, op.child.id);
91
- this.sql.exec("COMMIT");
92
- } catch (err) {
93
- this.sql.exec("ROLLBACK");
94
- throw err;
95
- }
96
- this.send(ws, {
97
- type: "committed",
98
- requestId,
99
- ops
100
- });
101
- const touchedViews = new Set(ops.map((op) => op.kind === "link" || op.kind === "unlink" ? op.parent.view.name : op.view.name));
102
- for (const [otherWs, session] of this.sessions) {
103
- if (otherWs === ws) continue;
104
- if (session.views.some((v) => touchedViews.has(v))) this.send(otherWs, {
105
- type: "push",
106
- ops
107
- });
108
- }
109
- for (const otherWs of this.state.getWebSockets()) {
110
- if (otherWs === ws) continue;
111
- if (!this.sessions.has(otherWs)) this.send(otherWs, {
112
- type: "push",
113
- ops
114
- });
115
- }
116
- } catch (err) {
117
- this.send(ws, {
118
- type: "rejected",
119
- requestId,
120
- reason: err instanceof Error ? err.message : "Unknown error"
121
- });
122
- }
123
- }
124
- send(ws, msg) {
125
- try {
126
- ws.send(JSON.stringify(msg));
127
- } catch {}
128
- }
129
- };
130
-
131
- //#endregion
132
- exports.SyncObject = SyncObject;
@@ -1,21 +0,0 @@
1
- //#region src/server/do.d.ts
2
- interface Env {
3
- SILO_SYNC: DurableObjectNamespace;
4
- SILO_DB: D1Database;
5
- }
6
- declare class SyncObject implements DurableObject {
7
- private readonly state;
8
- private readonly env;
9
- private sql;
10
- private sessions;
11
- constructor(state: DurableObjectState, env: Env);
12
- fetch(request: Request): Promise<Response>;
13
- webSocketMessage(ws: WebSocket, message: string | ArrayBuffer): Promise<void>;
14
- webSocketClose(ws: WebSocket): Promise<void>;
15
- webSocketError(ws: WebSocket): Promise<void>;
16
- private handleSubscribe;
17
- private handleCommit;
18
- private send;
19
- }
20
- //#endregion
21
- export { SyncObject };
@@ -1,21 +0,0 @@
1
- //#region src/server/do.d.ts
2
- interface Env {
3
- SILO_SYNC: DurableObjectNamespace;
4
- SILO_DB: D1Database;
5
- }
6
- declare class SyncObject implements DurableObject {
7
- private readonly state;
8
- private readonly env;
9
- private sql;
10
- private sessions;
11
- constructor(state: DurableObjectState, env: Env);
12
- fetch(request: Request): Promise<Response>;
13
- webSocketMessage(ws: WebSocket, message: string | ArrayBuffer): Promise<void>;
14
- webSocketClose(ws: WebSocket): Promise<void>;
15
- webSocketError(ws: WebSocket): Promise<void>;
16
- private handleSubscribe;
17
- private handleCommit;
18
- private send;
19
- }
20
- //#endregion
21
- export { SyncObject };
@@ -1,131 +0,0 @@
1
- //#region src/server/do.ts
2
- var SyncObject = class {
3
- constructor(state, env) {
4
- this.state = state;
5
- this.env = env;
6
- this.sessions = /* @__PURE__ */ new Map();
7
- this.sql = state.storage.sql;
8
- this.sql.exec(`
9
- CREATE TABLE IF NOT EXISTS views (
10
- id TEXT PRIMARY KEY,
11
- view TEXT NOT NULL,
12
- data BLOB NOT NULL,
13
- createdAt TEXT NOT NULL,
14
- updatedAt TEXT NOT NULL,
15
- version INTEGER DEFAULT 0
16
- );
17
- CREATE TABLE IF NOT EXISTS relations (
18
- parent TEXT NOT NULL,
19
- pid TEXT NOT NULL,
20
- child TEXT NOT NULL,
21
- cid TEXT NOT NULL
22
- );
23
- `);
24
- }
25
- async fetch(request) {
26
- const upgradeHeader = request.headers.get("Upgrade");
27
- if (!upgradeHeader || upgradeHeader !== "websocket") return new Response("Expected WebSocket", { status: 426 });
28
- const { 0: client, 1: server } = new WebSocketPair();
29
- this.state.acceptWebSocket(server);
30
- return new Response(null, {
31
- status: 101,
32
- webSocket: client
33
- });
34
- }
35
- async webSocketMessage(ws, message) {
36
- let msg;
37
- try {
38
- msg = JSON.parse(typeof message === "string" ? message : "");
39
- } catch {
40
- this.send(ws, {
41
- type: "error",
42
- message: "Invalid JSON"
43
- });
44
- return;
45
- }
46
- if (msg.type === "subscribe") await this.handleSubscribe(ws, msg.views);
47
- else if (msg.type === "commit") await this.handleCommit(ws, msg.ops, msg.requestId);
48
- }
49
- async webSocketClose(ws) {
50
- this.sessions.delete(ws);
51
- }
52
- async webSocketError(ws) {
53
- this.sessions.delete(ws);
54
- ws.close();
55
- }
56
- async handleSubscribe(ws, views) {
57
- this.sessions.set(ws, { views });
58
- for (const viewName of views) {
59
- const parsed = this.sql.exec(`SELECT id, view, data, createdAt, updatedAt, version
60
- FROM views WHERE view = ?`, viewName).toArray().map((row) => ({
61
- ...row,
62
- data: JSON.parse(row.data)
63
- }));
64
- this.send(ws, {
65
- type: "hydrate",
66
- view: viewName,
67
- rows: parsed
68
- });
69
- }
70
- }
71
- async handleCommit(ws, ops, requestId) {
72
- try {
73
- const timestamp = (/* @__PURE__ */ new Date()).toISOString();
74
- this.sql.exec("BEGIN");
75
- try {
76
- for (const op of ops) if (op.kind === "add") this.sql.exec(`INSERT INTO views (id, view, data, createdAt, updatedAt, version)
77
- VALUES (?, ?, ?, ?, ?, ?)
78
- ON CONFLICT(id) DO NOTHING`, op.id, op.view.name, JSON.stringify(op.value), timestamp, timestamp, 1);
79
- else if (op.kind === "update") this.sql.exec(`UPDATE views
80
- SET data = json_patch(data, ?), updatedAt = ?, version = version + 1
81
- WHERE id = ? AND view = ?`, JSON.stringify(op.value), timestamp, op.id, op.view.name);
82
- else if (op.kind === "remove") {
83
- this.sql.exec(`DELETE FROM views WHERE id = ? AND view = ?`, op.id, op.view.name);
84
- this.sql.exec(`DELETE FROM relations
85
- WHERE (parent = ? AND pid = ?) OR (child = ? AND cid = ?)`, op.view.name, op.id, op.view.name, op.id);
86
- } else if (op.kind === "link") this.sql.exec(`INSERT OR IGNORE INTO relations (parent, pid, child, cid)
87
- VALUES (?, ?, ?, ?)`, op.parent.view.name, op.parent.id, op.child.view.name, op.child.id);
88
- else if (op.kind === "unlink") this.sql.exec(`DELETE FROM relations
89
- WHERE parent = ? AND pid = ? AND child = ? AND cid = ?`, op.parent.view.name, op.parent.id, op.child.view.name, op.child.id);
90
- this.sql.exec("COMMIT");
91
- } catch (err) {
92
- this.sql.exec("ROLLBACK");
93
- throw err;
94
- }
95
- this.send(ws, {
96
- type: "committed",
97
- requestId,
98
- ops
99
- });
100
- const touchedViews = new Set(ops.map((op) => op.kind === "link" || op.kind === "unlink" ? op.parent.view.name : op.view.name));
101
- for (const [otherWs, session] of this.sessions) {
102
- if (otherWs === ws) continue;
103
- if (session.views.some((v) => touchedViews.has(v))) this.send(otherWs, {
104
- type: "push",
105
- ops
106
- });
107
- }
108
- for (const otherWs of this.state.getWebSockets()) {
109
- if (otherWs === ws) continue;
110
- if (!this.sessions.has(otherWs)) this.send(otherWs, {
111
- type: "push",
112
- ops
113
- });
114
- }
115
- } catch (err) {
116
- this.send(ws, {
117
- type: "rejected",
118
- requestId,
119
- reason: err instanceof Error ? err.message : "Unknown error"
120
- });
121
- }
122
- }
123
- send(ws, msg) {
124
- try {
125
- ws.send(JSON.stringify(msg));
126
- } catch {}
127
- }
128
- };
129
-
130
- //#endregion
131
- export { SyncObject };