@protobase/cli 0.12.4 → 0.12.5

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/entry.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { devJobs } from "./dev-jobs.js";
2
+ import { projectErrorReporter } from "../project/error-reporter.js";
2
3
  import { projectAdmin } from "../project/project-admin.js";
3
4
  import { loadProject, projectDb } from "./project.js";
4
5
  import { checkAuthSchema, checkChanges, checkWebhooksSchema, configExports, hasUsers } from "@protobase/server";
@@ -16,10 +17,11 @@ if (project.auth && !store.__protobaseAuthSchemaChecked) {
16
17
  }
17
18
  await checkChanges(db, resources.map((resource) => resource.toModel()), project.events);
18
19
  if (project.webhooks) await checkWebhooksSchema(db, project.webhooks);
20
+ const reporter = await projectErrorReporter(project, process.env);
19
21
  const { admin, jobs } = projectAdmin({
20
22
  ...project,
21
23
  authenticate: project.authenticate
22
- }, project.exports, db);
24
+ }, project.exports, db, void 0, reporter);
23
25
  await devJobs(db, jobs);
24
26
  var entry_default = new Hono().route("/", admin);
25
27
  if (project.auth && !store.__protobaseNoUsersShown) {
package/dist/dev/run.js CHANGED
@@ -41,7 +41,8 @@ const appDependencies = [
41
41
  "@tanstack/react-query",
42
42
  "@tanstack/react-table",
43
43
  "@tanstack/react-virtual",
44
- "recharts"
44
+ "recharts",
45
+ "@sentry/browser"
45
46
  ];
46
47
  const runDev = async (options, out) => {
47
48
  loadNearestEnvFile(options.projectDir);
package/dist/main.js CHANGED
@@ -10,7 +10,9 @@ import { resolveConnectionUrl } from "./db/connect.js";
10
10
  import { parseHosts } from "./dev/hosts.js";
11
11
  import { runDev } from "./dev/run.js";
12
12
  import { runDoctor } from "./doctor/run.js";
13
+ import { projectErrorReporter } from "./project/error-reporter.js";
13
14
  import { runScaffold } from "./scaffold/run.js";
15
+ import { reportCrashes } from "./serve/crash-reports.js";
14
16
  import { closeOnSignals } from "./serve/signals.js";
15
17
  import { serveBundle } from "./serve/serve-bundle.js";
16
18
  import { serveBundleDir } from "./serve/serve-dir.js";
@@ -110,8 +112,11 @@ program.command("serve").description("Serve a bundle written by `protobase build
110
112
  });
111
113
  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) => {
112
114
  loadNearestEnvFile(process.cwd());
115
+ const project = await loadWorkerBundle(bundle);
116
+ const reporter = await projectErrorReporter(project, process.env);
117
+ if (reporter) reportCrashes(reporter);
113
118
  const worker = await startWorker({
114
- project: await loadWorkerBundle(bundle),
119
+ project,
115
120
  databaseUrl: process.env.DATABASE_URL || void 0
116
121
  });
117
122
  closeOnSignals(worker.stop);
package/dist/package.js CHANGED
@@ -1,4 +1,4 @@
1
1
  //#region package.json
2
- var version = "0.12.4";
2
+ var version = "0.12.5";
3
3
  //#endregion
4
4
  export { version };
@@ -0,0 +1,9 @@
1
+ import { errorReportingSettings, startErrorReporting } from "@protobase/server";
2
+ //#region src/project/error-reporter.ts
3
+ /** The project's error reporter, when its `options.errorReporting` or `PROTOBASE_SENTRY_DSN` sets a DSN. */
4
+ const projectErrorReporter = async (project, env) => {
5
+ const settings = errorReportingSettings(project.options?.errorReporting, env);
6
+ return settings ? startErrorReporting(settings) : void 0;
7
+ };
8
+ //#endregion
9
+ export { projectErrorReporter };
@@ -3,11 +3,13 @@ import { configExports, createAdmin, jobDefinitions } from "@protobase/server";
3
3
  /**
4
4
  * The admin API of a project over `db`, as `dev`, `serve` and `worker` build it: its config module's resources, views,
5
5
  * pages and subscriptions, and the rest of its config; served from a bundle, the plugins it carries and their field
6
- * types. `jobs` are the project's own and the delivery of its events.
6
+ * types. `jobs` are the project's own and the delivery of its events. With a `reporter`, every error the API turns
7
+ * into a 500 goes to the error tracker too, besides the project's `onUnhandledError` or the console.
7
8
  */
8
- const projectAdmin = (project, config, db, ui) => {
9
+ const projectAdmin = (project, config, db, ui, reporter) => {
9
10
  const { resources, views, pages, userMenu, bottomBars, subscriptions } = configExports(config);
10
11
  const own = jobDefinitions(project.jobs ?? {});
12
+ const unhandled = project.options?.onUnhandledError ?? ((error) => console.error(error));
11
13
  const admin = createAdmin({
12
14
  resources,
13
15
  views,
@@ -28,8 +30,11 @@ const projectAdmin = (project, config, db, ui) => {
28
30
  fieldTypes: ui.fieldTypes
29
31
  },
30
32
  options: {
31
- onUnhandledError: (error) => console.error(error),
32
- ...project.options
33
+ ...project.options,
34
+ onUnhandledError: (error, request) => {
35
+ reporter?.report(error, request);
36
+ unhandled(error, request);
37
+ }
33
38
  }
34
39
  });
35
40
  return {
@@ -0,0 +1,16 @@
1
+ //#region src/serve/crash-reports.ts
2
+ /**
3
+ * Reports an exception or a rejection nothing handled, then ends the process as Node and Bun do without a listener:
4
+ * the error printed, exit code 1. The report has `flushMs` to reach the error tracker.
5
+ */
6
+ const reportCrashes = (reporter, target = process, flushMs = 2e3) => {
7
+ const crash = (error) => {
8
+ console.error(error);
9
+ reporter.report(error);
10
+ reporter.flush(flushMs).then(() => target.exit(1));
11
+ };
12
+ target.on("uncaughtException", crash);
13
+ target.on("unhandledRejection", crash);
14
+ };
15
+ //#endregion
16
+ export { reportCrashes };
@@ -14,7 +14,7 @@ const listen = (server, port) => new Promise((resolve, reject) => {
14
14
  });
15
15
  });
16
16
  const closeServer = (server) => new Promise((resolve, reject) => server.close((error) => error ? reject(error) : resolve()));
17
- const startServe = async ({ project, env, createDb = (url) => createPgDb(pg, url), site, ui }) => {
17
+ const startServe = async ({ project, env, createDb = (url) => createPgDb(pg, url), site, ui, reporter }) => {
18
18
  if (!project.db && !env.databaseUrl) throw new Error("No database: set DATABASE_URL or export `db` from protobase.config.ts");
19
19
  if (project.auth) await checkAuthSchema(project.auth);
20
20
  const ownDb = project.db ? void 0 : createDb(env.databaseUrl);
@@ -23,7 +23,7 @@ const startServe = async ({ project, env, createDb = (url) => createPgDb(pg, url
23
23
  const startJobsAndListen = async () => {
24
24
  await checkChanges(db, resources.map((resource) => resource.toModel()), project.events);
25
25
  if (project.webhooks) await checkWebhooksSchema(db, project.webhooks);
26
- const { admin, jobs: definitions } = projectAdmin(project, project.config, db, ui);
26
+ const { admin, jobs: definitions } = projectAdmin(project, project.config, db, ui, reporter);
27
27
  if (definitions.length > 0) await checkJobsSchema(db);
28
28
  const jobs = definitions.length > 0 ? await startJobs({
29
29
  db,
@@ -1,6 +1,8 @@
1
1
  import { readManifest } from "../bundle/manifest.js";
2
+ import { projectErrorReporter } from "../project/error-reporter.js";
2
3
  import { bundleUi } from "./bundle-ui.js";
3
4
  import { checkBundleVersion } from "./bundle-version.js";
5
+ import { reportCrashes } from "./crash-reports.js";
4
6
  import { readServeEnv } from "./env.js";
5
7
  import { startServe } from "./lifecycle.js";
6
8
  import { loadBundle } from "./load-bundle.js";
@@ -12,11 +14,14 @@ const serveBundle = async (file, env, out, site) => {
12
14
  await checkBundleVersion(file);
13
15
  const manifest = await readManifest(path.dirname(file));
14
16
  const project = await loadBundle(file);
17
+ const reporter = await projectErrorReporter(project, env);
18
+ if (reporter) reportCrashes(reporter);
15
19
  const server = await startServe({
16
20
  project,
17
21
  env: serveEnv,
18
22
  site,
19
- ui: bundleUi(manifest)
23
+ ui: bundleUi(manifest),
24
+ ...reporter && { reporter }
20
25
  });
21
26
  closeOnSignals(server.close);
22
27
  out(`protobase serve listening on port ${server.port}\n`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@protobase/cli",
3
- "version": "0.12.4",
3
+ "version": "0.12.5",
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.12.4",
38
- "@protobase/query": "0.12.4",
39
- "@protobase/schema": "0.12.4",
40
- "@protobase/server": "0.12.4",
41
- "@protobase/ui": "0.12.4",
37
+ "@protobase/layout": "0.12.5",
38
+ "@protobase/query": "0.12.5",
39
+ "@protobase/schema": "0.12.5",
40
+ "@protobase/server": "0.12.5",
41
+ "@protobase/ui": "0.12.5",
42
42
  "@scalar/hono-api-reference": "^0.12.10",
43
43
  "@tailwindcss/vite": "^4.3.3",
44
44
  "@vitejs/plugin-react": "^6.1.2",