@nifrajs/cli 3.5.0 → 4.0.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 +42 -3
- package/dist/app-files.d.ts +11 -0
- package/dist/app-files.d.ts.map +1 -0
- package/dist/app-files.js +34 -0
- package/dist/app-files.js.map +1 -0
- package/dist/assure-hydration.d.ts +7 -1
- package/dist/assure-hydration.d.ts.map +1 -1
- package/dist/assure-hydration.js +128 -43
- package/dist/assure-hydration.js.map +1 -1
- package/dist/assure.d.ts.map +1 -1
- package/dist/assure.js +16 -2
- package/dist/assure.js.map +1 -1
- package/dist/capabilities-tool.d.ts +5 -1
- package/dist/capabilities-tool.d.ts.map +1 -1
- package/dist/capabilities-tool.js +32 -10
- package/dist/capabilities-tool.js.map +1 -1
- package/dist/cdn-check.d.ts +41 -0
- package/dist/cdn-check.d.ts.map +1 -0
- package/dist/cdn-check.js +207 -0
- package/dist/cdn-check.js.map +1 -0
- package/dist/check-diagnostics.d.ts +4 -0
- package/dist/check-diagnostics.d.ts.map +1 -1
- package/dist/check-diagnostics.js +13 -0
- package/dist/check-diagnostics.js.map +1 -1
- package/dist/check-scan.d.ts +49 -7
- package/dist/check-scan.d.ts.map +1 -1
- package/dist/check-scan.js +291 -62
- package/dist/check-scan.js.map +1 -1
- package/dist/check.d.ts.map +1 -1
- package/dist/check.js +99 -63
- package/dist/check.js.map +1 -1
- package/dist/cli.d.ts +42 -16
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +262 -82
- package/dist/cli.js.map +1 -1
- package/dist/command-catalog.d.ts +62 -5
- package/dist/command-catalog.d.ts.map +1 -1
- package/dist/command-catalog.js +275 -35
- package/dist/command-catalog.js.map +1 -1
- package/dist/config-target.d.ts +8 -0
- package/dist/config-target.d.ts.map +1 -0
- package/dist/config-target.js +45 -0
- package/dist/config-target.js.map +1 -0
- package/dist/contracts.d.ts.map +1 -1
- package/dist/contracts.js +52 -13
- package/dist/contracts.js.map +1 -1
- package/dist/db-audit.d.ts +37 -0
- package/dist/db-audit.d.ts.map +1 -0
- package/dist/db-audit.js +99 -0
- package/dist/db-audit.js.map +1 -0
- package/dist/db-child.d.ts +64 -0
- package/dist/db-child.d.ts.map +1 -0
- package/dist/db-child.js +213 -0
- package/dist/db-child.js.map +1 -0
- package/dist/db-config.d.ts +60 -0
- package/dist/db-config.d.ts.map +1 -0
- package/dist/db-config.js +176 -0
- package/dist/db-config.js.map +1 -0
- package/dist/db-tool.d.ts +84 -0
- package/dist/db-tool.d.ts.map +1 -0
- package/dist/db-tool.js +537 -0
- package/dist/db-tool.js.map +1 -0
- package/dist/dev-bun-config.d.ts +20 -13
- package/dist/dev-bun-config.d.ts.map +1 -1
- package/dist/dev-bun-config.js +98 -41
- package/dist/dev-bun-config.js.map +1 -1
- package/dist/dev-feed-tool.d.ts +106 -0
- package/dist/dev-feed-tool.d.ts.map +1 -0
- package/dist/dev-feed-tool.js +713 -0
- package/dist/dev-feed-tool.js.map +1 -0
- package/dist/dev-server-client.d.ts +67 -0
- package/dist/dev-server-client.d.ts.map +1 -0
- package/dist/dev-server-client.js +195 -0
- package/dist/dev-server-client.js.map +1 -0
- package/dist/diff-tool.d.ts +3 -3
- package/dist/diff-tool.d.ts.map +1 -1
- package/dist/diff-tool.js +6 -5
- package/dist/diff-tool.js.map +1 -1
- package/dist/docs-search.d.ts.map +1 -1
- package/dist/docs-search.js +12 -4
- package/dist/docs-search.js.map +1 -1
- package/dist/doctor.d.ts +17 -0
- package/dist/doctor.d.ts.map +1 -1
- package/dist/doctor.js +76 -15
- package/dist/doctor.js.map +1 -1
- package/dist/env-file.d.ts +15 -0
- package/dist/env-file.d.ts.map +1 -1
- package/dist/env-file.js +73 -1
- package/dist/env-file.js.map +1 -1
- package/dist/fix-recipes.d.ts.map +1 -1
- package/dist/fix-recipes.js +48 -22
- package/dist/fix-recipes.js.map +1 -1
- package/dist/frontend-guidance.js +5 -5
- package/dist/frontend-guidance.js.map +1 -1
- package/dist/i18n-check.d.ts +16 -0
- package/dist/i18n-check.d.ts.map +1 -0
- package/dist/i18n-check.js +154 -0
- package/dist/i18n-check.js.map +1 -0
- package/dist/init-agents.d.ts +49 -13
- package/dist/init-agents.d.ts.map +1 -1
- package/dist/init-agents.js +239 -34
- package/dist/init-agents.js.map +1 -1
- package/dist/internal/code-unit-order.d.ts +4 -0
- package/dist/internal/code-unit-order.d.ts.map +1 -0
- package/dist/internal/code-unit-order.js +6 -0
- package/dist/internal/code-unit-order.js.map +1 -0
- package/dist/internal/script-kind.d.ts +7 -0
- package/dist/internal/script-kind.d.ts.map +1 -0
- package/dist/internal/script-kind.js +12 -0
- package/dist/internal/script-kind.js.map +1 -0
- package/dist/internal/source-facts.d.ts +5 -0
- package/dist/internal/source-facts.d.ts.map +1 -1
- package/dist/internal/source-facts.js +61 -5
- package/dist/internal/source-facts.js.map +1 -1
- package/dist/internal/typescript-import.d.ts +49 -24
- package/dist/internal/typescript-import.d.ts.map +1 -1
- package/dist/internal/typescript-import.js +507 -67
- package/dist/internal/typescript-import.js.map +1 -1
- package/dist/introspect.d.ts +5 -1
- package/dist/introspect.d.ts.map +1 -1
- package/dist/introspect.js +92 -27
- package/dist/introspect.js.map +1 -1
- package/dist/learn.js +3 -3
- package/dist/learn.js.map +1 -1
- package/dist/levels-tool.d.ts +10 -0
- package/dist/levels-tool.d.ts.map +1 -1
- package/dist/levels-tool.js +33 -3
- package/dist/levels-tool.js.map +1 -1
- package/dist/load.d.ts +67 -17
- package/dist/load.d.ts.map +1 -1
- package/dist/load.js +78 -18
- package/dist/load.js.map +1 -1
- package/dist/manifest-tool.d.ts.map +1 -1
- package/dist/manifest-tool.js +3 -2
- package/dist/manifest-tool.js.map +1 -1
- package/dist/mcp-app-tool.d.ts.map +1 -1
- package/dist/mcp-app-tool.js +2 -0
- package/dist/mcp-app-tool.js.map +1 -1
- package/dist/mcp-context.js +1 -1
- package/dist/mcp-context.js.map +1 -1
- package/dist/mcp-delegate.d.ts +57 -0
- package/dist/mcp-delegate.d.ts.map +1 -0
- package/dist/mcp-delegate.js +130 -0
- package/dist/mcp-delegate.js.map +1 -0
- package/dist/mcp-docs-tools.d.ts.map +1 -1
- package/dist/mcp-docs-tools.js +23 -5
- package/dist/mcp-docs-tools.js.map +1 -1
- package/dist/mcp-exec.d.ts +2 -0
- package/dist/mcp-exec.d.ts.map +1 -1
- package/dist/mcp-exec.js +132 -108
- package/dist/mcp-exec.js.map +1 -1
- package/dist/mcp-http.d.ts.map +1 -1
- package/dist/mcp-http.js +17 -5
- package/dist/mcp-http.js.map +1 -1
- package/dist/mcp-io.d.ts +14 -0
- package/dist/mcp-io.d.ts.map +1 -1
- package/dist/mcp-io.js +45 -0
- package/dist/mcp-io.js.map +1 -1
- package/dist/mcp-isolate.d.ts +48 -0
- package/dist/mcp-isolate.d.ts.map +1 -0
- package/dist/mcp-isolate.js +222 -0
- package/dist/mcp-isolate.js.map +1 -0
- package/dist/mcp-project-child.d.ts +74 -0
- package/dist/mcp-project-child.d.ts.map +1 -0
- package/dist/mcp-project-child.js +130 -0
- package/dist/mcp-project-child.js.map +1 -0
- package/dist/mcp-render.js +2 -2
- package/dist/mcp-render.js.map +1 -1
- package/dist/mcp-root.d.ts +37 -9
- package/dist/mcp-root.d.ts.map +1 -1
- package/dist/mcp-root.js +110 -23
- package/dist/mcp-root.js.map +1 -1
- package/dist/mcp-run.d.ts +18 -1
- package/dist/mcp-run.d.ts.map +1 -1
- package/dist/mcp-run.js +82 -9
- package/dist/mcp-run.js.map +1 -1
- package/dist/mcp-ws.js +4 -1
- package/dist/mcp-ws.js.map +1 -1
- package/dist/mcp.d.ts +16 -3
- package/dist/mcp.d.ts.map +1 -1
- package/dist/mcp.js +81 -53
- package/dist/mcp.js.map +1 -1
- package/dist/migrate-layout.d.ts +44 -0
- package/dist/migrate-layout.d.ts.map +1 -0
- package/dist/migrate-layout.js +1155 -0
- package/dist/migrate-layout.js.map +1 -0
- package/dist/openapi-tool.d.ts +2 -2
- package/dist/openapi-tool.d.ts.map +1 -1
- package/dist/openapi-tool.js.map +1 -1
- package/dist/openapi-types.d.ts +2 -1
- package/dist/openapi-types.d.ts.map +1 -1
- package/dist/openapi-types.js +240 -12
- package/dist/openapi-types.js.map +1 -1
- package/dist/pipeline-report.d.ts +3 -2
- package/dist/pipeline-report.d.ts.map +1 -1
- package/dist/pipeline-report.js +19 -16
- package/dist/pipeline-report.js.map +1 -1
- package/dist/port.d.ts +5 -4
- package/dist/port.d.ts.map +1 -1
- package/dist/port.js +46 -29
- package/dist/port.js.map +1 -1
- package/dist/project-facts.d.ts +5 -0
- package/dist/project-facts.d.ts.map +1 -1
- package/dist/project-facts.js.map +1 -1
- package/dist/recipes/4.0.0.d.ts +9 -0
- package/dist/recipes/4.0.0.d.ts.map +1 -0
- package/dist/recipes/4.0.0.js +36 -0
- package/dist/recipes/4.0.0.js.map +1 -0
- package/dist/recipes/index.d.ts.map +1 -1
- package/dist/recipes/index.js +2 -0
- package/dist/recipes/index.js.map +1 -1
- package/dist/release-verification.d.ts +11 -1
- package/dist/release-verification.d.ts.map +1 -1
- package/dist/release-verification.js +47 -4
- package/dist/release-verification.js.map +1 -1
- package/dist/review.d.ts.map +1 -1
- package/dist/review.js +12 -8
- package/dist/review.js.map +1 -1
- package/dist/route-types.d.ts +28 -0
- package/dist/route-types.d.ts.map +1 -0
- package/dist/route-types.js +106 -0
- package/dist/route-types.js.map +1 -0
- package/dist/rules/codes.d.ts +9 -0
- package/dist/rules/codes.d.ts.map +1 -1
- package/dist/rules/codes.js +9 -0
- package/dist/rules/codes.js.map +1 -1
- package/dist/rules/data-guard.d.ts +12 -0
- package/dist/rules/data-guard.d.ts.map +1 -0
- package/dist/rules/data-guard.js +213 -0
- package/dist/rules/data-guard.js.map +1 -0
- package/dist/rules/index.d.ts +3 -0
- package/dist/rules/index.d.ts.map +1 -1
- package/dist/rules/index.js +17 -5
- package/dist/rules/index.js.map +1 -1
- package/dist/rules/islands.d.ts.map +1 -1
- package/dist/rules/islands.js +7 -4
- package/dist/rules/islands.js.map +1 -1
- package/dist/rules/legacy.d.ts.map +1 -1
- package/dist/rules/legacy.js +71 -38
- package/dist/rules/legacy.js.map +1 -1
- package/dist/rules/nano.d.ts.map +1 -1
- package/dist/rules/nano.js +15 -6
- package/dist/rules/nano.js.map +1 -1
- package/dist/rules/pages.d.ts +15 -0
- package/dist/rules/pages.d.ts.map +1 -0
- package/dist/rules/pages.js +88 -0
- package/dist/rules/pages.js.map +1 -0
- package/dist/rules/routes.d.ts +11 -0
- package/dist/rules/routes.d.ts.map +1 -1
- package/dist/rules/routes.js +180 -2
- package/dist/rules/routes.js.map +1 -1
- package/dist/rules/secrets.d.ts +10 -0
- package/dist/rules/secrets.d.ts.map +1 -0
- package/dist/rules/secrets.js +169 -0
- package/dist/rules/secrets.js.map +1 -0
- package/dist/rules/security.d.ts +7 -0
- package/dist/rules/security.d.ts.map +1 -1
- package/dist/rules/security.js +171 -65
- package/dist/rules/security.js.map +1 -1
- package/dist/rules/typescript.d.ts +16 -0
- package/dist/rules/typescript.d.ts.map +1 -0
- package/dist/rules/typescript.js +59 -0
- package/dist/rules/typescript.js.map +1 -0
- package/dist/rules/zones.d.ts +17 -0
- package/dist/rules/zones.d.ts.map +1 -0
- package/dist/rules/zones.js +174 -0
- package/dist/rules/zones.js.map +1 -0
- package/dist/scaffold.d.ts +25 -12
- package/dist/scaffold.d.ts.map +1 -1
- package/dist/scaffold.js +132 -87
- package/dist/scaffold.js.map +1 -1
- package/dist/sdk.d.ts +17 -3
- package/dist/sdk.d.ts.map +1 -1
- package/dist/sdk.js +941 -153
- package/dist/sdk.js.map +1 -1
- package/dist/search-terms.d.ts +2 -0
- package/dist/search-terms.d.ts.map +1 -1
- package/dist/search-terms.js +23 -8
- package/dist/search-terms.js.map +1 -1
- package/dist/smoke.d.ts +79 -0
- package/dist/smoke.d.ts.map +1 -0
- package/dist/smoke.js +494 -0
- package/dist/smoke.js.map +1 -0
- package/dist/sync-manifest.d.ts +10 -2
- package/dist/sync-manifest.d.ts.map +1 -1
- package/dist/sync-manifest.js +44 -19
- package/dist/sync-manifest.js.map +1 -1
- package/dist/sync-routes.d.ts +4 -3
- package/dist/sync-routes.d.ts.map +1 -1
- package/dist/sync-routes.js +4 -3
- package/dist/sync-routes.js.map +1 -1
- package/dist/test-tool.d.ts.map +1 -1
- package/dist/test-tool.js +30 -11
- package/dist/test-tool.js.map +1 -1
- package/dist/types-search.d.ts.map +1 -1
- package/dist/types-search.js +11 -5
- package/dist/types-search.js.map +1 -1
- package/dist/upgrade.d.ts +36 -6
- package/dist/upgrade.d.ts.map +1 -1
- package/dist/upgrade.js +167 -29
- package/dist/upgrade.js.map +1 -1
- package/dist/verification-plan.d.ts.map +1 -1
- package/dist/verification-plan.js +4 -0
- package/dist/verification-plan.js.map +1 -1
- package/dist/verification.d.ts.map +1 -1
- package/dist/verification.js +45 -12
- package/dist/verification.js.map +1 -1
- package/dist/web-app-options.d.ts +19 -0
- package/dist/web-app-options.d.ts.map +1 -0
- package/dist/web-app-options.js +49 -0
- package/dist/web-app-options.js.map +1 -0
- package/dist/work-graph.d.ts.map +1 -1
- package/dist/work-graph.js +29 -13
- package/dist/work-graph.js.map +1 -1
- package/docs/examples.json +185 -29
- package/docs/llms-full.txt +3807 -580
- package/docs/types.json +14229 -10939
- package/package.json +19 -12
- package/src/app-files.ts +40 -0
- package/src/assure-hydration.ts +139 -46
- package/src/assure.ts +17 -2
- package/src/capabilities-tool.ts +35 -9
- package/src/cdn-check.ts +268 -0
- package/src/check-diagnostics.ts +17 -0
- package/src/check-scan.ts +358 -63
- package/src/check.ts +97 -62
- package/src/cli.ts +296 -87
- package/src/command-catalog.ts +389 -48
- package/src/config-target.ts +47 -0
- package/src/contracts.ts +54 -12
- package/src/db-audit.ts +128 -0
- package/src/db-child.ts +285 -0
- package/src/db-config.ts +224 -0
- package/src/db-tool.ts +690 -0
- package/src/dev-bun-config.ts +116 -40
- package/src/dev-feed-tool.ts +912 -0
- package/src/dev-server-client.ts +267 -0
- package/src/diff-tool.ts +6 -5
- package/src/docs-search.ts +10 -3
- package/src/doctor.ts +98 -15
- package/src/env-file.ts +78 -1
- package/src/fix-recipes.ts +53 -32
- package/src/frontend-guidance.ts +5 -5
- package/src/i18n-check.ts +179 -0
- package/src/init-agents.ts +301 -38
- package/src/internal/code-unit-order.ts +5 -0
- package/src/internal/script-kind.ts +11 -0
- package/src/internal/source-facts.ts +96 -22
- package/src/internal/typescript-import.ts +663 -68
- package/src/introspect.ts +90 -27
- package/src/learn.ts +3 -3
- package/src/levels-tool.ts +47 -2
- package/src/load.ts +140 -33
- package/src/manifest-tool.ts +3 -2
- package/src/mcp-app-tool.ts +2 -0
- package/src/mcp-context.ts +1 -1
- package/src/mcp-delegate.ts +162 -0
- package/src/mcp-docs-tools.ts +23 -5
- package/src/mcp-exec.ts +160 -132
- package/src/mcp-http.ts +19 -5
- package/src/mcp-io.ts +57 -0
- package/src/mcp-isolate.ts +287 -0
- package/src/mcp-project-child.ts +182 -0
- package/src/mcp-render.ts +2 -2
- package/src/mcp-root.ts +117 -22
- package/src/mcp-run.ts +104 -10
- package/src/mcp-ws.ts +4 -1
- package/src/mcp.ts +106 -64
- package/src/migrate-layout.ts +1338 -0
- package/src/openapi-tool.ts +7 -3
- package/src/openapi-types.ts +315 -13
- package/src/pipeline-report.ts +22 -18
- package/src/port.ts +53 -30
- package/src/project-facts.ts +5 -0
- package/src/recipes/4.0.0.ts +37 -0
- package/src/recipes/index.ts +2 -0
- package/src/release-verification.ts +74 -5
- package/src/review.ts +13 -8
- package/src/route-types.ts +133 -0
- package/src/rules/codes.ts +9 -0
- package/src/rules/data-guard.ts +230 -0
- package/src/rules/index.ts +18 -5
- package/src/rules/islands.ts +12 -4
- package/src/rules/legacy.ts +71 -39
- package/src/rules/nano.ts +18 -6
- package/src/rules/pages.ts +99 -0
- package/src/rules/routes.ts +181 -2
- package/src/rules/secrets.ts +174 -0
- package/src/rules/security.ts +198 -70
- package/src/rules/typescript.ts +77 -0
- package/src/rules/zones.ts +195 -0
- package/src/scaffold.ts +147 -95
- package/src/sdk.ts +1215 -158
- package/src/search-terms.ts +24 -7
- package/src/smoke.ts +607 -0
- package/src/sync-manifest.ts +50 -19
- package/src/sync-routes.ts +4 -3
- package/src/test-tool.ts +32 -11
- package/src/types-search.ts +11 -4
- package/src/upgrade.ts +205 -25
- package/src/verification-plan.ts +13 -0
- package/src/verification.ts +50 -12
- package/src/web-app-options.ts +57 -0
- package/src/work-graph.ts +27 -13
package/src/db-config.ts
ADDED
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `devDatabase` declaration in `nifra.config.ts`: the one database `nifra db` / `nifra_db_*` may
|
|
3
|
+
* read. Declared explicitly or not at all - `DATABASE_URL` is never read on its own, because it often
|
|
4
|
+
* points at production.
|
|
5
|
+
*
|
|
6
|
+
* export const devDatabase = { kind: "sqlite", file: "./data/app.db" }
|
|
7
|
+
* export const devDatabase = {
|
|
8
|
+
* kind: "postgres",
|
|
9
|
+
* url: process.env.NIFRA_DEV_DATABASE_URL,
|
|
10
|
+
* exclude: ["audit_log"],
|
|
11
|
+
* }
|
|
12
|
+
*
|
|
13
|
+
* The config is imported only inside the query subprocess (`db-child.ts`), after `.env` files load.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { existsSync } from "node:fs"
|
|
17
|
+
import { resolve } from "node:path"
|
|
18
|
+
import { type DbRefusal, dbRefusal } from "@nifrajs/mcp-db/engine"
|
|
19
|
+
import { CONFIG_FILE } from "./app-files.ts"
|
|
20
|
+
import { applyEnvFiles, parseEnvFile } from "./env-file.ts"
|
|
21
|
+
|
|
22
|
+
/** Fields both engines share, with their defaults applied. */
|
|
23
|
+
export interface DevDatabaseCommon {
|
|
24
|
+
/** Tables a query may not read (`name`, or `schema.name` on Postgres). */
|
|
25
|
+
readonly exclude: readonly string[]
|
|
26
|
+
readonly maxRows: number
|
|
27
|
+
readonly maxResultBytes: number
|
|
28
|
+
readonly timeoutMs: number
|
|
29
|
+
/** Columns a query may not read, on top of the credential-name classifier. */
|
|
30
|
+
readonly redactColumns: readonly string[]
|
|
31
|
+
/** Columns the classifier names that a query may read anyway. */
|
|
32
|
+
readonly revealColumns: readonly string[]
|
|
33
|
+
/** `nifra db query` is on for a declared database unless this is false. */
|
|
34
|
+
readonly query: boolean
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface DevSqliteDatabase extends DevDatabaseCommon {
|
|
38
|
+
readonly kind: "sqlite"
|
|
39
|
+
/** Relative to the project root; its real path must stay inside the root. */
|
|
40
|
+
readonly file: string
|
|
41
|
+
/** Paths outside the root that `file` may resolve to. */
|
|
42
|
+
readonly allowFiles: readonly string[]
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface DevPostgresDatabase extends DevDatabaseCommon {
|
|
46
|
+
readonly kind: "postgres"
|
|
47
|
+
readonly url: string
|
|
48
|
+
/** Remote hosts the URL may name; loopback, `*.localhost` and unix sockets need no entry. */
|
|
49
|
+
readonly allowHosts: readonly string[]
|
|
50
|
+
/** Extensions or untrusted languages the role may use without the query being refused. */
|
|
51
|
+
readonly allowExtensions: readonly string[]
|
|
52
|
+
/** Schemas a query may read (default `["public"]`). */
|
|
53
|
+
readonly schemas: readonly string[]
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export type DevDatabase = DevSqliteDatabase | DevPostgresDatabase
|
|
57
|
+
|
|
58
|
+
const COMMON_FIELDS = [
|
|
59
|
+
"kind",
|
|
60
|
+
"exclude",
|
|
61
|
+
"maxRows",
|
|
62
|
+
"maxResultBytes",
|
|
63
|
+
"timeoutMs",
|
|
64
|
+
"redactColumns",
|
|
65
|
+
"revealColumns",
|
|
66
|
+
"query",
|
|
67
|
+
] as const
|
|
68
|
+
const SQLITE_FIELDS = new Set<string>([...COMMON_FIELDS, "file", "allowFiles"])
|
|
69
|
+
const POSTGRES_FIELDS = new Set<string>([
|
|
70
|
+
...COMMON_FIELDS,
|
|
71
|
+
"url",
|
|
72
|
+
"allowHosts",
|
|
73
|
+
"allowExtensions",
|
|
74
|
+
"schemas",
|
|
75
|
+
])
|
|
76
|
+
|
|
77
|
+
/** The `.env` files the subprocess applies, lowest precedence first; the process env wins over all. */
|
|
78
|
+
export const DEV_DATABASE_ENV_FILES = [
|
|
79
|
+
".env",
|
|
80
|
+
".env.development",
|
|
81
|
+
".env.local",
|
|
82
|
+
".env.development.local",
|
|
83
|
+
] as const
|
|
84
|
+
|
|
85
|
+
class InvalidDeclaration extends Error {}
|
|
86
|
+
|
|
87
|
+
function invalid(message: string): never {
|
|
88
|
+
throw new InvalidDeclaration(message)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** One field of the declaration object, read without trusting its shape. */
|
|
92
|
+
type Fields = (field: string) => unknown
|
|
93
|
+
|
|
94
|
+
function strings(fields: Fields, field: string): readonly string[] {
|
|
95
|
+
const value = fields(field)
|
|
96
|
+
if (value === undefined) return []
|
|
97
|
+
if (!Array.isArray(value)) invalid(`devDatabase.${field} must be an array of non-empty strings`)
|
|
98
|
+
const out: string[] = []
|
|
99
|
+
for (const item of value) {
|
|
100
|
+
if (typeof item !== "string" || item === "") {
|
|
101
|
+
invalid(`devDatabase.${field} must be an array of non-empty strings`)
|
|
102
|
+
}
|
|
103
|
+
out.push(item)
|
|
104
|
+
}
|
|
105
|
+
return out
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function integer(
|
|
109
|
+
fields: Fields,
|
|
110
|
+
field: string,
|
|
111
|
+
fallback: number,
|
|
112
|
+
min: number,
|
|
113
|
+
max: number,
|
|
114
|
+
): number {
|
|
115
|
+
const value = fields(field)
|
|
116
|
+
if (value === undefined) return fallback
|
|
117
|
+
if (typeof value !== "number" || !Number.isSafeInteger(value) || value < min || value > max) {
|
|
118
|
+
invalid(`devDatabase.${field} must be an integer from ${min} to ${max}`)
|
|
119
|
+
}
|
|
120
|
+
return value
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/** Validate a `devDatabase` export and apply defaults. Unknown fields are refused, never ignored. */
|
|
124
|
+
export function parseDevDatabase(value: unknown): DevDatabase | DbRefusal {
|
|
125
|
+
try {
|
|
126
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
127
|
+
invalid('devDatabase must be an object such as { kind: "sqlite", file: "./data/app.db" }')
|
|
128
|
+
}
|
|
129
|
+
const fields: Fields = (field) => Reflect.get(value, field)
|
|
130
|
+
const declared = fields("kind")
|
|
131
|
+
const kind =
|
|
132
|
+
declared === "sqlite" || declared === "postgres"
|
|
133
|
+
? declared
|
|
134
|
+
: invalid('devDatabase.kind must be "sqlite" or "postgres"')
|
|
135
|
+
const known = kind === "sqlite" ? SQLITE_FIELDS : POSTGRES_FIELDS
|
|
136
|
+
for (const field of Object.keys(value)) {
|
|
137
|
+
if (!known.has(field))
|
|
138
|
+
invalid(`devDatabase has no field ${JSON.stringify(field)} for kind ${kind}`)
|
|
139
|
+
}
|
|
140
|
+
const query = fields("query")
|
|
141
|
+
if (query !== undefined && typeof query !== "boolean") {
|
|
142
|
+
invalid("devDatabase.query must be a boolean")
|
|
143
|
+
}
|
|
144
|
+
const common: DevDatabaseCommon = {
|
|
145
|
+
exclude: strings(fields, "exclude"),
|
|
146
|
+
maxRows: integer(fields, "maxRows", 100, 1, 10_000),
|
|
147
|
+
// The answer crosses the subprocess pipe as one line, bounded at 1 MiB with its envelope.
|
|
148
|
+
maxResultBytes: integer(fields, "maxResultBytes", 100 * 1024, 1024, 512 * 1024),
|
|
149
|
+
timeoutMs: integer(fields, "timeoutMs", 5_000, 100, 120_000),
|
|
150
|
+
redactColumns: strings(fields, "redactColumns"),
|
|
151
|
+
revealColumns: strings(fields, "revealColumns"),
|
|
152
|
+
query: query !== false,
|
|
153
|
+
}
|
|
154
|
+
if (kind === "sqlite") {
|
|
155
|
+
const file = fields("file")
|
|
156
|
+
if (typeof file !== "string" || file === "" || file.startsWith(":memory:")) {
|
|
157
|
+
invalid("devDatabase.file must be the path of a SQLite database file")
|
|
158
|
+
}
|
|
159
|
+
return { ...common, kind, file, allowFiles: strings(fields, "allowFiles") }
|
|
160
|
+
}
|
|
161
|
+
const url = fields("url")
|
|
162
|
+
if (url === undefined) {
|
|
163
|
+
invalid(
|
|
164
|
+
`devDatabase.url is undefined: the environment variable it reads is not set (nifra applies ${DEV_DATABASE_ENV_FILES.join(", ")} first)`,
|
|
165
|
+
)
|
|
166
|
+
}
|
|
167
|
+
if (typeof url !== "string" || url === "") {
|
|
168
|
+
invalid("devDatabase.url must be a postgres:// URL")
|
|
169
|
+
}
|
|
170
|
+
return {
|
|
171
|
+
...common,
|
|
172
|
+
kind,
|
|
173
|
+
url,
|
|
174
|
+
allowHosts: strings(fields, "allowHosts"),
|
|
175
|
+
allowExtensions: strings(fields, "allowExtensions"),
|
|
176
|
+
schemas: fields("schemas") === undefined ? ["public"] : strings(fields, "schemas"),
|
|
177
|
+
}
|
|
178
|
+
} catch (error) {
|
|
179
|
+
if (error instanceof InvalidDeclaration) return dbRefusal("NIFRA_DB_CONFIG", error.message)
|
|
180
|
+
throw error
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/** The project's `.env` files as one record, for redacting with the values the subprocess sees. */
|
|
185
|
+
export async function readProjectEnv(root: string): Promise<Record<string, string>> {
|
|
186
|
+
const merged: Record<string, string> = {}
|
|
187
|
+
for (const file of DEV_DATABASE_ENV_FILES) {
|
|
188
|
+
const path = resolve(root, file)
|
|
189
|
+
if (!existsSync(path)) continue
|
|
190
|
+
Object.assign(merged, parseEnvFile(await Bun.file(path).text()))
|
|
191
|
+
}
|
|
192
|
+
return merged
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Apply the project's `.env` files (never overriding the process environment), then import
|
|
197
|
+
* `nifra.config.ts` and validate its `devDatabase` export. Runs in the query subprocess only: the
|
|
198
|
+
* config is code, and importing it in a long-lived process would pin its modules.
|
|
199
|
+
*/
|
|
200
|
+
export async function loadDevDatabase(root: string): Promise<DevDatabase | DbRefusal> {
|
|
201
|
+
await applyEnvFiles(
|
|
202
|
+
root,
|
|
203
|
+
DEV_DATABASE_ENV_FILES.filter((file) => existsSync(resolve(root, file))),
|
|
204
|
+
)
|
|
205
|
+
const configPath = resolve(root, CONFIG_FILE)
|
|
206
|
+
if (!existsSync(configPath)) {
|
|
207
|
+
return dbRefusal("NIFRA_DB_NOT_DECLARED", `${root} has no ${CONFIG_FILE} declaring devDatabase`)
|
|
208
|
+
}
|
|
209
|
+
let config: unknown
|
|
210
|
+
try {
|
|
211
|
+
config = await import(configPath)
|
|
212
|
+
} catch (error) {
|
|
213
|
+
return dbRefusal(
|
|
214
|
+
"NIFRA_DB_CONFIG",
|
|
215
|
+
`${CONFIG_FILE} failed to load: ${error instanceof Error ? error.message : String(error)}`,
|
|
216
|
+
)
|
|
217
|
+
}
|
|
218
|
+
const declared =
|
|
219
|
+
typeof config === "object" && config !== null ? Reflect.get(config, "devDatabase") : undefined
|
|
220
|
+
if (declared === undefined) {
|
|
221
|
+
return dbRefusal("NIFRA_DB_NOT_DECLARED", `${CONFIG_FILE} does not export devDatabase`)
|
|
222
|
+
}
|
|
223
|
+
return parseDevDatabase(declared)
|
|
224
|
+
}
|