create-inferative 0.2.0-next.20261022160716 → 0.2.0
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/README.md +1 -1
- package/dist/bin.mjs +1 -1
- package/dist/{front-door-CGKOn3bI.mjs → front-door-C_ckNreK.mjs} +129 -13
- package/dist/heximon.inputs.json +3 -3
- package/dist/index.mjs +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -41,7 +41,7 @@ Add the token line to your `~/.npmrc`. If the token is missing, step 2 stops and
|
|
|
41
41
|
|
|
42
42
|
| Flag | What it does |
|
|
43
43
|
| :-- | :-- |
|
|
44
|
-
| `--starter <name>` | The starter to use: `nuxt-cloudflare` (a client site, the default)
|
|
44
|
+
| `--starter <name>` | The starter to use: `nuxt-cloudflare` (a client site, the default), `dashboard-cloudflare` (the dashboard) or `nuxt-sdk` (a website with its own server that reads a deployment with the SDK). |
|
|
45
45
|
| `--source <giget source>` | Download this source instead of the default starters. |
|
|
46
46
|
| `--local <folder>` | Copy the starter from this starters folder. Nothing is downloaded. |
|
|
47
47
|
| `--no-install` | Do not run `pnpm install`. |
|
package/dist/bin.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { t as CreateFrontDoor } from "./front-door-
|
|
2
|
+
import { t as CreateFrontDoor } from "./front-door-C_ckNreK.mjs";
|
|
3
3
|
import { runMain } from "citty";
|
|
4
4
|
//#region src/bin.ts
|
|
5
5
|
const argv = CreateFrontDoor.rawArgs(process.argv.slice(2));
|
|
@@ -3,7 +3,8 @@ import { defineCommand } from "citty";
|
|
|
3
3
|
import { basename, dirname, join, relative, resolve } from "node:path";
|
|
4
4
|
import { installDependencies } from "nypm";
|
|
5
5
|
import { x } from "tinyexec";
|
|
6
|
-
import { cp, mkdir, readFile, readdir, rm, rmdir, stat, writeFile } from "node:fs/promises";
|
|
6
|
+
import { cp, mkdir, mkdtemp, readFile, readdir, rm, rmdir, stat, writeFile } from "node:fs/promises";
|
|
7
|
+
import { tmpdir } from "node:os";
|
|
7
8
|
//#region src/package-version.ts
|
|
8
9
|
/**
|
|
9
10
|
* The version in this package's own `package.json`.
|
|
@@ -113,10 +114,13 @@ var InitMessages = class InitMessages {
|
|
|
113
114
|
static devCommand = "pnpm dev";
|
|
114
115
|
/** The command that writes the first migration of a starter. A starter commits no migration. */
|
|
115
116
|
static generateCommand = "pnpm db:generate";
|
|
117
|
+
/** The starters with no database of their own, so no migration step. */
|
|
118
|
+
static startersWithoutDatabase = /* @__PURE__ */ new Set(["nuxt-sdk"]);
|
|
116
119
|
/** The last line of the next steps for each starter: what its `README.md` explains first. */
|
|
117
120
|
static firstRunLines = {
|
|
118
121
|
"nuxt-cloudflare": "Fill in the values of .env first. README.md in the project explains the first run, with its first manifest sync (pnpm sync:manifest --first-sync).",
|
|
119
|
-
"dashboard-cloudflare": "Fill in the values of .env first. README.md in the project explains the secrets, the Cloudflare resources and the first run."
|
|
122
|
+
"dashboard-cloudflare": "Fill in the values of .env first. README.md in the project explains the secrets, the Cloudflare resources and the first run.",
|
|
123
|
+
"nuxt-sdk": "Fill in the values of .env first. README.md in the project explains the channel, its two keys and the manifest sync (pnpm sync:manifest)."
|
|
120
124
|
};
|
|
121
125
|
/** The last line of the next steps for a starter that {@link firstRunLines} does not name. */
|
|
122
126
|
static firstRunLine = "Fill in the values of .env first. README.md in the project explains the first run.";
|
|
@@ -136,7 +140,7 @@ var InitMessages = class InitMessages {
|
|
|
136
140
|
...changeDirectory === void 0 ? [] : [`cd ${InitMessages.quote(changeDirectory)}`],
|
|
137
141
|
...isInstalled ? [] : [`${DependencyInstaller.command} install`],
|
|
138
142
|
"cp .env.example .env",
|
|
139
|
-
InitMessages.generateCommand,
|
|
143
|
+
...InitMessages.startersWithoutDatabase.has(starter) ? [] : [InitMessages.generateCommand],
|
|
140
144
|
InitMessages.devCommand
|
|
141
145
|
].map((step) => ` ${step}`),
|
|
142
146
|
InitMessages.firstRunLines[starter] ?? InitMessages.firstRunLine
|
|
@@ -610,7 +614,7 @@ var NpmrcScopes = class NpmrcScopes {
|
|
|
610
614
|
};
|
|
611
615
|
//#endregion
|
|
612
616
|
//#region src/init/starter-source.ts
|
|
613
|
-
/** A download that failed. Only this failure makes {@link StarterSource.fetch} try the next source. */
|
|
617
|
+
/** A download that failed or wrote no file. Only this failure makes {@link StarterSource.fetch} try the next source. */
|
|
614
618
|
var StarterDownloadError = class StarterDownloadError extends InitError {
|
|
615
619
|
/** The giget sources that failed. */
|
|
616
620
|
sources;
|
|
@@ -632,6 +636,31 @@ var StarterDownloadError = class StarterDownloadError extends InitError {
|
|
|
632
636
|
return new StarterDownloadError([source], cause instanceof Error ? cause.message : String(cause), { cause });
|
|
633
637
|
}
|
|
634
638
|
};
|
|
639
|
+
/** No source holds the starter: each download worked and wrote no file. */
|
|
640
|
+
var StarterMissingError = class StarterMissingError extends InitError {
|
|
641
|
+
/** The giget sources that were tried. */
|
|
642
|
+
sources;
|
|
643
|
+
/** The starters that the repository holds, or `undefined` when they could not be read. */
|
|
644
|
+
listing;
|
|
645
|
+
constructor(sources, listing) {
|
|
646
|
+
super(StarterMissingError.describe(sources, listing));
|
|
647
|
+
this.name = "StarterMissingError";
|
|
648
|
+
this.sources = sources;
|
|
649
|
+
this.listing = listing;
|
|
650
|
+
}
|
|
651
|
+
/** The message: the starter, the repository and the refs tried, then the starters that exist. */
|
|
652
|
+
static describe(sources, listing) {
|
|
653
|
+
const locations = sources.map((source) => StarterSource.locate(source));
|
|
654
|
+
const [first] = locations;
|
|
655
|
+
const missing = first !== void 0 && locations.every((location) => location !== void 0 && location.repository === first.repository && location.folder === first.folder) ? `The starter "${first.folder}" does not exist in ${first.repository} (tried ${locations.map((location) => StarterMissingError.refName(location?.ref)).join(", ")}).` : `No source holds the starter: ${sources.join(", ")}.`;
|
|
656
|
+
if (listing === void 0) return missing;
|
|
657
|
+
const at = StarterMissingError.refName(listing.ref);
|
|
658
|
+
return listing.starters.length === 0 ? `${missing} The repository holds no starter at ${at}.` : `${missing} The starters at ${at}: ${listing.starters.join(", ")}.`;
|
|
659
|
+
}
|
|
660
|
+
static refName(ref) {
|
|
661
|
+
return ref === void 0 ? "the default branch" : `#${ref}`;
|
|
662
|
+
}
|
|
663
|
+
};
|
|
635
664
|
/** Fetches the files of a starter. */
|
|
636
665
|
var StarterSource = class StarterSource {
|
|
637
666
|
/** The public repository that holds the starters, one folder for each. */
|
|
@@ -641,11 +670,19 @@ var StarterSource = class StarterSource {
|
|
|
641
670
|
/** The starters of the starters repository, by folder name, with what each one creates. */
|
|
642
671
|
static starters = {
|
|
643
672
|
"nuxt-cloudflare": "a client site: the public site and its dashboard on one Worker",
|
|
644
|
-
"dashboard-cloudflare": "the Inferative dashboard on one Worker"
|
|
673
|
+
"dashboard-cloudflare": "the Inferative dashboard on one Worker",
|
|
674
|
+
"nuxt-sdk": "a website with its own server that reads a deployment with the SDK, on Node"
|
|
645
675
|
};
|
|
646
676
|
/** The branch that the default sources fall back to. */
|
|
647
677
|
static fallbackBranch = "main";
|
|
648
678
|
static starterNamePattern = /^[a-z0-9][a-z0-9-]*$/u;
|
|
679
|
+
/** Why a source that wrote no file failed. */
|
|
680
|
+
static missingReason = "the starter folder does not exist there";
|
|
681
|
+
static locationPattern = /^(?<provider>[\w+.-]+):(?<path>[^#]+)(?:#(?<ref>.+))?$/u;
|
|
682
|
+
/** The giget sources that are a URL, not a repository path: the error names them whole. */
|
|
683
|
+
static urlProviders = /* @__PURE__ */ new Set(["http", "https"]);
|
|
684
|
+
/** The giget providers whose repository path may have more than two segments (GitLab subgroups). */
|
|
685
|
+
static nestedRepositoryProviders = /* @__PURE__ */ new Set(["gitlab"]);
|
|
649
686
|
download;
|
|
650
687
|
/** @param download - The download function. It calls giget by default. */
|
|
651
688
|
constructor(download = (source, directory) => StarterSource.downloadWithGiget(source, directory)) {
|
|
@@ -668,6 +705,37 @@ var StarterSource = class StarterSource {
|
|
|
668
705
|
return Object.entries(StarterSource.starters).map(([name, creates]) => `${name} (${creates})`).join(", ");
|
|
669
706
|
}
|
|
670
707
|
/**
|
|
708
|
+
* Splits a giget source of a starter folder, such as `gh:inferative/starters/nuxt-cloudflare#main`.
|
|
709
|
+
*
|
|
710
|
+
* @returns The parts, or `undefined` when the source names no folder in a repository.
|
|
711
|
+
*/
|
|
712
|
+
static locate(source) {
|
|
713
|
+
const groups = StarterSource.locationPattern.exec(source)?.groups;
|
|
714
|
+
const provider = groups?.["provider"];
|
|
715
|
+
const path = groups?.["path"];
|
|
716
|
+
if (provider === void 0 || path === void 0) return;
|
|
717
|
+
const split = StarterSource.splitPath(provider, path);
|
|
718
|
+
return split === void 0 ? void 0 : {
|
|
719
|
+
repository: `${provider}:${split.repository}`,
|
|
720
|
+
folder: split.folder,
|
|
721
|
+
ref: groups?.["ref"]
|
|
722
|
+
};
|
|
723
|
+
}
|
|
724
|
+
/**
|
|
725
|
+
* Splits the path of a giget source as giget does: `::` ends the repository path; without it, a GitLab path is
|
|
726
|
+
* the repository only, and any other path has a repository of two segments.
|
|
727
|
+
*/
|
|
728
|
+
static splitPath(provider, path) {
|
|
729
|
+
const separator = path.indexOf("::");
|
|
730
|
+
const [repository, folder] = separator >= 0 ? [path.slice(0, separator), path.slice(separator + 2)] : StarterSource.nestedRepositoryProviders.has(provider) ? [path, ""] : [path.split("/").slice(0, 2).join("/"), path.split("/").slice(2).join("/")];
|
|
731
|
+
const trimmed = folder.replace(/^\/+|\/+$/gu, "");
|
|
732
|
+
const segments = repository.split("/");
|
|
733
|
+
return StarterSource.urlProviders.has(provider) || segments.length < 2 || segments.includes("") || trimmed === "" ? void 0 : {
|
|
734
|
+
repository,
|
|
735
|
+
folder: trimmed
|
|
736
|
+
};
|
|
737
|
+
}
|
|
738
|
+
/**
|
|
671
739
|
* Checks a starter name, which becomes a path segment.
|
|
672
740
|
*
|
|
673
741
|
* @throws {InitError} When the name is not a plain lowercase folder name.
|
|
@@ -678,24 +746,35 @@ var StarterSource = class StarterSource {
|
|
|
678
746
|
/**
|
|
679
747
|
* Downloads the starter from the first source that works.
|
|
680
748
|
*
|
|
681
|
-
* Only a failed download moves on to the next source. Any other error stops the
|
|
682
|
-
* source would fail the same way.
|
|
749
|
+
* Only a failed download, or one that wrote no file, moves on to the next source. Any other error stops the
|
|
750
|
+
* run, because the next source would fail the same way. Giget does not fail for a folder that the repository
|
|
751
|
+
* does not hold: it writes nothing.
|
|
683
752
|
*
|
|
684
753
|
* @param sources - The giget sources, in order.
|
|
685
754
|
* @param directory - The folder to fill.
|
|
686
755
|
* @param resetDirectory - Called before each later source, to remove the half-written files of the last one.
|
|
687
756
|
* @returns The source that worked.
|
|
757
|
+
* @throws {StarterMissingError} When no source holds the starter. The message names the starters that exist.
|
|
688
758
|
* @throws {StarterDownloadError} When every source failed. The message holds each failure.
|
|
689
759
|
*/
|
|
690
760
|
async fetch(sources, directory, resetDirectory) {
|
|
691
761
|
const failures = [];
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
762
|
+
const missing = [];
|
|
763
|
+
for (const source of sources) {
|
|
764
|
+
const before = new Set(await StarterSource.entryNames(directory));
|
|
765
|
+
try {
|
|
766
|
+
await this.download(source, directory);
|
|
767
|
+
} catch (error) {
|
|
768
|
+
failures.push(StarterDownloadError.of(source, error));
|
|
769
|
+
await resetDirectory();
|
|
770
|
+
continue;
|
|
771
|
+
}
|
|
772
|
+
if ((await StarterSource.entryNames(directory)).some((entry) => !before.has(entry))) return source;
|
|
773
|
+
missing.push(source);
|
|
774
|
+
failures.push(new StarterDownloadError([source], StarterSource.missingReason));
|
|
698
775
|
}
|
|
776
|
+
const lastMissing = missing.at(-1);
|
|
777
|
+
if (lastMissing !== void 0 && missing.length === sources.length) throw new StarterMissingError(sources, await this.listStarters(lastMissing));
|
|
699
778
|
const [first] = failures;
|
|
700
779
|
if (failures.length === 1 && first !== void 0) throw first;
|
|
701
780
|
throw new StarterDownloadError(sources, `Tried ${failures.map((failure) => `${failure.sources.join("")} (${failure.reason})`).join(", then ")}.`);
|
|
@@ -722,6 +801,43 @@ var StarterSource = class StarterSource {
|
|
|
722
801
|
});
|
|
723
802
|
return source;
|
|
724
803
|
}
|
|
804
|
+
/**
|
|
805
|
+
* Reads the starter folders of the repository at the ref of a source, from a download of the repository root
|
|
806
|
+
* into a temporary folder. The starters repository is small, so the second download is cheap.
|
|
807
|
+
*
|
|
808
|
+
* @returns The listing, or `undefined` when the source names no repository folder or the download fails.
|
|
809
|
+
*/
|
|
810
|
+
async listStarters(source) {
|
|
811
|
+
const location = StarterSource.locate(source);
|
|
812
|
+
if (location === void 0) return;
|
|
813
|
+
const root = location.ref === void 0 ? location.repository : `${location.repository}#${location.ref}`;
|
|
814
|
+
let directory;
|
|
815
|
+
try {
|
|
816
|
+
directory = await mkdtemp(join(tmpdir(), "inferative-starters-"));
|
|
817
|
+
await this.download(root, directory);
|
|
818
|
+
const starters = (await readdir(directory, { withFileTypes: true })).filter((entry) => entry.isDirectory() && !entry.name.startsWith(".")).map((entry) => entry.name).sort();
|
|
819
|
+
return {
|
|
820
|
+
ref: location.ref,
|
|
821
|
+
starters
|
|
822
|
+
};
|
|
823
|
+
} catch {
|
|
824
|
+
return;
|
|
825
|
+
} finally {
|
|
826
|
+
if (directory !== void 0) await rm(directory, {
|
|
827
|
+
recursive: true,
|
|
828
|
+
force: true
|
|
829
|
+
}).catch(() => void 0);
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
/** The entries of a folder, or none when it does not exist. */
|
|
833
|
+
static async entryNames(directory) {
|
|
834
|
+
try {
|
|
835
|
+
return await readdir(directory);
|
|
836
|
+
} catch (error) {
|
|
837
|
+
if (ErrorCode.is(error, "ENOENT")) return [];
|
|
838
|
+
throw error;
|
|
839
|
+
}
|
|
840
|
+
}
|
|
725
841
|
/** The default {@link StarterDownload}. It loads giget on first use, so a local copy needs no giget. */
|
|
726
842
|
static async downloadWithGiget(source, directory) {
|
|
727
843
|
const { downloadTemplate } = await import("giget");
|
package/dist/heximon.inputs.json
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
"../../tools/vitest/build-inputs.ts": "HO104hfJGDCrhwXLsy7I55ONi1PnjtDA6_gpYQ1gYlI",
|
|
7
7
|
"../../tools/vitest/measure-lane.ts": "VKf7uKWSoz3vYvCbLFw76YSksMT_E41akYmYdWIeFbE",
|
|
8
8
|
"../../tsconfig.base.json": "w6D6cbSUqUPq2R3SoBAQReeRQ-kQPVfQbddoBcybh-0",
|
|
9
|
-
"package.json": "
|
|
9
|
+
"package.json": "klm0tpBWEWBj7nJ7Y5DUAuFdn0x5AqSvgwo3quoyJ40",
|
|
10
10
|
"src/bin.ts": "IjsGZUVikS80RJn9Bo_1czPmrIh-J2cH4vVLZVmfggQ",
|
|
11
11
|
"src/error-code.ts": "5ollpvBpNVAGGvd0Jfic7xhNc0B_nGN9au8G7OqMIq4",
|
|
12
12
|
"src/front-door.ts": "AvZQP1lKw9zodvbNmg9HIdB8d1pfJx7MsrbBoO_bzlc",
|
|
@@ -14,12 +14,12 @@
|
|
|
14
14
|
"src/init/dependency-installer.ts": "jVTa8spFjggsWLUnSn9Vzvl4D-B2EYwRmpsVaBTCJaI",
|
|
15
15
|
"src/init/init-command.ts": "CWR-yuf-vglYxt2RiNqr5GCoEIiEO0ekvK3nCS20inU",
|
|
16
16
|
"src/init/init-error.ts": "Bdd0MQ9JvVwNHnzFH6aQnA1HiM_mVOsO0utGervvUsQ",
|
|
17
|
-
"src/init/init-messages.ts": "
|
|
17
|
+
"src/init/init-messages.ts": "r9kO19rAH-xgu-U2ty5vVMOPzywWe7z5TzsETbvzvZk",
|
|
18
18
|
"src/init/init-target.ts": "9UaRdl0vf6nVsgHJ5BHFcIIcbScWsocDol9zFf5_Kqc",
|
|
19
19
|
"src/init/manifest-stamper.ts": "0ANMdqEvOUbAYwiihoyIExim9fc0mIcjAkCfw840bfE",
|
|
20
20
|
"src/init/npmrc-scopes.ts": "aRIFEP9-WVq67QPsVjVP8HPPZFltMsKu-xXMFgJbLK4",
|
|
21
21
|
"src/init/project-initializer.ts": "NW9IsMY0Rx1vaDSGNkWUyCxDQU0V6UksrCQdfLK-RSk",
|
|
22
|
-
"src/init/starter-source.ts": "
|
|
22
|
+
"src/init/starter-source.ts": "AhAW-qXEBb4c5-beeIS8qh-DqZBkjY0X0IyvlPeWkkQ",
|
|
23
23
|
"src/package-version.ts": "BkSZq0oCN8fB5tbamfWcRonwCyWs2Rw0-qUXq-83zu4",
|
|
24
24
|
"src/process/npm-runner.ts": "KpIcT-JZAnaCXZ6v4AYo5WlEiWfb3jfel9El1R2jqjo",
|
|
25
25
|
"src/registry/registry-access.ts": "DVVkaI0o0MTVfyWZ1d9S8KT8h0WMS16xTzV2mjgf98M",
|
package/dist/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { i as RegistryAccessStatus, n as InitCommand, r as RegistryAccess, t as CreateFrontDoor } from "./front-door-
|
|
1
|
+
import { i as RegistryAccessStatus, n as InitCommand, r as RegistryAccess, t as CreateFrontDoor } from "./front-door-C_ckNreK.mjs";
|
|
2
2
|
export { CreateFrontDoor, InitCommand, RegistryAccess, RegistryAccessStatus };
|
package/package.json
CHANGED