@nbt-dev/nbt 0.0.9 → 0.1.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.
Files changed (50) hide show
  1. package/dist/nbt.js +117 -36
  2. package/package.json +1 -1
  3. package/stdlib/auth/migrations/20260614000000_add_user_devtools_settings/migration.nbt +4 -0
  4. package/stdlib/auth/migrations/20260614000000_add_user_devtools_settings/schema_snapshot.nbt +59 -0
  5. package/stdlib/auth/schema.nbt +5 -30
  6. package/stdlib/calendar/schema.nbt +2 -3
  7. package/stdlib/crm/schema.nbt +3 -4
  8. package/stdlib/design/schema.nbt +2 -2
  9. package/stdlib/dns/schema.nbt +3 -3
  10. package/stdlib/email/schema.nbt +12 -11
  11. package/stdlib/ingest/schema.nbt +4 -4
  12. package/stdlib/notifications/schema.nbt +2 -2
  13. package/stdlib/phone/schema.nbt +9 -10
  14. package/stdlib/workflows/schema.nbt +69 -21
  15. package/vendor/linux-x64/cartridges/auth/migrations/20260614000000_add_user_devtools_settings/migration.nbt +4 -0
  16. package/vendor/linux-x64/cartridges/auth/migrations/20260614000000_add_user_devtools_settings/schema_snapshot.nbt +59 -0
  17. package/vendor/linux-x64/cartridges/auth/schema.nbt +5 -30
  18. package/vendor/linux-x64/cartridges/calendar/schema.nbt +2 -3
  19. package/vendor/linux-x64/cartridges/crm/schema.nbt +3 -4
  20. package/vendor/linux-x64/cartridges/design/schema.nbt +2 -2
  21. package/vendor/linux-x64/cartridges/dns/schema.nbt +3 -3
  22. package/vendor/linux-x64/cartridges/email/schema.nbt +12 -11
  23. package/vendor/linux-x64/cartridges/ingest/schema.nbt +4 -4
  24. package/vendor/linux-x64/cartridges/notifications/schema.nbt +2 -2
  25. package/vendor/linux-x64/cartridges/phone/schema.nbt +9 -10
  26. package/vendor/linux-x64/cartridges/workflows/schema.nbt +69 -21
  27. package/vendor/linux-x64/console +0 -0
  28. package/vendor/linux-x64/nbt +0 -0
  29. package/stdlib/crm/adapters/gohighlevel/README.md +0 -85
  30. package/stdlib/crm/adapters/gohighlevel/tests/README.md +0 -159
  31. package/stdlib/crm/adapters/gohighlevel/tests/fixtures/webhooks/contact_138fields.json +0 -222
  32. package/stdlib/crm/adapters/gohighlevel/tests/fixtures/webhooks/contact_140fields.json +0 -219
  33. package/stdlib/crm/adapters/gohighlevel/tests/fixtures/webhooks/contact_alt.json +0 -212
  34. package/stdlib/crm/adapters/gohighlevel/tests/fixtures/webhooks/contact_changed.json +0 -102
  35. package/stdlib/crm/adapters/gohighlevel/tests/fixtures/webhooks/contact_created.json +0 -95
  36. package/stdlib/crm/adapters/gohighlevel/tests/fixtures/webhooks/contact_full.json +0 -213
  37. package/stdlib/crm/adapters/gohighlevel/tests/fixtures/webhooks/contact_sparse.json +0 -161
  38. package/stdlib/crm/adapters/gohighlevel/tests/fixtures/webhooks/contact_update_a.json +0 -197
  39. package/stdlib/crm/adapters/gohighlevel/tests/fixtures/webhooks/contact_update_b.json +0 -197
  40. package/stdlib/crm/adapters/gohighlevel/tests/fixtures/webhooks/opportunity_changed.json +0 -85
  41. package/stdlib/crm/adapters/gohighlevel/tests/fixtures/webhooks/opportunity_created.json +0 -85
  42. package/stdlib/crm/adapters/gohighlevel/tests/fixtures/webhooks/v2_contact_pilot.json +0 -43
  43. package/stdlib/crm/adapters/gohighlevel/tests/fixtures/webhooks/v2_contact_with_price_closed.json +0 -7
  44. package/stdlib/crm/adapters/gohighlevel/tests/fixtures/webhooks/v2_contact_with_price_open.json +0 -7
  45. package/stdlib/crm/adapters/gohighlevel/tests/fixtures/webhooks/v2_event_appointment_delete.json +0 -1
  46. package/stdlib/crm/adapters/gohighlevel/tests/fixtures/webhooks/v2_event_calendar_update.json +0 -1
  47. package/stdlib/crm/adapters/gohighlevel/tests/fixtures/webhooks/v2_event_contact_create.json +0 -1
  48. package/stdlib/crm/adapters/gohighlevel/tests/fixtures/webhooks/v2_event_opp_status_update.json +0 -1
  49. package/stdlib/crm/adapters/gohighlevel/tests/fixtures/webhooks/v2_opportunity_pilot.json +0 -16
  50. package/stdlib/crm/adapters/gohighlevel/tests/fixtures/webhooks/v2_pipelines_pilot.json +0 -137
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)) return c.filter((x) => typeof x === "string");
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 + console daemon for the nbt-dev console (linux/x64).");
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("[dir]", "directory to create the project in (default: current directory)").option("-y, --yes", "skip prompts; include the hello-world example").option("--no-example", "skip the hello-world example cartridge").action((dir, opts) => {
3507
- runInit(dir, opts).catch((e) => {
3508
- console.error(`nbt init: ${e?.message ?? e}`);
3509
- process.exit(1);
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(`nbt.json already exists ${dir ? `in ${dir}` : "here"} \u2014 this is already an nbt project`);
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("nbt/auth already exists; refusing to overwrite it during init");
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(" nbt dev # boot the console + live-reload on save");
3582
+ console.log(
3583
+ " nbt dev # boot the console + live-reload on save"
3584
+ );
3563
3585
  } else {
3564
- if (dir) console.log(`
3565
- Next: cd ${dir}, then run \`nbt dev\` or add a standard cartridge with \`nbt add <name>\`.`);
3566
- else console.log("\nNext: run `nbt dev`, or add another standard cartridge with `nbt add <name>`.");
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({ input: process.stdin, output: process.stdout });
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(name, proj.cartsDir, opts.overwrite === true);
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("Run `nbt migrate deploy` to deploy the local cartridge set.");
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) throw new Error(`${dest} already exists; use --overwrite to replace it`);
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(path3.join(proj.cartsDir, n, "schema.nbt"));
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("Update vendored standard-library modules from the bundled stdlib").argument("<module...>", "standard module name(s)").action((modules) => {
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(`'${name}' is not installed in this project \u2014 run: nbt add ${name}`);
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) console.log(` wrote ${path3.relative(proj.rootDir, f)}`);
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("Run `nbt migrate create <module>` to capture any schema changes, then `nbt migrate deploy`.");
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("-p, --port <port>", "console HTTP port (default: nbt.json dev env, else 8080)").option("-d, --data-dir <dir>", "console data dir (default: ./data)").action((opts) => {
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 { rootDir: process.cwd(), cartsDir: path3.resolve(process.cwd(), "nbt"), port: 8080 };
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((arg) => arg === "--port" || arg === "-p" || arg.startsWith("--port="));
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)(NBT_BIN, ["install", "--path", cartDir, "--port", String(port)], {
3748
- stdio: "inherit",
3749
- env: nativeEnv()
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) throw new Error(`invalid port '${opts.port}'`);
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, { stdio: "inherit", env: consoleEnv() });
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(`nbt dev: no carts found under ${proj.cartsDir} (nothing to watch)`);
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(`nbt dev: watching ${proj.cartsDir} \u2014 edit .nbt to reload (Ctrl-C to stop)`);
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(`completions: unknown shell '${shell}' (want bash|zsh|fish)`);
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], { stdio: "inherit", env });
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nbt-dev/nbt",
3
- "version": "0.0.9",
3
+ "version": "0.1.0",
4
4
  "description": "The nbt CLI and console daemon for the nbt-dev console — a fixed-target OS for web development. Linux/x64 prebuilt binaries.",
5
5
  "bin": {
6
6
  "nbt": "dist/nbt.js"
@@ -0,0 +1,4 @@
1
+ migration add_user_devtools_settings {
2
+ add_field User devtoolsSettings string default("")
3
+ set_optional User devtoolsSettings true
4
+ }
@@ -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 native/runtime.jai (formerly the
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 # what is this?
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 looking up rows here via modules/auth_lookup/ (in-process,
105
- # direct storage read — auth cart liveness is not required).
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 the customer's @embed template on every query. Populated at
49
- # ingest by the customer's @embed binding
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. Codegen serializes in declaration order;
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). See the EOF-tolerant deserialize
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 — codegen serializes in declaration order, so
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 native/runtime.jai over the generated ORM
140
- # see design_register_extra_routes.
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 native/runtime.jai as regular Jai over the
14
- # generated ORM see domains_register_extra_routes.
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 # raw token (TODO: encrypt at rest — same status as phone cart's authToken)
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 (modules/sendgrid). Nothing in the user-facing surface
4
- # mentions SendGrid; the cart is branded "Email".
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, see plans/squishy-puzzling-spindle.md):
17
- # - SENDGRID_API_KEY in console env.
18
- # - SENDGRID_EVENT_PUBKEY in console env (base64 SPKI for event webhook verification).
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 native/runtime.jai over the
24
- # generated ORM see email_register_extra_routes. These imports trigger the
25
- # #load of the native files into the cart module scope.
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). The
29
- # handlers live in native/runtime.jai; these keep the daemon's public-route
30
- # manifest correct so the /api/* auth gate is bypassed for SendGrid webhooks.
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 native/runtime.jai over the
2
- # generated ORM see
3
- # ingest_register_extra_routes. All routes stay auth-gated by the daemon
4
- # middleware (no @public_route), matching the pre-migration manifest.
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 native/runtime.jai as regular
6
- # Jai over the generated ORM see notifications_register_extra_routes.
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 (see modules/twilio/module.jai for the rationale):
4
- # - One master Twilio account owned by the platform (SID + auth token in
5
- # env: TWILIO_MASTER_SID, TWILIO_MASTER_TOKEN).
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 jai{} helper blocks + actions) lives in
13
- # native/runtime.jai over the generated ORM see phone_register_extra_routes,
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). The
17
- # handlers live in native/runtime.jai; these keep the daemon's public-route
18
- # manifest correct so the /api/* auth gate is bypassed for Twilio webhooks.
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 (TODO: encrypt at rest)
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