railcode 0.1.12 → 0.1.13
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 +3 -3
- package/dist/index.js +21 -46
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -36,9 +36,9 @@ railcode db <list|query> ... List data connectors / run read-only SQL
|
|
|
36
36
|
build command when needed, then uploads the output dir. The app is
|
|
37
37
|
created-or-resolved by slug in your saved org, and the live URL is printed.
|
|
38
38
|
- **`db`** inspects the org's **data connectors** (per-org Postgres) and runs
|
|
39
|
-
ad-hoc read-only SQL.
|
|
40
|
-
|
|
41
|
-
|
|
39
|
+
ad-hoc read-only SQL. It works straight after `railcode login` — **no app and no
|
|
40
|
+
`railcode.json` required** — since connectors are org-scoped; it hits the app-less
|
|
41
|
+
`/api/organizations/{org}/data/*` plane with your login token.
|
|
42
42
|
`railcode db list` (aliases `ls`, `connections`) prints each connector's
|
|
43
43
|
`name` + `engine` (`--json` for the raw array). `railcode db query "<sql>"`
|
|
44
44
|
(alias `sql`) runs SQL against `--connection` (default `default`) and prints a
|
package/dist/index.js
CHANGED
|
@@ -353,17 +353,6 @@ async function resolveOrCreateApp(config, slug) {
|
|
|
353
353
|
});
|
|
354
354
|
return (await readJsonOrThrow(created, "Create app"));
|
|
355
355
|
}
|
|
356
|
-
// Resolve an existing app by slug WITHOUT creating it — for read-only commands
|
|
357
|
-
// (e.g. `railcode db`) that must not spawn a phantom app as a side effect.
|
|
358
|
-
async function resolveExistingApp(config, slug) {
|
|
359
|
-
const orgPath = `/api/organizations/${config.orgUuid}/apps`;
|
|
360
|
-
const list = (await readJsonOrThrow(await authedFetch(config, orgPath), "List apps"));
|
|
361
|
-
const existing = list.find((app) => app.app_slug === slug);
|
|
362
|
-
if (!existing) {
|
|
363
|
-
throw new CliError(`App "${slug}" hasn't been created in your org yet. Run \`railcode deploy\` first.`, 1);
|
|
364
|
-
}
|
|
365
|
-
return existing;
|
|
366
|
-
}
|
|
367
356
|
async function postDeploy(config, appUuid, files) {
|
|
368
357
|
// The deploy API is multipart: one part named "files" per file, with the
|
|
369
358
|
// relative path carried as the part filename.
|
|
@@ -815,7 +804,7 @@ Query options:
|
|
|
815
804
|
--json Print the raw { columns, rows, rowcount, truncated } envelope
|
|
816
805
|
|
|
817
806
|
SQL is sent read-only with bound parameters — values are never interpolated into
|
|
818
|
-
the query.
|
|
807
|
+
the query. Works right after \`railcode login\` — no app or ${MANIFEST_NAME} required.
|
|
819
808
|
`;
|
|
820
809
|
async function commandDb(args) {
|
|
821
810
|
try {
|
|
@@ -851,8 +840,7 @@ async function commandDbList(args) {
|
|
|
851
840
|
throw new CliError(`railcode db list takes no arguments (got "${args.rest[1]}").`, 2);
|
|
852
841
|
}
|
|
853
842
|
const config = requireLogin(args);
|
|
854
|
-
const
|
|
855
|
-
const connections = await fetchDbConnections(config, app.uuid);
|
|
843
|
+
const connections = await fetchDbConnections(config);
|
|
856
844
|
if (args.options.json) {
|
|
857
845
|
console.log(JSON.stringify(connections, null, 2));
|
|
858
846
|
return;
|
|
@@ -874,10 +862,9 @@ async function commandDbQuery(args) {
|
|
|
874
862
|
const connection = optionString(args, "connection") ?? "default";
|
|
875
863
|
const query = source.kind === "file" ? readSqlFile(source.path) : source.sql;
|
|
876
864
|
const config = requireLogin(args);
|
|
877
|
-
const app = await resolveExistingApp(config, requireAppSlug());
|
|
878
865
|
// --engine wins; otherwise look the engine up from the connector list.
|
|
879
|
-
const engine = engineOption ?? inferEngine(await fetchDbConnections(config
|
|
880
|
-
const result = await runDbQuery(config,
|
|
866
|
+
const engine = engineOption ?? inferEngine(await fetchDbConnections(config), connection);
|
|
867
|
+
const result = await runDbQuery(config, { engine, connection, query, params });
|
|
881
868
|
if (args.options.json) {
|
|
882
869
|
console.log(JSON.stringify(result, null, 2));
|
|
883
870
|
return;
|
|
@@ -889,22 +876,14 @@ async function commandDbQuery(args) {
|
|
|
889
876
|
console.log("Note: results were truncated by the server.");
|
|
890
877
|
}
|
|
891
878
|
}
|
|
892
|
-
function
|
|
893
|
-
const
|
|
894
|
-
if (!manifest?.app) {
|
|
895
|
-
throw new CliError(`No ${MANIFEST_NAME} with an "app" slug here. Run \`railcode init <app>\` first, or add ${MANIFEST_NAME}.`, 2);
|
|
896
|
-
}
|
|
897
|
-
assertAppName(manifest.app);
|
|
898
|
-
return manifest.app;
|
|
899
|
-
}
|
|
900
|
-
async function fetchDbConnections(config, appUuid) {
|
|
901
|
-
const resp = await authedFetch(config, `/api/organizations/${config.orgUuid}/apps/${appUuid}/connections`);
|
|
879
|
+
async function fetchDbConnections(config) {
|
|
880
|
+
const resp = await authedFetch(config, `/api/organizations/${config.orgUuid}/data/connections`);
|
|
902
881
|
if (resp.status === 401)
|
|
903
882
|
await reLoginOrThrow();
|
|
904
883
|
return (await readJsonOrThrow(resp, "List connections"));
|
|
905
884
|
}
|
|
906
|
-
async function runDbQuery(config,
|
|
907
|
-
const resp = await authedFetch(config, `/api/organizations/${config.orgUuid}/
|
|
885
|
+
async function runDbQuery(config, body) {
|
|
886
|
+
const resp = await authedFetch(config, `/api/organizations/${config.orgUuid}/data/sql`, {
|
|
908
887
|
method: "POST",
|
|
909
888
|
headers: { "Content-Type": "application/json" },
|
|
910
889
|
body: JSON.stringify(body),
|
|
@@ -943,9 +922,8 @@ function camelToKebab(value) {
|
|
|
943
922
|
// (`railcode connector list|fetch`)
|
|
944
923
|
//
|
|
945
924
|
// Service connectors are org-configured HTTP proxies to downstream SaaS APIs.
|
|
946
|
-
//
|
|
947
|
-
//
|
|
948
|
-
// `railcode dev` forwards to.
|
|
925
|
+
// Like `railcode db`, these one-shot commands hit the org-scoped `/data/*` plane
|
|
926
|
+
// with the login bearer token — no app (and no railcode.json) required.
|
|
949
927
|
// ---------------------------------------------------------------------------
|
|
950
928
|
const CONNECTOR_HELP = `railcode connector — service connectors
|
|
951
929
|
|
|
@@ -972,8 +950,8 @@ Fetch options:
|
|
|
972
950
|
--json Print the raw { status, ok, headers, body, truncated } envelope
|
|
973
951
|
|
|
974
952
|
The connector holds the credential; you control only method/path/body. A non-2xx
|
|
975
|
-
upstream status is still printed but exits non-zero.
|
|
976
|
-
${MANIFEST_NAME}
|
|
953
|
+
upstream status is still printed but exits non-zero. Works right after
|
|
954
|
+
\`railcode login\` — no app or ${MANIFEST_NAME} required.
|
|
977
955
|
`;
|
|
978
956
|
async function commandConnector(args) {
|
|
979
957
|
try {
|
|
@@ -1013,8 +991,7 @@ async function commandConnectorList(args) {
|
|
|
1013
991
|
throw new CliError(`railcode connector list takes no arguments (got "${args.rest[1]}").`, 2);
|
|
1014
992
|
}
|
|
1015
993
|
const config = requireLogin(args);
|
|
1016
|
-
const
|
|
1017
|
-
const connectors = await fetchServiceConnectors(config, app.uuid);
|
|
994
|
+
const connectors = await fetchServiceConnectors(config);
|
|
1018
995
|
if (args.options.json) {
|
|
1019
996
|
console.log(JSON.stringify(connectors, null, 2));
|
|
1020
997
|
return;
|
|
@@ -1040,8 +1017,7 @@ async function commandConnectorFetch(args) {
|
|
|
1040
1017
|
: null;
|
|
1041
1018
|
const payload = buildConnectorRequest({ connector, method, path: args.rest[1] ?? "", body });
|
|
1042
1019
|
const config = requireLogin(args);
|
|
1043
|
-
const
|
|
1044
|
-
const envelope = await runConnectorRequest(config, app.uuid, payload);
|
|
1020
|
+
const envelope = await runConnectorRequest(config, payload);
|
|
1045
1021
|
if (args.options.json) {
|
|
1046
1022
|
console.log(JSON.stringify(envelope, null, 2));
|
|
1047
1023
|
}
|
|
@@ -1065,8 +1041,7 @@ async function commandConnectorDocs(args) {
|
|
|
1065
1041
|
throw new CliError("Pass either --json or --openapi, not both.", 2);
|
|
1066
1042
|
}
|
|
1067
1043
|
const config = requireLogin(args);
|
|
1068
|
-
const
|
|
1069
|
-
const docs = await fetchServiceConnectorDocs(config, app.uuid, name);
|
|
1044
|
+
const docs = await fetchServiceConnectorDocs(config, name);
|
|
1070
1045
|
if (args.options.json) {
|
|
1071
1046
|
console.log(JSON.stringify(docs, null, 2));
|
|
1072
1047
|
return;
|
|
@@ -1081,14 +1056,14 @@ async function commandConnectorDocs(args) {
|
|
|
1081
1056
|
}
|
|
1082
1057
|
console.log(renderConnectorDocs(docs));
|
|
1083
1058
|
}
|
|
1084
|
-
async function fetchServiceConnectors(config
|
|
1085
|
-
const resp = await authedFetch(config, `/api/organizations/${config.orgUuid}/
|
|
1059
|
+
async function fetchServiceConnectors(config) {
|
|
1060
|
+
const resp = await authedFetch(config, `/api/organizations/${config.orgUuid}/data/service-connectors`);
|
|
1086
1061
|
if (resp.status === 401)
|
|
1087
1062
|
await reLoginOrThrow();
|
|
1088
1063
|
return (await readJsonOrThrow(resp, "List service connectors"));
|
|
1089
1064
|
}
|
|
1090
|
-
async function fetchServiceConnectorDocs(config,
|
|
1091
|
-
const resp = await authedFetch(config, `/api/organizations/${config.orgUuid}/
|
|
1065
|
+
async function fetchServiceConnectorDocs(config, name) {
|
|
1066
|
+
const resp = await authedFetch(config, `/api/organizations/${config.orgUuid}/data/service-connectors/${encodeURIComponent(name)}`);
|
|
1092
1067
|
if (resp.status === 401)
|
|
1093
1068
|
await reLoginOrThrow();
|
|
1094
1069
|
if (resp.status === 404) {
|
|
@@ -1096,8 +1071,8 @@ async function fetchServiceConnectorDocs(config, appUuid, name) {
|
|
|
1096
1071
|
}
|
|
1097
1072
|
return (await readJsonOrThrow(resp, "Connector docs"));
|
|
1098
1073
|
}
|
|
1099
|
-
async function runConnectorRequest(config,
|
|
1100
|
-
const resp = await authedFetch(config, `/api/organizations/${config.orgUuid}/
|
|
1074
|
+
async function runConnectorRequest(config, body) {
|
|
1075
|
+
const resp = await authedFetch(config, `/api/organizations/${config.orgUuid}/data/service-connectors/request`, {
|
|
1101
1076
|
method: "POST",
|
|
1102
1077
|
headers: { "Content-Type": "application/json" },
|
|
1103
1078
|
body: JSON.stringify(body),
|