@gonvex/cli 0.5.2-staging.2 → 0.5.2-staging.21
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/index.js +71 -7
- package/dist/index.js.map +1 -1
- package/dist/lazy-reference-bindings.d.ts +3 -0
- package/dist/lazy-reference-bindings.js +22 -0
- package/dist/lazy-reference-bindings.js.map +1 -0
- package/dist/local-bindings.d.ts +4 -0
- package/dist/local-bindings.js +106 -0
- package/dist/local-bindings.js.map +1 -0
- package/dist/local-dependencies.d.ts +58 -0
- package/dist/local-dependencies.js +850 -0
- package/dist/local-dependencies.js.map +1 -0
- package/dist/local-schema.d.ts +6 -0
- package/dist/local-schema.js +55 -0
- package/dist/local-schema.js.map +1 -0
- package/dist/manifest-types.d.ts +43 -2
- package/dist/module-artifact.js +155 -8
- package/dist/module-artifact.js.map +1 -1
- package/dist/native-local-bindings.d.ts +2 -0
- package/dist/native-local-bindings.js +22 -0
- package/dist/native-local-bindings.js.map +1 -0
- package/dist/pglite-browser-bundle.d.ts +3 -0
- package/dist/pglite-browser-bundle.js +35 -0
- package/dist/pglite-browser-bundle.js.map +1 -0
- package/package.json +7 -5
- package/dist/templates/vite-react/gonvex/_build/module.js +0 -572
package/dist/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { lazyReferenceRuntime, renderLazyReferences } from "./lazy-reference-bindings.js";
|
|
2
3
|
import { createHash } from "node:crypto";
|
|
3
4
|
import { spawn } from "node:child_process";
|
|
4
5
|
import { existsSync, readFileSync, realpathSync } from "node:fs";
|
|
@@ -8,8 +9,10 @@ import { createInterface } from "node:readline/promises";
|
|
|
8
9
|
import { dirname, join, relative, resolve } from "node:path";
|
|
9
10
|
import { Writable } from "node:stream";
|
|
10
11
|
import { fileURLToPath } from "node:url";
|
|
11
|
-
import { buildModuleArtifact, detectProjectLanguage, moduleManifestFunctions, moduleSourceFiles,
|
|
12
|
+
import { buildModuleArtifact, detectProjectLanguage, moduleManifestFunctions, moduleSourceFiles, } from "./module-artifact.js";
|
|
12
13
|
import { renderFunctionCatalog } from "./function-catalog.js";
|
|
14
|
+
import { localBindings, projectLocalSchema } from "./local-bindings.js";
|
|
15
|
+
import { analyzeLocalReducerDependencies, formatLocalDependencyViolations, localDependencyTables, localDependencyViolations, } from "./local-dependencies.js";
|
|
13
16
|
export * from "./function-catalog.js";
|
|
14
17
|
const defaultRuntimeURL = "http://localhost:8080";
|
|
15
18
|
const runtimeSyncRetryMs = 5000;
|
|
@@ -1102,15 +1105,50 @@ async function buildManifest(root, sources, projectID) {
|
|
|
1102
1105
|
entrypoint: sources.config.module?.entrypoint,
|
|
1103
1106
|
bundle: sources.config.module?.bundle,
|
|
1104
1107
|
});
|
|
1108
|
+
const functions = moduleManifestFunctions(module);
|
|
1109
|
+
await applyLocalDependencies(root, sources, functions);
|
|
1105
1110
|
return {
|
|
1106
1111
|
project: projectID,
|
|
1107
1112
|
generatedAt: new Date().toISOString(),
|
|
1108
|
-
functions
|
|
1113
|
+
functions,
|
|
1109
1114
|
schema: emptySchemaDefinition(),
|
|
1110
1115
|
module,
|
|
1111
1116
|
...(Object.keys(module.visibility).length > 0 ? { visibility: module.visibility } : {}),
|
|
1112
1117
|
};
|
|
1113
1118
|
}
|
|
1119
|
+
/**
|
|
1120
|
+
* Record each locally executing Reducer's table dependencies in the manifest
|
|
1121
|
+
* and reject dependencies that no generated local collection can satisfy.
|
|
1122
|
+
* See local-dependencies.ts for the analysis and its precision limits.
|
|
1123
|
+
*/
|
|
1124
|
+
async function applyLocalDependencies(root, sources, functions) {
|
|
1125
|
+
const reducers = Object.entries(functions)
|
|
1126
|
+
.filter(([, entry]) => entry.kind === "reducer" && entry.localExecution === 1 && !entry.internal)
|
|
1127
|
+
.map(([path, entry]) => ({ path, file: entry.file, exportName: entry.handler }));
|
|
1128
|
+
if (!reducers.length)
|
|
1129
|
+
return;
|
|
1130
|
+
const mode = sources.config.module?.localDependencyCheck ?? "error";
|
|
1131
|
+
if (mode !== "error" && mode !== "warn")
|
|
1132
|
+
throw new Error('gonvex.json module.localDependencyCheck must be "error" or "warn"');
|
|
1133
|
+
const analyses = await analyzeLocalReducerDependencies({
|
|
1134
|
+
root, backendDir: join(root, "gonvex"), files: sources.moduleFiles, reducers, tsconfig: sources.config.module?.tsconfig,
|
|
1135
|
+
});
|
|
1136
|
+
const schema = await projectLocalSchema(root);
|
|
1137
|
+
const tableKeys = new Map(Object.entries(schema).map(([table, shape]) => [table, shape.key]));
|
|
1138
|
+
const localTables = new Set(Object.entries(functions)
|
|
1139
|
+
.filter(([path, entry]) => path.startsWith("__local.") && entry.replica)
|
|
1140
|
+
.map(([, entry]) => entry.replica.table));
|
|
1141
|
+
for (const analysis of analyses)
|
|
1142
|
+
functions[analysis.path].localDependencies = localDependencyTables(analysis, tableKeys);
|
|
1143
|
+
const violations = localDependencyViolations(analyses, localTables, tableKeys);
|
|
1144
|
+
if (!violations.length)
|
|
1145
|
+
return;
|
|
1146
|
+
const report = formatLocalDependencyViolations(violations);
|
|
1147
|
+
if (mode === "error") {
|
|
1148
|
+
throw new Error(`Local Reducer dependency check failed. ${report}\nSet gonvex.json module.localDependencyCheck to "warn" only while migrating.`);
|
|
1149
|
+
}
|
|
1150
|
+
console.warn(color.yellow(`[gonvex] warning: ${report}`));
|
|
1151
|
+
}
|
|
1114
1152
|
async function writeBindings(root, manifest) {
|
|
1115
1153
|
const dir = join(root, "gonvex", "_generated");
|
|
1116
1154
|
await mkdir(dir, { recursive: true });
|
|
@@ -1118,9 +1156,15 @@ async function writeBindings(root, manifest) {
|
|
|
1118
1156
|
let changedFiles = 0;
|
|
1119
1157
|
if (await writeManifestIfChanged(join(dir, "manifest.json"), manifest))
|
|
1120
1158
|
changedFiles += 1;
|
|
1159
|
+
const local = await localBindings(root, manifest);
|
|
1160
|
+
if (local["local-reducers.js"])
|
|
1161
|
+
await rm(join(dir, "local-reducers.ts"), { force: true });
|
|
1121
1162
|
const outputs = {
|
|
1163
|
+
...local,
|
|
1122
1164
|
"api.ts": renderAPI(manifest),
|
|
1123
|
-
"client.ts":
|
|
1165
|
+
"client.ts": local["local-runtime.ts"]
|
|
1166
|
+
? '// Generated by Gonvex. Do not edit.\nimport { GonvexClient as BaseClient, type GonvexClientOptions } from "@gonvex/client";\nimport { localRuntime } from "./local-runtime.js";\nexport class GonvexClient extends BaseClient { constructor(url: string, options: GonvexClientOptions = {}) { super(url, { ...options, localRuntime: options.localRuntime ?? localRuntime }); } }\nexport { createFirebaseAuthAdapter } from "@gonvex/client";\n'
|
|
1167
|
+
: '// Generated by gonvex dev. Do not edit.\nexport { GonvexClient, createFirebaseAuthAdapter } from "@gonvex/client";\nexport type { GonvexExternalAuthAdapter, GonvexExternalIdentityHint, GonvexFirebaseAuthAdapterOptions } from "@gonvex/client";\n',
|
|
1124
1168
|
"react.ts": '// Generated by gonvex dev. Do not edit.\nexport { createFirebaseAuthAdapter, createGonvexAuth, GonvexAuthProvider, GonvexGoogleAuthButton, GonvexProvider, GonvexProviderWithAuth, useAction, useControlQuery, useCurrentTenantProfile, useEntity, useGonvexAuth, useGonvexAuthState, useGonvexClient, useGonvexConnectionState, useInvitationList, useLiveQuery, useLiveQueryState, useQuery, useReducer, useReplicaCollection, useReplicaCollectionState, useReplicaEntities, useReplicaSelector, useRetainedLiveQuery } from "@gonvex/react";\nexport type { GonvexAuthAccount, GonvexAuthConfig, GonvexAuthProviderName, GonvexAuthTenant, GonvexAuthValue, GonvexDeveloperModeState, GonvexExternalAuthAdapter, GonvexExternalIdentityHint, GonvexFirebaseAuthAdapterOptions } from "@gonvex/react";\n',
|
|
1125
1169
|
"types.ts": "// Generated by gonvex dev. Do not edit.\nexport type JsonValue = null | boolean | number | string | JsonValue[] | { [key: string]: JsonValue };\n",
|
|
1126
1170
|
"schema.ts": renderSchemaIndex(manifest),
|
|
@@ -1136,6 +1180,22 @@ async function writeBindings(root, manifest) {
|
|
|
1136
1180
|
if (await writeFileIfChanged(join(dir, name), contents))
|
|
1137
1181
|
changedFiles += 1;
|
|
1138
1182
|
}
|
|
1183
|
+
// Agent catalogs are checked into some applications and imported by their
|
|
1184
|
+
// browser bundle. Once a project opts in by creating either conventional
|
|
1185
|
+
// output, keep it on the exact artifact built by `gonvex dev`/`codegen`.
|
|
1186
|
+
// Otherwise a backend hot reload can activate a new artifact while the
|
|
1187
|
+
// browser continues sending the old hash, making every delegated call fail
|
|
1188
|
+
// with STALE_AGENT_CATALOG until somebody manually re-emits the files.
|
|
1189
|
+
for (const [name, format] of [
|
|
1190
|
+
["agent-api.ndjson", "ndjson"],
|
|
1191
|
+
["agent-api.d.ts", "typescript"],
|
|
1192
|
+
]) {
|
|
1193
|
+
const output = join(root, name);
|
|
1194
|
+
if (existsSync(output) && await writeFileIfChanged(output, renderFunctionCatalog(manifest.module, format))) {
|
|
1195
|
+
changedFiles += 1;
|
|
1196
|
+
console.log(`[gonvex] refreshed ${name} for artifact ${manifest.module.hash}`);
|
|
1197
|
+
}
|
|
1198
|
+
}
|
|
1139
1199
|
return { changedFiles };
|
|
1140
1200
|
}
|
|
1141
1201
|
async function writeManifestIfChanged(path, manifest) {
|
|
@@ -1244,8 +1304,9 @@ function renderAPI(manifest) {
|
|
|
1244
1304
|
...(entry.delivery ? { delivery: entry.delivery } : {}),
|
|
1245
1305
|
...(entry.delivery === "replica" && entry.replica ? { replica: entry.replica } : {}),
|
|
1246
1306
|
...(entry.offline !== undefined ? { offline: entry.offline } : {}),
|
|
1247
|
-
...(
|
|
1248
|
-
|
|
1307
|
+
...(entry.localExecution !== undefined ? { localExecution: entry.localExecution } : {}),
|
|
1308
|
+
// Args/Result are phantom types below. Validation schemas remain in the
|
|
1309
|
+
// module manifest and agent catalog; the browser never consumes them.
|
|
1249
1310
|
};
|
|
1250
1311
|
if (entry.delivery === "live" && entry.dependencies?.liveQueryPlan) {
|
|
1251
1312
|
const plan = entry.dependencies.liveQueryPlan;
|
|
@@ -1284,6 +1345,7 @@ function renderAPI(manifest) {
|
|
|
1284
1345
|
" readonly delivery?: \"oneShot\" | \"live\" | \"replica\";",
|
|
1285
1346
|
" readonly replica?: { readonly table: string; readonly key: string; readonly columns?: readonly string[] };",
|
|
1286
1347
|
" readonly offline?: { readonly mode: \"forbidden\" | \"allowed\" | \"onlineOnly\"; readonly conflict?: \"reject\" | \"expectedVersion\" | \"merge\"; readonly reason?: string };",
|
|
1348
|
+
" readonly localExecution?: 1;",
|
|
1287
1349
|
" readonly args?: Args;",
|
|
1288
1350
|
" readonly result?: Result;",
|
|
1289
1351
|
" readonly live?: { readonly entity: string; readonly key: string; readonly resultPath?: readonly string[]; readonly plan: LiveQueryPlan };",
|
|
@@ -1295,11 +1357,13 @@ function renderAPI(manifest) {
|
|
|
1295
1357
|
`export type ${result} = ${renderSchemaType(manifest.functions[path]?.result)};`,
|
|
1296
1358
|
]),
|
|
1297
1359
|
"",
|
|
1298
|
-
|
|
1360
|
+
lazyReferenceRuntime,
|
|
1361
|
+
"",
|
|
1362
|
+
`export const api = ${renderLazyReferences(publicRoot, 0, isFunctionRef, renderObject)};`,
|
|
1299
1363
|
"",
|
|
1300
1364
|
"export const control = gonvexControl;",
|
|
1301
1365
|
"",
|
|
1302
|
-
`export const internal = ${
|
|
1366
|
+
`export const internal = ${renderLazyReferences(internalRoot, 0, isFunctionRef, renderObject)};`,
|
|
1303
1367
|
"export type Api = typeof api;",
|
|
1304
1368
|
"",
|
|
1305
1369
|
`export const optimisticTransactions: Record<string, OptimisticTransactionDefinition> = ${renderObject(optimisticTransactions, 0)};`,
|