@lunora/cli 1.0.0-alpha.7 → 1.0.0-alpha.9
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 +125 -104
- package/dist/index.d.ts +125 -104
- package/dist/index.mjs +2 -2
- package/dist/packem_chunks/handler.mjs +75 -4
- package/dist/packem_chunks/handler16.mjs +1 -1
- package/dist/packem_chunks/handler18.mjs +1 -1
- package/dist/packem_chunks/planDevCommand.mjs +1 -1
- package/dist/packem_chunks/runInitCommand.mjs +31 -11
- package/dist/packem_chunks/runResetCommand.mjs +1 -1
- package/dist/packem_shared/{COMMANDS-Bn8luojF.mjs → COMMANDS-Dh0bSERi.mjs} +6 -2
- package/dist/packem_shared/{commands-DqsEzojt.mjs → commands-CkkATMMx.mjs} +27 -3
- package/dist/packem_shared/{runAddCommand-G544_v6e.mjs → runAddCommand-DepS9W9W.mjs} +1 -1
- package/dist/packem_shared/storage-Bjo35hPa.mjs +84 -0
- package/dist/packem_shared/{tui-prompts-XHFxlOg5.mjs → tui-prompts-CA9lngSS.mjs} +1 -1
- package/package.json +5 -5
- package/skills/lunora-setup-storage/SKILL.md +7 -3
- package/dist/packem_shared/features-ocSSpZtS.mjs +0 -24
package/dist/bin.mjs
CHANGED
package/dist/index.d.mts
CHANGED
|
@@ -508,16 +508,123 @@ type PackageManagerProbe = (manager: PackageManager) => boolean;
|
|
|
508
508
|
/** A registry item a feature can install. */
|
|
509
509
|
type FeatureItem = "auth" | "auth-auth0" | "auth-clerk" | "mail";
|
|
510
510
|
/** The auth-provider choices offered for `add auth` / the init auth prompt. Each value is a registry item name. */
|
|
511
|
-
|
|
511
|
+
/** A single file the item scaffolds into the project. */
|
|
512
|
+
interface RegistryFile {
|
|
513
|
+
/** Source path inside the item dir (e.g. `schema.ts`). */
|
|
514
|
+
from: string;
|
|
515
|
+
/** Merge strategy. `create-or-skip` writes whole files; `schema-extension` AST-merges schema.ts. */
|
|
516
|
+
merge: "create-or-skip" | "schema-extension";
|
|
517
|
+
/** Destination relative to the project root (e.g. `lunora/ratelimit/index.ts`). */
|
|
518
|
+
to: string;
|
|
519
|
+
}
|
|
520
|
+
/** A wrangler.jsonc binding addition. `path` is the jsonc key path; `value` the value to set. */
|
|
521
|
+
interface RegistryBinding {
|
|
522
|
+
path: ReadonlyArray<string>;
|
|
523
|
+
value: unknown;
|
|
524
|
+
}
|
|
525
|
+
/**
|
|
526
|
+
* An environment variable an item needs. Scaffolded into `.dev.vars` (Workers'
|
|
527
|
+
* local-secrets file) on add — non-secrets get their `value`; secrets get an
|
|
528
|
+
* empty placeholder and a reminder to run `wrangler secret put` for production.
|
|
529
|
+
*/
|
|
530
|
+
interface RegistryEnvVariable {
|
|
531
|
+
/** Human note on what the variable is for. */
|
|
532
|
+
description?: string;
|
|
533
|
+
/** The variable name (e.g. `RESEND_API_KEY`). */
|
|
534
|
+
name: string;
|
|
535
|
+
/** Mark as a secret: never write a value, only a placeholder, and remind about prod. Defaults to `true` when no `value` is given. */
|
|
536
|
+
secret?: boolean;
|
|
537
|
+
/** A default/example value for non-secret vars. */
|
|
538
|
+
value?: string;
|
|
539
|
+
}
|
|
540
|
+
/** The `registry.json` manifest shape. */
|
|
541
|
+
interface RegistryManifest {
|
|
542
|
+
/** wrangler.jsonc additions (best-effort structural edits). */
|
|
543
|
+
bindings?: ReadonlyArray<RegistryBinding>;
|
|
544
|
+
/** npm deps to add to the project package.json (name → version range). */
|
|
545
|
+
deps?: Readonly<Record<string, string>>;
|
|
546
|
+
description?: string;
|
|
547
|
+
/** npm devDependencies to add to the project package.json. */
|
|
548
|
+
devDependencies?: Readonly<Record<string, string>>;
|
|
549
|
+
/** Post-install guidance printed after the item is added (per-item next steps). */
|
|
550
|
+
docs?: string;
|
|
551
|
+
/** Environment variables the item needs; scaffolded into `.dev.vars`. */
|
|
552
|
+
envVars?: ReadonlyArray<RegistryEnvVariable>;
|
|
553
|
+
files: ReadonlyArray<RegistryFile>;
|
|
554
|
+
name: string;
|
|
555
|
+
/** Other registry items this one depends on (resolved transitively, deps first). */
|
|
556
|
+
requires?: ReadonlyArray<string>;
|
|
557
|
+
/** Short human-readable label (distinct from the longer `description`). */
|
|
558
|
+
title?: string;
|
|
559
|
+
}
|
|
560
|
+
interface AddCommandOptions {
|
|
561
|
+
/** Bypass the `--source` safety gate (matches init). */
|
|
562
|
+
allowUnsafeSource?: boolean;
|
|
563
|
+
/** `registry build --check`: verify the index is current instead of rewriting it. */
|
|
564
|
+
check?: boolean;
|
|
565
|
+
/** Inject a confirmer for non-interactive callers / tests. */
|
|
566
|
+
confirm?: (prompt: string) => Promise<boolean>;
|
|
567
|
+
cwd?: string;
|
|
568
|
+
/** Preview the file-level changes (a content diff) and write nothing. */
|
|
569
|
+
diff?: boolean;
|
|
570
|
+
/** Print the plan and stop without writing anything. */
|
|
571
|
+
dryRun?: boolean;
|
|
572
|
+
/** Local registry root (offline / tests). Expects per-item subdirs, each with a `registry.json`. */
|
|
573
|
+
from?: string;
|
|
574
|
+
/** Emit a JSON snapshot of the plan/result. */
|
|
575
|
+
json?: boolean;
|
|
576
|
+
/** `--list`: enumerate available items instead of adding. */
|
|
577
|
+
list?: boolean;
|
|
578
|
+
logger: Logger;
|
|
579
|
+
/** Item names to add (positional args). */
|
|
580
|
+
names: ReadonlyArray<string>;
|
|
581
|
+
/** `registry build` output path for the generated catalog (defaults to the root's `index.json`). */
|
|
582
|
+
out?: string;
|
|
583
|
+
/** Force-overwrite existing files (take the incoming copy) instead of skipping/conflicting. */
|
|
584
|
+
overwrite?: boolean;
|
|
585
|
+
/** Override the git ref (branch, tag, or commit) items are fetched from (default: version-derived); appended to the `source` base when that is set. Ignored when `from` is set. */
|
|
586
|
+
ref?: string;
|
|
587
|
+
/** Override the remote registry source base (default gh:anolilab/lunora/registry). */
|
|
588
|
+
source?: string;
|
|
589
|
+
/**
|
|
590
|
+
* Customize each resolved manifest after it is loaded but before the plan is
|
|
591
|
+
* printed / reconciled — used to inject user-chosen values into otherwise
|
|
592
|
+
* static manifests (e.g. the R2 `bucket_name` the init storage prompt asks
|
|
593
|
+
* for). Applied to every item; return the manifest unchanged to leave it as-is.
|
|
594
|
+
*/
|
|
595
|
+
transformManifest?: (manifest: RegistryManifest) => RegistryManifest;
|
|
596
|
+
/** Skip the package.json mutation confirmation prompt. */
|
|
597
|
+
yes?: boolean;
|
|
598
|
+
}
|
|
599
|
+
interface AddCommandResult {
|
|
600
|
+
/** Bindings written to wrangler.jsonc. */
|
|
601
|
+
bindings: ReadonlyArray<string>;
|
|
602
|
+
code: number;
|
|
603
|
+
/** Deps added to package.json. */
|
|
604
|
+
deps: ReadonlyArray<string>;
|
|
605
|
+
/** Files skipped because they already existed. */
|
|
606
|
+
skipped: ReadonlyArray<string>;
|
|
607
|
+
/** Files written (absolute paths). */
|
|
608
|
+
written: ReadonlyArray<string>;
|
|
609
|
+
}
|
|
610
|
+
/** One resolved item: its parsed manifest plus the (possibly staged) directory it lives in. */
|
|
512
611
|
/**
|
|
513
612
|
* A feature offered in the post-scaffold multi-select. `auth`/`email` carry a
|
|
514
613
|
* sub-prompt or alias; every other value IS the registry item name applied
|
|
515
614
|
* directly (`storage` → the `storage` registry item, etc.).
|
|
516
615
|
*/
|
|
517
616
|
type StackFeature = "auth" | "backup" | "crons" | "email" | "presence" | "ratelimit" | "storage";
|
|
617
|
+
/** Customize a resolved manifest before it is written (e.g. inject the chosen R2 bucket name). */
|
|
618
|
+
type OfferTransformManifest = (manifest: RegistryManifest) => RegistryManifest;
|
|
518
619
|
interface OfferDeps {
|
|
519
|
-
/**
|
|
520
|
-
|
|
620
|
+
/**
|
|
621
|
+
* Apply one or more registry items into the new project; resolves `true` on
|
|
622
|
+
* success. `options.transformManifest` customizes each item's manifest before
|
|
623
|
+
* it is written (used to inject the user-chosen R2 bucket name for storage).
|
|
624
|
+
*/
|
|
625
|
+
apply: (names: ReadonlyArray<string>, options?: {
|
|
626
|
+
transformManifest?: OfferTransformManifest;
|
|
627
|
+
}) => Promise<boolean>;
|
|
521
628
|
/** When `false`, skip all prompts and print the later-setup hint. */
|
|
522
629
|
interactive: boolean;
|
|
523
630
|
logger: Logger;
|
|
@@ -529,6 +636,8 @@ interface OfferDeps {
|
|
|
529
636
|
}>, settings?: {
|
|
530
637
|
defaults?: ReadonlyArray<StackFeature>;
|
|
531
638
|
}) => Promise<StackFeature[]>;
|
|
639
|
+
/** The new project's name — seeds smart defaults like the `project-uploads` bucket name. */
|
|
640
|
+
projectName: string;
|
|
532
641
|
/** Single-select among the auth providers (TTY-backed in production). */
|
|
533
642
|
select: (message: string, options: ReadonlyArray<{
|
|
534
643
|
description?: string;
|
|
@@ -537,14 +646,19 @@ interface OfferDeps {
|
|
|
537
646
|
}>, settings?: {
|
|
538
647
|
default?: FeatureItem;
|
|
539
648
|
}) => Promise<FeatureItem | undefined>;
|
|
649
|
+
/** Single-line text input (TTY-backed in production) — used for the storage bucket-name prompt. */
|
|
650
|
+
text: (message: string, settings?: {
|
|
651
|
+
default?: string;
|
|
652
|
+
placeholder?: string;
|
|
653
|
+
}) => Promise<string>;
|
|
540
654
|
}
|
|
541
655
|
/**
|
|
542
656
|
* Offer the stack features (auth, email, storage, rate limiting, crons,
|
|
543
|
-
* presence, backups) in ONE multi-select after a successful scaffold.
|
|
544
|
-
*
|
|
545
|
-
*
|
|
546
|
-
*
|
|
547
|
-
*
|
|
657
|
+
* presence, backups) in ONE multi-select after a successful scaffold. Auth,
|
|
658
|
+
* email, and storage run a follow-up prompt (provider / destination / bucket
|
|
659
|
+
* name); every other feature value is applied as its registry item directly.
|
|
660
|
+
* Picked items are applied in selection order. Non-interactive: prints how to
|
|
661
|
+
* add them later and changes nothing.
|
|
548
662
|
*/
|
|
549
663
|
type Template = "analog" | "astro" | "next" | "nuxt" | "react-router" | "standalone" | "sveltekit" | "tanstack-start-react" | "tanstack-start-solid";
|
|
550
664
|
interface InitCommandOptions {
|
|
@@ -599,10 +713,10 @@ interface InitCommandOptions {
|
|
|
599
713
|
packageManagerProbe?: PackageManagerProbe;
|
|
600
714
|
/**
|
|
601
715
|
* Inject the offer's prompts (tests). When set, the offer is treated as
|
|
602
|
-
* interactive regardless of TTY, and these drive the feature multi-select
|
|
603
|
-
*
|
|
716
|
+
* interactive regardless of TTY, and these drive the feature multi-select,
|
|
717
|
+
* the auth-provider sub-select, and the storage bucket-name text input.
|
|
604
718
|
*/
|
|
605
|
-
prompt?: Pick<OfferDeps, "multiSelect" | "select">;
|
|
719
|
+
prompt?: Pick<OfferDeps, "multiSelect" | "select" | "text">;
|
|
606
720
|
/**
|
|
607
721
|
* Override the git ref (branch, tag, or commit) the default template source
|
|
608
722
|
* is fetched from. Takes precedence over the version-derived ref. Ignored
|
|
@@ -681,99 +795,6 @@ interface IndexItem extends CatalogItem {
|
|
|
681
795
|
declare const buildRegistryIndex: (root: string) => {
|
|
682
796
|
items: IndexItem[];
|
|
683
797
|
};
|
|
684
|
-
/** A single file the item scaffolds into the project. */
|
|
685
|
-
interface RegistryFile {
|
|
686
|
-
/** Source path inside the item dir (e.g. `schema.ts`). */
|
|
687
|
-
from: string;
|
|
688
|
-
/** Merge strategy. `create-or-skip` writes whole files; `schema-extension` AST-merges schema.ts. */
|
|
689
|
-
merge: "create-or-skip" | "schema-extension";
|
|
690
|
-
/** Destination relative to the project root (e.g. `lunora/ratelimit/index.ts`). */
|
|
691
|
-
to: string;
|
|
692
|
-
}
|
|
693
|
-
/** A wrangler.jsonc binding addition. `path` is the jsonc key path; `value` the value to set. */
|
|
694
|
-
interface RegistryBinding {
|
|
695
|
-
path: ReadonlyArray<string>;
|
|
696
|
-
value: unknown;
|
|
697
|
-
}
|
|
698
|
-
/**
|
|
699
|
-
* An environment variable an item needs. Scaffolded into `.dev.vars` (Workers'
|
|
700
|
-
* local-secrets file) on add — non-secrets get their `value`; secrets get an
|
|
701
|
-
* empty placeholder and a reminder to run `wrangler secret put` for production.
|
|
702
|
-
*/
|
|
703
|
-
interface RegistryEnvVariable {
|
|
704
|
-
/** Human note on what the variable is for. */
|
|
705
|
-
description?: string;
|
|
706
|
-
/** The variable name (e.g. `RESEND_API_KEY`). */
|
|
707
|
-
name: string;
|
|
708
|
-
/** Mark as a secret: never write a value, only a placeholder, and remind about prod. Defaults to `true` when no `value` is given. */
|
|
709
|
-
secret?: boolean;
|
|
710
|
-
/** A default/example value for non-secret vars. */
|
|
711
|
-
value?: string;
|
|
712
|
-
}
|
|
713
|
-
/** The `registry.json` manifest shape. */
|
|
714
|
-
interface RegistryManifest {
|
|
715
|
-
/** wrangler.jsonc additions (best-effort structural edits). */
|
|
716
|
-
bindings?: ReadonlyArray<RegistryBinding>;
|
|
717
|
-
/** npm deps to add to the project package.json (name → version range). */
|
|
718
|
-
deps?: Readonly<Record<string, string>>;
|
|
719
|
-
description?: string;
|
|
720
|
-
/** npm devDependencies to add to the project package.json. */
|
|
721
|
-
devDependencies?: Readonly<Record<string, string>>;
|
|
722
|
-
/** Post-install guidance printed after the item is added (per-item next steps). */
|
|
723
|
-
docs?: string;
|
|
724
|
-
/** Environment variables the item needs; scaffolded into `.dev.vars`. */
|
|
725
|
-
envVars?: ReadonlyArray<RegistryEnvVariable>;
|
|
726
|
-
files: ReadonlyArray<RegistryFile>;
|
|
727
|
-
name: string;
|
|
728
|
-
/** Other registry items this one depends on (resolved transitively, deps first). */
|
|
729
|
-
requires?: ReadonlyArray<string>;
|
|
730
|
-
/** Short human-readable label (distinct from the longer `description`). */
|
|
731
|
-
title?: string;
|
|
732
|
-
}
|
|
733
|
-
interface AddCommandOptions {
|
|
734
|
-
/** Bypass the `--source` safety gate (matches init). */
|
|
735
|
-
allowUnsafeSource?: boolean;
|
|
736
|
-
/** `registry build --check`: verify the index is current instead of rewriting it. */
|
|
737
|
-
check?: boolean;
|
|
738
|
-
/** Inject a confirmer for non-interactive callers / tests. */
|
|
739
|
-
confirm?: (prompt: string) => Promise<boolean>;
|
|
740
|
-
cwd?: string;
|
|
741
|
-
/** Preview the file-level changes (a content diff) and write nothing. */
|
|
742
|
-
diff?: boolean;
|
|
743
|
-
/** Print the plan and stop without writing anything. */
|
|
744
|
-
dryRun?: boolean;
|
|
745
|
-
/** Local registry root (offline / tests). Expects per-item subdirs, each with a `registry.json`. */
|
|
746
|
-
from?: string;
|
|
747
|
-
/** Emit a JSON snapshot of the plan/result. */
|
|
748
|
-
json?: boolean;
|
|
749
|
-
/** `--list`: enumerate available items instead of adding. */
|
|
750
|
-
list?: boolean;
|
|
751
|
-
logger: Logger;
|
|
752
|
-
/** Item names to add (positional args). */
|
|
753
|
-
names: ReadonlyArray<string>;
|
|
754
|
-
/** `registry build` output path for the generated catalog (defaults to the root's `index.json`). */
|
|
755
|
-
out?: string;
|
|
756
|
-
/** Force-overwrite existing files (take the incoming copy) instead of skipping/conflicting. */
|
|
757
|
-
overwrite?: boolean;
|
|
758
|
-
/** Override the git ref (branch, tag, or commit) items are fetched from (default: version-derived); appended to the `source` base when that is set. Ignored when `from` is set. */
|
|
759
|
-
ref?: string;
|
|
760
|
-
/** Override the remote registry source base (default gh:anolilab/lunora/registry). */
|
|
761
|
-
source?: string;
|
|
762
|
-
/** Skip the package.json mutation confirmation prompt. */
|
|
763
|
-
yes?: boolean;
|
|
764
|
-
}
|
|
765
|
-
interface AddCommandResult {
|
|
766
|
-
/** Bindings written to wrangler.jsonc. */
|
|
767
|
-
bindings: ReadonlyArray<string>;
|
|
768
|
-
code: number;
|
|
769
|
-
/** Deps added to package.json. */
|
|
770
|
-
deps: ReadonlyArray<string>;
|
|
771
|
-
/** Files skipped because they already existed. */
|
|
772
|
-
skipped: ReadonlyArray<string>;
|
|
773
|
-
/** Files written (absolute paths). */
|
|
774
|
-
written: ReadonlyArray<string>;
|
|
775
|
-
}
|
|
776
|
-
/** One resolved item: its parsed manifest plus the (possibly staged) directory it lives in. */
|
|
777
798
|
/** `lunora registry add` (one or more item names): scaffold items into the project. */
|
|
778
799
|
declare const runAddCommand: (options: AddCommandOptions) => Promise<AddCommandResult>;
|
|
779
800
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -508,16 +508,123 @@ type PackageManagerProbe = (manager: PackageManager) => boolean;
|
|
|
508
508
|
/** A registry item a feature can install. */
|
|
509
509
|
type FeatureItem = "auth" | "auth-auth0" | "auth-clerk" | "mail";
|
|
510
510
|
/** The auth-provider choices offered for `add auth` / the init auth prompt. Each value is a registry item name. */
|
|
511
|
-
|
|
511
|
+
/** A single file the item scaffolds into the project. */
|
|
512
|
+
interface RegistryFile {
|
|
513
|
+
/** Source path inside the item dir (e.g. `schema.ts`). */
|
|
514
|
+
from: string;
|
|
515
|
+
/** Merge strategy. `create-or-skip` writes whole files; `schema-extension` AST-merges schema.ts. */
|
|
516
|
+
merge: "create-or-skip" | "schema-extension";
|
|
517
|
+
/** Destination relative to the project root (e.g. `lunora/ratelimit/index.ts`). */
|
|
518
|
+
to: string;
|
|
519
|
+
}
|
|
520
|
+
/** A wrangler.jsonc binding addition. `path` is the jsonc key path; `value` the value to set. */
|
|
521
|
+
interface RegistryBinding {
|
|
522
|
+
path: ReadonlyArray<string>;
|
|
523
|
+
value: unknown;
|
|
524
|
+
}
|
|
525
|
+
/**
|
|
526
|
+
* An environment variable an item needs. Scaffolded into `.dev.vars` (Workers'
|
|
527
|
+
* local-secrets file) on add — non-secrets get their `value`; secrets get an
|
|
528
|
+
* empty placeholder and a reminder to run `wrangler secret put` for production.
|
|
529
|
+
*/
|
|
530
|
+
interface RegistryEnvVariable {
|
|
531
|
+
/** Human note on what the variable is for. */
|
|
532
|
+
description?: string;
|
|
533
|
+
/** The variable name (e.g. `RESEND_API_KEY`). */
|
|
534
|
+
name: string;
|
|
535
|
+
/** Mark as a secret: never write a value, only a placeholder, and remind about prod. Defaults to `true` when no `value` is given. */
|
|
536
|
+
secret?: boolean;
|
|
537
|
+
/** A default/example value for non-secret vars. */
|
|
538
|
+
value?: string;
|
|
539
|
+
}
|
|
540
|
+
/** The `registry.json` manifest shape. */
|
|
541
|
+
interface RegistryManifest {
|
|
542
|
+
/** wrangler.jsonc additions (best-effort structural edits). */
|
|
543
|
+
bindings?: ReadonlyArray<RegistryBinding>;
|
|
544
|
+
/** npm deps to add to the project package.json (name → version range). */
|
|
545
|
+
deps?: Readonly<Record<string, string>>;
|
|
546
|
+
description?: string;
|
|
547
|
+
/** npm devDependencies to add to the project package.json. */
|
|
548
|
+
devDependencies?: Readonly<Record<string, string>>;
|
|
549
|
+
/** Post-install guidance printed after the item is added (per-item next steps). */
|
|
550
|
+
docs?: string;
|
|
551
|
+
/** Environment variables the item needs; scaffolded into `.dev.vars`. */
|
|
552
|
+
envVars?: ReadonlyArray<RegistryEnvVariable>;
|
|
553
|
+
files: ReadonlyArray<RegistryFile>;
|
|
554
|
+
name: string;
|
|
555
|
+
/** Other registry items this one depends on (resolved transitively, deps first). */
|
|
556
|
+
requires?: ReadonlyArray<string>;
|
|
557
|
+
/** Short human-readable label (distinct from the longer `description`). */
|
|
558
|
+
title?: string;
|
|
559
|
+
}
|
|
560
|
+
interface AddCommandOptions {
|
|
561
|
+
/** Bypass the `--source` safety gate (matches init). */
|
|
562
|
+
allowUnsafeSource?: boolean;
|
|
563
|
+
/** `registry build --check`: verify the index is current instead of rewriting it. */
|
|
564
|
+
check?: boolean;
|
|
565
|
+
/** Inject a confirmer for non-interactive callers / tests. */
|
|
566
|
+
confirm?: (prompt: string) => Promise<boolean>;
|
|
567
|
+
cwd?: string;
|
|
568
|
+
/** Preview the file-level changes (a content diff) and write nothing. */
|
|
569
|
+
diff?: boolean;
|
|
570
|
+
/** Print the plan and stop without writing anything. */
|
|
571
|
+
dryRun?: boolean;
|
|
572
|
+
/** Local registry root (offline / tests). Expects per-item subdirs, each with a `registry.json`. */
|
|
573
|
+
from?: string;
|
|
574
|
+
/** Emit a JSON snapshot of the plan/result. */
|
|
575
|
+
json?: boolean;
|
|
576
|
+
/** `--list`: enumerate available items instead of adding. */
|
|
577
|
+
list?: boolean;
|
|
578
|
+
logger: Logger;
|
|
579
|
+
/** Item names to add (positional args). */
|
|
580
|
+
names: ReadonlyArray<string>;
|
|
581
|
+
/** `registry build` output path for the generated catalog (defaults to the root's `index.json`). */
|
|
582
|
+
out?: string;
|
|
583
|
+
/** Force-overwrite existing files (take the incoming copy) instead of skipping/conflicting. */
|
|
584
|
+
overwrite?: boolean;
|
|
585
|
+
/** Override the git ref (branch, tag, or commit) items are fetched from (default: version-derived); appended to the `source` base when that is set. Ignored when `from` is set. */
|
|
586
|
+
ref?: string;
|
|
587
|
+
/** Override the remote registry source base (default gh:anolilab/lunora/registry). */
|
|
588
|
+
source?: string;
|
|
589
|
+
/**
|
|
590
|
+
* Customize each resolved manifest after it is loaded but before the plan is
|
|
591
|
+
* printed / reconciled — used to inject user-chosen values into otherwise
|
|
592
|
+
* static manifests (e.g. the R2 `bucket_name` the init storage prompt asks
|
|
593
|
+
* for). Applied to every item; return the manifest unchanged to leave it as-is.
|
|
594
|
+
*/
|
|
595
|
+
transformManifest?: (manifest: RegistryManifest) => RegistryManifest;
|
|
596
|
+
/** Skip the package.json mutation confirmation prompt. */
|
|
597
|
+
yes?: boolean;
|
|
598
|
+
}
|
|
599
|
+
interface AddCommandResult {
|
|
600
|
+
/** Bindings written to wrangler.jsonc. */
|
|
601
|
+
bindings: ReadonlyArray<string>;
|
|
602
|
+
code: number;
|
|
603
|
+
/** Deps added to package.json. */
|
|
604
|
+
deps: ReadonlyArray<string>;
|
|
605
|
+
/** Files skipped because they already existed. */
|
|
606
|
+
skipped: ReadonlyArray<string>;
|
|
607
|
+
/** Files written (absolute paths). */
|
|
608
|
+
written: ReadonlyArray<string>;
|
|
609
|
+
}
|
|
610
|
+
/** One resolved item: its parsed manifest plus the (possibly staged) directory it lives in. */
|
|
512
611
|
/**
|
|
513
612
|
* A feature offered in the post-scaffold multi-select. `auth`/`email` carry a
|
|
514
613
|
* sub-prompt or alias; every other value IS the registry item name applied
|
|
515
614
|
* directly (`storage` → the `storage` registry item, etc.).
|
|
516
615
|
*/
|
|
517
616
|
type StackFeature = "auth" | "backup" | "crons" | "email" | "presence" | "ratelimit" | "storage";
|
|
617
|
+
/** Customize a resolved manifest before it is written (e.g. inject the chosen R2 bucket name). */
|
|
618
|
+
type OfferTransformManifest = (manifest: RegistryManifest) => RegistryManifest;
|
|
518
619
|
interface OfferDeps {
|
|
519
|
-
/**
|
|
520
|
-
|
|
620
|
+
/**
|
|
621
|
+
* Apply one or more registry items into the new project; resolves `true` on
|
|
622
|
+
* success. `options.transformManifest` customizes each item's manifest before
|
|
623
|
+
* it is written (used to inject the user-chosen R2 bucket name for storage).
|
|
624
|
+
*/
|
|
625
|
+
apply: (names: ReadonlyArray<string>, options?: {
|
|
626
|
+
transformManifest?: OfferTransformManifest;
|
|
627
|
+
}) => Promise<boolean>;
|
|
521
628
|
/** When `false`, skip all prompts and print the later-setup hint. */
|
|
522
629
|
interactive: boolean;
|
|
523
630
|
logger: Logger;
|
|
@@ -529,6 +636,8 @@ interface OfferDeps {
|
|
|
529
636
|
}>, settings?: {
|
|
530
637
|
defaults?: ReadonlyArray<StackFeature>;
|
|
531
638
|
}) => Promise<StackFeature[]>;
|
|
639
|
+
/** The new project's name — seeds smart defaults like the `project-uploads` bucket name. */
|
|
640
|
+
projectName: string;
|
|
532
641
|
/** Single-select among the auth providers (TTY-backed in production). */
|
|
533
642
|
select: (message: string, options: ReadonlyArray<{
|
|
534
643
|
description?: string;
|
|
@@ -537,14 +646,19 @@ interface OfferDeps {
|
|
|
537
646
|
}>, settings?: {
|
|
538
647
|
default?: FeatureItem;
|
|
539
648
|
}) => Promise<FeatureItem | undefined>;
|
|
649
|
+
/** Single-line text input (TTY-backed in production) — used for the storage bucket-name prompt. */
|
|
650
|
+
text: (message: string, settings?: {
|
|
651
|
+
default?: string;
|
|
652
|
+
placeholder?: string;
|
|
653
|
+
}) => Promise<string>;
|
|
540
654
|
}
|
|
541
655
|
/**
|
|
542
656
|
* Offer the stack features (auth, email, storage, rate limiting, crons,
|
|
543
|
-
* presence, backups) in ONE multi-select after a successful scaffold.
|
|
544
|
-
*
|
|
545
|
-
*
|
|
546
|
-
*
|
|
547
|
-
*
|
|
657
|
+
* presence, backups) in ONE multi-select after a successful scaffold. Auth,
|
|
658
|
+
* email, and storage run a follow-up prompt (provider / destination / bucket
|
|
659
|
+
* name); every other feature value is applied as its registry item directly.
|
|
660
|
+
* Picked items are applied in selection order. Non-interactive: prints how to
|
|
661
|
+
* add them later and changes nothing.
|
|
548
662
|
*/
|
|
549
663
|
type Template = "analog" | "astro" | "next" | "nuxt" | "react-router" | "standalone" | "sveltekit" | "tanstack-start-react" | "tanstack-start-solid";
|
|
550
664
|
interface InitCommandOptions {
|
|
@@ -599,10 +713,10 @@ interface InitCommandOptions {
|
|
|
599
713
|
packageManagerProbe?: PackageManagerProbe;
|
|
600
714
|
/**
|
|
601
715
|
* Inject the offer's prompts (tests). When set, the offer is treated as
|
|
602
|
-
* interactive regardless of TTY, and these drive the feature multi-select
|
|
603
|
-
*
|
|
716
|
+
* interactive regardless of TTY, and these drive the feature multi-select,
|
|
717
|
+
* the auth-provider sub-select, and the storage bucket-name text input.
|
|
604
718
|
*/
|
|
605
|
-
prompt?: Pick<OfferDeps, "multiSelect" | "select">;
|
|
719
|
+
prompt?: Pick<OfferDeps, "multiSelect" | "select" | "text">;
|
|
606
720
|
/**
|
|
607
721
|
* Override the git ref (branch, tag, or commit) the default template source
|
|
608
722
|
* is fetched from. Takes precedence over the version-derived ref. Ignored
|
|
@@ -681,99 +795,6 @@ interface IndexItem extends CatalogItem {
|
|
|
681
795
|
declare const buildRegistryIndex: (root: string) => {
|
|
682
796
|
items: IndexItem[];
|
|
683
797
|
};
|
|
684
|
-
/** A single file the item scaffolds into the project. */
|
|
685
|
-
interface RegistryFile {
|
|
686
|
-
/** Source path inside the item dir (e.g. `schema.ts`). */
|
|
687
|
-
from: string;
|
|
688
|
-
/** Merge strategy. `create-or-skip` writes whole files; `schema-extension` AST-merges schema.ts. */
|
|
689
|
-
merge: "create-or-skip" | "schema-extension";
|
|
690
|
-
/** Destination relative to the project root (e.g. `lunora/ratelimit/index.ts`). */
|
|
691
|
-
to: string;
|
|
692
|
-
}
|
|
693
|
-
/** A wrangler.jsonc binding addition. `path` is the jsonc key path; `value` the value to set. */
|
|
694
|
-
interface RegistryBinding {
|
|
695
|
-
path: ReadonlyArray<string>;
|
|
696
|
-
value: unknown;
|
|
697
|
-
}
|
|
698
|
-
/**
|
|
699
|
-
* An environment variable an item needs. Scaffolded into `.dev.vars` (Workers'
|
|
700
|
-
* local-secrets file) on add — non-secrets get their `value`; secrets get an
|
|
701
|
-
* empty placeholder and a reminder to run `wrangler secret put` for production.
|
|
702
|
-
*/
|
|
703
|
-
interface RegistryEnvVariable {
|
|
704
|
-
/** Human note on what the variable is for. */
|
|
705
|
-
description?: string;
|
|
706
|
-
/** The variable name (e.g. `RESEND_API_KEY`). */
|
|
707
|
-
name: string;
|
|
708
|
-
/** Mark as a secret: never write a value, only a placeholder, and remind about prod. Defaults to `true` when no `value` is given. */
|
|
709
|
-
secret?: boolean;
|
|
710
|
-
/** A default/example value for non-secret vars. */
|
|
711
|
-
value?: string;
|
|
712
|
-
}
|
|
713
|
-
/** The `registry.json` manifest shape. */
|
|
714
|
-
interface RegistryManifest {
|
|
715
|
-
/** wrangler.jsonc additions (best-effort structural edits). */
|
|
716
|
-
bindings?: ReadonlyArray<RegistryBinding>;
|
|
717
|
-
/** npm deps to add to the project package.json (name → version range). */
|
|
718
|
-
deps?: Readonly<Record<string, string>>;
|
|
719
|
-
description?: string;
|
|
720
|
-
/** npm devDependencies to add to the project package.json. */
|
|
721
|
-
devDependencies?: Readonly<Record<string, string>>;
|
|
722
|
-
/** Post-install guidance printed after the item is added (per-item next steps). */
|
|
723
|
-
docs?: string;
|
|
724
|
-
/** Environment variables the item needs; scaffolded into `.dev.vars`. */
|
|
725
|
-
envVars?: ReadonlyArray<RegistryEnvVariable>;
|
|
726
|
-
files: ReadonlyArray<RegistryFile>;
|
|
727
|
-
name: string;
|
|
728
|
-
/** Other registry items this one depends on (resolved transitively, deps first). */
|
|
729
|
-
requires?: ReadonlyArray<string>;
|
|
730
|
-
/** Short human-readable label (distinct from the longer `description`). */
|
|
731
|
-
title?: string;
|
|
732
|
-
}
|
|
733
|
-
interface AddCommandOptions {
|
|
734
|
-
/** Bypass the `--source` safety gate (matches init). */
|
|
735
|
-
allowUnsafeSource?: boolean;
|
|
736
|
-
/** `registry build --check`: verify the index is current instead of rewriting it. */
|
|
737
|
-
check?: boolean;
|
|
738
|
-
/** Inject a confirmer for non-interactive callers / tests. */
|
|
739
|
-
confirm?: (prompt: string) => Promise<boolean>;
|
|
740
|
-
cwd?: string;
|
|
741
|
-
/** Preview the file-level changes (a content diff) and write nothing. */
|
|
742
|
-
diff?: boolean;
|
|
743
|
-
/** Print the plan and stop without writing anything. */
|
|
744
|
-
dryRun?: boolean;
|
|
745
|
-
/** Local registry root (offline / tests). Expects per-item subdirs, each with a `registry.json`. */
|
|
746
|
-
from?: string;
|
|
747
|
-
/** Emit a JSON snapshot of the plan/result. */
|
|
748
|
-
json?: boolean;
|
|
749
|
-
/** `--list`: enumerate available items instead of adding. */
|
|
750
|
-
list?: boolean;
|
|
751
|
-
logger: Logger;
|
|
752
|
-
/** Item names to add (positional args). */
|
|
753
|
-
names: ReadonlyArray<string>;
|
|
754
|
-
/** `registry build` output path for the generated catalog (defaults to the root's `index.json`). */
|
|
755
|
-
out?: string;
|
|
756
|
-
/** Force-overwrite existing files (take the incoming copy) instead of skipping/conflicting. */
|
|
757
|
-
overwrite?: boolean;
|
|
758
|
-
/** Override the git ref (branch, tag, or commit) items are fetched from (default: version-derived); appended to the `source` base when that is set. Ignored when `from` is set. */
|
|
759
|
-
ref?: string;
|
|
760
|
-
/** Override the remote registry source base (default gh:anolilab/lunora/registry). */
|
|
761
|
-
source?: string;
|
|
762
|
-
/** Skip the package.json mutation confirmation prompt. */
|
|
763
|
-
yes?: boolean;
|
|
764
|
-
}
|
|
765
|
-
interface AddCommandResult {
|
|
766
|
-
/** Bindings written to wrangler.jsonc. */
|
|
767
|
-
bindings: ReadonlyArray<string>;
|
|
768
|
-
code: number;
|
|
769
|
-
/** Deps added to package.json. */
|
|
770
|
-
deps: ReadonlyArray<string>;
|
|
771
|
-
/** Files skipped because they already existed. */
|
|
772
|
-
skipped: ReadonlyArray<string>;
|
|
773
|
-
/** Files written (absolute paths). */
|
|
774
|
-
written: ReadonlyArray<string>;
|
|
775
|
-
}
|
|
776
|
-
/** One resolved item: its parsed manifest plus the (possibly staged) directory it lives in. */
|
|
777
798
|
/** `lunora registry add` (one or more item names): scaffold items into the project. */
|
|
778
799
|
declare const runAddCommand: (options: AddCommandOptions) => Promise<AddCommandResult>;
|
|
779
800
|
/**
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { COMMANDS, VERSION, runCli } from './packem_shared/COMMANDS-
|
|
1
|
+
export { COMMANDS, VERSION, runCli } from './packem_shared/COMMANDS-Dh0bSERi.mjs';
|
|
2
2
|
export { runCodegenCommand } from './packem_chunks/runCodegenCommand.mjs';
|
|
3
3
|
export { DEFAULT_IMPORT_BATCH_SIZE, runExportCommand, runImportCommand } from './packem_shared/DEFAULT_IMPORT_BATCH_SIZE-Ck-2bU08.mjs';
|
|
4
4
|
export { runDeployCommand } from './packem_chunks/runDeployCommand.mjs';
|
|
@@ -16,4 +16,4 @@ export { createRecordingSpawner, defaultSpawner } from './packem_shared/createRe
|
|
|
16
16
|
export { default as parseManifest } from './packem_shared/parseManifest--vZf2FY1.mjs';
|
|
17
17
|
export { REQUIRED_COMPATIBILITY_DATE, REQUIRED_FLAG, validateWranglerProject as validateWrangler, validateWranglerConfig } from '@lunora/config';
|
|
18
18
|
export { buildRegistryIndex } from './packem_shared/buildRegistryIndex-BcYe607_.mjs';
|
|
19
|
-
export { r as runAddCommand, a as runBuildIndexCommand, b as runRegistryViewCommand } from './packem_shared/commands-
|
|
19
|
+
export { r as runAddCommand, a as runBuildIndexCommand, b as runRegistryViewCommand } from './packem_shared/commands-CkkATMMx.mjs';
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { existsSync } from 'node:fs';
|
|
2
2
|
import { findWranglerFile } from '@lunora/config';
|
|
3
|
-
import { join } from '@visulima/path';
|
|
3
|
+
import { join, basename } from '@visulima/path';
|
|
4
4
|
import { d as defineHandler } from '../packem_shared/command-BDXcJCCJ.mjs';
|
|
5
|
-
import { t as tuiSelect } from '../packem_shared/tui-prompts-
|
|
6
|
-
import { n as normalizeFeature, E as EMAIL_ITEM, D as DEFAULT_AUTH_ITEM,
|
|
7
|
-
import { r as runAddCommand } from '../packem_shared/commands-
|
|
5
|
+
import { t as tuiText, a as tuiSelect } from '../packem_shared/tui-prompts-CA9lngSS.mjs';
|
|
6
|
+
import { n as normalizeFeature, E as EMAIL_ITEM, s as sanitizeBucketName, d as deriveBucketName, p as promptBucketName, r as resolveTypedDestination, M as MAIL_DESTINATION_PROMPT, a as sanitizeDatabaseName, b as deriveDatabaseName, c as promptDatabaseName, D as DEFAULT_AUTH_ITEM, e as promptAuthProvider, A as AUTH_PROVIDER_OPTIONS, w as withStorageBucketName, f as withMailDestination, g as withAuthDatabaseName } from '../packem_shared/storage-Bjo35hPa.mjs';
|
|
7
|
+
import { r as runAddCommand } from '../packem_shared/commands-CkkATMMx.mjs';
|
|
8
8
|
|
|
9
9
|
const providerToItem = (provider) => {
|
|
10
10
|
const value = provider.trim().toLowerCase();
|
|
@@ -28,6 +28,51 @@ const resolveAuthItem = async (options) => {
|
|
|
28
28
|
const select = options.promptSelect ?? ((message, choices, settings) => tuiSelect(message, choices, settings));
|
|
29
29
|
return promptAuthProvider(select);
|
|
30
30
|
};
|
|
31
|
+
const textPrompt = (options) => options.promptText ?? ((message, settings) => tuiText(message, settings));
|
|
32
|
+
const resolveStorageBucketName = async (options) => {
|
|
33
|
+
const projectName = basename(options.cwd ?? process.cwd());
|
|
34
|
+
if (options.bucket !== void 0 && options.bucket !== "") {
|
|
35
|
+
const sanitized = sanitizeBucketName(options.bucket);
|
|
36
|
+
if (sanitized !== void 0) {
|
|
37
|
+
return sanitized;
|
|
38
|
+
}
|
|
39
|
+
const fallback = deriveBucketName(projectName);
|
|
40
|
+
options.logger.warn(`add: "${options.bucket}" isn't a valid R2 bucket name (lowercase alphanumeric + hyphens, 3–63 chars) — using "${fallback}".`);
|
|
41
|
+
return fallback;
|
|
42
|
+
}
|
|
43
|
+
if (options.yes === true) {
|
|
44
|
+
return deriveBucketName(projectName);
|
|
45
|
+
}
|
|
46
|
+
return promptBucketName(textPrompt(options), projectName);
|
|
47
|
+
};
|
|
48
|
+
const resolveMailDestination = async (options) => {
|
|
49
|
+
const warn = (message) => {
|
|
50
|
+
options.logger.warn(`add: ${message}`);
|
|
51
|
+
};
|
|
52
|
+
if (options.mailTo !== void 0 && options.mailTo !== "") {
|
|
53
|
+
return resolveTypedDestination(options.mailTo, warn);
|
|
54
|
+
}
|
|
55
|
+
if (options.yes === true) {
|
|
56
|
+
return void 0;
|
|
57
|
+
}
|
|
58
|
+
return resolveTypedDestination(await textPrompt(options)(MAIL_DESTINATION_PROMPT, { placeholder: "you@yourdomain.com" }), warn);
|
|
59
|
+
};
|
|
60
|
+
const resolveAuthDatabaseName = async (options) => {
|
|
61
|
+
const projectName = basename(options.cwd ?? process.cwd());
|
|
62
|
+
if (options.db !== void 0 && options.db !== "") {
|
|
63
|
+
const sanitized = sanitizeDatabaseName(options.db);
|
|
64
|
+
if (sanitized !== void 0) {
|
|
65
|
+
return sanitized;
|
|
66
|
+
}
|
|
67
|
+
const fallback = deriveDatabaseName(projectName);
|
|
68
|
+
options.logger.warn(`add: "${options.db}" isn't a usable D1 database name — using "${fallback}".`);
|
|
69
|
+
return fallback;
|
|
70
|
+
}
|
|
71
|
+
if (options.yes === true) {
|
|
72
|
+
return deriveDatabaseName(projectName);
|
|
73
|
+
}
|
|
74
|
+
return promptDatabaseName(textPrompt(options), projectName);
|
|
75
|
+
};
|
|
31
76
|
const resolveFeatureItems = async (feature, options) => {
|
|
32
77
|
if (feature.kind === "auth") {
|
|
33
78
|
return [await resolveAuthItem(options)];
|
|
@@ -49,6 +94,28 @@ const runAddFeature = async (options) => {
|
|
|
49
94
|
return { code: 1, items: [] };
|
|
50
95
|
}
|
|
51
96
|
const items = await resolveFeatureItems(feature, options);
|
|
97
|
+
const transforms = [];
|
|
98
|
+
if (items.includes("storage")) {
|
|
99
|
+
const bucketName = await resolveStorageBucketName(options);
|
|
100
|
+
transforms.push((manifest) => withStorageBucketName(manifest, bucketName));
|
|
101
|
+
}
|
|
102
|
+
if (items.includes("mail")) {
|
|
103
|
+
const destination = await resolveMailDestination(options);
|
|
104
|
+
if (destination !== void 0) {
|
|
105
|
+
transforms.push((manifest) => withMailDestination(manifest, destination));
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
if (items.some((name) => name === "auth" || name.startsWith("auth-"))) {
|
|
109
|
+
const databaseName = await resolveAuthDatabaseName(options);
|
|
110
|
+
transforms.push((manifest) => withAuthDatabaseName(manifest, databaseName));
|
|
111
|
+
}
|
|
112
|
+
const transformManifest = transforms.length > 0 ? (manifest) => {
|
|
113
|
+
let result2 = manifest;
|
|
114
|
+
for (const transform of transforms) {
|
|
115
|
+
result2 = transform(result2);
|
|
116
|
+
}
|
|
117
|
+
return result2;
|
|
118
|
+
} : void 0;
|
|
52
119
|
const result = await runAddCommand({
|
|
53
120
|
allowUnsafeSource: options.allowUnsafeSource,
|
|
54
121
|
cwd,
|
|
@@ -57,6 +124,7 @@ const runAddFeature = async (options) => {
|
|
|
57
124
|
names: [...items],
|
|
58
125
|
ref: options.ref,
|
|
59
126
|
source: options.source,
|
|
127
|
+
transformManifest,
|
|
60
128
|
yes: true
|
|
61
129
|
});
|
|
62
130
|
return { code: result.code, items };
|
|
@@ -64,10 +132,13 @@ const runAddFeature = async (options) => {
|
|
|
64
132
|
const execute = defineHandler(async ({ argument, cwd, logger, options }) => {
|
|
65
133
|
const result = await runAddFeature({
|
|
66
134
|
allowUnsafeSource: options.allowUnsafeSource === true,
|
|
135
|
+
bucket: options.bucket,
|
|
67
136
|
cwd,
|
|
137
|
+
db: options.db,
|
|
68
138
|
feature: argument[0],
|
|
69
139
|
from: options.from,
|
|
70
140
|
logger,
|
|
141
|
+
mailTo: options.mailTo,
|
|
71
142
|
provider: options.provider,
|
|
72
143
|
ref: options.ref,
|
|
73
144
|
source: options.source,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { d as defineHandler } from '../packem_shared/command-BDXcJCCJ.mjs';
|
|
2
|
-
import { r as runAddCommand, b as runRegistryViewCommand, a as runBuildIndexCommand } from '../packem_shared/commands-
|
|
2
|
+
import { r as runAddCommand, b as runRegistryViewCommand, a as runBuildIndexCommand } from '../packem_shared/commands-CkkATMMx.mjs';
|
|
3
3
|
|
|
4
4
|
const execute = defineHandler(({ argument, cwd, logger, options }) => {
|
|
5
5
|
const subcommand = argument[0];
|
|
@@ -7,7 +7,7 @@ import { join } from '@visulima/path';
|
|
|
7
7
|
import { Project } from 'ts-morph';
|
|
8
8
|
import { d as defineHandler } from '../packem_shared/command-BDXcJCCJ.mjs';
|
|
9
9
|
import { a as resolveProductionWorkerUrl } from '../packem_shared/resolve-target-qbsJ_5sF.mjs';
|
|
10
|
-
import {
|
|
10
|
+
import { b as tuiConfirm } from '../packem_shared/tui-prompts-CA9lngSS.mjs';
|
|
11
11
|
import { runImportCommand } from '../packem_shared/DEFAULT_IMPORT_BATCH_SIZE-Ck-2bU08.mjs';
|
|
12
12
|
import { runResetCommand } from './runResetCommand.mjs';
|
|
13
13
|
|
|
@@ -9,7 +9,7 @@ import { d as detectPackageManager, e as execArgsFor } from '../packem_shared/de
|
|
|
9
9
|
import { createServer, request } from 'node:http';
|
|
10
10
|
import { connect } from 'node:net';
|
|
11
11
|
import { loadStudioAssets, studioAssetsStamp, renderStudioHtml, resolveAdminToken, SCHEMA_EDIT_ENDPOINT, POLICY_SCAFFOLD_ENDPOINT, SEED_ENDPOINT, serveJsonHandler, handleSchemaEditRequest, handlePolicyScaffoldRequest, handleSeedRequest } from '@lunora/config/studio-host';
|
|
12
|
-
import { c as createTuiConfirm } from '../packem_shared/tui-prompts-
|
|
12
|
+
import { c as createTuiConfirm } from '../packem_shared/tui-prompts-CA9lngSS.mjs';
|
|
13
13
|
|
|
14
14
|
const DEFAULT_DEBOUNCE_MS = 100;
|
|
15
15
|
const PATH_SEGMENT_SEPARATOR = /[/\\]/u;
|
|
@@ -10,10 +10,10 @@ import { d as defineHandler } from '../packem_shared/command-BDXcJCCJ.mjs';
|
|
|
10
10
|
import { a as detectInstalledManagers, i as installArgsFor } from '../packem_shared/detect-package-manager-DYp7n3mJ.mjs';
|
|
11
11
|
import MagicString from 'magic-string';
|
|
12
12
|
import { Project, SyntaxKind } from 'ts-morph';
|
|
13
|
-
import { c as resolveDistTag, d as resolveSourceRef, r as runAddCommand } from '../packem_shared/commands-
|
|
13
|
+
import { c as resolveDistTag, d as resolveSourceRef, r as runAddCommand } from '../packem_shared/commands-CkkATMMx.mjs';
|
|
14
14
|
import { defaultSpawner } from '../packem_shared/createRecordingSpawner-DxI3mebw.mjs';
|
|
15
|
-
import {
|
|
16
|
-
import { p as
|
|
15
|
+
import { d as tuiOutro, e as tuiBanner, t as tuiText, f as tuiIntro, a as tuiSelect, w as withTuiSpinner, b as tuiConfirm, g as tuiMultiSelect } from '../packem_shared/tui-prompts-CA9lngSS.mjs';
|
|
16
|
+
import { p as promptBucketName, w as withStorageBucketName, M as MAIL_DESTINATION_PROMPT, r as resolveTypedDestination, E as EMAIL_ITEM, f as withMailDestination, e as promptAuthProvider, c as promptDatabaseName, g as withAuthDatabaseName } from '../packem_shared/storage-Bjo35hPa.mjs';
|
|
17
17
|
|
|
18
18
|
const GITHUB_CONTENT = `name: Deploy
|
|
19
19
|
|
|
@@ -294,6 +294,27 @@ const STACK_FEATURE_OPTIONS = [
|
|
|
294
294
|
{ description: "Live presence / who's-online over hibernated WebSockets", label: "Presence", value: "presence" },
|
|
295
295
|
{ description: "Snapshot + restore your Durable Object data", label: "Backups", value: "backup" }
|
|
296
296
|
];
|
|
297
|
+
const applyAuthFeature = async (deps) => {
|
|
298
|
+
const provider = await promptAuthProvider(deps.select);
|
|
299
|
+
const databaseName = await promptDatabaseName(deps.text, deps.projectName);
|
|
300
|
+
await deps.apply([provider], { transformManifest: (manifest) => withAuthDatabaseName(manifest, databaseName) });
|
|
301
|
+
};
|
|
302
|
+
const applyEmailFeature = async (deps) => {
|
|
303
|
+
const answer = await deps.text(MAIL_DESTINATION_PROMPT, { placeholder: "you@yourdomain.com" });
|
|
304
|
+
const destination = resolveTypedDestination(answer, (message) => {
|
|
305
|
+
deps.logger.warn(message);
|
|
306
|
+
});
|
|
307
|
+
await deps.apply([EMAIL_ITEM], destination === void 0 ? void 0 : { transformManifest: (manifest) => withMailDestination(manifest, destination) });
|
|
308
|
+
};
|
|
309
|
+
const applyStorageFeature = async (deps) => {
|
|
310
|
+
const bucketName = await promptBucketName(deps.text, deps.projectName);
|
|
311
|
+
await deps.apply(["storage"], { transformManifest: (manifest) => withStorageBucketName(manifest, bucketName) });
|
|
312
|
+
};
|
|
313
|
+
const FEATURE_HANDLERS = {
|
|
314
|
+
auth: applyAuthFeature,
|
|
315
|
+
email: applyEmailFeature,
|
|
316
|
+
storage: applyStorageFeature
|
|
317
|
+
};
|
|
297
318
|
const offerRegistryExtras = async (deps) => {
|
|
298
319
|
if (!deps.interactive) {
|
|
299
320
|
deps.logger.info("tip: add features later with `lunora add <auth|email|storage|ratelimit|crons|presence|backup>`.");
|
|
@@ -301,12 +322,8 @@ const offerRegistryExtras = async (deps) => {
|
|
|
301
322
|
}
|
|
302
323
|
const picked = await deps.multiSelect("Which features do you want to add?", STACK_FEATURE_OPTIONS, { defaults: [] });
|
|
303
324
|
for (const feature of picked) {
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
await deps.apply([provider]);
|
|
307
|
-
} else {
|
|
308
|
-
await deps.apply([feature === "email" ? EMAIL_ITEM : feature]);
|
|
309
|
-
}
|
|
325
|
+
const handler = FEATURE_HANDLERS[feature];
|
|
326
|
+
await (handler ? handler(deps) : deps.apply([feature]));
|
|
310
327
|
}
|
|
311
328
|
};
|
|
312
329
|
|
|
@@ -936,7 +953,7 @@ const runInPlaceInit = (cwd, logger) => {
|
|
|
936
953
|
const offerIsInteractive = (options) => options.yes !== true && (options.prompt !== void 0 || (options.interactive ?? isInteractive()));
|
|
937
954
|
const maybeOfferExtras = async (options, projectDirectory) => {
|
|
938
955
|
const interactive = offerIsInteractive(options);
|
|
939
|
-
const apply = async (names) => {
|
|
956
|
+
const apply = async (names, applyOptions) => {
|
|
940
957
|
const applyLogger = isInteractive() ? {
|
|
941
958
|
error: (message) => {
|
|
942
959
|
options.logger.error(message);
|
|
@@ -959,6 +976,7 @@ const maybeOfferExtras = async (options, projectDirectory) => {
|
|
|
959
976
|
names: [...names],
|
|
960
977
|
ref: options.ref,
|
|
961
978
|
source: options.registrySource,
|
|
979
|
+
transformManifest: applyOptions?.transformManifest,
|
|
962
980
|
yes: true
|
|
963
981
|
})
|
|
964
982
|
);
|
|
@@ -970,7 +988,9 @@ const maybeOfferExtras = async (options, projectDirectory) => {
|
|
|
970
988
|
interactive,
|
|
971
989
|
logger: options.logger,
|
|
972
990
|
multiSelect: options.prompt?.multiSelect ?? ((message, choices, settings) => tuiMultiSelect(message, choices, settings)),
|
|
973
|
-
|
|
991
|
+
projectName: basename(projectDirectory),
|
|
992
|
+
select: options.prompt?.select ?? ((message, choices, settings) => tuiSelect(message, choices, settings)),
|
|
993
|
+
text: options.prompt?.text ?? ((message, settings) => tuiText(message, settings))
|
|
974
994
|
});
|
|
975
995
|
};
|
|
976
996
|
const DEFAULT_FRAMEWORK = "react";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { existsSync, rmSync } from 'node:fs';
|
|
2
2
|
import { join } from '@visulima/path';
|
|
3
3
|
import { d as defineHandler } from '../packem_shared/command-BDXcJCCJ.mjs';
|
|
4
|
-
import {
|
|
4
|
+
import { b as tuiConfirm } from '../packem_shared/tui-prompts-CA9lngSS.mjs';
|
|
5
5
|
|
|
6
6
|
const runResetCommand = async (options) => {
|
|
7
7
|
const cwd = options.cwd ?? process.cwd();
|
|
@@ -14,7 +14,8 @@ 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"],
|
|
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"],
|
|
18
19
|
["lunora add crons", "Add the scheduled-jobs registry item"],
|
|
19
20
|
["lunora add storage --ref alpha", "Add an item from the alpha branch's registry"]
|
|
20
21
|
],
|
|
@@ -25,7 +26,10 @@ const addCommand = {
|
|
|
25
26
|
name: "add",
|
|
26
27
|
options: [
|
|
27
28
|
{ description: "auth: provider to use without prompting (auth | clerk | auth0)", name: "provider", type: String },
|
|
28
|
-
{ 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 },
|
|
29
33
|
{ description: "Local registry root (offline; expects <name>/ subdirs)", name: "from", type: String },
|
|
30
34
|
{ description: "Override the remote registry source base (e.g. gh:owner/repo/registry)", name: "source", type: String },
|
|
31
35
|
{
|
|
@@ -3,7 +3,7 @@ import { dirname, join } from '@visulima/path';
|
|
|
3
3
|
import { DEV_VARS_FILE, parseDevVariableEntries } from '@lunora/config';
|
|
4
4
|
import { modify, applyEdits, parse } from 'jsonc-parser';
|
|
5
5
|
import { fileURLToPath } from 'node:url';
|
|
6
|
-
import {
|
|
6
|
+
import { b as tuiConfirm } from './tui-prompts-CA9lngSS.mjs';
|
|
7
7
|
import { collectCatalog, buildRegistryIndex } from './buildRegistryIndex-BcYe607_.mjs';
|
|
8
8
|
import { insertSchemaExtension } from './insertSchemaExtension-BuzF6-t2.mjs';
|
|
9
9
|
import { createHash } from 'node:crypto';
|
|
@@ -583,6 +583,26 @@ const resolvePlan = async (names, options) => {
|
|
|
583
583
|
const emptyResult = () => {
|
|
584
584
|
return { bindings: [], code: 0, deps: [], skipped: [], written: [] };
|
|
585
585
|
};
|
|
586
|
+
const setBindingField = (manifest, section, match, field, fieldValue) => {
|
|
587
|
+
if (!manifest.bindings) {
|
|
588
|
+
return manifest;
|
|
589
|
+
}
|
|
590
|
+
return {
|
|
591
|
+
...manifest,
|
|
592
|
+
bindings: manifest.bindings.map((binding) => {
|
|
593
|
+
if (binding.path[0] !== section || !Array.isArray(binding.value)) {
|
|
594
|
+
return binding;
|
|
595
|
+
}
|
|
596
|
+
const entries = binding.value;
|
|
597
|
+
return {
|
|
598
|
+
...binding,
|
|
599
|
+
value: entries.map(
|
|
600
|
+
(entry) => typeof entry === "object" && entry !== null && entry[match.key] === match.value ? { ...entry, [field]: fieldValue } : entry
|
|
601
|
+
)
|
|
602
|
+
};
|
|
603
|
+
})
|
|
604
|
+
};
|
|
605
|
+
};
|
|
586
606
|
|
|
587
607
|
const printPlan = (logger, manifest) => {
|
|
588
608
|
const label = manifest.title ?? manifest.description;
|
|
@@ -688,8 +708,12 @@ const runAddCommand = async (options) => {
|
|
|
688
708
|
}
|
|
689
709
|
let cleanups = [];
|
|
690
710
|
try {
|
|
691
|
-
const { cleanups: planCleanups, items } = await resolvePlan(options.names, options);
|
|
711
|
+
const { cleanups: planCleanups, items: resolvedItems } = await resolvePlan(options.names, options);
|
|
692
712
|
cleanups = planCleanups;
|
|
713
|
+
const { transformManifest } = options;
|
|
714
|
+
const items = transformManifest ? resolvedItems.map((item) => {
|
|
715
|
+
return { ...item, manifest: transformManifest(item.manifest) };
|
|
716
|
+
}) : resolvedItems;
|
|
693
717
|
for (const { manifest } of items) {
|
|
694
718
|
printPlan(options.logger, manifest);
|
|
695
719
|
}
|
|
@@ -785,4 +809,4 @@ const runBuildIndexCommand = async (options) => {
|
|
|
785
809
|
return empty;
|
|
786
810
|
};
|
|
787
811
|
|
|
788
|
-
export { runBuildIndexCommand as a, runRegistryViewCommand as b, resolveDistTag as c, resolveSourceRef as d, runListCommand as e, runAddCommand as r };
|
|
812
|
+
export { runBuildIndexCommand as a, runRegistryViewCommand as b, resolveDistTag as c, resolveSourceRef as d, runListCommand as e, runAddCommand as r, setBindingField as s };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import 'node:fs';
|
|
2
2
|
import '@visulima/path';
|
|
3
|
-
export { r as runAddCommand, a as runBuildIndexCommand, e as runListCommand, b as runRegistryViewCommand } from './commands-
|
|
3
|
+
export { r as runAddCommand, a as runBuildIndexCommand, e as runListCommand, b as runRegistryViewCommand } from './commands-CkkATMMx.mjs';
|
|
4
4
|
import './buildRegistryIndex-BcYe607_.mjs';
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { s as setBindingField } from './commands-CkkATMMx.mjs';
|
|
2
|
+
|
|
3
|
+
const INVALID_SLUG_CHARS = /[^a-z0-9]+/u;
|
|
4
|
+
const toKebabSlug = (input, min, max) => {
|
|
5
|
+
let slug = input.toLowerCase().split(INVALID_SLUG_CHARS).filter(Boolean).join("-").slice(0, max);
|
|
6
|
+
if (slug.endsWith("-")) {
|
|
7
|
+
slug = slug.slice(0, -1);
|
|
8
|
+
}
|
|
9
|
+
return slug.length >= min ? slug : void 0;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
const DB_BINDING = "DB";
|
|
13
|
+
const AUTH_DB_PROMPT = "Name your D1 database (run `wrangler d1 create` to get its id, then put it in wrangler.jsonc)";
|
|
14
|
+
const sanitizeDatabaseName = (input) => toKebabSlug(input, 1, 64);
|
|
15
|
+
const FALLBACK_DATABASE_NAME = "lunora-db";
|
|
16
|
+
const deriveDatabaseName = (projectName) => sanitizeDatabaseName(`${projectName}-db`) ?? FALLBACK_DATABASE_NAME;
|
|
17
|
+
const promptDatabaseName = async (text, projectName) => {
|
|
18
|
+
const fallback = deriveDatabaseName(projectName);
|
|
19
|
+
return sanitizeDatabaseName(await text(AUTH_DB_PROMPT, { default: fallback, placeholder: fallback })) ?? fallback;
|
|
20
|
+
};
|
|
21
|
+
const withAuthDatabaseName = (manifest, name) => setBindingField(manifest, "d1_databases", { key: "binding", value: DB_BINDING }, "database_name", name);
|
|
22
|
+
|
|
23
|
+
const AUTH_PROVIDER_OPTIONS = [
|
|
24
|
+
{ description: "Email + password on better-auth (default)", label: "Email & password", value: "auth" },
|
|
25
|
+
{ description: "Clerk-hosted auth", label: "Clerk", value: "auth-clerk" },
|
|
26
|
+
{ description: "Auth0 (OIDC)", label: "Auth0", value: "auth-auth0" }
|
|
27
|
+
];
|
|
28
|
+
const DEFAULT_AUTH_ITEM = "auth";
|
|
29
|
+
const promptAuthProvider = async (select) => await select("Which auth provider?", AUTH_PROVIDER_OPTIONS, { default: DEFAULT_AUTH_ITEM }) ?? DEFAULT_AUTH_ITEM;
|
|
30
|
+
const EMAIL_ITEM = "mail";
|
|
31
|
+
const normalizeFeature = (raw) => {
|
|
32
|
+
const value = raw.trim();
|
|
33
|
+
if (value === "") {
|
|
34
|
+
return void 0;
|
|
35
|
+
}
|
|
36
|
+
const lower = value.toLowerCase();
|
|
37
|
+
if (lower === "auth") {
|
|
38
|
+
return { kind: "auth" };
|
|
39
|
+
}
|
|
40
|
+
if (lower === "email" || lower === "mail") {
|
|
41
|
+
return { kind: "email" };
|
|
42
|
+
}
|
|
43
|
+
return { item: lower, kind: "item" };
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const SEND_EMAIL_BINDING = "SEND_EMAIL";
|
|
47
|
+
const MAIL_DESTINATION_PROMPT = "Verified destination email for production delivery (blank = set it later in wrangler.jsonc)";
|
|
48
|
+
const isValidEmail = (value) => {
|
|
49
|
+
const trimmed = value.trim();
|
|
50
|
+
if (trimmed.length === 0 || trimmed.includes(" ")) {
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
const at = trimmed.indexOf("@");
|
|
54
|
+
if (at <= 0 || at !== trimmed.lastIndexOf("@")) {
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
const domain = trimmed.slice(at + 1);
|
|
58
|
+
return domain.length >= 3 && domain.includes(".") && !domain.startsWith(".") && !domain.endsWith(".");
|
|
59
|
+
};
|
|
60
|
+
const resolveTypedDestination = (entered, warn) => {
|
|
61
|
+
const trimmed = entered.trim();
|
|
62
|
+
if (trimmed === "") {
|
|
63
|
+
return void 0;
|
|
64
|
+
}
|
|
65
|
+
if (!isValidEmail(trimmed)) {
|
|
66
|
+
warn(`"${trimmed}" doesn't look like an email — leaving the placeholder; set destination_address in wrangler.jsonc.`);
|
|
67
|
+
return void 0;
|
|
68
|
+
}
|
|
69
|
+
return trimmed;
|
|
70
|
+
};
|
|
71
|
+
const withMailDestination = (manifest, address) => setBindingField(manifest, "send_email", { key: "name", value: SEND_EMAIL_BINDING }, "destination_address", address);
|
|
72
|
+
|
|
73
|
+
const UPLOADS_BINDING = "UPLOADS";
|
|
74
|
+
const STORAGE_BUCKET_PROMPT = "Name your R2 bucket (you can rename it in wrangler.jsonc later)";
|
|
75
|
+
const sanitizeBucketName = (input) => toKebabSlug(input, 3, 63);
|
|
76
|
+
const FALLBACK_BUCKET_NAME = "lunora-uploads";
|
|
77
|
+
const deriveBucketName = (projectName) => sanitizeBucketName(`${projectName}-uploads`) ?? FALLBACK_BUCKET_NAME;
|
|
78
|
+
const promptBucketName = async (text, projectName) => {
|
|
79
|
+
const fallback = deriveBucketName(projectName);
|
|
80
|
+
return sanitizeBucketName(await text(STORAGE_BUCKET_PROMPT, { default: fallback, placeholder: fallback })) ?? fallback;
|
|
81
|
+
};
|
|
82
|
+
const withStorageBucketName = (manifest, bucketName) => setBindingField(manifest, "r2_buckets", { key: "binding", value: UPLOADS_BINDING }, "bucket_name", bucketName);
|
|
83
|
+
|
|
84
|
+
export { AUTH_PROVIDER_OPTIONS as A, DEFAULT_AUTH_ITEM as D, EMAIL_ITEM as E, MAIL_DESTINATION_PROMPT as M, sanitizeDatabaseName as a, deriveDatabaseName as b, promptDatabaseName as c, deriveBucketName as d, promptAuthProvider as e, withMailDestination as f, withAuthDatabaseName as g, normalizeFeature as n, promptBucketName as p, resolveTypedDestination as r, sanitizeBucketName as s, withStorageBucketName as w };
|
|
@@ -266,4 +266,4 @@ const withTuiSpinner = async (label, task) => {
|
|
|
266
266
|
}
|
|
267
267
|
};
|
|
268
268
|
|
|
269
|
-
export {
|
|
269
|
+
export { tuiSelect as a, tuiConfirm as b, createTuiConfirm as c, tuiOutro as d, tuiBanner as e, tuiIntro as f, tuiMultiSelect as g, tuiText as t, withTuiSpinner as w };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lunora/cli",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.9",
|
|
4
4
|
"description": "The Lunora CLI: init, dev, deploy, codegen, run, reset, and migrate commands",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agent-skills",
|
|
@@ -51,11 +51,11 @@
|
|
|
51
51
|
"access": "public"
|
|
52
52
|
},
|
|
53
53
|
"dependencies": {
|
|
54
|
-
"@bomb.sh/tab": "0.0.
|
|
55
|
-
"@lunora/codegen": "1.0.0-alpha.
|
|
56
|
-
"@lunora/config": "1.0.0-alpha.
|
|
54
|
+
"@bomb.sh/tab": "0.0.16",
|
|
55
|
+
"@lunora/codegen": "1.0.0-alpha.3",
|
|
56
|
+
"@lunora/config": "1.0.0-alpha.4",
|
|
57
57
|
"@lunora/container": "1.0.0-alpha.1",
|
|
58
|
-
"@lunora/d1": "1.0.0-alpha.
|
|
58
|
+
"@lunora/d1": "1.0.0-alpha.4",
|
|
59
59
|
"@lunora/seed": "1.0.0-alpha.1",
|
|
60
60
|
"@visulima/cerebro": "3.0.0-alpha.32",
|
|
61
61
|
"@visulima/fs": "5.0.0-alpha.32",
|
|
@@ -41,7 +41,7 @@ This:
|
|
|
41
41
|
1. Adds `@lunora/storage` and `@lunora/server` to `package.json` (run
|
|
42
42
|
`pnpm install` afterwards).
|
|
43
43
|
2. Adds an R2 bucket binding to `wrangler.jsonc` (`r2_buckets`, binding
|
|
44
|
-
**`UPLOADS`**, `bucket_name: "
|
|
44
|
+
**`UPLOADS`**, `bucket_name: "replace-me-uploads"` — rename it to a real
|
|
45
45
|
bucket). It **merges** into any existing `r2_buckets`.
|
|
46
46
|
3. Scaffolds `STORAGE_SIGNING_SECRET` (a secret) and `STORAGE_PUBLIC_BASE_URL`
|
|
47
47
|
into `.dev.vars`.
|
|
@@ -137,8 +137,12 @@ persist that, and pass the bare key back in — the component re-scopes it.
|
|
|
137
137
|
|
|
138
138
|
1. **Skipping `verifySignedUrl` on the download route.** Without it, anyone can
|
|
139
139
|
read any key. Always verify before streaming.
|
|
140
|
-
2. **Placeholder bucket name.** `
|
|
141
|
-
|
|
140
|
+
2. **Placeholder bucket name.** `lunora init` and `lunora add storage` prompt for
|
|
141
|
+
the bucket name (or take `--bucket <name>`), but the low-level
|
|
142
|
+
`lunora registry add storage` writes the placeholder
|
|
143
|
+
`bucket_name: "replace-me-uploads"` — rename it to a real R2 bucket. (R2 names
|
|
144
|
+
are lowercase alphanumeric + hyphens, 3–63 chars; wrangler rejects anything
|
|
145
|
+
else on `dev`/`deploy`.)
|
|
142
146
|
3. **Short / shared signing secret.** Use ≥32 chars and a distinct secret per
|
|
143
147
|
bucket; reusing it lets one bucket's URLs sign for another.
|
|
144
148
|
4. **Proxying bytes through the Worker.** The design uploads/downloads directly
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
const AUTH_PROVIDER_OPTIONS = [
|
|
2
|
-
{ description: "Email + password on better-auth (default)", label: "Email & password", value: "auth" },
|
|
3
|
-
{ description: "Clerk-hosted auth", label: "Clerk", value: "auth-clerk" },
|
|
4
|
-
{ description: "Auth0 (OIDC)", label: "Auth0", value: "auth-auth0" }
|
|
5
|
-
];
|
|
6
|
-
const DEFAULT_AUTH_ITEM = "auth";
|
|
7
|
-
const promptAuthProvider = async (select) => await select("Which auth provider?", AUTH_PROVIDER_OPTIONS, { default: DEFAULT_AUTH_ITEM }) ?? DEFAULT_AUTH_ITEM;
|
|
8
|
-
const EMAIL_ITEM = "mail";
|
|
9
|
-
const normalizeFeature = (raw) => {
|
|
10
|
-
const value = raw.trim();
|
|
11
|
-
if (value === "") {
|
|
12
|
-
return void 0;
|
|
13
|
-
}
|
|
14
|
-
const lower = value.toLowerCase();
|
|
15
|
-
if (lower === "auth") {
|
|
16
|
-
return { kind: "auth" };
|
|
17
|
-
}
|
|
18
|
-
if (lower === "email" || lower === "mail") {
|
|
19
|
-
return { kind: "email" };
|
|
20
|
-
}
|
|
21
|
-
return { item: lower, kind: "item" };
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
export { AUTH_PROVIDER_OPTIONS as A, DEFAULT_AUTH_ITEM as D, EMAIL_ITEM as E, normalizeFeature as n, promptAuthProvider as p };
|