@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.
Files changed (200) hide show
  1. package/.turbo/turbo-build.log +4 -0
  2. package/.turbo/turbo-test.log +7 -0
  3. package/.turbo/turbo-typecheck.log +4 -0
  4. package/bin/dev-entry.ts +2 -0
  5. package/bin/supatype.js +5 -0
  6. package/dist/app/framework.d.ts +44 -0
  7. package/dist/app/framework.d.ts.map +1 -0
  8. package/dist/app/framework.js +200 -0
  9. package/dist/app/framework.js.map +1 -0
  10. package/dist/cli.d.ts +2 -0
  11. package/dist/cli.d.ts.map +1 -0
  12. package/dist/cli.js +55 -0
  13. package/dist/cli.js.map +1 -0
  14. package/dist/commands/admin.d.ts +4 -0
  15. package/dist/commands/admin.d.ts.map +1 -0
  16. package/dist/commands/admin.js +270 -0
  17. package/dist/commands/admin.js.map +1 -0
  18. package/dist/commands/app.d.ts +3 -0
  19. package/dist/commands/app.d.ts.map +1 -0
  20. package/dist/commands/app.js +235 -0
  21. package/dist/commands/app.js.map +1 -0
  22. package/dist/commands/cloud.d.ts +3 -0
  23. package/dist/commands/cloud.d.ts.map +1 -0
  24. package/dist/commands/cloud.js +256 -0
  25. package/dist/commands/cloud.js.map +1 -0
  26. package/dist/commands/db.d.ts +8 -0
  27. package/dist/commands/db.d.ts.map +1 -0
  28. package/dist/commands/db.js +123 -0
  29. package/dist/commands/db.js.map +1 -0
  30. package/dist/commands/deploy-types.d.ts +14 -0
  31. package/dist/commands/deploy-types.d.ts.map +1 -0
  32. package/dist/commands/deploy-types.js +38 -0
  33. package/dist/commands/deploy-types.js.map +1 -0
  34. package/dist/commands/deploy.d.ts +14 -0
  35. package/dist/commands/deploy.d.ts.map +1 -0
  36. package/dist/commands/deploy.js +295 -0
  37. package/dist/commands/deploy.js.map +1 -0
  38. package/dist/commands/dev.d.ts +3 -0
  39. package/dist/commands/dev.d.ts.map +1 -0
  40. package/dist/commands/dev.js +428 -0
  41. package/dist/commands/dev.js.map +1 -0
  42. package/dist/commands/diff.d.ts +3 -0
  43. package/dist/commands/diff.d.ts.map +1 -0
  44. package/dist/commands/diff.js +39 -0
  45. package/dist/commands/diff.js.map +1 -0
  46. package/dist/commands/engine.d.ts +9 -0
  47. package/dist/commands/engine.d.ts.map +1 -0
  48. package/dist/commands/engine.js +99 -0
  49. package/dist/commands/engine.js.map +1 -0
  50. package/dist/commands/functions.d.ts +3 -0
  51. package/dist/commands/functions.d.ts.map +1 -0
  52. package/dist/commands/functions.js +762 -0
  53. package/dist/commands/functions.js.map +1 -0
  54. package/dist/commands/generate.d.ts +3 -0
  55. package/dist/commands/generate.d.ts.map +1 -0
  56. package/dist/commands/generate.js +28 -0
  57. package/dist/commands/generate.js.map +1 -0
  58. package/dist/commands/init.d.ts +7 -0
  59. package/dist/commands/init.d.ts.map +1 -0
  60. package/dist/commands/init.js +515 -0
  61. package/dist/commands/init.js.map +1 -0
  62. package/dist/commands/keys.d.ts +4 -0
  63. package/dist/commands/keys.d.ts.map +1 -0
  64. package/dist/commands/keys.js +57 -0
  65. package/dist/commands/keys.js.map +1 -0
  66. package/dist/commands/logs.d.ts +6 -0
  67. package/dist/commands/logs.d.ts.map +1 -0
  68. package/dist/commands/logs.js +52 -0
  69. package/dist/commands/logs.js.map +1 -0
  70. package/dist/commands/migrate.d.ts +3 -0
  71. package/dist/commands/migrate.d.ts.map +1 -0
  72. package/dist/commands/migrate.js +71 -0
  73. package/dist/commands/migrate.js.map +1 -0
  74. package/dist/commands/plugins.d.ts +3 -0
  75. package/dist/commands/plugins.d.ts.map +1 -0
  76. package/dist/commands/plugins.js +431 -0
  77. package/dist/commands/plugins.js.map +1 -0
  78. package/dist/commands/pull.d.ts +3 -0
  79. package/dist/commands/pull.d.ts.map +1 -0
  80. package/dist/commands/pull.js +73 -0
  81. package/dist/commands/pull.js.map +1 -0
  82. package/dist/commands/push.d.ts +3 -0
  83. package/dist/commands/push.d.ts.map +1 -0
  84. package/dist/commands/push.js +87 -0
  85. package/dist/commands/push.js.map +1 -0
  86. package/dist/commands/seed.d.ts +3 -0
  87. package/dist/commands/seed.d.ts.map +1 -0
  88. package/dist/commands/seed.js +22 -0
  89. package/dist/commands/seed.js.map +1 -0
  90. package/dist/commands/self-host.d.ts +3 -0
  91. package/dist/commands/self-host.d.ts.map +1 -0
  92. package/dist/commands/self-host.js +796 -0
  93. package/dist/commands/self-host.js.map +1 -0
  94. package/dist/commands/status.d.ts +6 -0
  95. package/dist/commands/status.d.ts.map +1 -0
  96. package/dist/commands/status.js +69 -0
  97. package/dist/commands/status.js.map +1 -0
  98. package/dist/config.d.ts +106 -0
  99. package/dist/config.d.ts.map +1 -0
  100. package/dist/config.js +66 -0
  101. package/dist/config.js.map +1 -0
  102. package/dist/engine/cache.d.ts +37 -0
  103. package/dist/engine/cache.d.ts.map +1 -0
  104. package/dist/engine/cache.js +121 -0
  105. package/dist/engine/cache.js.map +1 -0
  106. package/dist/engine/download.d.ts +19 -0
  107. package/dist/engine/download.d.ts.map +1 -0
  108. package/dist/engine/download.js +108 -0
  109. package/dist/engine/download.js.map +1 -0
  110. package/dist/engine/platform.d.ts +24 -0
  111. package/dist/engine/platform.d.ts.map +1 -0
  112. package/dist/engine/platform.js +50 -0
  113. package/dist/engine/platform.js.map +1 -0
  114. package/dist/engine/resolve.d.ts +37 -0
  115. package/dist/engine/resolve.d.ts.map +1 -0
  116. package/dist/engine/resolve.js +133 -0
  117. package/dist/engine/resolve.js.map +1 -0
  118. package/dist/engine/update-notify.d.ts +11 -0
  119. package/dist/engine/update-notify.d.ts.map +1 -0
  120. package/dist/engine/update-notify.js +43 -0
  121. package/dist/engine/update-notify.js.map +1 -0
  122. package/dist/engine/verify.d.ts +50 -0
  123. package/dist/engine/verify.d.ts.map +1 -0
  124. package/dist/engine/verify.js +161 -0
  125. package/dist/engine/verify.js.map +1 -0
  126. package/dist/engine-version.d.ts +35 -0
  127. package/dist/engine-version.d.ts.map +1 -0
  128. package/dist/engine-version.js +35 -0
  129. package/dist/engine-version.js.map +1 -0
  130. package/dist/engine.d.ts +34 -0
  131. package/dist/engine.d.ts.map +1 -0
  132. package/dist/engine.js +76 -0
  133. package/dist/engine.js.map +1 -0
  134. package/dist/index.d.ts +12 -0
  135. package/dist/index.d.ts.map +1 -0
  136. package/dist/index.js +10 -0
  137. package/dist/index.js.map +1 -0
  138. package/dist/jwt.d.ts +3 -0
  139. package/dist/jwt.d.ts.map +1 -0
  140. package/dist/jwt.js +13 -0
  141. package/dist/jwt.js.map +1 -0
  142. package/dist/pull-utils.d.ts +16 -0
  143. package/dist/pull-utils.d.ts.map +1 -0
  144. package/dist/pull-utils.js +65 -0
  145. package/dist/pull-utils.js.map +1 -0
  146. package/dist/scripts/postinstall.d.ts +12 -0
  147. package/dist/scripts/postinstall.d.ts.map +1 -0
  148. package/dist/scripts/postinstall.js +31 -0
  149. package/dist/scripts/postinstall.js.map +1 -0
  150. package/dist/tsx-runner.d.ts +18 -0
  151. package/dist/tsx-runner.d.ts.map +1 -0
  152. package/dist/tsx-runner.js +62 -0
  153. package/dist/tsx-runner.js.map +1 -0
  154. package/package.json +36 -0
  155. package/src/app/framework.ts +249 -0
  156. package/src/cli.ts +58 -0
  157. package/src/commands/admin.ts +371 -0
  158. package/src/commands/app.ts +261 -0
  159. package/src/commands/cloud.ts +326 -0
  160. package/src/commands/db.ts +145 -0
  161. package/src/commands/deploy-types.ts +49 -0
  162. package/src/commands/deploy.ts +366 -0
  163. package/src/commands/dev.ts +477 -0
  164. package/src/commands/diff.ts +61 -0
  165. package/src/commands/engine.ts +133 -0
  166. package/src/commands/functions.ts +919 -0
  167. package/src/commands/generate.ts +31 -0
  168. package/src/commands/init.ts +532 -0
  169. package/src/commands/keys.ts +66 -0
  170. package/src/commands/logs.ts +58 -0
  171. package/src/commands/migrate.ts +83 -0
  172. package/src/commands/plugins.ts +508 -0
  173. package/src/commands/pull.ts +96 -0
  174. package/src/commands/push.ts +119 -0
  175. package/src/commands/seed.ts +26 -0
  176. package/src/commands/self-host.ts +932 -0
  177. package/src/commands/status.ts +83 -0
  178. package/src/config.ts +190 -0
  179. package/src/engine/cache.ts +135 -0
  180. package/src/engine/download.ts +143 -0
  181. package/src/engine/platform.ts +66 -0
  182. package/src/engine/resolve.ts +197 -0
  183. package/src/engine/update-notify.ts +50 -0
  184. package/src/engine/verify.ts +206 -0
  185. package/src/engine-version.ts +39 -0
  186. package/src/engine.ts +99 -0
  187. package/src/index.ts +19 -0
  188. package/src/jwt.ts +14 -0
  189. package/src/pull-utils.ts +57 -0
  190. package/src/scripts/postinstall.ts +40 -0
  191. package/src/tsx-runner.ts +79 -0
  192. package/tests/cli-help.test.ts +107 -0
  193. package/tests/config.test.ts +117 -0
  194. package/tests/engine-distribution.test.ts +418 -0
  195. package/tests/init.test.ts +184 -0
  196. package/tests/keys.test.ts +160 -0
  197. package/tests/pull-utils.test.ts +115 -0
  198. package/tests/tsx-runner.test.ts +66 -0
  199. package/tsconfig.json +10 -0
  200. package/tsconfig.tsbuildinfo +1 -0
