@protobase/cli 0.8.1 → 0.9.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/dev/dev-jobs.js +25 -0
- package/dist/dev/entry.js +10 -18
- package/dist/dev/run.js +6 -0
- package/dist/main.js +11 -0
- package/dist/migration/load-project.js +3 -1
- package/dist/migration/parts.js +23 -10
- package/dist/migration/register.js +1 -1
- package/dist/package.js +1 -1
- package/dist/project/project-admin.js +35 -0
- package/dist/serve/app.js +6 -19
- package/dist/serve/env.js +5 -1
- package/dist/serve/lifecycle.js +32 -9
- package/dist/worker/start-worker.js +56 -0
- package/package.json +6 -6
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { checkJobsSchema, startJobs } from "@protobase/server";
|
|
2
|
+
//#region src/dev/dev-jobs.ts
|
|
3
|
+
const store = globalThis;
|
|
4
|
+
/**
|
|
5
|
+
* Runs the project's jobs in the dev server: started on the first load, once the jobs schema checks out, and given the
|
|
6
|
+
* reloaded definitions on every load after it, so an edited job runs its new code from the next job on.
|
|
7
|
+
*/
|
|
8
|
+
const devJobs = async (db, definitions) => {
|
|
9
|
+
if (store.__protobaseJobs) return store.__protobaseJobs.update(definitions);
|
|
10
|
+
if (definitions.length === 0) return;
|
|
11
|
+
await checkJobsSchema(db);
|
|
12
|
+
store.__protobaseJobs = await startJobs({
|
|
13
|
+
db,
|
|
14
|
+
jobs: definitions,
|
|
15
|
+
onError: (error) => console.error(error)
|
|
16
|
+
});
|
|
17
|
+
};
|
|
18
|
+
/** Lets running jobs finish and stops them, when the dev server closes. */
|
|
19
|
+
const stopDevJobs = async () => {
|
|
20
|
+
const runtime = store.__protobaseJobs;
|
|
21
|
+
delete store.__protobaseJobs;
|
|
22
|
+
await runtime?.stop();
|
|
23
|
+
};
|
|
24
|
+
//#endregion
|
|
25
|
+
export { devJobs, stopDevJobs };
|
package/dist/dev/entry.js
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
|
+
import { devJobs } from "./dev-jobs.js";
|
|
2
|
+
import { projectAdmin } from "../project/project-admin.js";
|
|
1
3
|
import { loadProject, projectDb } from "./project.js";
|
|
2
|
-
import { checkAuthSchema, checkChanges,
|
|
4
|
+
import { checkAuthSchema, checkChanges, checkWebhooksSchema, configExports, hasUsers } from "@protobase/server";
|
|
3
5
|
import { Hono } from "hono";
|
|
4
6
|
//#region src/dev/entry.ts
|
|
5
7
|
const projectDir = process.env.PROTOBASE_PROJECT;
|
|
6
8
|
const project = await loadProject(projectDir, JSON.parse(process.env.PROTOBASE_EXTENSIONS ?? "[]"));
|
|
7
9
|
const db = projectDb(project, projectDir);
|
|
8
|
-
const { resources
|
|
10
|
+
const { resources } = configExports(project.exports);
|
|
9
11
|
if (!project.authenticate) throw new Error("No authenticator: export `authenticate` (and `auth`) from protobase.config.ts; see https://docs.protobase.net/reference/auth/");
|
|
10
12
|
const store = globalThis;
|
|
11
13
|
if (project.auth && !store.__protobaseAuthSchemaChecked) {
|
|
@@ -13,22 +15,12 @@ if (project.auth && !store.__protobaseAuthSchemaChecked) {
|
|
|
13
15
|
store.__protobaseAuthSchemaChecked = true;
|
|
14
16
|
}
|
|
15
17
|
await checkChanges(db, resources.map((resource) => resource.toModel()), project.events);
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
authenticate: project.authenticate,
|
|
23
|
-
...project.auth && { auth: project.auth },
|
|
24
|
-
...project.functions && { functions: project.functions },
|
|
25
|
-
...project.files && { files: project.files },
|
|
26
|
-
...project.events && { events: project.events },
|
|
27
|
-
options: {
|
|
28
|
-
onUnhandledError: (error) => console.error(error),
|
|
29
|
-
...project.options
|
|
30
|
-
}
|
|
31
|
-
});
|
|
18
|
+
if (project.webhooks) await checkWebhooksSchema(db, project.webhooks);
|
|
19
|
+
const { admin, jobs } = projectAdmin({
|
|
20
|
+
...project,
|
|
21
|
+
authenticate: project.authenticate
|
|
22
|
+
}, project.exports, db);
|
|
23
|
+
await devJobs(db, jobs);
|
|
32
24
|
var entry_default = new Hono().route("/", admin);
|
|
33
25
|
if (project.auth && !store.__protobaseNoUsersShown) {
|
|
34
26
|
store.__protobaseNoUsersShown = true;
|
package/dist/dev/run.js
CHANGED
|
@@ -5,6 +5,7 @@ import { moduleFile } from "../module-file.js";
|
|
|
5
5
|
import { layoutCheck } from "../build/layout-check.js";
|
|
6
6
|
import { projectUiPlugin } from "../project/project-ui.js";
|
|
7
7
|
import { checkDatabase } from "./check-database.js";
|
|
8
|
+
import { stopDevJobs } from "./dev-jobs.js";
|
|
8
9
|
import { existsSync } from "node:fs";
|
|
9
10
|
import path from "node:path";
|
|
10
11
|
import { createServer, searchForWorkspaceRoot } from "vite";
|
|
@@ -23,6 +24,10 @@ const reloadOnProjectChange = (dirs) => ({
|
|
|
23
24
|
if (dirs.some((dir) => file.startsWith(`${dir}${path.sep}`)) && !file.includes(`${path.sep}node_modules${path.sep}`)) server.environments.ssr.moduleGraph.invalidateAll();
|
|
24
25
|
}
|
|
25
26
|
});
|
|
27
|
+
const stopJobsOnClose = {
|
|
28
|
+
name: "protobase-jobs",
|
|
29
|
+
closeBundle: () => stopDevJobs()
|
|
30
|
+
};
|
|
26
31
|
const appDependencies = [
|
|
27
32
|
"react",
|
|
28
33
|
"react/jsx-runtime",
|
|
@@ -65,6 +70,7 @@ const runDev = async (options, out) => {
|
|
|
65
70
|
},
|
|
66
71
|
plugins: [
|
|
67
72
|
reloadOnProjectChange([options.projectDir, ...extensions.map((extension) => extension.dir)]),
|
|
73
|
+
stopJobsOnClose,
|
|
68
74
|
projectUiPlugin(options.projectDir, extensions),
|
|
69
75
|
extensionImports(options.projectDir, extensions),
|
|
70
76
|
extensionStyles(extensions),
|
package/dist/main.js
CHANGED
|
@@ -9,8 +9,10 @@ import { parseHosts } from "./dev/hosts.js";
|
|
|
9
9
|
import { runDev } from "./dev/run.js";
|
|
10
10
|
import { runDoctor } from "./doctor/run.js";
|
|
11
11
|
import { runScaffold } from "./scaffold/run.js";
|
|
12
|
+
import { closeOnSignals } from "./serve/signals.js";
|
|
12
13
|
import { serveBundle } from "./serve/serve-bundle.js";
|
|
13
14
|
import { serveBundleDir } from "./serve/serve-dir.js";
|
|
15
|
+
import { loadWorkerBundle, startWorker } from "./worker/start-worker.js";
|
|
14
16
|
import { registerOrganizations } from "./organizations/register.js";
|
|
15
17
|
import { registerFiles } from "./files/register.js";
|
|
16
18
|
import { registerMigration } from "./migration/register.js";
|
|
@@ -86,6 +88,15 @@ program.command("serve").description("Serve a bundle written by `protobase build
|
|
|
86
88
|
if (statSync(bundle).isDirectory()) await serveBundleDir(bundle, process.env, out);
|
|
87
89
|
else await serveBundle(bundle, process.env, out);
|
|
88
90
|
});
|
|
91
|
+
program.command("worker").description("Run the jobs of a bundle from `protobase build` in a process of their own, until SIGTERM or SIGINT, as `serve` runs them beside the API").argument("<bundle>", "the bundle folder, e.g. dist, or its dist/protobase.config.js").action(async (bundle) => {
|
|
92
|
+
loadNearestEnvFile(process.cwd());
|
|
93
|
+
const worker = await startWorker({
|
|
94
|
+
project: await loadWorkerBundle(bundle),
|
|
95
|
+
databaseUrl: process.env.DATABASE_URL || void 0
|
|
96
|
+
});
|
|
97
|
+
closeOnSignals(worker.stop);
|
|
98
|
+
out(`protobase worker running ${worker.jobs} job${worker.jobs === 1 ? "" : "s"}\n`);
|
|
99
|
+
});
|
|
89
100
|
registerUsers(program);
|
|
90
101
|
registerOrganizations(program);
|
|
91
102
|
registerToken(program);
|
|
@@ -3,7 +3,7 @@ import { importProjectFile } from "../project/import-project-file.js";
|
|
|
3
3
|
import { createPgDb } from "../project/pg-db.js";
|
|
4
4
|
import { existsSync } from "node:fs";
|
|
5
5
|
import path from "node:path";
|
|
6
|
-
import { configExports, mergeConfig } from "@protobase/server";
|
|
6
|
+
import { configExports, jobDefinitions, mergeConfig } from "@protobase/server";
|
|
7
7
|
import pg from "pg";
|
|
8
8
|
//#region src/migration/load-project.ts
|
|
9
9
|
const configOf = async (file) => (await importProjectFile(file)).default ?? {};
|
|
@@ -32,6 +32,8 @@ const loadMigrationProject = async (dir, extensions = []) => {
|
|
|
32
32
|
db: project.db ?? ownDb,
|
|
33
33
|
...project.auth && { auth: project.auth },
|
|
34
34
|
...project.events && { events: project.events },
|
|
35
|
+
...project.webhooks && { webhooks: project.webhooks },
|
|
36
|
+
jobs: jobDefinitions(project.jobs ?? {}),
|
|
35
37
|
close: async () => {
|
|
36
38
|
await ownDb?.destroy();
|
|
37
39
|
}
|
package/dist/migration/parts.js
CHANGED
|
@@ -1,14 +1,27 @@
|
|
|
1
|
-
import { authSchemaMigration, changesMigration } from "@protobase/server";
|
|
1
|
+
import { authSchemaMigration, changesMigration, jobsSchemaMigration, webhooksMigration } from "@protobase/server";
|
|
2
2
|
//#region src/migration/parts.ts
|
|
3
3
|
/** Every feature the project's config enables, in the order their files are written. */
|
|
4
|
-
const migrationParts = (project) => [
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
4
|
+
const migrationParts = (project) => [
|
|
5
|
+
...project.auth ? [{
|
|
6
|
+
name: "auth",
|
|
7
|
+
title: "The auth schema changes this version of Protobase needs",
|
|
8
|
+
sql: () => authSchemaMigration(project.auth)
|
|
9
|
+
}] : [],
|
|
10
|
+
...project.jobs.length > 0 || project.models.some((model) => model.events) || project.webhooks ? [{
|
|
11
|
+
name: "jobs",
|
|
12
|
+
title: "The jobs schema this version of Protobase needs",
|
|
13
|
+
sql: () => jobsSchemaMigration(project.db)
|
|
14
|
+
}] : [],
|
|
15
|
+
{
|
|
16
|
+
name: "changes",
|
|
17
|
+
title: "The change capture the resources' events need",
|
|
18
|
+
sql: () => changesMigration(project.db, project.models, project.events)
|
|
19
|
+
},
|
|
20
|
+
...project.webhooks ? [{
|
|
21
|
+
name: "webhooks",
|
|
22
|
+
title: "The webhook subscriptions of webhooks()",
|
|
23
|
+
sql: () => webhooksMigration(project.db, project.webhooks, project.events)
|
|
24
|
+
}] : []
|
|
25
|
+
];
|
|
13
26
|
//#endregion
|
|
14
27
|
export { migrationParts };
|
|
@@ -7,7 +7,7 @@ import path from "node:path";
|
|
|
7
7
|
const out = (text) => process.stdout.write(text);
|
|
8
8
|
const collect = (value, previous) => [...previous, value];
|
|
9
9
|
const registerMigration = (program) => {
|
|
10
|
-
program.command("migration").description("Write what the database still needs for every feature the config enables (auth, events) as the project's next SQL migrations").option("--dir <dir>", "migrations folder", "db/migrations").option("--extend <dir>", "merge the protobase.config.ts in this folder before the project's, as dev and build do, repeatable", collect, []).action(async (opts) => {
|
|
10
|
+
program.command("migration").description("Write what the database still needs for every feature the config enables (auth, events, jobs) as the project's next SQL migrations").option("--dir <dir>", "migrations folder", "db/migrations").option("--extend <dir>", "merge the protobase.config.ts in this folder before the project's, as dev and build do, repeatable", collect, []).action(async (opts) => {
|
|
11
11
|
const project = await loadMigrationProject(process.cwd(), resolveExtensions(opts.extend));
|
|
12
12
|
try {
|
|
13
13
|
const files = await writeMigrations(migrationParts(project), path.resolve(opts.dir));
|
package/dist/package.js
CHANGED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { configExports, createAdmin, jobDefinitions } from "@protobase/server";
|
|
2
|
+
//#region src/project/project-admin.ts
|
|
3
|
+
/**
|
|
4
|
+
* The admin API of a project over `db`, as `dev`, `serve` and `worker` build it: its config module's resources, views,
|
|
5
|
+
* pages and subscriptions, and the rest of its config. `jobs` are the project's own and the delivery of its events.
|
|
6
|
+
*/
|
|
7
|
+
const projectAdmin = (project, config, db) => {
|
|
8
|
+
const { resources, views, pages, userMenu, subscriptions } = configExports(config);
|
|
9
|
+
const own = jobDefinitions(project.jobs ?? {});
|
|
10
|
+
const admin = createAdmin({
|
|
11
|
+
resources,
|
|
12
|
+
views,
|
|
13
|
+
pages,
|
|
14
|
+
...userMenu && { userMenu },
|
|
15
|
+
db,
|
|
16
|
+
authenticate: project.authenticate,
|
|
17
|
+
...project.auth && { auth: project.auth },
|
|
18
|
+
...project.functions && { functions: project.functions },
|
|
19
|
+
...project.files && { files: project.files },
|
|
20
|
+
...project.events && { events: project.events },
|
|
21
|
+
...project.webhooks && { webhooks: project.webhooks },
|
|
22
|
+
jobs: own,
|
|
23
|
+
subscriptions,
|
|
24
|
+
options: {
|
|
25
|
+
onUnhandledError: (error) => console.error(error),
|
|
26
|
+
...project.options
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
return {
|
|
30
|
+
admin,
|
|
31
|
+
jobs: [...own, ...admin.jobs]
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
//#endregion
|
|
35
|
+
export { projectAdmin };
|
package/dist/serve/app.js
CHANGED
|
@@ -1,31 +1,18 @@
|
|
|
1
1
|
import { isApiPath } from "../bundle/manifest.js";
|
|
2
2
|
import { serveStaticSite } from "./static-site.js";
|
|
3
|
-
import {
|
|
3
|
+
import { jobsDrainApp } from "@protobase/server";
|
|
4
4
|
import { Hono } from "hono";
|
|
5
5
|
import { logger } from "hono/logger";
|
|
6
6
|
//#region src/serve/app.ts
|
|
7
|
-
const createServeApp = ({
|
|
8
|
-
const { resources, views, pages, userMenu } = configExports(project.config);
|
|
9
|
-
const admin = createAdmin({
|
|
10
|
-
resources,
|
|
11
|
-
views,
|
|
12
|
-
pages,
|
|
13
|
-
...userMenu && { userMenu },
|
|
14
|
-
db,
|
|
15
|
-
authenticate: project.authenticate,
|
|
16
|
-
...project.auth && { auth: project.auth },
|
|
17
|
-
...project.functions && { functions: project.functions },
|
|
18
|
-
...project.files && { files: project.files },
|
|
19
|
-
...project.events && { events: project.events },
|
|
20
|
-
options: {
|
|
21
|
-
onUnhandledError: (error) => console.error(error),
|
|
22
|
-
...project.options
|
|
23
|
-
}
|
|
24
|
-
});
|
|
7
|
+
const createServeApp = ({ admin, requestLog, site, jobs, drainToken }) => {
|
|
25
8
|
const app = new Hono();
|
|
26
9
|
if (requestLog) app.use(logger());
|
|
27
10
|
app.get("/health", (c) => c.json({ status: "ok" }));
|
|
28
11
|
if (site) app.use("*", (c, next) => isApiPath(site.api, c.req.path) ? next() : serveStaticSite(site, c.req.raw));
|
|
12
|
+
if (jobs && drainToken) app.route("/", jobsDrainApp({
|
|
13
|
+
runtime: jobs,
|
|
14
|
+
token: drainToken
|
|
15
|
+
}));
|
|
29
16
|
app.route("/", admin);
|
|
30
17
|
return app;
|
|
31
18
|
};
|
package/dist/serve/env.js
CHANGED
|
@@ -5,11 +5,15 @@ const readServeEnv = (env) => {
|
|
|
5
5
|
if (!Number.isInteger(port) || port < 0 || port > 65535) throw new Error(`PORT must be a port number, not "${env.PORT}"`);
|
|
6
6
|
const minutes = env.PROTOBASE_FILES_CLEANUP_MINUTES ? Number(env.PROTOBASE_FILES_CLEANUP_MINUTES) : 60;
|
|
7
7
|
if (!Number.isInteger(minutes) || minutes < 0) throw new Error(`PROTOBASE_FILES_CLEANUP_MINUTES must be a whole number of minutes, not "${env.PROTOBASE_FILES_CLEANUP_MINUTES}"`);
|
|
8
|
+
const jobs = env.PROTOBASE_JOBS ?? "on";
|
|
9
|
+
if (jobs !== "on" && jobs !== "off") throw new Error(`PROTOBASE_JOBS must be on or off, not "${jobs}"`);
|
|
8
10
|
return {
|
|
9
11
|
port,
|
|
10
12
|
databaseUrl: env.DATABASE_URL || void 0,
|
|
11
13
|
requestLog: Boolean(env.REQUEST_LOG),
|
|
12
|
-
filesCleanupMinutes: minutes
|
|
14
|
+
filesCleanupMinutes: minutes,
|
|
15
|
+
runJobs: jobs === "on",
|
|
16
|
+
...env.PROTOBASE_JOBS_DRAIN_TOKEN && { drainToken: env.PROTOBASE_JOBS_DRAIN_TOKEN }
|
|
13
17
|
};
|
|
14
18
|
};
|
|
15
19
|
//#endregion
|
package/dist/serve/lifecycle.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import { projectAdmin } from "../project/project-admin.js";
|
|
1
2
|
import { createPgDb } from "../project/pg-db.js";
|
|
2
3
|
import { createServeApp } from "./app.js";
|
|
3
4
|
import { startCleanupTimer } from "./cleanup-timer.js";
|
|
4
|
-
import { checkAuthSchema, checkChanges, configExports, createFileCleanup } from "@protobase/server";
|
|
5
|
+
import { checkAuthSchema, checkChanges, checkJobsSchema, checkWebhooksSchema, configExports, createFileCleanup, startJobs } from "@protobase/server";
|
|
5
6
|
import { createAdaptorServer } from "@hono/node-server";
|
|
6
7
|
import pg from "pg";
|
|
7
8
|
//#region src/serve/lifecycle.ts
|
|
@@ -19,14 +20,35 @@ const startServe = async ({ project, env, createDb = (url) => createPgDb(pg, url
|
|
|
19
20
|
const ownDb = project.db ? void 0 : createDb(env.databaseUrl);
|
|
20
21
|
const db = project.db ?? ownDb;
|
|
21
22
|
const { resources } = configExports(project.config);
|
|
22
|
-
const
|
|
23
|
-
project
|
|
24
|
-
db,
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
23
|
+
const startJobsAndListen = async () => {
|
|
24
|
+
await checkChanges(db, resources.map((resource) => resource.toModel()), project.events);
|
|
25
|
+
if (project.webhooks) await checkWebhooksSchema(db, project.webhooks);
|
|
26
|
+
const { admin, jobs: definitions } = projectAdmin(project, project.config, db);
|
|
27
|
+
if (definitions.length > 0) await checkJobsSchema(db);
|
|
28
|
+
const jobs = definitions.length > 0 ? await startJobs({
|
|
29
|
+
db,
|
|
30
|
+
jobs: definitions,
|
|
31
|
+
work: env.runJobs,
|
|
32
|
+
onError: (error) => console.error(error)
|
|
33
|
+
}) : void 0;
|
|
34
|
+
const app = createServeApp({
|
|
35
|
+
admin,
|
|
36
|
+
requestLog: env.requestLog,
|
|
37
|
+
site,
|
|
38
|
+
...jobs && { jobs },
|
|
39
|
+
...env.drainToken && { drainToken: env.drainToken }
|
|
40
|
+
});
|
|
41
|
+
const server = createAdaptorServer({ fetch: app.fetch });
|
|
42
|
+
await listen(server, env.port).catch(async (error) => {
|
|
43
|
+
await jobs?.stop();
|
|
44
|
+
throw error;
|
|
45
|
+
});
|
|
46
|
+
return {
|
|
47
|
+
server,
|
|
48
|
+
jobs
|
|
49
|
+
};
|
|
50
|
+
};
|
|
51
|
+
const { server, jobs } = await startJobsAndListen().catch(async (error) => {
|
|
30
52
|
await ownDb?.destroy();
|
|
31
53
|
throw error;
|
|
32
54
|
});
|
|
@@ -39,6 +61,7 @@ const startServe = async ({ project, env, createDb = (url) => createPgDb(pg, url
|
|
|
39
61
|
const close = async () => {
|
|
40
62
|
await closeServer(server);
|
|
41
63
|
await timer?.stop();
|
|
64
|
+
await jobs?.stop();
|
|
42
65
|
await ownDb?.destroy();
|
|
43
66
|
};
|
|
44
67
|
return {
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { readManifest } from "../bundle/manifest.js";
|
|
2
|
+
import { checkBundleVersion } from "../serve/bundle-version.js";
|
|
3
|
+
import { projectAdmin } from "../project/project-admin.js";
|
|
4
|
+
import { createPgDb } from "../project/pg-db.js";
|
|
5
|
+
import { loadBundle } from "../serve/load-bundle.js";
|
|
6
|
+
import { statSync } from "node:fs";
|
|
7
|
+
import path from "node:path";
|
|
8
|
+
import { checkJobsSchema, configExports, jobDefinitions, startJobs } from "@protobase/server";
|
|
9
|
+
import pg from "pg";
|
|
10
|
+
//#region src/worker/start-worker.ts
|
|
11
|
+
const bundleConfigFile = async (bundle) => {
|
|
12
|
+
if (!statSync(bundle).isDirectory()) return bundle;
|
|
13
|
+
return path.join(bundle, (await readManifest(bundle)).server);
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Runs the project's jobs, and nothing else, until `stop`: the same handlers `protobase serve` runs, in a process of
|
|
17
|
+
* their own. It reads the jobs schema at start and refuses one that is missing or behind, like `serve`.
|
|
18
|
+
*/
|
|
19
|
+
const startWorker = async ({ project, databaseUrl, createDb = (url) => createPgDb(pg, url) }) => {
|
|
20
|
+
const withEvents = configExports(project.config).resources.some((resource) => resource.toModel().events);
|
|
21
|
+
if (jobDefinitions(project.jobs ?? {}).length === 0 && !withEvents) throw new Error("The bundle has no jobs: export them from protobase.config.ts as `jobs`, or give a resource events");
|
|
22
|
+
if (!project.db && !databaseUrl) throw new Error("No database: set DATABASE_URL or export `db` from protobase.config.ts");
|
|
23
|
+
const ownDb = project.db ? void 0 : createDb(databaseUrl);
|
|
24
|
+
const db = project.db ?? ownDb;
|
|
25
|
+
const start = async () => {
|
|
26
|
+
const { jobs: definitions } = projectAdmin(project, project.config, db);
|
|
27
|
+
await checkJobsSchema(db);
|
|
28
|
+
return {
|
|
29
|
+
definitions,
|
|
30
|
+
runtime: await startJobs({
|
|
31
|
+
db,
|
|
32
|
+
jobs: definitions,
|
|
33
|
+
onError: (error) => console.error(error)
|
|
34
|
+
})
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
const { definitions, runtime: jobs } = await start().catch(async (error) => {
|
|
38
|
+
await ownDb?.destroy();
|
|
39
|
+
throw error;
|
|
40
|
+
});
|
|
41
|
+
return {
|
|
42
|
+
jobs: definitions.length,
|
|
43
|
+
stop: async () => {
|
|
44
|
+
await jobs.stop();
|
|
45
|
+
await ownDb?.destroy();
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
/** `protobase worker <bundle>`: the bundle's jobs until SIGTERM or SIGINT, once its manifest shows a version this CLI runs. */
|
|
50
|
+
const loadWorkerBundle = async (bundle) => {
|
|
51
|
+
const file = await bundleConfigFile(bundle);
|
|
52
|
+
await checkBundleVersion(file);
|
|
53
|
+
return loadBundle(file);
|
|
54
|
+
};
|
|
55
|
+
//#endregion
|
|
56
|
+
export { bundleConfigFile, loadWorkerBundle, startWorker };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@protobase/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "The protobase command: scaffold, doctor, dev, build and serve a Protobase project.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -34,11 +34,11 @@
|
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"@hono/node-server": "^2.1.3",
|
|
36
36
|
"@hono/vite-dev-server": "^0.26.1",
|
|
37
|
-
"@protobase/layout": "0.
|
|
38
|
-
"@protobase/query": "0.
|
|
39
|
-
"@protobase/schema": "0.
|
|
40
|
-
"@protobase/server": "0.
|
|
41
|
-
"@protobase/ui": "0.
|
|
37
|
+
"@protobase/layout": "0.9.0",
|
|
38
|
+
"@protobase/query": "0.9.0",
|
|
39
|
+
"@protobase/schema": "0.9.0",
|
|
40
|
+
"@protobase/server": "0.9.0",
|
|
41
|
+
"@protobase/ui": "0.9.0",
|
|
42
42
|
"@scalar/hono-api-reference": "^0.12.10",
|
|
43
43
|
"@tailwindcss/vite": "^4.3.3",
|
|
44
44
|
"@vitejs/plugin-react": "^6.1.2",
|