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
|
@@ -0,0 +1,583 @@
|
|
|
1
|
+
import { mkdir, mkdtemp, readFile, readdir, rm, writeFile } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { VALID_SYNCORE_TEMPLATES, detectProjectTemplate, fileExists, importJsonlIntoProject, isLocalPortInUse, loadProjectConfig, loadProjectFunctions, loadProjectSchema, resolvePortFromEnv, resolveProjectTargetConfig, runCodegen } from "../core/cli.mjs";
|
|
4
|
+
import os from "node:os";
|
|
5
|
+
import { pathToFileURL } from "node:url";
|
|
6
|
+
import AdmZip from "adm-zip";
|
|
7
|
+
import { createPublicRuntimeId, createPublicTargetId } from "../devtools-protocol/index.js";
|
|
8
|
+
import { NodeSqliteDriver, createManagedNodeSyncoreClient } from "../platform-node/index.mjs";
|
|
9
|
+
import WebSocket from "ws";
|
|
10
|
+
//#region src/project.ts
|
|
11
|
+
const PROJECT_TARGET_CAPABILITIES = [
|
|
12
|
+
"run",
|
|
13
|
+
"readData",
|
|
14
|
+
"writeData",
|
|
15
|
+
"exportData"
|
|
16
|
+
];
|
|
17
|
+
const CLIENT_TARGET_CAPABILITIES = [
|
|
18
|
+
"run",
|
|
19
|
+
"readData",
|
|
20
|
+
"writeData",
|
|
21
|
+
"exportData",
|
|
22
|
+
"streamLogs"
|
|
23
|
+
];
|
|
24
|
+
function createPublicRuntimeId$1(runtimeId, runtimeIds) {
|
|
25
|
+
return createPublicRuntimeId(runtimeId, runtimeIds);
|
|
26
|
+
}
|
|
27
|
+
function getClientRuntimeLabel(input) {
|
|
28
|
+
return input.sessionLabel ?? input.appName ?? input.platform;
|
|
29
|
+
}
|
|
30
|
+
function buildRuntimeLookup(targets) {
|
|
31
|
+
const lookup = /* @__PURE__ */ new Map();
|
|
32
|
+
for (const target of targets) {
|
|
33
|
+
if (target.kind !== "client") continue;
|
|
34
|
+
for (const runtime of target.runtimes) lookup.set(runtime.runtimeId, {
|
|
35
|
+
...runtime,
|
|
36
|
+
targetId: target.id,
|
|
37
|
+
targetLabel: target.label
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
return lookup;
|
|
41
|
+
}
|
|
42
|
+
async function resolveProjectPaths(cwd) {
|
|
43
|
+
if (!await fileExists(path.join(cwd, "syncore.config.ts"))) return null;
|
|
44
|
+
const projectTarget = resolveProjectTargetConfig(await loadProjectConfig(cwd));
|
|
45
|
+
if (!projectTarget) return null;
|
|
46
|
+
return {
|
|
47
|
+
databasePath: path.resolve(cwd, projectTarget.databasePath),
|
|
48
|
+
storageDirectory: path.resolve(cwd, projectTarget.storageDirectory)
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
async function requireProjectPaths(cwd) {
|
|
52
|
+
const paths = await resolveProjectPaths(cwd);
|
|
53
|
+
if (!paths) throw new Error("This Syncore project does not define a projectTarget. Use a connected client target instead.");
|
|
54
|
+
return paths;
|
|
55
|
+
}
|
|
56
|
+
async function resolveProjectTargetDescriptor(cwd) {
|
|
57
|
+
const paths = await resolveProjectPaths(cwd);
|
|
58
|
+
if (!paths) return null;
|
|
59
|
+
return {
|
|
60
|
+
id: "project",
|
|
61
|
+
kind: "project",
|
|
62
|
+
label: `project (${path.basename(paths.databasePath)})`,
|
|
63
|
+
databasePath: paths.databasePath,
|
|
64
|
+
storageDirectory: paths.storageDirectory,
|
|
65
|
+
online: true,
|
|
66
|
+
capabilities: [...PROJECT_TARGET_CAPABILITIES]
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
async function createManagedProjectClient(cwd) {
|
|
70
|
+
const [paths, schema, functions] = await Promise.all([
|
|
71
|
+
requireProjectPaths(cwd),
|
|
72
|
+
loadProjectSchema(cwd),
|
|
73
|
+
loadRuntimeProjectFunctions(cwd)
|
|
74
|
+
]);
|
|
75
|
+
return await createManagedNodeSyncoreClient({
|
|
76
|
+
databasePath: paths.databasePath,
|
|
77
|
+
storageDirectory: paths.storageDirectory,
|
|
78
|
+
schema,
|
|
79
|
+
functions,
|
|
80
|
+
devtools: false,
|
|
81
|
+
platform: "cli"
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
async function resolveProjectFunction(cwd, requestedName) {
|
|
85
|
+
const functions = await loadRuntimeProjectFunctions(cwd);
|
|
86
|
+
const normalizedName = normalizeFunctionName(requestedName, functions);
|
|
87
|
+
const definition = functions[normalizedName];
|
|
88
|
+
if (!definition) {
|
|
89
|
+
const available = Object.keys(functions).sort((left, right) => left.localeCompare(right));
|
|
90
|
+
const suggestions = suggestFunctionNames(requestedName, available);
|
|
91
|
+
throw new Error(`Unknown function ${JSON.stringify(requestedName)}.${suggestions.length > 0 ? ` Did you mean: ${suggestions.join(", ")}?` : ""} Available functions: ${available.join(", ")}`);
|
|
92
|
+
}
|
|
93
|
+
return {
|
|
94
|
+
name: normalizedName,
|
|
95
|
+
definition,
|
|
96
|
+
reference: {
|
|
97
|
+
kind: definition.kind,
|
|
98
|
+
name: normalizedName
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
function suggestFunctionNames(requestedName, available) {
|
|
103
|
+
const normalized = requestedName.trim().replace(/^api\./, "").replaceAll(".", "/").replaceAll(":", "/").toLowerCase();
|
|
104
|
+
return available.map((name) => ({
|
|
105
|
+
name,
|
|
106
|
+
score: (name.toLowerCase() === normalized ? 100 : 0) + (name.toLowerCase().startsWith(normalized) ? 30 : 0) + (name.toLowerCase().includes(normalized) ? 20 : 0) + sharedSegmentsScore(normalized, name.toLowerCase())
|
|
107
|
+
})).filter((entry) => entry.score > 0).sort((left, right) => right.score - left.score || left.name.localeCompare(right.name)).slice(0, 5).map((entry) => entry.name);
|
|
108
|
+
}
|
|
109
|
+
function sharedSegmentsScore(left, right) {
|
|
110
|
+
const leftSegments = left.split("/").filter(Boolean);
|
|
111
|
+
const rightSegments = right.split("/").filter(Boolean);
|
|
112
|
+
let score = 0;
|
|
113
|
+
for (const segment of leftSegments) if (rightSegments.includes(segment)) score += 10;
|
|
114
|
+
return score;
|
|
115
|
+
}
|
|
116
|
+
function normalizeFunctionName(requestedName, functions) {
|
|
117
|
+
const trimmed = requestedName.trim();
|
|
118
|
+
const candidates = [
|
|
119
|
+
trimmed,
|
|
120
|
+
trimmed.replace(/^api\./, "").replaceAll(".", "/"),
|
|
121
|
+
trimmed.replace(/^api\./, "").replaceAll(".", "/").replaceAll(":", "/"),
|
|
122
|
+
trimmed.replaceAll(":", "/"),
|
|
123
|
+
trimmed.replaceAll(".", "/")
|
|
124
|
+
];
|
|
125
|
+
for (const candidate of candidates) if (functions[candidate]) return candidate;
|
|
126
|
+
return trimmed.replace(/^api\./, "").replaceAll(".", "/").replaceAll(":", "/");
|
|
127
|
+
}
|
|
128
|
+
async function listProjectTables(cwd) {
|
|
129
|
+
const [paths, schema] = await Promise.all([requireProjectPaths(cwd), loadProjectSchema(cwd)]);
|
|
130
|
+
await mkdir(path.dirname(paths.databasePath), { recursive: true });
|
|
131
|
+
const driver = new NodeSqliteDriver(paths.databasePath);
|
|
132
|
+
try {
|
|
133
|
+
const results = [];
|
|
134
|
+
for (const tableName of schema.tableNames()) {
|
|
135
|
+
const row = await driver.get(`SELECT COUNT(*) AS count FROM ${quoteIdentifier(tableName)}`);
|
|
136
|
+
results.push({
|
|
137
|
+
name: tableName,
|
|
138
|
+
documentCount: Number(row?.count ?? 0)
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
return results;
|
|
142
|
+
} finally {
|
|
143
|
+
await driver.close();
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
async function readProjectTable(cwd, tableName, options) {
|
|
147
|
+
const driver = new NodeSqliteDriver((await requireProjectPaths(cwd)).databasePath);
|
|
148
|
+
try {
|
|
149
|
+
return {
|
|
150
|
+
table: tableName,
|
|
151
|
+
rows: (await driver.all(`SELECT _id, _creationTime, _json FROM ${quoteIdentifier(tableName)} ORDER BY _creationTime ${options.order.toUpperCase()} LIMIT ?`, [options.limit])).map((row) => ({
|
|
152
|
+
_id: row._id,
|
|
153
|
+
_creationTime: row._creationTime,
|
|
154
|
+
...JSON.parse(row._json)
|
|
155
|
+
}))
|
|
156
|
+
};
|
|
157
|
+
} finally {
|
|
158
|
+
await driver.close();
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
async function exportProjectData(cwd, outputPath, options = {}) {
|
|
162
|
+
const resolvedOutput = path.resolve(cwd, outputPath);
|
|
163
|
+
const tables = options.table ? [options.table] : (await listProjectTables(cwd)).map((table) => table.name);
|
|
164
|
+
if (tables.length === 0) throw new Error("No tables are available to export.");
|
|
165
|
+
return await writeExportData(resolvedOutput, await Promise.all(tables.map(async (table) => ({
|
|
166
|
+
table,
|
|
167
|
+
rows: (await readProjectTable(cwd, table, {
|
|
168
|
+
limit: Number.MAX_SAFE_INTEGER,
|
|
169
|
+
order: "asc"
|
|
170
|
+
})).rows
|
|
171
|
+
}))));
|
|
172
|
+
}
|
|
173
|
+
async function writeExportData(resolvedOutput, payloads) {
|
|
174
|
+
const tables = payloads.map((payload) => payload.table);
|
|
175
|
+
if (tables.length === 0) throw new Error("No tables are available to export.");
|
|
176
|
+
const extension = path.extname(resolvedOutput).toLowerCase();
|
|
177
|
+
if (extension === ".json" || extension === ".jsonl") {
|
|
178
|
+
if (tables.length !== 1) throw new Error(`Single-file exports require --table. Available tables: ${tables.join(", ")}`);
|
|
179
|
+
const payload = payloads[0];
|
|
180
|
+
await mkdir(path.dirname(resolvedOutput), { recursive: true });
|
|
181
|
+
await writeFile(resolvedOutput, extension === ".json" ? `${JSON.stringify(payload.rows, null, 2)}\n` : `${payload.rows.map((row) => JSON.stringify(row)).join("\n")}\n`);
|
|
182
|
+
return {
|
|
183
|
+
path: resolvedOutput,
|
|
184
|
+
tables: [payload.table],
|
|
185
|
+
format: extension === ".json" ? "json" : "jsonl"
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
if (extension === ".zip") {
|
|
189
|
+
const zip = new AdmZip();
|
|
190
|
+
for (const payload of payloads) zip.addFile(`${payload.table}.jsonl`, Buffer.from(`${payload.rows.map((row) => JSON.stringify(row)).join("\n")}\n`));
|
|
191
|
+
await mkdir(path.dirname(resolvedOutput), { recursive: true });
|
|
192
|
+
zip.writeZip(resolvedOutput);
|
|
193
|
+
return {
|
|
194
|
+
path: resolvedOutput,
|
|
195
|
+
tables,
|
|
196
|
+
format: "zip"
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
await mkdir(resolvedOutput, { recursive: true });
|
|
200
|
+
for (const payload of payloads) await writeFile(path.join(resolvedOutput, `${payload.table}.jsonl`), `${payload.rows.map((row) => JSON.stringify(row)).join("\n")}\n`);
|
|
201
|
+
return {
|
|
202
|
+
path: resolvedOutput,
|
|
203
|
+
tables,
|
|
204
|
+
format: "directory"
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
async function importProjectData(cwd, sourcePath, options = {}) {
|
|
208
|
+
const resolvedSource = path.resolve(cwd, sourcePath);
|
|
209
|
+
const extension = path.extname(resolvedSource).toLowerCase();
|
|
210
|
+
const cleanupDirectories = [];
|
|
211
|
+
try {
|
|
212
|
+
const sources = extension === ".zip" ? await extractImportSourcesFromZip(resolvedSource, cleanupDirectories) : await resolveImportSources(resolvedSource, options.table, cleanupDirectories);
|
|
213
|
+
const imported = [];
|
|
214
|
+
for (const source of sources) {
|
|
215
|
+
const importedCount = await importJsonlIntoProject(cwd, source.table, source.filePath);
|
|
216
|
+
imported.push({
|
|
217
|
+
table: source.table,
|
|
218
|
+
importedCount
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
return imported;
|
|
222
|
+
} finally {
|
|
223
|
+
for (const directory of cleanupDirectories) await rm(directory, {
|
|
224
|
+
recursive: true,
|
|
225
|
+
force: true
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
async function loadImportDocumentBatches(cwd, sourcePath, options = {}) {
|
|
230
|
+
const resolvedSource = path.resolve(cwd, sourcePath);
|
|
231
|
+
const extension = path.extname(resolvedSource).toLowerCase();
|
|
232
|
+
const cleanupDirectories = [];
|
|
233
|
+
try {
|
|
234
|
+
const sources = extension === ".zip" ? await extractImportSourcesFromZip(resolvedSource, cleanupDirectories) : await resolveImportSources(resolvedSource, options.table, cleanupDirectories);
|
|
235
|
+
return await Promise.all(sources.map(async (source) => ({
|
|
236
|
+
table: source.table,
|
|
237
|
+
rows: await readJsonlRows(source.filePath)
|
|
238
|
+
})));
|
|
239
|
+
} finally {
|
|
240
|
+
for (const directory of cleanupDirectories) await rm(directory, {
|
|
241
|
+
recursive: true,
|
|
242
|
+
force: true
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
async function findWorkspaceSyncoreProjects(cwd) {
|
|
247
|
+
const packageJsonPath = path.join(cwd, "package.json");
|
|
248
|
+
if (!await fileExists(packageJsonPath)) return [];
|
|
249
|
+
let workspaces = [];
|
|
250
|
+
try {
|
|
251
|
+
workspaces = JSON.parse(await readFile(packageJsonPath, "utf8")).workspaces ?? [];
|
|
252
|
+
} catch {
|
|
253
|
+
return [];
|
|
254
|
+
}
|
|
255
|
+
const directories = /* @__PURE__ */ new Set();
|
|
256
|
+
for (const workspace of workspaces) {
|
|
257
|
+
const prefix = workspace.replace(/\/\*+$/, "");
|
|
258
|
+
const fullPrefix = path.join(cwd, prefix);
|
|
259
|
+
if (!await fileExists(fullPrefix)) continue;
|
|
260
|
+
const entries = await readdir(fullPrefix, { withFileTypes: true });
|
|
261
|
+
for (const entry of entries) if (entry.isDirectory()) directories.add(path.join(fullPrefix, entry.name));
|
|
262
|
+
}
|
|
263
|
+
const matches = [];
|
|
264
|
+
for (const directory of directories) {
|
|
265
|
+
if (!await fileExists(path.join(directory, "syncore.config.ts"))) continue;
|
|
266
|
+
matches.push({
|
|
267
|
+
path: directory,
|
|
268
|
+
relativePath: path.relative(cwd, directory).replaceAll("\\", "/"),
|
|
269
|
+
template: await detectProjectTemplate(directory)
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
return matches.sort((left, right) => left.relativePath.localeCompare(right.relativePath));
|
|
273
|
+
}
|
|
274
|
+
async function resolveDocsTarget(cwd) {
|
|
275
|
+
const template = await detectProjectTemplate(cwd);
|
|
276
|
+
const docsFile = template === "react-web" ? path.join("docs", "quickstarts", "react-web.md") : template === "next" ? path.join("docs", "quickstarts", "next-pwa.md") : template === "expo" ? path.join("docs", "quickstarts", "expo.md") : template === "electron" ? path.join("docs", "quickstarts", "electron.md") : template === "node" ? path.join("docs", "quickstarts", "node-script.md") : path.join("README.md");
|
|
277
|
+
return pathToFileURL(path.resolve(import.meta.dirname, "..", "..", "..", docsFile)).href;
|
|
278
|
+
}
|
|
279
|
+
function resolveDashboardUrl() {
|
|
280
|
+
return `http://localhost:${resolvePortFromEnv("SYNCORE_DASHBOARD_PORT", 4310)}`;
|
|
281
|
+
}
|
|
282
|
+
function resolveDevtoolsUrl() {
|
|
283
|
+
return `ws://127.0.0.1:${resolvePortFromEnv("SYNCORE_DEVTOOLS_PORT", 4311)}`;
|
|
284
|
+
}
|
|
285
|
+
async function listConnectedClientTargets(devtoolsUrl = resolveDevtoolsUrl()) {
|
|
286
|
+
const port = Number.parseInt(new URL(devtoolsUrl).port, 10);
|
|
287
|
+
if (!Number.isFinite(port) || !await isLocalPortInUse(port)) return [];
|
|
288
|
+
let hub;
|
|
289
|
+
try {
|
|
290
|
+
hub = await connectToDevtoolsHub(devtoolsUrl);
|
|
291
|
+
} catch {
|
|
292
|
+
return [];
|
|
293
|
+
}
|
|
294
|
+
try {
|
|
295
|
+
return buildClientTargets((await hub.collectSnapshot()).hellos);
|
|
296
|
+
} finally {
|
|
297
|
+
await hub.dispose();
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
async function listAvailableTargets(cwd) {
|
|
301
|
+
const [projectTarget, clientTargets] = await Promise.all([resolveProjectTargetDescriptor(cwd), listConnectedClientTargets()]);
|
|
302
|
+
return [...projectTarget ? [projectTarget] : [], ...clientTargets];
|
|
303
|
+
}
|
|
304
|
+
async function connectToProjectHub(devtoolsUrl = resolveDevtoolsUrl()) {
|
|
305
|
+
const port = Number.parseInt(new URL(devtoolsUrl).port, 10);
|
|
306
|
+
if (!Number.isFinite(port) || !await isLocalPortInUse(port)) return null;
|
|
307
|
+
try {
|
|
308
|
+
return await connectToDevtoolsHub(devtoolsUrl);
|
|
309
|
+
} catch {
|
|
310
|
+
return null;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
function isKnownTemplate(value) {
|
|
314
|
+
return VALID_SYNCORE_TEMPLATES.includes(value);
|
|
315
|
+
}
|
|
316
|
+
async function loadRuntimeProjectFunctions(cwd) {
|
|
317
|
+
try {
|
|
318
|
+
return await loadProjectFunctions(cwd);
|
|
319
|
+
} catch (error) {
|
|
320
|
+
if (!await fileExists(path.join(cwd, "syncore", "functions"))) throw error;
|
|
321
|
+
await runCodegen(cwd);
|
|
322
|
+
return await loadProjectFunctions(cwd);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
function quoteIdentifier(value) {
|
|
326
|
+
return `"${value.replaceAll("\"", "\"\"")}"`;
|
|
327
|
+
}
|
|
328
|
+
async function resolveImportSources(sourcePath, explicitTable, cleanupDirectories) {
|
|
329
|
+
const extension = path.extname(sourcePath).toLowerCase();
|
|
330
|
+
if (extension === ".jsonl") {
|
|
331
|
+
if (!explicitTable) throw new Error("`syncorejs import` requires --table when importing a .jsonl file.");
|
|
332
|
+
return [{
|
|
333
|
+
table: explicitTable,
|
|
334
|
+
filePath: sourcePath
|
|
335
|
+
}];
|
|
336
|
+
}
|
|
337
|
+
if (extension === ".json") {
|
|
338
|
+
if (!explicitTable) throw new Error("`syncorejs import` requires --table when importing a .json file.");
|
|
339
|
+
const rows = JSON.parse(await readFile(sourcePath, "utf8"));
|
|
340
|
+
if (!Array.isArray(rows)) throw new Error(`${sourcePath} must contain a JSON array.`);
|
|
341
|
+
const { directory, filePath } = await writeRowsToTempJsonl(rows);
|
|
342
|
+
cleanupDirectories.push(directory);
|
|
343
|
+
return [{
|
|
344
|
+
table: explicitTable,
|
|
345
|
+
filePath
|
|
346
|
+
}];
|
|
347
|
+
}
|
|
348
|
+
if (await isDirectory(sourcePath)) {
|
|
349
|
+
const entries = await readdir(sourcePath, { withFileTypes: true });
|
|
350
|
+
const sources = [];
|
|
351
|
+
for (const entry of entries) {
|
|
352
|
+
const fullPath = path.join(sourcePath, entry.name);
|
|
353
|
+
if (entry.isFile() && entry.name.endsWith(".jsonl")) sources.push({
|
|
354
|
+
table: entry.name.replace(/\.jsonl$/i, ""),
|
|
355
|
+
filePath: fullPath
|
|
356
|
+
});
|
|
357
|
+
if (entry.isDirectory()) {
|
|
358
|
+
const nestedPath = path.join(fullPath, "documents.jsonl");
|
|
359
|
+
if (await fileExists(nestedPath)) sources.push({
|
|
360
|
+
table: entry.name,
|
|
361
|
+
filePath: nestedPath
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
if (sources.length === 0) throw new Error(`No importable JSONL files were found in ${sourcePath}.`);
|
|
366
|
+
return sources.sort((left, right) => left.table.localeCompare(right.table));
|
|
367
|
+
}
|
|
368
|
+
throw new Error(`Unsupported import source: ${sourcePath}`);
|
|
369
|
+
}
|
|
370
|
+
async function extractImportSourcesFromZip(sourcePath, cleanupDirectories) {
|
|
371
|
+
const tempDirectory = await mkdtemp(path.join(os.tmpdir(), "syncore-cli-import-"));
|
|
372
|
+
cleanupDirectories.push(tempDirectory);
|
|
373
|
+
new AdmZip(sourcePath).extractAllTo(tempDirectory, true);
|
|
374
|
+
return await resolveImportSources(tempDirectory, void 0, cleanupDirectories);
|
|
375
|
+
}
|
|
376
|
+
async function writeRowsToTempJsonl(rows) {
|
|
377
|
+
const tempDirectory = await mkdtemp(path.join(os.tmpdir(), "syncore-cli-json-"));
|
|
378
|
+
const tempFile = path.join(tempDirectory, "rows.jsonl");
|
|
379
|
+
await writeFile(tempFile, `${rows.map((row) => JSON.stringify(row)).join("\n")}\n`);
|
|
380
|
+
return {
|
|
381
|
+
directory: tempDirectory,
|
|
382
|
+
filePath: tempFile
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
async function readJsonlRows(filePath) {
|
|
386
|
+
const source = await readFile(filePath, "utf8");
|
|
387
|
+
const rows = [];
|
|
388
|
+
let lineNumber = 0;
|
|
389
|
+
for (const line of source.split(/\r?\n/)) {
|
|
390
|
+
const trimmed = line.trim();
|
|
391
|
+
if (!trimmed) continue;
|
|
392
|
+
lineNumber += 1;
|
|
393
|
+
const parsed = JSON.parse(trimmed);
|
|
394
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error(`Line ${lineNumber} of ${filePath} must contain a JSON object.`);
|
|
395
|
+
rows.push(parsed);
|
|
396
|
+
}
|
|
397
|
+
return rows;
|
|
398
|
+
}
|
|
399
|
+
async function isDirectory(filePath) {
|
|
400
|
+
try {
|
|
401
|
+
const entries = await readdir(filePath);
|
|
402
|
+
return Array.isArray(entries);
|
|
403
|
+
} catch {
|
|
404
|
+
return false;
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
async function connectToDevtoolsHub(url) {
|
|
408
|
+
const socket = new WebSocket(url);
|
|
409
|
+
socket.on("error", () => {});
|
|
410
|
+
const hellos = /* @__PURE__ */ new Map();
|
|
411
|
+
const events = [];
|
|
412
|
+
const eventListeners = /* @__PURE__ */ new Set();
|
|
413
|
+
const commandResolvers = /* @__PURE__ */ new Map();
|
|
414
|
+
const subscriptionHandlers = /* @__PURE__ */ new Map();
|
|
415
|
+
await new Promise((resolve, reject) => {
|
|
416
|
+
socket.once("open", () => resolve());
|
|
417
|
+
socket.once("error", (error) => reject(error));
|
|
418
|
+
});
|
|
419
|
+
socket.on("message", (rawPayload) => {
|
|
420
|
+
const payload = typeof rawPayload === "string" ? rawPayload : rawPayload instanceof Buffer ? rawPayload.toString("utf8") : Array.isArray(rawPayload) ? Buffer.concat(rawPayload).toString("utf8") : rawPayload instanceof ArrayBuffer ? Buffer.from(rawPayload).toString("utf8") : Buffer.from(rawPayload.buffer, rawPayload.byteOffset, rawPayload.byteLength).toString("utf8");
|
|
421
|
+
if (payload.length === 0) return;
|
|
422
|
+
const message = JSON.parse(payload);
|
|
423
|
+
if (message.type === "hello") {
|
|
424
|
+
hellos.set(message.runtimeId, message);
|
|
425
|
+
return;
|
|
426
|
+
}
|
|
427
|
+
if (message.type === "event") {
|
|
428
|
+
events.unshift(message.event);
|
|
429
|
+
events.splice(200);
|
|
430
|
+
if (message.event.type === "runtime.disconnected") hellos.delete(message.event.runtimeId);
|
|
431
|
+
for (const listener of eventListeners) listener(message.event);
|
|
432
|
+
return;
|
|
433
|
+
}
|
|
434
|
+
if (message.type === "command.result") {
|
|
435
|
+
const resolver = commandResolvers.get(message.commandId);
|
|
436
|
+
if (!resolver) return;
|
|
437
|
+
commandResolvers.delete(message.commandId);
|
|
438
|
+
resolver.resolve(message.payload);
|
|
439
|
+
return;
|
|
440
|
+
}
|
|
441
|
+
if (message.type === "subscription.data") {
|
|
442
|
+
subscriptionHandlers.get(message.subscriptionId)?.onData(message.payload);
|
|
443
|
+
return;
|
|
444
|
+
}
|
|
445
|
+
if (message.type === "subscription.error") subscriptionHandlers.get(message.subscriptionId)?.onError?.(message.error);
|
|
446
|
+
});
|
|
447
|
+
const dispose = async () => {
|
|
448
|
+
for (const [commandId, resolver] of commandResolvers) {
|
|
449
|
+
commandResolvers.delete(commandId);
|
|
450
|
+
resolver.reject(/* @__PURE__ */ new Error("Syncore devtools hub disconnected."));
|
|
451
|
+
}
|
|
452
|
+
subscriptionHandlers.clear();
|
|
453
|
+
if (socket.readyState === WebSocket.CLOSED) return;
|
|
454
|
+
await new Promise((resolve) => {
|
|
455
|
+
socket.once("close", () => resolve());
|
|
456
|
+
socket.close();
|
|
457
|
+
});
|
|
458
|
+
};
|
|
459
|
+
return {
|
|
460
|
+
async collectSnapshot(timeoutMs = 120) {
|
|
461
|
+
await new Promise((resolve) => setTimeout(resolve, timeoutMs));
|
|
462
|
+
return {
|
|
463
|
+
hellos: [...hellos.values()],
|
|
464
|
+
events: [...events]
|
|
465
|
+
};
|
|
466
|
+
},
|
|
467
|
+
listRuntimeHellos() {
|
|
468
|
+
return [...hellos.values()];
|
|
469
|
+
},
|
|
470
|
+
onEvent(listener) {
|
|
471
|
+
eventListeners.add(listener);
|
|
472
|
+
return () => {
|
|
473
|
+
eventListeners.delete(listener);
|
|
474
|
+
};
|
|
475
|
+
},
|
|
476
|
+
async sendCommand(runtimeId, payload) {
|
|
477
|
+
const commandId = createHubRequestId("command");
|
|
478
|
+
return await new Promise((resolve, reject) => {
|
|
479
|
+
commandResolvers.set(commandId, {
|
|
480
|
+
resolve,
|
|
481
|
+
reject
|
|
482
|
+
});
|
|
483
|
+
socket.send(JSON.stringify({
|
|
484
|
+
type: "command",
|
|
485
|
+
commandId,
|
|
486
|
+
targetRuntimeId: runtimeId,
|
|
487
|
+
payload
|
|
488
|
+
}));
|
|
489
|
+
});
|
|
490
|
+
},
|
|
491
|
+
subscribe(runtimeId, payload, handlers) {
|
|
492
|
+
const subscriptionId = createHubRequestId("subscription");
|
|
493
|
+
subscriptionHandlers.set(subscriptionId, handlers);
|
|
494
|
+
socket.send(JSON.stringify({
|
|
495
|
+
type: "subscribe",
|
|
496
|
+
subscriptionId,
|
|
497
|
+
targetRuntimeId: runtimeId,
|
|
498
|
+
payload
|
|
499
|
+
}));
|
|
500
|
+
return () => {
|
|
501
|
+
if (!subscriptionHandlers.has(subscriptionId)) return;
|
|
502
|
+
subscriptionHandlers.delete(subscriptionId);
|
|
503
|
+
socket.send(JSON.stringify({
|
|
504
|
+
type: "unsubscribe",
|
|
505
|
+
subscriptionId,
|
|
506
|
+
targetRuntimeId: runtimeId
|
|
507
|
+
}));
|
|
508
|
+
};
|
|
509
|
+
},
|
|
510
|
+
dispose
|
|
511
|
+
};
|
|
512
|
+
}
|
|
513
|
+
function buildClientTargets(hellos) {
|
|
514
|
+
const groups = /* @__PURE__ */ new Map();
|
|
515
|
+
for (const hello of hellos) {
|
|
516
|
+
if (hello.runtimeId === "syncore-dev-hub") continue;
|
|
517
|
+
const key = hello.storageIdentity ?? `runtime::${hello.runtimeId}`;
|
|
518
|
+
const group = groups.get(key) ?? {
|
|
519
|
+
key,
|
|
520
|
+
runtimes: []
|
|
521
|
+
};
|
|
522
|
+
group.runtimes.push(hello);
|
|
523
|
+
groups.set(key, group);
|
|
524
|
+
}
|
|
525
|
+
const allRuntimeIds = hellos.filter((hello) => hello.runtimeId !== "syncore-dev-hub").map((hello) => hello.runtimeId).sort();
|
|
526
|
+
return [...groups.values()].map(({ key, runtimes }) => {
|
|
527
|
+
const sortedRuntimes = [...runtimes].sort((left, right) => left.runtimeId.localeCompare(right.runtimeId));
|
|
528
|
+
const primary = sortedRuntimes[0];
|
|
529
|
+
const sessionLabels = Array.from(new Set(sortedRuntimes.map((entry) => entry.sessionLabel).filter((value) => typeof value === "string")));
|
|
530
|
+
const runtimeIds = sortedRuntimes.map((entry) => entry.runtimeId);
|
|
531
|
+
const runtimeDescriptors = sortedRuntimes.map((entry, index) => ({
|
|
532
|
+
id: createPublicRuntimeId$1(entry.runtimeId, allRuntimeIds),
|
|
533
|
+
runtimeId: entry.runtimeId,
|
|
534
|
+
label: getClientRuntimeLabel({
|
|
535
|
+
...entry.sessionLabel ? { sessionLabel: entry.sessionLabel } : {},
|
|
536
|
+
...entry.appName ? { appName: entry.appName } : {},
|
|
537
|
+
platform: entry.platform
|
|
538
|
+
}),
|
|
539
|
+
platform: entry.platform,
|
|
540
|
+
...entry.appName ? { appName: entry.appName } : {},
|
|
541
|
+
...entry.origin ? { origin: entry.origin } : {},
|
|
542
|
+
...entry.sessionLabel ? { sessionLabel: entry.sessionLabel } : {},
|
|
543
|
+
...entry.storageIdentity ? { storageIdentity: entry.storageIdentity } : {},
|
|
544
|
+
online: true,
|
|
545
|
+
primary: index === 0
|
|
546
|
+
}));
|
|
547
|
+
return {
|
|
548
|
+
id: createPublicClientTargetId(key, groups),
|
|
549
|
+
kind: "client",
|
|
550
|
+
label: renderClientTargetLabel(primary, runtimes.length),
|
|
551
|
+
runtimeId: primary.runtimeId,
|
|
552
|
+
runtimeIds,
|
|
553
|
+
runtimes: runtimeDescriptors,
|
|
554
|
+
platform: primary.platform,
|
|
555
|
+
...primary.appName ? { appName: primary.appName } : {},
|
|
556
|
+
...primary.origin ? { origin: primary.origin } : {},
|
|
557
|
+
sessionLabels,
|
|
558
|
+
...primary.storageProtocol ? { storageProtocol: primary.storageProtocol } : {},
|
|
559
|
+
...primary.databaseLabel ? { databaseLabel: primary.databaseLabel } : {},
|
|
560
|
+
...primary.storageIdentity ? { storageIdentity: primary.storageIdentity } : {},
|
|
561
|
+
connectedSessions: runtimes.length,
|
|
562
|
+
online: true,
|
|
563
|
+
capabilities: [...CLIENT_TARGET_CAPABILITIES]
|
|
564
|
+
};
|
|
565
|
+
}).sort((left, right) => left.label.localeCompare(right.label));
|
|
566
|
+
}
|
|
567
|
+
function createPublicClientTargetId(key, groupsOrKeys) {
|
|
568
|
+
return createPublicTargetId(key, groupsOrKeys instanceof Map ? [...groupsOrKeys.keys()] : [...groupsOrKeys]);
|
|
569
|
+
}
|
|
570
|
+
function targetSupportsCapability(target, capability) {
|
|
571
|
+
return target.capabilities.includes(capability);
|
|
572
|
+
}
|
|
573
|
+
function renderClientTargetLabel(hello, connectedSessions) {
|
|
574
|
+
const base = hello.appName ?? hello.databaseLabel ?? hello.origin ?? `${hello.platform} client`;
|
|
575
|
+
return connectedSessions > 1 ? `${base} (${connectedSessions} sessions)` : base;
|
|
576
|
+
}
|
|
577
|
+
function createHubRequestId(prefix) {
|
|
578
|
+
return `syncore-cli-${prefix}-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;
|
|
579
|
+
}
|
|
580
|
+
//#endregion
|
|
581
|
+
export { buildRuntimeLookup, connectToProjectHub, createManagedProjectClient, createPublicRuntimeId$1 as createPublicRuntimeId, exportProjectData, findWorkspaceSyncoreProjects, importProjectData, isKnownTemplate, listAvailableTargets, listConnectedClientTargets, listProjectTables, loadImportDocumentBatches, readProjectTable, resolveDashboardUrl, resolveDevtoolsUrl, resolveDocsTarget, resolveProjectFunction, resolveProjectTargetDescriptor, targetSupportsCapability, writeExportData };
|
|
582
|
+
|
|
583
|
+
//# sourceMappingURL=project.mjs.map
|