@gurulu/cli 0.4.6 → 1.0.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 (180) 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 +25410 -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 +25 -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 +24985 -853
  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/package.json +40 -20
  28. package/bin/gurulu.js +0 -2
  29. package/dist/api-client.d.ts +0 -33
  30. package/dist/api-client.js +0 -175
  31. package/dist/commands/add-server.d.ts +0 -9
  32. package/dist/commands/add-server.js +0 -162
  33. package/dist/commands/alerts.d.ts +0 -27
  34. package/dist/commands/alerts.js +0 -309
  35. package/dist/commands/api-keys.d.ts +0 -20
  36. package/dist/commands/api-keys.js +0 -130
  37. package/dist/commands/attribution.d.ts +0 -22
  38. package/dist/commands/attribution.js +0 -111
  39. package/dist/commands/audiences.d.ts +0 -23
  40. package/dist/commands/audiences.js +0 -243
  41. package/dist/commands/audit.d.ts +0 -20
  42. package/dist/commands/audit.js +0 -130
  43. package/dist/commands/auth.js +0 -249
  44. package/dist/commands/chat.d.ts +0 -18
  45. package/dist/commands/chat.js +0 -117
  46. package/dist/commands/config.d.ts +0 -10
  47. package/dist/commands/config.js +0 -92
  48. package/dist/commands/consent.d.ts +0 -27
  49. package/dist/commands/consent.js +0 -233
  50. package/dist/commands/conversion-paths.d.ts +0 -19
  51. package/dist/commands/conversion-paths.js +0 -55
  52. package/dist/commands/db.d.ts +0 -25
  53. package/dist/commands/db.js +0 -330
  54. package/dist/commands/destinations.d.ts +0 -20
  55. package/dist/commands/destinations.js +0 -191
  56. package/dist/commands/doctor.js +0 -360
  57. package/dist/commands/errors.d.ts +0 -27
  58. package/dist/commands/errors.js +0 -121
  59. package/dist/commands/events.d.ts +0 -33
  60. package/dist/commands/events.js +0 -349
  61. package/dist/commands/experiments.d.ts +0 -22
  62. package/dist/commands/experiments.js +0 -264
  63. package/dist/commands/funnels.d.ts +0 -17
  64. package/dist/commands/funnels.js +0 -203
  65. package/dist/commands/goals.d.ts +0 -18
  66. package/dist/commands/goals.js +0 -214
  67. package/dist/commands/heatmap.d.ts +0 -27
  68. package/dist/commands/heatmap.js +0 -112
  69. package/dist/commands/identity.d.ts +0 -29
  70. package/dist/commands/identity.js +0 -328
  71. package/dist/commands/init.js +0 -215
  72. package/dist/commands/insights.d.ts +0 -10
  73. package/dist/commands/insights.js +0 -65
  74. package/dist/commands/install.d.ts +0 -259
  75. package/dist/commands/install.js +0 -1590
  76. package/dist/commands/login.d.ts +0 -20
  77. package/dist/commands/login.js +0 -170
  78. package/dist/commands/logout.d.ts +0 -10
  79. package/dist/commands/logout.js +0 -41
  80. package/dist/commands/playground.d.ts +0 -11
  81. package/dist/commands/playground.js +0 -47
  82. package/dist/commands/releases.d.ts +0 -17
  83. package/dist/commands/releases.js +0 -54
  84. package/dist/commands/replay.d.ts +0 -18
  85. package/dist/commands/replay.js +0 -64
  86. package/dist/commands/secrets.d.ts +0 -19
  87. package/dist/commands/secrets.js +0 -145
  88. package/dist/commands/sites.d.ts +0 -18
  89. package/dist/commands/sites.js +0 -139
  90. package/dist/commands/skad.d.ts +0 -18
  91. package/dist/commands/skad.js +0 -53
  92. package/dist/commands/sourcemap.d.ts +0 -33
  93. package/dist/commands/sourcemap.js +0 -204
  94. package/dist/commands/status.d.ts +0 -7
  95. package/dist/commands/status.js +0 -136
  96. package/dist/commands/upgrade.d.ts +0 -21
  97. package/dist/commands/upgrade.js +0 -183
  98. package/dist/commands/warehouse.d.ts +0 -20
  99. package/dist/commands/warehouse.js +0 -65
  100. package/dist/commands/warehouses.d.ts +0 -17
  101. package/dist/commands/warehouses.js +0 -182
  102. package/dist/commands/watch.d.ts +0 -45
  103. package/dist/commands/watch.js +0 -258
  104. package/dist/commands/whoami.d.ts +0 -9
  105. package/dist/commands/whoami.js +0 -50
  106. package/dist/config.d.ts +0 -75
  107. package/dist/config.js +0 -329
  108. package/dist/frameworks/detect.d.ts +0 -8
  109. package/dist/frameworks/detect.js +0 -444
  110. package/dist/install-intent-proposal.d.ts +0 -99
  111. package/dist/install-intent-proposal.js +0 -202
  112. package/dist/utils/api.d.ts +0 -20
  113. package/dist/utils/api.js +0 -47
  114. package/dist/utils/config.d.ts +0 -13
  115. package/dist/utils/config.js +0 -30
  116. package/dist/utils/confirm.d.ts +0 -17
  117. package/dist/utils/confirm.js +0 -40
  118. package/dist/utils/dry-run.d.ts +0 -20
  119. package/dist/utils/dry-run.js +0 -67
  120. package/dist/utils/from-file.d.ts +0 -9
  121. package/dist/utils/from-file.js +0 -72
  122. package/dist/utils/redact.d.ts +0 -14
  123. package/dist/utils/redact.js +0 -48
  124. package/dist/utils/ui.d.ts +0 -14
  125. package/dist/utils/ui.js +0 -59
  126. package/scripts/.gitkeep +0 -0
  127. package/scripts/README-gurulu-agentic-install.md +0 -114
  128. package/scripts/README-gurulu-scan.md +0 -98
  129. package/scripts/audit-cli-scopes.mjs +0 -204
  130. package/scripts/backfill-tenant-id.mjs +0 -172
  131. package/scripts/backfill-tenant-links.ts +0 -252
  132. package/scripts/backup-clickhouse.sh +0 -27
  133. package/scripts/backup-postgres.sh +0 -19
  134. package/scripts/bootstrap-runtime-schema.mjs +0 -87
  135. package/scripts/bootstrap-stripe.mjs +0 -158
  136. package/scripts/gurulu-agentic-install.lib.cjs +0 -762
  137. package/scripts/gurulu-agentic-install.mjs +0 -623
  138. package/scripts/gurulu-scan.lib.cjs +0 -1509
  139. package/scripts/gurulu-scan.mjs +0 -91
  140. package/scripts/gurulu-verify-install.lib.cjs +0 -334
  141. package/scripts/gurulu-verify-install.mjs +0 -59
  142. package/scripts/init-ssl.sh +0 -26
  143. package/scripts/migrate-flow-graph-enums.sh +0 -86
  144. package/scripts/monitor-disk.sh +0 -24
  145. package/scripts/patches/astro.patch.cjs +0 -74
  146. package/scripts/patches/auto-instrument/ast-helper.cjs +0 -480
  147. package/scripts/patches/auto-instrument/astro.cjs +0 -273
  148. package/scripts/patches/auto-instrument/express.cjs +0 -383
  149. package/scripts/patches/auto-instrument/fastify.cjs +0 -262
  150. package/scripts/patches/auto-instrument/hono.cjs +0 -392
  151. package/scripts/patches/auto-instrument/index.cjs +0 -80
  152. package/scripts/patches/auto-instrument/nestjs.cjs +0 -286
  153. package/scripts/patches/auto-instrument/nextjs-app-router.cjs +0 -345
  154. package/scripts/patches/auto-instrument/nextjs-pages.cjs +0 -361
  155. package/scripts/patches/auto-instrument/remix.cjs +0 -168
  156. package/scripts/patches/auto-instrument/sdk-helper-map.cjs +0 -241
  157. package/scripts/patches/auto-instrument/singleton-helper.cjs +0 -193
  158. package/scripts/patches/auto-instrument/sveltekit.cjs +0 -161
  159. package/scripts/patches/auto-instrument/vite-react.cjs +0 -37
  160. package/scripts/patches/auto-instrument/vue.cjs +0 -196
  161. package/scripts/patches/express.patch.cjs +0 -99
  162. package/scripts/patches/fastify.patch.cjs +0 -108
  163. package/scripts/patches/index.cjs +0 -300
  164. package/scripts/patches/nestjs.patch.cjs +0 -112
  165. package/scripts/patches/nextjs-app-router.patch.cjs +0 -97
  166. package/scripts/patches/nextjs-pages.patch.cjs +0 -97
  167. package/scripts/patches/remix.patch.cjs +0 -75
  168. package/scripts/patches/sveltekit.patch.cjs +0 -72
  169. package/scripts/patches/vite-react.patch.cjs +0 -73
  170. package/scripts/patches/vue.patch.cjs +0 -82
  171. package/scripts/renew-ssl.sh +0 -14
  172. package/scripts/resolve-migration.sh +0 -23
  173. package/scripts/seed-cli-dev-keys.mjs +0 -130
  174. package/scripts/seed-test-data.mjs +0 -391
  175. package/scripts/spike-browserless.ts +0 -65
  176. package/scripts/tenant-pivot-consistency-check.mjs +0 -205
  177. package/scripts/tenant-pivot-phase-3-cleanup.lib.cjs +0 -258
  178. package/scripts/tenant-pivot-phase-3-cleanup.mjs +0 -98
  179. package/scripts/test-identity-resolution.ts +0 -804
  180. 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());