@lunora/cli 0.0.0 → 1.0.0-alpha.2

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 (72) hide show
  1. package/LICENSE.md +105 -0
  2. package/README.md +109 -9
  3. package/__assets__/package-og.svg +14 -0
  4. package/dist/bin.mjs +11 -0
  5. package/dist/index.d.mts +852 -0
  6. package/dist/index.d.ts +852 -0
  7. package/dist/index.mjs +19 -0
  8. package/dist/packem_chunks/handler.mjs +76 -0
  9. package/dist/packem_chunks/handler10.mjs +22 -0
  10. package/dist/packem_chunks/handler11.mjs +192 -0
  11. package/dist/packem_chunks/handler12.mjs +131 -0
  12. package/dist/packem_chunks/handler13.mjs +65 -0
  13. package/dist/packem_chunks/handler14.mjs +58 -0
  14. package/dist/packem_chunks/handler15.mjs +79 -0
  15. package/dist/packem_chunks/handler16.mjs +41 -0
  16. package/dist/packem_chunks/handler17.mjs +105 -0
  17. package/dist/packem_chunks/handler18.mjs +172 -0
  18. package/dist/packem_chunks/handler19.mjs +89 -0
  19. package/dist/packem_chunks/handler2.mjs +114 -0
  20. package/dist/packem_chunks/handler20.mjs +94 -0
  21. package/dist/packem_chunks/handler21.mjs +311 -0
  22. package/dist/packem_chunks/handler3.mjs +204 -0
  23. package/dist/packem_chunks/handler4.mjs +33 -0
  24. package/dist/packem_chunks/handler5.mjs +49 -0
  25. package/dist/packem_chunks/handler6.mjs +91 -0
  26. package/dist/packem_chunks/handler7.mjs +42 -0
  27. package/dist/packem_chunks/handler8.mjs +174 -0
  28. package/dist/packem_chunks/handler9.mjs +16 -0
  29. package/dist/packem_chunks/planDevCommand.mjs +543 -0
  30. package/dist/packem_chunks/runCodegenCommand.mjs +52 -0
  31. package/dist/packem_chunks/runDeployCommand.mjs +504 -0
  32. package/dist/packem_chunks/runInitCommand.mjs +652 -0
  33. package/dist/packem_chunks/runMigrateGenerateCommand.mjs +397 -0
  34. package/dist/packem_chunks/runResetCommand.mjs +41 -0
  35. package/dist/packem_chunks/runRpcCommand.mjs +68 -0
  36. package/dist/packem_shared/COMMANDS-1V_KEx35.mjs +905 -0
  37. package/dist/packem_shared/DEFAULT_IMPORT_BATCH_SIZE-Ck-2bU08.mjs +244 -0
  38. package/dist/packem_shared/admin-url-4UzT-CI4.mjs +19 -0
  39. package/dist/packem_shared/api-spec-CtA6ilu4.mjs +13 -0
  40. package/dist/packem_shared/buildRegistryIndex-BcYe607_.mjs +38 -0
  41. package/dist/packem_shared/command-BDXcJCCJ.mjs +14 -0
  42. package/dist/packem_shared/createLogger-CHPNjFw2.mjs +73 -0
  43. package/dist/packem_shared/defaultSpawner-DxI3mebw.mjs +43 -0
  44. package/dist/packem_shared/diffSnapshots-RR2ZE8Ya.mjs +161 -0
  45. package/dist/packem_shared/docker-hMQ97KSQ.mjs +21 -0
  46. package/dist/packem_shared/features-ocSSpZtS.mjs +24 -0
  47. package/dist/packem_shared/insertSchemaExtension-BuzF6-t2.mjs +59 -0
  48. package/dist/packem_shared/open-url-Dfq6fAyT.mjs +41 -0
  49. package/dist/packem_shared/output-format-7gyGR3h8.mjs +17 -0
  50. package/dist/packem_shared/parseArgs-YXFuKdEk.mjs +56 -0
  51. package/dist/packem_shared/parseManifest--vZf2FY1.mjs +94 -0
  52. package/dist/packem_shared/resolve-target-qbsJ_5sF.mjs +16 -0
  53. package/dist/packem_shared/runAddCommand-BZGkRnBs.mjs +693 -0
  54. package/dist/packem_shared/schema-drift-gate-BtBt0as0.mjs +79 -0
  55. package/dist/packem_shared/schemaIrToSnapshot-aBTo7TM5.mjs +43 -0
  56. package/dist/packem_shared/wrangler-name-cy4yhm9j.mjs +12 -0
  57. package/package.json +61 -18
  58. package/skills/README.md +29 -0
  59. package/skills/lunora/SKILL.md +83 -0
  60. package/skills/lunora-create-package/SKILL.md +129 -0
  61. package/skills/lunora-deploy/SKILL.md +150 -0
  62. package/skills/lunora-functions/SKILL.md +182 -0
  63. package/skills/lunora-migration-helper/SKILL.md +194 -0
  64. package/skills/lunora-performance-audit/SKILL.md +143 -0
  65. package/skills/lunora-quickstart/SKILL.md +240 -0
  66. package/skills/lunora-realtime/SKILL.md +177 -0
  67. package/skills/lunora-setup-auth/SKILL.md +170 -0
  68. package/skills/lunora-setup-hyperdrive/SKILL.md +154 -0
  69. package/skills/lunora-setup-hyperdrive-global/SKILL.md +171 -0
  70. package/skills/lunora-setup-mail/SKILL.md +151 -0
  71. package/skills/lunora-setup-scheduler/SKILL.md +157 -0
  72. package/skills/lunora-setup-storage/SKILL.md +154 -0
