@gurulu/cli 0.4.7 → 1.0.1

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 (190) hide show
  1. package/LICENSE +92 -0
  2. package/README.md +35 -106
  3. package/dist/bin.d.ts +3 -0
  4. package/dist/bin.d.ts.map +1 -0
  5. package/dist/bin.js +25751 -0
  6. package/dist/commands/auth.d.ts +23 -20
  7. package/dist/commands/auth.d.ts.map +1 -0
  8. package/dist/commands/doctor.d.ts +20 -6
  9. package/dist/commands/doctor.d.ts.map +1 -0
  10. package/dist/commands/init.d.ts +33 -11
  11. package/dist/commands/init.d.ts.map +1 -0
  12. package/dist/commands/pull.d.ts +13 -0
  13. package/dist/commands/pull.d.ts.map +1 -0
  14. package/dist/commands/push.d.ts +40 -0
  15. package/dist/commands/push.d.ts.map +1 -0
  16. package/dist/commands/validate.d.ts +36 -0
  17. package/dist/commands/validate.d.ts.map +1 -0
  18. package/dist/index.d.ts +4 -1
  19. package/dist/index.d.ts.map +1 -0
  20. package/dist/index.js +25326 -876
  21. package/dist/lib/api.d.ts +139 -0
  22. package/dist/lib/api.d.ts.map +1 -0
  23. package/dist/lib/codegen.d.ts +4 -0
  24. package/dist/lib/codegen.d.ts.map +1 -0
  25. package/dist/lib/config.d.ts +43 -0
  26. package/dist/lib/config.d.ts.map +1 -0
  27. package/dist/lib/detect.d.ts +27 -0
  28. package/dist/lib/detect.d.ts.map +1 -0
  29. package/dist/lib/detect.js +106 -0
  30. package/dist/lib/exec-install.d.ts +21 -0
  31. package/dist/lib/exec-install.d.ts.map +1 -0
  32. package/dist/lib/install-plan.d.ts +25 -0
  33. package/dist/lib/install-plan.d.ts.map +1 -0
  34. package/dist/lib/install-plan.js +161 -0
  35. package/package.json +51 -20
  36. package/bin/gurulu.js +0 -2
  37. package/dist/api-client.d.ts +0 -33
  38. package/dist/api-client.js +0 -175
  39. package/dist/commands/add-server.d.ts +0 -9
  40. package/dist/commands/add-server.js +0 -162
  41. package/dist/commands/alerts.d.ts +0 -27
  42. package/dist/commands/alerts.js +0 -309
  43. package/dist/commands/api-keys.d.ts +0 -20
  44. package/dist/commands/api-keys.js +0 -130
  45. package/dist/commands/attribution.d.ts +0 -22
  46. package/dist/commands/attribution.js +0 -111
  47. package/dist/commands/audiences.d.ts +0 -23
  48. package/dist/commands/audiences.js +0 -243
  49. package/dist/commands/audit.d.ts +0 -20
  50. package/dist/commands/audit.js +0 -130
  51. package/dist/commands/auth.js +0 -249
  52. package/dist/commands/chat.d.ts +0 -19
  53. package/dist/commands/chat.js +0 -118
  54. package/dist/commands/config.d.ts +0 -10
  55. package/dist/commands/config.js +0 -92
  56. package/dist/commands/consent.d.ts +0 -27
  57. package/dist/commands/consent.js +0 -233
  58. package/dist/commands/conversion-paths.d.ts +0 -19
  59. package/dist/commands/conversion-paths.js +0 -55
  60. package/dist/commands/db.d.ts +0 -25
  61. package/dist/commands/db.js +0 -330
  62. package/dist/commands/destinations.d.ts +0 -20
  63. package/dist/commands/destinations.js +0 -191
  64. package/dist/commands/doctor.js +0 -360
  65. package/dist/commands/errors.d.ts +0 -27
  66. package/dist/commands/errors.js +0 -121
  67. package/dist/commands/events.d.ts +0 -33
  68. package/dist/commands/events.js +0 -371
  69. package/dist/commands/experiments.d.ts +0 -22
  70. package/dist/commands/experiments.js +0 -264
  71. package/dist/commands/funnels.d.ts +0 -17
  72. package/dist/commands/funnels.js +0 -203
  73. package/dist/commands/goals.d.ts +0 -18
  74. package/dist/commands/goals.js +0 -214
  75. package/dist/commands/heatmap.d.ts +0 -27
  76. package/dist/commands/heatmap.js +0 -112
  77. package/dist/commands/identity.d.ts +0 -29
  78. package/dist/commands/identity.js +0 -328
  79. package/dist/commands/init.js +0 -215
  80. package/dist/commands/insights.d.ts +0 -10
  81. package/dist/commands/insights.js +0 -77
  82. package/dist/commands/install.d.ts +0 -259
  83. package/dist/commands/install.js +0 -1590
  84. package/dist/commands/login.d.ts +0 -20
  85. package/dist/commands/login.js +0 -170
  86. package/dist/commands/logout.d.ts +0 -10
  87. package/dist/commands/logout.js +0 -41
  88. package/dist/commands/playground.d.ts +0 -11
  89. package/dist/commands/playground.js +0 -47
  90. package/dist/commands/releases.d.ts +0 -17
  91. package/dist/commands/releases.js +0 -54
  92. package/dist/commands/replay.d.ts +0 -18
  93. package/dist/commands/replay.js +0 -64
  94. package/dist/commands/secrets.d.ts +0 -19
  95. package/dist/commands/secrets.js +0 -145
  96. package/dist/commands/setup.d.ts +0 -21
  97. package/dist/commands/setup.js +0 -67
  98. package/dist/commands/sites.d.ts +0 -18
  99. package/dist/commands/sites.js +0 -139
  100. package/dist/commands/skad.d.ts +0 -18
  101. package/dist/commands/skad.js +0 -53
  102. package/dist/commands/sourcemap.d.ts +0 -33
  103. package/dist/commands/sourcemap.js +0 -204
  104. package/dist/commands/status.d.ts +0 -7
  105. package/dist/commands/status.js +0 -136
  106. package/dist/commands/upgrade.d.ts +0 -21
  107. package/dist/commands/upgrade.js +0 -183
  108. package/dist/commands/warehouse.d.ts +0 -20
  109. package/dist/commands/warehouse.js +0 -65
  110. package/dist/commands/warehouses.d.ts +0 -17
  111. package/dist/commands/warehouses.js +0 -182
  112. package/dist/commands/watch.d.ts +0 -45
  113. package/dist/commands/watch.js +0 -258
  114. package/dist/commands/whoami.d.ts +0 -9
  115. package/dist/commands/whoami.js +0 -50
  116. package/dist/config.d.ts +0 -75
  117. package/dist/config.js +0 -329
  118. package/dist/frameworks/detect.d.ts +0 -8
  119. package/dist/frameworks/detect.js +0 -458
  120. package/dist/install-intent-proposal.d.ts +0 -99
  121. package/dist/install-intent-proposal.js +0 -202
  122. package/dist/utils/api.d.ts +0 -20
  123. package/dist/utils/api.js +0 -47
  124. package/dist/utils/config.d.ts +0 -13
  125. package/dist/utils/config.js +0 -30
  126. package/dist/utils/confirm.d.ts +0 -17
  127. package/dist/utils/confirm.js +0 -40
  128. package/dist/utils/dry-run.d.ts +0 -20
  129. package/dist/utils/dry-run.js +0 -67
  130. package/dist/utils/from-file.d.ts +0 -9
  131. package/dist/utils/from-file.js +0 -72
  132. package/dist/utils/redact.d.ts +0 -14
  133. package/dist/utils/redact.js +0 -48
  134. package/dist/utils/ui.d.ts +0 -14
  135. package/dist/utils/ui.js +0 -59
  136. package/scripts/.gitkeep +0 -0
  137. package/scripts/README-gurulu-agentic-install.md +0 -114
  138. package/scripts/README-gurulu-scan.md +0 -98
  139. package/scripts/audit-cli-scopes.mjs +0 -204
  140. package/scripts/backfill-tenant-id.mjs +0 -172
  141. package/scripts/backfill-tenant-links.ts +0 -252
  142. package/scripts/backup-clickhouse.sh +0 -27
  143. package/scripts/backup-postgres.sh +0 -19
  144. package/scripts/bootstrap-runtime-schema.mjs +0 -87
  145. package/scripts/bootstrap-stripe.mjs +0 -158
  146. package/scripts/gurulu-agentic-install.lib.cjs +0 -762
  147. package/scripts/gurulu-agentic-install.mjs +0 -623
  148. package/scripts/gurulu-scan.lib.cjs +0 -1509
  149. package/scripts/gurulu-scan.mjs +0 -91
  150. package/scripts/gurulu-verify-install.lib.cjs +0 -334
  151. package/scripts/gurulu-verify-install.mjs +0 -59
  152. package/scripts/init-ssl.sh +0 -26
  153. package/scripts/migrate-flow-graph-enums.sh +0 -86
  154. package/scripts/monitor-disk.sh +0 -24
  155. package/scripts/patches/astro.patch.cjs +0 -74
  156. package/scripts/patches/auto-instrument/ast-helper.cjs +0 -480
  157. package/scripts/patches/auto-instrument/astro.cjs +0 -273
  158. package/scripts/patches/auto-instrument/express.cjs +0 -383
  159. package/scripts/patches/auto-instrument/fastify.cjs +0 -262
  160. package/scripts/patches/auto-instrument/hono.cjs +0 -392
  161. package/scripts/patches/auto-instrument/index.cjs +0 -80
  162. package/scripts/patches/auto-instrument/nestjs.cjs +0 -286
  163. package/scripts/patches/auto-instrument/nextjs-app-router.cjs +0 -345
  164. package/scripts/patches/auto-instrument/nextjs-pages.cjs +0 -361
  165. package/scripts/patches/auto-instrument/remix.cjs +0 -168
  166. package/scripts/patches/auto-instrument/sdk-helper-map.cjs +0 -241
  167. package/scripts/patches/auto-instrument/singleton-helper.cjs +0 -193
  168. package/scripts/patches/auto-instrument/sveltekit.cjs +0 -161
  169. package/scripts/patches/auto-instrument/vite-react.cjs +0 -37
  170. package/scripts/patches/auto-instrument/vue.cjs +0 -196
  171. package/scripts/patches/express.patch.cjs +0 -99
  172. package/scripts/patches/fastify.patch.cjs +0 -108
  173. package/scripts/patches/index.cjs +0 -300
  174. package/scripts/patches/nestjs.patch.cjs +0 -112
  175. package/scripts/patches/nextjs-app-router.patch.cjs +0 -97
  176. package/scripts/patches/nextjs-pages.patch.cjs +0 -97
  177. package/scripts/patches/remix.patch.cjs +0 -75
  178. package/scripts/patches/sveltekit.patch.cjs +0 -72
  179. package/scripts/patches/vite-react.patch.cjs +0 -73
  180. package/scripts/patches/vue.patch.cjs +0 -82
  181. package/scripts/renew-ssl.sh +0 -14
  182. package/scripts/resolve-migration.sh +0 -23
  183. package/scripts/seed-cli-dev-keys.mjs +0 -130
  184. package/scripts/seed-test-data.mjs +0 -391
  185. package/scripts/spike-browserless.ts +0 -65
  186. package/scripts/tenant-pivot-consistency-check.mjs +0 -205
  187. package/scripts/tenant-pivot-phase-3-cleanup.lib.cjs +0 -258
  188. package/scripts/tenant-pivot-phase-3-cleanup.mjs +0 -98
  189. package/scripts/test-identity-resolution.ts +0 -804
  190. package/scripts/validate-gurulu-schemas.mjs +0 -79
