@bytesbrains/cruise 0.12.1 → 0.13.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/{budget-FIRNSN67.mjs → budget-IIC4NJUU.mjs} +6 -5
- package/dist/{chunk-FGLMW5IY.mjs → chunk-2Z62Z53P.mjs} +2 -2
- package/dist/chunk-5AFYJTLS.mjs +62 -0
- package/dist/{chunk-WS6NFRIU.mjs → chunk-5LRJO4Z3.mjs} +1 -1
- package/dist/chunk-7ZUKADIS.mjs +131 -0
- package/dist/{chunk-LALZUKEC.mjs → chunk-A4DIVNYV.mjs} +1 -0
- package/dist/chunk-CDBZLSL7.mjs +65 -0
- package/dist/chunk-D3K25SBO.mjs +69 -0
- package/dist/chunk-NR4K7AUA.mjs +17 -0
- package/dist/{chunk-GUZNI3NS.mjs → chunk-PNJVYZ3Y.mjs} +3 -56
- package/dist/chunk-TJR2U73N.mjs +12 -0
- package/dist/{chunk-THEXUHQC.mjs → chunk-UBM65ZNR.mjs} +1 -0
- package/dist/{chunk-JZPUTXM7.mjs → chunk-Y2I46CTD.mjs} +113 -1
- package/dist/{compress-3DWG35BY.mjs → compress-QAEEBNVF.mjs} +1 -2
- package/dist/{conformance-NPFDYCQL.mjs → conformance-H2DRKMVX.mjs} +4 -5
- package/dist/cruise.mjs +132 -32
- package/dist/demo-seed-PRVDIWCM.mjs +59 -0
- package/dist/doctor-LVMXEX35.mjs +802 -0
- package/dist/{fallback-P5KK55M4.mjs → fallback-HRVI5XCK.mjs} +7 -6
- package/dist/journey-JXQ3VYCT.mjs +136 -0
- package/dist/{keys-FWPQPMTW.mjs → keys-S5QOOVMS.mjs} +3 -4
- package/dist/{ledger-XBGWXY6C.mjs → ledger-DWOMA7WD.mjs} +2 -3
- package/dist/{member-ZBV4YG2M.mjs → member-R7HUJK45.mjs} +1 -2
- package/dist/metrics-LCO4YNPW.mjs +144 -0
- package/dist/{report-VRYJ3W5L.mjs → report-CLNJPK6Z.mjs} +2 -3
- package/dist/secrets-check-6PWXXJM7.mjs +65 -0
- package/dist/{service-key-N2RZ7FMZ.mjs → service-key-E6SGTLWA.mjs} +1 -2
- package/dist/{smoke-ZNYX6RO5.mjs → smoke-DFNUPTZ7.mjs} +1 -2
- package/dist/staging-seed-647DRUW5.mjs +41 -0
- package/dist/{sweep-SZX7OIDK.mjs → sweep-5O32ZU4T.mjs} +2 -3
- package/dist/{tenant-4YDGI23Q.mjs → tenant-DRN6BAOI.mjs} +13 -9
- package/dist/{tier-4L3SPLFP.mjs → tier-JSY5OU65.mjs} +1 -2
- package/package.json +2 -2
- package/dist/chunk-7NQHBXVZ.mjs +0 -104
- package/dist/chunk-ICJVJSTC.mjs +0 -42
- package/dist/chunk-N3YKWKOA.mjs +0 -9
package/dist/cruise.mjs
CHANGED
|
@@ -6,53 +6,72 @@ import {
|
|
|
6
6
|
} from "./chunk-2FB2T3UI.mjs";
|
|
7
7
|
import {
|
|
8
8
|
provisionTenant
|
|
9
|
-
} from "./chunk-
|
|
10
|
-
import "./chunk-
|
|
9
|
+
} from "./chunk-PNJVYZ3Y.mjs";
|
|
10
|
+
import "./chunk-5AFYJTLS.mjs";
|
|
11
|
+
import "./chunk-D3K25SBO.mjs";
|
|
12
|
+
import "./chunk-CDBZLSL7.mjs";
|
|
11
13
|
import "./chunk-2NVDAK5J.mjs";
|
|
12
|
-
import "./chunk-
|
|
14
|
+
import "./chunk-2Z62Z53P.mjs";
|
|
13
15
|
import "./chunk-4447IUTF.mjs";
|
|
14
16
|
import "./chunk-XOH3XKM3.mjs";
|
|
15
17
|
import "./chunk-42ERHAJD.mjs";
|
|
16
18
|
import "./chunk-BNP63KB2.mjs";
|
|
17
|
-
import "./chunk-ICJVJSTC.mjs";
|
|
18
19
|
import "./chunk-UNXM6FSM.mjs";
|
|
19
20
|
import "./chunk-SYTYOTO4.mjs";
|
|
20
21
|
import "./chunk-O7TNRKSA.mjs";
|
|
22
|
+
import "./chunk-O7TNRKSA.mjs";
|
|
23
|
+
import "./chunk-7ZUKADIS.mjs";
|
|
21
24
|
import "./chunk-T3ICD43U.mjs";
|
|
22
25
|
import "./chunk-RT4R2W6H.mjs";
|
|
23
|
-
import "./chunk-
|
|
24
|
-
import "./chunk-
|
|
26
|
+
import "./chunk-NR4K7AUA.mjs";
|
|
27
|
+
import "./chunk-UBM65ZNR.mjs";
|
|
28
|
+
import "./chunk-A4DIVNYV.mjs";
|
|
25
29
|
import "./chunk-5TVD3ZAI.mjs";
|
|
26
30
|
import {
|
|
27
31
|
HttpD1,
|
|
28
|
-
LocalD1
|
|
29
|
-
|
|
32
|
+
LocalD1,
|
|
33
|
+
connect,
|
|
34
|
+
loadWranglerConfig,
|
|
35
|
+
resolveScope,
|
|
36
|
+
wranglerConfigPath
|
|
37
|
+
} from "./chunk-Y2I46CTD.mjs";
|
|
38
|
+
|
|
39
|
+
// packages/cli/src/main.ts
|
|
40
|
+
import path8 from "node:path";
|
|
30
41
|
|
|
31
42
|
// selfhost/commands.ts
|
|
32
43
|
var COMMANDS = {
|
|
33
|
-
"key:issue": { load: () => import("./keys-
|
|
34
|
-
"key:revoke": { load: () => import("./keys-
|
|
35
|
-
"key:list": { load: () => import("./keys-
|
|
36
|
-
"budget:show": { load: () => import("./budget-
|
|
37
|
-
"budget:set": { load: () => import("./budget-
|
|
38
|
-
"budget:align": { load: () => import("./budget-
|
|
39
|
-
"tenant:provision": { load: () => import("./tenant-
|
|
40
|
-
"tenant:list": { load: () => import("./tenant-
|
|
41
|
-
"member:grant": { load: () => import("./member-
|
|
42
|
-
"member:revoke": { load: () => import("./member-
|
|
43
|
-
"member:list": { load: () => import("./member-
|
|
44
|
-
"service-key:issue": { load: () => import("./service-key-
|
|
45
|
-
"fallback:show": { load: () => import("./fallback-
|
|
46
|
-
"fallback:set": { load: () => import("./fallback-
|
|
47
|
-
"tier:show": { load: () => import("./tier-
|
|
48
|
-
"tier:set": { load: () => import("./tier-
|
|
49
|
-
"compress:show": { load: () => import("./compress-
|
|
50
|
-
"compress:set": { load: () => import("./compress-
|
|
51
|
-
ledger: { load: () => import("./ledger-
|
|
52
|
-
report: { load: () => import("./report-
|
|
53
|
-
conformance: { load: () => import("./conformance-
|
|
54
|
-
sweep: { load: () => import("./sweep-
|
|
55
|
-
smoke: { load: () => import("./smoke-
|
|
44
|
+
"key:issue": { load: () => import("./keys-S5QOOVMS.mjs"), args: ["issue"] },
|
|
45
|
+
"key:revoke": { load: () => import("./keys-S5QOOVMS.mjs"), args: ["revoke"] },
|
|
46
|
+
"key:list": { load: () => import("./keys-S5QOOVMS.mjs"), args: ["list"] },
|
|
47
|
+
"budget:show": { load: () => import("./budget-IIC4NJUU.mjs"), args: ["show"] },
|
|
48
|
+
"budget:set": { load: () => import("./budget-IIC4NJUU.mjs"), args: ["set"] },
|
|
49
|
+
"budget:align": { load: () => import("./budget-IIC4NJUU.mjs"), args: ["align"] },
|
|
50
|
+
"tenant:provision": { load: () => import("./tenant-DRN6BAOI.mjs"), args: ["provision"] },
|
|
51
|
+
"tenant:list": { load: () => import("./tenant-DRN6BAOI.mjs"), args: ["list"] },
|
|
52
|
+
"member:grant": { load: () => import("./member-R7HUJK45.mjs"), args: ["grant"] },
|
|
53
|
+
"member:revoke": { load: () => import("./member-R7HUJK45.mjs"), args: ["revoke"] },
|
|
54
|
+
"member:list": { load: () => import("./member-R7HUJK45.mjs"), args: ["list"] },
|
|
55
|
+
"service-key:issue": { load: () => import("./service-key-E6SGTLWA.mjs"), args: ["issue"] },
|
|
56
|
+
"fallback:show": { load: () => import("./fallback-HRVI5XCK.mjs"), args: ["show"] },
|
|
57
|
+
"fallback:set": { load: () => import("./fallback-HRVI5XCK.mjs"), args: ["set"] },
|
|
58
|
+
"tier:show": { load: () => import("./tier-JSY5OU65.mjs"), args: ["show"] },
|
|
59
|
+
"tier:set": { load: () => import("./tier-JSY5OU65.mjs"), args: ["set"] },
|
|
60
|
+
"compress:show": { load: () => import("./compress-QAEEBNVF.mjs"), args: ["show"] },
|
|
61
|
+
"compress:set": { load: () => import("./compress-QAEEBNVF.mjs"), args: ["set"] },
|
|
62
|
+
ledger: { load: () => import("./ledger-DWOMA7WD.mjs"), args: [] },
|
|
63
|
+
report: { load: () => import("./report-CLNJPK6Z.mjs"), args: [] },
|
|
64
|
+
conformance: { load: () => import("./conformance-H2DRKMVX.mjs"), args: [] },
|
|
65
|
+
sweep: { load: () => import("./sweep-5O32ZU4T.mjs"), args: [] },
|
|
66
|
+
smoke: { load: () => import("./smoke-DFNUPTZ7.mjs"), args: [] }
|
|
67
|
+
};
|
|
68
|
+
var CLOUDFLARE_COMMANDS = {
|
|
69
|
+
doctor: { load: () => import("./doctor-LVMXEX35.mjs"), args: [] },
|
|
70
|
+
metrics: { load: () => import("./metrics-LCO4YNPW.mjs"), args: [] },
|
|
71
|
+
journey: { load: () => import("./journey-JXQ3VYCT.mjs"), args: [] },
|
|
72
|
+
"secrets:check": { load: () => import("./secrets-check-6PWXXJM7.mjs"), args: [] },
|
|
73
|
+
"demo:seed": { load: () => import("./demo-seed-PRVDIWCM.mjs"), args: [] },
|
|
74
|
+
"staging:seed": { load: () => import("./staging-seed-647DRUW5.mjs"), args: [] }
|
|
56
75
|
};
|
|
57
76
|
|
|
58
77
|
// selfhost/measure.ts
|
|
@@ -621,6 +640,58 @@ async function inContainer(argv) {
|
|
|
621
640
|
process.exitCode = code;
|
|
622
641
|
}
|
|
623
642
|
|
|
643
|
+
// packages/cli/src/release.ts
|
|
644
|
+
import { spawn as spawn4 } from "node:child_process";
|
|
645
|
+
import { readdirSync } from "node:fs";
|
|
646
|
+
import path7 from "node:path";
|
|
647
|
+
function wrangler2(args) {
|
|
648
|
+
return new Promise((resolve, reject) => {
|
|
649
|
+
const child = spawn4("npx", ["--yes", `wrangler@${WRANGLER_VERSION}`, ...args, "-c", wranglerConfigPath()], {
|
|
650
|
+
stdio: "inherit",
|
|
651
|
+
// CI=true answers wrangler's confirmation prompt on a remote migration apply.
|
|
652
|
+
env: { ...process.env, CI: "true", WRANGLER_SEND_METRICS: "false" }
|
|
653
|
+
});
|
|
654
|
+
child.on("error", reject);
|
|
655
|
+
child.on("exit", (code) => code === 0 ? resolve() : reject(new Error(`wrangler ${args.join(" ")} exited ${code}`)));
|
|
656
|
+
});
|
|
657
|
+
}
|
|
658
|
+
function database(environment) {
|
|
659
|
+
const scope = resolveScope(loadWranglerConfig(), environment);
|
|
660
|
+
return scope.d1_databases?.[0] ?? null;
|
|
661
|
+
}
|
|
662
|
+
function shippedMigrations(entry, configPath) {
|
|
663
|
+
const dir = path7.resolve(path7.dirname(configPath), entry.migrations_dir ?? "migrations");
|
|
664
|
+
return readdirSync(dir).filter((file) => file.endsWith(".sql")).sort();
|
|
665
|
+
}
|
|
666
|
+
function pendingMigrations(shipped, applied) {
|
|
667
|
+
const done = new Set(applied);
|
|
668
|
+
return shipped.filter((name) => !done.has(name));
|
|
669
|
+
}
|
|
670
|
+
async function migrate(environment) {
|
|
671
|
+
const entry = database(environment);
|
|
672
|
+
if (!entry?.database_name) throw new Error(`--env ${environment} has no D1 database in ${wranglerConfigPath()}`);
|
|
673
|
+
await wrangler2(["d1", "migrations", "apply", entry.database_name, "--remote", "--env", environment]);
|
|
674
|
+
}
|
|
675
|
+
async function deploy2(environment) {
|
|
676
|
+
const entry = database(environment);
|
|
677
|
+
if (entry) {
|
|
678
|
+
const token2 = process.env.CLOUDFLARE_API_TOKEN;
|
|
679
|
+
if (!token2) throw new Error("Set CLOUDFLARE_API_TOKEN: deploy checks the database's migrations first.");
|
|
680
|
+
const accountId = loadWranglerConfig().account_id;
|
|
681
|
+
if (!accountId || !entry.database_id) throw new Error(`--env ${environment} needs account_id and database_id`);
|
|
682
|
+
const db = new HttpD1(accountId, entry.database_id, token2);
|
|
683
|
+
const table = entry.migrations_table ?? "d1_migrations";
|
|
684
|
+
const { results } = await db.query(`SELECT name FROM ${table}`, []);
|
|
685
|
+
const pending = pendingMigrations(shippedMigrations(entry, wranglerConfigPath()), results.map((r) => r.name));
|
|
686
|
+
if (pending.length > 0) {
|
|
687
|
+
throw new Error(
|
|
688
|
+
`${environment} has not applied ${pending.length} migration(s) this Worker reads: ${pending.join(", ")}. Run \`cruise migrate --config ${path7.basename(wranglerConfigPath())} --env ${environment}\` first.`
|
|
689
|
+
);
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
await wrangler2(["deploy", "--env", environment]);
|
|
693
|
+
}
|
|
694
|
+
|
|
624
695
|
// packages/cli/src/main.ts
|
|
625
696
|
var HELP = `cruise ${VERSION} \u2014 one OpenAI-compatible endpoint in front of every model provider
|
|
626
697
|
|
|
@@ -636,6 +707,12 @@ Your own Cloudflare account (needs CLOUDFLARE_API_TOKEN):
|
|
|
636
707
|
cruise cloudflare measure [--name cruise]
|
|
637
708
|
cruise cloudflare <admin command> [--name cruise]
|
|
638
709
|
|
|
710
|
+
A deployment described by your own wrangler.jsonc (needs CLOUDFLARE_API_TOKEN):
|
|
711
|
+
cruise migrate --config wrangler.jsonc --env <env> apply the pinned Worker's migrations
|
|
712
|
+
cruise deploy --config wrangler.jsonc --env <env> deploy it; refused while a migration is pending
|
|
713
|
+
cruise measure --config wrangler.jsonc --env <env> --base https://\u2026
|
|
714
|
+
cruise <command> --config wrangler.jsonc --env <env> any admin command, and ${Object.keys(CLOUDFLARE_COMMANDS).join(", ")}
|
|
715
|
+
|
|
639
716
|
Admin commands: ${Object.keys(COMMANDS).join(", ")}
|
|
640
717
|
Manual: https://gitlab.com/bytesbrains-oss/cruise/-/blob/main/docs/self-hosting.md`;
|
|
641
718
|
function takeFlag(argv, name) {
|
|
@@ -644,7 +721,7 @@ function takeFlag(argv, name) {
|
|
|
644
721
|
return { value: argv[i + 1], rest: [...argv.slice(0, i), ...argv.slice(i + 2)] };
|
|
645
722
|
}
|
|
646
723
|
async function runScript(name, rest) {
|
|
647
|
-
const command = COMMANDS[name];
|
|
724
|
+
const command = COMMANDS[name] ?? CLOUDFLARE_COMMANDS[name];
|
|
648
725
|
if (!command) throw new Error(`unknown command: ${name}
|
|
649
726
|
|
|
650
727
|
${HELP}`);
|
|
@@ -667,7 +744,30 @@ async function cloudflare(argv) {
|
|
|
667
744
|
}
|
|
668
745
|
return runScript(sub, ["--env", "cloudflare", ...args]);
|
|
669
746
|
}
|
|
747
|
+
function flagValue(argv, name) {
|
|
748
|
+
const i = argv.indexOf(`--${name}`);
|
|
749
|
+
return i >= 0 ? argv[i + 1] : void 0;
|
|
750
|
+
}
|
|
751
|
+
async function configured(argv) {
|
|
752
|
+
const [name, ...rest] = argv;
|
|
753
|
+
const environment = flagValue(rest, "env");
|
|
754
|
+
if (!name || !environment) throw new Error(`--config needs a command and --env <environment>
|
|
755
|
+
|
|
756
|
+
${HELP}`);
|
|
757
|
+
if (name === "migrate") return migrate(environment);
|
|
758
|
+
if (name === "deploy") return deploy2(environment);
|
|
759
|
+
if (name === "measure") {
|
|
760
|
+
const base = flagValue(rest, "base");
|
|
761
|
+
if (!base) throw new Error("measure --config needs --base https://\u2026 : the deployment's own URL");
|
|
762
|
+
const others = rest.filter((arg, i) => !(arg === "--env" || rest[i - 1] === "--env"));
|
|
763
|
+
return measure(others, { db: connect(environment), environment, base });
|
|
764
|
+
}
|
|
765
|
+
return runScript(name, rest);
|
|
766
|
+
}
|
|
670
767
|
async function main(argv) {
|
|
768
|
+
const { value: config, rest: withoutConfig } = takeFlag(argv, "config");
|
|
769
|
+
if (config) process.env.CRUISE_WRANGLER_CONFIG = path8.resolve(config);
|
|
770
|
+
if (process.env.CRUISE_WRANGLER_CONFIG) return configured(withoutConfig);
|
|
671
771
|
const [name, ...rest] = argv;
|
|
672
772
|
if (!name || name === "help" || name === "--help" || name === "-h") {
|
|
673
773
|
console.log(HELP);
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Built by packages/cli/build.ts.
|
|
3
|
+
import {
|
|
4
|
+
DEMO_EMULATOR_BASE,
|
|
5
|
+
DEMO_ENVIRONMENT,
|
|
6
|
+
seedDemoCatalogue
|
|
7
|
+
} from "./chunk-D3K25SBO.mjs";
|
|
8
|
+
import {
|
|
9
|
+
productionRoutable,
|
|
10
|
+
requireSource
|
|
11
|
+
} from "./chunk-CDBZLSL7.mjs";
|
|
12
|
+
import "./chunk-A4DIVNYV.mjs";
|
|
13
|
+
import {
|
|
14
|
+
connect,
|
|
15
|
+
environmentOf,
|
|
16
|
+
parseArgs,
|
|
17
|
+
run
|
|
18
|
+
} from "./chunk-Y2I46CTD.mjs";
|
|
19
|
+
|
|
20
|
+
// scripts/demo-seed.ts
|
|
21
|
+
var SOURCE = "production";
|
|
22
|
+
run(async () => {
|
|
23
|
+
const args = parseArgs(process.argv.slice(2));
|
|
24
|
+
const environment = environmentOf(args);
|
|
25
|
+
if (environment !== DEMO_ENVIRONMENT) {
|
|
26
|
+
throw new Error(
|
|
27
|
+
`demo:seed refuses --env ${environment}. It zeroes every price and repoints every upstream at the emulator, which is only ever right on the demo. Pass --env ${DEMO_ENVIRONMENT}.`
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
const emulator = typeof args.emulator === "string" ? args.emulator : DEMO_EMULATOR_BASE;
|
|
31
|
+
const measured = requireSource(await productionRoutable(connect(SOURCE)), SOURCE);
|
|
32
|
+
console.log(`Cruise \u2014 demo catalogue, from ${SOURCE}
|
|
33
|
+
`);
|
|
34
|
+
console.log(` emulator ${emulator}`);
|
|
35
|
+
console.log(` routable ${measured.length} model(s) in ${SOURCE}`);
|
|
36
|
+
if (args["dry-run"] === true) {
|
|
37
|
+
for (const m of measured) console.log(` ${m.modality.padEnd(10)} ${m.id}`);
|
|
38
|
+
console.log("\n --dry-run: nothing written.");
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
const summary = await seedDemoCatalogue(connect(environment), measured, emulator);
|
|
42
|
+
console.log(`
|
|
43
|
+
upstreams ${summary.upstreams} repointed at the emulator`);
|
|
44
|
+
console.log(` prices ${summary.pricedRows} token row(s), ${summary.componentRows} component row(s) zeroed`);
|
|
45
|
+
console.log(` budgets ${summary.budgets} row(s) at reserve_micros = 0`);
|
|
46
|
+
console.log(` measured ${summary.routable.length} model(s) now routable on the demo`);
|
|
47
|
+
if (summary.absent.length > 0) {
|
|
48
|
+
console.log(`
|
|
49
|
+
${summary.absent.length} model(s) ${SOURCE} serves are NOT IN THIS CATALOGUE \u2014 run migrate:demo:`);
|
|
50
|
+
for (const id of summary.absent) console.log(` ${id}`);
|
|
51
|
+
}
|
|
52
|
+
if (summary.unservable.length > 0) {
|
|
53
|
+
console.log(`
|
|
54
|
+
${summary.unservable.length} model(s) left unmeasured \u2014 the emulator has no route for them:`);
|
|
55
|
+
for (const id of summary.unservable) console.log(` ${id}`);
|
|
56
|
+
}
|
|
57
|
+
console.log(`
|
|
58
|
+
Run \`npm run doctor -- --env ${DEMO_ENVIRONMENT}\` to check the mirror.`);
|
|
59
|
+
});
|