hollware 1.0.0-rc.1 → 1.0.0-rc.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{d1-BvAz-iyW.mjs → d1-B6dc_ugC.mjs} +1 -1
- package/dist/{deploy-DsHNryRG.mjs → deploy-sYjaZ0d4.mjs} +59 -9
- package/dist/{dev--aG_y4gx.mjs → dev-B2gk-YHQ.mjs} +13 -4
- package/dist/{doctor-fpXiQgnU.mjs → doctor-DjRkQKrh.mjs} +7 -3
- package/dist/{export-Ims-m9Rl.mjs → export-HsextQcU.mjs} +84 -4
- package/dist/{import-CR4G8q5W.mjs → import-BpIvnM-l.mjs} +42 -3
- package/dist/import-CsbL7X6d.mjs +1 -0
- package/dist/index.mjs +10 -10
- package/dist/{init-BozoqmFw.mjs → init-A7Un-Ng_.mjs} +1 -1
- package/dist/{invite-tg1_MWv-.mjs → invite-CsGI2Gut.mjs} +2 -2
- package/dist/migrate-C15IVa7w.mjs +1 -0
- package/dist/{migrate-D2QcagMk.mjs → migrate-Dx-imcel.mjs} +2 -2
- package/dist/{token-B0UKrZBf.mjs → token-BxAQXSQO.mjs} +1 -1
- package/dist/token-DG5H7VPC.mjs +1 -0
- package/dist/{wrangler-DO3h-eNH.mjs → wrangler-C0QYL8dC.mjs} +10 -4
- package/package.json +2 -2
- package/dist/import-D4_IhUC7.mjs +0 -1
- package/dist/migrate-B2GrwRh4.mjs +0 -1
- package/dist/token-BG3q6bWZ.mjs +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { n as UsageError, t as CliError } from "./errors-DJX_jiSP.mjs";
|
|
2
2
|
import { t as printable } from "./format-Dvk_h5ys.mjs";
|
|
3
|
-
import { n as failureReason } from "./wrangler-
|
|
3
|
+
import { n as failureReason } from "./wrangler-C0QYL8dC.mjs";
|
|
4
4
|
import { t as parseJsonc } from "./jsonc-CA2ezIB6.mjs";
|
|
5
5
|
import { existsSync, readFileSync } from "node:fs";
|
|
6
6
|
import { join } from "node:path";
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { t as CliError } from "./errors-DJX_jiSP.mjs";
|
|
2
|
-
import { i as stripAnsi, n as failureReason } from "./wrangler-
|
|
2
|
+
import { i as stripAnsi, n as failureReason } from "./wrangler-C0QYL8dC.mjs";
|
|
3
3
|
import { t as parseFlags } from "./args-D42wi6n2.mjs";
|
|
4
|
-
import { f as ownerQuery, i as resolveDatabase, r as query } from "./d1-
|
|
4
|
+
import { f as ownerQuery, i as resolveDatabase, r as query } from "./d1-B6dc_ugC.mjs";
|
|
5
5
|
import { t as publicUrlOf } from "./public-url-d_yOsEMO.mjs";
|
|
6
|
-
import { i as migrate } from "./migrate-
|
|
6
|
+
import { i as migrate } from "./migrate-Dx-imcel.mjs";
|
|
7
7
|
import { existsSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
8
8
|
import { join } from "node:path";
|
|
9
9
|
//#region src/commands/deploy.ts
|
|
@@ -16,13 +16,30 @@ const DEPLOY_USAGE = [
|
|
|
16
16
|
"",
|
|
17
17
|
"HOLLWARE_PUBLIC_URL must be the public URL of the Worker. While it is a localhost URL, the",
|
|
18
18
|
"workers.dev URL that wrangler prints is written into wrangler.jsonc, and the Worker is deployed",
|
|
19
|
-
"again with it.
|
|
19
|
+
"again with it. A URL on a domain of your own (not workers.dev) also gets a route in",
|
|
20
|
+
"wrangler.jsonc that serves the Worker there as a custom domain: Cloudflare makes its DNS record",
|
|
21
|
+
"and its certificate, in a zone of the same account. Run \"wrangler login\" first.",
|
|
20
22
|
"",
|
|
21
23
|
"Options:",
|
|
22
24
|
" --url <url> The public URL of the Worker, such as https://cms.example.com (default: the",
|
|
23
25
|
" HOLLWARE_PUBLIC_URL of wrangler.jsonc, or the workers.dev URL)",
|
|
24
26
|
" --help Show this help"
|
|
25
27
|
].join("\n");
|
|
28
|
+
/** "Run wrangler login" only when wrangler says so: another failure has nothing to do with it. */
|
|
29
|
+
function loginHint(result) {
|
|
30
|
+
return /not logged in|log ?in|authenticat|oauth|api token/i.test(`${result.stdout}\n${result.stderr}`) ? " Is wrangler logged in (\"wrangler login\")?" : "";
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* `wrangler types` after deploy rewrote wrangler.jsonc: the types of the Worker hold the value of
|
|
34
|
+
* HOLLWARE_PUBLIC_URL, and `wrangler types --check` fails on the old one. A project without the
|
|
35
|
+
* generated file has nothing to keep current.
|
|
36
|
+
*/
|
|
37
|
+
async function regenerateTypes(io) {
|
|
38
|
+
if (!existsSync(join(io.cwd, "worker-configuration.d.ts"))) return;
|
|
39
|
+
const typed = await io.wrangler(["types"]);
|
|
40
|
+
if (typed.code !== 0) throw new CliError(`wrangler could not write the types of the Worker: ${failureReason(typed)}`);
|
|
41
|
+
io.out("Wrote worker-configuration.d.ts again, for the new wrangler.jsonc.");
|
|
42
|
+
}
|
|
26
43
|
/** The workers.dev URL that `wrangler deploy` prints, or `undefined`. */
|
|
27
44
|
function workersDevUrlOf(stdout) {
|
|
28
45
|
const match = /https:\/\/[a-z0-9-]+(?:\.[a-z0-9-]+)*\.workers\.dev(?![\w.-])/i.exec(stripAnsi(stdout));
|
|
@@ -33,6 +50,24 @@ function isLoopback(url) {
|
|
|
33
50
|
const { hostname } = new URL(url);
|
|
34
51
|
return hostname === "localhost" || hostname === "127.0.0.1" || hostname === "[::1]";
|
|
35
52
|
}
|
|
53
|
+
/** The host of a public URL on a domain of its own: neither this machine nor workers.dev. */
|
|
54
|
+
function customDomainOf(url) {
|
|
55
|
+
if (isLoopback(url)) return void 0;
|
|
56
|
+
const { hostname } = new URL(url);
|
|
57
|
+
return /(?:^|\.)workers\.dev$/i.test(hostname) ? void 0 : hostname;
|
|
58
|
+
}
|
|
59
|
+
const ROUTES_KEY = /^\s*"routes"\s*:/m;
|
|
60
|
+
/** The first key of the starter's wrangler.jsonc, at the top level of the object. */
|
|
61
|
+
const TOP_LEVEL_NAME = /^ {2}"name"\s*:\s*"[^"\n]*",[^\n]*\n/m;
|
|
62
|
+
/**
|
|
63
|
+
* `wrangler.jsonc` with a route that serves the Worker at `host` as a custom domain, after its
|
|
64
|
+
* `name`, and everything else as it was. A config with routes of its own is left as it is.
|
|
65
|
+
*/
|
|
66
|
+
function withCustomDomain(text, host) {
|
|
67
|
+
if (ROUTES_KEY.test(text)) return text;
|
|
68
|
+
if (!TOP_LEVEL_NAME.test(text)) throw new CliError(`wrangler.jsonc has no "name" at its top. Add "routes": [{ "pattern": "${host}", "custom_domain": true }] to it.`);
|
|
69
|
+
return text.replace(TOP_LEVEL_NAME, (line) => `${line} // The custom domain of the Worker: Cloudflare makes its DNS record and its certificate.\n "routes": [{ "pattern": ${JSON.stringify(host)}, "custom_domain": true }],\n`);
|
|
70
|
+
}
|
|
36
71
|
const PUBLIC_URL_VALUE = /("HOLLWARE_PUBLIC_URL"\s*:\s*)"[^"\n]*"/;
|
|
37
72
|
/**
|
|
38
73
|
* `wrangler.jsonc` with `HOLLWARE_PUBLIC_URL` set to `url`, and everything else as it was: its
|
|
@@ -44,7 +79,7 @@ function withPublicUrl(text, url) {
|
|
|
44
79
|
}
|
|
45
80
|
async function wranglerDeploy(io) {
|
|
46
81
|
const deployed = await io.wrangler(["deploy"]);
|
|
47
|
-
if (deployed.code !== 0) throw new CliError(`wrangler could not deploy: ${failureReason(deployed)
|
|
82
|
+
if (deployed.code !== 0) throw new CliError(`wrangler could not deploy: ${failureReason(deployed).replace(/\.$/, "")}.${loginHint(deployed)}`);
|
|
48
83
|
return deployed.stdout;
|
|
49
84
|
}
|
|
50
85
|
async function deploy(argv, io) {
|
|
@@ -65,14 +100,29 @@ async function deploy(argv, io) {
|
|
|
65
100
|
const configured = publicUrlOf(io.cwd, void 0);
|
|
66
101
|
const asked = values.url === void 0 ? void 0 : publicUrlOf(io.cwd, values.url);
|
|
67
102
|
const database = resolveDatabase(io.cwd, void 0);
|
|
103
|
+
const known = asked ?? (configured !== void 0 && !isLoopback(configured) ? configured : void 0);
|
|
104
|
+
const domain = known === void 0 ? void 0 : customDomainOf(known);
|
|
105
|
+
let written = configured;
|
|
106
|
+
if (known !== void 0 && domain !== void 0) {
|
|
107
|
+
const before = readFileSync(file, "utf8");
|
|
108
|
+
const withUrl = known === configured ? before : withPublicUrl(before, known);
|
|
109
|
+
const after = withCustomDomain(withUrl, domain);
|
|
110
|
+
if (after === withUrl && !withUrl.includes(JSON.stringify(domain))) io.out(`wrangler.jsonc has routes of its own and none for ${domain}: add { "pattern": "${domain}", "custom_domain": true } to them.`);
|
|
111
|
+
if (after !== before) {
|
|
112
|
+
writeFileSync(file, after);
|
|
113
|
+
io.out(`Serving the Worker at ${domain}: set HOLLWARE_PUBLIC_URL and its route in wrangler.jsonc.`);
|
|
114
|
+
await regenerateTypes(io);
|
|
115
|
+
}
|
|
116
|
+
written = known;
|
|
117
|
+
}
|
|
68
118
|
io.out("Deploying with wrangler ...");
|
|
69
119
|
const printed = await wranglerDeploy(io);
|
|
70
|
-
|
|
71
|
-
url ??= workersDevUrlOf(printed);
|
|
120
|
+
const url = known ?? workersDevUrlOf(printed);
|
|
72
121
|
if (url === void 0) throw new CliError("wrangler deployed the Worker but printed no workers.dev URL. Run \"hollware deploy --url <the public URL of the Worker>\".");
|
|
73
|
-
if (url !==
|
|
122
|
+
if (url !== written) {
|
|
74
123
|
writeFileSync(file, withPublicUrl(readFileSync(file, "utf8"), url));
|
|
75
124
|
io.out(`Set HOLLWARE_PUBLIC_URL to ${url} in wrangler.jsonc. Deploying again with it ...`);
|
|
125
|
+
await regenerateTypes(io);
|
|
76
126
|
await wranglerDeploy(io);
|
|
77
127
|
}
|
|
78
128
|
await ensureMasterSecret(io);
|
|
@@ -88,7 +138,7 @@ async function deploy(argv, io) {
|
|
|
88
138
|
` MCP ${url}/mcp`,
|
|
89
139
|
` Admin ${url}/admin/`,
|
|
90
140
|
"",
|
|
91
|
-
"Commit wrangler.jsonc: it holds the
|
|
141
|
+
"Commit wrangler.jsonc: it holds the public URL, and any id wrangler wrote into it.",
|
|
92
142
|
...owners.length === 0 ? [
|
|
93
143
|
"",
|
|
94
144
|
"Next: create your site and its owner in the remote database. It prints a token for your",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { n as UsageError, t as CliError } from "./errors-DJX_jiSP.mjs";
|
|
2
|
-
import { r as findBin } from "./wrangler-
|
|
2
|
+
import { r as findBin } from "./wrangler-C0QYL8dC.mjs";
|
|
3
3
|
import { t as parseFlags } from "./args-D42wi6n2.mjs";
|
|
4
4
|
import { t as publicUrlOf } from "./public-url-d_yOsEMO.mjs";
|
|
5
5
|
import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
@@ -16,10 +16,13 @@ const DEV_USAGE = [
|
|
|
16
16
|
"With --detach it starts the server in the background, writes its process id and URL to",
|
|
17
17
|
`.wrangler/hollware-dev.json, prints the ready line and exits 0. "hollware dev --stop" stops what`,
|
|
18
18
|
"that file names.",
|
|
19
|
+
"Once \"hollware deploy\" has written the public URL into wrangler.jsonc, the local server still",
|
|
20
|
+
"answers at localhost: the vite.config.ts of the project sets HOLLWARE_PUBLIC_URL to it in",
|
|
21
|
+
"development, and hollware dev waits for it there.",
|
|
19
22
|
"",
|
|
20
23
|
"Options:",
|
|
21
|
-
" --url <url> Where the server listens (default: HOLLWARE_PUBLIC_URL of wrangler.jsonc
|
|
22
|
-
" else http://localhost:5199)",
|
|
24
|
+
" --url <url> Where the server listens (default: HOLLWARE_PUBLIC_URL of wrangler.jsonc",
|
|
25
|
+
" when it is a localhost URL, else http://localhost:5199)",
|
|
23
26
|
" --timeout <seconds> How long to wait for /health, 1 to 600 (default: 60)",
|
|
24
27
|
" --detach Start it in the background and exit",
|
|
25
28
|
" --stop Stop the server that --detach started",
|
|
@@ -56,7 +59,8 @@ async function dev(argv, io) {
|
|
|
56
59
|
return stop(io, host, json);
|
|
57
60
|
}
|
|
58
61
|
const timeout = timeoutOf(values.timeout);
|
|
59
|
-
const
|
|
62
|
+
const configured = publicUrlOf(io.cwd, void 0);
|
|
63
|
+
const url = values.url !== void 0 ? publicUrlOf(io.cwd, values.url) ?? DEFAULT_URL : configured !== void 0 && isLoopback(configured) ? configured : DEFAULT_URL;
|
|
60
64
|
const bin = findBin(io.cwd, "vp");
|
|
61
65
|
if (bin === void 0) throw new CliError(`vp is not installed in ${io.cwd} or any directory above it. Install the dependencies of the project (for example "pnpm install") and run hollware dev from the project directory.`);
|
|
62
66
|
const detach = values.detach === true;
|
|
@@ -103,6 +107,11 @@ async function dev(argv, io) {
|
|
|
103
107
|
off();
|
|
104
108
|
}
|
|
105
109
|
}
|
|
110
|
+
/** Whether a URL is this machine's. */
|
|
111
|
+
function isLoopback(url) {
|
|
112
|
+
const { hostname } = new URL(url);
|
|
113
|
+
return hostname === "localhost" || hostname === "127.0.0.1" || hostname === "[::1]";
|
|
114
|
+
}
|
|
106
115
|
async function stop(io, host, json) {
|
|
107
116
|
const state = readState(io.cwd);
|
|
108
117
|
if (state === void 0) {
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { t as CliError } from "./errors-DJX_jiSP.mjs";
|
|
2
|
-
import { n as failureReason } from "./wrangler-
|
|
2
|
+
import { n as failureReason } from "./wrangler-C0QYL8dC.mjs";
|
|
3
3
|
import { t as parseFlags } from "./args-D42wi6n2.mjs";
|
|
4
4
|
import { t as parseJsonc } from "./jsonc-CA2ezIB6.mjs";
|
|
5
|
-
import { f as ownerQuery, r as query, t as chooseTarget } from "./d1-
|
|
6
|
-
import { a as parsePendingMigrations } from "./migrate-
|
|
5
|
+
import { f as ownerQuery, r as query, t as chooseTarget } from "./d1-B6dc_ugC.mjs";
|
|
6
|
+
import { a as parsePendingMigrations } from "./migrate-Dx-imcel.mjs";
|
|
7
7
|
import { existsSync, readFileSync, readdirSync } from "node:fs";
|
|
8
8
|
import { join } from "node:path";
|
|
9
9
|
//#region src/commands/doctor.ts
|
|
@@ -59,6 +59,10 @@ function checkConfig(cwd, config) {
|
|
|
59
59
|
findings.push(db === void 0 ? fail("d1-binding", `there is no D1 binding "DB"`, "Add it to d1_databases in wrangler.jsonc, as the starter has it.") : migrations.length === 0 ? fail("d1-binding", `the D1 binding "DB" has no migrations in its migrations_dir`, "Set migrations_dir to \"node_modules/@hollware/server/migrations\", and install the dependencies.") : pass("d1-binding", `the D1 binding "DB" has ${migrations.length} migrations`));
|
|
60
60
|
const kv = records(config["kv_namespaces"]).some((entry) => entry["binding"] === "OAUTH_KV");
|
|
61
61
|
findings.push(kv ? pass("kv-binding", "the KV binding \"OAUTH_KV\" is there") : fail("kv-binding", "there is no KV binding \"OAUTH_KV\", which the OAuth server needs", "Add { \"binding\": \"OAUTH_KV\" } to kv_namespaces in wrangler.jsonc."));
|
|
62
|
+
const media = records(config["r2_buckets"]).some((entry) => entry["binding"] === "MEDIA");
|
|
63
|
+
findings.push(media ? pass("media-bucket", "the R2 bucket \"MEDIA\" keeps the images of the sites") : fail("media-bucket", "there is no R2 bucket \"MEDIA\", so upload_asset answers unavailable", "Add { \"binding\": \"MEDIA\", \"bucket_name\": \"<name>-media\" } to r2_buckets in wrangler.jsonc; hollware deploy creates the bucket."));
|
|
64
|
+
const images = isRecord(config["images"]) && config["images"]["binding"] === "IMAGES";
|
|
65
|
+
findings.push(pass("images-binding", images ? "the Images binding \"IMAGES\" converts each image once, by the media setting of its site" : "there is no Images binding \"IMAGES\": images are kept as they come, unconverted (add \"images\": { \"binding\": \"IMAGES\" } to convert them)"));
|
|
62
66
|
const assets = isRecord(config["assets"]) ? config["assets"] : void 0;
|
|
63
67
|
const directory = typeof assets?.["directory"] === "string" ? assets["directory"] : void 0;
|
|
64
68
|
const admin = directory !== void 0 && existsSync(join(cwd, directory, "admin"));
|
|
@@ -2,15 +2,15 @@ import { n as UsageError, t as CliError } from "./errors-DJX_jiSP.mjs";
|
|
|
2
2
|
import { t as printable } from "./format-Dvk_h5ys.mjs";
|
|
3
3
|
import { t as readVersion } from "./version-BMhdZaNo.mjs";
|
|
4
4
|
import { t as parseFlags } from "./args-D42wi6n2.mjs";
|
|
5
|
-
import { a as redact, c as openSession, i as readToken, o as withoutToken, r as mcpEndpoint, s as ToolFailure } from "./import-
|
|
5
|
+
import { a as redact, c as openSession, i as readToken, o as withoutToken, r as mcpEndpoint, s as ToolFailure } from "./import-BpIvnM-l.mjs";
|
|
6
6
|
import { mkdirSync, readdirSync, writeFileSync } from "node:fs";
|
|
7
7
|
import { dirname, join, resolve } from "node:path";
|
|
8
|
-
import { describeSite, getEntry, listEntries, schemas } from "@hollware/core";
|
|
8
|
+
import { EXTENSIONS, describeSite, getAsset, getEntry, listEntries, schemas } from "@hollware/core";
|
|
9
9
|
//#region src/commands/export.ts
|
|
10
10
|
const EXPORT_USAGE = [
|
|
11
11
|
"Usage: hollware export <directory> --url <hollware url> (--token-file <file> | token on stdin)",
|
|
12
12
|
" [--site <key>] [--collection <name>]... [--locale <code>]...",
|
|
13
|
-
" [--published] [--dry-run]",
|
|
13
|
+
" [--published] [--assets <dir> --assets-url <path>] [--dry-run]",
|
|
14
14
|
"",
|
|
15
15
|
"Writes the entries of a running Hollware, read over MCP, as Markdown files at",
|
|
16
16
|
"<directory>/<collection>/<locale>/<slug>.md: the layout \"hollware import\" reads. Each file is",
|
|
@@ -26,6 +26,11 @@ const EXPORT_USAGE = [
|
|
|
26
26
|
" --locale <code> Export only this locale; repeat it for several",
|
|
27
27
|
" --published Export only the published entries, as they are published; by default the",
|
|
28
28
|
" latest revision of every entry, drafts included",
|
|
29
|
+
" --assets <dir> Write the images the entries show to <dir>, as the site serves them,",
|
|
30
|
+
" and point each asset: reference at --assets-url: for a site that",
|
|
31
|
+
" serves its images itself. Without it, the images go to <directory>/_assets",
|
|
32
|
+
" as they were uploaded, with assets.json, which \"hollware import\" uploads again",
|
|
33
|
+
" --assets-url <path> With --assets: the path the site serves <dir> at, such as /images/cms/",
|
|
29
34
|
" --dry-run List the files it would write, and write nothing",
|
|
30
35
|
" --help Show this help",
|
|
31
36
|
"",
|
|
@@ -55,6 +60,8 @@ async function exportContent(argv, io) {
|
|
|
55
60
|
multiple: true
|
|
56
61
|
},
|
|
57
62
|
published: { type: "boolean" },
|
|
63
|
+
assets: { type: "string" },
|
|
64
|
+
"assets-url": { type: "string" },
|
|
58
65
|
"dry-run": { type: "boolean" },
|
|
59
66
|
help: { type: "boolean" }
|
|
60
67
|
}
|
|
@@ -66,9 +73,16 @@ async function exportContent(argv, io) {
|
|
|
66
73
|
const [directory, ...extra] = positionals;
|
|
67
74
|
if (directory === void 0 || extra.length > 0) throw new UsageError("export takes one directory: hollware export <directory> --url <url>.");
|
|
68
75
|
if (values.url === void 0) throw new UsageError("--url is required: the address of your Hollware, such as https://cms.example.com.");
|
|
76
|
+
if (values.assets === void 0 !== (values["assets-url"] === void 0)) throw new UsageError("--assets and --assets-url go together: where to write the images, and the path the site serves them at.");
|
|
69
77
|
const endpoint = mcpEndpoint(values.url);
|
|
70
78
|
const root = resolve(io.cwd, directory);
|
|
71
79
|
checkTarget(root, directory);
|
|
80
|
+
const assets = values.assets === void 0 || values["assets-url"] === void 0 ? void 0 : {
|
|
81
|
+
root: resolve(io.cwd, values.assets),
|
|
82
|
+
directory: values.assets,
|
|
83
|
+
url: values["assets-url"]
|
|
84
|
+
};
|
|
85
|
+
if (assets !== void 0) checkTarget(assets.root, assets.directory);
|
|
72
86
|
const token = await readToken(io, values["token-file"]);
|
|
73
87
|
try {
|
|
74
88
|
return await exportEntries({
|
|
@@ -81,6 +95,7 @@ async function exportContent(argv, io) {
|
|
|
81
95
|
collections: values.collection,
|
|
82
96
|
locales: values.locale,
|
|
83
97
|
published: values.published === true,
|
|
98
|
+
assets,
|
|
84
99
|
dryRun: values["dry-run"] === true
|
|
85
100
|
});
|
|
86
101
|
} catch (error) {
|
|
@@ -100,6 +115,8 @@ function checkTarget(root, directory) {
|
|
|
100
115
|
}
|
|
101
116
|
if (names.length > 0) throw new CliError(`${printable(directory)} is not empty: export into a new or an empty directory, so that no file is overwritten. Nothing was written.`);
|
|
102
117
|
}
|
|
118
|
+
/** Every `asset:` reference in Markdown, by id (ADR-038). */
|
|
119
|
+
const ASSET_REFERENCE = /asset:(ast_[0-9a-f]{26})/g;
|
|
103
120
|
/**
|
|
104
121
|
* Reads everything first, then writes: a call that fails stops the export before any file is
|
|
105
122
|
* written.
|
|
@@ -109,12 +126,14 @@ async function exportEntries(plan) {
|
|
|
109
126
|
const out = (message) => io.out(redact(message, token));
|
|
110
127
|
const session = await openSession(plan.endpoint, token, readVersion());
|
|
111
128
|
let files;
|
|
129
|
+
let images;
|
|
112
130
|
let siteKey;
|
|
113
131
|
try {
|
|
114
132
|
const { site } = await session.call(describeSite, {});
|
|
115
133
|
siteKey = site.key;
|
|
116
134
|
if (plan.site !== void 0 && plan.site !== site.key) throw new CliError(`the token is of the site ${printable(JSON.stringify(site.key))}, not ${printable(JSON.stringify(plan.site))}: a personal token reads the one site it is of. Use a token of ${printable(plan.site)}.`);
|
|
117
135
|
files = await readAll(session, await listAll(session, chosen("collection", site.collections.map((collection) => collection.name), plan.collections), plan.locales === void 0 ? [void 0] : chosen("locale", site.locales, plan.locales), published), published);
|
|
136
|
+
images = await readImages(session, plan, files);
|
|
118
137
|
} finally {
|
|
119
138
|
await session.close();
|
|
120
139
|
}
|
|
@@ -123,8 +142,10 @@ async function exportEntries(plan) {
|
|
|
123
142
|
out(`No entries to export from the site ${printable(siteKey)} (${view}). Nothing was written.`);
|
|
124
143
|
return 0;
|
|
125
144
|
}
|
|
145
|
+
const imagesRoot = plan.assets?.root ?? join(root, "_assets");
|
|
146
|
+
const imagesShown = plan.assets?.directory ?? join(directory, "_assets");
|
|
126
147
|
if (dryRun) {
|
|
127
|
-
out(files.map((file) => `would write ${printable(file.path)}`).join("\n"));
|
|
148
|
+
out([...files.map((file) => `would write ${printable(file.path)}`), ...images.map((image) => `would write ${printable(join(imagesShown, image.path))}`)].join("\n"));
|
|
128
149
|
out(`Dry run: ${count(files.length, "entry", "entries")} of the site ${printable(siteKey)} would be written to ${printable(directory)} (${view}):\n${groupSummary(files)}\nNothing was written.`);
|
|
129
150
|
return 0;
|
|
130
151
|
}
|
|
@@ -139,6 +160,16 @@ async function exportEntries(plan) {
|
|
|
139
160
|
}
|
|
140
161
|
written += 1;
|
|
141
162
|
}
|
|
163
|
+
for (const image of images) {
|
|
164
|
+
const target = join(imagesRoot, image.path);
|
|
165
|
+
try {
|
|
166
|
+
mkdirSync(dirname(target), { recursive: true });
|
|
167
|
+
writeFileSync(target, image.bytes, { flag: "wx" });
|
|
168
|
+
} catch (error) {
|
|
169
|
+
throw new CliError(`could not write ${printable(join(imagesShown, image.path))}: ${error instanceof Error ? error.message : String(error)}. Remove ${printable(directory)} and run the export again.`);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
if (images.length > 0) out(`Wrote ${count(images.filter((image) => image.path !== "assets.json").length, "image")} to ${printable(imagesShown)}.`);
|
|
142
173
|
out(`Exported ${count(files.length, "entry", "entries")} of the site ${printable(siteKey)} to ${printable(directory)} (${view}):\n${groupSummary(files)}`);
|
|
143
174
|
return 0;
|
|
144
175
|
}
|
|
@@ -213,6 +244,55 @@ async function readAll(session, listed, published) {
|
|
|
213
244
|
}
|
|
214
245
|
return files;
|
|
215
246
|
}
|
|
247
|
+
/**
|
|
248
|
+
* The images the entries show (ADR-038). With --assets: each as the site serves it, at
|
|
249
|
+
* `<id>.<ext>`, and every `asset:` reference of the files pointed at `<assets-url><id>.<ext>`.
|
|
250
|
+
* Without it: each as it was uploaded, at `_assets/<id>.<ext>`, and `assets.json` with what
|
|
251
|
+
* `hollware import` needs to upload it again under the same id. Reads everything before it
|
|
252
|
+
* writes, as the entries are read.
|
|
253
|
+
*/
|
|
254
|
+
async function readImages(session, plan, files) {
|
|
255
|
+
const ids = [...new Set(files.flatMap((file) => [...file.markdown.matchAll(ASSET_REFERENCE)].map((match) => match[1] ?? "")))].sort();
|
|
256
|
+
if (ids.length === 0) return [];
|
|
257
|
+
const images = [];
|
|
258
|
+
const manifest = {};
|
|
259
|
+
const urls = /* @__PURE__ */ new Map();
|
|
260
|
+
for (const id of ids) {
|
|
261
|
+
const answer = await session.call(getAsset, { id });
|
|
262
|
+
const asset = answer.asset;
|
|
263
|
+
if (answer.outcome !== "ok" || asset === void 0) throw new CliError(`an entry shows the image ${id}, which the site does not have. Nothing was written.`);
|
|
264
|
+
if (plan.assets !== void 0) {
|
|
265
|
+
const name = `${id}.${EXTENSIONS[asset.format]}`;
|
|
266
|
+
images.push({
|
|
267
|
+
path: name,
|
|
268
|
+
bytes: await download(new URL(asset.url), null, id)
|
|
269
|
+
});
|
|
270
|
+
urls.set(id, `${plan.assets.url}${name}`);
|
|
271
|
+
} else {
|
|
272
|
+
const original = new URL(`/v1/assets/${id}/original`, plan.endpoint);
|
|
273
|
+
const name = `${id}.${EXTENSIONS[asset.originalFormat]}`;
|
|
274
|
+
images.push({
|
|
275
|
+
path: name,
|
|
276
|
+
bytes: await download(original, plan.token, id)
|
|
277
|
+
});
|
|
278
|
+
manifest[name] = {
|
|
279
|
+
alt: asset.alt,
|
|
280
|
+
filename: asset.filename
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
if (plan.assets !== void 0) for (const file of files) file.markdown = file.markdown.replace(ASSET_REFERENCE, (reference, id) => urls.get(id) ?? reference);
|
|
285
|
+
else images.push({
|
|
286
|
+
path: "assets.json",
|
|
287
|
+
bytes: new TextEncoder().encode(`${JSON.stringify(manifest, null, 2)}\n`)
|
|
288
|
+
});
|
|
289
|
+
return images;
|
|
290
|
+
}
|
|
291
|
+
async function download(url, token, id) {
|
|
292
|
+
const response = await fetch(url, token === null ? {} : { headers: { authorization: `Bearer ${token}` } });
|
|
293
|
+
if (!response.ok) throw new CliError(`could not download the image ${id} (${response.status} from ${url.pathname}). Nothing was written.`);
|
|
294
|
+
return new Uint8Array(await response.arrayBuffer());
|
|
295
|
+
}
|
|
216
296
|
function sentence(message) {
|
|
217
297
|
return message.replace(/[\s.]+$/, "");
|
|
218
298
|
}
|
|
@@ -2,9 +2,9 @@ import { n as UsageError, t as CliError } from "./errors-DJX_jiSP.mjs";
|
|
|
2
2
|
import { t as printable } from "./format-Dvk_h5ys.mjs";
|
|
3
3
|
import { t as readVersion } from "./version-BMhdZaNo.mjs";
|
|
4
4
|
import { t as parseFlags } from "./args-D42wi6n2.mjs";
|
|
5
|
-
import { readFileSync, readdirSync, statSync } from "node:fs";
|
|
5
|
+
import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
|
|
6
6
|
import { join, resolve } from "node:path";
|
|
7
|
-
import { REFUSAL_CONTRACT_IDS, createDraft, getEntry, isPersonalToken, publish, schemas, updateDraft, validate } from "@hollware/core";
|
|
7
|
+
import { REFUSAL_CONTRACT_IDS, createDraft, getEntry, isPersonalToken, publish, schemas, updateDraft, uploadAsset, validate } from "@hollware/core";
|
|
8
8
|
import { Client, InsufficientScopeError, ProtocolError, SdkError, SdkErrorCode, SdkHttpError, StreamableHTTPClientTransport, UnauthorizedError } from "@modelcontextprotocol/client";
|
|
9
9
|
//#region src/import/session.ts
|
|
10
10
|
/** A tool failed and said so in words, instead of answering with one of its outcomes. */
|
|
@@ -338,6 +338,7 @@ async function importContent(argv, io) {
|
|
|
338
338
|
token,
|
|
339
339
|
endpoint,
|
|
340
340
|
directory,
|
|
341
|
+
root,
|
|
341
342
|
corpus,
|
|
342
343
|
publish: values.publish === true,
|
|
343
344
|
dryRun: values["dry-run"] === true
|
|
@@ -359,7 +360,7 @@ function withoutToken(error, token) {
|
|
|
359
360
|
function sourceOf(from, root, options) {
|
|
360
361
|
return from === "markdown" ? readCorpus(root) : corpusFromNuxtContent(root, options);
|
|
361
362
|
}
|
|
362
|
-
async function importFiles({ io, token, endpoint, directory, corpus, publish: publishToo, dryRun }) {
|
|
363
|
+
async function importFiles({ io, token, endpoint, directory, root, corpus, publish: publishToo, dryRun }) {
|
|
363
364
|
const out = (message) => io.out(redact(message, token));
|
|
364
365
|
if (corpus.files.length === 0 && corpus.problems.length === 0) throw new CliError(`no entries in ${directory}: expected Markdown files at <collection>/<locale>/<slug>.md, such as blog/en/hello.md.`);
|
|
365
366
|
if (corpus.files.length > 0) out(`Found ${count(corpus.files.length, "entry", "entries")} in ${directory} (${collectionSummary(corpus.files)}).`);
|
|
@@ -371,6 +372,7 @@ async function importFiles({ io, token, endpoint, directory, corpus, publish: pu
|
|
|
371
372
|
].join("\n"));
|
|
372
373
|
const session = await openSession(endpoint, token, readVersion());
|
|
373
374
|
try {
|
|
375
|
+
await uploadImages(session, root, directory, dryRun, out);
|
|
374
376
|
const checks = await validateAll(session, corpus.files);
|
|
375
377
|
if (dryRun) out(dryRunReport(checks));
|
|
376
378
|
const refused = checks.filter((check) => check.refusals.length > 0 || check.failure !== void 0);
|
|
@@ -668,5 +670,42 @@ function listSome(paths) {
|
|
|
668
670
|
const shown = paths.slice(0, 5).map(printable);
|
|
669
671
|
return paths.length > shown.length ? `${shown.join(", ")} and ${paths.length - shown.length} more` : shown.join(", ");
|
|
670
672
|
}
|
|
673
|
+
/**
|
|
674
|
+
* The images an export kept in `_assets/` (ADR-038), uploaded before the entries that show them:
|
|
675
|
+
* each is the file as it was uploaded, so it gets its id again and every `asset:` reference of the
|
|
676
|
+
* entries still names it. An image the site has already is `exists`, and nothing changes.
|
|
677
|
+
*/
|
|
678
|
+
async function uploadImages(session, root, directory, dryRun, out) {
|
|
679
|
+
const manifestFile = join(root, "_assets", "assets.json");
|
|
680
|
+
if (!existsSync(manifestFile)) return;
|
|
681
|
+
let manifest;
|
|
682
|
+
try {
|
|
683
|
+
manifest = JSON.parse(readFileSync(manifestFile, "utf8"));
|
|
684
|
+
} catch {
|
|
685
|
+
throw new CliError(`${directory}/_assets/assets.json is not JSON. Nothing was sent.`);
|
|
686
|
+
}
|
|
687
|
+
const names = Object.keys(manifest).sort();
|
|
688
|
+
if (dryRun) {
|
|
689
|
+
out(`Would upload ${count(names.length, "image")} of ${directory}/_assets.`);
|
|
690
|
+
return;
|
|
691
|
+
}
|
|
692
|
+
let created = 0;
|
|
693
|
+
let existing = 0;
|
|
694
|
+
for (const name of names) {
|
|
695
|
+
const { alt, filename } = manifest[name] ?? {};
|
|
696
|
+
if (!/^ast_[0-9a-f]{26}\.[a-z]+$/.test(name) || typeof alt !== "string") throw new CliError(`${directory}/_assets/assets.json names ${printable(name)} without its alt, or not as an export writes it. Nothing more was sent.`);
|
|
697
|
+
const data = readFileSync(join(root, "_assets", name)).toString("base64");
|
|
698
|
+
const answer = await session.call(uploadAsset, {
|
|
699
|
+
filename: typeof filename === "string" && filename !== "" ? filename : name,
|
|
700
|
+
alt,
|
|
701
|
+
data
|
|
702
|
+
});
|
|
703
|
+
if (answer.outcome === "created") created += 1;
|
|
704
|
+
else if (answer.outcome === "exists") existing += 1;
|
|
705
|
+
else throw new CliError(`could not upload ${printable(name)}: ${answer.problem?.message ?? answer.outcome} ${answer.problem?.fix ?? ""}`.trim());
|
|
706
|
+
if (answer.asset !== void 0 && `${answer.asset.id}.` !== name.slice(0, answer.asset.id.length + 1)) throw new CliError(`${printable(name)} came back as ${answer.asset.id}: the file is not the one the export wrote.`);
|
|
707
|
+
}
|
|
708
|
+
out(`Images: ${created} uploaded, ${existing} already there.`);
|
|
709
|
+
}
|
|
671
710
|
//#endregion
|
|
672
711
|
export { redact as a, openSession as c, readToken as i, importContent as n, withoutToken as o, mcpEndpoint as r, ToolFailure as s, IMPORT_USAGE as t };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { n as importContent } from "./import-BpIvnM-l.mjs";
|
package/dist/index.mjs
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { n as UsageError, t as CliError } from "./errors-DJX_jiSP.mjs";
|
|
3
3
|
import { t as printable } from "./format-Dvk_h5ys.mjs";
|
|
4
4
|
import { t as readVersion } from "./version-BMhdZaNo.mjs";
|
|
5
|
-
import { t as createWranglerRunner } from "./wrangler-
|
|
5
|
+
import { t as createWranglerRunner } from "./wrangler-C0QYL8dC.mjs";
|
|
6
6
|
import { spawn } from "node:child_process";
|
|
7
7
|
import { mkdtempSync, realpathSync } from "node:fs";
|
|
8
8
|
import { tmpdir } from "node:os";
|
|
@@ -114,16 +114,16 @@ async function main(argv, io) {
|
|
|
114
114
|
}
|
|
115
115
|
async function run(command, args, io) {
|
|
116
116
|
switch (command) {
|
|
117
|
-
case "init": return (await import("./init-
|
|
118
|
-
case "dev": return (await import("./dev
|
|
117
|
+
case "init": return (await import("./init-A7Un-Ng_.mjs")).init(args, io);
|
|
118
|
+
case "dev": return (await import("./dev-B2gk-YHQ.mjs")).dev(args, io);
|
|
119
119
|
case "mcp-config": return (await import("./mcp-config-CDOUrEpU.mjs")).mcpConfig(args, io);
|
|
120
|
-
case "migrate": return (await import("./migrate-
|
|
121
|
-
case "deploy": return (await import("./deploy-
|
|
122
|
-
case "doctor": return (await import("./doctor-
|
|
123
|
-
case "token": return (await import("./token-
|
|
124
|
-
case "invite": return (await import("./invite-
|
|
125
|
-
case "export": return (await import("./export-
|
|
126
|
-
default: return (await import("./import-
|
|
120
|
+
case "migrate": return (await import("./migrate-C15IVa7w.mjs")).migrate(args, io);
|
|
121
|
+
case "deploy": return (await import("./deploy-sYjaZ0d4.mjs")).deploy(args, io);
|
|
122
|
+
case "doctor": return (await import("./doctor-DjRkQKrh.mjs")).doctor(args, io);
|
|
123
|
+
case "token": return (await import("./token-DG5H7VPC.mjs")).token(args, io);
|
|
124
|
+
case "invite": return (await import("./invite-CsGI2Gut.mjs")).invite(args, io);
|
|
125
|
+
case "export": return (await import("./export-HsextQcU.mjs")).exportContent(args, io);
|
|
126
|
+
default: return (await import("./import-CsbL7X6d.mjs")).importContent(args, io);
|
|
127
127
|
}
|
|
128
128
|
}
|
|
129
129
|
function isEntryPoint() {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { n as UsageError, t as CliError } from "./errors-DJX_jiSP.mjs";
|
|
2
2
|
import { t as parseFlags } from "./args-D42wi6n2.mjs";
|
|
3
|
-
import { _ as parseSiteKey, a as runFile, c as insertInvitation, f as ownerQuery, h as parseOwnerName, i as resolveDatabase, n as describeDatabase, o as anotherSiteScript, r as query, s as initScript, t as chooseTarget } from "./d1-
|
|
3
|
+
import { _ as parseSiteKey, a as runFile, c as insertInvitation, f as ownerQuery, h as parseOwnerName, i as resolveDatabase, n as describeDatabase, o as anotherSiteScript, r as query, s as initScript, t as chooseTarget } from "./d1-B6dc_ugC.mjs";
|
|
4
4
|
import { n as setupLink, t as publicUrlOf } from "./public-url-d_yOsEMO.mjs";
|
|
5
5
|
import { a as newInvitationSecret, i as newId, n as tokenFileOf, o as newPersonalToken, r as inDays, t as deliverToken } from "./token-output-DTn4X40H.mjs";
|
|
6
6
|
import { a as mcpJson, i as claudeAddLine, o as setVariableLine } from "./mcp-config-BU2YmmGE.mjs";
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { n as UsageError, t as CliError } from "./errors-DJX_jiSP.mjs";
|
|
2
2
|
import { t as parseFlags } from "./args-D42wi6n2.mjs";
|
|
3
|
-
import { _ as parseSiteKey, c as insertInvitation, d as ownerOfSiteQuery, i as resolveDatabase, p as parseExpiresInDays, r as query, t as chooseTarget, x as sitesQuery } from "./d1-
|
|
3
|
+
import { _ as parseSiteKey, c as insertInvitation, d as ownerOfSiteQuery, i as resolveDatabase, p as parseExpiresInDays, r as query, t as chooseTarget, x as sitesQuery } from "./d1-B6dc_ugC.mjs";
|
|
4
4
|
import { n as setupLink, t as publicUrlOf } from "./public-url-d_yOsEMO.mjs";
|
|
5
5
|
import { a as newInvitationSecret, i as newId, r as inDays } from "./token-output-DTn4X40H.mjs";
|
|
6
|
-
import { o as WHERE_OPTIONS, s as chooseSite } from "./token-
|
|
6
|
+
import { o as WHERE_OPTIONS, s as chooseSite } from "./token-BxAQXSQO.mjs";
|
|
7
7
|
import { hashPersonalToken } from "@hollware/core";
|
|
8
8
|
//#region src/commands/invite.ts
|
|
9
9
|
const INVITE_USAGE = [
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { i as migrate } from "./migrate-Dx-imcel.mjs";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { t as CliError } from "./errors-DJX_jiSP.mjs";
|
|
2
|
-
import { i as stripAnsi, n as failureReason } from "./wrangler-
|
|
2
|
+
import { i as stripAnsi, n as failureReason } from "./wrangler-C0QYL8dC.mjs";
|
|
3
3
|
import { t as parseFlags } from "./args-D42wi6n2.mjs";
|
|
4
|
-
import { i as resolveDatabase, n as describeDatabase, t as chooseTarget } from "./d1-
|
|
4
|
+
import { i as resolveDatabase, n as describeDatabase, t as chooseTarget } from "./d1-B6dc_ugC.mjs";
|
|
5
5
|
import { existsSync, mkdirSync, statSync } from "node:fs";
|
|
6
6
|
import { dirname, join } from "node:path";
|
|
7
7
|
//#region src/commands/migrate.ts
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { n as UsageError, t as CliError } from "./errors-DJX_jiSP.mjs";
|
|
2
2
|
import { n as table, t as printable } from "./format-Dvk_h5ys.mjs";
|
|
3
3
|
import { t as parseFlags } from "./args-D42wi6n2.mjs";
|
|
4
|
-
import { _ as parseSiteKey, b as sitesAndOwnerQuery, g as parseScopes, i as resolveDatabase, l as insertToken, m as parseLabel, p as parseExpiresInDays, r as query, t as chooseTarget, u as listTokens, v as parseTokenId, x as sitesQuery, y as revokeToken } from "./d1-
|
|
4
|
+
import { _ as parseSiteKey, b as sitesAndOwnerQuery, g as parseScopes, i as resolveDatabase, l as insertToken, m as parseLabel, p as parseExpiresInDays, r as query, t as chooseTarget, u as listTokens, v as parseTokenId, x as sitesQuery, y as revokeToken } from "./d1-B6dc_ugC.mjs";
|
|
5
5
|
import { t as publicUrlOf } from "./public-url-d_yOsEMO.mjs";
|
|
6
6
|
import { i as newId, n as tokenFileOf, o as newPersonalToken, r as inDays, s as newReadToken, t as deliverToken } from "./token-output-DTn4X40H.mjs";
|
|
7
7
|
import { hashPersonalToken } from "@hollware/core";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { c as token } from "./token-BxAQXSQO.mjs";
|
|
@@ -80,12 +80,18 @@ function failureReason(result) {
|
|
|
80
80
|
const stderr = stripAnsi(result.stderr);
|
|
81
81
|
const fromJson = jsonError(stdout.trim());
|
|
82
82
|
if (fromJson !== void 0) return oneLine(fromJson);
|
|
83
|
-
const
|
|
84
|
-
for (const line of
|
|
83
|
+
const raw = stderr.split("\n").map((line) => line.trim());
|
|
84
|
+
for (const [index, line] of raw.entries()) {
|
|
85
85
|
const message = /^\W*\[ERROR\]\s*(.+)$/.exec(line)?.[1];
|
|
86
|
-
if (message
|
|
86
|
+
if (message === void 0) continue;
|
|
87
|
+
const parts = [message];
|
|
88
|
+
for (const next of raw.slice(index + 1)) {
|
|
89
|
+
if (next === "" || /^\W*\[(?:ERROR|WARNING|INFO)\]/.test(next)) break;
|
|
90
|
+
parts.push(next);
|
|
91
|
+
}
|
|
92
|
+
return oneLine(parts.join(" "));
|
|
87
93
|
}
|
|
88
|
-
return oneLine(
|
|
94
|
+
return oneLine(linesOf(stderr).at(-1) ?? linesOf(stdout).at(-1) ?? `wrangler exited with code ${result.code} and printed nothing`);
|
|
89
95
|
}
|
|
90
96
|
function linesOf(text) {
|
|
91
97
|
return text.split("\n").map((line) => line.trim()).filter((line) => line !== "" && !line.includes("Logs were written to"));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hollware",
|
|
3
|
-
"version": "1.0.0-rc.
|
|
3
|
+
"version": "1.0.0-rc.2",
|
|
4
4
|
"description": "The Hollware CLI: init, migrate, token, import and export.",
|
|
5
5
|
"homepage": "https://hollware.com",
|
|
6
6
|
"bugs": {
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"provenance": true
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@hollware/core": "1.0.0-rc.
|
|
34
|
+
"@hollware/core": "1.0.0-rc.2",
|
|
35
35
|
"@modelcontextprotocol/client": "2.3.1",
|
|
36
36
|
"zod": "4.6.7"
|
|
37
37
|
},
|
package/dist/import-D4_IhUC7.mjs
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { n as importContent } from "./import-CR4G8q5W.mjs";
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { i as migrate } from "./migrate-D2QcagMk.mjs";
|
package/dist/token-BG3q6bWZ.mjs
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { c as token } from "./token-B0UKrZBf.mjs";
|