@@ -1,72 +0,0 @@
1
- // sveltekit.patch.cjs — Phase 18.7 A1
2
- //
3
- // Detects a SvelteKit app by the presence of `src/app.html` (the HTML shell
4
- // template) and injects a plain <script> tag before the `%sveltekit.body%`
5
- // placeholder (or `</body>` as fallback). The shell is static HTML with
6
- // SvelteKit placeholder comments, so regex insertion is safe.
7
-
8
- const fs = require('fs');
9
- const path = require('path');
10
-
11
- const NAME = 'sveltekit';
12
- const CANDIDATES = [
13
- 'src/app.html',
14
- ];
15
-
16
- const MARKER = 'data-gurulu-install="1"';
17
-
18
- function detect(repoRoot) {
19
- for (const rel of CANDIDATES) {
20
- if (fs.existsSync(path.join(repoRoot, rel))) {
21
- return { framework: NAME, files: [rel] };
22
- }
23
- }
24
- return null;
25
- }
26
-
27
- function buildScriptTag(injection) {
28
- const pkAttr = injection.publishableKey
29
- ? ` data-gurulu-publishable-key="${injection.publishableKey}"`
30
- : '';
31
- return (
32
- ` <script\n` +
33
- ` src="${injection.scriptSrc}"\n` +
34
- ` data-gurulu-site-id="${injection.siteId}"\n` +
35
- ` data-gurulu-tenant-id="${injection.tenantId}"${pkAttr}\n` +
36
- ` data-features="errors,replay,advanced"\n` +
37
- ` ${MARKER}\n` +
38
- ` async\n` +
39
- ` ></script>\n`
40
- );
41
- }
42
-
43
- function injectScriptTag(source, injection) {
44
- if (source.includes(MARKER)) return source;
45
- const tag = buildScriptTag(injection);
46
- // Prefer to insert just before </body> so it sits just after
47
- // %sveltekit.body% placeholder which SvelteKit injects the app into.
48
- if (/<\/body>/.test(source)) {
49
- return source.replace(/<\/body>/, `${tag} </body>`);
50
- }
51
- if (/%sveltekit\.body%/.test(source)) {
52
- return source.replace(/(%sveltekit\.body%)/, `$1\n${tag}`);
53
- }
54
- return source + '\n' + tag;
55
- }
56
-
57
- function plan(ctx) {
58
- const detection = detect(ctx.repoRoot);
59
- if (!detection) return { changes: [], notes: ['no-sveltekit-shell'] };
60
- const changes = [];
61
- for (const rel of detection.files) {
62
- const abs = path.join(ctx.repoRoot, rel);
63
- const before = fs.readFileSync(abs, 'utf8');
64
- const after = injectScriptTag(before, ctx.injection);
65
- if (after !== before) {
66
- changes.push({ relPath: rel, before, after, reason: 'inject-script-tag' });
67
- }
68
- }
69
- return { changes, notes: [] };
70
- }
71
-
72
- module.exports = { name: NAME, detect, plan };
@@ -1,73 +0,0 @@
1
- // vite-react.patch.cjs — Phase 16 A1
2
- //
3
- // Detects a Vite + React project (`vite.config.*` + `src/main.tsx`/`main.jsx`)
4
- // and inserts a `window.gurulu` bootstrap near the root render call.
5
-
6
- const fs = require('fs');
7
- const path = require('path');
8
-
9
- const NAME = 'vite-react';
10
- const VITE_CONFIGS = ['vite.config.ts', 'vite.config.js', 'vite.config.mjs'];
11
- const MAIN_CANDIDATES = ['src/main.tsx', 'src/main.jsx', 'src/main.ts', 'src/main.js'];
12
-
13
- const MARKER = '/* gurulu:install */';
14
-
15
- function detect(repoRoot) {
16
- const hasVite = VITE_CONFIGS.some((f) => fs.existsSync(path.join(repoRoot, f)));
17
- if (!hasVite) return null;
18
- const main = MAIN_CANDIDATES.find((f) => fs.existsSync(path.join(repoRoot, f)));
19
- if (!main) return null;
20
- return { framework: NAME, files: [main] };
21
- }
22
-
23
- function buildBootstrap(injection) {
24
- const pkLine = injection.publishableKey
25
- ? ` s.setAttribute('data-gurulu-publishable-key', ${JSON.stringify(injection.publishableKey)});\n`
26
- : '';
27
- return (
28
- `${MARKER}\n` +
29
- `if (typeof window !== 'undefined' && !window.__guruluInstalled) {\n` +
30
- ` window.__guruluInstalled = true;\n` +
31
- ` window.gurulu = window.gurulu || { queue: [], siteId: ${JSON.stringify(injection.siteId)}, tenantId: ${JSON.stringify(injection.tenantId)} };\n` +
32
- ` const s = document.createElement('script');\n` +
33
- ` s.src = ${JSON.stringify(injection.scriptSrc)};\n` +
34
- ` s.async = true;\n` +
35
- ` s.setAttribute('data-gurulu-install', '1');\n` +
36
- ` s.setAttribute('data-gurulu-site-id', ${JSON.stringify(injection.siteId)});\n` +
37
- pkLine +
38
- ` s.setAttribute('data-features', 'errors,replay,advanced');\n` +
39
- ` document.head.appendChild(s);\n` +
40
- `}\n`
41
- );
42
- }
43
-
44
- function inject(source, injection) {
45
- if (source.includes(MARKER)) return source;
46
- const bootstrap = buildBootstrap(injection);
47
- // Insert immediately before the first `createRoot(` or `ReactDOM.render(` call.
48
- const rootCall = source.search(/(?:ReactDOM\.render|createRoot)\s*\(/);
49
- if (rootCall !== -1) {
50
- // Insert before the surrounding statement start — find the previous newline.
51
- const lineStart = source.lastIndexOf('\n', rootCall) + 1;
52
- return source.slice(0, lineStart) + bootstrap + source.slice(lineStart);
53
- }
54
- // Fallback: append at end.
55
- return source + '\n' + bootstrap;
56
- }
57
-
58
- function plan(ctx) {
59
- const detection = detect(ctx.repoRoot);
60
- if (!detection) return { changes: [], notes: ['no-vite-main'] };
61
- const changes = [];
62
- for (const rel of detection.files) {
63
- const abs = path.join(ctx.repoRoot, rel);
64
- const before = fs.readFileSync(abs, 'utf8');
65
- const after = inject(before, ctx.injection);
66
- if (after !== before) {
67
- changes.push({ relPath: rel, before, after, reason: 'inject-bootstrap' });
68
- }
69
- }
70
- return { changes, notes: [] };
71
- }
72
-
73
- module.exports = { name: NAME, detect, plan };
@@ -1,82 +0,0 @@
1
- // vue.patch.cjs — Phase 18.7 A1
2
- //
3
- // Detects a Vue 3 (Vite) project by the presence of a project-root
4
- // `index.html` (the Vite SPA shell). We inject a plain <script> tag
5
- // immediately before `</body>`. Unlike vite-react.patch which injects
6
- // into `src/main.ts`, Vue SPAs canonically expose `index.html` directly,
7
- // so HTML injection is cleaner and idempotent.
8
-
9
- const fs = require('fs');
10
- const path = require('path');
11
-
12
- const NAME = 'vue';
13
- const CANDIDATES = [
14
- 'index.html',
15
- 'public/index.html',
16
- ];
17
-
18
- const MARKER = 'data-gurulu-install="1"';
19
-
20
- function looksLikeVue(repoRoot) {
21
- const pkgPath = path.join(repoRoot, 'package.json');
22
- if (!fs.existsSync(pkgPath)) return false;
23
- try {
24
- const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
25
- const deps = { ...(pkg.dependencies || {}), ...(pkg.devDependencies || {}) };
26
- return Boolean(deps['vue']);
27
- } catch {
28
- return false;
29
- }
30
- }
31
-
32
- function detect(repoRoot) {
33
- if (!looksLikeVue(repoRoot)) return null;
34
- for (const rel of CANDIDATES) {
35
- if (fs.existsSync(path.join(repoRoot, rel))) {
36
- return { framework: NAME, files: [rel] };
37
- }
38
- }
39
- return null;
40
- }
41
-
42
- function buildScriptTag(injection) {
43
- const pkAttr = injection.publishableKey
44
- ? ` data-gurulu-publishable-key="${injection.publishableKey}"`
45
- : '';
46
- return (
47
- ` <script\n` +
48
- ` src="${injection.scriptSrc}"\n` +
49
- ` data-gurulu-site-id="${injection.siteId}"\n` +
50
- ` data-gurulu-tenant-id="${injection.tenantId}"${pkAttr}\n` +
51
- ` data-features="errors,replay,advanced"\n` +
52
- ` ${MARKER}\n` +
53
- ` async\n` +
54
- ` ></script>\n`
55
- );
56
- }
57
-
58
- function injectScriptTag(source, injection) {
59
- if (source.includes(MARKER)) return source;
60
- const tag = buildScriptTag(injection);
61
- if (/<\/body>/.test(source)) {
62
- return source.replace(/<\/body>/, `${tag} </body>`);
63
- }
64
- return source + '\n' + tag;
65
- }
66
-
67
- function plan(ctx) {
68
- const detection = detect(ctx.repoRoot);
69
- if (!detection) return { changes: [], notes: ['no-vue-shell'] };
70
- const changes = [];
71
- for (const rel of detection.files) {
72
- const abs = path.join(ctx.repoRoot, rel);
73
- const before = fs.readFileSync(abs, 'utf8');
74
- const after = injectScriptTag(before, ctx.injection);
75
- if (after !== before) {
76
- changes.push({ relPath: rel, before, after, reason: 'inject-script-tag' });
77
- }
78
- }
79
- return { changes, notes: [] };
80
- }
81
-
82
- module.exports = { name: NAME, detect, plan };
@@ -1,14 +0,0 @@
1
- #!/bin/bash
2
- set -e
3
-
4
- echo "[ssl] Renewing SSL certificates..."
5
-
6
- docker run --rm \
7
- -v "$(pwd)/certbot/conf:/etc/letsencrypt" \
8
- -v "$(pwd)/certbot/www:/var/www/certbot" \
9
- certbot/certbot renew --quiet
10
-
11
- # Reload nginx
12
- docker compose restart nginx-ssl 2>/dev/null || true
13
-
14
- echo "[ssl] Renewal complete."
@@ -1,23 +0,0 @@
1
- #!/bin/bash
2
- set -e
3
-
4
- echo "=== Resolve Migration ==="
5
-
6
- # Mark any stuck migrations as resolved
7
- STUCK=$(npx prisma migrate status 2>&1 | grep -o 'Migration "[^"]*" has a state of "failed"' | sed 's/Migration "//;s/" has a state of "failed"//' || true)
8
-
9
- if [ -n "$STUCK" ]; then
10
- echo "Found stuck migration(s): $STUCK"
11
- for migration in $STUCK; do
12
- echo "Resolving: $migration"
13
- npx prisma migrate resolve --applied "$migration" || true
14
- done
15
- else
16
- echo "No stuck migrations found."
17
- fi
18
-
19
- # Generate Prisma client
20
- echo "Generating Prisma client..."
21
- npx prisma generate
22
-
23
- echo "=== Resolve Migration Complete ==="
@@ -1,130 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * Phase 18.5 W1 — seed a test tenant + user + master CLI keys for local
4
- * dev. Prints the full gsk_live_... and gsk_test_... keys to stdout ONE
5
- * TIME. Re-running against an existing seed user just prints the
6
- * existing tenant id + prefixes (not the plaintext).
7
- *
8
- * Usage:
9
- * npm run seed:cli-dev
10
- * npm run seed:cli-dev -- --email dev@example.com
11
- */
12
-
13
- import { PrismaClient } from '@prisma/client';
14
- import crypto from 'node:crypto';
15
-
16
- const prisma = new PrismaClient();
17
-
18
- function parseArg(flag, fallback) {
19
- const i = process.argv.indexOf(flag);
20
- if (i === -1 || i + 1 >= process.argv.length) return fallback;
21
- return process.argv[i + 1];
22
- }
23
-
24
- function randomAlphaNumeric(bytes) {
25
- let out = '';
26
- while (out.length < bytes * 2) {
27
- out += crypto.randomBytes(bytes).toString('base64url').replace(/[-_]/g, '');
28
- }
29
- return out.slice(0, bytes * 2);
30
- }
31
-
32
- function generateSecretKey(mode) {
33
- const random = randomAlphaNumeric(24);
34
- const fullKey = `gsk_${mode}_${random}`;
35
- const prefix = fullKey.slice(0, 13);
36
- const hash = crypto.createHash('sha256').update(fullKey).digest('hex');
37
- return { fullKey, prefix, hash };
38
- }
39
-
40
- async function main() {
41
- const email = parseArg('--email', 'dev@gurulu.local');
42
- const tenantName = parseArg('--tenant', 'Dev Workspace');
43
-
44
- console.log(`[seed-cli-dev] email=${email} tenant=${tenantName}`);
45
-
46
- let user = await prisma.user.findUnique({ where: { email } });
47
- let tenantId;
48
-
49
- if (user) {
50
- tenantId = user.tenantId;
51
- console.log(`[seed-cli-dev] user exists: id=${user.id} tenant=${tenantId}`);
52
- } else {
53
- const tenant = await prisma.tenant.create({ data: { name: tenantName } });
54
- user = await prisma.user.create({
55
- data: {
56
- email,
57
- emailVerified: new Date(),
58
- tenantId: tenant.id,
59
- },
60
- });
61
- await prisma.member.create({
62
- data: { tenantId: tenant.id, userId: user.id, role: 'OWNER' },
63
- });
64
- tenantId = tenant.id;
65
- console.log(`[seed-cli-dev] created user=${user.id} tenant=${tenantId}`);
66
- }
67
-
68
- const existingMaster = await prisma.secretKey.findFirst({
69
- where: { tenantId, name: 'Master' },
70
- });
71
-
72
- if (existingMaster) {
73
- const all = await prisma.secretKey.findMany({
74
- where: { tenantId, name: 'Master' },
75
- select: { id: true, prefix: true, mode: true, revokedAt: true },
76
- });
77
- console.log(`[seed-cli-dev] master keys already exist (plaintext not recoverable):`);
78
- for (const k of all) {
79
- console.log(` - ${k.mode}\t${k.prefix}...\trevoked=${k.revokedAt ? 'yes' : 'no'}`);
80
- }
81
- console.log(`[seed-cli-dev] delete them manually and re-run if you need fresh plaintext.`);
82
- return;
83
- }
84
-
85
- const now = new Date();
86
- const resetAt = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth() + 1, 1));
87
- await prisma.cliQuota.upsert({
88
- where: { tenantId },
89
- update: {},
90
- create: {
91
- tenantId,
92
- installsThisMonth: 0,
93
- apiCallsThisMonth: 0,
94
- eventsThisMonth: BigInt(0),
95
- resetAt,
96
- },
97
- });
98
-
99
- const output = [];
100
- for (const mode of ['live', 'test']) {
101
- const { fullKey, prefix, hash } = generateSecretKey(mode);
102
- await prisma.secretKey.create({
103
- data: {
104
- tenantId,
105
- createdBy: user.id,
106
- name: 'Master',
107
- prefix,
108
- tokenHash: hash,
109
- mode,
110
- scopes: ['admin:*'],
111
- },
112
- });
113
- output.push({ mode, fullKey });
114
- }
115
-
116
- console.log('\n=============================================================');
117
- console.log(' Master CLI keys created — save these NOW, they are shown once.');
118
- console.log('=============================================================');
119
- for (const k of output) {
120
- console.log(` ${k.mode.toUpperCase()} ${k.fullKey}`);
121
- }
122
- console.log('=============================================================\n');
123
- }
124
-
125
- main()
126
- .catch((err) => {
127
- console.error('[seed-cli-dev] failed:', err);
128
- process.exit(1);
129
- })
130
- .finally(() => prisma.$disconnect());