syncorejs 0.2.0 → 0.2.2
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/README.md +2 -1
- package/dist/_vendor/cli/app.d.mts.map +1 -1
- package/dist/_vendor/cli/app.mjs +323 -42
- package/dist/_vendor/cli/app.mjs.map +1 -1
- package/dist/_vendor/cli/context.mjs +27 -9
- package/dist/_vendor/cli/context.mjs.map +1 -1
- package/dist/_vendor/cli/doctor.mjs +513 -46
- package/dist/_vendor/cli/doctor.mjs.map +1 -1
- package/dist/_vendor/cli/messages.mjs +5 -4
- package/dist/_vendor/cli/messages.mjs.map +1 -1
- package/dist/_vendor/cli/project.mjs +110 -12
- package/dist/_vendor/cli/project.mjs.map +1 -1
- package/dist/_vendor/cli/render.mjs +57 -9
- package/dist/_vendor/cli/render.mjs.map +1 -1
- package/dist/_vendor/cli/targets.mjs +4 -3
- package/dist/_vendor/cli/targets.mjs.map +1 -1
- package/dist/_vendor/core/cli.d.mts +13 -3
- package/dist/_vendor/core/cli.d.mts.map +1 -1
- package/dist/_vendor/core/cli.mjs +242 -91
- package/dist/_vendor/core/cli.mjs.map +1 -1
- package/dist/_vendor/core/devtools-auth.mjs +60 -0
- package/dist/_vendor/core/devtools-auth.mjs.map +1 -0
- package/dist/_vendor/core/index.d.mts +5 -3
- package/dist/_vendor/core/index.mjs +22 -2
- package/dist/_vendor/core/index.mjs.map +1 -1
- package/dist/_vendor/core/runtime/components.d.mts +111 -0
- package/dist/_vendor/core/runtime/components.d.mts.map +1 -0
- package/dist/_vendor/core/runtime/components.mjs +186 -0
- package/dist/_vendor/core/runtime/components.mjs.map +1 -0
- package/dist/_vendor/core/runtime/devtools.d.mts +4 -4
- package/dist/_vendor/core/runtime/devtools.d.mts.map +1 -1
- package/dist/_vendor/core/runtime/devtools.mjs +52 -41
- package/dist/_vendor/core/runtime/devtools.mjs.map +1 -1
- package/dist/_vendor/core/runtime/functions.d.mts +10 -10
- package/dist/_vendor/core/runtime/functions.d.mts.map +1 -1
- package/dist/_vendor/core/runtime/functions.mjs +2 -2
- package/dist/_vendor/core/runtime/functions.mjs.map +1 -1
- package/dist/_vendor/core/runtime/internal/engines/devtoolsEngine.mjs +77 -0
- package/dist/_vendor/core/runtime/internal/engines/devtoolsEngine.mjs.map +1 -0
- package/dist/_vendor/core/runtime/internal/engines/executionEngine.mjs +617 -0
- package/dist/_vendor/core/runtime/internal/engines/executionEngine.mjs.map +1 -0
- package/dist/_vendor/core/runtime/internal/engines/reactivityEngine.mjs +186 -0
- package/dist/_vendor/core/runtime/internal/engines/reactivityEngine.mjs.map +1 -0
- package/dist/_vendor/core/runtime/internal/engines/schedulerEngine.mjs +220 -0
- package/dist/_vendor/core/runtime/internal/engines/schedulerEngine.mjs.map +1 -0
- package/dist/_vendor/core/runtime/internal/engines/schemaEngine.mjs +203 -0
- package/dist/_vendor/core/runtime/internal/engines/schemaEngine.mjs.map +1 -0
- package/dist/_vendor/core/runtime/internal/engines/shared.mjs +177 -0
- package/dist/_vendor/core/runtime/internal/engines/shared.mjs.map +1 -0
- package/dist/_vendor/core/runtime/internal/engines/storageEngine.mjs +144 -0
- package/dist/_vendor/core/runtime/internal/engines/storageEngine.mjs.map +1 -0
- package/dist/_vendor/core/runtime/internal/runtimeKernel.mjs +220 -0
- package/dist/_vendor/core/runtime/internal/runtimeKernel.mjs.map +1 -0
- package/dist/_vendor/core/runtime/internal/runtimeStatus.mjs +32 -0
- package/dist/_vendor/core/runtime/internal/runtimeStatus.mjs.map +1 -0
- package/dist/_vendor/core/runtime/internal/systemMeta.mjs +61 -0
- package/dist/_vendor/core/runtime/internal/systemMeta.mjs.map +1 -0
- package/dist/_vendor/core/runtime/internal/transactionCoordinator.mjs +37 -0
- package/dist/_vendor/core/runtime/internal/transactionCoordinator.mjs.map +1 -0
- package/dist/_vendor/core/runtime/runtime.d.mts +159 -205
- package/dist/_vendor/core/runtime/runtime.d.mts.map +1 -1
- package/dist/_vendor/core/runtime/runtime.mjs +16 -1371
- package/dist/_vendor/core/runtime/runtime.mjs.map +1 -1
- package/dist/_vendor/core/transport.d.mts +111 -0
- package/dist/_vendor/core/transport.d.mts.map +1 -0
- package/dist/_vendor/core/transport.mjs +419 -0
- package/dist/_vendor/core/transport.mjs.map +1 -0
- package/dist/_vendor/devtools-protocol/index.d.ts +39 -1
- package/dist/_vendor/devtools-protocol/index.d.ts.map +1 -1
- package/dist/_vendor/devtools-protocol/index.js +25 -9
- package/dist/_vendor/devtools-protocol/index.js.map +1 -1
- package/dist/_vendor/next/index.d.ts +1 -1
- package/dist/_vendor/next/index.d.ts.map +1 -1
- package/dist/_vendor/next/index.js +31 -13
- package/dist/_vendor/next/index.js.map +1 -1
- package/dist/_vendor/platform-expo/index.d.ts +12 -12
- package/dist/_vendor/platform-expo/index.d.ts.map +1 -1
- package/dist/_vendor/platform-expo/index.js +4 -2
- package/dist/_vendor/platform-expo/index.js.map +1 -1
- package/dist/_vendor/platform-expo/react.d.ts.map +1 -1
- package/dist/_vendor/platform-expo/react.js +11 -10
- package/dist/_vendor/platform-expo/react.js.map +1 -1
- package/dist/_vendor/platform-node/index.d.mts +23 -19
- package/dist/_vendor/platform-node/index.d.mts.map +1 -1
- package/dist/_vendor/platform-node/index.mjs +13 -5
- package/dist/_vendor/platform-node/index.mjs.map +1 -1
- package/dist/_vendor/platform-node/ipc-react.d.mts.map +1 -1
- package/dist/_vendor/platform-node/ipc-react.mjs +15 -2
- package/dist/_vendor/platform-node/ipc-react.mjs.map +1 -1
- package/dist/_vendor/platform-node/ipc.d.mts +11 -35
- package/dist/_vendor/platform-node/ipc.d.mts.map +1 -1
- package/dist/_vendor/platform-node/ipc.mjs +3 -273
- package/dist/_vendor/platform-node/ipc.mjs.map +1 -1
- package/dist/_vendor/platform-web/external-change.d.ts +2 -1
- package/dist/_vendor/platform-web/external-change.d.ts.map +1 -1
- package/dist/_vendor/platform-web/external-change.js +2 -1
- package/dist/_vendor/platform-web/external-change.js.map +1 -1
- package/dist/_vendor/platform-web/index.d.ts +21 -21
- package/dist/_vendor/platform-web/index.d.ts.map +1 -1
- package/dist/_vendor/platform-web/index.js +44 -7
- package/dist/_vendor/platform-web/index.js.map +1 -1
- package/dist/_vendor/platform-web/react.d.ts.map +1 -1
- package/dist/_vendor/platform-web/react.js +29 -13
- package/dist/_vendor/platform-web/react.js.map +1 -1
- package/dist/_vendor/platform-web/worker.d.ts +11 -35
- package/dist/_vendor/platform-web/worker.d.ts.map +1 -1
- package/dist/_vendor/platform-web/worker.js +3 -267
- package/dist/_vendor/platform-web/worker.js.map +1 -1
- package/dist/_vendor/react/index.d.ts +36 -20
- package/dist/_vendor/react/index.d.ts.map +1 -1
- package/dist/_vendor/react/index.js +279 -57
- package/dist/_vendor/react/index.js.map +1 -1
- package/dist/_vendor/schema/definition.d.ts +48 -63
- package/dist/_vendor/schema/definition.d.ts.map +1 -1
- package/dist/_vendor/schema/definition.js +22 -39
- package/dist/_vendor/schema/definition.js.map +1 -1
- package/dist/_vendor/schema/index.d.ts +4 -4
- package/dist/_vendor/schema/index.js +2 -2
- package/dist/_vendor/schema/planner.d.ts +19 -2
- package/dist/_vendor/schema/planner.d.ts.map +1 -1
- package/dist/_vendor/schema/planner.js +79 -3
- package/dist/_vendor/schema/planner.js.map +1 -1
- package/dist/_vendor/schema/validators.d.ts +141 -121
- package/dist/_vendor/schema/validators.d.ts.map +1 -1
- package/dist/_vendor/schema/validators.js +300 -42
- package/dist/_vendor/schema/validators.js.map +1 -1
- package/dist/_vendor/svelte/index.d.ts +47 -19
- package/dist/_vendor/svelte/index.d.ts.map +1 -1
- package/dist/_vendor/svelte/index.js +250 -20
- package/dist/_vendor/svelte/index.js.map +1 -1
- package/dist/components.d.ts +2 -0
- package/dist/components.js +2 -0
- package/dist/index.d.ts +3 -2
- package/dist/index.js +2 -1
- package/package.json +8 -3
|
@@ -0,0 +1,617 @@
|
|
|
1
|
+
import { toCanonicalComponentFunctionName } from "../../components.mjs";
|
|
2
|
+
import { generateId } from "../../id.mjs";
|
|
3
|
+
import { fieldExpression, normalizeOptionalArgs, omitSystemFields, quoteIdentifier, resolveSearchIndexTableName, splitSchedulerArgs, stableStringify } from "./shared.mjs";
|
|
4
|
+
import { createEmptyExecutionResult } from "../transactionCoordinator.mjs";
|
|
5
|
+
//#region src/runtime/internal/engines/executionEngine.ts
|
|
6
|
+
const DEFAULT_MISFIRE_POLICY = { type: "catch_up" };
|
|
7
|
+
var RuntimeFilterBuilder = class {
|
|
8
|
+
eq(field, value) {
|
|
9
|
+
return {
|
|
10
|
+
type: "condition",
|
|
11
|
+
condition: {
|
|
12
|
+
field,
|
|
13
|
+
operator: "=",
|
|
14
|
+
value
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
gt(field, value) {
|
|
19
|
+
return {
|
|
20
|
+
type: "condition",
|
|
21
|
+
condition: {
|
|
22
|
+
field,
|
|
23
|
+
operator: ">",
|
|
24
|
+
value
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
gte(field, value) {
|
|
29
|
+
return {
|
|
30
|
+
type: "condition",
|
|
31
|
+
condition: {
|
|
32
|
+
field,
|
|
33
|
+
operator: ">=",
|
|
34
|
+
value
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
lt(field, value) {
|
|
39
|
+
return {
|
|
40
|
+
type: "condition",
|
|
41
|
+
condition: {
|
|
42
|
+
field,
|
|
43
|
+
operator: "<",
|
|
44
|
+
value
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
lte(field, value) {
|
|
49
|
+
return {
|
|
50
|
+
type: "condition",
|
|
51
|
+
condition: {
|
|
52
|
+
field,
|
|
53
|
+
operator: "<=",
|
|
54
|
+
value
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
and(...expressions) {
|
|
59
|
+
return {
|
|
60
|
+
type: "and",
|
|
61
|
+
expressions
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
or(...expressions) {
|
|
65
|
+
return {
|
|
66
|
+
type: "or",
|
|
67
|
+
expressions
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
var RuntimeIndexRangeBuilder = class {
|
|
72
|
+
conditions = [];
|
|
73
|
+
eq(field, value) {
|
|
74
|
+
this.conditions.push({
|
|
75
|
+
field,
|
|
76
|
+
operator: "=",
|
|
77
|
+
value
|
|
78
|
+
});
|
|
79
|
+
return this;
|
|
80
|
+
}
|
|
81
|
+
gt(field, value) {
|
|
82
|
+
this.conditions.push({
|
|
83
|
+
field,
|
|
84
|
+
operator: ">",
|
|
85
|
+
value
|
|
86
|
+
});
|
|
87
|
+
return this;
|
|
88
|
+
}
|
|
89
|
+
gte(field, value) {
|
|
90
|
+
this.conditions.push({
|
|
91
|
+
field,
|
|
92
|
+
operator: ">=",
|
|
93
|
+
value
|
|
94
|
+
});
|
|
95
|
+
return this;
|
|
96
|
+
}
|
|
97
|
+
lt(field, value) {
|
|
98
|
+
this.conditions.push({
|
|
99
|
+
field,
|
|
100
|
+
operator: "<",
|
|
101
|
+
value
|
|
102
|
+
});
|
|
103
|
+
return this;
|
|
104
|
+
}
|
|
105
|
+
lte(field, value) {
|
|
106
|
+
this.conditions.push({
|
|
107
|
+
field,
|
|
108
|
+
operator: "<=",
|
|
109
|
+
value
|
|
110
|
+
});
|
|
111
|
+
return this;
|
|
112
|
+
}
|
|
113
|
+
build() {
|
|
114
|
+
return [...this.conditions];
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
var RuntimeSearchIndexBuilder = class {
|
|
118
|
+
searchField;
|
|
119
|
+
searchText;
|
|
120
|
+
filters = [];
|
|
121
|
+
search(field, value) {
|
|
122
|
+
this.searchField = field;
|
|
123
|
+
this.searchText = value;
|
|
124
|
+
return this;
|
|
125
|
+
}
|
|
126
|
+
eq(field, value) {
|
|
127
|
+
this.filters.push({
|
|
128
|
+
field,
|
|
129
|
+
operator: "=",
|
|
130
|
+
value
|
|
131
|
+
});
|
|
132
|
+
return this;
|
|
133
|
+
}
|
|
134
|
+
build() {
|
|
135
|
+
if (!this.searchField || !this.searchText) throw new Error("Search queries require a search field and search text.");
|
|
136
|
+
return {
|
|
137
|
+
searchField: this.searchField,
|
|
138
|
+
searchText: this.searchText,
|
|
139
|
+
filters: [...this.filters]
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
var RuntimeQueryBuilder = class {
|
|
144
|
+
orderDirection = "asc";
|
|
145
|
+
source = { type: "table" };
|
|
146
|
+
filterExpression;
|
|
147
|
+
constructor(executeQuery, tableName, dependencyCollector) {
|
|
148
|
+
this.executeQuery = executeQuery;
|
|
149
|
+
this.tableName = tableName;
|
|
150
|
+
this.dependencyCollector = dependencyCollector;
|
|
151
|
+
}
|
|
152
|
+
withIndex(indexName, builder) {
|
|
153
|
+
this.source = {
|
|
154
|
+
type: "index",
|
|
155
|
+
name: indexName,
|
|
156
|
+
range: builder?.(new RuntimeIndexRangeBuilder()).build() ?? []
|
|
157
|
+
};
|
|
158
|
+
return this;
|
|
159
|
+
}
|
|
160
|
+
withSearchIndex(indexName, builder) {
|
|
161
|
+
this.source = {
|
|
162
|
+
type: "search",
|
|
163
|
+
name: indexName,
|
|
164
|
+
query: builder(new RuntimeSearchIndexBuilder()).build()
|
|
165
|
+
};
|
|
166
|
+
return this;
|
|
167
|
+
}
|
|
168
|
+
order(order) {
|
|
169
|
+
this.orderDirection = order;
|
|
170
|
+
return this;
|
|
171
|
+
}
|
|
172
|
+
filter(builder) {
|
|
173
|
+
this.filterExpression = builder(new RuntimeFilterBuilder());
|
|
174
|
+
return this;
|
|
175
|
+
}
|
|
176
|
+
async collect() {
|
|
177
|
+
return this.execute();
|
|
178
|
+
}
|
|
179
|
+
async take(count) {
|
|
180
|
+
return this.execute({ limit: count });
|
|
181
|
+
}
|
|
182
|
+
async first() {
|
|
183
|
+
return (await this.execute({ limit: 1 }))[0] ?? null;
|
|
184
|
+
}
|
|
185
|
+
async unique() {
|
|
186
|
+
const results = await this.execute({ limit: 2 });
|
|
187
|
+
if (results.length > 1) throw new Error("Expected a unique result but found multiple rows.");
|
|
188
|
+
return results[0] ?? null;
|
|
189
|
+
}
|
|
190
|
+
async paginate(options) {
|
|
191
|
+
const offset = options.cursor ? Number.parseInt(options.cursor, 10) : 0;
|
|
192
|
+
const page = await this.execute({
|
|
193
|
+
limit: options.numItems,
|
|
194
|
+
offset
|
|
195
|
+
});
|
|
196
|
+
const nextCursor = page.length < options.numItems ? null : String(offset + page.length);
|
|
197
|
+
return {
|
|
198
|
+
page,
|
|
199
|
+
cursor: nextCursor,
|
|
200
|
+
isDone: nextCursor === null
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
async execute(options) {
|
|
204
|
+
this.dependencyCollector?.add(`table:${this.tableName}`);
|
|
205
|
+
const queryOptions = {
|
|
206
|
+
tableName: this.tableName,
|
|
207
|
+
source: this.source,
|
|
208
|
+
filterExpression: this.filterExpression,
|
|
209
|
+
orderDirection: this.orderDirection
|
|
210
|
+
};
|
|
211
|
+
if (this.dependencyCollector) queryOptions.dependencyCollector = this.dependencyCollector;
|
|
212
|
+
if (options?.limit !== void 0) queryOptions.limit = options.limit;
|
|
213
|
+
if (options?.offset !== void 0) queryOptions.offset = options.offset;
|
|
214
|
+
return this.executeQuery(queryOptions);
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
var ExecutionEngine = class {
|
|
218
|
+
constructor(deps) {
|
|
219
|
+
this.deps = deps;
|
|
220
|
+
}
|
|
221
|
+
createClient() {
|
|
222
|
+
return {
|
|
223
|
+
query: (reference, ...args) => this.runQuery(reference, normalizeOptionalArgs(args)),
|
|
224
|
+
mutation: (reference, ...args) => this.runMutation(reference, normalizeOptionalArgs(args)),
|
|
225
|
+
action: (reference, ...args) => this.runAction(reference, normalizeOptionalArgs(args)),
|
|
226
|
+
watchQuery: (reference, ...args) => this.watchQuery(reference, normalizeOptionalArgs(args)),
|
|
227
|
+
watchRuntimeStatus: () => this.deps.runtimeStatus.watch()
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
watchQuery(reference, args = {}) {
|
|
231
|
+
return this.deps.reactivity.watchQuery(reference, args);
|
|
232
|
+
}
|
|
233
|
+
async runQuery(reference, args = {}, meta = {}) {
|
|
234
|
+
const definition = this.resolveFunction(reference, "query");
|
|
235
|
+
const dependencyCollector = /* @__PURE__ */ new Set();
|
|
236
|
+
const startedAt = Date.now();
|
|
237
|
+
const result = await this.invokeFunction(definition, args, {
|
|
238
|
+
mutationDepth: 0,
|
|
239
|
+
changedTables: /* @__PURE__ */ new Set(),
|
|
240
|
+
storageChanges: [],
|
|
241
|
+
dependencyCollector,
|
|
242
|
+
componentMetadata: definition.__syncoreComponent
|
|
243
|
+
});
|
|
244
|
+
this.deps.devtools.emit({
|
|
245
|
+
type: "query.executed",
|
|
246
|
+
runtimeId: this.deps.runtimeId,
|
|
247
|
+
queryId: reference.name,
|
|
248
|
+
functionName: reference.name,
|
|
249
|
+
...definition.__syncoreComponent ? {
|
|
250
|
+
componentPath: definition.__syncoreComponent.componentPath,
|
|
251
|
+
componentName: definition.__syncoreComponent.componentName
|
|
252
|
+
} : {},
|
|
253
|
+
dependencies: [...dependencyCollector],
|
|
254
|
+
durationMs: Date.now() - startedAt,
|
|
255
|
+
timestamp: Date.now(),
|
|
256
|
+
...meta.origin ? { origin: meta.origin } : {}
|
|
257
|
+
});
|
|
258
|
+
return result;
|
|
259
|
+
}
|
|
260
|
+
async runMutation(reference, args = {}, meta = {}) {
|
|
261
|
+
const definition = this.resolveFunction(reference, "mutation");
|
|
262
|
+
const mutationId = generateId();
|
|
263
|
+
const startedAt = Date.now();
|
|
264
|
+
const execution = await this.deps.transactionCoordinator.runInTransaction(async (transactionState) => this.invokeFunction(definition, args, {
|
|
265
|
+
mutationDepth: 1,
|
|
266
|
+
changedTables: transactionState.changedTables,
|
|
267
|
+
storageChanges: transactionState.storageChanges,
|
|
268
|
+
componentMetadata: definition.__syncoreComponent
|
|
269
|
+
}));
|
|
270
|
+
await this.finalizeStatefulExecution(mutationId, execution, Date.now() - startedAt);
|
|
271
|
+
this.deps.devtools.emit({
|
|
272
|
+
type: "mutation.committed",
|
|
273
|
+
runtimeId: this.deps.runtimeId,
|
|
274
|
+
mutationId,
|
|
275
|
+
functionName: reference.name,
|
|
276
|
+
...definition.__syncoreComponent ? {
|
|
277
|
+
componentPath: definition.__syncoreComponent.componentPath,
|
|
278
|
+
componentName: definition.__syncoreComponent.componentName
|
|
279
|
+
} : {},
|
|
280
|
+
changedTables: [...execution.changedTables],
|
|
281
|
+
durationMs: Date.now() - startedAt,
|
|
282
|
+
timestamp: Date.now(),
|
|
283
|
+
...meta.origin ? { origin: meta.origin } : {}
|
|
284
|
+
});
|
|
285
|
+
return execution.result;
|
|
286
|
+
}
|
|
287
|
+
async runAction(reference, args = {}, meta = {}) {
|
|
288
|
+
const definition = this.resolveFunction(reference, "action");
|
|
289
|
+
const actionId = generateId();
|
|
290
|
+
const startedAt = Date.now();
|
|
291
|
+
const state = this.deps.transactionCoordinator.createState();
|
|
292
|
+
try {
|
|
293
|
+
const result = await this.invokeFunction(definition, args, {
|
|
294
|
+
mutationDepth: 0,
|
|
295
|
+
changedTables: state.changedTables,
|
|
296
|
+
storageChanges: state.storageChanges,
|
|
297
|
+
componentMetadata: definition.__syncoreComponent
|
|
298
|
+
});
|
|
299
|
+
await this.finalizeStatefulExecution(actionId, createEmptyExecutionResult(result, state), Date.now() - startedAt);
|
|
300
|
+
this.deps.devtools.emit({
|
|
301
|
+
type: "action.completed",
|
|
302
|
+
runtimeId: this.deps.runtimeId,
|
|
303
|
+
actionId,
|
|
304
|
+
functionName: reference.name,
|
|
305
|
+
...definition.__syncoreComponent ? {
|
|
306
|
+
componentPath: definition.__syncoreComponent.componentPath,
|
|
307
|
+
componentName: definition.__syncoreComponent.componentName
|
|
308
|
+
} : {},
|
|
309
|
+
durationMs: Date.now() - startedAt,
|
|
310
|
+
timestamp: Date.now(),
|
|
311
|
+
...meta.origin ? { origin: meta.origin } : {}
|
|
312
|
+
});
|
|
313
|
+
return result;
|
|
314
|
+
} catch (error) {
|
|
315
|
+
this.deps.devtools.emit({
|
|
316
|
+
type: "action.completed",
|
|
317
|
+
runtimeId: this.deps.runtimeId,
|
|
318
|
+
actionId,
|
|
319
|
+
functionName: reference.name,
|
|
320
|
+
...definition.__syncoreComponent ? {
|
|
321
|
+
componentPath: definition.__syncoreComponent.componentPath,
|
|
322
|
+
componentName: definition.__syncoreComponent.componentName
|
|
323
|
+
} : {},
|
|
324
|
+
durationMs: Date.now() - startedAt,
|
|
325
|
+
timestamp: Date.now(),
|
|
326
|
+
...meta.origin ? { origin: meta.origin } : {},
|
|
327
|
+
error: error instanceof Error ? error.message : String(error)
|
|
328
|
+
});
|
|
329
|
+
throw error;
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
async runDevtoolsMutation(callback, meta = {}) {
|
|
333
|
+
const mutationId = generateId();
|
|
334
|
+
const startedAt = Date.now();
|
|
335
|
+
const execution = await this.deps.transactionCoordinator.runInTransaction(async (transactionState) => callback({ db: this.createDatabaseWriter({
|
|
336
|
+
mutationDepth: 1,
|
|
337
|
+
changedTables: transactionState.changedTables,
|
|
338
|
+
storageChanges: transactionState.storageChanges
|
|
339
|
+
}) }));
|
|
340
|
+
await this.finalizeStatefulExecution(mutationId, execution, Date.now() - startedAt);
|
|
341
|
+
this.deps.devtools.emit({
|
|
342
|
+
type: "mutation.committed",
|
|
343
|
+
runtimeId: this.deps.runtimeId,
|
|
344
|
+
mutationId,
|
|
345
|
+
functionName: "__devtools__/mutation",
|
|
346
|
+
changedTables: [...execution.changedTables],
|
|
347
|
+
durationMs: Date.now() - startedAt,
|
|
348
|
+
timestamp: Date.now(),
|
|
349
|
+
...meta.origin ? { origin: meta.origin } : {}
|
|
350
|
+
});
|
|
351
|
+
return execution.result;
|
|
352
|
+
}
|
|
353
|
+
async finalizeStatefulExecution(executionId, execution, durationMs) {
|
|
354
|
+
const changedScopes = collectChangedScopes(execution.changedTables, execution.storageChanges);
|
|
355
|
+
if (changedScopes.size > 0) await this.deps.reactivity.refreshQueriesForScopes(changedScopes, `Execution ${executionId} touched ${[...changedScopes].join(", ")}`);
|
|
356
|
+
if (execution.changedTables.size > 0) await this.deps.reactivity.publishExternalChange({
|
|
357
|
+
scope: "database",
|
|
358
|
+
reason: "commit",
|
|
359
|
+
changedScopes: [...changedScopes].filter((scope) => scope.startsWith("table:")),
|
|
360
|
+
changedTables: [...execution.changedTables]
|
|
361
|
+
});
|
|
362
|
+
await this.deps.reactivity.publishStorageChanges(execution.storageChanges);
|
|
363
|
+
}
|
|
364
|
+
async collectQueryDependencies(functionName, args) {
|
|
365
|
+
const definition = this.resolveFunction({
|
|
366
|
+
kind: "query",
|
|
367
|
+
name: functionName
|
|
368
|
+
}, "query");
|
|
369
|
+
const dependencyCollector = /* @__PURE__ */ new Set();
|
|
370
|
+
await this.invokeFunction(definition, args, {
|
|
371
|
+
mutationDepth: 0,
|
|
372
|
+
changedTables: /* @__PURE__ */ new Set(),
|
|
373
|
+
storageChanges: [],
|
|
374
|
+
dependencyCollector,
|
|
375
|
+
componentMetadata: definition.__syncoreComponent
|
|
376
|
+
});
|
|
377
|
+
return dependencyCollector;
|
|
378
|
+
}
|
|
379
|
+
async executeQueryBuilder(options) {
|
|
380
|
+
const table = this.deps.schema.getTableDefinition(options.tableName);
|
|
381
|
+
const params = [];
|
|
382
|
+
const whereClauses = [];
|
|
383
|
+
const orderClauses = [];
|
|
384
|
+
let joinClause = "";
|
|
385
|
+
const source = options.source;
|
|
386
|
+
if (source.type === "index") {
|
|
387
|
+
const index = table.indexes.find((candidate) => candidate.name === source.name);
|
|
388
|
+
if (!index) throw new Error(`Unknown index "${source.name}" on table "${options.tableName}".`);
|
|
389
|
+
for (const condition of source.range) whereClauses.push(this.renderCondition("t", condition, params));
|
|
390
|
+
const primaryField = index.fields[0];
|
|
391
|
+
if (primaryField) orderClauses.push(`${fieldExpression("t", primaryField)} ${options.orderDirection.toUpperCase()}`);
|
|
392
|
+
}
|
|
393
|
+
if (source.type === "search") {
|
|
394
|
+
const searchIndex = table.searchIndexes.find((candidate) => candidate.name === source.name);
|
|
395
|
+
if (!searchIndex) throw new Error(`Unknown search index "${source.name}" on table "${options.tableName}".`);
|
|
396
|
+
if (searchIndex.searchField !== source.query.searchField) throw new Error(`Search index "${searchIndex.name}" expects field "${searchIndex.searchField}".`);
|
|
397
|
+
if (this.deps.schema.isSearchIndexDisabled(options.tableName, searchIndex.name)) {
|
|
398
|
+
whereClauses.push(`${fieldExpression("t", searchIndex.searchField)} LIKE ?`);
|
|
399
|
+
params.push(`%${source.query.searchText}%`);
|
|
400
|
+
} else {
|
|
401
|
+
joinClause = `JOIN ${quoteIdentifier(resolveSearchIndexTableName(options.tableName, searchIndex.name))} s ON s._id = t._id`;
|
|
402
|
+
whereClauses.push(`s.search_value MATCH ?`);
|
|
403
|
+
params.push(source.query.searchText);
|
|
404
|
+
}
|
|
405
|
+
for (const condition of source.query.filters) whereClauses.push(this.renderCondition("t", condition, params));
|
|
406
|
+
}
|
|
407
|
+
if (options.filterExpression) whereClauses.push(this.renderExpression("t", options.filterExpression, params));
|
|
408
|
+
if (orderClauses.length === 0) orderClauses.push(`t._creationTime ${options.orderDirection.toUpperCase()}`);
|
|
409
|
+
orderClauses.push(`t._id ${options.orderDirection.toUpperCase()}`);
|
|
410
|
+
const sql = [
|
|
411
|
+
`SELECT t._id, t._creationTime, t._json FROM ${quoteIdentifier(options.tableName)} t`,
|
|
412
|
+
joinClause,
|
|
413
|
+
whereClauses.length > 0 ? `WHERE ${whereClauses.join(" AND ")}` : "",
|
|
414
|
+
`ORDER BY ${orderClauses.join(", ")}`,
|
|
415
|
+
options.limit !== void 0 ? `LIMIT ${options.limit}` : "",
|
|
416
|
+
options.offset !== void 0 ? `OFFSET ${options.offset}` : ""
|
|
417
|
+
].filter(Boolean).join(" ");
|
|
418
|
+
return (await this.deps.driver.all(sql, params)).map((row) => this.deps.schema.deserializeDocument(options.tableName, row));
|
|
419
|
+
}
|
|
420
|
+
async invokeFunction(definition, rawArgs, state) {
|
|
421
|
+
const args = definition.argsValidator.parse(rawArgs);
|
|
422
|
+
const ctx = this.createContext(definition.kind, {
|
|
423
|
+
...state,
|
|
424
|
+
componentMetadata: definition.__syncoreComponent ?? state.componentMetadata
|
|
425
|
+
});
|
|
426
|
+
const result = await definition.handler(ctx, args);
|
|
427
|
+
if (definition.returnsValidator) return definition.returnsValidator.parse(result);
|
|
428
|
+
return result;
|
|
429
|
+
}
|
|
430
|
+
createContext(kind, state) {
|
|
431
|
+
const db = kind === "mutation" ? this.createDatabaseWriter(state) : this.createDatabaseReader(state);
|
|
432
|
+
const storage = this.deps.storage.createStorageApi(state);
|
|
433
|
+
const scheduler = this.createSchedulerApi(state.componentMetadata);
|
|
434
|
+
const callerMetadata = state.componentMetadata;
|
|
435
|
+
return {
|
|
436
|
+
db,
|
|
437
|
+
storage,
|
|
438
|
+
capabilities: this.deps.capabilities,
|
|
439
|
+
capabilityDescriptors: this.deps.capabilityDescriptors,
|
|
440
|
+
...callerMetadata ? { component: {
|
|
441
|
+
path: callerMetadata.componentPath,
|
|
442
|
+
name: callerMetadata.componentName,
|
|
443
|
+
version: callerMetadata.version,
|
|
444
|
+
capabilities: callerMetadata.grantedCapabilities
|
|
445
|
+
} } : {},
|
|
446
|
+
scheduler,
|
|
447
|
+
runQuery: (reference, ...args) => this.runQuery(this.resolveReferenceForCaller(reference, "query", callerMetadata), normalizeOptionalArgs(args)),
|
|
448
|
+
runMutation: (reference, ...args) => {
|
|
449
|
+
const resolvedReference = this.resolveReferenceForCaller(reference, "mutation", callerMetadata);
|
|
450
|
+
const normalizedArgs = normalizeOptionalArgs(args);
|
|
451
|
+
if (kind === "mutation") return this.deps.driver.withSavepoint(`sp_${generateId().replace(/-/g, "_")}`, () => this.invokeFunction(this.resolveFunction(resolvedReference, "mutation", callerMetadata), normalizedArgs, {
|
|
452
|
+
mutationDepth: state.mutationDepth + 1,
|
|
453
|
+
changedTables: state.changedTables,
|
|
454
|
+
storageChanges: state.storageChanges,
|
|
455
|
+
componentMetadata: callerMetadata
|
|
456
|
+
}));
|
|
457
|
+
return this.runMutation(resolvedReference, normalizedArgs);
|
|
458
|
+
},
|
|
459
|
+
runAction: (reference, ...args) => this.runAction(this.resolveReferenceForCaller(reference, "action", callerMetadata), normalizeOptionalArgs(args))
|
|
460
|
+
};
|
|
461
|
+
}
|
|
462
|
+
createDatabaseReader(state) {
|
|
463
|
+
return {
|
|
464
|
+
get: async (tableName, id) => {
|
|
465
|
+
const scopedTableName = this.resolveTableName(tableName, state.componentMetadata);
|
|
466
|
+
state.dependencyCollector?.add(`table:${scopedTableName}`);
|
|
467
|
+
state.dependencyCollector?.add(`row:${scopedTableName}:${id}`);
|
|
468
|
+
const row = await this.deps.driver.get(`SELECT _id, _creationTime, _json FROM ${quoteIdentifier(scopedTableName)} WHERE _id = ?`, [id]);
|
|
469
|
+
return row ? this.deps.schema.deserializeDocument(scopedTableName, row) : null;
|
|
470
|
+
},
|
|
471
|
+
query: (tableName) => new RuntimeQueryBuilder((options) => this.executeQueryBuilder({
|
|
472
|
+
...options,
|
|
473
|
+
tableName: this.resolveTableName(tableName, state.componentMetadata)
|
|
474
|
+
}), this.resolveTableName(tableName, state.componentMetadata), state.dependencyCollector),
|
|
475
|
+
raw: (sql, params) => this.deps.driver.all(sql, params)
|
|
476
|
+
};
|
|
477
|
+
}
|
|
478
|
+
createDatabaseWriter(state) {
|
|
479
|
+
const reader = this.createDatabaseReader(state);
|
|
480
|
+
return {
|
|
481
|
+
...reader,
|
|
482
|
+
insert: async (tableName, value) => {
|
|
483
|
+
const scopedTableName = this.resolveTableName(tableName, state.componentMetadata);
|
|
484
|
+
const validated = this.deps.schema.validateDocument(scopedTableName, value);
|
|
485
|
+
const id = generateId();
|
|
486
|
+
const creationTime = Date.now();
|
|
487
|
+
const json = stableStringify(validated);
|
|
488
|
+
await this.deps.driver.run(`INSERT INTO ${quoteIdentifier(scopedTableName)} (_id, _creationTime, _json) VALUES (?, ?, ?)`, [
|
|
489
|
+
id,
|
|
490
|
+
creationTime,
|
|
491
|
+
json
|
|
492
|
+
]);
|
|
493
|
+
await this.deps.schema.syncSearchIndexes(scopedTableName, {
|
|
494
|
+
_id: id,
|
|
495
|
+
_creationTime: creationTime,
|
|
496
|
+
_json: json
|
|
497
|
+
});
|
|
498
|
+
state.changedTables.add(scopedTableName);
|
|
499
|
+
return id;
|
|
500
|
+
},
|
|
501
|
+
patch: async (tableName, id, value) => {
|
|
502
|
+
const scopedTableName = this.resolveTableName(tableName, state.componentMetadata);
|
|
503
|
+
const current = await reader.get(tableName, id);
|
|
504
|
+
if (!current) throw new Error(`Document "${id}" does not exist in "${scopedTableName}".`);
|
|
505
|
+
const merged = {
|
|
506
|
+
...omitSystemFields(current),
|
|
507
|
+
...value
|
|
508
|
+
};
|
|
509
|
+
for (const key of Object.keys(merged)) if (merged[key] === void 0) delete merged[key];
|
|
510
|
+
const validated = this.deps.schema.validateDocument(scopedTableName, merged);
|
|
511
|
+
await this.deps.driver.run(`UPDATE ${quoteIdentifier(scopedTableName)} SET _json = ? WHERE _id = ?`, [stableStringify(validated), id]);
|
|
512
|
+
const row = await this.deps.driver.get(`SELECT _id, _creationTime, _json FROM ${quoteIdentifier(scopedTableName)} WHERE _id = ?`, [id]);
|
|
513
|
+
if (row) await this.deps.schema.syncSearchIndexes(scopedTableName, row);
|
|
514
|
+
state.changedTables.add(scopedTableName);
|
|
515
|
+
},
|
|
516
|
+
replace: async (tableName, id, value) => {
|
|
517
|
+
const scopedTableName = this.resolveTableName(tableName, state.componentMetadata);
|
|
518
|
+
const validated = this.deps.schema.validateDocument(scopedTableName, value);
|
|
519
|
+
await this.deps.driver.run(`UPDATE ${quoteIdentifier(scopedTableName)} SET _json = ? WHERE _id = ?`, [stableStringify(validated), id]);
|
|
520
|
+
const row = await this.deps.driver.get(`SELECT _id, _creationTime, _json FROM ${quoteIdentifier(scopedTableName)} WHERE _id = ?`, [id]);
|
|
521
|
+
if (!row) throw new Error(`Document "${id}" does not exist in "${scopedTableName}".`);
|
|
522
|
+
await this.deps.schema.syncSearchIndexes(scopedTableName, row);
|
|
523
|
+
state.changedTables.add(scopedTableName);
|
|
524
|
+
},
|
|
525
|
+
delete: async (tableName, id) => {
|
|
526
|
+
const scopedTableName = this.resolveTableName(tableName, state.componentMetadata);
|
|
527
|
+
await this.deps.driver.run(`DELETE FROM ${quoteIdentifier(scopedTableName)} WHERE _id = ?`, [id]);
|
|
528
|
+
await this.deps.schema.removeSearchIndexes(scopedTableName, id);
|
|
529
|
+
state.changedTables.add(scopedTableName);
|
|
530
|
+
}
|
|
531
|
+
};
|
|
532
|
+
}
|
|
533
|
+
createSchedulerApi(componentMetadata) {
|
|
534
|
+
return {
|
|
535
|
+
runAfter: async (delayMs, reference, ...args) => {
|
|
536
|
+
if (componentMetadata && !componentMetadata.grantedCapabilities.includes("scheduler")) throw new Error(`Component ${JSON.stringify(componentMetadata.componentPath)} does not have scheduler capability.`);
|
|
537
|
+
const schedulerArgs = splitSchedulerArgs(args);
|
|
538
|
+
const functionArgs = schedulerArgs[0];
|
|
539
|
+
const misfirePolicy = schedulerArgs[1] ?? DEFAULT_MISFIRE_POLICY;
|
|
540
|
+
const resolvedReference = this.resolveReferenceForCaller(reference, reference.kind, componentMetadata);
|
|
541
|
+
return this.deps.scheduler.scheduleJob(Date.now() + delayMs, resolvedReference, functionArgs, misfirePolicy, componentMetadata ? `component:${componentMetadata.componentPath}:` : void 0);
|
|
542
|
+
},
|
|
543
|
+
runAt: async (timestamp, reference, ...args) => {
|
|
544
|
+
if (componentMetadata && !componentMetadata.grantedCapabilities.includes("scheduler")) throw new Error(`Component ${JSON.stringify(componentMetadata.componentPath)} does not have scheduler capability.`);
|
|
545
|
+
const schedulerArgs = splitSchedulerArgs(args);
|
|
546
|
+
const functionArgs = schedulerArgs[0];
|
|
547
|
+
const misfirePolicy = schedulerArgs[1] ?? DEFAULT_MISFIRE_POLICY;
|
|
548
|
+
const value = timestamp instanceof Date ? timestamp.getTime() : timestamp;
|
|
549
|
+
const resolvedReference = this.resolveReferenceForCaller(reference, reference.kind, componentMetadata);
|
|
550
|
+
return this.deps.scheduler.scheduleJob(value, resolvedReference, functionArgs, misfirePolicy, componentMetadata ? `component:${componentMetadata.componentPath}:` : void 0);
|
|
551
|
+
},
|
|
552
|
+
cancel: async (id) => {
|
|
553
|
+
await this.deps.scheduler.cancelScheduledJob(id);
|
|
554
|
+
}
|
|
555
|
+
};
|
|
556
|
+
}
|
|
557
|
+
resolveFunction(reference, expectedKind, callerMetadata) {
|
|
558
|
+
const resolvedReference = this.resolveReferenceForCaller(reference, expectedKind, callerMetadata);
|
|
559
|
+
const definition = this.deps.functions[resolvedReference.name];
|
|
560
|
+
if (!definition) throw new Error(`Unknown function "${resolvedReference.name}".`);
|
|
561
|
+
if (definition.kind !== expectedKind) throw new Error(`Function "${resolvedReference.name}" is a ${definition.kind}, expected ${expectedKind}.`);
|
|
562
|
+
const metadata = definition.__syncoreComponent;
|
|
563
|
+
if (metadata?.visibility === "internal") {
|
|
564
|
+
if (!callerMetadata) throw new Error(`Function "${resolvedReference.name}" is internal to component "${metadata.componentPath}".`);
|
|
565
|
+
if (callerMetadata.componentPath !== metadata.componentPath) throw new Error(`Function "${resolvedReference.name}" is internal to component "${metadata.componentPath}" and cannot be called from "${callerMetadata.componentPath}".`);
|
|
566
|
+
}
|
|
567
|
+
return definition;
|
|
568
|
+
}
|
|
569
|
+
renderExpression(tableAlias, expression, params) {
|
|
570
|
+
if (expression.type === "condition") return this.renderCondition(tableAlias, expression.condition, params);
|
|
571
|
+
const separator = expression.type === "and" ? " AND " : " OR ";
|
|
572
|
+
return `(${expression.expressions.map((child) => this.renderExpression(tableAlias, child, params)).join(separator)})`;
|
|
573
|
+
}
|
|
574
|
+
renderCondition(tableAlias, condition, params) {
|
|
575
|
+
params.push(condition.value);
|
|
576
|
+
return `${fieldExpression(tableAlias, condition.field)} ${condition.operator} ?`;
|
|
577
|
+
}
|
|
578
|
+
resolveReferenceForCaller(reference, expectedKind, callerMetadata) {
|
|
579
|
+
if (!callerMetadata) return reference;
|
|
580
|
+
if (reference.name.startsWith("components/")) return reference;
|
|
581
|
+
const bindingMatch = /^binding:([^/]+)\/(.+)$/.exec(reference.name);
|
|
582
|
+
if (bindingMatch) {
|
|
583
|
+
const bindingName = bindingMatch[1];
|
|
584
|
+
const localName = bindingMatch[2];
|
|
585
|
+
const targetComponentPath = callerMetadata.bindings[bindingName];
|
|
586
|
+
if (!targetComponentPath) throw new Error(`Component ${JSON.stringify(callerMetadata.componentPath)} does not define binding ${JSON.stringify(bindingName)}.`);
|
|
587
|
+
return {
|
|
588
|
+
kind: expectedKind,
|
|
589
|
+
name: toCanonicalComponentFunctionName(targetComponentPath, "public", localName)
|
|
590
|
+
};
|
|
591
|
+
}
|
|
592
|
+
const internalName = toCanonicalComponentFunctionName(callerMetadata.componentPath, "internal", reference.name);
|
|
593
|
+
if (this.deps.functions[internalName]) return {
|
|
594
|
+
kind: expectedKind,
|
|
595
|
+
name: internalName
|
|
596
|
+
};
|
|
597
|
+
const publicName = toCanonicalComponentFunctionName(callerMetadata.componentPath, "public", reference.name);
|
|
598
|
+
if (this.deps.functions[publicName]) return {
|
|
599
|
+
kind: expectedKind,
|
|
600
|
+
name: publicName
|
|
601
|
+
};
|
|
602
|
+
return reference;
|
|
603
|
+
}
|
|
604
|
+
resolveTableName(tableName, componentMetadata) {
|
|
605
|
+
if (!componentMetadata) return tableName;
|
|
606
|
+
const scopedTableName = componentMetadata.localTables[tableName];
|
|
607
|
+
if (!scopedTableName) throw new Error(`Table ${JSON.stringify(tableName)} is not available inside component ${JSON.stringify(componentMetadata.componentPath)}.`);
|
|
608
|
+
return scopedTableName;
|
|
609
|
+
}
|
|
610
|
+
};
|
|
611
|
+
function collectChangedScopes(changedTables, storageChanges) {
|
|
612
|
+
return new Set([...[...changedTables].map((tableName) => `table:${tableName}`), ...storageChanges.map((change) => `storage:${change.storageId}`)]);
|
|
613
|
+
}
|
|
614
|
+
//#endregion
|
|
615
|
+
export { ExecutionEngine };
|
|
616
|
+
|
|
617
|
+
//# sourceMappingURL=executionEngine.mjs.map
|