@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.
- package/LICENSE +92 -0
- package/README.md +35 -106
- package/dist/bin.d.ts +3 -0
- package/dist/bin.d.ts.map +1 -0
- package/dist/bin.js +25751 -0
- package/dist/commands/auth.d.ts +23 -20
- package/dist/commands/auth.d.ts.map +1 -0
- package/dist/commands/doctor.d.ts +20 -6
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/init.d.ts +33 -11
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/pull.d.ts +13 -0
- package/dist/commands/pull.d.ts.map +1 -0
- package/dist/commands/push.d.ts +40 -0
- package/dist/commands/push.d.ts.map +1 -0
- package/dist/commands/validate.d.ts +36 -0
- package/dist/commands/validate.d.ts.map +1 -0
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +25326 -876
- package/dist/lib/api.d.ts +139 -0
- package/dist/lib/api.d.ts.map +1 -0
- package/dist/lib/codegen.d.ts +4 -0
- package/dist/lib/codegen.d.ts.map +1 -0
- package/dist/lib/config.d.ts +43 -0
- package/dist/lib/config.d.ts.map +1 -0
- package/dist/lib/detect.d.ts +27 -0
- package/dist/lib/detect.d.ts.map +1 -0
- package/dist/lib/detect.js +106 -0
- package/dist/lib/exec-install.d.ts +21 -0
- package/dist/lib/exec-install.d.ts.map +1 -0
- package/dist/lib/install-plan.d.ts +25 -0
- package/dist/lib/install-plan.d.ts.map +1 -0
- package/dist/lib/install-plan.js +161 -0
- package/package.json +51 -20
- package/bin/gurulu.js +0 -2
- package/dist/api-client.d.ts +0 -33
- package/dist/api-client.js +0 -175
- package/dist/commands/add-server.d.ts +0 -9
- package/dist/commands/add-server.js +0 -162
- package/dist/commands/alerts.d.ts +0 -27
- package/dist/commands/alerts.js +0 -309
- package/dist/commands/api-keys.d.ts +0 -20
- package/dist/commands/api-keys.js +0 -130
- package/dist/commands/attribution.d.ts +0 -22
- package/dist/commands/attribution.js +0 -111
- package/dist/commands/audiences.d.ts +0 -23
- package/dist/commands/audiences.js +0 -243
- package/dist/commands/audit.d.ts +0 -20
- package/dist/commands/audit.js +0 -130
- package/dist/commands/auth.js +0 -249
- package/dist/commands/chat.d.ts +0 -19
- package/dist/commands/chat.js +0 -118
- package/dist/commands/config.d.ts +0 -10
- package/dist/commands/config.js +0 -92
- package/dist/commands/consent.d.ts +0 -27
- package/dist/commands/consent.js +0 -233
- package/dist/commands/conversion-paths.d.ts +0 -19
- package/dist/commands/conversion-paths.js +0 -55
- package/dist/commands/db.d.ts +0 -25
- package/dist/commands/db.js +0 -330
- package/dist/commands/destinations.d.ts +0 -20
- package/dist/commands/destinations.js +0 -191
- package/dist/commands/doctor.js +0 -360
- package/dist/commands/errors.d.ts +0 -27
- package/dist/commands/errors.js +0 -121
- package/dist/commands/events.d.ts +0 -33
- package/dist/commands/events.js +0 -371
- package/dist/commands/experiments.d.ts +0 -22
- package/dist/commands/experiments.js +0 -264
- package/dist/commands/funnels.d.ts +0 -17
- package/dist/commands/funnels.js +0 -203
- package/dist/commands/goals.d.ts +0 -18
- package/dist/commands/goals.js +0 -214
- package/dist/commands/heatmap.d.ts +0 -27
- package/dist/commands/heatmap.js +0 -112
- package/dist/commands/identity.d.ts +0 -29
- package/dist/commands/identity.js +0 -328
- package/dist/commands/init.js +0 -215
- package/dist/commands/insights.d.ts +0 -10
- package/dist/commands/insights.js +0 -77
- package/dist/commands/install.d.ts +0 -259
- package/dist/commands/install.js +0 -1590
- package/dist/commands/login.d.ts +0 -20
- package/dist/commands/login.js +0 -170
- package/dist/commands/logout.d.ts +0 -10
- package/dist/commands/logout.js +0 -41
- package/dist/commands/playground.d.ts +0 -11
- package/dist/commands/playground.js +0 -47
- package/dist/commands/releases.d.ts +0 -17
- package/dist/commands/releases.js +0 -54
- package/dist/commands/replay.d.ts +0 -18
- package/dist/commands/replay.js +0 -64
- package/dist/commands/secrets.d.ts +0 -19
- package/dist/commands/secrets.js +0 -145
- package/dist/commands/setup.d.ts +0 -21
- package/dist/commands/setup.js +0 -67
- package/dist/commands/sites.d.ts +0 -18
- package/dist/commands/sites.js +0 -139
- package/dist/commands/skad.d.ts +0 -18
- package/dist/commands/skad.js +0 -53
- package/dist/commands/sourcemap.d.ts +0 -33
- package/dist/commands/sourcemap.js +0 -204
- package/dist/commands/status.d.ts +0 -7
- package/dist/commands/status.js +0 -136
- package/dist/commands/upgrade.d.ts +0 -21
- package/dist/commands/upgrade.js +0 -183
- package/dist/commands/warehouse.d.ts +0 -20
- package/dist/commands/warehouse.js +0 -65
- package/dist/commands/warehouses.d.ts +0 -17
- package/dist/commands/warehouses.js +0 -182
- package/dist/commands/watch.d.ts +0 -45
- package/dist/commands/watch.js +0 -258
- package/dist/commands/whoami.d.ts +0 -9
- package/dist/commands/whoami.js +0 -50
- package/dist/config.d.ts +0 -75
- package/dist/config.js +0 -329
- package/dist/frameworks/detect.d.ts +0 -8
- package/dist/frameworks/detect.js +0 -458
- package/dist/install-intent-proposal.d.ts +0 -99
- package/dist/install-intent-proposal.js +0 -202
- package/dist/utils/api.d.ts +0 -20
- package/dist/utils/api.js +0 -47
- package/dist/utils/config.d.ts +0 -13
- package/dist/utils/config.js +0 -30
- package/dist/utils/confirm.d.ts +0 -17
- package/dist/utils/confirm.js +0 -40
- package/dist/utils/dry-run.d.ts +0 -20
- package/dist/utils/dry-run.js +0 -67
- package/dist/utils/from-file.d.ts +0 -9
- package/dist/utils/from-file.js +0 -72
- package/dist/utils/redact.d.ts +0 -14
- package/dist/utils/redact.js +0 -48
- package/dist/utils/ui.d.ts +0 -14
- package/dist/utils/ui.js +0 -59
- package/scripts/.gitkeep +0 -0
- package/scripts/README-gurulu-agentic-install.md +0 -114
- package/scripts/README-gurulu-scan.md +0 -98
- package/scripts/audit-cli-scopes.mjs +0 -204
- package/scripts/backfill-tenant-id.mjs +0 -172
- package/scripts/backfill-tenant-links.ts +0 -252
- package/scripts/backup-clickhouse.sh +0 -27
- package/scripts/backup-postgres.sh +0 -19
- package/scripts/bootstrap-runtime-schema.mjs +0 -87
- package/scripts/bootstrap-stripe.mjs +0 -158
- package/scripts/gurulu-agentic-install.lib.cjs +0 -762
- package/scripts/gurulu-agentic-install.mjs +0 -623
- package/scripts/gurulu-scan.lib.cjs +0 -1509
- package/scripts/gurulu-scan.mjs +0 -91
- package/scripts/gurulu-verify-install.lib.cjs +0 -334
- package/scripts/gurulu-verify-install.mjs +0 -59
- package/scripts/init-ssl.sh +0 -26
- package/scripts/migrate-flow-graph-enums.sh +0 -86
- package/scripts/monitor-disk.sh +0 -24
- package/scripts/patches/astro.patch.cjs +0 -74
- package/scripts/patches/auto-instrument/ast-helper.cjs +0 -480
- package/scripts/patches/auto-instrument/astro.cjs +0 -273
- package/scripts/patches/auto-instrument/express.cjs +0 -383
- package/scripts/patches/auto-instrument/fastify.cjs +0 -262
- package/scripts/patches/auto-instrument/hono.cjs +0 -392
- package/scripts/patches/auto-instrument/index.cjs +0 -80
- package/scripts/patches/auto-instrument/nestjs.cjs +0 -286
- package/scripts/patches/auto-instrument/nextjs-app-router.cjs +0 -345
- package/scripts/patches/auto-instrument/nextjs-pages.cjs +0 -361
- package/scripts/patches/auto-instrument/remix.cjs +0 -168
- package/scripts/patches/auto-instrument/sdk-helper-map.cjs +0 -241
- package/scripts/patches/auto-instrument/singleton-helper.cjs +0 -193
- package/scripts/patches/auto-instrument/sveltekit.cjs +0 -161
- package/scripts/patches/auto-instrument/vite-react.cjs +0 -37
- package/scripts/patches/auto-instrument/vue.cjs +0 -196
- package/scripts/patches/express.patch.cjs +0 -99
- package/scripts/patches/fastify.patch.cjs +0 -108
- package/scripts/patches/index.cjs +0 -300
- package/scripts/patches/nestjs.patch.cjs +0 -112
- package/scripts/patches/nextjs-app-router.patch.cjs +0 -97
- package/scripts/patches/nextjs-pages.patch.cjs +0 -97
- package/scripts/patches/remix.patch.cjs +0 -75
- package/scripts/patches/sveltekit.patch.cjs +0 -72
- package/scripts/patches/vite-react.patch.cjs +0 -73
- package/scripts/patches/vue.patch.cjs +0 -82
- package/scripts/renew-ssl.sh +0 -14
- package/scripts/resolve-migration.sh +0 -23
- package/scripts/seed-cli-dev-keys.mjs +0 -130
- package/scripts/seed-test-data.mjs +0 -391
- package/scripts/spike-browserless.ts +0 -65
- package/scripts/tenant-pivot-consistency-check.mjs +0 -205
- package/scripts/tenant-pivot-phase-3-cleanup.lib.cjs +0 -258
- package/scripts/tenant-pivot-phase-3-cleanup.mjs +0 -98
- package/scripts/test-identity-resolution.ts +0 -804
- 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 };
|
package/scripts/renew-ssl.sh
DELETED
|
@@ -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());
|