@supatype/cli 0.1.0-alpha.6
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/.turbo/turbo-build.log +4 -0
- package/.turbo/turbo-test.log +7 -0
- package/.turbo/turbo-typecheck.log +4 -0
- package/bin/dev-entry.ts +2 -0
- package/bin/supatype.js +5 -0
- package/dist/app/framework.d.ts +44 -0
- package/dist/app/framework.d.ts.map +1 -0
- package/dist/app/framework.js +200 -0
- package/dist/app/framework.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +55 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/admin.d.ts +4 -0
- package/dist/commands/admin.d.ts.map +1 -0
- package/dist/commands/admin.js +270 -0
- package/dist/commands/admin.js.map +1 -0
- package/dist/commands/app.d.ts +3 -0
- package/dist/commands/app.d.ts.map +1 -0
- package/dist/commands/app.js +235 -0
- package/dist/commands/app.js.map +1 -0
- package/dist/commands/cloud.d.ts +3 -0
- package/dist/commands/cloud.d.ts.map +1 -0
- package/dist/commands/cloud.js +256 -0
- package/dist/commands/cloud.js.map +1 -0
- package/dist/commands/db.d.ts +8 -0
- package/dist/commands/db.d.ts.map +1 -0
- package/dist/commands/db.js +123 -0
- package/dist/commands/db.js.map +1 -0
- package/dist/commands/deploy-types.d.ts +14 -0
- package/dist/commands/deploy-types.d.ts.map +1 -0
- package/dist/commands/deploy-types.js +38 -0
- package/dist/commands/deploy-types.js.map +1 -0
- package/dist/commands/deploy.d.ts +14 -0
- package/dist/commands/deploy.d.ts.map +1 -0
- package/dist/commands/deploy.js +295 -0
- package/dist/commands/deploy.js.map +1 -0
- package/dist/commands/dev.d.ts +3 -0
- package/dist/commands/dev.d.ts.map +1 -0
- package/dist/commands/dev.js +428 -0
- package/dist/commands/dev.js.map +1 -0
- package/dist/commands/diff.d.ts +3 -0
- package/dist/commands/diff.d.ts.map +1 -0
- package/dist/commands/diff.js +39 -0
- package/dist/commands/diff.js.map +1 -0
- package/dist/commands/engine.d.ts +9 -0
- package/dist/commands/engine.d.ts.map +1 -0
- package/dist/commands/engine.js +99 -0
- package/dist/commands/engine.js.map +1 -0
- package/dist/commands/functions.d.ts +3 -0
- package/dist/commands/functions.d.ts.map +1 -0
- package/dist/commands/functions.js +762 -0
- package/dist/commands/functions.js.map +1 -0
- package/dist/commands/generate.d.ts +3 -0
- package/dist/commands/generate.d.ts.map +1 -0
- package/dist/commands/generate.js +28 -0
- package/dist/commands/generate.js.map +1 -0
- package/dist/commands/init.d.ts +7 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +515 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/keys.d.ts +4 -0
- package/dist/commands/keys.d.ts.map +1 -0
- package/dist/commands/keys.js +57 -0
- package/dist/commands/keys.js.map +1 -0
- package/dist/commands/logs.d.ts +6 -0
- package/dist/commands/logs.d.ts.map +1 -0
- package/dist/commands/logs.js +52 -0
- package/dist/commands/logs.js.map +1 -0
- package/dist/commands/migrate.d.ts +3 -0
- package/dist/commands/migrate.d.ts.map +1 -0
- package/dist/commands/migrate.js +71 -0
- package/dist/commands/migrate.js.map +1 -0
- package/dist/commands/plugins.d.ts +3 -0
- package/dist/commands/plugins.d.ts.map +1 -0
- package/dist/commands/plugins.js +431 -0
- package/dist/commands/plugins.js.map +1 -0
- package/dist/commands/pull.d.ts +3 -0
- package/dist/commands/pull.d.ts.map +1 -0
- package/dist/commands/pull.js +73 -0
- package/dist/commands/pull.js.map +1 -0
- package/dist/commands/push.d.ts +3 -0
- package/dist/commands/push.d.ts.map +1 -0
- package/dist/commands/push.js +87 -0
- package/dist/commands/push.js.map +1 -0
- package/dist/commands/seed.d.ts +3 -0
- package/dist/commands/seed.d.ts.map +1 -0
- package/dist/commands/seed.js +22 -0
- package/dist/commands/seed.js.map +1 -0
- package/dist/commands/self-host.d.ts +3 -0
- package/dist/commands/self-host.d.ts.map +1 -0
- package/dist/commands/self-host.js +796 -0
- package/dist/commands/self-host.js.map +1 -0
- package/dist/commands/status.d.ts +6 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +69 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/config.d.ts +106 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +66 -0
- package/dist/config.js.map +1 -0
- package/dist/engine/cache.d.ts +37 -0
- package/dist/engine/cache.d.ts.map +1 -0
- package/dist/engine/cache.js +121 -0
- package/dist/engine/cache.js.map +1 -0
- package/dist/engine/download.d.ts +19 -0
- package/dist/engine/download.d.ts.map +1 -0
- package/dist/engine/download.js +108 -0
- package/dist/engine/download.js.map +1 -0
- package/dist/engine/platform.d.ts +24 -0
- package/dist/engine/platform.d.ts.map +1 -0
- package/dist/engine/platform.js +50 -0
- package/dist/engine/platform.js.map +1 -0
- package/dist/engine/resolve.d.ts +37 -0
- package/dist/engine/resolve.d.ts.map +1 -0
- package/dist/engine/resolve.js +133 -0
- package/dist/engine/resolve.js.map +1 -0
- package/dist/engine/update-notify.d.ts +11 -0
- package/dist/engine/update-notify.d.ts.map +1 -0
- package/dist/engine/update-notify.js +43 -0
- package/dist/engine/update-notify.js.map +1 -0
- package/dist/engine/verify.d.ts +50 -0
- package/dist/engine/verify.d.ts.map +1 -0
- package/dist/engine/verify.js +161 -0
- package/dist/engine/verify.js.map +1 -0
- package/dist/engine-version.d.ts +35 -0
- package/dist/engine-version.d.ts.map +1 -0
- package/dist/engine-version.js +35 -0
- package/dist/engine-version.js.map +1 -0
- package/dist/engine.d.ts +34 -0
- package/dist/engine.d.ts.map +1 -0
- package/dist/engine.js +76 -0
- package/dist/engine.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/jwt.d.ts +3 -0
- package/dist/jwt.d.ts.map +1 -0
- package/dist/jwt.js +13 -0
- package/dist/jwt.js.map +1 -0
- package/dist/pull-utils.d.ts +16 -0
- package/dist/pull-utils.d.ts.map +1 -0
- package/dist/pull-utils.js +65 -0
- package/dist/pull-utils.js.map +1 -0
- package/dist/scripts/postinstall.d.ts +12 -0
- package/dist/scripts/postinstall.d.ts.map +1 -0
- package/dist/scripts/postinstall.js +31 -0
- package/dist/scripts/postinstall.js.map +1 -0
- package/dist/tsx-runner.d.ts +18 -0
- package/dist/tsx-runner.d.ts.map +1 -0
- package/dist/tsx-runner.js +62 -0
- package/dist/tsx-runner.js.map +1 -0
- package/package.json +36 -0
- package/src/app/framework.ts +249 -0
- package/src/cli.ts +58 -0
- package/src/commands/admin.ts +371 -0
- package/src/commands/app.ts +261 -0
- package/src/commands/cloud.ts +326 -0
- package/src/commands/db.ts +145 -0
- package/src/commands/deploy-types.ts +49 -0
- package/src/commands/deploy.ts +366 -0
- package/src/commands/dev.ts +477 -0
- package/src/commands/diff.ts +61 -0
- package/src/commands/engine.ts +133 -0
- package/src/commands/functions.ts +919 -0
- package/src/commands/generate.ts +31 -0
- package/src/commands/init.ts +532 -0
- package/src/commands/keys.ts +66 -0
- package/src/commands/logs.ts +58 -0
- package/src/commands/migrate.ts +83 -0
- package/src/commands/plugins.ts +508 -0
- package/src/commands/pull.ts +96 -0
- package/src/commands/push.ts +119 -0
- package/src/commands/seed.ts +26 -0
- package/src/commands/self-host.ts +932 -0
- package/src/commands/status.ts +83 -0
- package/src/config.ts +190 -0
- package/src/engine/cache.ts +135 -0
- package/src/engine/download.ts +143 -0
- package/src/engine/platform.ts +66 -0
- package/src/engine/resolve.ts +197 -0
- package/src/engine/update-notify.ts +50 -0
- package/src/engine/verify.ts +206 -0
- package/src/engine-version.ts +39 -0
- package/src/engine.ts +99 -0
- package/src/index.ts +19 -0
- package/src/jwt.ts +14 -0
- package/src/pull-utils.ts +57 -0
- package/src/scripts/postinstall.ts +40 -0
- package/src/tsx-runner.ts +79 -0
- package/tests/cli-help.test.ts +107 -0
- package/tests/config.test.ts +117 -0
- package/tests/engine-distribution.test.ts +418 -0
- package/tests/init.test.ts +184 -0
- package/tests/keys.test.ts +160 -0
- package/tests/pull-utils.test.ts +115 -0
- package/tests/tsx-runner.test.ts +66 -0
- package/tsconfig.json +10 -0
- package/tsconfig.tsbuildinfo +1 -0
package/bin/dev-entry.ts
ADDED
package/bin/supatype.js
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Framework auto-detection and build configuration.
|
|
3
|
+
* Inspects package.json to determine the framework, then resolves
|
|
4
|
+
* build command, output directory, and SPA mode defaults.
|
|
5
|
+
*/
|
|
6
|
+
import type { AppConfig, AppFramework } from "../config.js";
|
|
7
|
+
export interface ResolvedAppConfig {
|
|
8
|
+
framework: AppFramework;
|
|
9
|
+
directory: string;
|
|
10
|
+
buildCommand: string;
|
|
11
|
+
outputDirectory: string;
|
|
12
|
+
spa: boolean;
|
|
13
|
+
env: Record<string, string>;
|
|
14
|
+
headers: Record<string, string>;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Detect the framework from package.json dependencies.
|
|
18
|
+
*/
|
|
19
|
+
export declare function detectFramework(appDir: string): AppFramework | undefined;
|
|
20
|
+
/**
|
|
21
|
+
* Detect if the project is a monorepo.
|
|
22
|
+
*/
|
|
23
|
+
export declare function detectMonorepo(cwd: string): {
|
|
24
|
+
isMonorepo: boolean;
|
|
25
|
+
tool?: string;
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Detect package manager from lockfiles.
|
|
29
|
+
*/
|
|
30
|
+
export declare function detectPackageManager(dir: string): "npm" | "pnpm" | "yarn";
|
|
31
|
+
/**
|
|
32
|
+
* Resolve the full app configuration from user config + auto-detection.
|
|
33
|
+
*/
|
|
34
|
+
export declare function resolveAppConfig(appConfig: AppConfig | undefined, cwd: string): ResolvedAppConfig;
|
|
35
|
+
/**
|
|
36
|
+
* Validate that the framework is configured for static output.
|
|
37
|
+
* Returns an error message if SSR mode is detected.
|
|
38
|
+
*/
|
|
39
|
+
export declare function validateStaticMode(framework: AppFramework, appDir: string): string | null;
|
|
40
|
+
/**
|
|
41
|
+
* Validate the build output.
|
|
42
|
+
*/
|
|
43
|
+
export declare function validateBuildOutput(outputDir: string, maxSizeMb: number): string | null;
|
|
44
|
+
//# sourceMappingURL=framework.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"framework.d.ts","sourceRoot":"","sources":["../../src/app/framework.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAE3D,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,YAAY,CAAA;IACvB,SAAS,EAAE,MAAM,CAAA;IACjB,YAAY,EAAE,MAAM,CAAA;IACpB,eAAe,EAAE,MAAM,CAAA;IACvB,GAAG,EAAE,OAAO,CAAA;IACZ,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC3B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAChC;AA6BD;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS,CAmBxE;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG;IAAE,UAAU,EAAE,OAAO,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAKlF;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,CAIzE;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,SAAS,EAAE,SAAS,GAAG,SAAS,EAChC,GAAG,EAAE,MAAM,GACV,iBAAiB,CAwCnB;AASD;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAgDzF;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAwBvF"}
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Framework auto-detection and build configuration.
|
|
3
|
+
* Inspects package.json to determine the framework, then resolves
|
|
4
|
+
* build command, output directory, and SPA mode defaults.
|
|
5
|
+
*/
|
|
6
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
7
|
+
import { join, resolve } from "node:path";
|
|
8
|
+
const FRAMEWORK_DEFAULTS = {
|
|
9
|
+
nextjs: { buildCommand: "next build", outputDirectory: "out", spa: false },
|
|
10
|
+
astro: { buildCommand: "astro build", outputDirectory: "dist", spa: false },
|
|
11
|
+
vite: { buildCommand: "vite build", outputDirectory: "dist", spa: true },
|
|
12
|
+
"remix-spa": { buildCommand: "remix vite:build", outputDirectory: "build/client", spa: true },
|
|
13
|
+
sveltekit: { buildCommand: "vite build", outputDirectory: "build", spa: false },
|
|
14
|
+
nuxt: { buildCommand: "nuxt generate", outputDirectory: "dist", spa: false },
|
|
15
|
+
static: { buildCommand: "", outputDirectory: ".", spa: false },
|
|
16
|
+
};
|
|
17
|
+
// Maps package.json dependency names to framework identifiers
|
|
18
|
+
const FRAMEWORK_DETECTION = [
|
|
19
|
+
{ dep: "next", framework: "nextjs" },
|
|
20
|
+
{ dep: "astro", framework: "astro" },
|
|
21
|
+
{ dep: "@remix-run/react", framework: "remix-spa" },
|
|
22
|
+
{ dep: "@sveltejs/kit", framework: "sveltekit" },
|
|
23
|
+
{ dep: "nuxt", framework: "nuxt" },
|
|
24
|
+
// Vite last — many frameworks use Vite under the hood
|
|
25
|
+
{ dep: "vite", framework: "vite" },
|
|
26
|
+
];
|
|
27
|
+
/**
|
|
28
|
+
* Detect the framework from package.json dependencies.
|
|
29
|
+
*/
|
|
30
|
+
export function detectFramework(appDir) {
|
|
31
|
+
const pkgPath = join(appDir, "package.json");
|
|
32
|
+
if (!existsSync(pkgPath))
|
|
33
|
+
return undefined;
|
|
34
|
+
const pkg = JSON.parse(readFileSync(pkgPath, "utf8"));
|
|
35
|
+
const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
36
|
+
for (const { dep, framework } of FRAMEWORK_DETECTION) {
|
|
37
|
+
if (dep in allDeps)
|
|
38
|
+
return framework;
|
|
39
|
+
}
|
|
40
|
+
// Check for plain HTML
|
|
41
|
+
if (existsSync(join(appDir, "index.html")))
|
|
42
|
+
return "static";
|
|
43
|
+
return undefined;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Detect if the project is a monorepo.
|
|
47
|
+
*/
|
|
48
|
+
export function detectMonorepo(cwd) {
|
|
49
|
+
if (existsSync(join(cwd, "turbo.json")))
|
|
50
|
+
return { isMonorepo: true, tool: "turbo" };
|
|
51
|
+
if (existsSync(join(cwd, "pnpm-workspace.yaml")))
|
|
52
|
+
return { isMonorepo: true, tool: "pnpm" };
|
|
53
|
+
if (existsSync(join(cwd, "nx.json")))
|
|
54
|
+
return { isMonorepo: true, tool: "nx" };
|
|
55
|
+
return { isMonorepo: false };
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Detect package manager from lockfiles.
|
|
59
|
+
*/
|
|
60
|
+
export function detectPackageManager(dir) {
|
|
61
|
+
if (existsSync(join(dir, "pnpm-lock.yaml")))
|
|
62
|
+
return "pnpm";
|
|
63
|
+
if (existsSync(join(dir, "yarn.lock")))
|
|
64
|
+
return "yarn";
|
|
65
|
+
return "npm";
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Resolve the full app configuration from user config + auto-detection.
|
|
69
|
+
*/
|
|
70
|
+
export function resolveAppConfig(appConfig, cwd) {
|
|
71
|
+
const directory = resolve(cwd, appConfig?.directory || ".");
|
|
72
|
+
// Framework detection
|
|
73
|
+
let framework = appConfig?.framework;
|
|
74
|
+
if (!framework) {
|
|
75
|
+
framework = detectFramework(directory);
|
|
76
|
+
if (!framework) {
|
|
77
|
+
throw new Error("Could not detect frontend framework.\n" +
|
|
78
|
+
"Set app.framework in supatype.config.ts, or ensure package.json is present.");
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
const defaults = FRAMEWORK_DEFAULTS[framework];
|
|
82
|
+
// Build command
|
|
83
|
+
let buildCommand = appConfig?.buildCommand || defaults.buildCommand;
|
|
84
|
+
const mono = detectMonorepo(cwd);
|
|
85
|
+
if (mono.isMonorepo && mono.tool === "turbo" && !appConfig?.buildCommand) {
|
|
86
|
+
// In a Turborepo, run build via turbo from workspace root
|
|
87
|
+
const appDirRelative = appConfig?.directory || ".";
|
|
88
|
+
if (appDirRelative !== ".") {
|
|
89
|
+
const pkgName = getPackageName(directory);
|
|
90
|
+
if (pkgName) {
|
|
91
|
+
buildCommand = `turbo run build --filter=${pkgName}`;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return {
|
|
96
|
+
framework,
|
|
97
|
+
directory,
|
|
98
|
+
buildCommand,
|
|
99
|
+
outputDirectory: resolve(directory, appConfig?.outputDirectory || defaults.outputDirectory),
|
|
100
|
+
spa: appConfig?.spa ?? defaults.spa,
|
|
101
|
+
env: appConfig?.env ?? {},
|
|
102
|
+
headers: appConfig?.headers ?? {},
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
function getPackageName(dir) {
|
|
106
|
+
const pkgPath = join(dir, "package.json");
|
|
107
|
+
if (!existsSync(pkgPath))
|
|
108
|
+
return undefined;
|
|
109
|
+
const pkg = JSON.parse(readFileSync(pkgPath, "utf8"));
|
|
110
|
+
return pkg.name;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Validate that the framework is configured for static output.
|
|
114
|
+
* Returns an error message if SSR mode is detected.
|
|
115
|
+
*/
|
|
116
|
+
export function validateStaticMode(framework, appDir) {
|
|
117
|
+
if (framework === "nextjs") {
|
|
118
|
+
// Check for output: 'export' in next.config.js/mjs/ts
|
|
119
|
+
for (const name of ["next.config.js", "next.config.mjs", "next.config.ts"]) {
|
|
120
|
+
const configPath = join(appDir, name);
|
|
121
|
+
if (existsSync(configPath)) {
|
|
122
|
+
const content = readFileSync(configPath, "utf8");
|
|
123
|
+
if (!content.includes("export")) {
|
|
124
|
+
return ("Supatype currently supports Next.js static export only.\n" +
|
|
125
|
+
"Add `output: 'export'` to your next.config.js,\n" +
|
|
126
|
+
"or deploy your frontend to Vercel for SSR support.");
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
if (framework === "astro") {
|
|
132
|
+
const configPath = join(appDir, "astro.config.mjs");
|
|
133
|
+
if (existsSync(configPath)) {
|
|
134
|
+
const content = readFileSync(configPath, "utf8");
|
|
135
|
+
if (content.includes("output: 'server'") || content.includes("output: \"server\"")) {
|
|
136
|
+
return ("Supatype currently supports Astro static sites only.\n" +
|
|
137
|
+
"Remove `output: 'server'` from astro.config.mjs,\n" +
|
|
138
|
+
"or deploy your frontend separately for SSR support.");
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
if (framework === "sveltekit") {
|
|
143
|
+
const pkgPath = join(appDir, "package.json");
|
|
144
|
+
if (existsSync(pkgPath)) {
|
|
145
|
+
const pkg = JSON.parse(readFileSync(pkgPath, "utf8"));
|
|
146
|
+
if (!pkg.devDependencies?.["@sveltejs/adapter-static"]) {
|
|
147
|
+
return ("Supatype requires @sveltejs/adapter-static for SvelteKit.\n" +
|
|
148
|
+
"Install it: npm install -D @sveltejs/adapter-static");
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return null;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Validate the build output.
|
|
156
|
+
*/
|
|
157
|
+
export function validateBuildOutput(outputDir, maxSizeMb) {
|
|
158
|
+
if (!existsSync(outputDir)) {
|
|
159
|
+
return `Build output directory not found: ${outputDir}`;
|
|
160
|
+
}
|
|
161
|
+
// Check for at least one HTML file
|
|
162
|
+
const hasHtml = findHtmlFile(outputDir);
|
|
163
|
+
if (!hasHtml) {
|
|
164
|
+
return `No HTML files found in build output: ${outputDir}`;
|
|
165
|
+
}
|
|
166
|
+
// Check total size
|
|
167
|
+
const sizeMb = getDirSizeMb(outputDir);
|
|
168
|
+
if (sizeMb > maxSizeMb) {
|
|
169
|
+
return `Build output ${sizeMb.toFixed(1)}MB exceeds limit of ${maxSizeMb}MB`;
|
|
170
|
+
}
|
|
171
|
+
if (sizeMb > 500) {
|
|
172
|
+
console.warn(`Warning: Build output is ${sizeMb.toFixed(1)}MB. This may include unoptimised assets or node_modules.`);
|
|
173
|
+
}
|
|
174
|
+
return null;
|
|
175
|
+
}
|
|
176
|
+
function findHtmlFile(dir) {
|
|
177
|
+
const { readdirSync, statSync } = require("node:fs");
|
|
178
|
+
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
179
|
+
if (entry.isFile() && entry.name.endsWith(".html"))
|
|
180
|
+
return true;
|
|
181
|
+
if (entry.isDirectory()) {
|
|
182
|
+
if (findHtmlFile(join(dir, entry.name)))
|
|
183
|
+
return true;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
return false;
|
|
187
|
+
}
|
|
188
|
+
function getDirSizeMb(dir) {
|
|
189
|
+
const { readdirSync, statSync } = require("node:fs");
|
|
190
|
+
let size = 0;
|
|
191
|
+
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
192
|
+
const path = join(dir, entry.name);
|
|
193
|
+
if (entry.isFile())
|
|
194
|
+
size += statSync(path).size;
|
|
195
|
+
else if (entry.isDirectory())
|
|
196
|
+
size += getDirSizeMb(path) * 1024 * 1024;
|
|
197
|
+
}
|
|
198
|
+
return size / (1024 * 1024);
|
|
199
|
+
}
|
|
200
|
+
//# sourceMappingURL=framework.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"framework.js","sourceRoot":"","sources":["../../src/app/framework.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAwBA,wBAAgB,GAAG,IAAI,IAAI,CAiC1B"}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import { ENGINE_VERSION } from "./engine-version.js";
|
|
3
|
+
import { registerInit } from "./commands/init.js";
|
|
4
|
+
import { registerDev } from "./commands/dev.js";
|
|
5
|
+
import { registerPush } from "./commands/push.js";
|
|
6
|
+
import { registerDiff } from "./commands/diff.js";
|
|
7
|
+
import { registerPull } from "./commands/pull.js";
|
|
8
|
+
import { registerGenerate } from "./commands/generate.js";
|
|
9
|
+
import { registerMigrate } from "./commands/migrate.js";
|
|
10
|
+
import { registerSeed } from "./commands/seed.js";
|
|
11
|
+
import { registerKeys } from "./commands/keys.js";
|
|
12
|
+
import { registerApp } from "./commands/app.js";
|
|
13
|
+
import { registerSelfHost } from "./commands/self-host.js";
|
|
14
|
+
import { registerCloud } from "./commands/cloud.js";
|
|
15
|
+
import { registerEngine } from "./commands/engine.js";
|
|
16
|
+
import { registerDb } from "./commands/db.js";
|
|
17
|
+
import { registerDeploy } from "./commands/deploy.js";
|
|
18
|
+
import { registerStatus } from "./commands/status.js";
|
|
19
|
+
import { registerLogs } from "./commands/logs.js";
|
|
20
|
+
import { registerAdmin } from "./commands/admin.js";
|
|
21
|
+
import { registerFunctions } from "./commands/functions.js";
|
|
22
|
+
import { registerPlugins } from "./commands/plugins.js";
|
|
23
|
+
import { showUpdateNotification } from "./engine/update-notify.js";
|
|
24
|
+
export function run() {
|
|
25
|
+
const program = new Command()
|
|
26
|
+
.name("supatype")
|
|
27
|
+
.description("Supatype — schema-first Postgres API")
|
|
28
|
+
.version(ENGINE_VERSION);
|
|
29
|
+
registerInit(program);
|
|
30
|
+
registerDev(program);
|
|
31
|
+
registerPush(program);
|
|
32
|
+
registerDiff(program);
|
|
33
|
+
registerPull(program);
|
|
34
|
+
registerGenerate(program);
|
|
35
|
+
registerMigrate(program);
|
|
36
|
+
registerSeed(program);
|
|
37
|
+
registerKeys(program);
|
|
38
|
+
registerApp(program);
|
|
39
|
+
registerSelfHost(program);
|
|
40
|
+
registerCloud(program);
|
|
41
|
+
registerEngine(program);
|
|
42
|
+
registerDb(program);
|
|
43
|
+
registerDeploy(program);
|
|
44
|
+
registerStatus(program);
|
|
45
|
+
registerLogs(program);
|
|
46
|
+
registerAdmin(program);
|
|
47
|
+
registerFunctions(program);
|
|
48
|
+
registerPlugins(program);
|
|
49
|
+
// After command execution, show update notification (non-blocking)
|
|
50
|
+
program.hook("postAction", async () => {
|
|
51
|
+
await showUpdateNotification();
|
|
52
|
+
});
|
|
53
|
+
program.parse();
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAA;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAC/C,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAA;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAC7C,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AACrD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AACnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAA;AAC3D,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA;AACvD,OAAO,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAA;AAElE,MAAM,UAAU,GAAG;IACjB,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE;SAC1B,IAAI,CAAC,UAAU,CAAC;SAChB,WAAW,CAAC,sCAAsC,CAAC;SACnD,OAAO,CAAC,cAAc,CAAC,CAAA;IAE1B,YAAY,CAAC,OAAO,CAAC,CAAA;IACrB,WAAW,CAAC,OAAO,CAAC,CAAA;IACpB,YAAY,CAAC,OAAO,CAAC,CAAA;IACrB,YAAY,CAAC,OAAO,CAAC,CAAA;IACrB,YAAY,CAAC,OAAO,CAAC,CAAA;IACrB,gBAAgB,CAAC,OAAO,CAAC,CAAA;IACzB,eAAe,CAAC,OAAO,CAAC,CAAA;IACxB,YAAY,CAAC,OAAO,CAAC,CAAA;IACrB,YAAY,CAAC,OAAO,CAAC,CAAA;IACrB,WAAW,CAAC,OAAO,CAAC,CAAA;IACpB,gBAAgB,CAAC,OAAO,CAAC,CAAA;IACzB,aAAa,CAAC,OAAO,CAAC,CAAA;IACtB,cAAc,CAAC,OAAO,CAAC,CAAA;IACvB,UAAU,CAAC,OAAO,CAAC,CAAA;IACnB,cAAc,CAAC,OAAO,CAAC,CAAA;IACvB,cAAc,CAAC,OAAO,CAAC,CAAA;IACvB,YAAY,CAAC,OAAO,CAAC,CAAA;IACrB,aAAa,CAAC,OAAO,CAAC,CAAA;IACtB,iBAAiB,CAAC,OAAO,CAAC,CAAA;IAC1B,eAAe,CAAC,OAAO,CAAC,CAAA;IAExB,mEAAmE;IACnE,OAAO,CAAC,IAAI,CAAC,YAAY,EAAE,KAAK,IAAI,EAAE;QACpC,MAAM,sBAAsB,EAAE,CAAA;IAChC,CAAC,CAAC,CAAA;IAEF,OAAO,CAAC,KAAK,EAAE,CAAA;AACjB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"admin.d.ts","sourceRoot":"","sources":["../../src/commands/admin.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AASxC,wBAAgB,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAsOpD;AAKD,wBAAsB,oBAAoB,CACxC,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,IAAI,CAAC,CAkFf"}
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
// ─── Admin panel CLI commands (Gap Appendices task 48) ──────────────────────
|
|
2
|
+
//
|
|
3
|
+
// `npx supatype admin create-user` — create an admin user in the project's
|
|
4
|
+
// {ref}_auth.users table. Used for initial setup and ongoing admin management.
|
|
5
|
+
import { createInterface } from "node:readline";
|
|
6
|
+
import { randomBytes, scrypt } from "node:crypto";
|
|
7
|
+
import { promisify } from "node:util";
|
|
8
|
+
import { loadConfig } from "../config.js";
|
|
9
|
+
const scryptAsync = promisify(scrypt);
|
|
10
|
+
export function registerAdmin(program) {
|
|
11
|
+
const adminCmd = program
|
|
12
|
+
.command("admin")
|
|
13
|
+
.description("Manage admin panel users and configuration");
|
|
14
|
+
adminCmd
|
|
15
|
+
.command("create-user")
|
|
16
|
+
.description("Create an admin user for the admin panel")
|
|
17
|
+
.option("--email <email>", "Admin user email address")
|
|
18
|
+
.option("--password <password>", "Admin user password (prompted if not provided)")
|
|
19
|
+
.option("--role <role>", "Admin role to assign", "admin")
|
|
20
|
+
.option("--connection <url>", "Database connection URL (overrides config)")
|
|
21
|
+
.action(async (opts) => {
|
|
22
|
+
const cwd = process.cwd();
|
|
23
|
+
const config = loadConfig(cwd);
|
|
24
|
+
const connection = opts.connection ?? config.connection;
|
|
25
|
+
const email = opts.email ?? (await prompt("Admin email: "));
|
|
26
|
+
if (!email || !email.includes("@")) {
|
|
27
|
+
console.error("A valid email address is required.");
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
const password = opts.password ?? (await prompt("Admin password (min 8 chars): "));
|
|
31
|
+
if (!password || password.length < 8) {
|
|
32
|
+
console.error("Password must be at least 8 characters.");
|
|
33
|
+
process.exit(1);
|
|
34
|
+
}
|
|
35
|
+
const role = opts.role;
|
|
36
|
+
console.log(`\nCreating admin user: ${email} (role: ${role})...`);
|
|
37
|
+
// We use pg directly to insert into the auth.users table
|
|
38
|
+
const pg = await importPg();
|
|
39
|
+
const pool = new pg.Pool({ connectionString: connection, max: 2 });
|
|
40
|
+
try {
|
|
41
|
+
// Ensure the auth schema and users table exist
|
|
42
|
+
await pool.query(`
|
|
43
|
+
CREATE SCHEMA IF NOT EXISTS auth;
|
|
44
|
+
|
|
45
|
+
CREATE TABLE IF NOT EXISTS auth.users (
|
|
46
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
47
|
+
instance_id UUID,
|
|
48
|
+
aud TEXT DEFAULT 'authenticated',
|
|
49
|
+
role TEXT DEFAULT 'authenticated',
|
|
50
|
+
email TEXT UNIQUE,
|
|
51
|
+
encrypted_password TEXT,
|
|
52
|
+
email_confirmed_at TIMESTAMPTZ DEFAULT now(),
|
|
53
|
+
raw_app_meta_data JSONB DEFAULT '{}',
|
|
54
|
+
raw_user_meta_data JSONB DEFAULT '{}',
|
|
55
|
+
created_at TIMESTAMPTZ DEFAULT now(),
|
|
56
|
+
updated_at TIMESTAMPTZ DEFAULT now(),
|
|
57
|
+
confirmation_token TEXT DEFAULT '',
|
|
58
|
+
recovery_token TEXT DEFAULT '',
|
|
59
|
+
email_change_token_new TEXT DEFAULT '',
|
|
60
|
+
email_change TEXT DEFAULT ''
|
|
61
|
+
);
|
|
62
|
+
`);
|
|
63
|
+
// Check if user already exists
|
|
64
|
+
const existing = await pool.query(`SELECT id FROM auth.users WHERE email = $1`, [email.toLowerCase()]);
|
|
65
|
+
if (existing.rows.length > 0) {
|
|
66
|
+
console.error(`\nUser with email "${email}" already exists.`);
|
|
67
|
+
console.log(`To update their role, use: supatype admin set-role --email ${email} --role ${role}`);
|
|
68
|
+
process.exit(1);
|
|
69
|
+
}
|
|
70
|
+
// Hash the password (bcrypt-style for GoTrue compatibility)
|
|
71
|
+
const passwordHash = await hashPassword(password);
|
|
72
|
+
// Insert the admin user with the admin role in app_metadata
|
|
73
|
+
const appMetadata = JSON.stringify({ role, provider: "email", providers: ["email"] });
|
|
74
|
+
const userMetadata = JSON.stringify({});
|
|
75
|
+
const result = await pool.query(`INSERT INTO auth.users (
|
|
76
|
+
email, encrypted_password, role, aud,
|
|
77
|
+
raw_app_meta_data, raw_user_meta_data,
|
|
78
|
+
email_confirmed_at, created_at, updated_at
|
|
79
|
+
) VALUES (
|
|
80
|
+
$1, $2, 'authenticated', 'authenticated',
|
|
81
|
+
$3::jsonb, $4::jsonb,
|
|
82
|
+
now(), now(), now()
|
|
83
|
+
) RETURNING id, email`, [email.toLowerCase(), passwordHash, appMetadata, userMetadata]);
|
|
84
|
+
const user = result.rows[0];
|
|
85
|
+
console.log(`\nAdmin user created successfully.`);
|
|
86
|
+
console.log(` ID: ${user.id}`);
|
|
87
|
+
console.log(` Email: ${user.email}`);
|
|
88
|
+
console.log(` Role: ${role}`);
|
|
89
|
+
console.log(`\nThis user can now log in to the admin panel at /admin\n`);
|
|
90
|
+
}
|
|
91
|
+
catch (err) {
|
|
92
|
+
const message = err instanceof Error ? err.message : "Unknown error";
|
|
93
|
+
console.error(`\nFailed to create admin user: ${message}`);
|
|
94
|
+
process.exit(1);
|
|
95
|
+
}
|
|
96
|
+
finally {
|
|
97
|
+
await pool.end();
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
adminCmd
|
|
101
|
+
.command("set-role")
|
|
102
|
+
.description("Change an existing user's admin role")
|
|
103
|
+
.requiredOption("--email <email>", "User email address")
|
|
104
|
+
.requiredOption("--role <role>", "New role to assign")
|
|
105
|
+
.option("--connection <url>", "Database connection URL (overrides config)")
|
|
106
|
+
.action(async (opts) => {
|
|
107
|
+
const cwd = process.cwd();
|
|
108
|
+
const config = loadConfig(cwd);
|
|
109
|
+
const connection = opts.connection ?? config.connection;
|
|
110
|
+
const pg = await importPg();
|
|
111
|
+
const pool = new pg.Pool({ connectionString: connection, max: 2 });
|
|
112
|
+
try {
|
|
113
|
+
const result = await pool.query(`UPDATE auth.users
|
|
114
|
+
SET raw_app_meta_data = raw_app_meta_data || $1::jsonb,
|
|
115
|
+
updated_at = now()
|
|
116
|
+
WHERE email = $2
|
|
117
|
+
RETURNING id, email, raw_app_meta_data`, [JSON.stringify({ role: opts.role }), opts.email.toLowerCase()]);
|
|
118
|
+
if (result.rows.length === 0) {
|
|
119
|
+
console.error(`\nNo user found with email "${opts.email}".`);
|
|
120
|
+
process.exit(1);
|
|
121
|
+
}
|
|
122
|
+
const user = result.rows[0];
|
|
123
|
+
console.log(`\nRole updated successfully.`);
|
|
124
|
+
console.log(` ID: ${user.id}`);
|
|
125
|
+
console.log(` Email: ${user.email}`);
|
|
126
|
+
console.log(` Role: ${opts.role}\n`);
|
|
127
|
+
}
|
|
128
|
+
catch (err) {
|
|
129
|
+
const message = err instanceof Error ? err.message : "Unknown error";
|
|
130
|
+
console.error(`\nFailed to update role: ${message}`);
|
|
131
|
+
process.exit(1);
|
|
132
|
+
}
|
|
133
|
+
finally {
|
|
134
|
+
await pool.end();
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
adminCmd
|
|
138
|
+
.command("list-users")
|
|
139
|
+
.description("List users with admin roles")
|
|
140
|
+
.option("--connection <url>", "Database connection URL (overrides config)")
|
|
141
|
+
.action(async (opts) => {
|
|
142
|
+
const cwd = process.cwd();
|
|
143
|
+
const config = loadConfig(cwd);
|
|
144
|
+
const connection = opts.connection ?? config.connection;
|
|
145
|
+
const pg = await importPg();
|
|
146
|
+
const pool = new pg.Pool({ connectionString: connection, max: 2 });
|
|
147
|
+
try {
|
|
148
|
+
const result = await pool.query(`SELECT id, email, raw_app_meta_data->>'role' as role, created_at
|
|
149
|
+
FROM auth.users
|
|
150
|
+
WHERE raw_app_meta_data->>'role' IS NOT NULL
|
|
151
|
+
AND raw_app_meta_data->>'role' != 'authenticated'
|
|
152
|
+
ORDER BY created_at ASC`);
|
|
153
|
+
if (result.rows.length === 0) {
|
|
154
|
+
console.log("\nNo admin users found.");
|
|
155
|
+
console.log("Create one with: supatype admin create-user --email admin@example.com --role admin\n");
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
console.log("\n ID Email Role Created");
|
|
159
|
+
console.log(" " + "-".repeat(100));
|
|
160
|
+
for (const row of result.rows) {
|
|
161
|
+
const r = row;
|
|
162
|
+
const date = new Date(r.created_at).toISOString().slice(0, 10);
|
|
163
|
+
console.log(` ${r.id} ${r.email.padEnd(30)} ${r.role.padEnd(12)} ${date}`);
|
|
164
|
+
}
|
|
165
|
+
console.log();
|
|
166
|
+
}
|
|
167
|
+
catch (err) {
|
|
168
|
+
const message = err instanceof Error ? err.message : "Unknown error";
|
|
169
|
+
console.error(`\nFailed to list admin users: ${message}`);
|
|
170
|
+
process.exit(1);
|
|
171
|
+
}
|
|
172
|
+
finally {
|
|
173
|
+
await pool.end();
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
// ─── First admin user prompt (task 48) ──────────────────────────────────────
|
|
178
|
+
// Called by `supatype push` on initial setup if no admin users exist.
|
|
179
|
+
export async function promptFirstAdminUser(connection) {
|
|
180
|
+
const pg = await importPg();
|
|
181
|
+
const pool = new pg.Pool({ connectionString: connection, max: 2 });
|
|
182
|
+
try {
|
|
183
|
+
// Check if auth.users table exists
|
|
184
|
+
const tableExists = await pool.query(`SELECT EXISTS (
|
|
185
|
+
SELECT FROM information_schema.tables
|
|
186
|
+
WHERE table_schema = 'auth' AND table_name = 'users'
|
|
187
|
+
) as exists`);
|
|
188
|
+
if (!tableExists.rows[0]?.exists)
|
|
189
|
+
return;
|
|
190
|
+
// Check if any admin users exist
|
|
191
|
+
const adminCount = await pool.query(`SELECT COUNT(*) as count FROM auth.users
|
|
192
|
+
WHERE raw_app_meta_data->>'role' IS NOT NULL
|
|
193
|
+
AND raw_app_meta_data->>'role' != 'authenticated'`);
|
|
194
|
+
const count = parseInt(adminCount.rows[0].count, 10);
|
|
195
|
+
if (count > 0)
|
|
196
|
+
return;
|
|
197
|
+
// No admin users — prompt to create one
|
|
198
|
+
console.log("\n No admin users found for the admin panel.");
|
|
199
|
+
const createAdmin = await confirm(" Create an admin user now? [y/N] ");
|
|
200
|
+
if (!createAdmin) {
|
|
201
|
+
console.log(" Skipped. You can create one later with: supatype admin create-user\n");
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
const email = await prompt(" Admin email: ");
|
|
205
|
+
if (!email || !email.includes("@")) {
|
|
206
|
+
console.log(" Invalid email. Skipping admin user creation.\n");
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
const password = await prompt(" Admin password (min 8 chars): ");
|
|
210
|
+
if (!password || password.length < 8) {
|
|
211
|
+
console.log(" Password too short. Skipping admin user creation.\n");
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
const passwordHash = await hashPassword(password);
|
|
215
|
+
const appMetadata = JSON.stringify({
|
|
216
|
+
role: "admin",
|
|
217
|
+
provider: "email",
|
|
218
|
+
providers: ["email"],
|
|
219
|
+
});
|
|
220
|
+
await pool.query(`INSERT INTO auth.users (
|
|
221
|
+
email, encrypted_password, role, aud,
|
|
222
|
+
raw_app_meta_data, raw_user_meta_data,
|
|
223
|
+
email_confirmed_at, created_at, updated_at
|
|
224
|
+
) VALUES (
|
|
225
|
+
$1, $2, 'authenticated', 'authenticated',
|
|
226
|
+
$3::jsonb, '{}'::jsonb,
|
|
227
|
+
now(), now(), now()
|
|
228
|
+
)`, [email.toLowerCase(), passwordHash, appMetadata]);
|
|
229
|
+
console.log(`\n Admin user "${email}" created (role: admin).`);
|
|
230
|
+
console.log(` Log in at /admin after starting the dev server.\n`);
|
|
231
|
+
}
|
|
232
|
+
catch {
|
|
233
|
+
// Non-fatal — if auth schema doesn't exist yet, skip silently
|
|
234
|
+
}
|
|
235
|
+
finally {
|
|
236
|
+
await pool.end();
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
// ─── Helpers ────────────────────────────────────────────────────────────────────
|
|
240
|
+
async function importPg() {
|
|
241
|
+
try {
|
|
242
|
+
return await import("pg");
|
|
243
|
+
}
|
|
244
|
+
catch {
|
|
245
|
+
console.error("pg package is required for admin commands. Install it with: pnpm add pg");
|
|
246
|
+
process.exit(1);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
async function hashPassword(password) {
|
|
250
|
+
const salt = randomBytes(16).toString("hex");
|
|
251
|
+
const derived = (await scryptAsync(password, salt, 64));
|
|
252
|
+
return `${salt}:${derived.toString("hex")}`;
|
|
253
|
+
}
|
|
254
|
+
function prompt(question) {
|
|
255
|
+
const rl = createInterface({
|
|
256
|
+
input: process.stdin,
|
|
257
|
+
output: process.stdout,
|
|
258
|
+
});
|
|
259
|
+
return new Promise((resolve) => {
|
|
260
|
+
rl.question(question, (answer) => {
|
|
261
|
+
rl.close();
|
|
262
|
+
resolve(answer.trim());
|
|
263
|
+
});
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
async function confirm(question) {
|
|
267
|
+
const answer = await prompt(question);
|
|
268
|
+
return answer.toLowerCase() === "y";
|
|
269
|
+
}
|
|
270
|
+
//# sourceMappingURL=admin.js.map
|