@@ -0,0 +1,59 @@
1
+ import { Project, SyntaxKind } from 'ts-morph';
2
+
3
+ const VALID_JS_IDENTIFIER = /^[A-Za-z_$][\w$]*$/u;
4
+ const startMarker = (key) => `// lunora:add:${key}:start`;
5
+ const endMarker = (key) => `// lunora:add:${key}:end`;
6
+ const extensionImportSpecifier = (key) => `./${key}/schema`;
7
+ const findDefineSchemaCall = (callExpressions) => {
8
+ for (const call of callExpressions) {
9
+ if (call.getExpression().getText() === "defineSchema") {
10
+ return call;
11
+ }
12
+ }
13
+ return void 0;
14
+ };
15
+ const insertSchemaExtension = (source, key) => {
16
+ if (!VALID_JS_IDENTIFIER.test(key)) {
17
+ return { ok: false, reason: "invalid-identifier" };
18
+ }
19
+ if (source.includes(startMarker(key))) {
20
+ return { ok: false, reason: "already-applied" };
21
+ }
22
+ const project = new Project({
23
+ compilerOptions: { allowJs: true },
24
+ useInMemoryFileSystem: true
25
+ });
26
+ const sourceFile = project.createSourceFile("schema.ts", source, { overwrite: true });
27
+ const callExpressions = sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression);
28
+ const defineSchemaCall = findDefineSchemaCall(callExpressions);
29
+ if (!defineSchemaCall) {
30
+ return { ok: false, reason: "no-define-schema" };
31
+ }
32
+ const tablesArgument = defineSchemaCall.getArguments()[0];
33
+ if (tablesArgument?.getKind() !== SyntaxKind.ObjectLiteralExpression) {
34
+ return { ok: false, reason: "non-object-argument" };
35
+ }
36
+ const variableDeclaration = defineSchemaCall.getFirstAncestorByKind(SyntaxKind.VariableDeclaration);
37
+ if (!variableDeclaration) {
38
+ return { ok: false, reason: "no-define-schema" };
39
+ }
40
+ const initializer = variableDeclaration.getInitializer();
41
+ if (!initializer) {
42
+ return { ok: false, reason: "no-define-schema" };
43
+ }
44
+ const insertAt = initializer.getEnd();
45
+ const chainText = `
46
+ ${startMarker(key)}
47
+ .extend(${key}.extension)
48
+ ${endMarker(key)}
49
+ `;
50
+ sourceFile.insertText(insertAt, chainText);
51
+ const importText = `${startMarker(key)}
52
+ import { ${key} } from "${extensionImportSpecifier(key)}";
53
+ ${endMarker(key)}
54
+ `;
55
+ sourceFile.insertText(0, importText);
56
+ return { ok: true, text: sourceFile.getFullText() };
57
+ };
58
+
59
+ export { insertSchemaExtension };
@@ -0,0 +1,41 @@
1
+ import { spawn } from 'node:child_process';
2
+ import { platform } from 'node:os';
3
+
4
+ const platformCommand = () => {
5
+ const os = platform();
6
+ if (os === "darwin") {
7
+ return { args: [], command: "open" };
8
+ }
9
+ if (os === "win32") {
10
+ return { args: ["/c", "start", ""], command: "cmd" };
11
+ }
12
+ return { args: [], command: "xdg-open" };
13
+ };
14
+ const escapeForCmd = (url) => url.replaceAll("%", "%25").replaceAll("&", "%26").replaceAll("|", "%7C").replaceAll("^", "%5E").replaceAll("<", "%3C").replaceAll(">", "%3E").replaceAll("(", "%28").replaceAll(")", "%29").replaceAll('"', "%22").replaceAll("!", "%21");
15
+ const platformOpener = (url) => new Promise((resolve, reject) => {
16
+ const { args, command } = platformCommand();
17
+ const safeUrl = platform() === "win32" ? escapeForCmd(url) : url;
18
+ const child = spawn(command, [...args, safeUrl], { detached: true, stdio: "ignore" });
19
+ child.once("error", (error) => {
20
+ reject(error);
21
+ });
22
+ child.once("spawn", () => {
23
+ child.unref();
24
+ resolve();
25
+ });
26
+ });
27
+ const openUrl = async (url, options = {}) => {
28
+ let parsed;
29
+ try {
30
+ parsed = new URL(url);
31
+ } catch {
32
+ throw new Error(`Invalid URL: ${url}`);
33
+ }
34
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
35
+ throw new Error(`Refusing to open non-http(s) URL: ${url}`);
36
+ }
37
+ const opener = options.opener ?? platformOpener;
38
+ await opener(url);
39
+ };
40
+
41
+ export { openUrl as o };
@@ -0,0 +1,17 @@
1
+ import { createStderrLogger } from './createLogger-CHPNjFw2.mjs';
2
+
3
+ const OUTPUT_FORMATS = /* @__PURE__ */ new Set(["json", "pretty"]);
4
+ const validateOutputFormat = (command, format) => {
5
+ if (format !== void 0 && !OUTPUT_FORMATS.has(format)) {
6
+ return `${command}: unknown --format "${format}" — expected pretty | json`;
7
+ }
8
+ return void 0;
9
+ };
10
+ const isJsonFormat = (format) => format === "json";
11
+ const loggerForFormat = (format, prettyLogger) => isJsonFormat(format) ? createStderrLogger() : prettyLogger;
12
+ const printJson = (result) => {
13
+ process.stdout.write(`${JSON.stringify(result, void 0, 2)}
14
+ `);
15
+ };
16
+
17
+ export { isJsonFormat as i, loggerForFormat as l, printJson as p, validateOutputFormat as v };
@@ -0,0 +1,56 @@
1
+ const consumeLongOption = (body, next, booleanFlags, accumulator) => {
2
+ const eqIndex = body.indexOf("=");
3
+ if (eqIndex !== -1) {
4
+ accumulator.options[body.slice(0, eqIndex)] = body.slice(eqIndex + 1);
5
+ return 1;
6
+ }
7
+ if (booleanFlags.has(body)) {
8
+ accumulator.flags[body] = true;
9
+ return 1;
10
+ }
11
+ if (next !== void 0 && !next.startsWith("-")) {
12
+ accumulator.options[body] = next;
13
+ return 2;
14
+ }
15
+ accumulator.flags[body] = true;
16
+ return 1;
17
+ };
18
+ const consumeShortOption = (body, next, accumulator) => {
19
+ if (body.length > 1) {
20
+ accumulator.options[body[0]] = body.slice(1);
21
+ return 1;
22
+ }
23
+ if (next !== void 0 && !next.startsWith("-")) {
24
+ accumulator.options[body] = next;
25
+ return 2;
26
+ }
27
+ accumulator.flags[body] = true;
28
+ return 1;
29
+ };
30
+ const parseArgs = (argv, booleanFlags = /* @__PURE__ */ new Set()) => {
31
+ const accumulator = { flags: {}, options: {}, positional: [] };
32
+ let index = 0;
33
+ let terminated = false;
34
+ while (index < argv.length) {
35
+ const token = argv[index];
36
+ if (token === void 0) {
37
+ index += 1;
38
+ continue;
39
+ }
40
+ if (terminated || !token.startsWith("-") || token.length === 1) {
41
+ accumulator.positional.push(token);
42
+ index += 1;
43
+ continue;
44
+ }
45
+ if (token === "--") {
46
+ terminated = true;
47
+ index += 1;
48
+ continue;
49
+ }
50
+ const next = argv[index + 1];
51
+ index += token.startsWith("--") ? consumeLongOption(token.slice(2), next, booleanFlags, accumulator) : consumeShortOption(token.slice(1), next, accumulator);
52
+ }
53
+ return { flags: accumulator.flags, options: accumulator.options, positional: accumulator.positional };
54
+ };
55
+
56
+ export { parseArgs as default };
@@ -0,0 +1,94 @@
1
+ const NEWLINE_PRESENT = /[\r\n]/u;
2
+ const VALID_ENV_NAME = /^[A-Za-z_]\w*$/u;
3
+ const VALID_ITEM_NAME = /^[A-Za-z0-9][\w-]*$/u;
4
+ const parseManifest = (raw, itemName) => {
5
+ if (typeof raw !== "object" || raw === null) {
6
+ throw new Error(`registry.json for "${itemName}" is not an object`);
7
+ }
8
+ const record = raw;
9
+ const { name } = record;
10
+ if (typeof name !== "string" || name.length === 0) {
11
+ throw new Error(`registry.json for "${itemName}" is missing a string "name"`);
12
+ }
13
+ if (!VALID_ITEM_NAME.test(name)) {
14
+ throw new Error(
15
+ `registry.json for "${itemName}": name "${name}" must match ${VALID_ITEM_NAME.source} (letters, digits, "-", "_"; no path separators, "..", or code)`
16
+ );
17
+ }
18
+ const filesRaw = record.files;
19
+ if (!Array.isArray(filesRaw)) {
20
+ throw new TypeError(`registry.json for "${itemName}" is missing a "files" array`);
21
+ }
22
+ const files = filesRaw.map((entry, index) => {
23
+ if (typeof entry !== "object" || entry === null) {
24
+ throw new Error(`registry.json "${itemName}": files[${String(index)}] is not an object`);
25
+ }
26
+ const fileRecord = entry;
27
+ const { from } = fileRecord;
28
+ const { to } = fileRecord;
29
+ const { merge } = fileRecord;
30
+ if (typeof from !== "string" || typeof to !== "string") {
31
+ throw new TypeError(`registry.json "${itemName}": files[${String(index)}] needs string "from" and "to"`);
32
+ }
33
+ if (merge !== "create-or-skip" && merge !== "schema-extension") {
34
+ throw new Error(`registry.json "${itemName}": files[${String(index)}].merge must be "create-or-skip" or "schema-extension"`);
35
+ }
36
+ for (const [field, value] of [
37
+ ["from", from],
38
+ ["to", to]
39
+ ]) {
40
+ if (value.includes("..") || value.startsWith("/")) {
41
+ throw new Error(`registry.json "${itemName}": files[${String(index)}].${field} "${value}" must be a relative path without ".."`);
42
+ }
43
+ }
44
+ return { from, merge, to };
45
+ });
46
+ const asStringMap = (value) => typeof value === "object" && value !== null ? value : void 0;
47
+ const deps = asStringMap(record.deps);
48
+ const devDependencies = asStringMap(record.devDependencies);
49
+ const requires = Array.isArray(record.requires) ? record.requires.filter((value) => typeof value === "string") : void 0;
50
+ const bindings = Array.isArray(record.bindings) ? record.bindings.filter((value) => {
51
+ if (typeof value !== "object" || value === null) {
52
+ return false;
53
+ }
54
+ const bindingRecord = value;
55
+ return Array.isArray(bindingRecord.path) && bindingRecord.path.every((segment) => typeof segment === "string");
56
+ }) : void 0;
57
+ const envVariables = Array.isArray(record.envVars) ? record.envVars.filter(
58
+ (value) => typeof value === "object" && value !== null && typeof value.name === "string"
59
+ ).map((entry) => {
60
+ const hasValue = typeof entry.value === "string";
61
+ if (!VALID_ENV_NAME.test(entry.name)) {
62
+ throw new Error(
63
+ `registry.json "${itemName}": envVars["${entry.name}"].name must match ${VALID_ENV_NAME.source} (letters, digits, underscore; no "=" or newline)`
64
+ );
65
+ }
66
+ if (hasValue && NEWLINE_PRESENT.test(entry.value)) {
67
+ throw new Error(`registry.json "${itemName}": envVars["${entry.name}"].value must not contain a newline`);
68
+ }
69
+ if (typeof entry.description === "string" && NEWLINE_PRESENT.test(entry.description)) {
70
+ throw new Error(`registry.json "${itemName}": envVars["${entry.name}"].description must not contain a newline`);
71
+ }
72
+ return {
73
+ ...typeof entry.description === "string" ? { description: entry.description } : {},
74
+ name: entry.name,
75
+ // Default to secret unless a concrete value is provided.
76
+ secret: typeof entry.secret === "boolean" ? entry.secret : !hasValue,
77
+ ...hasValue ? { value: entry.value } : {}
78
+ };
79
+ }) : void 0;
80
+ return {
81
+ bindings,
82
+ deps,
83
+ description: typeof record.description === "string" ? record.description : void 0,
84
+ devDependencies,
85
+ docs: typeof record.docs === "string" ? record.docs : void 0,
86
+ envVars: envVariables,
87
+ files,
88
+ name,
89
+ requires,
90
+ title: typeof record.title === "string" ? record.title : void 0
91
+ };
92
+ };
93
+
94
+ export { parseManifest as default };
@@ -0,0 +1,16 @@
1
+ import { readLinkedProject } from '@lunora/config';
2
+
3
+ const resolveWorkerUrl = ({ cwd, url }) => {
4
+ if (url !== void 0 && url !== "") {
5
+ return url;
6
+ }
7
+ return readLinkedProject(cwd)?.workerUrl;
8
+ };
9
+ const resolveProductionWorkerUrl = ({ cwd, prod, url }) => {
10
+ if (url !== void 0 && url !== "") {
11
+ return url;
12
+ }
13
+ return prod ? readLinkedProject(cwd)?.workerUrl : void 0;
14
+ };
15
+
16
+ export { resolveProductionWorkerUrl as a, resolveWorkerUrl as r };