@nbt-dev/nbt 0.0.8 → 0.0.10
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/nbt.js +117 -36
- package/package.json +1 -1
- package/stdlib/auth/migrations/20260614000000_add_user_devtools_settings/migration.nbt +4 -0
- package/stdlib/auth/migrations/20260614000000_add_user_devtools_settings/schema_snapshot.nbt +59 -0
- package/stdlib/auth/schema.nbt +5 -30
- package/stdlib/calendar/schema.nbt +2 -3
- package/stdlib/crm/schema.nbt +3 -4
- package/stdlib/design/schema.nbt +2 -2
- package/stdlib/dns/schema.nbt +3 -3
- package/stdlib/email/schema.nbt +12 -11
- package/stdlib/ingest/schema.nbt +4 -4
- package/stdlib/notifications/schema.nbt +2 -2
- package/stdlib/phone/schema.nbt +9 -10
- package/stdlib/workflows/schema.nbt +0 -4
- package/vendor/linux-x64/cartridges/auth/migrations/20260614000000_add_user_devtools_settings/migration.nbt +4 -0
- package/vendor/linux-x64/cartridges/auth/migrations/20260614000000_add_user_devtools_settings/schema_snapshot.nbt +59 -0
- package/vendor/linux-x64/cartridges/auth/schema.nbt +5 -30
- package/vendor/linux-x64/cartridges/calendar/schema.nbt +2 -3
- package/vendor/linux-x64/cartridges/crm/schema.nbt +3 -4
- package/vendor/linux-x64/cartridges/design/schema.nbt +2 -2
- package/vendor/linux-x64/cartridges/dns/schema.nbt +3 -3
- package/vendor/linux-x64/cartridges/email/schema.nbt +12 -11
- package/vendor/linux-x64/cartridges/ingest/schema.nbt +4 -4
- package/vendor/linux-x64/cartridges/notifications/schema.nbt +2 -2
- package/vendor/linux-x64/cartridges/phone/schema.nbt +9 -10
- package/vendor/linux-x64/cartridges/workflows/schema.nbt +0 -4
- package/vendor/linux-x64/console +0 -0
- package/vendor/linux-x64/nbt +0 -0
package/dist/nbt.js
CHANGED
|
@@ -3439,7 +3439,8 @@ function corsOriginsFromNbtJson() {
|
|
|
3439
3439
|
try {
|
|
3440
3440
|
const cfg = JSON.parse(fs2.readFileSync(candidate, "utf8"));
|
|
3441
3441
|
const c = cfg?.cors;
|
|
3442
|
-
if (Array.isArray(c))
|
|
3442
|
+
if (Array.isArray(c))
|
|
3443
|
+
return c.filter((x) => typeof x === "string");
|
|
3443
3444
|
if (typeof c === "string") return [c];
|
|
3444
3445
|
} catch {
|
|
3445
3446
|
}
|
|
@@ -3484,8 +3485,18 @@ function forwardToNative(argv2) {
|
|
|
3484
3485
|
}
|
|
3485
3486
|
process.exit(r.status === null ? 1 : r.status);
|
|
3486
3487
|
}
|
|
3488
|
+
function packageVersion() {
|
|
3489
|
+
try {
|
|
3490
|
+
const pkg = JSON.parse(
|
|
3491
|
+
fs2.readFileSync(path3.join(__dirname, "..", "package.json"), "utf8")
|
|
3492
|
+
);
|
|
3493
|
+
return typeof pkg?.version === "string" ? pkg.version : "unknown";
|
|
3494
|
+
} catch {
|
|
3495
|
+
return "unknown";
|
|
3496
|
+
}
|
|
3497
|
+
}
|
|
3487
3498
|
var program2 = new Command();
|
|
3488
|
-
program2.name("nbt").description("nbt CLI
|
|
3499
|
+
program2.name("nbt").description("nbt.dev CLI").version(packageVersion(), "-v, --version", "Print the @nbt-dev/nbt version");
|
|
3489
3500
|
var NBT = [
|
|
3490
3501
|
["install", "Install a cartridge on a live instance"],
|
|
3491
3502
|
["generate", "Generate a typed client from contracts"],
|
|
@@ -3503,12 +3514,17 @@ for (const [name, summary] of [...NBT, ...CONSOLE]) {
|
|
|
3503
3514
|
}
|
|
3504
3515
|
var customCommands = /* @__PURE__ */ new Set();
|
|
3505
3516
|
customCommands.add("init");
|
|
3506
|
-
program2.command("init").description("Scaffold an nbt project (nbt.json, nbt/, generated/)").argument(
|
|
3507
|
-
|
|
3508
|
-
|
|
3509
|
-
|
|
3510
|
-
|
|
3511
|
-
|
|
3517
|
+
program2.command("init").description("Scaffold an nbt project (nbt.json, nbt/, generated/)").argument(
|
|
3518
|
+
"[dir]",
|
|
3519
|
+
"directory to create the project in (default: current directory)"
|
|
3520
|
+
).option("-y, --yes", "skip prompts; include the hello-world example").option("--no-example", "skip the hello-world example cartridge").action(
|
|
3521
|
+
(dir, opts) => {
|
|
3522
|
+
runInit(dir, opts).catch((e) => {
|
|
3523
|
+
console.error(`nbt init: ${e?.message ?? e}`);
|
|
3524
|
+
process.exit(1);
|
|
3525
|
+
});
|
|
3526
|
+
}
|
|
3527
|
+
);
|
|
3512
3528
|
var NBT_JSON_TEMPLATE = `{
|
|
3513
3529
|
"carts": "nbt",
|
|
3514
3530
|
"generated": "generated",
|
|
@@ -3537,13 +3553,17 @@ async function runInit(dir, opts) {
|
|
|
3537
3553
|
const root = dir ? path3.resolve(process.cwd(), dir) : process.cwd();
|
|
3538
3554
|
if (dir) fs2.mkdirSync(root, { recursive: true });
|
|
3539
3555
|
if (fs2.existsSync(path3.join(root, "nbt.json"))) {
|
|
3540
|
-
throw new Error(
|
|
3556
|
+
throw new Error(
|
|
3557
|
+
`nbt.json already exists ${dir ? `in ${dir}` : "here"} \u2014 this is already an nbt project`
|
|
3558
|
+
);
|
|
3541
3559
|
}
|
|
3542
3560
|
if (!fs2.existsSync(path3.join(STDLIB, "auth", "schema.nbt"))) {
|
|
3543
3561
|
throw new Error("bundled auth cartridge is missing (broken install)");
|
|
3544
3562
|
}
|
|
3545
3563
|
if (fs2.existsSync(path3.join(root, "nbt", "auth"))) {
|
|
3546
|
-
throw new Error(
|
|
3564
|
+
throw new Error(
|
|
3565
|
+
"nbt/auth already exists; refusing to overwrite it during init"
|
|
3566
|
+
);
|
|
3547
3567
|
}
|
|
3548
3568
|
fs2.writeFileSync(path3.join(root, "nbt.json"), NBT_JSON_TEMPLATE);
|
|
3549
3569
|
fs2.mkdirSync(path3.join(root, "nbt"), { recursive: true });
|
|
@@ -3559,16 +3579,27 @@ async function runInit(dir, opts) {
|
|
|
3559
3579
|
console.log("\nCreated example cartridge nbt/hello/ (entity Note).");
|
|
3560
3580
|
console.log("\nNext:");
|
|
3561
3581
|
if (dir) console.log(` cd ${dir}`);
|
|
3562
|
-
console.log(
|
|
3582
|
+
console.log(
|
|
3583
|
+
" nbt dev # boot the console + live-reload on save"
|
|
3584
|
+
);
|
|
3563
3585
|
} else {
|
|
3564
|
-
if (dir)
|
|
3565
|
-
|
|
3566
|
-
|
|
3586
|
+
if (dir)
|
|
3587
|
+
console.log(
|
|
3588
|
+
`
|
|
3589
|
+
Next: cd ${dir}, then run \`nbt dev\` or add a standard cartridge with \`nbt add <name>\`.`
|
|
3590
|
+
);
|
|
3591
|
+
else
|
|
3592
|
+
console.log(
|
|
3593
|
+
"\nNext: run `nbt dev`, or add another standard cartridge with `nbt add <name>`."
|
|
3594
|
+
);
|
|
3567
3595
|
}
|
|
3568
3596
|
}
|
|
3569
3597
|
async function wantExample() {
|
|
3570
3598
|
if (!process.stdin.isTTY) return true;
|
|
3571
|
-
const rl = readline.createInterface({
|
|
3599
|
+
const rl = readline.createInterface({
|
|
3600
|
+
input: process.stdin,
|
|
3601
|
+
output: process.stdout
|
|
3602
|
+
});
|
|
3572
3603
|
try {
|
|
3573
3604
|
const ans = (await rl.question("Add a hello-world example cartridge? [Y/n] ")).trim().toLowerCase();
|
|
3574
3605
|
return ans === "" || ans === "y" || ans === "yes";
|
|
@@ -3585,10 +3616,16 @@ program2.command("add").description("Vendor standard-library cartridges into thi
|
|
|
3585
3616
|
try {
|
|
3586
3617
|
const proj = loadNbtProject();
|
|
3587
3618
|
for (const name of cartridges) {
|
|
3588
|
-
const dest = addStandardCartridge(
|
|
3619
|
+
const dest = addStandardCartridge(
|
|
3620
|
+
name,
|
|
3621
|
+
proj.cartsDir,
|
|
3622
|
+
opts.overwrite === true
|
|
3623
|
+
);
|
|
3589
3624
|
console.log(`Added ${name} -> ${path3.relative(proj.rootDir, dest)}`);
|
|
3590
3625
|
}
|
|
3591
|
-
console.log(
|
|
3626
|
+
console.log(
|
|
3627
|
+
"Run `nbt migrate deploy` to deploy the local cartridge set."
|
|
3628
|
+
);
|
|
3592
3629
|
} catch (e) {
|
|
3593
3630
|
console.error(`nbt add: ${e?.message ?? e}`);
|
|
3594
3631
|
process.exit(1);
|
|
@@ -3607,7 +3644,8 @@ function addStandardCartridge(name, cartsDir, overwrite) {
|
|
|
3607
3644
|
}
|
|
3608
3645
|
const dest = path3.join(cartsDir, name);
|
|
3609
3646
|
if (fs2.existsSync(dest)) {
|
|
3610
|
-
if (!overwrite)
|
|
3647
|
+
if (!overwrite)
|
|
3648
|
+
throw new Error(`${dest} already exists; use --overwrite to replace it`);
|
|
3611
3649
|
fs2.rmSync(dest, { recursive: true, force: true });
|
|
3612
3650
|
}
|
|
3613
3651
|
fs2.mkdirSync(cartsDir, { recursive: true });
|
|
@@ -3623,12 +3661,16 @@ program2.command("list").description("List available standard-library modules").
|
|
|
3623
3661
|
const proj = loadNbtProject();
|
|
3624
3662
|
const names = fs2.readdirSync(STDLIB, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name).filter((n) => fs2.existsSync(path3.join(STDLIB, n, "schema.nbt"))).sort();
|
|
3625
3663
|
for (const n of names) {
|
|
3626
|
-
const installed = fs2.existsSync(
|
|
3664
|
+
const installed = fs2.existsSync(
|
|
3665
|
+
path3.join(proj.cartsDir, n, "schema.nbt")
|
|
3666
|
+
);
|
|
3627
3667
|
console.log(installed ? `${n} (installed)` : n);
|
|
3628
3668
|
}
|
|
3629
3669
|
});
|
|
3630
3670
|
customCommands.add("update");
|
|
3631
|
-
program2.command("update").description(
|
|
3671
|
+
program2.command("update").description(
|
|
3672
|
+
"Update vendored standard-library modules from the bundled stdlib"
|
|
3673
|
+
).argument("<module...>", "standard module name(s)").action((modules) => {
|
|
3632
3674
|
try {
|
|
3633
3675
|
const proj = loadNbtProject();
|
|
3634
3676
|
for (const name of modules) {
|
|
@@ -3638,13 +3680,18 @@ program2.command("update").description("Update vendored standard-library modules
|
|
|
3638
3680
|
}
|
|
3639
3681
|
const dest = path3.join(proj.cartsDir, name);
|
|
3640
3682
|
if (!fs2.existsSync(path3.join(dest, "schema.nbt"))) {
|
|
3641
|
-
throw new Error(
|
|
3683
|
+
throw new Error(
|
|
3684
|
+
`'${name}' is not installed in this project \u2014 run: nbt add ${name}`
|
|
3685
|
+
);
|
|
3642
3686
|
}
|
|
3643
3687
|
const written = copyStdlibOver(src, dest);
|
|
3644
|
-
for (const f of written)
|
|
3688
|
+
for (const f of written)
|
|
3689
|
+
console.log(` wrote ${path3.relative(proj.rootDir, f)}`);
|
|
3645
3690
|
console.log(`Updated ${name}.`);
|
|
3646
3691
|
}
|
|
3647
|
-
console.log(
|
|
3692
|
+
console.log(
|
|
3693
|
+
"Run `nbt migrate create <module>` to capture any schema changes, then `nbt migrate deploy`."
|
|
3694
|
+
);
|
|
3648
3695
|
} catch (e) {
|
|
3649
3696
|
console.error(`nbt update: ${e?.message ?? e}`);
|
|
3650
3697
|
process.exit(1);
|
|
@@ -3668,7 +3715,10 @@ function copyStdlibOver(src, dest) {
|
|
|
3668
3715
|
return written;
|
|
3669
3716
|
}
|
|
3670
3717
|
customCommands.add("dev");
|
|
3671
|
-
program2.command("dev").description("Boot the console and live-reload local carts on .nbt change").option(
|
|
3718
|
+
program2.command("dev").description("Boot the console and live-reload local carts on .nbt change").option(
|
|
3719
|
+
"-p, --port <port>",
|
|
3720
|
+
"console HTTP port (default: nbt.json dev env, else 8080)"
|
|
3721
|
+
).option("-d, --data-dir <dir>", "console data dir (default: ./data)").action((opts) => {
|
|
3672
3722
|
runDev(opts).catch((e) => {
|
|
3673
3723
|
console.error(`nbt dev: ${e?.message ?? e}`);
|
|
3674
3724
|
process.exit(1);
|
|
@@ -3692,10 +3742,16 @@ function loadNbtProject() {
|
|
|
3692
3742
|
if (parent === dir) break;
|
|
3693
3743
|
dir = parent;
|
|
3694
3744
|
}
|
|
3695
|
-
return {
|
|
3745
|
+
return {
|
|
3746
|
+
rootDir: process.cwd(),
|
|
3747
|
+
cartsDir: path3.resolve(process.cwd(), "nbt"),
|
|
3748
|
+
port: 8080
|
|
3749
|
+
};
|
|
3696
3750
|
}
|
|
3697
3751
|
function withProjectUpDefaults(argv2) {
|
|
3698
|
-
const hasPort = argv2.some(
|
|
3752
|
+
const hasPort = argv2.some(
|
|
3753
|
+
(arg) => arg === "--port" || arg === "-p" || arg.startsWith("--port=")
|
|
3754
|
+
);
|
|
3699
3755
|
if (hasPort) return argv2;
|
|
3700
3756
|
return [...argv2, "--port", String(loadNbtProject().port)];
|
|
3701
3757
|
}
|
|
@@ -3744,20 +3800,28 @@ function tcpUp(port, host = "127.0.0.1") {
|
|
|
3744
3800
|
}
|
|
3745
3801
|
var sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
3746
3802
|
function installCart(cartDir, port) {
|
|
3747
|
-
const r = (0, import_node_child_process2.spawnSync)(
|
|
3748
|
-
|
|
3749
|
-
|
|
3750
|
-
|
|
3803
|
+
const r = (0, import_node_child_process2.spawnSync)(
|
|
3804
|
+
NBT_BIN,
|
|
3805
|
+
["install", "--path", cartDir, "--port", String(port)],
|
|
3806
|
+
{
|
|
3807
|
+
stdio: "inherit",
|
|
3808
|
+
env: nativeEnv()
|
|
3809
|
+
}
|
|
3810
|
+
);
|
|
3751
3811
|
return r.status === 0;
|
|
3752
3812
|
}
|
|
3753
3813
|
async function runDev(opts) {
|
|
3754
3814
|
const proj = loadNbtProject();
|
|
3755
3815
|
const port = opts.port ? Number(opts.port) : proj.port;
|
|
3756
|
-
if (!Number.isFinite(port) || port <= 0)
|
|
3816
|
+
if (!Number.isFinite(port) || port <= 0)
|
|
3817
|
+
throw new Error(`invalid port '${opts.port}'`);
|
|
3757
3818
|
const upArgs = ["up", "--port", String(port)];
|
|
3758
3819
|
if (opts.dataDir) upArgs.push("--data-dir", opts.dataDir);
|
|
3759
3820
|
console.log(`nbt dev: starting console on :${port}`);
|
|
3760
|
-
const daemon = (0, import_node_child_process2.spawn)(CONSOLE_BIN, upArgs, {
|
|
3821
|
+
const daemon = (0, import_node_child_process2.spawn)(CONSOLE_BIN, upArgs, {
|
|
3822
|
+
stdio: "inherit",
|
|
3823
|
+
env: consoleEnv()
|
|
3824
|
+
});
|
|
3761
3825
|
let shuttingDown = false;
|
|
3762
3826
|
const shutdown = (code = 0) => {
|
|
3763
3827
|
if (shuttingDown) return;
|
|
@@ -3790,7 +3854,9 @@ async function runDev(opts) {
|
|
|
3790
3854
|
}
|
|
3791
3855
|
const carts = discoverCarts(proj.cartsDir);
|
|
3792
3856
|
if (carts.length === 0) {
|
|
3793
|
-
console.warn(
|
|
3857
|
+
console.warn(
|
|
3858
|
+
`nbt dev: no carts found under ${proj.cartsDir} (nothing to watch)`
|
|
3859
|
+
);
|
|
3794
3860
|
}
|
|
3795
3861
|
const applied = /* @__PURE__ */ new Map();
|
|
3796
3862
|
for (const c of carts) {
|
|
@@ -3798,7 +3864,9 @@ async function runDev(opts) {
|
|
|
3798
3864
|
installCart(c, port);
|
|
3799
3865
|
applied.set(c, newestNbtMtime(c));
|
|
3800
3866
|
}
|
|
3801
|
-
console.log(
|
|
3867
|
+
console.log(
|
|
3868
|
+
`nbt dev: watching ${proj.cartsDir} \u2014 edit .nbt to reload (Ctrl-C to stop)`
|
|
3869
|
+
);
|
|
3802
3870
|
let busy = false;
|
|
3803
3871
|
setInterval(async () => {
|
|
3804
3872
|
if (busy || shuttingDown) return;
|
|
@@ -3828,11 +3896,17 @@ program2.command("bundle").description("Bundle TypeScript workflow code via esbu
|
|
|
3828
3896
|
}
|
|
3829
3897
|
bundleWorkflows({ entryPoints: entry, outfile: opts.outfile });
|
|
3830
3898
|
});
|
|
3899
|
+
customCommands.add("version");
|
|
3900
|
+
program2.command("version").description("Print the @nbt-dev/nbt version").action(() => {
|
|
3901
|
+
process.stdout.write(packageVersion() + "\n");
|
|
3902
|
+
});
|
|
3831
3903
|
customCommands.add("completions");
|
|
3832
3904
|
program2.command("completions").description("Emit a shell completion script (bash | zsh | fish)").argument("<shell>", "bash | zsh | fish").action((shell) => {
|
|
3833
3905
|
const script = completionScript(shell);
|
|
3834
3906
|
if (!script) {
|
|
3835
|
-
console.error(
|
|
3907
|
+
console.error(
|
|
3908
|
+
`completions: unknown shell '${shell}' (want bash|zsh|fish)`
|
|
3909
|
+
);
|
|
3836
3910
|
process.exit(1);
|
|
3837
3911
|
}
|
|
3838
3912
|
process.stdout.write(script);
|
|
@@ -3881,7 +3955,10 @@ function runCompletion(words) {
|
|
|
3881
3955
|
const isConsole = consoleCommands.has(first2);
|
|
3882
3956
|
const bin = isConsole ? CONSOLE_BIN : NBT_BIN;
|
|
3883
3957
|
const env = isConsole ? consoleEnv() : nativeEnv();
|
|
3884
|
-
const r = (0, import_node_child_process2.spawnSync)(bin, ["__complete__", ...words], {
|
|
3958
|
+
const r = (0, import_node_child_process2.spawnSync)(bin, ["__complete__", ...words], {
|
|
3959
|
+
stdio: "inherit",
|
|
3960
|
+
env
|
|
3961
|
+
});
|
|
3885
3962
|
process.exit(r.status === null ? 0 : r.status);
|
|
3886
3963
|
}
|
|
3887
3964
|
var argv = process.argv.slice(2);
|
|
@@ -3893,6 +3970,10 @@ if (!first || first === "-h" || first === "--help" || first === "help") {
|
|
|
3893
3970
|
program2.outputHelp();
|
|
3894
3971
|
process.exit(first ? 0 : 1);
|
|
3895
3972
|
}
|
|
3973
|
+
if (first === "-v" || first === "--version") {
|
|
3974
|
+
process.stdout.write(packageVersion() + "\n");
|
|
3975
|
+
process.exit(0);
|
|
3976
|
+
}
|
|
3896
3977
|
if (customCommands.has(first)) {
|
|
3897
3978
|
program2.parse(process.argv);
|
|
3898
3979
|
} else {
|
package/package.json
CHANGED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
entity User {
|
|
2
|
+
name: string
|
|
3
|
+
username?: string
|
|
4
|
+
email?: string
|
|
5
|
+
emailVerified: bool
|
|
6
|
+
externalId?: string
|
|
7
|
+
capsVersion: u32
|
|
8
|
+
devtoolsSettings?: string
|
|
9
|
+
@@index([email])
|
|
10
|
+
@@index([externalId])
|
|
11
|
+
@@unique([email])
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
entity UserRole {
|
|
15
|
+
userId: string
|
|
16
|
+
cart: string
|
|
17
|
+
role: string
|
|
18
|
+
@@index([userId])
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
entity Session {
|
|
22
|
+
userId: string
|
|
23
|
+
token: string
|
|
24
|
+
expiresAt: DateTime
|
|
25
|
+
ipAddress?: string
|
|
26
|
+
userAgent?: string
|
|
27
|
+
@@index([token])
|
|
28
|
+
@@index([userId])
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
entity Account {
|
|
32
|
+
userId: string
|
|
33
|
+
providerId: string
|
|
34
|
+
password: string
|
|
35
|
+
accessToken: string
|
|
36
|
+
refreshToken: string
|
|
37
|
+
idToken: string
|
|
38
|
+
accessTokenExpiresAt: DateTime
|
|
39
|
+
refreshTokenExpiresAt: DateTime
|
|
40
|
+
scope: string
|
|
41
|
+
@@index([userId])
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
entity Verification {
|
|
45
|
+
identifier: string
|
|
46
|
+
value: string
|
|
47
|
+
expiresAt: DateTime
|
|
48
|
+
@@index([identifier])
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
entity ApiKey {
|
|
52
|
+
name: string
|
|
53
|
+
projectId: string
|
|
54
|
+
start: string
|
|
55
|
+
prefix: string
|
|
56
|
+
key: string
|
|
57
|
+
permissions: string
|
|
58
|
+
roles: string
|
|
59
|
+
}
|
package/stdlib/auth/schema.nbt
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import crypto from "crypto"
|
|
2
2
|
|
|
3
|
-
# Auth policy for the hand-written routes in
|
|
3
|
+
# Auth policy for the hand-written routes in modules/cart/auth.jai (formerly the
|
|
4
4
|
# @public actions + the `authenticate` middleware block). These keep the
|
|
5
5
|
# daemon's public-route + middleware manifest correct: public routes bypass the
|
|
6
6
|
# /api/* auth gate; @middleware tells the proxy this cart exports the global
|
|
@@ -25,7 +25,8 @@ export entity User {
|
|
|
25
25
|
email?: string
|
|
26
26
|
emailVerified: bool
|
|
27
27
|
externalId?: string
|
|
28
|
-
capsVersion: u32
|
|
28
|
+
capsVersion: u32 # capability version; bumped on every role change so cached authorizations invalidate
|
|
29
|
+
devtoolsSettings?: string # per-operator devtools UI preferences, stored as a JSON blob
|
|
29
30
|
|
|
30
31
|
@@index([email])
|
|
31
32
|
@@index([externalId])
|
|
@@ -101,8 +102,8 @@ entity ApiKey {
|
|
|
101
102
|
}
|
|
102
103
|
|
|
103
104
|
# Console-operator SSH public keys. The console daemon authenticates SSH
|
|
104
|
-
# connections by
|
|
105
|
-
#
|
|
105
|
+
# connections by reading these rows directly from storage (in-process —
|
|
106
|
+
# auth cart liveness is not required).
|
|
106
107
|
entity SshKey {
|
|
107
108
|
id: ulid
|
|
108
109
|
createdAt: DateTime @default(now())
|
|
@@ -114,29 +115,3 @@ entity SshKey {
|
|
|
114
115
|
@@index([userId])
|
|
115
116
|
@@unique([blob])
|
|
116
117
|
}
|
|
117
|
-
|
|
118
|
-
jai {
|
|
119
|
-
find_synced_user :: (requestedId: string, email: string) -> (User, bool) {
|
|
120
|
-
if requestedId.count > 0 {
|
|
121
|
-
by_id, by_id_ok := get_user(requestedId);
|
|
122
|
-
if by_id_ok return by_id, true;
|
|
123
|
-
|
|
124
|
-
by_external := find_users_by_externalId(requestedId);
|
|
125
|
-
if by_external.count > 0 {
|
|
126
|
-
u, ok := get_user(by_external[0].id);
|
|
127
|
-
if ok return u, true;
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
if email.count > 0 {
|
|
132
|
-
by_email := find_users_by_email(email);
|
|
133
|
-
if by_email.count > 0 {
|
|
134
|
-
u, ok := get_user(by_email[0].id);
|
|
135
|
-
if ok return u, true;
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
empty: User;
|
|
140
|
-
return empty, false;
|
|
141
|
-
}
|
|
142
|
-
}
|
|
@@ -45,9 +45,8 @@ export entity Appointment {
|
|
|
45
45
|
|
|
46
46
|
# Rendered embedding-template text. Persisted alongside the Appointment so
|
|
47
47
|
# similarity search can score (target_text, candidate_text) pairs without
|
|
48
|
-
# re-rendering
|
|
49
|
-
#
|
|
50
|
-
# (D09.10c). Generic surface — every customer composing similarity search
|
|
48
|
+
# re-rendering on every query. Populated at ingest by the customer's
|
|
49
|
+
# pipeline. Generic surface — every customer composing similarity search
|
|
51
50
|
# over Appointments needs it; the *content* of the text is customer policy.
|
|
52
51
|
embedText?: string
|
|
53
52
|
|
package/stdlib/crm/schema.nbt
CHANGED
|
@@ -77,11 +77,10 @@ export entity Deal {
|
|
|
77
77
|
customData: document
|
|
78
78
|
|
|
79
79
|
# Append-only suffix — fields below this comment must stay at the end
|
|
80
|
-
# of the entity declaration.
|
|
80
|
+
# of the entity declaration. The row codec serializes in declaration order;
|
|
81
81
|
# newly-added fields go *after* existing fields so the on-disk byte
|
|
82
82
|
# layout stays forward-compatible (old records deserialize cleanly with
|
|
83
|
-
# trailing fields default-initialised).
|
|
84
|
-
# codegen in modules/nbt/codegen_serial.jai.
|
|
83
|
+
# trailing fields default-initialised).
|
|
85
84
|
|
|
86
85
|
# D09.02 — generic lifecycle status, customer-domain. mylocalpro reacts
|
|
87
86
|
# to `deal.status == "won"` to mark the source Appointment positive.
|
|
@@ -101,7 +100,7 @@ export entity Deal {
|
|
|
101
100
|
|
|
102
101
|
# Date the deal closed (won or lost). Resolved at GHL adapter ingest
|
|
103
102
|
# from Contact custom field "Date Sold" via CONTACT_LATEST_OPEN_DEAL.
|
|
104
|
-
# Append-only field —
|
|
103
|
+
# Append-only field — the row codec serializes in declaration order, so
|
|
105
104
|
# existing rows deserialize cleanly with this trailing default.
|
|
106
105
|
closedDate?: DateTime
|
|
107
106
|
}
|
package/stdlib/design/schema.nbt
CHANGED
|
@@ -136,5 +136,5 @@ entity Page {
|
|
|
136
136
|
}
|
|
137
137
|
|
|
138
138
|
# Behavior (former Design.create/save_version/get_head/list_versions actions +
|
|
139
|
-
# tasks/parse.nbt @task) moved to
|
|
140
|
-
#
|
|
139
|
+
# tasks/parse.nbt @task) moved to hand-written Jai over the generated ORM,
|
|
140
|
+
# which also registers the HTTP routes.
|
package/stdlib/dns/schema.nbt
CHANGED
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
# - Future: TLS cart, custom gateway-domains cart.
|
|
11
11
|
#
|
|
12
12
|
# Schema only. All behavior (token verify, CF API calls, DNS record CRUD,
|
|
13
|
-
# TXT verify polling) lives in
|
|
14
|
-
#
|
|
13
|
+
# TXT verify polling) lives in hand-written Jai over the generated ORM, which
|
|
14
|
+
# also registers the HTTP routes.
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
|
|
@@ -21,7 +21,7 @@ entity DnsProvider {
|
|
|
21
21
|
updatedAt: DateTime @updatedAt
|
|
22
22
|
type: string # "cloudflare"
|
|
23
23
|
label: string # user-facing name ("my CF account")
|
|
24
|
-
apiToken: string #
|
|
24
|
+
apiToken: string # provider API token (stored as-is)
|
|
25
25
|
accountId: string # CF account_id, needed for add_zone + registrar calls (optional)
|
|
26
26
|
status: string # "ACTIVE" | "INVALID" | "DISCONNECTED"
|
|
27
27
|
lastCheckedAt: u64 # ms epoch — updated on connect + test
|
package/stdlib/email/schema.nbt
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Email cartridge — transactional send + synthetic inboxes.
|
|
2
2
|
#
|
|
3
|
-
# Provider: SendGrid
|
|
4
|
-
#
|
|
3
|
+
# Provider: SendGrid. Nothing in the user-facing surface mentions SendGrid;
|
|
4
|
+
# the cart is branded "Email".
|
|
5
5
|
#
|
|
6
6
|
# Per-console model:
|
|
7
7
|
# - Every console auto-provisions `<console>.nbt.dev` as the default mail
|
|
@@ -13,21 +13,22 @@
|
|
|
13
13
|
# register with SendGrid Inbound Parse + Domain Authentication, poll
|
|
14
14
|
# until everything is green.
|
|
15
15
|
#
|
|
16
|
-
# Ops prerequisites (one-time
|
|
17
|
-
# -
|
|
18
|
-
# -
|
|
16
|
+
# Ops prerequisites (one-time):
|
|
17
|
+
# - Provider API key in console env.
|
|
18
|
+
# - Provider event-webhook public key in console env (base64 SPKI for event
|
|
19
|
+
# webhook signature verification).
|
|
19
20
|
# - `*.nbt.dev MX 10 mx.sendgrid.net` at zone level.
|
|
20
21
|
# - SendGrid Inbound Parse wildcard entry + per-console entries (latter are
|
|
21
22
|
# created programmatically by MailDomain.ensure_default).
|
|
22
23
|
|
|
23
|
-
# Behavior (the former main.nbt actions) lives in
|
|
24
|
-
# generated ORM
|
|
25
|
-
#
|
|
24
|
+
# Behavior (the former main.nbt actions) lives in hand-written Jai over the
|
|
25
|
+
# generated ORM, which also registers the HTTP routes. The import below pulls
|
|
26
|
+
# the crypto module into the cart scope.
|
|
26
27
|
import crypto from "crypto"
|
|
27
28
|
|
|
28
|
-
# Auth policy for the hand-written routes (formerly @public actions).
|
|
29
|
-
#
|
|
30
|
-
#
|
|
29
|
+
# Auth policy for the hand-written routes (formerly @public actions). These
|
|
30
|
+
# keep the daemon's public-route manifest correct so the /api/* auth gate is
|
|
31
|
+
# bypassed for SendGrid webhooks.
|
|
31
32
|
@public_route "/api/email/inbound"
|
|
32
33
|
@public_route "/api/email/events"
|
|
33
34
|
|
package/stdlib/ingest/schema.nbt
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
# Behavior (the former main.nbt actions) lives in
|
|
2
|
-
# generated ORM
|
|
3
|
-
#
|
|
4
|
-
#
|
|
1
|
+
# Behavior (the former main.nbt actions) lives in hand-written Jai over the
|
|
2
|
+
# generated ORM, which also registers the HTTP routes. All routes stay
|
|
3
|
+
# auth-gated by the daemon middleware (no @public_route), matching the
|
|
4
|
+
# pre-migration manifest.
|
|
5
5
|
|
|
6
6
|
entity Endpoint {
|
|
7
7
|
id: ulid
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
# subscriptions. The portal owns browser permission prompts and service worker
|
|
3
3
|
# registration; this cartridge owns the resulting state.
|
|
4
4
|
#
|
|
5
|
-
# Behavior (the former main.nbt actions) lives in
|
|
6
|
-
#
|
|
5
|
+
# Behavior (the former main.nbt actions) lives in hand-written Jai over the
|
|
6
|
+
# generated ORM, which also registers the HTTP routes.
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
entity Notification {
|
package/stdlib/phone/schema.nbt
CHANGED
|
@@ -1,21 +1,20 @@
|
|
|
1
1
|
# Phone cartridge — Twilio number management, SMS, click-to-call.
|
|
2
2
|
#
|
|
3
|
-
# Per-tenant model
|
|
4
|
-
# - One master Twilio account owned by the platform (SID + auth token
|
|
5
|
-
#
|
|
3
|
+
# Per-tenant model:
|
|
4
|
+
# - One master Twilio account owned by the platform (master SID + auth token
|
|
5
|
+
# supplied via env).
|
|
6
6
|
# - Each tenant gets a TwilioAccount row with its own subaccount SID and
|
|
7
7
|
# auth token. All per-tenant API calls authenticate as the subaccount.
|
|
8
8
|
# - Webhooks are configured to URLs under the tenant's public base
|
|
9
9
|
# (TwilioAccount.publicUrlBase), which the gateway routes back to this
|
|
10
10
|
# cart. Signature verification uses the subaccount's auth token.
|
|
11
11
|
|
|
12
|
-
# Behavior (the former
|
|
13
|
-
#
|
|
14
|
-
# which registers the HTTP routes.
|
|
12
|
+
# Behavior (the former actions) lives in hand-written Jai over the generated
|
|
13
|
+
# ORM, which also registers the HTTP routes.
|
|
15
14
|
|
|
16
|
-
# Auth policy for the hand-written routes (formerly @public actions).
|
|
17
|
-
#
|
|
18
|
-
#
|
|
15
|
+
# Auth policy for the hand-written routes (formerly @public actions). These
|
|
16
|
+
# keep the daemon's public-route manifest correct so the /api/* auth gate is
|
|
17
|
+
# bypassed for Twilio webhooks.
|
|
19
18
|
@public_route "/api/phone/webhook/sms"
|
|
20
19
|
@public_route "/api/phone/webhook/status"
|
|
21
20
|
|
|
@@ -25,7 +24,7 @@ entity TwilioAccount {
|
|
|
25
24
|
updatedAt: DateTime @updatedAt
|
|
26
25
|
name: string # operator-facing label
|
|
27
26
|
subAccountSid: string # AC... — populated by provision()
|
|
28
|
-
authToken: string # subaccount auth token (
|
|
27
|
+
authToken: string # subaccount auth token (stored as-is)
|
|
29
28
|
publicUrlBase: string # e.g. "https://acme.console.app"
|
|
30
29
|
status: string # PENDING | ACTIVE | SUSPENDED | CLOSED
|
|
31
30
|
retentionDays: s32 # 0 = keep message bodies forever; N = null body after N days
|
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
# Question: How do we tie in cartridge metadata and workflow side effects into all this?
|
|
3
|
-
|
|
4
1
|
enum WorkerStatus {
|
|
5
2
|
WAITING
|
|
6
3
|
RUNNING
|
|
@@ -14,7 +11,6 @@ entity Worker {
|
|
|
14
11
|
source: blob
|
|
15
12
|
contentHash: string
|
|
16
13
|
queue?: string
|
|
17
|
-
# TODO: We need some sort of termination options like a restart policy
|
|
18
14
|
}
|
|
19
15
|
|
|
20
16
|
# Stub — flesh out execution lifecycle fields later.
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
entity User {
|
|
2
|
+
name: string
|
|
3
|
+
username?: string
|
|
4
|
+
email?: string
|
|
5
|
+
emailVerified: bool
|
|
6
|
+
externalId?: string
|
|
7
|
+
capsVersion: u32
|
|
8
|
+
devtoolsSettings?: string
|
|
9
|
+
@@index([email])
|
|
10
|
+
@@index([externalId])
|
|
11
|
+
@@unique([email])
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
entity UserRole {
|
|
15
|
+
userId: string
|
|
16
|
+
cart: string
|
|
17
|
+
role: string
|
|
18
|
+
@@index([userId])
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
entity Session {
|
|
22
|
+
userId: string
|
|
23
|
+
token: string
|
|
24
|
+
expiresAt: DateTime
|
|
25
|
+
ipAddress?: string
|
|
26
|
+
userAgent?: string
|
|
27
|
+
@@index([token])
|
|
28
|
+
@@index([userId])
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
entity Account {
|
|
32
|
+
userId: string
|
|
33
|
+
providerId: string
|
|
34
|
+
password: string
|
|
35
|
+
accessToken: string
|
|
36
|
+
refreshToken: string
|
|
37
|
+
idToken: string
|
|
38
|
+
accessTokenExpiresAt: DateTime
|
|
39
|
+
refreshTokenExpiresAt: DateTime
|
|
40
|
+
scope: string
|
|
41
|
+
@@index([userId])
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
entity Verification {
|
|
45
|
+
identifier: string
|
|
46
|
+
value: string
|
|
47
|
+
expiresAt: DateTime
|
|
48
|
+
@@index([identifier])
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
entity ApiKey {
|
|
52
|
+
name: string
|
|
53
|
+
projectId: string
|
|
54
|
+
start: string
|
|
55
|
+
prefix: string
|
|
56
|
+
key: string
|
|
57
|
+
permissions: string
|
|
58
|
+
roles: string
|
|
59
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import crypto from "crypto"
|
|
2
2
|
|
|
3
|
-
# Auth policy for the hand-written routes in
|
|
3
|
+
# Auth policy for the hand-written routes in modules/cart/auth.jai (formerly the
|
|
4
4
|
# @public actions + the `authenticate` middleware block). These keep the
|
|
5
5
|
# daemon's public-route + middleware manifest correct: public routes bypass the
|
|
6
6
|
# /api/* auth gate; @middleware tells the proxy this cart exports the global
|
|
@@ -25,7 +25,8 @@ export entity User {
|
|
|
25
25
|
email?: string
|
|
26
26
|
emailVerified: bool
|
|
27
27
|
externalId?: string
|
|
28
|
-
capsVersion: u32
|
|
28
|
+
capsVersion: u32 # capability version; bumped on every role change so cached authorizations invalidate
|
|
29
|
+
devtoolsSettings?: string # per-operator devtools UI preferences, stored as a JSON blob
|
|
29
30
|
|
|
30
31
|
@@index([email])
|
|
31
32
|
@@index([externalId])
|
|
@@ -101,8 +102,8 @@ entity ApiKey {
|
|
|
101
102
|
}
|
|
102
103
|
|
|
103
104
|
# Console-operator SSH public keys. The console daemon authenticates SSH
|
|
104
|
-
# connections by
|
|
105
|
-
#
|
|
105
|
+
# connections by reading these rows directly from storage (in-process —
|
|
106
|
+
# auth cart liveness is not required).
|
|
106
107
|
entity SshKey {
|
|
107
108
|
id: ulid
|
|
108
109
|
createdAt: DateTime @default(now())
|
|
@@ -114,29 +115,3 @@ entity SshKey {
|
|
|
114
115
|
@@index([userId])
|
|
115
116
|
@@unique([blob])
|
|
116
117
|
}
|
|
117
|
-
|
|
118
|
-
jai {
|
|
119
|
-
find_synced_user :: (requestedId: string, email: string) -> (User, bool) {
|
|
120
|
-
if requestedId.count > 0 {
|
|
121
|
-
by_id, by_id_ok := get_user(requestedId);
|
|
122
|
-
if by_id_ok return by_id, true;
|
|
123
|
-
|
|
124
|
-
by_external := find_users_by_externalId(requestedId);
|
|
125
|
-
if by_external.count > 0 {
|
|
126
|
-
u, ok := get_user(by_external[0].id);
|
|
127
|
-
if ok return u, true;
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
if email.count > 0 {
|
|
132
|
-
by_email := find_users_by_email(email);
|
|
133
|
-
if by_email.count > 0 {
|
|
134
|
-
u, ok := get_user(by_email[0].id);
|
|
135
|
-
if ok return u, true;
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
empty: User;
|
|
140
|
-
return empty, false;
|
|
141
|
-
}
|
|
142
|
-
}
|
|
@@ -45,9 +45,8 @@ export entity Appointment {
|
|
|
45
45
|
|
|
46
46
|
# Rendered embedding-template text. Persisted alongside the Appointment so
|
|
47
47
|
# similarity search can score (target_text, candidate_text) pairs without
|
|
48
|
-
# re-rendering
|
|
49
|
-
#
|
|
50
|
-
# (D09.10c). Generic surface — every customer composing similarity search
|
|
48
|
+
# re-rendering on every query. Populated at ingest by the customer's
|
|
49
|
+
# pipeline. Generic surface — every customer composing similarity search
|
|
51
50
|
# over Appointments needs it; the *content* of the text is customer policy.
|
|
52
51
|
embedText?: string
|
|
53
52
|
|
|
@@ -77,11 +77,10 @@ export entity Deal {
|
|
|
77
77
|
customData: document
|
|
78
78
|
|
|
79
79
|
# Append-only suffix — fields below this comment must stay at the end
|
|
80
|
-
# of the entity declaration.
|
|
80
|
+
# of the entity declaration. The row codec serializes in declaration order;
|
|
81
81
|
# newly-added fields go *after* existing fields so the on-disk byte
|
|
82
82
|
# layout stays forward-compatible (old records deserialize cleanly with
|
|
83
|
-
# trailing fields default-initialised).
|
|
84
|
-
# codegen in modules/nbt/codegen_serial.jai.
|
|
83
|
+
# trailing fields default-initialised).
|
|
85
84
|
|
|
86
85
|
# D09.02 — generic lifecycle status, customer-domain. mylocalpro reacts
|
|
87
86
|
# to `deal.status == "won"` to mark the source Appointment positive.
|
|
@@ -101,7 +100,7 @@ export entity Deal {
|
|
|
101
100
|
|
|
102
101
|
# Date the deal closed (won or lost). Resolved at GHL adapter ingest
|
|
103
102
|
# from Contact custom field "Date Sold" via CONTACT_LATEST_OPEN_DEAL.
|
|
104
|
-
# Append-only field —
|
|
103
|
+
# Append-only field — the row codec serializes in declaration order, so
|
|
105
104
|
# existing rows deserialize cleanly with this trailing default.
|
|
106
105
|
closedDate?: DateTime
|
|
107
106
|
}
|
|
@@ -136,5 +136,5 @@ entity Page {
|
|
|
136
136
|
}
|
|
137
137
|
|
|
138
138
|
# Behavior (former Design.create/save_version/get_head/list_versions actions +
|
|
139
|
-
# tasks/parse.nbt @task) moved to
|
|
140
|
-
#
|
|
139
|
+
# tasks/parse.nbt @task) moved to hand-written Jai over the generated ORM,
|
|
140
|
+
# which also registers the HTTP routes.
|
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
# - Future: TLS cart, custom gateway-domains cart.
|
|
11
11
|
#
|
|
12
12
|
# Schema only. All behavior (token verify, CF API calls, DNS record CRUD,
|
|
13
|
-
# TXT verify polling) lives in
|
|
14
|
-
#
|
|
13
|
+
# TXT verify polling) lives in hand-written Jai over the generated ORM, which
|
|
14
|
+
# also registers the HTTP routes.
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
|
|
@@ -21,7 +21,7 @@ entity DnsProvider {
|
|
|
21
21
|
updatedAt: DateTime @updatedAt
|
|
22
22
|
type: string # "cloudflare"
|
|
23
23
|
label: string # user-facing name ("my CF account")
|
|
24
|
-
apiToken: string #
|
|
24
|
+
apiToken: string # provider API token (stored as-is)
|
|
25
25
|
accountId: string # CF account_id, needed for add_zone + registrar calls (optional)
|
|
26
26
|
status: string # "ACTIVE" | "INVALID" | "DISCONNECTED"
|
|
27
27
|
lastCheckedAt: u64 # ms epoch — updated on connect + test
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Email cartridge — transactional send + synthetic inboxes.
|
|
2
2
|
#
|
|
3
|
-
# Provider: SendGrid
|
|
4
|
-
#
|
|
3
|
+
# Provider: SendGrid. Nothing in the user-facing surface mentions SendGrid;
|
|
4
|
+
# the cart is branded "Email".
|
|
5
5
|
#
|
|
6
6
|
# Per-console model:
|
|
7
7
|
# - Every console auto-provisions `<console>.nbt.dev` as the default mail
|
|
@@ -13,21 +13,22 @@
|
|
|
13
13
|
# register with SendGrid Inbound Parse + Domain Authentication, poll
|
|
14
14
|
# until everything is green.
|
|
15
15
|
#
|
|
16
|
-
# Ops prerequisites (one-time
|
|
17
|
-
# -
|
|
18
|
-
# -
|
|
16
|
+
# Ops prerequisites (one-time):
|
|
17
|
+
# - Provider API key in console env.
|
|
18
|
+
# - Provider event-webhook public key in console env (base64 SPKI for event
|
|
19
|
+
# webhook signature verification).
|
|
19
20
|
# - `*.nbt.dev MX 10 mx.sendgrid.net` at zone level.
|
|
20
21
|
# - SendGrid Inbound Parse wildcard entry + per-console entries (latter are
|
|
21
22
|
# created programmatically by MailDomain.ensure_default).
|
|
22
23
|
|
|
23
|
-
# Behavior (the former main.nbt actions) lives in
|
|
24
|
-
# generated ORM
|
|
25
|
-
#
|
|
24
|
+
# Behavior (the former main.nbt actions) lives in hand-written Jai over the
|
|
25
|
+
# generated ORM, which also registers the HTTP routes. The import below pulls
|
|
26
|
+
# the crypto module into the cart scope.
|
|
26
27
|
import crypto from "crypto"
|
|
27
28
|
|
|
28
|
-
# Auth policy for the hand-written routes (formerly @public actions).
|
|
29
|
-
#
|
|
30
|
-
#
|
|
29
|
+
# Auth policy for the hand-written routes (formerly @public actions). These
|
|
30
|
+
# keep the daemon's public-route manifest correct so the /api/* auth gate is
|
|
31
|
+
# bypassed for SendGrid webhooks.
|
|
31
32
|
@public_route "/api/email/inbound"
|
|
32
33
|
@public_route "/api/email/events"
|
|
33
34
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
# Behavior (the former main.nbt actions) lives in
|
|
2
|
-
# generated ORM
|
|
3
|
-
#
|
|
4
|
-
#
|
|
1
|
+
# Behavior (the former main.nbt actions) lives in hand-written Jai over the
|
|
2
|
+
# generated ORM, which also registers the HTTP routes. All routes stay
|
|
3
|
+
# auth-gated by the daemon middleware (no @public_route), matching the
|
|
4
|
+
# pre-migration manifest.
|
|
5
5
|
|
|
6
6
|
entity Endpoint {
|
|
7
7
|
id: ulid
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
# subscriptions. The portal owns browser permission prompts and service worker
|
|
3
3
|
# registration; this cartridge owns the resulting state.
|
|
4
4
|
#
|
|
5
|
-
# Behavior (the former main.nbt actions) lives in
|
|
6
|
-
#
|
|
5
|
+
# Behavior (the former main.nbt actions) lives in hand-written Jai over the
|
|
6
|
+
# generated ORM, which also registers the HTTP routes.
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
entity Notification {
|
|
@@ -1,21 +1,20 @@
|
|
|
1
1
|
# Phone cartridge — Twilio number management, SMS, click-to-call.
|
|
2
2
|
#
|
|
3
|
-
# Per-tenant model
|
|
4
|
-
# - One master Twilio account owned by the platform (SID + auth token
|
|
5
|
-
#
|
|
3
|
+
# Per-tenant model:
|
|
4
|
+
# - One master Twilio account owned by the platform (master SID + auth token
|
|
5
|
+
# supplied via env).
|
|
6
6
|
# - Each tenant gets a TwilioAccount row with its own subaccount SID and
|
|
7
7
|
# auth token. All per-tenant API calls authenticate as the subaccount.
|
|
8
8
|
# - Webhooks are configured to URLs under the tenant's public base
|
|
9
9
|
# (TwilioAccount.publicUrlBase), which the gateway routes back to this
|
|
10
10
|
# cart. Signature verification uses the subaccount's auth token.
|
|
11
11
|
|
|
12
|
-
# Behavior (the former
|
|
13
|
-
#
|
|
14
|
-
# which registers the HTTP routes.
|
|
12
|
+
# Behavior (the former actions) lives in hand-written Jai over the generated
|
|
13
|
+
# ORM, which also registers the HTTP routes.
|
|
15
14
|
|
|
16
|
-
# Auth policy for the hand-written routes (formerly @public actions).
|
|
17
|
-
#
|
|
18
|
-
#
|
|
15
|
+
# Auth policy for the hand-written routes (formerly @public actions). These
|
|
16
|
+
# keep the daemon's public-route manifest correct so the /api/* auth gate is
|
|
17
|
+
# bypassed for Twilio webhooks.
|
|
19
18
|
@public_route "/api/phone/webhook/sms"
|
|
20
19
|
@public_route "/api/phone/webhook/status"
|
|
21
20
|
|
|
@@ -25,7 +24,7 @@ entity TwilioAccount {
|
|
|
25
24
|
updatedAt: DateTime @updatedAt
|
|
26
25
|
name: string # operator-facing label
|
|
27
26
|
subAccountSid: string # AC... — populated by provision()
|
|
28
|
-
authToken: string # subaccount auth token (
|
|
27
|
+
authToken: string # subaccount auth token (stored as-is)
|
|
29
28
|
publicUrlBase: string # e.g. "https://acme.console.app"
|
|
30
29
|
status: string # PENDING | ACTIVE | SUSPENDED | CLOSED
|
|
31
30
|
retentionDays: s32 # 0 = keep message bodies forever; N = null body after N days
|
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
# Question: How do we tie in cartridge metadata and workflow side effects into all this?
|
|
3
|
-
|
|
4
1
|
enum WorkerStatus {
|
|
5
2
|
WAITING
|
|
6
3
|
RUNNING
|
|
@@ -14,7 +11,6 @@ entity Worker {
|
|
|
14
11
|
source: blob
|
|
15
12
|
contentHash: string
|
|
16
13
|
queue?: string
|
|
17
|
-
# TODO: We need some sort of termination options like a restart policy
|
|
18
14
|
}
|
|
19
15
|
|
|
20
16
|
# Stub — flesh out execution lifecycle fields later.
|
package/vendor/linux-x64/console
CHANGED
|
Binary file
|
package/vendor/linux-x64/nbt
CHANGED
|
Binary file
|