syncorejs 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{core/src/cli.d.ts → _vendor/cli/app.d.mts} +4 -2
- package/dist/_vendor/cli/app.d.mts.map +1 -0
- package/dist/_vendor/cli/app.mjs +997 -0
- package/dist/_vendor/cli/app.mjs.map +1 -0
- package/dist/_vendor/cli/context.mjs +180 -0
- package/dist/_vendor/cli/context.mjs.map +1 -0
- package/dist/_vendor/cli/dev-session.mjs +49 -0
- package/dist/_vendor/cli/dev-session.mjs.map +1 -0
- package/dist/_vendor/cli/doctor.mjs +80 -0
- package/dist/_vendor/cli/doctor.mjs.map +1 -0
- package/dist/_vendor/cli/errors.mjs +22 -0
- package/dist/_vendor/cli/errors.mjs.map +1 -0
- package/dist/_vendor/cli/help.mjs +26 -0
- package/dist/_vendor/cli/help.mjs.map +1 -0
- package/dist/_vendor/cli/index.d.mts +2 -0
- package/dist/_vendor/cli/index.mjs +23 -0
- package/dist/_vendor/cli/index.mjs.map +1 -0
- package/dist/_vendor/cli/messages.mjs +32 -0
- package/dist/_vendor/cli/messages.mjs.map +1 -0
- package/dist/_vendor/cli/preflight.mjs +35 -0
- package/dist/_vendor/cli/preflight.mjs.map +1 -0
- package/dist/_vendor/cli/project.mjs +583 -0
- package/dist/_vendor/cli/project.mjs.map +1 -0
- package/dist/_vendor/cli/render.mjs +133 -0
- package/dist/_vendor/cli/render.mjs.map +1 -0
- package/dist/_vendor/cli/targets.mjs +87 -0
- package/dist/_vendor/cli/targets.mjs.map +1 -0
- package/dist/_vendor/core/cli.d.mts +59 -1
- package/dist/_vendor/core/cli.d.mts.map +1 -1
- package/dist/_vendor/core/cli.mjs +528 -75
- package/dist/_vendor/core/cli.mjs.map +1 -1
- package/dist/_vendor/core/index.d.mts +12 -4
- package/dist/_vendor/core/index.d.mts.map +1 -0
- package/dist/_vendor/core/index.mjs +4 -3
- package/dist/_vendor/core/index.mjs.map +1 -1
- package/dist/_vendor/core/runtime/devtools.d.mts +32 -6
- package/dist/_vendor/core/runtime/devtools.d.mts.map +1 -1
- package/dist/_vendor/core/runtime/devtools.mjs +397 -182
- package/dist/_vendor/core/runtime/devtools.mjs.map +1 -1
- package/dist/_vendor/core/runtime/functions.mjs.map +1 -1
- package/dist/_vendor/core/runtime/runtime.d.mts +89 -7
- package/dist/_vendor/core/runtime/runtime.d.mts.map +1 -1
- package/dist/_vendor/core/runtime/runtime.mjs +303 -32
- package/dist/_vendor/core/runtime/runtime.mjs.map +1 -1
- package/dist/_vendor/devtools-protocol/index.d.ts +189 -82
- package/dist/_vendor/devtools-protocol/index.d.ts.map +1 -1
- package/dist/_vendor/devtools-protocol/index.js +39 -0
- package/dist/_vendor/devtools-protocol/index.js.map +1 -0
- package/dist/_vendor/next/config.d.ts.map +1 -1
- package/dist/_vendor/next/config.js +2 -5
- package/dist/_vendor/next/config.js.map +1 -1
- package/dist/_vendor/platform-expo/index.d.ts +15 -5
- package/dist/_vendor/platform-expo/index.d.ts.map +1 -1
- package/dist/_vendor/platform-expo/index.js +33 -3
- package/dist/_vendor/platform-expo/index.js.map +1 -1
- package/dist/_vendor/platform-expo/react.js.map +1 -1
- package/dist/_vendor/platform-node/index.d.mts +10 -5
- package/dist/_vendor/platform-node/index.d.mts.map +1 -1
- package/dist/_vendor/platform-node/index.mjs +145 -35
- package/dist/_vendor/platform-node/index.mjs.map +1 -1
- package/dist/_vendor/platform-node/ipc-react.mjs.map +1 -1
- package/dist/_vendor/platform-web/external-change.d.ts +39 -0
- package/dist/_vendor/platform-web/external-change.d.ts.map +1 -0
- package/dist/_vendor/platform-web/external-change.js +61 -0
- package/dist/_vendor/platform-web/external-change.js.map +1 -0
- package/dist/_vendor/platform-web/index.d.ts +27 -5
- package/dist/_vendor/platform-web/index.d.ts.map +1 -1
- package/dist/_vendor/platform-web/index.js +310 -44
- package/dist/_vendor/platform-web/index.js.map +1 -1
- package/dist/_vendor/platform-web/indexeddb.js.map +1 -1
- package/dist/_vendor/platform-web/opfs.js.map +1 -1
- package/dist/_vendor/platform-web/persistence.js.map +1 -1
- package/dist/_vendor/platform-web/react.js.map +1 -1
- package/dist/_vendor/platform-web/sqljs.js +22 -2
- package/dist/_vendor/platform-web/sqljs.js.map +1 -1
- package/dist/_vendor/schema/definition.js.map +1 -1
- package/dist/_vendor/schema/planner.js.map +1 -1
- package/dist/_vendor/schema/validators.js.map +1 -1
- package/dist/browser-react.d.ts +1 -1
- package/dist/browser-react.js +1 -1
- package/dist/browser.d.ts +6 -7
- package/dist/browser.d.ts.map +1 -1
- package/dist/browser.js +4 -5
- package/dist/browser.js.map +1 -1
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +12 -3
- package/dist/cli.js.map +1 -1
- package/dist/expo-react.d.ts +1 -1
- package/dist/expo-react.js +1 -1
- package/dist/expo.d.ts +1 -2
- package/dist/expo.js +1 -2
- package/dist/index.d.ts +3 -7
- package/dist/index.js +3 -8
- package/dist/next-config.d.ts +1 -2
- package/dist/next-config.js +1 -2
- package/dist/next.d.ts +1 -3
- package/dist/next.js +1 -3
- package/dist/node-ipc-react.d.ts +1 -1
- package/dist/node-ipc-react.js +1 -1
- package/dist/node-ipc.d.ts +1 -2
- package/dist/node-ipc.js +1 -2
- package/dist/node.d.ts +1 -4
- package/dist/node.js +1 -3
- package/dist/react.d.ts +1 -2
- package/dist/react.js +1 -2
- package/dist/svelte.d.ts +1 -2
- package/dist/svelte.js +1 -2
- package/package.json +6 -3
- package/dist/core/src/cli.d.ts.map +0 -1
- package/dist/core/src/cli.js +0 -1196
- package/dist/core/src/cli.js.map +0 -1
- package/dist/core/src/index.js +0 -7
- package/dist/core/src/runtime/devtools.d.ts +0 -7
- package/dist/core/src/runtime/devtools.d.ts.map +0 -1
- package/dist/core/src/runtime/devtools.js +0 -300
- package/dist/core/src/runtime/devtools.js.map +0 -1
- package/dist/core/src/runtime/functions.d.ts +0 -123
- package/dist/core/src/runtime/functions.d.ts.map +0 -1
- package/dist/core/src/runtime/functions.js +0 -71
- package/dist/core/src/runtime/functions.js.map +0 -1
- package/dist/core/src/runtime/id.d.ts +0 -13
- package/dist/core/src/runtime/id.d.ts.map +0 -1
- package/dist/core/src/runtime/id.js +0 -28
- package/dist/core/src/runtime/id.js.map +0 -1
- package/dist/core/src/runtime/runtime.d.ts +0 -371
- package/dist/core/src/runtime/runtime.d.ts.map +0 -1
- package/dist/core/src/runtime/runtime.js +0 -1143
- package/dist/core/src/runtime/runtime.js.map +0 -1
- package/dist/devtools-protocol/src/index.d.ts +0 -201
- package/dist/devtools-protocol/src/index.d.ts.map +0 -1
- package/dist/next/src/config.d.ts +0 -17
- package/dist/next/src/config.d.ts.map +0 -1
- package/dist/next/src/config.js +0 -73
- package/dist/next/src/config.js.map +0 -1
- package/dist/next/src/index.d.ts +0 -80
- package/dist/next/src/index.d.ts.map +0 -1
- package/dist/next/src/index.js +0 -82
- package/dist/next/src/index.js.map +0 -1
- package/dist/platform-expo/src/index.d.ts +0 -96
- package/dist/platform-expo/src/index.d.ts.map +0 -1
- package/dist/platform-expo/src/index.js +0 -198
- package/dist/platform-expo/src/index.js.map +0 -1
- package/dist/platform-expo/src/react.d.ts +0 -26
- package/dist/platform-expo/src/react.d.ts.map +0 -1
- package/dist/platform-expo/src/react.js +0 -30
- package/dist/platform-expo/src/react.js.map +0 -1
- package/dist/platform-node/src/index.d.ts +0 -145
- package/dist/platform-node/src/index.d.ts.map +0 -1
- package/dist/platform-node/src/index.js +0 -407
- package/dist/platform-node/src/index.js.map +0 -1
- package/dist/platform-node/src/ipc-react.d.ts +0 -25
- package/dist/platform-node/src/ipc-react.d.ts.map +0 -1
- package/dist/platform-node/src/ipc-react.js +0 -21
- package/dist/platform-node/src/ipc-react.js.map +0 -1
- package/dist/platform-node/src/ipc.d.ts +0 -76
- package/dist/platform-node/src/ipc.d.ts.map +0 -1
- package/dist/platform-node/src/ipc.js +0 -344
- package/dist/platform-node/src/ipc.js.map +0 -1
- package/dist/platform-web/src/index.d.ts +0 -106
- package/dist/platform-web/src/index.d.ts.map +0 -1
- package/dist/platform-web/src/index.js +0 -311
- package/dist/platform-web/src/index.js.map +0 -1
- package/dist/platform-web/src/indexeddb.js +0 -125
- package/dist/platform-web/src/indexeddb.js.map +0 -1
- package/dist/platform-web/src/opfs.js +0 -146
- package/dist/platform-web/src/opfs.js.map +0 -1
- package/dist/platform-web/src/persistence.d.ts +0 -20
- package/dist/platform-web/src/persistence.d.ts.map +0 -1
- package/dist/platform-web/src/persistence.js +0 -23
- package/dist/platform-web/src/persistence.js.map +0 -1
- package/dist/platform-web/src/react.d.ts +0 -35
- package/dist/platform-web/src/react.d.ts.map +0 -1
- package/dist/platform-web/src/react.js +0 -42
- package/dist/platform-web/src/react.js.map +0 -1
- package/dist/platform-web/src/sqljs.js +0 -133
- package/dist/platform-web/src/sqljs.js.map +0 -1
- package/dist/platform-web/src/worker.d.ts +0 -79
- package/dist/platform-web/src/worker.d.ts.map +0 -1
- package/dist/platform-web/src/worker.js +0 -308
- package/dist/platform-web/src/worker.js.map +0 -1
- package/dist/react/src/index.d.ts +0 -59
- package/dist/react/src/index.d.ts.map +0 -1
- package/dist/react/src/index.js +0 -151
- package/dist/react/src/index.js.map +0 -1
- package/dist/schema/src/definition.d.ts +0 -98
- package/dist/schema/src/definition.d.ts.map +0 -1
- package/dist/schema/src/definition.js +0 -84
- package/dist/schema/src/definition.js.map +0 -1
- package/dist/schema/src/planner.d.ts +0 -42
- package/dist/schema/src/planner.d.ts.map +0 -1
- package/dist/schema/src/planner.js +0 -131
- package/dist/schema/src/planner.js.map +0 -1
- package/dist/schema/src/validators.d.ts +0 -194
- package/dist/schema/src/validators.d.ts.map +0 -1
- package/dist/schema/src/validators.js +0 -158
- package/dist/schema/src/validators.js.map +0 -1
- package/dist/svelte/src/index.d.ts +0 -44
- package/dist/svelte/src/index.d.ts.map +0 -1
- package/dist/svelte/src/index.js +0 -75
- package/dist/svelte/src/index.js.map +0 -1
|
@@ -1,261 +1,416 @@
|
|
|
1
1
|
import { createFunctionReference } from "./runtime.mjs";
|
|
2
2
|
import { describeValidator } from "../../schema/index.js";
|
|
3
3
|
//#region src/runtime/devtools.ts
|
|
4
|
-
function
|
|
5
|
-
const { driver,
|
|
4
|
+
function createDevtoolsCommandHandler(deps) {
|
|
5
|
+
const { driver, runtime, sql } = deps;
|
|
6
6
|
return async (payload) => {
|
|
7
|
+
await runtime.prepareForDirectAccess();
|
|
7
8
|
switch (payload.kind) {
|
|
8
|
-
case "fn.list": return {
|
|
9
|
-
kind: "fn.list.result",
|
|
10
|
-
functions: Object.entries(functions).filter((entry) => entry[1] !== void 0).map(([name, fn]) => {
|
|
11
|
-
const def = {
|
|
12
|
-
name,
|
|
13
|
-
type: fn.kind,
|
|
14
|
-
file: inferFileFromFunctionName(name)
|
|
15
|
-
};
|
|
16
|
-
const argsDesc = describeValidator(fn.argsValidator);
|
|
17
|
-
if (argsDesc.kind === "object") def.args = argsDesc.shape;
|
|
18
|
-
return def;
|
|
19
|
-
})
|
|
20
|
-
};
|
|
21
9
|
case "fn.run": {
|
|
22
10
|
const start = performance.now();
|
|
23
11
|
try {
|
|
24
12
|
let result;
|
|
25
13
|
switch (payload.functionType) {
|
|
26
|
-
case "query":
|
|
27
|
-
|
|
28
|
-
result = await runtime.runQuery(ref, payload.args);
|
|
14
|
+
case "query":
|
|
15
|
+
result = await runtime.runQuery(createFunctionReference("query", payload.functionName), payload.args, { origin: "dashboard" });
|
|
29
16
|
break;
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
const ref = createFunctionReference("mutation", payload.functionName);
|
|
33
|
-
result = await runtime.runMutation(ref, payload.args);
|
|
17
|
+
case "mutation":
|
|
18
|
+
result = await runtime.runMutation(createFunctionReference("mutation", payload.functionName), payload.args, { origin: "dashboard" });
|
|
34
19
|
break;
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
const ref = createFunctionReference("action", payload.functionName);
|
|
38
|
-
result = await runtime.runAction(ref, payload.args);
|
|
20
|
+
case "action":
|
|
21
|
+
result = await runtime.runAction(createFunctionReference("action", payload.functionName), payload.args, { origin: "dashboard" });
|
|
39
22
|
break;
|
|
40
|
-
}
|
|
41
23
|
}
|
|
42
24
|
return {
|
|
43
25
|
kind: "fn.run.result",
|
|
44
26
|
result,
|
|
45
27
|
durationMs: performance.now() - start
|
|
46
28
|
};
|
|
47
|
-
} catch (
|
|
29
|
+
} catch (error) {
|
|
48
30
|
return {
|
|
49
31
|
kind: "fn.run.result",
|
|
50
|
-
error:
|
|
32
|
+
error: error instanceof Error ? error.message : String(error),
|
|
51
33
|
durationMs: performance.now() - start
|
|
52
34
|
};
|
|
53
35
|
}
|
|
54
36
|
}
|
|
55
|
-
case "schema.get": {
|
|
56
|
-
const tableNames = schema.tableNames();
|
|
57
|
-
return {
|
|
58
|
-
kind: "schema.result",
|
|
59
|
-
tables: await Promise.all(tableNames.map(async (name) => {
|
|
60
|
-
const table = schema.getTable(name);
|
|
61
|
-
const validatorDesc = describeValidator(table.validator);
|
|
62
|
-
const fields = validatorDesc.kind === "object" ? Object.entries(validatorDesc.shape).map(([fieldName, fieldDesc]) => {
|
|
63
|
-
const desc = fieldDesc;
|
|
64
|
-
const optional = desc.kind === "optional";
|
|
65
|
-
return {
|
|
66
|
-
name: fieldName,
|
|
67
|
-
type: optional ? desc.inner?.kind ?? "any" : desc.kind,
|
|
68
|
-
optional
|
|
69
|
-
};
|
|
70
|
-
}) : [];
|
|
71
|
-
fields.unshift({
|
|
72
|
-
name: "_id",
|
|
73
|
-
type: "string",
|
|
74
|
-
optional: false
|
|
75
|
-
}, {
|
|
76
|
-
name: "_creationTime",
|
|
77
|
-
type: "number",
|
|
78
|
-
optional: false
|
|
79
|
-
});
|
|
80
|
-
let documentCount = 0;
|
|
81
|
-
try {
|
|
82
|
-
const countRow = await driver.get(`SELECT COUNT(*) as count FROM "${name}"`);
|
|
83
|
-
if (countRow) documentCount = countRow.count;
|
|
84
|
-
} catch {}
|
|
85
|
-
return {
|
|
86
|
-
name,
|
|
87
|
-
fields,
|
|
88
|
-
indexes: table.indexes.map((idx) => ({
|
|
89
|
-
name: idx.name,
|
|
90
|
-
fields: idx.fields,
|
|
91
|
-
unique: false
|
|
92
|
-
})),
|
|
93
|
-
documentCount
|
|
94
|
-
};
|
|
95
|
-
}))
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
|
-
case "data.query": try {
|
|
99
|
-
let sql = `SELECT _id, _creationTime, _json FROM "${payload.table}"`;
|
|
100
|
-
const params = [];
|
|
101
|
-
if (payload.filters && payload.filters.length > 0) {
|
|
102
|
-
const conditions = payload.filters.map((filter) => {
|
|
103
|
-
const op = filterOperatorToSql(filter.operator);
|
|
104
|
-
params.push(normalizeFilterValue(filter));
|
|
105
|
-
return `json_extract(_json, '$.${filter.field}') ${op} ?`;
|
|
106
|
-
});
|
|
107
|
-
sql += ` WHERE ${conditions.join(" AND ")}`;
|
|
108
|
-
}
|
|
109
|
-
sql += " ORDER BY _creationTime DESC";
|
|
110
|
-
if (payload.limit) sql += ` LIMIT ${payload.limit}`;
|
|
111
|
-
return {
|
|
112
|
-
kind: "data.result",
|
|
113
|
-
rows: (await driver.all(sql, params)).map((row) => ({
|
|
114
|
-
_id: row._id,
|
|
115
|
-
_creationTime: row._creationTime,
|
|
116
|
-
...JSON.parse(row._json)
|
|
117
|
-
})),
|
|
118
|
-
totalCount: (await driver.get(`SELECT COUNT(*) as count FROM "${payload.table}"`))?.count ?? 0
|
|
119
|
-
};
|
|
120
|
-
} catch (err) {
|
|
121
|
-
return {
|
|
122
|
-
kind: "error",
|
|
123
|
-
message: err instanceof Error ? err.message : String(err)
|
|
124
|
-
};
|
|
125
|
-
}
|
|
126
37
|
case "data.insert": try {
|
|
127
|
-
const id = generateId();
|
|
128
|
-
const now = Date.now();
|
|
129
|
-
await driver.run(`INSERT INTO "${payload.table}" (_id, _creationTime, _json) VALUES (?, ?, ?)`, [
|
|
130
|
-
id,
|
|
131
|
-
now,
|
|
132
|
-
JSON.stringify(payload.document)
|
|
133
|
-
]);
|
|
134
38
|
return {
|
|
135
39
|
kind: "data.mutate.result",
|
|
136
40
|
success: true,
|
|
137
|
-
id
|
|
41
|
+
id: await runDevtoolsMutation(runtime, async (ctx) => ctx.db.insert(payload.table, payload.document), { origin: "dashboard" })
|
|
138
42
|
};
|
|
139
|
-
} catch (
|
|
43
|
+
} catch (error) {
|
|
140
44
|
return {
|
|
141
45
|
kind: "data.mutate.result",
|
|
142
46
|
success: false,
|
|
143
|
-
error:
|
|
47
|
+
error: error instanceof Error ? error.message : String(error)
|
|
144
48
|
};
|
|
145
49
|
}
|
|
146
50
|
case "data.patch": try {
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
error: `Document ${payload.id} not found`
|
|
152
|
-
};
|
|
153
|
-
const doc = {
|
|
154
|
-
...JSON.parse(existing._json),
|
|
155
|
-
...payload.fields
|
|
156
|
-
};
|
|
157
|
-
await driver.run(`UPDATE "${payload.table}" SET _json = ? WHERE _id = ?`, [JSON.stringify(doc), payload.id]);
|
|
51
|
+
await runDevtoolsMutation(runtime, async (ctx) => {
|
|
52
|
+
await ctx.db.patch(payload.table, payload.id, payload.fields);
|
|
53
|
+
return null;
|
|
54
|
+
}, { origin: "dashboard" });
|
|
158
55
|
return {
|
|
159
56
|
kind: "data.mutate.result",
|
|
160
57
|
success: true,
|
|
161
58
|
id: payload.id
|
|
162
59
|
};
|
|
163
|
-
} catch (
|
|
60
|
+
} catch (error) {
|
|
164
61
|
return {
|
|
165
62
|
kind: "data.mutate.result",
|
|
166
63
|
success: false,
|
|
167
|
-
error:
|
|
64
|
+
error: error instanceof Error ? error.message : String(error)
|
|
168
65
|
};
|
|
169
66
|
}
|
|
170
67
|
case "data.delete": try {
|
|
171
|
-
await
|
|
68
|
+
await runDevtoolsMutation(runtime, async (ctx) => {
|
|
69
|
+
await ctx.db.delete(payload.table, payload.id);
|
|
70
|
+
return null;
|
|
71
|
+
}, { origin: "dashboard" });
|
|
172
72
|
return {
|
|
173
73
|
kind: "data.mutate.result",
|
|
174
74
|
success: true
|
|
175
75
|
};
|
|
176
|
-
} catch (
|
|
76
|
+
} catch (error) {
|
|
177
77
|
return {
|
|
178
78
|
kind: "data.mutate.result",
|
|
179
79
|
success: false,
|
|
180
|
-
error:
|
|
80
|
+
error: error instanceof Error ? error.message : String(error)
|
|
181
81
|
};
|
|
182
82
|
}
|
|
183
|
-
case "sql.
|
|
184
|
-
const
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
return {
|
|
189
|
-
kind: "sql.result",
|
|
190
|
-
columns,
|
|
191
|
-
rows: rows.map((row) => columns.map((col) => row[col])),
|
|
192
|
-
rowsAffected: 0
|
|
193
|
-
};
|
|
194
|
-
}
|
|
83
|
+
case "sql.read": try {
|
|
84
|
+
const sqlSupport = requireDevtoolsSqlSupport(sql);
|
|
85
|
+
const databasePath = runtime.getDriverDatabasePath();
|
|
86
|
+
if (!databasePath) throw new Error("SQL Read requires a file-backed database path.");
|
|
87
|
+
const { columns, rows } = sqlSupport.runReadonlyQuery(databasePath, payload.query);
|
|
195
88
|
return {
|
|
196
|
-
kind: "sql.result",
|
|
197
|
-
columns
|
|
198
|
-
rows
|
|
199
|
-
rowsAffected: (await driver.run(payload.query)).changes
|
|
89
|
+
kind: "sql.read.result",
|
|
90
|
+
columns,
|
|
91
|
+
rows
|
|
200
92
|
};
|
|
201
|
-
} catch (
|
|
93
|
+
} catch (error) {
|
|
202
94
|
return {
|
|
203
|
-
kind: "sql.result",
|
|
95
|
+
kind: "sql.read.result",
|
|
204
96
|
columns: [],
|
|
205
97
|
rows: [],
|
|
206
|
-
|
|
207
|
-
error: err instanceof Error ? err.message : String(err)
|
|
98
|
+
error: error instanceof Error ? error.message : String(error)
|
|
208
99
|
};
|
|
209
100
|
}
|
|
210
|
-
case "
|
|
101
|
+
case "sql.write": try {
|
|
102
|
+
const analysis = requireDevtoolsSqlSupport(sql).analyzeSqlStatement(payload.query);
|
|
103
|
+
if (analysis.mode === "read") throw new Error("Use SQL Read or SQL Live for read-only statements.");
|
|
104
|
+
const result = await driver.run(payload.query);
|
|
105
|
+
runtime.notifyDevtoolsScopes(analysis.observedScopes);
|
|
106
|
+
await runtime.forceRefreshDevtools("SQL write executed from devtools dashboard.", { origin: "dashboard" });
|
|
211
107
|
return {
|
|
212
|
-
kind: "
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
id: row.id,
|
|
216
|
-
functionName: row.function_name,
|
|
217
|
-
args: JSON.parse(row.args_json),
|
|
218
|
-
scheduledAt: row.created_at,
|
|
219
|
-
runAt: row.run_at,
|
|
220
|
-
status: mapJobStatus(row.status)
|
|
221
|
-
};
|
|
222
|
-
if (row.schedule_json) try {
|
|
223
|
-
const schedule = JSON.parse(row.schedule_json);
|
|
224
|
-
if (schedule.cron) job.cronSchedule = schedule.cron;
|
|
225
|
-
} catch {}
|
|
226
|
-
if (row.status === "completed" || row.status === "failed") job.completedAt = row.updated_at;
|
|
227
|
-
return job;
|
|
228
|
-
})
|
|
108
|
+
kind: "sql.write.result",
|
|
109
|
+
rowsAffected: result.changes,
|
|
110
|
+
invalidationScopes: [...analysis.observedScopes]
|
|
229
111
|
};
|
|
230
|
-
} catch {
|
|
112
|
+
} catch (error) {
|
|
231
113
|
return {
|
|
232
|
-
kind: "
|
|
233
|
-
|
|
114
|
+
kind: "sql.write.result",
|
|
115
|
+
rowsAffected: 0,
|
|
116
|
+
invalidationScopes: [],
|
|
117
|
+
error: error instanceof Error ? error.message : String(error)
|
|
234
118
|
};
|
|
235
119
|
}
|
|
236
120
|
case "scheduler.cancel": try {
|
|
237
|
-
await driver.run(`UPDATE "_scheduled_functions" SET status = 'cancelled', updated_at = ? WHERE id = ? AND status = 'scheduled'`, [Date.now(), payload.jobId]);
|
|
238
121
|
return {
|
|
239
122
|
kind: "scheduler.cancel.result",
|
|
240
|
-
success: true
|
|
123
|
+
success: true,
|
|
124
|
+
cancelled: await runtime.cancelScheduledJob(payload.jobId)
|
|
241
125
|
};
|
|
242
|
-
} catch (
|
|
126
|
+
} catch (error) {
|
|
243
127
|
return {
|
|
244
128
|
kind: "scheduler.cancel.result",
|
|
245
129
|
success: false,
|
|
246
|
-
|
|
130
|
+
cancelled: false,
|
|
131
|
+
error: error instanceof Error ? error.message : String(error)
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
case "scheduler.update": try {
|
|
135
|
+
const updated = await runtime.updateScheduledJob({
|
|
136
|
+
id: payload.jobId,
|
|
137
|
+
schedule: payload.schedule,
|
|
138
|
+
args: payload.args,
|
|
139
|
+
misfirePolicy: payload.misfirePolicy,
|
|
140
|
+
...payload.runAt !== void 0 ? { runAt: payload.runAt } : {}
|
|
141
|
+
});
|
|
142
|
+
const updatedJob = (updated ? await listSchedulerJobs(driver) : []).find((job) => job.id === payload.jobId);
|
|
143
|
+
return {
|
|
144
|
+
kind: "scheduler.update.result",
|
|
145
|
+
success: true,
|
|
146
|
+
updated,
|
|
147
|
+
...updated && updatedJob ? { job: updatedJob } : {}
|
|
148
|
+
};
|
|
149
|
+
} catch (error) {
|
|
150
|
+
return {
|
|
151
|
+
kind: "scheduler.update.result",
|
|
152
|
+
success: false,
|
|
153
|
+
updated: false,
|
|
154
|
+
error: error instanceof Error ? error.message : String(error)
|
|
247
155
|
};
|
|
248
156
|
}
|
|
249
157
|
default: return {
|
|
250
158
|
kind: "error",
|
|
251
|
-
message: `Unknown
|
|
159
|
+
message: `Unknown devtools command: ${payload.kind}`
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
function createDevtoolsSubscriptionHost(deps) {
|
|
165
|
+
const { driver, schema, functions, runtime } = deps;
|
|
166
|
+
const subscriptions = /* @__PURE__ */ new Map();
|
|
167
|
+
const emit = async (payload, listener) => {
|
|
168
|
+
listener(await resolveSubscriptionPayload(payload, {
|
|
169
|
+
driver,
|
|
170
|
+
schema,
|
|
171
|
+
functions,
|
|
172
|
+
runtime,
|
|
173
|
+
...deps.sql ? { sql: deps.sql } : {}
|
|
174
|
+
}));
|
|
175
|
+
};
|
|
176
|
+
const handleInvalidation = async (scopes) => {
|
|
177
|
+
for (const record of subscriptions.values()) {
|
|
178
|
+
if (!intersects(scopes, record.scopes)) continue;
|
|
179
|
+
await emit(record.payload, record.listener);
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
|
+
return {
|
|
183
|
+
async subscribe(subscriptionId, payload, listener) {
|
|
184
|
+
if (payload.kind === "fn.watch") {
|
|
185
|
+
const definition = functions[payload.functionName];
|
|
186
|
+
if (!definition || definition.kind !== "query") {
|
|
187
|
+
listener({
|
|
188
|
+
kind: "fn.watch.result",
|
|
189
|
+
error: `Unknown query function: ${payload.functionName}`
|
|
190
|
+
});
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
const watch = runtime.createClient().watchQuery(createFunctionReference("query", payload.functionName), payload.args);
|
|
194
|
+
const emitWatchResult = () => {
|
|
195
|
+
const error = watch.localQueryError();
|
|
196
|
+
listener({
|
|
197
|
+
kind: "fn.watch.result",
|
|
198
|
+
...error ? { error: error.message } : { result: watch.localQueryResult() }
|
|
199
|
+
});
|
|
200
|
+
};
|
|
201
|
+
const unsubscribeUpdates = watch.onUpdate(emitWatchResult);
|
|
202
|
+
subscriptions.set(subscriptionId, {
|
|
203
|
+
payload,
|
|
204
|
+
listener,
|
|
205
|
+
unsubscribeRuntime: () => {
|
|
206
|
+
unsubscribeUpdates();
|
|
207
|
+
watch.dispose?.();
|
|
208
|
+
},
|
|
209
|
+
scopes: new Set(["all"])
|
|
210
|
+
});
|
|
211
|
+
emitWatchResult();
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
const unsubscribeRuntime = runtime.subscribeToDevtoolsInvalidations((scopes) => {
|
|
215
|
+
handleInvalidation(scopes);
|
|
216
|
+
});
|
|
217
|
+
const unsubscribeEvents = runtime.subscribeToDevtoolsEvents((event) => {
|
|
218
|
+
if (event.type === "runtime.disconnected") emit(payload, listener);
|
|
219
|
+
});
|
|
220
|
+
subscriptions.set(subscriptionId, {
|
|
221
|
+
payload,
|
|
222
|
+
listener,
|
|
223
|
+
unsubscribeRuntime: () => {
|
|
224
|
+
unsubscribeRuntime();
|
|
225
|
+
unsubscribeEvents();
|
|
226
|
+
},
|
|
227
|
+
scopes: scopesForSubscription(payload, deps.sql)
|
|
228
|
+
});
|
|
229
|
+
await emit(payload, listener);
|
|
230
|
+
},
|
|
231
|
+
unsubscribe(subscriptionId) {
|
|
232
|
+
const record = subscriptions.get(subscriptionId);
|
|
233
|
+
if (!record) return;
|
|
234
|
+
record.unsubscribeRuntime();
|
|
235
|
+
subscriptions.delete(subscriptionId);
|
|
236
|
+
},
|
|
237
|
+
dispose() {
|
|
238
|
+
for (const [subscriptionId, record] of subscriptions) {
|
|
239
|
+
record.unsubscribeRuntime();
|
|
240
|
+
subscriptions.delete(subscriptionId);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
async function resolveSubscriptionPayload(payload, deps) {
|
|
246
|
+
const { driver, schema, functions, runtime } = deps;
|
|
247
|
+
await runtime.prepareForDirectAccess();
|
|
248
|
+
switch (payload.kind) {
|
|
249
|
+
case "runtime.summary": return {
|
|
250
|
+
kind: "runtime.summary.result",
|
|
251
|
+
summary: runtime.getRuntimeSummary()
|
|
252
|
+
};
|
|
253
|
+
case "runtime.activeQueries": return {
|
|
254
|
+
kind: "runtime.activeQueries.result",
|
|
255
|
+
activeQueries: runtime.getActiveQueryInfos()
|
|
256
|
+
};
|
|
257
|
+
case "fn.watch": throw new Error("Function watches are pushed incrementally and have no snapshot payload.");
|
|
258
|
+
case "schema.tables": {
|
|
259
|
+
const tables = await getSchemaTables(driver, schema);
|
|
260
|
+
console.debug("[devtools] schema.tables", {
|
|
261
|
+
runtimeId: runtime.getRuntimeId(),
|
|
262
|
+
tables: tables.map((table) => ({
|
|
263
|
+
name: table.name,
|
|
264
|
+
documentCount: table.documentCount
|
|
265
|
+
}))
|
|
266
|
+
});
|
|
267
|
+
return {
|
|
268
|
+
kind: "schema.tables.result",
|
|
269
|
+
tables
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
case "data.table": {
|
|
273
|
+
const result = await queryTable(driver, payload.table, payload.filters, payload.limit);
|
|
274
|
+
console.debug("[devtools] data.table", {
|
|
275
|
+
runtimeId: runtime.getRuntimeId(),
|
|
276
|
+
table: payload.table,
|
|
277
|
+
filters: payload.filters ?? [],
|
|
278
|
+
limit: payload.limit,
|
|
279
|
+
totalCount: result.totalCount,
|
|
280
|
+
rowCount: result.rows.length,
|
|
281
|
+
firstRow: result.rows[0] ?? null
|
|
282
|
+
});
|
|
283
|
+
return {
|
|
284
|
+
kind: "data.table.result",
|
|
285
|
+
rows: result.rows,
|
|
286
|
+
totalCount: result.totalCount,
|
|
287
|
+
...result.cursor ? { cursor: result.cursor } : {}
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
case "scheduler.jobs": return {
|
|
291
|
+
kind: "scheduler.jobs.result",
|
|
292
|
+
jobs: await listSchedulerJobs(driver)
|
|
293
|
+
};
|
|
294
|
+
case "functions.catalog": return {
|
|
295
|
+
kind: "functions.catalog.result",
|
|
296
|
+
functions: listFunctions(functions)
|
|
297
|
+
};
|
|
298
|
+
case "sql.watch": {
|
|
299
|
+
const sqlSupport = requireDevtoolsSqlSupport(deps.sql);
|
|
300
|
+
const databasePath = runtime.getDriverDatabasePath();
|
|
301
|
+
if (!databasePath) throw new Error("SQL Live requires a file-backed database path.");
|
|
302
|
+
const { columns, rows, observedTables } = sqlSupport.runReadonlyQuery(databasePath, payload.query);
|
|
303
|
+
return {
|
|
304
|
+
kind: "sql.watch.result",
|
|
305
|
+
columns,
|
|
306
|
+
rows,
|
|
307
|
+
observedTables
|
|
252
308
|
};
|
|
253
309
|
}
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
async function queryTable(driver, table, filters, limit) {
|
|
313
|
+
let sql = `SELECT _id, _creationTime, _json FROM "${table}"`;
|
|
314
|
+
const params = [];
|
|
315
|
+
if (filters && filters.length > 0) sql += ` WHERE ${filters.map((filter) => {
|
|
316
|
+
params.push(normalizeFilterValue(filter));
|
|
317
|
+
return `json_extract(_json, '$.${filter.field}') ${filterOperatorToSql(filter.operator)} ?`;
|
|
318
|
+
}).join(" AND ")}`;
|
|
319
|
+
sql += " ORDER BY _creationTime DESC";
|
|
320
|
+
if (limit) sql += ` LIMIT ${limit}`;
|
|
321
|
+
return {
|
|
322
|
+
rows: (await driver.all(sql, params)).map((row) => ({
|
|
323
|
+
_id: row._id,
|
|
324
|
+
_creationTime: row._creationTime,
|
|
325
|
+
...JSON.parse(row._json)
|
|
326
|
+
})),
|
|
327
|
+
totalCount: (await driver.get(`SELECT COUNT(*) as count FROM "${table}"`))?.count ?? 0
|
|
254
328
|
};
|
|
255
329
|
}
|
|
330
|
+
async function getSchemaTables(driver, schema) {
|
|
331
|
+
return Promise.all(schema.tableNames().map(async (name) => {
|
|
332
|
+
const table = schema.getTable(name);
|
|
333
|
+
const validatorDesc = describeValidator(table.validator);
|
|
334
|
+
const fields = validatorDesc.kind === "object" ? Object.entries(validatorDesc.shape).map(([fieldName, fieldDesc]) => {
|
|
335
|
+
const desc = fieldDesc;
|
|
336
|
+
const optional = desc.kind === "optional";
|
|
337
|
+
return {
|
|
338
|
+
name: fieldName,
|
|
339
|
+
type: optional ? desc.inner?.kind ?? "any" : desc.kind,
|
|
340
|
+
optional
|
|
341
|
+
};
|
|
342
|
+
}) : [];
|
|
343
|
+
fields.unshift({
|
|
344
|
+
name: "_id",
|
|
345
|
+
type: "string",
|
|
346
|
+
optional: false
|
|
347
|
+
}, {
|
|
348
|
+
name: "_creationTime",
|
|
349
|
+
type: "number",
|
|
350
|
+
optional: false
|
|
351
|
+
});
|
|
352
|
+
let documentCount = 0;
|
|
353
|
+
try {
|
|
354
|
+
documentCount = (await driver.get(`SELECT COUNT(*) as count FROM "${name}"`))?.count ?? 0;
|
|
355
|
+
} catch {
|
|
356
|
+
documentCount = 0;
|
|
357
|
+
}
|
|
358
|
+
return {
|
|
359
|
+
name,
|
|
360
|
+
fields,
|
|
361
|
+
indexes: table.indexes.map((index) => ({
|
|
362
|
+
name: index.name,
|
|
363
|
+
fields: index.fields,
|
|
364
|
+
unique: false
|
|
365
|
+
})),
|
|
366
|
+
documentCount
|
|
367
|
+
};
|
|
368
|
+
}));
|
|
369
|
+
}
|
|
370
|
+
async function listSchedulerJobs(driver) {
|
|
371
|
+
try {
|
|
372
|
+
return (await driver.all(`SELECT * FROM "_scheduled_functions" ORDER BY run_at DESC LIMIT 200`)).map((row) => {
|
|
373
|
+
const schedule = safeReadSchedule(row.schedule_json);
|
|
374
|
+
const scheduleLabel = schedule ? formatScheduleLabel(schedule) : void 0;
|
|
375
|
+
return {
|
|
376
|
+
id: row.id,
|
|
377
|
+
functionName: row.function_name,
|
|
378
|
+
args: JSON.parse(row.args_json),
|
|
379
|
+
scheduledAt: row.created_at,
|
|
380
|
+
runAt: row.run_at,
|
|
381
|
+
status: mapJobStatus(row.status),
|
|
382
|
+
...row.status === "completed" || row.status === "failed" ? { completedAt: row.updated_at } : {},
|
|
383
|
+
...row.recurring_name ? { recurringName: row.recurring_name } : {},
|
|
384
|
+
...schedule ? { schedule } : {},
|
|
385
|
+
...scheduleLabel ? {
|
|
386
|
+
scheduleLabel,
|
|
387
|
+
cronSchedule: scheduleLabel
|
|
388
|
+
} : {},
|
|
389
|
+
...row.timezone ? { timezone: row.timezone } : {},
|
|
390
|
+
...row.last_run_at !== null ? { lastRunAt: row.last_run_at } : {},
|
|
391
|
+
...row.updated_at ? { updatedAt: row.updated_at } : {},
|
|
392
|
+
misfirePolicy: readMisfirePolicy(row.misfire_policy, row.window_ms)
|
|
393
|
+
};
|
|
394
|
+
});
|
|
395
|
+
} catch {
|
|
396
|
+
return [];
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
function listFunctions(functions) {
|
|
400
|
+
return Object.entries(functions).filter((entry) => entry[1] !== void 0).map(([name, fn]) => {
|
|
401
|
+
const descriptor = {
|
|
402
|
+
name,
|
|
403
|
+
type: fn.kind,
|
|
404
|
+
file: inferFileFromFunctionName(name)
|
|
405
|
+
};
|
|
406
|
+
const argsDesc = describeValidator(fn.argsValidator);
|
|
407
|
+
if (argsDesc.kind === "object") descriptor.args = argsDesc.shape;
|
|
408
|
+
return descriptor;
|
|
409
|
+
});
|
|
410
|
+
}
|
|
256
411
|
function inferFileFromFunctionName(name) {
|
|
257
412
|
const parts = name.split(":");
|
|
258
|
-
if (parts.length > 1) return parts[0]
|
|
413
|
+
if (parts.length > 1) return `${parts[0]}.ts`;
|
|
259
414
|
return "unknown";
|
|
260
415
|
}
|
|
261
416
|
function normalizeFilterValue(filter) {
|
|
@@ -265,15 +420,15 @@ function normalizeFilterValue(filter) {
|
|
|
265
420
|
default: return filter.value;
|
|
266
421
|
}
|
|
267
422
|
}
|
|
268
|
-
function filterOperatorToSql(
|
|
269
|
-
switch (
|
|
423
|
+
function filterOperatorToSql(operator) {
|
|
424
|
+
switch (operator) {
|
|
270
425
|
case "eq": return "=";
|
|
271
426
|
case "neq": return "!=";
|
|
272
427
|
case "gt": return ">";
|
|
273
428
|
case "gte": return ">=";
|
|
274
429
|
case "lt": return "<";
|
|
275
430
|
case "lte": return "<=";
|
|
276
|
-
case "contains":
|
|
431
|
+
case "contains":
|
|
277
432
|
case "startsWith": return "LIKE";
|
|
278
433
|
default: return "=";
|
|
279
434
|
}
|
|
@@ -288,13 +443,73 @@ function mapJobStatus(status) {
|
|
|
288
443
|
default: return "pending";
|
|
289
444
|
}
|
|
290
445
|
}
|
|
291
|
-
function
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
446
|
+
function safeReadSchedule(scheduleJson) {
|
|
447
|
+
if (!scheduleJson) return;
|
|
448
|
+
try {
|
|
449
|
+
return JSON.parse(scheduleJson);
|
|
450
|
+
} catch {
|
|
451
|
+
return;
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
function formatScheduleLabel(schedule) {
|
|
455
|
+
switch (schedule.type) {
|
|
456
|
+
case "interval": {
|
|
457
|
+
const parts = [];
|
|
458
|
+
if (schedule.hours) parts.push(`${schedule.hours}h`);
|
|
459
|
+
if (schedule.minutes) parts.push(`${schedule.minutes}m`);
|
|
460
|
+
if (schedule.seconds) parts.push(`${schedule.seconds}s`);
|
|
461
|
+
return parts.length > 0 ? `Every ${parts.join(" ")}` : "Recurring";
|
|
462
|
+
}
|
|
463
|
+
case "daily": return `Daily ${padNumber(schedule.hour)}:${padNumber(schedule.minute)}${schedule.timezone ? ` ${schedule.timezone}` : ""}`;
|
|
464
|
+
case "weekly": return `Weekly ${capitalize(schedule.dayOfWeek)} ${padNumber(schedule.hour)}:${padNumber(schedule.minute)}${schedule.timezone ? ` ${schedule.timezone}` : ""}`;
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
function readMisfirePolicy(type, windowMs) {
|
|
468
|
+
if (type === "windowed") return {
|
|
469
|
+
type,
|
|
470
|
+
windowMs: windowMs ?? 0
|
|
471
|
+
};
|
|
472
|
+
if (type === "skip" || type === "run_once_if_missed") return { type };
|
|
473
|
+
return { type: "catch_up" };
|
|
474
|
+
}
|
|
475
|
+
function padNumber(value) {
|
|
476
|
+
return String(value).padStart(2, "0");
|
|
477
|
+
}
|
|
478
|
+
function capitalize(value) {
|
|
479
|
+
return value.slice(0, 1).toUpperCase() + value.slice(1);
|
|
480
|
+
}
|
|
481
|
+
async function runDevtoolsMutation(runtime, callback, meta) {
|
|
482
|
+
return runtime.runDevtoolsMutation(callback, meta);
|
|
483
|
+
}
|
|
484
|
+
function scopesForSubscription(payload, sql) {
|
|
485
|
+
switch (payload.kind) {
|
|
486
|
+
case "runtime.summary": return new Set(["runtime.summary"]);
|
|
487
|
+
case "runtime.activeQueries": return new Set(["runtime.activeQueries"]);
|
|
488
|
+
case "fn.watch": return new Set(["all"]);
|
|
489
|
+
case "schema.tables": return new Set(["schema.tables"]);
|
|
490
|
+
case "data.table": return new Set([`table:${payload.table}`]);
|
|
491
|
+
case "scheduler.jobs": return new Set(["scheduler.jobs"]);
|
|
492
|
+
case "functions.catalog": return new Set(["all"]);
|
|
493
|
+
case "sql.watch": try {
|
|
494
|
+
const sqlSupport = requireDevtoolsSqlSupport(sql);
|
|
495
|
+
const analysis = sqlSupport.analyzeSqlStatement(payload.query);
|
|
496
|
+
sqlSupport.ensureSqlMode(analysis, "watch");
|
|
497
|
+
return new Set(analysis.observedScopes);
|
|
498
|
+
} catch {
|
|
499
|
+
return new Set(["all"]);
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
function intersects(a, b) {
|
|
504
|
+
if (a.has("all") || b.has("all")) return true;
|
|
505
|
+
for (const value of a) if (b.has(value)) return true;
|
|
506
|
+
return false;
|
|
507
|
+
}
|
|
508
|
+
function requireDevtoolsSqlSupport(sql) {
|
|
509
|
+
if (!sql) throw new Error("SQL devtools are only available in Node-hosted runtimes.");
|
|
510
|
+
return sql;
|
|
296
511
|
}
|
|
297
512
|
//#endregion
|
|
298
|
-
export {
|
|
513
|
+
export { createDevtoolsCommandHandler, createDevtoolsSubscriptionHost };
|
|
299
514
|
|
|
300
515
|
//# sourceMappingURL=devtools.mjs.map
|