@lunora/cli 1.0.0-alpha.2 → 1.0.0-alpha.21
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/dist/bin.mjs +1 -1
- package/dist/index.d.mts +217 -113
- package/dist/index.d.ts +217 -113
- package/dist/index.mjs +7 -7
- package/dist/packem_chunks/handler.mjs +80 -6
- package/dist/packem_chunks/handler10.mjs +1 -1
- package/dist/packem_chunks/handler11.mjs +1 -1
- package/dist/packem_chunks/handler12.mjs +1 -1
- package/dist/packem_chunks/handler13.mjs +1 -1
- package/dist/packem_chunks/handler14.mjs +2 -2
- package/dist/packem_chunks/handler15.mjs +1 -1
- package/dist/packem_chunks/handler16.mjs +5 -3
- package/dist/packem_chunks/handler17.mjs +1 -1
- package/dist/packem_chunks/handler18.mjs +4 -6
- package/dist/packem_chunks/handler19.mjs +3 -3
- package/dist/packem_chunks/handler2.mjs +2 -2
- package/dist/packem_chunks/handler20.mjs +1 -1
- package/dist/packem_chunks/handler21.mjs +2 -2
- package/dist/packem_chunks/handler3.mjs +1 -1
- package/dist/packem_chunks/handler4.mjs +1 -1
- package/dist/packem_chunks/handler5.mjs +2 -2
- package/dist/packem_chunks/handler6.mjs +2 -2
- package/dist/packem_chunks/handler7.mjs +1 -1
- package/dist/packem_chunks/handler8.mjs +1 -1
- package/dist/packem_chunks/handler9.mjs +1 -1
- package/dist/packem_chunks/planDevCommand.mjs +6 -49
- package/dist/packem_chunks/runCodegenCommand.mjs +2 -2
- package/dist/packem_chunks/runDeployCommand.mjs +3 -3
- package/dist/packem_chunks/runInitCommand.mjs +1948 -107
- package/dist/packem_chunks/runMigrateGenerateCommand.mjs +5 -5
- package/dist/packem_chunks/runResetCommand.mjs +4 -4
- package/dist/packem_chunks/runRpcCommand.mjs +1 -1
- package/dist/packem_shared/{COMMANDS-1V_KEx35.mjs → COMMANDS-D3h9Iwvl.mjs} +45 -6
- package/dist/packem_shared/{command-BDXcJCCJ.mjs → command-BC30oSBW.mjs} +1 -1
- package/dist/packem_shared/{runAddCommand-BZGkRnBs.mjs → commands-hl0mRqqg.mjs} +177 -25
- package/dist/packem_shared/{createLogger-CHPNjFw2.mjs → createLogger-B40gPzQo.mjs} +9 -4
- package/dist/packem_shared/detect-package-manager-DYp7n3mJ.mjs +61 -0
- package/dist/packem_shared/{diffSnapshots-RR2ZE8Ya.mjs → diffSnapshots-BeDvvNiF.mjs} +1 -1
- package/dist/packem_shared/{insertSchemaExtension-BuzF6-t2.mjs → insertSchemaExtension-DAqbfr9Z.mjs} +15 -10
- package/dist/packem_shared/{output-format-7gyGR3h8.mjs → output-format-wUvAN6AL.mjs} +1 -1
- package/dist/packem_shared/runAddCommand-vJdgiR5t.mjs +4 -0
- package/dist/packem_shared/{schemaIrToSnapshot-aBTo7TM5.mjs → schemaIrToSnapshot-DdsljJT-.mjs} +1 -1
- package/dist/packem_shared/storage-B7hHSTZP.mjs +84 -0
- package/dist/packem_shared/tui-prompts-M6OWsuyw.mjs +663 -0
- package/package.json +11 -10
- package/skills/lunora-setup-storage/SKILL.md +7 -3
- package/dist/packem_shared/features-ocSSpZtS.mjs +0 -24
- /package/dist/packem_shared/{defaultSpawner-DxI3mebw.mjs → createRecordingSpawner-DxI3mebw.mjs} +0 -0
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { existsSync, mkdirSync, writeFileSync,
|
|
1
|
+
import { existsSync, mkdirSync, writeFileSync, mkdtempSync, rmSync, readFileSync } from 'node:fs';
|
|
2
2
|
import { tmpdir } from 'node:os';
|
|
3
|
-
import {
|
|
3
|
+
import { discoverSchema, discoverMigrations } from '@lunora/codegen';
|
|
4
4
|
import { join } from '@visulima/path';
|
|
5
5
|
import { Project } from 'ts-morph';
|
|
6
6
|
import { r as resolveAdminBaseUrl } from '../packem_shared/admin-url-4UzT-CI4.mjs';
|
|
7
|
-
import { d as defineHandler } from '../packem_shared/command-
|
|
8
|
-
import { diffSnapshots, renderMigrationFile } from '../packem_shared/diffSnapshots-
|
|
7
|
+
import { d as defineHandler } from '../packem_shared/command-BC30oSBW.mjs';
|
|
8
|
+
import { diffSnapshots, renderMigrationFile } from '../packem_shared/diffSnapshots-BeDvvNiF.mjs';
|
|
9
9
|
import { a as resolveProductionWorkerUrl } from '../packem_shared/resolve-target-qbsJ_5sF.mjs';
|
|
10
|
-
import schemaIrToSnapshot from '../packem_shared/schemaIrToSnapshot-
|
|
10
|
+
import schemaIrToSnapshot from '../packem_shared/schemaIrToSnapshot-DdsljJT-.mjs';
|
|
11
11
|
import { runExportCommand, runImportCommand } from '../packem_shared/DEFAULT_IMPORT_BATCH_SIZE-Ck-2bU08.mjs';
|
|
12
12
|
|
|
13
13
|
const SNAPSHOT_FILENAME = ".snapshot.json";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { existsSync, rmSync } from 'node:fs';
|
|
2
|
-
import { promptYesNo } from '@lunora/config';
|
|
3
2
|
import { join } from '@visulima/path';
|
|
4
|
-
import { d as defineHandler } from '../packem_shared/command-
|
|
3
|
+
import { d as defineHandler } from '../packem_shared/command-BC30oSBW.mjs';
|
|
4
|
+
import { b as tuiConfirm } from '../packem_shared/tui-prompts-M6OWsuyw.mjs';
|
|
5
5
|
|
|
6
6
|
const runResetCommand = async (options) => {
|
|
7
7
|
const cwd = options.cwd ?? process.cwd();
|
|
@@ -15,8 +15,8 @@ const runResetCommand = async (options) => {
|
|
|
15
15
|
options.logger.error("reset: stdin is not a TTY — re-run with --yes to confirm deleting .wrangler/state");
|
|
16
16
|
return { code: 1, removed: [] };
|
|
17
17
|
}
|
|
18
|
-
const confirmer = options.confirm ??
|
|
19
|
-
const confirmed = await confirmer("This will delete .wrangler/state. Continue?
|
|
18
|
+
const confirmer = options.confirm ?? tuiConfirm;
|
|
19
|
+
const confirmed = await confirmer("This will delete .wrangler/state. Continue?");
|
|
20
20
|
if (!confirmed) {
|
|
21
21
|
options.logger.info("reset: aborted");
|
|
22
22
|
return { code: 1, removed: [] };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { d as defineHandler } from '../packem_shared/command-
|
|
1
|
+
import { d as defineHandler } from '../packem_shared/command-BC30oSBW.mjs';
|
|
2
2
|
import { r as resolveWorkerUrl } from '../packem_shared/resolve-target-qbsJ_5sF.mjs';
|
|
3
3
|
|
|
4
4
|
const parseArgsJson = (raw) => {
|
|
@@ -3,7 +3,7 @@ import { createCerebro } from '@visulima/cerebro';
|
|
|
3
3
|
import completionCommand from '@visulima/cerebro/command/completion';
|
|
4
4
|
import versionCommand from '@visulima/cerebro/command/version';
|
|
5
5
|
import { A as API_SPEC_HELP } from './api-spec-CtA6ilu4.mjs';
|
|
6
|
-
import { createLogger } from './createLogger-
|
|
6
|
+
import { createLogger } from './createLogger-B40gPzQo.mjs';
|
|
7
7
|
import { tmpdir } from 'node:os';
|
|
8
8
|
import { join } from 'node:path';
|
|
9
9
|
|
|
@@ -14,8 +14,10 @@ const addCommand = {
|
|
|
14
14
|
["lunora add auth", "Add authentication (asks which provider)"],
|
|
15
15
|
["lunora add auth --provider clerk", "Add Clerk auth without prompting"],
|
|
16
16
|
["lunora add email", "Add transactional email (Cloudflare Email Workers + dev mail catcher)"],
|
|
17
|
-
["lunora add storage", "Add the R2 storage registry item"],
|
|
18
|
-
["lunora add
|
|
17
|
+
["lunora add storage", "Add the R2 storage registry item (asks for the bucket name)"],
|
|
18
|
+
["lunora add storage --bucket my-app-uploads", "Add storage with a bucket name, no prompt"],
|
|
19
|
+
["lunora add crons", "Add the scheduled-jobs registry item"],
|
|
20
|
+
["lunora add storage --ref alpha", "Add an item from the alpha branch's registry"]
|
|
19
21
|
],
|
|
20
22
|
group: "Project",
|
|
21
23
|
loader: () => import('../packem_chunks/handler.mjs').then((m) => {
|
|
@@ -24,9 +26,17 @@ const addCommand = {
|
|
|
24
26
|
name: "add",
|
|
25
27
|
options: [
|
|
26
28
|
{ description: "auth: provider to use without prompting (auth | clerk | auth0)", name: "provider", type: String },
|
|
27
|
-
{ description: "
|
|
29
|
+
{ description: "auth: D1 database name to use without prompting (lowercase alphanumeric + hyphens)", name: "db", type: String },
|
|
30
|
+
{ description: "storage: R2 bucket name to use without prompting (lowercase alphanumeric + hyphens)", name: "bucket", type: String },
|
|
31
|
+
{ description: "email: verified destination address to use without prompting", name: "mail-to", type: String },
|
|
32
|
+
{ description: "Skip prompts (auth provider, DB name, bucket name, mail destination) and use the defaults", name: "yes", type: Boolean },
|
|
28
33
|
{ description: "Local registry root (offline; expects <name>/ subdirs)", name: "from", type: String },
|
|
29
34
|
{ description: "Override the remote registry source base (e.g. gh:owner/repo/registry)", name: "source", type: String },
|
|
35
|
+
{
|
|
36
|
+
description: "Fetch items from a git ref (branch, tag, or commit), e.g. --ref alpha. Overrides the version-derived default",
|
|
37
|
+
name: "ref",
|
|
38
|
+
type: String
|
|
39
|
+
},
|
|
30
40
|
{ description: "Permit --source values outside gh:/github:/https://", name: "allow-unsafe-source", type: Boolean }
|
|
31
41
|
]
|
|
32
42
|
};
|
|
@@ -342,6 +352,7 @@ const initCommand = {
|
|
|
342
352
|
["lunora init my-app", "Scaffold with the default (vite) template"],
|
|
343
353
|
["lunora init my-app -t tanstack-start-react", "Scaffold a TanStack Start (React) app"],
|
|
344
354
|
["lunora init my-app -t tanstack-start-solid", "Scaffold a TanStack Start (Solid) app"],
|
|
355
|
+
["lunora init my-app --ref alpha", "Scaffold from the alpha branch's templates"],
|
|
345
356
|
["lunora init --here", "Add Lunora to the current project"],
|
|
346
357
|
["lunora init my-app --ci github", "Scaffold + add a GitHub Actions deploy pipeline"],
|
|
347
358
|
["lunora init my-app --ci gitlab", "Scaffold + add a GitLab CI deploy pipeline"]
|
|
@@ -354,11 +365,19 @@ const initCommand = {
|
|
|
354
365
|
options: [
|
|
355
366
|
{
|
|
356
367
|
alias: "t",
|
|
357
|
-
|
|
358
|
-
|
|
368
|
+
// No default: when omitted, an interactive run shows the framework
|
|
369
|
+
// picker (default React overlay) and a non-interactive run errors.
|
|
370
|
+
// For React/Vue/Solid/Svelte SPAs use `--vite <framework>` (overlay);
|
|
371
|
+
// `-t` selects a bespoke template.
|
|
372
|
+
description: "Bespoke template (standalone | astro | nuxt | sveltekit | tanstack-start-react | tanstack-start-solid). For an SPA use --vite react|vue|solid|svelte.",
|
|
359
373
|
name: "template",
|
|
360
374
|
type: String
|
|
361
375
|
},
|
|
376
|
+
{
|
|
377
|
+
description: "Scaffold via the create-vite overlay for a framework (react | vue | solid | svelte | vanilla) — official create-vite base + Lunora layer",
|
|
378
|
+
name: "vite",
|
|
379
|
+
type: String
|
|
380
|
+
},
|
|
362
381
|
{
|
|
363
382
|
description: "Local templates root to copy from (offline-friendly; expects <type>/ subdirs)",
|
|
364
383
|
name: "from",
|
|
@@ -369,6 +388,11 @@ const initCommand = {
|
|
|
369
388
|
name: "source",
|
|
370
389
|
type: String
|
|
371
390
|
},
|
|
391
|
+
{
|
|
392
|
+
description: "Fetch templates from a git ref (branch, tag, or commit), e.g. --ref alpha. Overrides the version-derived default",
|
|
393
|
+
name: "ref",
|
|
394
|
+
type: String
|
|
395
|
+
},
|
|
372
396
|
{
|
|
373
397
|
description: "Permit --source values outside gh:/github:/https:// (e.g. local file://)",
|
|
374
398
|
name: "allow-unsafe-source",
|
|
@@ -395,6 +419,16 @@ const initCommand = {
|
|
|
395
419
|
description: "Also scaffold a CI deploy pipeline: github (.github/workflows/deploy.yml) or gitlab (.gitlab-ci.yml)",
|
|
396
420
|
name: "ci",
|
|
397
421
|
type: String
|
|
422
|
+
},
|
|
423
|
+
{
|
|
424
|
+
description: "Add features non-interactively after scaffolding (comma-separated): auth | email | storage | ratelimit | crons | presence | backup",
|
|
425
|
+
name: "add",
|
|
426
|
+
type: String
|
|
427
|
+
},
|
|
428
|
+
{
|
|
429
|
+
description: "Walk through every step (prompts + output) without writing files, installing, or running git",
|
|
430
|
+
name: "dry-run",
|
|
431
|
+
type: Boolean
|
|
398
432
|
}
|
|
399
433
|
]
|
|
400
434
|
};
|
|
@@ -541,6 +575,11 @@ const registryCommand = {
|
|
|
541
575
|
{ description: "add: skip the package.json mutation confirmation prompt", name: "yes", type: Boolean },
|
|
542
576
|
{ description: "Local registry root (offline; expects <name>/ subdirs)", name: "from", type: String },
|
|
543
577
|
{ description: "Override the remote registry source base (e.g. gh:owner/repo/registry)", name: "source", type: String },
|
|
578
|
+
{
|
|
579
|
+
description: "Fetch items from a git ref (branch, tag, or commit), e.g. --ref alpha. Overrides the version-derived default",
|
|
580
|
+
name: "ref",
|
|
581
|
+
type: String
|
|
582
|
+
},
|
|
544
583
|
{ description: "Permit --source values outside gh:/github:/https://", name: "allow-unsafe-source", type: Boolean },
|
|
545
584
|
{ description: "Emit JSON output (add plan / list)", name: "json", type: Boolean },
|
|
546
585
|
{ description: "build: output path for the catalog (default <root>/index.json)", name: "out", type: String },
|
|
@@ -1,15 +1,130 @@
|
|
|
1
1
|
import { existsSync, readFileSync, writeFileSync, mkdirSync, mkdtempSync, rmSync } from 'node:fs';
|
|
2
|
-
import {
|
|
3
|
-
import { DEV_VARS_FILE, parseDevVariableEntries
|
|
2
|
+
import { dirname, join } from '@visulima/path';
|
|
3
|
+
import { DEV_VARS_FILE, parseDevVariableEntries } from '@lunora/config';
|
|
4
4
|
import { modify, applyEdits, parse } from 'jsonc-parser';
|
|
5
|
+
import { fileURLToPath } from 'node:url';
|
|
6
|
+
import { b as tuiConfirm } from './tui-prompts-M6OWsuyw.mjs';
|
|
5
7
|
import { collectCatalog, buildRegistryIndex } from './buildRegistryIndex-BcYe607_.mjs';
|
|
6
|
-
import { insertSchemaExtension } from './insertSchemaExtension-
|
|
8
|
+
import { insertSchemaExtension } from './insertSchemaExtension-DAqbfr9Z.mjs';
|
|
7
9
|
import { createHash } from 'node:crypto';
|
|
8
10
|
import { tmpdir } from 'node:os';
|
|
9
11
|
import { downloadTemplate } from 'giget';
|
|
10
12
|
import parseManifest from './parseManifest--vZf2FY1.mjs';
|
|
11
13
|
|
|
12
|
-
const
|
|
14
|
+
const DEFAULT_SOURCE_REF_FALLBACK = "alpha";
|
|
15
|
+
const STABLE_BRANCH = "main";
|
|
16
|
+
const PRERELEASE_CHANNEL_BRANCHES = /* @__PURE__ */ new Set(["alpha", "beta", "next"]);
|
|
17
|
+
const SAFE_REF = /^[\w./@-]+$/;
|
|
18
|
+
const isSafeRef = (ref) => !ref.includes("..") && SAFE_REF.test(ref);
|
|
19
|
+
const resolveCliVersion = () => {
|
|
20
|
+
try {
|
|
21
|
+
let directory = dirname(fileURLToPath(import.meta.url));
|
|
22
|
+
for (let index = 0; index < 6; index += 1) {
|
|
23
|
+
const candidate = join(directory, "package.json");
|
|
24
|
+
if (existsSync(candidate)) {
|
|
25
|
+
const parsed = JSON.parse(readFileSync(candidate, "utf8"));
|
|
26
|
+
if (parsed.name === "@lunora/cli" && typeof parsed.version === "string") {
|
|
27
|
+
return parsed.version;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
const parent = dirname(directory);
|
|
31
|
+
if (parent === directory) {
|
|
32
|
+
break;
|
|
33
|
+
}
|
|
34
|
+
directory = parent;
|
|
35
|
+
}
|
|
36
|
+
} catch {
|
|
37
|
+
}
|
|
38
|
+
return "0.0.0";
|
|
39
|
+
};
|
|
40
|
+
const resolveVersionRef = (version) => {
|
|
41
|
+
if (version === "0.0.0") {
|
|
42
|
+
return DEFAULT_SOURCE_REF_FALLBACK;
|
|
43
|
+
}
|
|
44
|
+
const core = version.split("+")[0] ?? version;
|
|
45
|
+
const dashIndex = core.indexOf("-");
|
|
46
|
+
if (dashIndex !== -1) {
|
|
47
|
+
const [channel] = core.slice(dashIndex + 1).split(".");
|
|
48
|
+
if (channel !== void 0 && PRERELEASE_CHANNEL_BRANCHES.has(channel)) {
|
|
49
|
+
return channel;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return STABLE_BRANCH;
|
|
53
|
+
};
|
|
54
|
+
const resolveSourceRef = (ref) => {
|
|
55
|
+
if (ref !== void 0 && ref.length > 0) {
|
|
56
|
+
if (!isSafeRef(ref)) {
|
|
57
|
+
throw new Error(`invalid --ref "${ref}" — a ref may contain letters, digits, ".", "_", "-", "/", "@" and must not contain "..".`);
|
|
58
|
+
}
|
|
59
|
+
return ref;
|
|
60
|
+
}
|
|
61
|
+
return resolveVersionRef(resolveCliVersion());
|
|
62
|
+
};
|
|
63
|
+
const STABLE_DIST_TAG = "latest";
|
|
64
|
+
const resolveDistTag = () => {
|
|
65
|
+
const ref = resolveVersionRef(resolveCliVersion());
|
|
66
|
+
return ref === STABLE_BRANCH ? STABLE_DIST_TAG : ref;
|
|
67
|
+
};
|
|
68
|
+
const DEFAULT_REGISTRY = "https://registry.npmjs.org";
|
|
69
|
+
const registryBase = () => {
|
|
70
|
+
const configured = process.env["npm_config_registry"];
|
|
71
|
+
const base = configured !== void 0 && configured.length > 0 ? configured : DEFAULT_REGISTRY;
|
|
72
|
+
return base.endsWith("/") ? base.slice(0, -1) : base;
|
|
73
|
+
};
|
|
74
|
+
const resolveTagVersion = async (packageName, tag) => {
|
|
75
|
+
try {
|
|
76
|
+
const response = await fetch(`${registryBase()}/${packageName.replace("/", "%2F")}`, {
|
|
77
|
+
headers: { accept: "application/vnd.npm.install-v1+json" },
|
|
78
|
+
signal: AbortSignal.timeout(1e4)
|
|
79
|
+
});
|
|
80
|
+
if (!response.ok) {
|
|
81
|
+
return void 0;
|
|
82
|
+
}
|
|
83
|
+
const packument = await response.json();
|
|
84
|
+
return packument["dist-tags"]?.[tag];
|
|
85
|
+
} catch {
|
|
86
|
+
return void 0;
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
const resolveTagVersions = async (names, tag) => {
|
|
90
|
+
const resolved = /* @__PURE__ */ new Map();
|
|
91
|
+
await Promise.all(
|
|
92
|
+
[...new Set(names)].map(async (name) => {
|
|
93
|
+
const version = await resolveTagVersion(name, tag);
|
|
94
|
+
if (version !== void 0) {
|
|
95
|
+
resolved.set(name, version);
|
|
96
|
+
}
|
|
97
|
+
})
|
|
98
|
+
);
|
|
99
|
+
return resolved;
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
const resolveDepRange = (range) => {
|
|
103
|
+
if (!range.startsWith("workspace:")) {
|
|
104
|
+
return range;
|
|
105
|
+
}
|
|
106
|
+
const rest = range.slice("workspace:".length);
|
|
107
|
+
if (rest === "" || rest === "*" || rest === "^" || rest === "~") {
|
|
108
|
+
return resolveDistTag();
|
|
109
|
+
}
|
|
110
|
+
return rest;
|
|
111
|
+
};
|
|
112
|
+
const UMBRELLA_REEXPORTED_DEPS = /* @__PURE__ */ new Set(["@lunora/client", "@lunora/do", "@lunora/runtime", "@lunora/server", "@lunora/values"]);
|
|
113
|
+
const UMBRELLA_IMPORT_RE = /(['"])@lunora\/(client|do|runtime|server|values)(\/[^'"]*)?\1/gu;
|
|
114
|
+
const projectUsesUmbrella = (projectRoot) => {
|
|
115
|
+
const packageJsonPath = join(projectRoot, "package.json");
|
|
116
|
+
if (!existsSync(packageJsonPath)) {
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
try {
|
|
120
|
+
const parsed = JSON.parse(readFileSync(packageJsonPath, "utf8"));
|
|
121
|
+
return parsed.dependencies?.lunorash !== void 0 || parsed.devDependencies?.lunorash !== void 0;
|
|
122
|
+
} catch {
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
const rewriteUmbrellaImports = (source) => source.replaceAll(UMBRELLA_IMPORT_RE, (_match, quote, base, subpath) => `${quote}lunorash/${base}${subpath ?? ""}${quote}`);
|
|
127
|
+
const applyDeps = (deps, projectRoot, logger, section = "dependencies", useUmbrella = false) => {
|
|
13
128
|
const entries = Object.entries(deps);
|
|
14
129
|
if (entries.length === 0) {
|
|
15
130
|
return [];
|
|
@@ -23,11 +138,15 @@ const applyDeps = (deps, projectRoot, logger, section = "dependencies") => {
|
|
|
23
138
|
const parsed = JSON.parse(text);
|
|
24
139
|
const added = [];
|
|
25
140
|
for (const [name, range] of entries) {
|
|
141
|
+
if (useUmbrella && UMBRELLA_REEXPORTED_DEPS.has(name)) {
|
|
142
|
+
logger.info(`dep provided by the lunorash umbrella, skipping: ${name}`);
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
26
145
|
if (parsed.dependencies?.[name] !== void 0 || parsed.devDependencies?.[name] !== void 0) {
|
|
27
146
|
logger.info(`dep already present: ${name}`);
|
|
28
147
|
continue;
|
|
29
148
|
}
|
|
30
|
-
const edits = modify(text, [section, name], range, {
|
|
149
|
+
const edits = modify(text, [section, name], resolveDepRange(range), {
|
|
31
150
|
formattingOptions: { insertSpaces: true, tabSize: 4 }
|
|
32
151
|
});
|
|
33
152
|
text = applyEdits(text, edits);
|
|
@@ -148,14 +267,14 @@ const applyBindings = (bindings, projectRoot, logger) => {
|
|
|
148
267
|
}
|
|
149
268
|
return applied;
|
|
150
269
|
};
|
|
151
|
-
const applyItemResources = (manifest, cwd, logger) => {
|
|
270
|
+
const applyItemResources = (manifest, cwd, logger, useUmbrella = false) => {
|
|
152
271
|
const deps = [];
|
|
153
272
|
const bindings = [];
|
|
154
273
|
if (manifest.deps) {
|
|
155
|
-
deps.push(...applyDeps(manifest.deps, cwd, logger));
|
|
274
|
+
deps.push(...applyDeps(manifest.deps, cwd, logger, "dependencies", useUmbrella));
|
|
156
275
|
}
|
|
157
276
|
if (manifest.devDependencies) {
|
|
158
|
-
deps.push(...applyDeps(manifest.devDependencies, cwd, logger, "devDependencies"));
|
|
277
|
+
deps.push(...applyDeps(manifest.devDependencies, cwd, logger, "devDependencies", useUmbrella));
|
|
159
278
|
}
|
|
160
279
|
if (manifest.bindings) {
|
|
161
280
|
bindings.push(...applyBindings(manifest.bindings, cwd, logger));
|
|
@@ -187,8 +306,8 @@ const confirmDepMutation = async (items, options) => {
|
|
|
187
306
|
options.logger.error(`add: stdin is not a TTY and the requested items ${reasonText} — re-run with --yes to confirm`);
|
|
188
307
|
return false;
|
|
189
308
|
}
|
|
190
|
-
const confirmer = options.confirm ??
|
|
191
|
-
const confirmed = await confirmer(`The requested items ${reasonText}. Continue
|
|
309
|
+
const confirmer = options.confirm ?? tuiConfirm;
|
|
310
|
+
const confirmed = await confirmer(`The requested items ${reasonText}. Continue?`);
|
|
192
311
|
if (!confirmed) {
|
|
193
312
|
options.logger.info("add: aborted");
|
|
194
313
|
}
|
|
@@ -267,7 +386,12 @@ const renderDiff = (oldText, newText) => {
|
|
|
267
386
|
return out;
|
|
268
387
|
};
|
|
269
388
|
|
|
270
|
-
const
|
|
389
|
+
const CODE_FILE_RE = /\.[cm]?[jt]sx?$/u;
|
|
390
|
+
const readItemFile = (itemDirectory, file, useUmbrella) => {
|
|
391
|
+
const source = readFileSync(join(itemDirectory, file.from), "utf8");
|
|
392
|
+
return useUmbrella && CODE_FILE_RE.test(file.to) ? rewriteUmbrellaImports(source) : source;
|
|
393
|
+
};
|
|
394
|
+
const reconcileSchemaExtension = (file, itemKey, itemDirectory, projectRoot, logger, diff, useUmbrella) => {
|
|
271
395
|
const schemaPath = join(projectRoot, "lunora", "schema.ts");
|
|
272
396
|
if (diff) {
|
|
273
397
|
logger.info(`~ would merge .extend(${itemKey}.extension) into lunora/schema.ts (and create ${file.to} if absent)`);
|
|
@@ -276,9 +400,13 @@ const reconcileSchemaExtension = (file, itemKey, itemDirectory, projectRoot, log
|
|
|
276
400
|
const destinationPath = join(projectRoot, file.to);
|
|
277
401
|
if (!existsSync(destinationPath)) {
|
|
278
402
|
mkdirSync(dirname(destinationPath), { recursive: true });
|
|
279
|
-
writeFileSync(destinationPath,
|
|
403
|
+
writeFileSync(destinationPath, readItemFile(itemDirectory, file, useUmbrella), "utf8");
|
|
280
404
|
}
|
|
281
|
-
const
|
|
405
|
+
const baseModule = useUmbrella ? "lunorash/server" : "@lunora/server";
|
|
406
|
+
const existingSchema = existsSync(schemaPath) ? readFileSync(schemaPath, "utf8") : `import { defineSchema } from "${baseModule}";
|
|
407
|
+
|
|
408
|
+
export const schema = defineSchema({});
|
|
409
|
+
`;
|
|
282
410
|
const result = insertSchemaExtension(existingSchema, itemKey);
|
|
283
411
|
if (result.ok) {
|
|
284
412
|
mkdirSync(dirname(schemaPath), { recursive: true });
|
|
@@ -308,9 +436,9 @@ const previewWholeFile = (file, current, incoming, exists, logger) => {
|
|
|
308
436
|
logger.info(` ${line}`);
|
|
309
437
|
}
|
|
310
438
|
};
|
|
311
|
-
const reconcileWholeFile = (file, itemKey, itemDirectory, projectRoot, logger, lock, reconcileOptions) => {
|
|
439
|
+
const reconcileWholeFile = (file, itemKey, itemDirectory, projectRoot, logger, lock, reconcileOptions, useUmbrella) => {
|
|
312
440
|
const destinationPath = join(projectRoot, file.to);
|
|
313
|
-
const incoming =
|
|
441
|
+
const incoming = readItemFile(itemDirectory, file, useUmbrella);
|
|
314
442
|
const exists = existsSync(destinationPath);
|
|
315
443
|
const current = exists ? readFileSync(destinationPath, "utf8") : "";
|
|
316
444
|
const write = (message) => {
|
|
@@ -348,11 +476,11 @@ const reconcileWholeFile = (file, itemKey, itemDirectory, projectRoot, logger, l
|
|
|
348
476
|
logger.warn(`conflict: ${file.to} has local edits and an upstream update — wrote ${file.to}.new (use --overwrite to take theirs)`);
|
|
349
477
|
return { kind: "skipped", path: destinationPath };
|
|
350
478
|
};
|
|
351
|
-
const reconcileFile = (file, itemKey, itemDirectory, projectRoot, logger, lock, reconcileOptions = {}) => {
|
|
479
|
+
const reconcileFile = (file, itemKey, itemDirectory, projectRoot, logger, lock, reconcileOptions = {}, useUmbrella = false) => {
|
|
352
480
|
if (file.merge === "schema-extension") {
|
|
353
|
-
return reconcileSchemaExtension(file, itemKey, itemDirectory, projectRoot, logger, reconcileOptions.diff === true);
|
|
481
|
+
return reconcileSchemaExtension(file, itemKey, itemDirectory, projectRoot, logger, reconcileOptions.diff === true, useUmbrella);
|
|
354
482
|
}
|
|
355
|
-
return reconcileWholeFile(file, itemKey, itemDirectory, projectRoot, logger, lock, reconcileOptions);
|
|
483
|
+
return reconcileWholeFile(file, itemKey, itemDirectory, projectRoot, logger, lock, reconcileOptions, useUmbrella);
|
|
356
484
|
};
|
|
357
485
|
const reconcileItems = (items, cwd, logger, reconcileOptions = {}) => {
|
|
358
486
|
const written = [];
|
|
@@ -360,15 +488,16 @@ const reconcileItems = (items, cwd, logger, reconcileOptions = {}) => {
|
|
|
360
488
|
const depsAdded = [];
|
|
361
489
|
const bindingsApplied = [];
|
|
362
490
|
const lock = readLock(cwd);
|
|
491
|
+
const useUmbrella = projectUsesUmbrella(cwd);
|
|
363
492
|
for (const { directory, manifest } of items) {
|
|
364
493
|
for (const file of manifest.files) {
|
|
365
|
-
const outcome = reconcileFile(file, manifest.name, directory, cwd, logger, lock, reconcileOptions);
|
|
494
|
+
const outcome = reconcileFile(file, manifest.name, directory, cwd, logger, lock, reconcileOptions, useUmbrella);
|
|
366
495
|
(outcome.kind === "written" ? written : skipped).push(outcome.path);
|
|
367
496
|
}
|
|
368
497
|
if (reconcileOptions.diff) {
|
|
369
498
|
continue;
|
|
370
499
|
}
|
|
371
|
-
const applied = applyItemResources(manifest, cwd, logger);
|
|
500
|
+
const applied = applyItemResources(manifest, cwd, logger, useUmbrella);
|
|
372
501
|
depsAdded.push(...applied.deps);
|
|
373
502
|
bindingsApplied.push(...applied.bindings);
|
|
374
503
|
}
|
|
@@ -379,7 +508,6 @@ const reconcileItems = (items, cwd, logger, reconcileOptions = {}) => {
|
|
|
379
508
|
};
|
|
380
509
|
|
|
381
510
|
const DEFAULT_SOURCE_BASE = "gh:anolilab/lunora/registry";
|
|
382
|
-
const DEFAULT_SOURCE_REF = "alpha";
|
|
383
511
|
const VALID_ITEM_NAME = /^[A-Za-z0-9][\w-]*$/u;
|
|
384
512
|
const assertSafeItemName = (name) => {
|
|
385
513
|
if (!VALID_ITEM_NAME.test(name)) {
|
|
@@ -431,7 +559,7 @@ const resolveItemDirectory = async (name, options) => {
|
|
|
431
559
|
}, directory };
|
|
432
560
|
}
|
|
433
561
|
const base = options.source ?? DEFAULT_SOURCE_BASE;
|
|
434
|
-
return fetchToStaging(`${base}/${name}#${
|
|
562
|
+
return fetchToStaging(`${base}/${name}#${resolveSourceRef(options.ref)}`, "item", options.logger);
|
|
435
563
|
};
|
|
436
564
|
const resolveRegistryRoot = async (options) => {
|
|
437
565
|
if (options.from !== void 0) {
|
|
@@ -442,7 +570,7 @@ const resolveRegistryRoot = async (options) => {
|
|
|
442
570
|
}, root: options.from };
|
|
443
571
|
}
|
|
444
572
|
const base = options.source ?? DEFAULT_SOURCE_BASE;
|
|
445
|
-
const { cleanup, directory } = await fetchToStaging(`${base}#${
|
|
573
|
+
const { cleanup, directory } = await fetchToStaging(`${base}#${resolveSourceRef(options.ref)}`, "registry", options.logger);
|
|
446
574
|
return { cleanup, root: directory };
|
|
447
575
|
};
|
|
448
576
|
const readManifest = (itemDirectory, name) => {
|
|
@@ -488,6 +616,26 @@ const resolvePlan = async (names, options) => {
|
|
|
488
616
|
const emptyResult = () => {
|
|
489
617
|
return { bindings: [], code: 0, deps: [], skipped: [], written: [] };
|
|
490
618
|
};
|
|
619
|
+
const setBindingField = (manifest, section, match, field, fieldValue) => {
|
|
620
|
+
if (!manifest.bindings) {
|
|
621
|
+
return manifest;
|
|
622
|
+
}
|
|
623
|
+
return {
|
|
624
|
+
...manifest,
|
|
625
|
+
bindings: manifest.bindings.map((binding) => {
|
|
626
|
+
if (binding.path[0] !== section || !Array.isArray(binding.value)) {
|
|
627
|
+
return binding;
|
|
628
|
+
}
|
|
629
|
+
const entries = binding.value;
|
|
630
|
+
return {
|
|
631
|
+
...binding,
|
|
632
|
+
value: entries.map(
|
|
633
|
+
(entry) => typeof entry === "object" && entry !== null && entry[match.key] === match.value ? { ...entry, [field]: fieldValue } : entry
|
|
634
|
+
)
|
|
635
|
+
};
|
|
636
|
+
})
|
|
637
|
+
};
|
|
638
|
+
};
|
|
491
639
|
|
|
492
640
|
const printPlan = (logger, manifest) => {
|
|
493
641
|
const label = manifest.title ?? manifest.description;
|
|
@@ -593,8 +741,12 @@ const runAddCommand = async (options) => {
|
|
|
593
741
|
}
|
|
594
742
|
let cleanups = [];
|
|
595
743
|
try {
|
|
596
|
-
const { cleanups: planCleanups, items } = await resolvePlan(options.names, options);
|
|
744
|
+
const { cleanups: planCleanups, items: resolvedItems } = await resolvePlan(options.names, options);
|
|
597
745
|
cleanups = planCleanups;
|
|
746
|
+
const { transformManifest } = options;
|
|
747
|
+
const items = transformManifest ? resolvedItems.map((item) => {
|
|
748
|
+
return { ...item, manifest: transformManifest(item.manifest) };
|
|
749
|
+
}) : resolvedItems;
|
|
598
750
|
for (const { manifest } of items) {
|
|
599
751
|
printPlan(options.logger, manifest);
|
|
600
752
|
}
|
|
@@ -690,4 +842,4 @@ const runBuildIndexCommand = async (options) => {
|
|
|
690
842
|
return empty;
|
|
691
843
|
};
|
|
692
844
|
|
|
693
|
-
export {
|
|
845
|
+
export { runBuildIndexCommand as a, runRegistryViewCommand as b, resolveTagVersions as c, resolveSourceRef as d, resolveDistTag as e, runListCommand as f, runAddCommand as r, setBindingField as s };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import { STEP_BADGE_NAMES, LunoraReporter } from '@lunora/config';
|
|
1
2
|
import { JsonReporter } from '@visulima/pail/reporter/json';
|
|
2
|
-
import { PrettyReporter } from '@visulima/pail/reporter/pretty';
|
|
3
3
|
import { createPail } from '@visulima/pail/server';
|
|
4
4
|
|
|
5
5
|
const wantJson = () => {
|
|
@@ -7,16 +7,18 @@ const wantJson = () => {
|
|
|
7
7
|
return flag === "1" || flag === "true";
|
|
8
8
|
};
|
|
9
9
|
const buildReporter = () => {
|
|
10
|
-
const Reporter = wantJson() ? JsonReporter :
|
|
10
|
+
const Reporter = wantJson() ? JsonReporter : LunoraReporter;
|
|
11
11
|
return new Reporter();
|
|
12
12
|
};
|
|
13
|
+
const STEP_LOG_TYPES = Object.fromEntries(STEP_BADGE_NAMES.map((name) => [name, { label: name, logLevel: "informational" }]));
|
|
13
14
|
let sharedPail;
|
|
14
15
|
const getPail = () => {
|
|
15
16
|
sharedPail ??= createPail({
|
|
16
17
|
reporters: [buildReporter()],
|
|
17
18
|
scope: ["lunora"],
|
|
18
19
|
stderr: process.stderr,
|
|
19
|
-
stdout: process.stdout
|
|
20
|
+
stdout: process.stdout,
|
|
21
|
+
types: STEP_LOG_TYPES
|
|
20
22
|
});
|
|
21
23
|
return sharedPail;
|
|
22
24
|
};
|
|
@@ -69,5 +71,8 @@ const pail = /* @__PURE__ */ new Proxy({}, {
|
|
|
69
71
|
return typeof value === "function" ? value.bind(instance) : value;
|
|
70
72
|
}
|
|
71
73
|
});
|
|
74
|
+
const logStep = (type, message) => {
|
|
75
|
+
getPail()[type](message);
|
|
76
|
+
};
|
|
72
77
|
|
|
73
|
-
export { createLogger, createStderrLogger, getPail, pail };
|
|
78
|
+
export { createLogger, createStderrLogger, getPail, logStep, pail };
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { spawnSync } from 'node:child_process';
|
|
2
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
3
|
+
import { dirname, join } from '@visulima/path';
|
|
4
|
+
|
|
5
|
+
const FALLBACK = "pnpm";
|
|
6
|
+
const KNOWN_MANAGERS = ["pnpm", "yarn", "npm", "bun"];
|
|
7
|
+
const INSTALL_PREFERENCE = ["pnpm", "bun", "yarn", "npm"];
|
|
8
|
+
const isManagerInstalled = (manager) => {
|
|
9
|
+
try {
|
|
10
|
+
return spawnSync(manager, ["--version"], { stdio: "ignore", timeout: 5e3 }).status === 0;
|
|
11
|
+
} catch {
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
const detectInstalledManagers = (probe = isManagerInstalled) => INSTALL_PREFERENCE.filter((manager) => probe(manager));
|
|
16
|
+
const installArgsFor = (manager) => {
|
|
17
|
+
return { args: ["install"], command: manager };
|
|
18
|
+
};
|
|
19
|
+
const parseDeclaredManager = (declared) => {
|
|
20
|
+
if (typeof declared !== "string") {
|
|
21
|
+
return void 0;
|
|
22
|
+
}
|
|
23
|
+
return KNOWN_MANAGERS.find((manager) => declared.startsWith(`${manager}@`));
|
|
24
|
+
};
|
|
25
|
+
const readDeclaredManager = (directory) => {
|
|
26
|
+
const candidate = join(directory, "package.json");
|
|
27
|
+
if (!existsSync(candidate)) {
|
|
28
|
+
return void 0;
|
|
29
|
+
}
|
|
30
|
+
try {
|
|
31
|
+
const parsed = JSON.parse(readFileSync(candidate, "utf8"));
|
|
32
|
+
return parseDeclaredManager(parsed.packageManager);
|
|
33
|
+
} catch {
|
|
34
|
+
return void 0;
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
const detectPackageManager = (startDirectory) => {
|
|
38
|
+
let directory = startDirectory;
|
|
39
|
+
while (directory && directory !== dirname(directory)) {
|
|
40
|
+
const declared = readDeclaredManager(directory);
|
|
41
|
+
if (declared !== void 0) {
|
|
42
|
+
return declared;
|
|
43
|
+
}
|
|
44
|
+
directory = dirname(directory);
|
|
45
|
+
}
|
|
46
|
+
return FALLBACK;
|
|
47
|
+
};
|
|
48
|
+
const execArgsFor = (manager, command, args) => {
|
|
49
|
+
if (manager === "yarn") {
|
|
50
|
+
return { args: [command, ...args], command: "yarn" };
|
|
51
|
+
}
|
|
52
|
+
if (manager === "bun") {
|
|
53
|
+
return { args: ["x", command, ...args], command: "bun" };
|
|
54
|
+
}
|
|
55
|
+
if (manager === "npm") {
|
|
56
|
+
return { args: ["--", command, ...args], command: "npx" };
|
|
57
|
+
}
|
|
58
|
+
return { args: ["exec", command, ...args], command: "pnpm" };
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
export { detectInstalledManagers as a, detectPackageManager as d, execArgsFor as e, installArgsFor as i };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { quoteIdentifier,
|
|
1
|
+
import { quoteIdentifier, sqlAffinityForKind, frameworkColumnDdl, columnRef, physicalIndexName } from '@lunora/d1/dialect';
|
|
2
2
|
|
|
3
3
|
const validatorKindToSqlType = (kind) => sqlAffinityForKind(kind);
|
|
4
4
|
const renderColumnDefinition = (name, column) => {
|
package/dist/packem_shared/{insertSchemaExtension-BuzF6-t2.mjs → insertSchemaExtension-DAqbfr9Z.mjs}
RENAMED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Project, SyntaxKind } from 'ts-morph';
|
|
1
|
+
import { Project, SyntaxKind, Node } from 'ts-morph';
|
|
2
2
|
|
|
3
3
|
const VALID_JS_IDENTIFIER = /^[A-Za-z_$][\w$]*$/u;
|
|
4
4
|
const startMarker = (key) => `// lunora:add:${key}:start`;
|
|
@@ -12,6 +12,19 @@ const findDefineSchemaCall = (callExpressions) => {
|
|
|
12
12
|
}
|
|
13
13
|
return void 0;
|
|
14
14
|
};
|
|
15
|
+
const outermostChainExpression = (defineSchemaCall) => {
|
|
16
|
+
let node = defineSchemaCall;
|
|
17
|
+
for (let parent = node.getParent(); parent !== void 0; parent = node.getParent()) {
|
|
18
|
+
if (Node.isPropertyAccessExpression(parent) && parent.getExpression() === node) {
|
|
19
|
+
node = parent;
|
|
20
|
+
} else if (Node.isCallExpression(parent) && parent.getExpression() === node) {
|
|
21
|
+
node = parent;
|
|
22
|
+
} else {
|
|
23
|
+
break;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return node;
|
|
27
|
+
};
|
|
15
28
|
const insertSchemaExtension = (source, key) => {
|
|
16
29
|
if (!VALID_JS_IDENTIFIER.test(key)) {
|
|
17
30
|
return { ok: false, reason: "invalid-identifier" };
|
|
@@ -33,15 +46,7 @@ const insertSchemaExtension = (source, key) => {
|
|
|
33
46
|
if (tablesArgument?.getKind() !== SyntaxKind.ObjectLiteralExpression) {
|
|
34
47
|
return { ok: false, reason: "non-object-argument" };
|
|
35
48
|
}
|
|
36
|
-
const
|
|
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();
|
|
49
|
+
const insertAt = outermostChainExpression(defineSchemaCall).getEnd();
|
|
45
50
|
const chainText = `
|
|
46
51
|
${startMarker(key)}
|
|
47
52
|
.extend(${key}.extension)
|