@rebasepro/server-postgres 0.23.0 → 0.24.1-canary.g19596ef
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 +16 -0
- package/dist/{BranchService-DGPL6G_C.js → BranchService-UgKa416x.js} +47 -19
- package/dist/BranchService-UgKa416x.js.map +1 -0
- package/dist/PostgresBackendDriver.d.ts +187 -13
- package/dist/PostgresBootstrapper.d.ts +101 -2
- package/dist/auth/ensure-tables.d.ts +12 -0
- package/dist/auth/services.d.ts +78 -14
- package/dist/{auth-users-columns-D2LBFrMH.js → auth-users-columns-C72EMoDJ.js} +17 -1
- package/dist/{auth-users-columns-D2LBFrMH.js.map → auth-users-columns-C72EMoDJ.js.map} +1 -1
- package/dist/backup/backup-cli.d.ts +75 -2
- package/dist/backup/backup-service.d.ts +2 -2
- package/dist/backup/pg-binary.d.ts +5 -0
- package/dist/{backup-cli-24v4OlSp.js → backup-cli-yiKd1GsC.js} +168 -75
- package/dist/backup-cli-yiKd1GsC.js.map +1 -0
- package/dist/{backup-service-HQ9GC4tN.js → backup-service-AZWc2wvI.js} +104 -35
- package/dist/backup-service-AZWc2wvI.js.map +1 -0
- package/dist/boot-ddl-B9ZmBJ75.js +105 -0
- package/dist/boot-ddl-B9ZmBJ75.js.map +1 -0
- package/dist/cli-console-DGee3Zl7.js +225 -0
- package/dist/cli-console-DGee3Zl7.js.map +1 -0
- package/dist/cli-console.d.ts +39 -0
- package/dist/cli-errors-oVUuD8k0.js +2180 -0
- package/dist/cli-errors-oVUuD8k0.js.map +1 -0
- package/dist/cli-errors.d.ts +133 -9
- package/dist/{cli-flags-BglvpjHv.js → cli-flags-DnPHXjRH.js} +56 -6
- package/dist/cli-flags-DnPHXjRH.js.map +1 -0
- package/dist/cli-flags.d.ts +15 -0
- package/dist/cli-helpers.d.ts +88 -34
- package/dist/cli-output.d.ts +16 -28
- package/dist/{arg-Dni7MzLB.js → cli-prompt-egtNKkZl.js} +49 -3
- package/dist/cli-prompt-egtNKkZl.js.map +1 -0
- package/dist/cli-prompt.d.ts +19 -0
- package/dist/cli-push.d.ts +87 -0
- package/dist/cli-scratch-database.d.ts +33 -8
- package/dist/cli.js +826 -230
- package/dist/cli.js.map +1 -1
- package/dist/{column-plan-helpers-DF-8dTVa.js → column-plan-helpers-D_V4oaZh.js} +43 -27
- package/dist/column-plan-helpers-D_V4oaZh.js.map +1 -0
- package/dist/{databasePoolManager-Bj5FbeAs.js → connection-C938nR3E.js} +25 -113
- package/dist/connection-C938nR3E.js.map +1 -0
- package/dist/connection.d.ts +13 -2
- package/dist/data-transformer.d.ts +0 -8
- package/dist/databasePoolManager-DZgnBOgj.js +119 -0
- package/dist/databasePoolManager-DZgnBOgj.js.map +1 -0
- package/dist/deferred-index-build-BqmEHGaD.js +1051 -0
- package/dist/deferred-index-build-BqmEHGaD.js.map +1 -0
- package/dist/{doctor-Cb2thZ8s.js → doctor-CUAAOFZm.js} +281 -89
- package/dist/doctor-CUAAOFZm.js.map +1 -0
- package/dist/ensure-collection-policies-Bb51V2OV.js +541 -0
- package/dist/ensure-collection-policies-Bb51V2OV.js.map +1 -0
- package/dist/ensure-collection-tables-egjGBjhv.js +532 -0
- package/dist/ensure-collection-tables-egjGBjhv.js.map +1 -0
- package/dist/{ensure-tables-Dhn9KM3B.js → ensure-tables-DMPWhJ6R.js} +180 -77
- package/dist/ensure-tables-DMPWhJ6R.js.map +1 -0
- package/dist/enum-labels-kept-Msq5gMcb.js +56 -0
- package/dist/enum-labels-kept-Msq5gMcb.js.map +1 -0
- package/dist/generate-drizzle-schema-DrA-YgXv.js +57 -0
- package/dist/generate-drizzle-schema-DrA-YgXv.js.map +1 -0
- package/dist/{generate-drizzle-schema-logic-BfzK7UQd.js → generate-drizzle-schema-logic-BaT0H7Gq.js} +29 -11
- package/dist/generate-drizzle-schema-logic-BaT0H7Gq.js.map +1 -0
- package/dist/generate-files-OoRJLEdk.js +199 -0
- package/dist/generate-files-OoRJLEdk.js.map +1 -0
- package/dist/generate-postgres-ddl-logic-B4k9djAV.js +152 -0
- package/dist/generate-postgres-ddl-logic-B4k9djAV.js.map +1 -0
- package/dist/{generated-schema-staleness-Di9c4ZxN.js → generated-schema-staleness-BWN_PsMi.js} +2 -2
- package/dist/{generated-schema-staleness-Di9c4ZxN.js.map → generated-schema-staleness-BWN_PsMi.js.map} +1 -1
- package/dist/generated-sql.d.ts +34 -0
- package/dist/history/HistoryService.d.ts +64 -5
- package/dist/history/ensure-history-table.d.ts +63 -4
- package/dist/index.d.ts +1 -0
- package/dist/index.es.js +139 -16738
- package/dist/index.es.js.map +1 -1
- package/dist/{introspect-db-logic-WMuAfxvw.js → introspect-db-logic-BCc1Jym2.js} +654 -353
- package/dist/introspect-db-logic-BCc1Jym2.js.map +1 -0
- package/dist/introspect-db-queries-BhhJg0b8.js +364 -0
- package/dist/introspect-db-queries-BhhJg0b8.js.map +1 -0
- package/dist/open-rebase-CAjWpPjs.js +20895 -0
- package/dist/open-rebase-CAjWpPjs.js.map +1 -0
- package/dist/open-rebase.d.ts +94 -0
- package/dist/pg-error-utils-Bs_Ue4wn.js +395 -0
- package/dist/pg-error-utils-Bs_Ue4wn.js.map +1 -0
- package/dist/{plan-schema-C0fxM8dY.js → plan-schema-CsNgK0qi.js} +279 -534
- package/dist/plan-schema-CsNgK0qi.js.map +1 -0
- package/dist/{policy-drift-DljYdrpW.js → policy-drift-BKC50y2p.js} +33 -9
- package/dist/policy-drift-BKC50y2p.js.map +1 -0
- package/dist/push-index-prebuild-C_qhyoJa.js +45 -0
- package/dist/push-index-prebuild-C_qhyoJa.js.map +1 -0
- package/dist/push-legacy-renames-5g9h3HOa.js +34 -0
- package/dist/push-legacy-renames-5g9h3HOa.js.map +1 -0
- package/dist/{generate-postgres-ddl-logic-Bt2d2mRH.js → render-ddl-CrfEe__B.js} +24 -157
- package/dist/render-ddl-CrfEe__B.js.map +1 -0
- package/dist/{rls-bootstrap-sql-B8EclDyM.js → rls-bootstrap-sql-Bd-hJk08.js} +125 -1101
- package/dist/rls-bootstrap-sql-Bd-hJk08.js.map +1 -0
- package/dist/{rls-enforcement-C6Xk0lA6.js → rls-enforcement-D7P4-ZYX.js} +138 -18
- package/dist/rls-enforcement-D7P4-ZYX.js.map +1 -0
- package/dist/{__vite-browser-external-BnuHet1e.js → rolldown-runtime-V7rFbMRe.js} +1 -8
- package/dist/schema/atlas-exclude.d.ts +42 -0
- package/dist/schema/auth-schema.d.ts +172 -2
- package/dist/schema/boot-ddl.d.ts +47 -0
- package/dist/schema/carved-out-migration.d.ts +5 -4
- package/dist/schema/classify-change.d.ts +29 -1
- package/dist/schema/collection-index.d.ts +45 -0
- package/dist/schema/column-plan-helpers.d.ts +38 -21
- package/dist/schema/deferred-index-build.d.ts +131 -0
- package/dist/schema/destructive-sql.d.ts +50 -2
- package/dist/schema/doctor-cli.js +110 -6
- package/dist/schema/doctor-cli.js.map +1 -1
- package/dist/schema/doctor-search-scale.d.ts +45 -0
- package/dist/schema/doctor.d.ts +53 -1
- package/dist/schema/ensure-collection-policies.d.ts +95 -35
- package/dist/schema/ensure-collection-tables.d.ts +56 -3
- package/dist/schema/enum-labels-kept.d.ts +26 -0
- package/dist/schema/generate-drizzle-schema.js +1 -1
- package/dist/schema/generate-files.d.ts +44 -0
- package/dist/schema/generate-next-step.d.ts +0 -13
- package/dist/schema/generate-postgres-ddl-logic.d.ts +5 -5
- package/dist/schema/generate-postgres-ddl.js +10 -81
- package/dist/schema/generate-postgres-ddl.js.map +1 -1
- package/dist/schema/generate-schema-commit.d.ts +12 -0
- package/dist/schema/generated-schema-diff.d.ts +7 -0
- package/dist/schema/introspect-db-logic.d.ts +63 -0
- package/dist/schema/introspect-db-queries.d.ts +21 -2
- package/dist/schema/introspect-db-search.d.ts +22 -0
- package/dist/schema/introspect-db-storage.d.ts +83 -0
- package/dist/schema/introspect-db-structure.d.ts +10 -0
- package/dist/schema/introspect-db.js +29 -21
- package/dist/schema/introspect-db.js.map +1 -1
- package/dist/schema/migrate-baseline.d.ts +33 -0
- package/dist/schema/migration-post-process.d.ts +34 -0
- package/dist/schema/plan/diff-plan.d.ts +127 -1
- package/dist/schema/plan/plan-schema.d.ts +16 -8
- package/dist/schema/plan/render-ddl.d.ts +8 -1
- package/dist/schema/plan/types.d.ts +45 -11
- package/dist/schema/push-index-prebuild.d.ts +25 -0
- package/dist/schema/push-legacy-renames.d.ts +20 -0
- package/dist/schema/rls-bootstrap-sql.d.ts +15 -0
- package/dist/schema/undeclarable-constraints.d.ts +59 -0
- package/dist/search-column-BM-GV6vH.js +442 -0
- package/dist/search-column-BM-GV6vH.js.map +1 -0
- package/dist/security/policy-drift.d.ts +1 -1
- package/dist/security/rls-enforcement.d.ts +39 -4
- package/dist/services/BranchService.d.ts +29 -1
- package/dist/services/FetchService.d.ts +63 -12
- package/dist/services/PersistService.d.ts +15 -0
- package/dist/services/RelationService.d.ts +106 -3
- package/dist/services/cdc/CdcListener.d.ts +26 -10
- package/dist/services/cdc/identity-columns.d.ts +19 -0
- package/dist/services/cdc/trigger-cdc.d.ts +180 -18
- package/dist/services/channel-bus/PostgresChannelBus.d.ts +12 -7
- package/dist/services/channel-bus/index.d.ts +1 -1
- package/dist/services/channel-history.d.ts +32 -5
- package/dist/services/collection-helpers.d.ts +26 -1
- package/dist/services/field-viewer.d.ts +15 -1
- package/dist/services/pg-notify-listener.d.ts +95 -6
- package/dist/services/realtimeService.d.ts +467 -53
- package/dist/services/row-pipeline.d.ts +16 -9
- package/dist/services/socket-liveness.d.ts +85 -0
- package/dist/services/soft-delete.d.ts +12 -0
- package/dist/services/sql-script.d.ts +275 -0
- package/dist/services/vector-iterative-scan.d.ts +40 -0
- package/dist/services/write-depth.d.ts +22 -0
- package/dist/services/write-transaction-scope.d.ts +15 -3
- package/dist/socket-opt-ins.d.ts +64 -0
- package/dist/source-DB6xJv3p.js +873 -0
- package/dist/source-DB6xJv3p.js.map +1 -0
- package/dist/tsx-loader.d.ts +14 -0
- package/dist/utils/connection-string.d.ts +31 -0
- package/dist/utils/drizzle-conditions.d.ts +63 -3
- package/dist/utils/error-cause.d.ts +7 -0
- package/dist/utils/pg-error-utils.d.ts +2 -4
- package/dist/utils/result-rows.d.ts +10 -0
- package/dist/{vector-index-CMJKb3C9.js → vector-index-BFhyEaiz.js} +2 -2
- package/dist/{vector-index-CMJKb3C9.js.map → vector-index-BFhyEaiz.js.map} +1 -1
- package/dist/websocket-DUiiwQd2.js +1632 -0
- package/dist/websocket-DUiiwQd2.js.map +1 -0
- package/dist/websocket.d.ts +63 -18
- package/package.json +7 -7
- package/dist/BranchService-DGPL6G_C.js.map +0 -1
- package/dist/__vite-browser-external-BnuHet1e.js.map +0 -1
- package/dist/arg-Dni7MzLB.js.map +0 -1
- package/dist/backup-cli-24v4OlSp.js.map +0 -1
- package/dist/backup-service-HQ9GC4tN.js.map +0 -1
- package/dist/cli-errors-B8qHg02P.js +0 -798
- package/dist/cli-errors-B8qHg02P.js.map +0 -1
- package/dist/cli-flags-BglvpjHv.js.map +0 -1
- package/dist/cli-output-CNdMql-L.js +0 -47
- package/dist/cli-output-CNdMql-L.js.map +0 -1
- package/dist/collection-index-DdnsxiJ_.js +0 -286
- package/dist/collection-index-DdnsxiJ_.js.map +0 -1
- package/dist/column-plan-helpers-DF-8dTVa.js.map +0 -1
- package/dist/databasePoolManager-Bj5FbeAs.js.map +0 -1
- package/dist/doctor-Cb2thZ8s.js.map +0 -1
- package/dist/ensure-collection-policies-RHUcEp4v.js +0 -105
- package/dist/ensure-collection-policies-RHUcEp4v.js.map +0 -1
- package/dist/ensure-collection-tables-BEEjn5cn.js +0 -857
- package/dist/ensure-collection-tables-BEEjn5cn.js.map +0 -1
- package/dist/ensure-tables-Dhn9KM3B.js.map +0 -1
- package/dist/generate-drizzle-schema-logic-BfzK7UQd.js.map +0 -1
- package/dist/generate-drizzle-schema-yzY_BLhr.js +0 -123
- package/dist/generate-drizzle-schema-yzY_BLhr.js.map +0 -1
- package/dist/generate-postgres-ddl-logic-Bt2d2mRH.js.map +0 -1
- package/dist/introspect-db-logic-WMuAfxvw.js.map +0 -1
- package/dist/plan-schema-C0fxM8dY.js.map +0 -1
- package/dist/policy-drift-DljYdrpW.js.map +0 -1
- package/dist/rls-bootstrap-sql-B8EclDyM.js.map +0 -1
- package/dist/rls-enforcement-C6Xk0lA6.js.map +0 -1
- package/dist/source-Br7L7GOI.js +0 -410
- package/dist/source-Br7L7GOI.js.map +0 -1
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
import { createRequire as __createRequire } from "module";
|
|
2
|
+
__createRequire(import.meta.url);
|
|
3
|
+
import { i as __toESM } from "./rolldown-runtime-V7rFbMRe.js";
|
|
4
|
+
import { l as poolMaxCeiling } from "./connection-C938nR3E.js";
|
|
5
|
+
import { t as openRebase } from "./open-rebase-CAjWpPjs.js";
|
|
6
|
+
import { i as outError, n as describeFailure, r as out } from "./source-DB6xJv3p.js";
|
|
7
|
+
import { n as require_arg } from "./cli-prompt-egtNKkZl.js";
|
|
8
|
+
import { t as RELAYED_FLAGS } from "./cli-flags-DnPHXjRH.js";
|
|
9
|
+
import { setLogOutput } from "@rebasepro/server";
|
|
10
|
+
import path from "path";
|
|
11
|
+
import fs from "fs";
|
|
12
|
+
import tty from "node:tty";
|
|
13
|
+
import { inspect } from "node:util";
|
|
14
|
+
import { PassThrough } from "node:stream";
|
|
15
|
+
import readline from "node:readline";
|
|
16
|
+
import repl from "node:repl";
|
|
17
|
+
//#region src/cli-console.ts
|
|
18
|
+
var import_arg = /* @__PURE__ */ __toESM(require_arg(), 1);
|
|
19
|
+
/**
|
|
20
|
+
* The flags `rebase console` takes. `--history` is the CLI's own: where it
|
|
21
|
+
* keeps the REPL's history (`.rebase/console_history` in the project).
|
|
22
|
+
*/
|
|
23
|
+
var CONSOLE_FLAGS = {
|
|
24
|
+
"--collections": String,
|
|
25
|
+
"-c": "--collections",
|
|
26
|
+
"--eval": String,
|
|
27
|
+
"-e": "--eval",
|
|
28
|
+
"--history": String
|
|
29
|
+
};
|
|
30
|
+
/** The constructor of `async function` — what `new Function` is for a body that awaits. */
|
|
31
|
+
var AsyncFunction = Object.getPrototypeOf(async () => void 0).constructor;
|
|
32
|
+
/**
|
|
33
|
+
* Run `code` with `rebase` and `collections` in scope and resolve with its
|
|
34
|
+
* value.
|
|
35
|
+
*
|
|
36
|
+
* Read as an expression first, so `rebase.dataAsAdmin.posts.find()` is its own
|
|
37
|
+
* result; code that is not one expression runs as a function body, where
|
|
38
|
+
* `await` works everywhere and `return` gives the result.
|
|
39
|
+
*/
|
|
40
|
+
async function evaluateInConsole(code, scope) {
|
|
41
|
+
let run;
|
|
42
|
+
try {
|
|
43
|
+
run = new AsyncFunction("rebase", "collections", `return (${code}\n);`);
|
|
44
|
+
} catch (error) {
|
|
45
|
+
if (!(error instanceof SyntaxError)) throw error;
|
|
46
|
+
run = new AsyncFunction("rebase", "collections", code);
|
|
47
|
+
}
|
|
48
|
+
return run(scope.rebase, scope.collections);
|
|
49
|
+
}
|
|
50
|
+
/** A result as JSON, the way `--eval` prints it: dates as ISO strings, bigints as strings. */
|
|
51
|
+
function consoleJson(value) {
|
|
52
|
+
return JSON.stringify(value, (_key, item) => typeof item === "bigint" ? item.toString() : item, 2) ?? "undefined";
|
|
53
|
+
}
|
|
54
|
+
/** The host and database a URL names, for the banner — never its credentials. */
|
|
55
|
+
function describeDatabase(databaseUrl) {
|
|
56
|
+
try {
|
|
57
|
+
const url = new URL(databaseUrl);
|
|
58
|
+
return `${url.hostname}${url.port ? `:${url.port}` : ""}${url.pathname}`;
|
|
59
|
+
} catch {
|
|
60
|
+
return "the configured database";
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* `rebase console [--eval <code>] [--collections <dir>]`, from the driver
|
|
65
|
+
* line `["console", …flags]`. Resolves with the exit code.
|
|
66
|
+
*/
|
|
67
|
+
async function consoleCommand(args, streams = {}) {
|
|
68
|
+
const flags = (0, import_arg.default)({
|
|
69
|
+
...RELAYED_FLAGS,
|
|
70
|
+
...CONSOLE_FLAGS
|
|
71
|
+
}, { argv: args.slice(1) });
|
|
72
|
+
if (flags["--help"]) {
|
|
73
|
+
out("Run `rebase console --help` for the options — this is the driver's own entry point.");
|
|
74
|
+
return 0;
|
|
75
|
+
}
|
|
76
|
+
const databaseUrl = flags["--database-url"] || process.env.DATABASE_URL;
|
|
77
|
+
if (!databaseUrl) {
|
|
78
|
+
outError("✗ No database to open: DATABASE_URL is not set. Set it in .env, or pass --database-url.");
|
|
79
|
+
return 1;
|
|
80
|
+
}
|
|
81
|
+
if (process.env.LOG_LEVEL === void 0) process.env.LOG_LEVEL = "warn";
|
|
82
|
+
setLogOutput("stderr");
|
|
83
|
+
try {
|
|
84
|
+
return await openAndRun({
|
|
85
|
+
databaseUrl,
|
|
86
|
+
collections: flags["--collections"],
|
|
87
|
+
eval: flags["--eval"],
|
|
88
|
+
history: flags["--history"]
|
|
89
|
+
}, streams);
|
|
90
|
+
} finally {
|
|
91
|
+
setLogOutput();
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
/** Open the project, run `--eval` or the REPL, and close it again. Resolves with the exit code. */
|
|
95
|
+
async function openAndRun(options, streams) {
|
|
96
|
+
const { databaseUrl } = options;
|
|
97
|
+
const collectionsPath = path.resolve(options.collections || path.join("..", "config", "collections"));
|
|
98
|
+
const { loadCollections } = await import("./doctor-CUAAOFZm.js").then((n) => n.t);
|
|
99
|
+
const collections = fs.existsSync(collectionsPath) ? await loadCollections(collectionsPath) : [];
|
|
100
|
+
const ceiling = poolMaxCeiling();
|
|
101
|
+
const rebase = await openRebase({
|
|
102
|
+
databaseUrl,
|
|
103
|
+
collections,
|
|
104
|
+
...ceiling !== null ? { pool: { max: ceiling } } : {}
|
|
105
|
+
});
|
|
106
|
+
try {
|
|
107
|
+
const code = options.eval;
|
|
108
|
+
if (code !== void 0) try {
|
|
109
|
+
const result = await evaluateInConsole(code, {
|
|
110
|
+
rebase,
|
|
111
|
+
collections: rebase.collections
|
|
112
|
+
});
|
|
113
|
+
if (result !== void 0) out(consoleJson(result));
|
|
114
|
+
return 0;
|
|
115
|
+
} catch (error) {
|
|
116
|
+
outError(describeFailure(error));
|
|
117
|
+
return 1;
|
|
118
|
+
}
|
|
119
|
+
await startRepl({
|
|
120
|
+
rebase,
|
|
121
|
+
collections: rebase.collections
|
|
122
|
+
}, {
|
|
123
|
+
history: options.history,
|
|
124
|
+
database: describeDatabase(databaseUrl),
|
|
125
|
+
...streams
|
|
126
|
+
});
|
|
127
|
+
return 0;
|
|
128
|
+
} finally {
|
|
129
|
+
await rebase.close();
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
/** The interactive half: a Node REPL until `.exit`, Ctrl-D or the end of piped input. */
|
|
133
|
+
async function startRepl(scope, options) {
|
|
134
|
+
out("");
|
|
135
|
+
out(` rebase console — ${options.database}, ${scope.collections.length} collection(s)`);
|
|
136
|
+
out(" In scope: rebase (dataAsAdmin, sql, withAuth, close) and collections. Top-level await works.");
|
|
137
|
+
out(" Try: await rebase.dataAsAdmin.<collection>.find({ limit: 5 })");
|
|
138
|
+
out("");
|
|
139
|
+
const input = options.input ?? process.stdin;
|
|
140
|
+
const output = options.output ?? process.stdout;
|
|
141
|
+
const feed = input instanceof tty.ReadStream && input.isTTY ? void 0 : new PassThrough();
|
|
142
|
+
const colors = output instanceof tty.WriteStream && output.isTTY;
|
|
143
|
+
const server = repl.start({
|
|
144
|
+
prompt: "",
|
|
145
|
+
useGlobal: false,
|
|
146
|
+
...feed ? {
|
|
147
|
+
input: feed,
|
|
148
|
+
output,
|
|
149
|
+
terminal: false
|
|
150
|
+
} : {
|
|
151
|
+
input,
|
|
152
|
+
output
|
|
153
|
+
},
|
|
154
|
+
writer: (value) => inspect(value, {
|
|
155
|
+
colors,
|
|
156
|
+
depth: 6
|
|
157
|
+
})
|
|
158
|
+
});
|
|
159
|
+
server.context.rebase = scope.rebase;
|
|
160
|
+
server.context.collections = scope.collections;
|
|
161
|
+
server.setPrompt("rebase> ");
|
|
162
|
+
const history = options.history;
|
|
163
|
+
if (history) {
|
|
164
|
+
fs.mkdirSync(path.dirname(history), { recursive: true });
|
|
165
|
+
await new Promise((resolve) => {
|
|
166
|
+
server.setupHistory(history, (error) => {
|
|
167
|
+
if (error) outError(` (history is off: ${error.message})`);
|
|
168
|
+
resolve();
|
|
169
|
+
});
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
const exited = new Promise((resolve) => server.once("exit", () => resolve()));
|
|
173
|
+
server.displayPrompt();
|
|
174
|
+
if (feed) await feedLineByLine(input, server, feed, exited);
|
|
175
|
+
await exited;
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Hand input that is not typed at a terminal to the REPL a line at a time,
|
|
179
|
+
* each once the REPL has finished the one before.
|
|
180
|
+
*
|
|
181
|
+
* Typed, the REPL holds keystrokes back while a top-level `await` is pending.
|
|
182
|
+
* Piped, every line arrives at once and each is evaluated as it arrives, so in
|
|
183
|
+
* `const { data } = await …` followed by `data.map(…)` the second line read
|
|
184
|
+
* `data` before the first had assigned it.
|
|
185
|
+
*
|
|
186
|
+
* The REPL is paused as each line reaches it, and it resumes its input when it
|
|
187
|
+
* displays its prompt again: once the line's value has settled, its error has
|
|
188
|
+
* been printed, or it needs the next line to complete it. That resumption is
|
|
189
|
+
* when the next line goes in. Lines are written one per chunk, because a
|
|
190
|
+
* chunk holding several is split and every line of it handed over at once.
|
|
191
|
+
*/
|
|
192
|
+
async function feedLineByLine(source, server, feed, exited) {
|
|
193
|
+
let evaluated;
|
|
194
|
+
const ready = () => {
|
|
195
|
+
const resolve = evaluated;
|
|
196
|
+
evaluated = void 0;
|
|
197
|
+
resolve?.();
|
|
198
|
+
};
|
|
199
|
+
server.prependListener("line", () => {
|
|
200
|
+
if (!server.editorMode) server.pause();
|
|
201
|
+
});
|
|
202
|
+
server.on("line", () => {
|
|
203
|
+
if (!server.editorMode) return;
|
|
204
|
+
server.resume();
|
|
205
|
+
ready();
|
|
206
|
+
});
|
|
207
|
+
server.on("resume", ready);
|
|
208
|
+
const closed = exited.then(() => "closed");
|
|
209
|
+
const lines = readline.createInterface({
|
|
210
|
+
input: source,
|
|
211
|
+
crlfDelay: Infinity
|
|
212
|
+
});
|
|
213
|
+
for await (const line of lines) {
|
|
214
|
+
const done = new Promise((resolve) => {
|
|
215
|
+
evaluated = () => resolve("done");
|
|
216
|
+
});
|
|
217
|
+
feed.write(`${line}\n`);
|
|
218
|
+
if (await Promise.race([done, closed]) === "closed") break;
|
|
219
|
+
}
|
|
220
|
+
feed.end();
|
|
221
|
+
}
|
|
222
|
+
//#endregion
|
|
223
|
+
export { consoleCommand };
|
|
224
|
+
|
|
225
|
+
//# sourceMappingURL=cli-console-DGee3Zl7.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-console-DGee3Zl7.js","names":[],"sources":["../src/cli-console.ts"],"sourcesContent":["/**\n * `rebase console` — the driver's half.\n *\n * Loads the project's collections the way `rebase db push` does, opens the\n * database with {@link openRebase}, and either evaluates one piece of code\n * (`--eval`) or starts a Node REPL with `rebase` and `collections` in scope.\n * The `rebase` CLI resolves the database first (the managed one included) and\n * hands this process `DATABASE_URL`, exactly as it does for `db` commands.\n *\n * This is the boot side of `openRebase`: it is where the environment is read\n * — `DATABASE_URL`, and the `REBASE_DB_POOL_MAX` ceiling the managed\n * development database needs — and turned into explicit options.\n */\nimport arg from \"arg\";\nimport fs from \"fs\";\nimport path from \"path\";\nimport readline from \"node:readline\";\nimport repl from \"node:repl\";\nimport { PassThrough } from \"node:stream\";\nimport tty from \"node:tty\";\nimport { inspect } from \"node:util\";\nimport { setLogOutput } from \"@rebasepro/server\";\nimport type { CollectionConfig } from \"@rebasepro/types\";\nimport { RELAYED_FLAGS } from \"./cli-flags\";\nimport { out, outError, describeFailure } from \"./cli-output\";\nimport { poolMaxCeiling } from \"./connection\";\nimport { openRebase, type OpenedRebase } from \"./open-rebase\";\n\n/**\n * The flags `rebase console` takes. `--history` is the CLI's own: where it\n * keeps the REPL's history (`.rebase/console_history` in the project).\n */\nexport const CONSOLE_FLAGS = {\n \"--collections\": String,\n \"-c\": \"--collections\",\n \"--eval\": String,\n \"-e\": \"--eval\",\n \"--history\": String\n} satisfies arg.Spec;\n\n/** What the code the console runs can name. */\nexport interface ConsoleScope {\n rebase: OpenedRebase;\n collections: CollectionConfig[];\n}\n\ntype ScopedFunction = (rebase: OpenedRebase, collections: CollectionConfig[]) => Promise<unknown>;\ntype AsyncFunctionConstructor = new (...parameters: string[]) => ScopedFunction;\n\n/** The constructor of `async function` — what `new Function` is for a body that awaits. */\nconst AsyncFunction: AsyncFunctionConstructor = Object.getPrototypeOf(async () => undefined).constructor;\n\n/**\n * Run `code` with `rebase` and `collections` in scope and resolve with its\n * value.\n *\n * Read as an expression first, so `rebase.dataAsAdmin.posts.find()` is its own\n * result; code that is not one expression runs as a function body, where\n * `await` works everywhere and `return` gives the result.\n */\nexport async function evaluateInConsole(code: string, scope: ConsoleScope): Promise<unknown> {\n let run: ScopedFunction;\n try {\n run = new AsyncFunction(\"rebase\", \"collections\", `return (${code}\\n);`);\n } catch (error) {\n if (!(error instanceof SyntaxError)) throw error;\n run = new AsyncFunction(\"rebase\", \"collections\", code);\n }\n return run(scope.rebase, scope.collections);\n}\n\n/** A result as JSON, the way `--eval` prints it: dates as ISO strings, bigints as strings. */\nexport function consoleJson(value: unknown): string {\n return JSON.stringify(value, (_key, item: unknown) => typeof item === \"bigint\" ? item.toString() : item, 2) ?? \"undefined\";\n}\n\n/** The host and database a URL names, for the banner — never its credentials. */\nfunction describeDatabase(databaseUrl: string): string {\n try {\n const url = new URL(databaseUrl);\n return `${url.hostname}${url.port ? `:${url.port}` : \"\"}${url.pathname}`;\n } catch {\n return \"the configured database\";\n }\n}\n\n/** Where the REPL reads and writes; the terminal unless a caller hands it streams. */\nexport interface ConsoleStreams {\n input?: NodeJS.ReadableStream;\n output?: NodeJS.WritableStream;\n}\n\n/**\n * `rebase console [--eval <code>] [--collections <dir>]`, from the driver\n * line `[\"console\", …flags]`. Resolves with the exit code.\n */\nexport async function consoleCommand(args: string[], streams: ConsoleStreams = {}): Promise<number> {\n const flags = arg({ ...RELAYED_FLAGS, ...CONSOLE_FLAGS }, { argv: args.slice(1) });\n if (flags[\"--help\"]) {\n out(\"Run `rebase console --help` for the options — this is the driver's own entry point.\");\n return 0;\n }\n\n const databaseUrl = flags[\"--database-url\"] || process.env.DATABASE_URL;\n if (!databaseUrl) {\n outError(\"✗ No database to open: DATABASE_URL is not set. Set it in .env, or pass --database-url.\");\n return 1;\n }\n\n // The console's own lines are what the reader is here for; the driver's\n // info-level boot notes are not, unless they asked for them.\n if (process.env.LOG_LEVEL === undefined) process.env.LOG_LEVEL = \"warn\";\n\n // And whatever level they asked for, a log line is never part of the\n // answer: stdout holds the `--eval` result a pipe reads (`| jq .`) and the\n // REPL's values. The scaffold's `.env` sets LOG_LEVEL=info, and under\n // NODE_ENV=production warnings go to stdout too.\n setLogOutput(\"stderr\");\n try {\n return await openAndRun({\n databaseUrl,\n collections: flags[\"--collections\"],\n eval: flags[\"--eval\"],\n history: flags[\"--history\"]\n }, streams);\n } finally {\n setLogOutput();\n }\n}\n\n/** Open the project, run `--eval` or the REPL, and close it again. Resolves with the exit code. */\nasync function openAndRun(\n options: { databaseUrl: string; collections?: string; eval?: string; history?: string },\n streams: ConsoleStreams\n): Promise<number> {\n const { databaseUrl } = options;\n const collectionsPath = path.resolve(options.collections || path.join(\"..\", \"config\", \"collections\"));\n const { loadCollections } = await import(\"./schema/doctor\");\n const collections = fs.existsSync(collectionsPath) ? await loadCollections(collectionsPath) : [];\n\n const ceiling = poolMaxCeiling();\n const rebase = await openRebase({\n databaseUrl,\n collections,\n ...(ceiling !== null ? { pool: { max: ceiling } } : {})\n });\n\n try {\n const code = options.eval;\n if (code !== undefined) {\n try {\n const result = await evaluateInConsole(code, { rebase, collections: rebase.collections });\n if (result !== undefined) out(consoleJson(result));\n return 0;\n } catch (error) {\n outError(describeFailure(error));\n return 1;\n }\n }\n\n await startRepl({ rebase, collections: rebase.collections }, {\n history: options.history,\n database: describeDatabase(databaseUrl),\n ...streams\n });\n return 0;\n } finally {\n await rebase.close();\n }\n}\n\n/** The interactive half: a Node REPL until `.exit`, Ctrl-D or the end of piped input. */\nasync function startRepl(scope: ConsoleScope, options: { history?: string; database: string } & ConsoleStreams): Promise<void> {\n out(\"\");\n out(` rebase console — ${options.database}, ${scope.collections.length} collection(s)`);\n out(\" In scope: rebase (dataAsAdmin, sql, withAuth, close) and collections. Top-level await works.\");\n out(\" Try: await rebase.dataAsAdmin.<collection>.find({ limit: 5 })\");\n out(\"\");\n\n const input = options.input ?? process.stdin;\n const output = options.output ?? process.stdout;\n // Typed at a terminal, the REPL reads it as one. Anything else — a pipe, a\n // file, a stream handed in — reaches it a line at a time through `feed`\n // (see `feedLineByLine`).\n const feed = input instanceof tty.ReadStream && input.isTTY ? undefined : new PassThrough();\n // Colours for a terminal only: piped to a file or another program, the\n // escape codes are noise in the text.\n const colors = output instanceof tty.WriteStream && output.isTTY;\n // Started without a prompt, and given one once the scope is in place: a\n // line that arrives with the first prompt must already see `rebase`.\n const server = repl.start({\n prompt: \"\",\n useGlobal: false,\n ...(feed ? { input: feed, output, terminal: false } : { input, output }),\n writer: (value: unknown) => inspect(value, { colors, depth: 6 })\n });\n server.context.rebase = scope.rebase;\n server.context.collections = scope.collections;\n server.setPrompt(\"rebase> \");\n\n const history = options.history;\n if (history) {\n fs.mkdirSync(path.dirname(history), { recursive: true });\n await new Promise<void>((resolve) => {\n server.setupHistory(history, (error) => {\n if (error) outError(` (history is off: ${error.message})`);\n resolve();\n });\n });\n }\n\n const exited = new Promise<void>((resolve) => server.once(\"exit\", () => resolve()));\n server.displayPrompt();\n if (feed) await feedLineByLine(input, server, feed, exited);\n await exited;\n}\n\n/**\n * Hand input that is not typed at a terminal to the REPL a line at a time,\n * each once the REPL has finished the one before.\n *\n * Typed, the REPL holds keystrokes back while a top-level `await` is pending.\n * Piped, every line arrives at once and each is evaluated as it arrives, so in\n * `const { data } = await …` followed by `data.map(…)` the second line read\n * `data` before the first had assigned it.\n *\n * The REPL is paused as each line reaches it, and it resumes its input when it\n * displays its prompt again: once the line's value has settled, its error has\n * been printed, or it needs the next line to complete it. That resumption is\n * when the next line goes in. Lines are written one per chunk, because a\n * chunk holding several is split and every line of it handed over at once.\n */\nasync function feedLineByLine(\n source: NodeJS.ReadableStream,\n server: repl.REPLServer,\n feed: PassThrough,\n exited: Promise<void>\n): Promise<void> {\n let evaluated: (() => void) | undefined;\n const ready = () => {\n const resolve = evaluated;\n evaluated = undefined;\n resolve?.();\n };\n // Before the REPL's own handler, so a line it evaluates at once resumes\n // after this pause rather than before it.\n server.prependListener(\"line\", () => {\n if (!server.editorMode) server.pause();\n });\n // `.editor` collects lines with no prompt until Ctrl-D: they go straight in.\n server.on(\"line\", () => {\n if (!server.editorMode) return;\n server.resume();\n ready();\n });\n server.on(\"resume\", ready);\n\n const closed = exited.then(() => \"closed\" as const);\n const lines = readline.createInterface({ input: source, crlfDelay: Infinity });\n for await (const line of lines) {\n const done = new Promise<\"done\">((resolve) => { evaluated = () => resolve(\"done\"); });\n feed.write(`${line}\\n`);\n // `.exit`: the rest of the input is not for this REPL.\n if (await Promise.race([done, closed]) === \"closed\") break;\n }\n feed.end();\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { CollectionConfig } from "@rebasepro/types";
|
|
2
|
+
import { type OpenedRebase } from "./open-rebase.js";
|
|
3
|
+
/**
|
|
4
|
+
* The flags `rebase console` takes. `--history` is the CLI's own: where it
|
|
5
|
+
* keeps the REPL's history (`.rebase/console_history` in the project).
|
|
6
|
+
*/
|
|
7
|
+
export declare const CONSOLE_FLAGS: {
|
|
8
|
+
"--collections": StringConstructor;
|
|
9
|
+
"-c": string;
|
|
10
|
+
"--eval": StringConstructor;
|
|
11
|
+
"-e": string;
|
|
12
|
+
"--history": StringConstructor;
|
|
13
|
+
};
|
|
14
|
+
/** What the code the console runs can name. */
|
|
15
|
+
export interface ConsoleScope {
|
|
16
|
+
rebase: OpenedRebase;
|
|
17
|
+
collections: CollectionConfig[];
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Run `code` with `rebase` and `collections` in scope and resolve with its
|
|
21
|
+
* value.
|
|
22
|
+
*
|
|
23
|
+
* Read as an expression first, so `rebase.dataAsAdmin.posts.find()` is its own
|
|
24
|
+
* result; code that is not one expression runs as a function body, where
|
|
25
|
+
* `await` works everywhere and `return` gives the result.
|
|
26
|
+
*/
|
|
27
|
+
export declare function evaluateInConsole(code: string, scope: ConsoleScope): Promise<unknown>;
|
|
28
|
+
/** A result as JSON, the way `--eval` prints it: dates as ISO strings, bigints as strings. */
|
|
29
|
+
export declare function consoleJson(value: unknown): string;
|
|
30
|
+
/** Where the REPL reads and writes; the terminal unless a caller hands it streams. */
|
|
31
|
+
export interface ConsoleStreams {
|
|
32
|
+
input?: NodeJS.ReadableStream;
|
|
33
|
+
output?: NodeJS.WritableStream;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* `rebase console [--eval <code>] [--collections <dir>]`, from the driver
|
|
37
|
+
* line `["console", …flags]`. Resolves with the exit code.
|
|
38
|
+
*/
|
|
39
|
+
export declare function consoleCommand(args: string[], streams?: ConsoleStreams): Promise<number>;
|