@@ -0,0 +1,57 @@
1
+ import { readFileSync, existsSync } from "node:fs";
2
+ import { resolve } from "node:path";
3
+ import { signJwt } from "../jwt.js";
4
+ export function registerKeys(program) {
5
+ program
6
+ .command("keys")
7
+ .description("Generate ANON_KEY and SERVICE_ROLE_KEY JWTs from your JWT_SECRET")
8
+ .option("--secret <secret>", "JWT secret (defaults to JWT_SECRET env var or value in .env)")
9
+ .option("--exp-years <years>", "Token expiry in years (default: 10)", "10")
10
+ .action((opts) => {
11
+ const secret = opts.secret ?? resolveSecret();
12
+ if (!secret) {
13
+ console.error("Error: JWT_SECRET not found. Set it in .env or pass --secret <value>");
14
+ process.exit(1);
15
+ }
16
+ const expYears = parseInt(opts.expYears, 10);
17
+ if (isNaN(expYears) || expYears < 1) {
18
+ console.error("Error: --exp-years must be a positive integer");
19
+ process.exit(1);
20
+ }
21
+ const now = Math.floor(Date.now() / 1000);
22
+ const exp = now + expYears * 365 * 24 * 60 * 60;
23
+ const anonKey = signJwt({ iss: "supatype", role: "anon", iat: now, exp }, secret);
24
+ const serviceKey = signJwt({ iss: "supatype", role: "service_role", iat: now, exp }, secret);
25
+ console.log("\nGenerated keys (valid for", expYears, "years):\n");
26
+ console.log("ANON_KEY=" + anonKey);
27
+ console.log("SERVICE_ROLE_KEY=" + serviceKey);
28
+ console.log("\nAdd these to your .env file. Do not commit .env to source control.");
29
+ });
30
+ }
31
+ // ─── Helpers ─────────────────────────────────────────────────────────────────
32
+ export function resolveSecret() {
33
+ // 1. Check environment variable
34
+ const fromEnv = process.env["JWT_SECRET"];
35
+ if (fromEnv)
36
+ return fromEnv;
37
+ // 2. Parse .env file in cwd
38
+ const envPath = resolve(process.cwd(), ".env");
39
+ if (!existsSync(envPath))
40
+ return undefined;
41
+ try {
42
+ const contents = readFileSync(envPath, "utf8");
43
+ for (const line of contents.split("\n")) {
44
+ const trimmed = line.trim();
45
+ if (trimmed.startsWith("JWT_SECRET=")) {
46
+ const value = trimmed.slice("JWT_SECRET=".length).trim();
47
+ if (value && !value.startsWith("#"))
48
+ return value;
49
+ }
50
+ }
51
+ }
52
+ catch {
53
+ // ignore read errors
54
+ }
55
+ return undefined;
56
+ }
57
+ //# sourceMappingURL=keys.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keys.js","sourceRoot":"","sources":["../../src/commands/keys.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * supatype logs — tail aggregated logs from local Docker containers.
3
+ */
4
+ import type { Command } from "commander";
5
+ export declare function registerLogs(program: Command): void;
6
+ //# sourceMappingURL=logs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logs.d.ts","sourceRoot":"","sources":["../../src/commands/logs.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAKxC,wBAAgB,YAAY,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAiDnD"}
@@ -0,0 +1,52 @@
1
+ import { spawn } from "node:child_process";
2
+ const SERVICES = ["postgres", "postgrest", "gotrue", "kong", "minio", "realtime", "studio"];
3
+ export function registerLogs(program) {
4
+ program
5
+ .command("logs")
6
+ .description("Tail aggregated logs from local dev services")
7
+ .option("--service <name>", "Filter to a specific service")
8
+ .option("--since <duration>", "Show logs since duration (e.g., 5m, 1h)", "5m")
9
+ .option("-f, --follow", "Follow log output", true)
10
+ .action((opts) => {
11
+ const services = opts.service
12
+ ? [`supatype-${opts.service}`]
13
+ : SERVICES.map((s) => `supatype-${s}`);
14
+ if (opts.service && !SERVICES.includes(opts.service)) {
15
+ console.error(`Unknown service: ${opts.service}`);
16
+ console.error(`Available: ${SERVICES.join(", ")}`);
17
+ process.exit(1);
18
+ }
19
+ const args = ["compose", "logs"];
20
+ if (opts.follow)
21
+ args.push("-f");
22
+ if (opts.since)
23
+ args.push("--since", opts.since);
24
+ args.push("--tail", "100");
25
+ // If filtering by service, use docker logs for that container
26
+ if (opts.service) {
27
+ const containerArgs = ["logs"];
28
+ if (opts.follow)
29
+ containerArgs.push("-f");
30
+ if (opts.since)
31
+ containerArgs.push("--since", opts.since);
32
+ containerArgs.push("--tail", "100");
33
+ containerArgs.push(`supatype-${opts.service}`);
34
+ const child = spawn("docker", containerArgs, { stdio: "inherit" });
35
+ child.on("error", () => {
36
+ console.error("Docker not found. Ensure Docker is installed and running.");
37
+ process.exit(1);
38
+ });
39
+ return;
40
+ }
41
+ // Aggregated logs via docker compose
42
+ const child = spawn("docker", args, {
43
+ stdio: "inherit",
44
+ cwd: process.cwd(),
45
+ });
46
+ child.on("error", () => {
47
+ console.error("Docker not found. Ensure Docker is installed and running.");
48
+ process.exit(1);
49
+ });
50
+ });
51
+ }
52
+ //# sourceMappingURL=logs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logs.js","sourceRoot":"","sources":["../../src/commands/logs.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { Command } from "commander";
2
+ export declare function registerMigrate(program: Command): void;
3
+ //# sourceMappingURL=migrate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migrate.d.ts","sourceRoot":"","sources":["../../src/commands/migrate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAKxC,wBAAgB,eAAe,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAmEtD"}
@@ -0,0 +1,71 @@
1
+ import { createInterface } from "node:readline";
2
+ import { loadConfig } from "../config.js";
3
+ import { ensureEngine, invokeEngine } from "../engine.js";
4
+ export function registerMigrate(program) {
5
+ // migrate — apply all pending migrations
6
+ program
7
+ .command("migrate")
8
+ .description("Apply pending migrations from the migration history")
9
+ .option("--connection <url>", "Database connection URL (overrides config)")
10
+ .action(async (opts) => {
11
+ const config = loadConfig();
12
+ const connection = opts.connection ?? config.connection;
13
+ await ensureEngine();
14
+ const result = invokeEngine(["migrate", "--pending", "--connection", connection]);
15
+ if (result.exitCode !== 0) {
16
+ console.error(result.stderr || result.stdout);
17
+ process.exit(1);
18
+ }
19
+ console.log(result.stdout || "Migrations applied.");
20
+ });
21
+ // rollback — undo the last applied migration
22
+ program
23
+ .command("rollback")
24
+ .description("Roll back the last applied migration")
25
+ .option("--connection <url>", "Database connection URL (overrides config)")
26
+ .action(async (opts) => {
27
+ const config = loadConfig();
28
+ const connection = opts.connection ?? config.connection;
29
+ await ensureEngine();
30
+ const result = invokeEngine(["rollback", "--connection", connection]);
31
+ if (result.exitCode !== 0) {
32
+ console.error(result.stderr || result.stdout);
33
+ process.exit(1);
34
+ }
35
+ console.log(result.stdout || "Rolled back.");
36
+ });
37
+ // reset — drop all tables and re-apply from scratch
38
+ program
39
+ .command("reset")
40
+ .description("Drop all managed tables and re-apply the schema from scratch (destructive)")
41
+ .option("--yes", "Skip confirmation prompt")
42
+ .option("--connection <url>", "Database connection URL (overrides config)")
43
+ .action(async (opts) => {
44
+ if (!opts.yes) {
45
+ const confirmed = await confirm("This will DROP all managed tables and re-apply the schema. Proceed? [y/N] ");
46
+ if (!confirmed) {
47
+ console.log("Aborted.");
48
+ return;
49
+ }
50
+ }
51
+ const config = loadConfig();
52
+ const connection = opts.connection ?? config.connection;
53
+ await ensureEngine();
54
+ const result = invokeEngine(["reset", "--connection", connection]);
55
+ if (result.exitCode !== 0) {
56
+ console.error(result.stderr || result.stdout);
57
+ process.exit(1);
58
+ }
59
+ console.log(result.stdout || "Reset complete.");
60
+ });
61
+ }
62
+ async function confirm(prompt) {
63
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
64
+ return new Promise((resolve) => {
65
+ rl.question(prompt, (answer) => {
66
+ rl.close();
67
+ resolve(answer.toLowerCase() === "y");
68
+ });
69
+ });
70
+ }
71
+ //# sourceMappingURL=migrate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migrate.js","sourceRoot":"","sources":["../../src/commands/migrate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { Command } from "commander";
2
+ export declare function registerPlugins(program: Command): void;
3
+ //# sourceMappingURL=plugins.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugins.d.ts","sourceRoot":"","sources":["../../src/commands/plugins.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAOxC,wBAAgB,eAAe,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAgDtD"}
@@ -0,0 +1,431 @@
1
+ import { existsSync, readFileSync, mkdirSync, writeFileSync } from "node:fs";
2
+ import { resolve, join } from "node:path";
3
+ import { spawnSync } from "node:child_process";
4
+ // ─── Registration ────────────────────────────────────────────────────────────
5
+ export function registerPlugins(program) {
6
+ const cmd = program
7
+ .command("plugins")
8
+ .description("Manage Supatype plugins (field types, composites, providers, widgets)");
9
+ cmd
10
+ .command("list")
11
+ .description("Show all installed and active plugins")
12
+ .action(() => {
13
+ listPlugins(process.cwd());
14
+ });
15
+ cmd
16
+ .command("search <query>")
17
+ .description("Search npm registry for Supatype plugins")
18
+ .action(async (query) => {
19
+ await searchPlugins(query);
20
+ });
21
+ cmd
22
+ .command("add <package>")
23
+ .description("Install a plugin package and register it")
24
+ .action((pkg) => {
25
+ addPlugin(process.cwd(), pkg);
26
+ });
27
+ cmd
28
+ .command("remove <package>")
29
+ .description("Uninstall and deregister a plugin")
30
+ .action((pkg) => {
31
+ removePlugin(process.cwd(), pkg);
32
+ });
33
+ cmd
34
+ .command("create")
35
+ .description("Scaffold a new plugin project")
36
+ .option("--type <type>", "Plugin type: field, composite, provider, or widget", "field")
37
+ .option("--name <name>", "Plugin name")
38
+ .action((opts) => {
39
+ createPlugin(process.cwd(), opts);
40
+ });
41
+ cmd
42
+ .command("validate")
43
+ .description("Validate installed plugins for compatibility and correctness")
44
+ .action(() => {
45
+ validatePlugins(process.cwd());
46
+ });
47
+ }
48
+ // ─── List ────────────────────────────────────────────────────────────────────
49
+ function listPlugins(cwd) {
50
+ const plugins = discoverInstalledPlugins(cwd);
51
+ if (plugins.length === 0) {
52
+ console.log("No Supatype plugins installed.");
53
+ console.log("\nSearch for plugins: npx supatype plugins search <query>");
54
+ console.log("Create a plugin: npx supatype plugins create");
55
+ return;
56
+ }
57
+ console.log("Installed plugins:\n");
58
+ console.log(` ${"Name".padEnd(35)} ${"Type".padEnd(14)} ${"Version".padEnd(12)} Status`);
59
+ console.log(` ${"─".repeat(35)} ${"─".repeat(14)} ${"─".repeat(12)} ${"─".repeat(15)}`);
60
+ for (const p of plugins) {
61
+ const types = p.supatype?.types?.join(", ") ?? "unknown";
62
+ const status = p.compatible ? "active" : "incompatible";
63
+ console.log(` ${p.name.padEnd(35)} ${types.padEnd(14)} ${p.version.padEnd(12)} ${status}`);
64
+ }
65
+ }
66
+ // ─── Search ──────────────────────────────────────────────────────────────────
67
+ async function searchPlugins(query) {
68
+ console.log(`Searching npm for "${query}" supatype plugins...\n`);
69
+ try {
70
+ const searchUrl = `https://registry.npmjs.org/-/v1/search?text=supatype-plugin+${encodeURIComponent(query)}&size=20`;
71
+ const res = await fetch(searchUrl, {
72
+ signal: AbortSignal.timeout(10_000),
73
+ });
74
+ if (!res.ok) {
75
+ console.error(`Search failed: ${res.statusText}`);
76
+ return;
77
+ }
78
+ const data = await res.json();
79
+ if (data.objects.length === 0) {
80
+ console.log("No plugins found.");
81
+ console.log("\nTry a different search term, or create your own plugin:");
82
+ console.log(" npx supatype plugins create");
83
+ return;
84
+ }
85
+ console.log(` ${"Package".padEnd(40)} ${"Version".padEnd(12)} Description`);
86
+ console.log(` ${"─".repeat(40)} ${"─".repeat(12)} ${"─".repeat(40)}`);
87
+ for (const obj of data.objects) {
88
+ const pkg = obj.package;
89
+ const desc = (pkg.description ?? "").slice(0, 50);
90
+ console.log(` ${pkg.name.padEnd(40)} ${pkg.version.padEnd(12)} ${desc}`);
91
+ }
92
+ console.log(`\nInstall: npx supatype plugins add <package-name>`);
93
+ }
94
+ catch (err) {
95
+ console.error(`Error: ${err instanceof Error ? err.message : "unknown"}`);
96
+ }
97
+ }
98
+ // ─── Add ─────────────────────────────────────────────────────────────────────
99
+ function addPlugin(cwd, pkg) {
100
+ console.log(`Installing ${pkg}...`);
101
+ // Detect package manager
102
+ const pm = detectPackageManager(cwd);
103
+ const installCmd = pm === "pnpm" ? ["pnpm", "add", pkg]
104
+ : pm === "yarn" ? ["yarn", "add", pkg]
105
+ : ["npm", "install", pkg];
106
+ const result = spawnSync(installCmd[0], installCmd.slice(1), {
107
+ stdio: "inherit",
108
+ cwd,
109
+ });
110
+ if (result.status !== 0) {
111
+ console.error(`Failed to install ${pkg}`);
112
+ process.exit(1);
113
+ }
114
+ // Check compatibility
115
+ const pluginPkgPath = resolvePackageJson(cwd, pkg);
116
+ if (pluginPkgPath) {
117
+ const pkgJson = JSON.parse(readFileSync(pluginPkgPath, "utf8"));
118
+ const supatype = pkgJson["supatype"];
119
+ if (supatype?.["pluginApi"] !== undefined) {
120
+ const pluginApi = supatype["pluginApi"];
121
+ if (pluginApi !== 1) {
122
+ console.warn(`\nWarning: ${pkg} targets plugin API v${pluginApi}, current is v1.`);
123
+ console.warn("The plugin may not work correctly.");
124
+ }
125
+ }
126
+ }
127
+ console.log(`\n${pkg} installed and registered.`);
128
+ console.log("Run 'npx supatype plugins list' to see active plugins.");
129
+ }
130
+ // ─── Remove ──────────────────────────────────────────────────────────────────
131
+ function removePlugin(cwd, pkg) {
132
+ // Check if the plugin is referenced in the schema
133
+ // This is a best-effort check
134
+ const schemaFiles = findSchemaFiles(cwd);
135
+ for (const file of schemaFiles) {
136
+ const content = readFileSync(file, "utf8");
137
+ if (content.includes(pkg)) {
138
+ console.warn(`Warning: ${pkg} appears to be referenced in ${file}`);
139
+ console.warn("Removing it may break your schema. Proceed with caution.\n");
140
+ }
141
+ }
142
+ console.log(`Removing ${pkg}...`);
143
+ const pm = detectPackageManager(cwd);
144
+ const removeCmd = pm === "pnpm" ? ["pnpm", "remove", pkg]
145
+ : pm === "yarn" ? ["yarn", "remove", pkg]
146
+ : ["npm", "uninstall", pkg];
147
+ const result = spawnSync(removeCmd[0], removeCmd.slice(1), {
148
+ stdio: "inherit",
149
+ cwd,
150
+ });
151
+ if (result.status !== 0) {
152
+ console.error(`Failed to remove ${pkg}`);
153
+ process.exit(1);
154
+ }
155
+ console.log(`${pkg} removed.`);
156
+ }
157
+ // ─── Create ──────────────────────────────────────────────────────────────────
158
+ function createPlugin(cwd, opts) {
159
+ const validTypes = ["field", "composite", "provider", "widget"];
160
+ if (!validTypes.includes(opts.type)) {
161
+ console.error(`Invalid plugin type "${opts.type}". Must be one of: ${validTypes.join(", ")}`);
162
+ process.exit(1);
163
+ }
164
+ const name = opts.name ?? `supatype-plugin-my-${opts.type}`;
165
+ const pluginDir = resolve(cwd, name);
166
+ if (existsSync(pluginDir)) {
167
+ console.error(`Directory "${name}" already exists.`);
168
+ process.exit(1);
169
+ }
170
+ mkdirSync(pluginDir, { recursive: true });
171
+ mkdirSync(join(pluginDir, "src"), { recursive: true });
172
+ // package.json
173
+ writeFileSync(join(pluginDir, "package.json"), JSON.stringify({
174
+ name,
175
+ version: "0.1.0",
176
+ description: `Supatype ${opts.type} plugin`,
177
+ type: "module",
178
+ main: "./dist/index.js",
179
+ types: "./dist/index.d.ts",
180
+ exports: {
181
+ ".": {
182
+ import: "./dist/index.js",
183
+ types: "./dist/index.d.ts",
184
+ },
185
+ },
186
+ keywords: ["supatype", "supatype-plugin"],
187
+ supatype: {
188
+ pluginApi: 1,
189
+ types: [opts.type],
190
+ },
191
+ scripts: {
192
+ build: "tsc",
193
+ typecheck: "tsc --noEmit",
194
+ },
195
+ dependencies: {
196
+ "@supatype/plugin-sdk": "^0.1.0",
197
+ },
198
+ devDependencies: {
199
+ typescript: "^5",
200
+ },
201
+ }, null, 2) + "\n", "utf8");
202
+ // tsconfig.json
203
+ writeFileSync(join(pluginDir, "tsconfig.json"), JSON.stringify({
204
+ compilerOptions: {
205
+ target: "ES2022",
206
+ module: "Node16",
207
+ moduleResolution: "Node16",
208
+ outDir: "dist",
209
+ rootDir: "src",
210
+ declaration: true,
211
+ strict: true,
212
+ esModuleInterop: true,
213
+ skipLibCheck: true,
214
+ },
215
+ include: ["src"],
216
+ }, null, 2) + "\n", "utf8");
217
+ // Source file based on type
218
+ const sourceContent = generatePluginTemplate(opts.type, name);
219
+ writeFileSync(join(pluginDir, "src/index.ts"), sourceContent, "utf8");
220
+ console.log(`\nCreated plugin project: ${name}/\n`);
221
+ console.log(" Files:");
222
+ console.log(` ${name}/package.json`);
223
+ console.log(` ${name}/tsconfig.json`);
224
+ console.log(` ${name}/src/index.ts`);
225
+ console.log(`\n Next steps:`);
226
+ console.log(` cd ${name}`);
227
+ console.log(` npm install`);
228
+ console.log(` npm run build`);
229
+ console.log(` npx supatype plugins validate`);
230
+ }
231
+ function generatePluginTemplate(type, name) {
232
+ switch (type) {
233
+ case "field":
234
+ return `import { defineFieldType } from "@supatype/plugin-sdk"
235
+
236
+ export default defineFieldType({
237
+ name: "${name.replace(/.*plugin-/, "")}",
238
+ pgType: "TEXT",
239
+ tsType: "string",
240
+
241
+ validate(value) {
242
+ if (typeof value !== "string") return "Must be a string"
243
+ return null
244
+ },
245
+
246
+ serialise(value: string) {
247
+ return value
248
+ },
249
+
250
+ deserialise(raw) {
251
+ return String(raw)
252
+ },
253
+
254
+ filterOperators: ["eq", "neq", "in", "like"],
255
+ // widgetPath: "./src/Widget.tsx",
256
+ })
257
+ `;
258
+ case "composite":
259
+ return `import { defineComposite } from "@supatype/plugin-sdk"
260
+
261
+ export default defineComposite({
262
+ name: "${name.replace(/.*plugin-/, "")}",
263
+ label: "${name.replace(/.*plugin-/, "").replace(/-/g, " ").replace(/\b\w/g, l => l.toUpperCase())}",
264
+ fields: [
265
+ { name: "example_field", type: "text", required: false },
266
+ ],
267
+ adminGroup: {
268
+ collapsible: true,
269
+ defaultCollapsed: false,
270
+ },
271
+ })
272
+ `;
273
+ case "provider":
274
+ return `import { defineProvider, type EmailProvider } from "@supatype/plugin-sdk"
275
+
276
+ interface MyProviderConfig {
277
+ apiKey: string
278
+ region?: string
279
+ }
280
+
281
+ export default defineProvider<MyProviderConfig>({
282
+ name: "${name.replace(/.*plugin-/, "")}",
283
+ category: "email",
284
+ label: "${name.replace(/.*plugin-/, "").replace(/-/g, " ").replace(/\b\w/g, l => l.toUpperCase())}",
285
+ configSchema: {
286
+ apiKey: { type: "string", label: "API Key", required: true, secret: true },
287
+ region: { type: "select", label: "Region", options: ["us-east-1", "eu-west-1"] },
288
+ },
289
+ create(config): EmailProvider {
290
+ return {
291
+ async send(params) {
292
+ // Implement email sending using config.apiKey
293
+ console.log("Sending email to", params.to)
294
+ return { messageId: "msg_" + Date.now() }
295
+ },
296
+ }
297
+ },
298
+ })
299
+ `;
300
+ case "widget":
301
+ return `import { defineWidget } from "@supatype/plugin-sdk"
302
+
303
+ export default defineWidget({
304
+ name: "${name.replace(/.*plugin-/, "")}",
305
+ label: "${name.replace(/.*plugin-/, "").replace(/-/g, " ").replace(/\b\w/g, l => l.toUpperCase())}",
306
+ compatibleTypes: ["text", "varchar"],
307
+ componentPath: "./src/Widget.tsx",
308
+ })
309
+ `;
310
+ default:
311
+ return `// Unknown plugin type: ${type}\n`;
312
+ }
313
+ }
314
+ // ─── Validate ────────────────────────────────────────────────────────────────
315
+ function validatePlugins(cwd) {
316
+ const plugins = discoverInstalledPlugins(cwd);
317
+ if (plugins.length === 0) {
318
+ console.log("No plugins to validate.");
319
+ return;
320
+ }
321
+ let hasErrors = false;
322
+ for (const p of plugins) {
323
+ const issues = [];
324
+ if (!p.supatype) {
325
+ issues.push("Missing 'supatype' field in package.json");
326
+ }
327
+ else {
328
+ if (!p.supatype.pluginApi) {
329
+ issues.push("Missing supatype.pluginApi version");
330
+ }
331
+ else if (p.supatype.pluginApi !== 1) {
332
+ issues.push(`Targets plugin API v${p.supatype.pluginApi}, current is v1`);
333
+ }
334
+ if (!p.supatype.types || p.supatype.types.length === 0) {
335
+ issues.push("Missing supatype.types array");
336
+ }
337
+ }
338
+ if (issues.length === 0) {
339
+ console.log(` ✓ ${p.name} — valid`);
340
+ }
341
+ else {
342
+ hasErrors = true;
343
+ console.log(` ✗ ${p.name}`);
344
+ for (const issue of issues) {
345
+ console.log(` - ${issue}`);
346
+ }
347
+ }
348
+ }
349
+ if (hasErrors) {
350
+ console.log("\nSome plugins have issues. Fix them before deploying.");
351
+ process.exit(1);
352
+ }
353
+ else {
354
+ console.log("\nAll plugins are valid.");
355
+ }
356
+ }
357
+ function discoverInstalledPlugins(cwd) {
358
+ const nodeModulesDir = resolve(cwd, "node_modules");
359
+ if (!existsSync(nodeModulesDir))
360
+ return [];
361
+ const plugins = [];
362
+ // Read package.json to find dependencies
363
+ const pkgJsonPath = resolve(cwd, "package.json");
364
+ if (!existsSync(pkgJsonPath))
365
+ return [];
366
+ const pkgJson = JSON.parse(readFileSync(pkgJsonPath, "utf8"));
367
+ const deps = {
368
+ ...pkgJson["dependencies"],
369
+ ...pkgJson["devDependencies"],
370
+ };
371
+ for (const depName of Object.keys(deps)) {
372
+ const depPkgPath = resolvePackageJson(cwd, depName);
373
+ if (!depPkgPath)
374
+ continue;
375
+ try {
376
+ const depPkg = JSON.parse(readFileSync(depPkgPath, "utf8"));
377
+ // Check if it's a Supatype plugin
378
+ const keywords = depPkg["keywords"] ?? [];
379
+ const supatype = depPkg["supatype"];
380
+ if (keywords.includes("supatype-plugin") || supatype) {
381
+ plugins.push({
382
+ name: depName,
383
+ version: depPkg["version"] ?? "unknown",
384
+ supatype: supatype ? {
385
+ pluginApi: supatype["pluginApi"],
386
+ types: supatype["types"],
387
+ } : undefined,
388
+ compatible: !supatype?.["pluginApi"] || supatype["pluginApi"] === 1,
389
+ });
390
+ }
391
+ }
392
+ catch {
393
+ // Skip packages we can't read
394
+ }
395
+ }
396
+ return plugins;
397
+ }
398
+ function resolvePackageJson(cwd, packageName) {
399
+ // Handle scoped packages
400
+ const parts = packageName.startsWith("@") ? packageName.split("/") : [packageName];
401
+ const pkgPath = resolve(cwd, "node_modules", ...parts, "package.json");
402
+ return existsSync(pkgPath) ? pkgPath : null;
403
+ }
404
+ function detectPackageManager(cwd) {
405
+ if (existsSync(resolve(cwd, "pnpm-lock.yaml")))
406
+ return "pnpm";
407
+ if (existsSync(resolve(cwd, "yarn.lock")))
408
+ return "yarn";
409
+ return "npm";
410
+ }
411
+ function findSchemaFiles(cwd) {
412
+ const schemaDir = resolve(cwd, "supatype/schema");
413
+ if (!existsSync(schemaDir))
414
+ return [];
415
+ const files = [];
416
+ try {
417
+ const { readdirSync, statSync } = require("node:fs");
418
+ const entries = readdirSync(schemaDir);
419
+ for (const entry of entries) {
420
+ const fullPath = join(schemaDir, entry);
421
+ if (statSync(fullPath).isFile() && entry.endsWith(".ts")) {
422
+ files.push(fullPath);
423
+ }
424
+ }
425
+ }
426
+ catch {
427
+ // Ignore errors
428
+ }
429
+ return files;
430
+ }
431
+ //# sourceMappingURL=plugins.js.map