@moku-labs/web 0.4.2 → 0.5.1
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 +40 -7
- package/dist/browser.d.mts +1852 -0
- package/dist/browser.mjs +3866 -0
- package/dist/index.cjs +100 -57
- package/dist/index.d.cts +19 -1
- package/dist/index.d.mts +19 -1
- package/dist/index.mjs +100 -58
- package/package.json +8 -1
package/dist/index.mjs
CHANGED
|
@@ -24,7 +24,7 @@ import { h } from "preact";
|
|
|
24
24
|
import { renderToString } from "preact-render-to-string";
|
|
25
25
|
//#region src/plugins/env/api.ts
|
|
26
26
|
/** Error prefix for all env API failures. */
|
|
27
|
-
const ERROR_PREFIX$
|
|
27
|
+
const ERROR_PREFIX$14 = "[web]";
|
|
28
28
|
/**
|
|
29
29
|
* Creates the env plugin API surface mounted at `ctx.env`. Closes over
|
|
30
30
|
* `ctx.state` ({@link EnvState}) and reads the frozen `resolved` / `publicMap`
|
|
@@ -68,7 +68,7 @@ function createEnvApi(ctx) {
|
|
|
68
68
|
*/
|
|
69
69
|
require(key) {
|
|
70
70
|
const value = resolved.get(key);
|
|
71
|
-
if (value === void 0) throw new Error(`${ERROR_PREFIX$
|
|
71
|
+
if (value === void 0) throw new Error(`${ERROR_PREFIX$14} env: required variable "${key}" is not defined.`);
|
|
72
72
|
return value;
|
|
73
73
|
},
|
|
74
74
|
/**
|
|
@@ -135,7 +135,7 @@ function createEnvState() {
|
|
|
135
135
|
/** Error message thrown by every frozen-map mutator. */
|
|
136
136
|
const FROZEN_MESSAGE = "env: map is frozen and cannot be mutated";
|
|
137
137
|
/** Error prefix for all resolution-pipeline failures. */
|
|
138
|
-
const ERROR_PREFIX$
|
|
138
|
+
const ERROR_PREFIX$13 = "[web]";
|
|
139
139
|
/**
|
|
140
140
|
* Throws the canonical frozen-map error; installed as a map's `set`/`clear`/`delete`.
|
|
141
141
|
*
|
|
@@ -186,8 +186,8 @@ function crossCheckPublicPrefix(config) {
|
|
|
186
186
|
const { schema, publicPrefix } = config;
|
|
187
187
|
for (const [key, spec] of Object.entries(schema)) {
|
|
188
188
|
const hasPrefix = key.startsWith(publicPrefix);
|
|
189
|
-
if (spec.public === true && !hasPrefix) throw new Error(`${ERROR_PREFIX$
|
|
190
|
-
if (hasPrefix && spec.public !== true) throw new Error(`${ERROR_PREFIX$
|
|
189
|
+
if (spec.public === true && !hasPrefix) throw new Error(`${ERROR_PREFIX$13} env: "${key}" is marked public but does not start with "${publicPrefix}".`);
|
|
190
|
+
if (hasPrefix && spec.public !== true) throw new Error(`${ERROR_PREFIX$13} env: "${key}" starts with "${publicPrefix}" but is not marked public:true.`);
|
|
191
191
|
}
|
|
192
192
|
}
|
|
193
193
|
/**
|
|
@@ -238,7 +238,7 @@ function validateSchema(ctx) {
|
|
|
238
238
|
crossCheckPublicPrefix(config);
|
|
239
239
|
for (const [key, spec] of Object.entries(schema)) {
|
|
240
240
|
if (merged[key] === void 0 && spec.default !== void 0) merged[key] = spec.default;
|
|
241
|
-
if (merged[key] === void 0 && spec.required === true) throw new Error(`${ERROR_PREFIX$
|
|
241
|
+
if (merged[key] === void 0 && spec.required === true) throw new Error(`${ERROR_PREFIX$13} env: required variable "${key}" is not defined by any provider or default.`);
|
|
242
242
|
}
|
|
243
243
|
for (const [key, spec] of Object.entries(schema)) {
|
|
244
244
|
const value = merged[key];
|
|
@@ -730,6 +730,12 @@ const logPlugin = createCorePlugin("log", {
|
|
|
730
730
|
api: createLogApi,
|
|
731
731
|
onInit: installDefaultSinks
|
|
732
732
|
});
|
|
733
|
+
//#endregion
|
|
734
|
+
//#region src/config.ts
|
|
735
|
+
/**
|
|
736
|
+
* @file Framework configuration — Config + Events types, core plugin registration.
|
|
737
|
+
* @see README.md
|
|
738
|
+
*/
|
|
733
739
|
const coreConfig = createCoreConfig("web", {
|
|
734
740
|
config: { mode: "production" },
|
|
735
741
|
plugins: [logPlugin, envPlugin],
|
|
@@ -759,7 +765,7 @@ const createCore = coreConfig.createCore;
|
|
|
759
765
|
//#endregion
|
|
760
766
|
//#region src/plugins/i18n/api.ts
|
|
761
767
|
/** Error prefix for all i18n lifecycle failures. */
|
|
762
|
-
const ERROR_PREFIX$
|
|
768
|
+
const ERROR_PREFIX$12 = "[web]";
|
|
763
769
|
/**
|
|
764
770
|
* Validates the resolved i18n config (fail-fast at `createApp`). Throws when
|
|
765
771
|
* `locales` is empty or when `defaultLocale` is not a member of `locales`.
|
|
@@ -775,8 +781,8 @@ const ERROR_PREFIX$11 = "[web]";
|
|
|
775
781
|
*/
|
|
776
782
|
function validateI18nConfig(ctx) {
|
|
777
783
|
const { locales, defaultLocale } = ctx.config;
|
|
778
|
-
if (locales.length === 0) throw new Error(`${ERROR_PREFIX$
|
|
779
|
-
if (!locales.includes(defaultLocale)) throw new Error(`${ERROR_PREFIX$
|
|
784
|
+
if (locales.length === 0) throw new Error(`${ERROR_PREFIX$12} i18n.locales must contain at least one locale.\n Set pluginConfigs.i18n.locales to a non-empty array, e.g. ["en"].`);
|
|
785
|
+
if (!locales.includes(defaultLocale)) throw new Error(`${ERROR_PREFIX$12} i18n.defaultLocale "${defaultLocale}" is not in i18n.locales [${locales.join(", ")}].\n Set pluginConfigs.i18n.defaultLocale to one of the configured locales, or add "${defaultLocale}" to i18n.locales.`);
|
|
780
786
|
}
|
|
781
787
|
/**
|
|
782
788
|
* Creates the i18n plugin API surface — locale registry accessors plus the
|
|
@@ -1751,7 +1757,7 @@ const contentPlugin = createPlugin$1("content", {
|
|
|
1751
1757
|
//#endregion
|
|
1752
1758
|
//#region src/plugins/site/api.ts
|
|
1753
1759
|
/** Error prefix for all site lifecycle/validation failures. */
|
|
1754
|
-
const ERROR_PREFIX$
|
|
1760
|
+
const ERROR_PREFIX$11 = "[web]";
|
|
1755
1761
|
/**
|
|
1756
1762
|
* Joins a relative path against an absolute base URL, normalizing the slash
|
|
1757
1763
|
* boundary to exactly one "/". Returns the base unchanged for an empty or
|
|
@@ -1819,8 +1825,8 @@ function isAbsoluteUrl(value) {
|
|
|
1819
1825
|
* ```
|
|
1820
1826
|
*/
|
|
1821
1827
|
function validateSiteConfig(ctx) {
|
|
1822
|
-
if (!isNonEmpty(ctx.config.name)) throw new Error(`${ERROR_PREFIX$
|
|
1823
|
-
if (!isAbsoluteUrl(ctx.config.url)) throw new Error(`${ERROR_PREFIX$
|
|
1828
|
+
if (!isNonEmpty(ctx.config.name)) throw new Error(`${ERROR_PREFIX$11} site.name is required.\n Provide a non-empty site name in pluginConfigs.site.name.`);
|
|
1829
|
+
if (!isAbsoluteUrl(ctx.config.url)) throw new Error(`${ERROR_PREFIX$11} site.url must be a valid absolute URL (http/https), received ${JSON.stringify(ctx.config.url)}.\n Provide an absolute URL in pluginConfigs.site.url, e.g. "https://blog.dev".`);
|
|
1824
1830
|
}
|
|
1825
1831
|
/**
|
|
1826
1832
|
* Creates the site plugin API surface — read-only accessors over frozen config
|
|
@@ -2010,7 +2016,7 @@ function matchRoute(compiled, pathname) {
|
|
|
2010
2016
|
* `manifest`. Returns values/copies, never the raw `ctx.state` reference (spec/11 §2.4).
|
|
2011
2017
|
*/
|
|
2012
2018
|
/** Error prefix for router API failures. */
|
|
2013
|
-
const ERROR_PREFIX$
|
|
2019
|
+
const ERROR_PREFIX$10 = "[web] router";
|
|
2014
2020
|
/**
|
|
2015
2021
|
* Read the compiled matcher table, throwing if `onInit` has not run yet. This
|
|
2016
2022
|
* `null` cannot occur in practice post-`onInit`; the guard documents the invariant.
|
|
@@ -2024,7 +2030,7 @@ const ERROR_PREFIX$9 = "[web] router";
|
|
|
2024
2030
|
* ```
|
|
2025
2031
|
*/
|
|
2026
2032
|
function readTable(state) {
|
|
2027
|
-
if (state.table === null) throw new Error(`${ERROR_PREFIX$
|
|
2033
|
+
if (state.table === null) throw new Error(`${ERROR_PREFIX$10}: matcher table accessed before onInit compiled it.`);
|
|
2028
2034
|
return state.table;
|
|
2029
2035
|
}
|
|
2030
2036
|
/**
|
|
@@ -2108,7 +2114,7 @@ function createApi$4(ctx) {
|
|
|
2108
2114
|
*/
|
|
2109
2115
|
toUrl(routeName, params) {
|
|
2110
2116
|
const entry = readTable(state).byName.get(routeName);
|
|
2111
|
-
if (!entry) throw new Error(`${ERROR_PREFIX$
|
|
2117
|
+
if (!entry) throw new Error(`${ERROR_PREFIX$10}: unknown route name "${routeName}".`);
|
|
2112
2118
|
return entry.toUrl(params);
|
|
2113
2119
|
},
|
|
2114
2120
|
/**
|
|
@@ -2243,7 +2249,7 @@ function bySpecificity(a, b) {
|
|
|
2243
2249
|
* only (`CompileInput`) — never the plugin ctx.
|
|
2244
2250
|
*/
|
|
2245
2251
|
/** Shared `[web]` error prefix for router validation failures. */
|
|
2246
|
-
const ERROR_PREFIX$
|
|
2252
|
+
const ERROR_PREFIX$9 = "[web] router";
|
|
2247
2253
|
/**
|
|
2248
2254
|
* Validate the route map (fail-fast in `onInit`). Throws with the `[web]` prefix
|
|
2249
2255
|
* naming the offending route/pattern on any failure: empty map, a pattern not
|
|
@@ -2258,12 +2264,12 @@ const ERROR_PREFIX$8 = "[web] router";
|
|
|
2258
2264
|
*/
|
|
2259
2265
|
function validateRoutes(routes) {
|
|
2260
2266
|
const names = Object.keys(routes);
|
|
2261
|
-
if (names.length === 0) throw new Error(`${ERROR_PREFIX$
|
|
2267
|
+
if (names.length === 0) throw new Error(`${ERROR_PREFIX$9}: route map is empty — provide at least one route via pluginConfigs.router.routes.`);
|
|
2262
2268
|
for (const name of names) {
|
|
2263
2269
|
const pattern = routes[name]?.pattern ?? "";
|
|
2264
|
-
if (!pattern.startsWith("/")) throw new Error(`${ERROR_PREFIX$
|
|
2265
|
-
if ((pattern.match(/\{/g) ?? []).length !== (pattern.match(/\}/g) ?? []).length) throw new Error(`${ERROR_PREFIX$
|
|
2266
|
-
if ((pattern.match(/\{lang:\?\}/g) ?? []).length > 1) throw new Error(`${ERROR_PREFIX$
|
|
2270
|
+
if (!pattern.startsWith("/")) throw new Error(`${ERROR_PREFIX$9}: route "${name}" pattern must start with "/" (got "${pattern}").`);
|
|
2271
|
+
if ((pattern.match(/\{/g) ?? []).length !== (pattern.match(/\}/g) ?? []).length) throw new Error(`${ERROR_PREFIX$9}: route "${name}" pattern has unbalanced braces ("${pattern}").`);
|
|
2272
|
+
if ((pattern.match(/\{lang:\?\}/g) ?? []).length > 1) throw new Error(`${ERROR_PREFIX$9}: route "${name}" pattern has more than one {lang:?} segment ("${pattern}").`);
|
|
2267
2273
|
}
|
|
2268
2274
|
}
|
|
2269
2275
|
/**
|
|
@@ -3045,7 +3051,7 @@ function serializeHead(elements) {
|
|
|
3045
3051
|
* it to a string. It holds no resource and caches no subscription.
|
|
3046
3052
|
*/
|
|
3047
3053
|
/** Error prefix for head API invariant failures. */
|
|
3048
|
-
const ERROR_PREFIX$
|
|
3054
|
+
const ERROR_PREFIX$8 = "[head]";
|
|
3049
3055
|
/**
|
|
3050
3056
|
* Read the normalized defaults, asserting the post-`onInit` invariant (the slot is
|
|
3051
3057
|
* `null` only before `onInit` assigns it, which cannot occur at render time).
|
|
@@ -3059,7 +3065,7 @@ const ERROR_PREFIX$7 = "[head]";
|
|
|
3059
3065
|
* ```
|
|
3060
3066
|
*/
|
|
3061
3067
|
function readDefaults(state) {
|
|
3062
|
-
if (state.defaults === null) throw new Error(`${ERROR_PREFIX$
|
|
3068
|
+
if (state.defaults === null) throw new Error(`${ERROR_PREFIX$8}: defaults accessed before onInit normalized them.`);
|
|
3063
3069
|
return state.defaults;
|
|
3064
3070
|
}
|
|
3065
3071
|
/**
|
|
@@ -3102,7 +3108,7 @@ render(route, data) {
|
|
|
3102
3108
|
//#endregion
|
|
3103
3109
|
//#region src/plugins/head/config.ts
|
|
3104
3110
|
/** Error prefix for all head config-validation failures. */
|
|
3105
|
-
const ERROR_PREFIX$
|
|
3111
|
+
const ERROR_PREFIX$7 = "[head] config:";
|
|
3106
3112
|
/** The allowed `twitterCard` literals (also the runtime guard set). */
|
|
3107
3113
|
const VALID_TWITTER_CARDS = ["summary", "summary_large_image"];
|
|
3108
3114
|
/**
|
|
@@ -3129,8 +3135,8 @@ const defaultConfig$2 = { twitterCard: "summary_large_image" };
|
|
|
3129
3135
|
* ```
|
|
3130
3136
|
*/
|
|
3131
3137
|
function validateHeadConfig(config) {
|
|
3132
|
-
if (config.titleTemplate !== void 0 && !config.titleTemplate.includes("%s")) throw new Error(`${ERROR_PREFIX$
|
|
3133
|
-
if (config.twitterCard !== void 0 && !VALID_TWITTER_CARDS.includes(config.twitterCard)) throw new Error(`${ERROR_PREFIX$
|
|
3138
|
+
if (config.titleTemplate !== void 0 && !config.titleTemplate.includes("%s")) throw new Error(`${ERROR_PREFIX$7} titleTemplate must contain the "%s" token (replaced by the route title), received ${JSON.stringify(config.titleTemplate)}.`);
|
|
3139
|
+
if (config.twitterCard !== void 0 && !VALID_TWITTER_CARDS.includes(config.twitterCard)) throw new Error(`${ERROR_PREFIX$7} twitterCard must be one of [${VALID_TWITTER_CARDS.join(", ")}], received ${JSON.stringify(config.twitterCard)}.`);
|
|
3134
3140
|
}
|
|
3135
3141
|
/**
|
|
3136
3142
|
* Validate then build the frozen, normalized {@link HeadDefaults} snapshot read by
|
|
@@ -3588,13 +3594,14 @@ async function expandRedirects(definition, entry, defaultLocale) {
|
|
|
3588
3594
|
const parameterSets = definition._handlers.generate ? await definition._handlers.generate(defaultLocale) : [{}];
|
|
3589
3595
|
const jobs = [];
|
|
3590
3596
|
for (const raw of parameterSets) {
|
|
3591
|
-
const
|
|
3592
|
-
|
|
3597
|
+
const bareParams = { ...raw ?? {} };
|
|
3598
|
+
delete bareParams.lang;
|
|
3599
|
+
const file = entry.toFile(bareParams);
|
|
3593
3600
|
const target = entry.toUrl({
|
|
3594
|
-
...
|
|
3601
|
+
...bareParams,
|
|
3595
3602
|
lang: defaultLocale
|
|
3596
3603
|
});
|
|
3597
|
-
if (target !== entry.toUrl(
|
|
3604
|
+
if (target !== entry.toUrl(bareParams)) jobs.push({
|
|
3598
3605
|
file,
|
|
3599
3606
|
target
|
|
3600
3607
|
});
|
|
@@ -3937,7 +3944,7 @@ async function generateOgImages(ctx, options = {}) {
|
|
|
3937
3944
|
try {
|
|
3938
3945
|
const png = await renderPng(input);
|
|
3939
3946
|
await mkdir(outDir, { recursive: true });
|
|
3940
|
-
await writeFile(path.join(outDir, `${
|
|
3947
|
+
await writeFile(path.join(outDir, `${article.computed.slug}.png`), png);
|
|
3941
3948
|
cache.set(key, hash);
|
|
3942
3949
|
rendered += 1;
|
|
3943
3950
|
} finally {
|
|
@@ -4775,7 +4782,7 @@ async function runPipeline(ctx, options) {
|
|
|
4775
4782
|
* @file build plugin — API factory (run + phases), cross-plugin wiring, and onInit config validation.
|
|
4776
4783
|
*/
|
|
4777
4784
|
/** Error prefix for build config/validation failures (spec/11 Part-3). */
|
|
4778
|
-
const ERROR_PREFIX$
|
|
4785
|
+
const ERROR_PREFIX$6 = "[web] build";
|
|
4779
4786
|
/** Recognized font file extensions for OG-image validation. */
|
|
4780
4787
|
const FONT_EXTENSIONS = [
|
|
4781
4788
|
".ttf",
|
|
@@ -4846,8 +4853,8 @@ function createApi$2(ctx) {
|
|
|
4846
4853
|
* ```
|
|
4847
4854
|
*/
|
|
4848
4855
|
function validateFonts(og) {
|
|
4849
|
-
if (typeof og.fontDir !== "string" || og.fontDir.length === 0 || !existsSync(og.fontDir)) throw new Error(`${ERROR_PREFIX$
|
|
4850
|
-
if (!readdirSync(og.fontDir).some((name) => FONT_EXTENSIONS.some((extension) => name.endsWith(extension)))) throw new Error(`${ERROR_PREFIX$
|
|
4856
|
+
if (typeof og.fontDir !== "string" || og.fontDir.length === 0 || !existsSync(og.fontDir)) throw new Error(`${ERROR_PREFIX$6}.ogImage: fontDir "${og.fontDir}" does not exist — provide a directory with at least one font.`);
|
|
4857
|
+
if (!readdirSync(og.fontDir).some((name) => FONT_EXTENSIONS.some((extension) => name.endsWith(extension)))) throw new Error(`${ERROR_PREFIX$6}.ogImage: fontDir "${og.fontDir}" contains no .ttf/.otf/.woff font files.`);
|
|
4851
4858
|
}
|
|
4852
4859
|
/**
|
|
4853
4860
|
* Validates `build` config synchronously in `onInit` (return value discarded).
|
|
@@ -4861,10 +4868,10 @@ function validateFonts(og) {
|
|
|
4861
4868
|
* ```
|
|
4862
4869
|
*/
|
|
4863
4870
|
function validateConfig$1(config) {
|
|
4864
|
-
if (typeof config.outDir !== "string" || config.outDir.trim().length === 0) throw new Error(`${ERROR_PREFIX$
|
|
4865
|
-
if (config.publicDir !== void 0 && typeof config.publicDir !== "string") throw new Error(`${ERROR_PREFIX$
|
|
4866
|
-
if (config.template !== void 0 && typeof config.template !== "string") throw new Error(`${ERROR_PREFIX$
|
|
4867
|
-
if (config.clientEntry !== void 0 && typeof config.clientEntry !== "string") throw new Error(`${ERROR_PREFIX$
|
|
4871
|
+
if (typeof config.outDir !== "string" || config.outDir.trim().length === 0) throw new Error(`${ERROR_PREFIX$6}.outDir: must be a non-empty string.`);
|
|
4872
|
+
if (config.publicDir !== void 0 && typeof config.publicDir !== "string") throw new Error(`${ERROR_PREFIX$6}.publicDir: must be a string when set.`);
|
|
4873
|
+
if (config.template !== void 0 && typeof config.template !== "string") throw new Error(`${ERROR_PREFIX$6}.template: must be a string path when set.`);
|
|
4874
|
+
if (config.clientEntry !== void 0 && typeof config.clientEntry !== "string") throw new Error(`${ERROR_PREFIX$6}.clientEntry: must be a string path when set.`);
|
|
4868
4875
|
if (config.ogImage) validateFonts(config.ogImage);
|
|
4869
4876
|
}
|
|
4870
4877
|
//#endregion
|
|
@@ -4966,7 +4973,7 @@ const buildPlugin = createPlugin$1("build", {
|
|
|
4966
4973
|
*/
|
|
4967
4974
|
const MOKU_WRANGLER_VERSION = "4.34.0";
|
|
4968
4975
|
/** Error prefix for deploy runtime failures (spec/11 Part-3). */
|
|
4969
|
-
const ERROR_PREFIX$
|
|
4976
|
+
const ERROR_PREFIX$5 = "[web] deploy";
|
|
4970
4977
|
/** Mask substituted for a detected secret-like token. */
|
|
4971
4978
|
const MASK = "***";
|
|
4972
4979
|
/** Minimum token length eligible for entropy-gated scrubbing. */
|
|
@@ -5044,7 +5051,7 @@ function scrubSecrets(text, allowlist) {
|
|
|
5044
5051
|
* guardBranch("preview/landing"); // "preview/landing"
|
|
5045
5052
|
*/
|
|
5046
5053
|
function guardBranch(branch) {
|
|
5047
|
-
if (!BRANCH_REGEX.test(branch) || branch.startsWith("-")) throw deployError("ERR_DEPLOY_INVALID_BRANCH", `${ERROR_PREFIX$
|
|
5054
|
+
if (!BRANCH_REGEX.test(branch) || branch.startsWith("-")) throw deployError("ERR_DEPLOY_INVALID_BRANCH", `${ERROR_PREFIX$5}: branch ${JSON.stringify(branch)} is invalid.\n Branches must match /^[a-zA-Z0-9/_.-]+$/ so they cannot inject wrangler flags.`);
|
|
5048
5055
|
return branch;
|
|
5049
5056
|
}
|
|
5050
5057
|
/**
|
|
@@ -5061,7 +5068,7 @@ function guardBranch(branch) {
|
|
|
5061
5068
|
function assertWithinRoot(outDir, root) {
|
|
5062
5069
|
const resolved = path.isAbsolute(outDir) ? path.resolve(outDir) : path.resolve(root, outDir);
|
|
5063
5070
|
const rootResolved = path.resolve(root);
|
|
5064
|
-
if (resolved !== rootResolved && !resolved.startsWith(rootResolved + path.sep)) throw deployError("ERR_DEPLOY_PATH_TRAVERSAL", `${ERROR_PREFIX$
|
|
5071
|
+
if (resolved !== rootResolved && !resolved.startsWith(rootResolved + path.sep)) throw deployError("ERR_DEPLOY_PATH_TRAVERSAL", `${ERROR_PREFIX$5}: outDir ${JSON.stringify(outDir)} resolves outside the project root.\n Point outDir at a directory inside ${JSON.stringify(rootResolved)}.`);
|
|
5065
5072
|
return resolved;
|
|
5066
5073
|
}
|
|
5067
5074
|
/**
|
|
@@ -5146,11 +5153,11 @@ function classifyWranglerError(exitCode, scrubbedStderr) {
|
|
|
5146
5153
|
const haystack = scrubbedStderr.toLowerCase();
|
|
5147
5154
|
for (const signature of ERROR_SIGNATURES) if (signature.match.some((needle) => haystack.includes(needle))) return {
|
|
5148
5155
|
code: signature.kind,
|
|
5149
|
-
message: `${ERROR_PREFIX$
|
|
5156
|
+
message: `${ERROR_PREFIX$5}: wrangler failed (exit ${exitCode}).\n ${signature.advice}`
|
|
5150
5157
|
};
|
|
5151
5158
|
return {
|
|
5152
5159
|
code: "ERR_DEPLOY_WRANGLER_FAILED",
|
|
5153
|
-
message: `${ERROR_PREFIX$
|
|
5160
|
+
message: `${ERROR_PREFIX$5}: wrangler failed (exit ${exitCode}).\n ${scrubbedStderr.trim().slice(-500)}`
|
|
5154
5161
|
};
|
|
5155
5162
|
}
|
|
5156
5163
|
/**
|
|
@@ -5416,7 +5423,7 @@ async function reconcile(input) {
|
|
|
5416
5423
|
* and short-circuiting on the first failure.
|
|
5417
5424
|
*/
|
|
5418
5425
|
/** Error prefix for deploy preflight failures (spec/11 Part-3). */
|
|
5419
|
-
const ERROR_PREFIX$
|
|
5426
|
+
const ERROR_PREFIX$4 = "[web] deploy";
|
|
5420
5427
|
/** Cloudflare Pages free-tier file-count limit. */
|
|
5421
5428
|
const FREE_TIER_FILE_LIMIT = 2e4;
|
|
5422
5429
|
/** Cloudflare Pages paid-tier file-count limit (env override target). */
|
|
@@ -5492,15 +5499,15 @@ async function runPreflight(config, root, env = process.env) {
|
|
|
5492
5499
|
try {
|
|
5493
5500
|
await stat(wranglerPath);
|
|
5494
5501
|
} catch {
|
|
5495
|
-
throw deployError("ERR_DEPLOY_NO_WRANGLER_CONFIG", `${ERROR_PREFIX$
|
|
5502
|
+
throw deployError("ERR_DEPLOY_NO_WRANGLER_CONFIG", `${ERROR_PREFIX$4}: wrangler.jsonc not found.\n Run \`app.deploy.init()\` to scaffold it, then retry.`);
|
|
5496
5503
|
}
|
|
5497
5504
|
const stats = await inspectOutdir(path.isAbsolute(config.outDir) ? path.resolve(config.outDir) : path.resolve(root, config.outDir)).catch(() => {
|
|
5498
|
-
throw deployError("ERR_DEPLOY_EMPTY_OUTDIR", `${ERROR_PREFIX$
|
|
5505
|
+
throw deployError("ERR_DEPLOY_EMPTY_OUTDIR", `${ERROR_PREFIX$4}: outDir ${JSON.stringify(config.outDir)} is missing.\n Run your build first, then retry.`);
|
|
5499
5506
|
});
|
|
5500
|
-
if (stats.fileCount === 0) throw deployError("ERR_DEPLOY_EMPTY_OUTDIR", `${ERROR_PREFIX$
|
|
5507
|
+
if (stats.fileCount === 0) throw deployError("ERR_DEPLOY_EMPTY_OUTDIR", `${ERROR_PREFIX$4}: outDir ${JSON.stringify(config.outDir)} is empty — nothing to deploy.`);
|
|
5501
5508
|
const limit = resolveFileLimit(env);
|
|
5502
|
-
if (stats.fileCount > limit) throw deployError("ERR_DEPLOY_TOO_MANY_FILES", `${ERROR_PREFIX$
|
|
5503
|
-
if (stats.oversizePath !== null) throw deployError("ERR_DEPLOY_FILE_TOO_LARGE", `${ERROR_PREFIX$
|
|
5509
|
+
if (stats.fileCount > limit) throw deployError("ERR_DEPLOY_TOO_MANY_FILES", `${ERROR_PREFIX$4}: outDir contains ${stats.fileCount} files; the limit is ${limit}.\n Raise it with ${MAX_FILES_ENV} (paid tier) or reduce the output.`);
|
|
5510
|
+
if (stats.oversizePath !== null) throw deployError("ERR_DEPLOY_FILE_TOO_LARGE", `${ERROR_PREFIX$4}: file ${JSON.stringify(stats.oversizePath)} exceeds the 25 MiB per-file limit.`);
|
|
5504
5511
|
}
|
|
5505
5512
|
//#endregion
|
|
5506
5513
|
//#region src/plugins/deploy/slug.ts
|
|
@@ -5545,7 +5552,7 @@ function toSlug(name) {
|
|
|
5545
5552
|
//#endregion
|
|
5546
5553
|
//#region src/plugins/deploy/api.ts
|
|
5547
5554
|
/** Error prefix for deploy config/validation failures (spec/11 Part-3). */
|
|
5548
|
-
const ERROR_PREFIX$
|
|
5555
|
+
const ERROR_PREFIX$3 = "[web] deploy";
|
|
5549
5556
|
/** `YYYY-MM-DD` validator for the compatibility date config field. */
|
|
5550
5557
|
const COMPAT_DATE_REGEX = /^\d{4}-\d{2}-\d{2}$/;
|
|
5551
5558
|
/**
|
|
@@ -5560,10 +5567,10 @@ const COMPAT_DATE_REGEX = /^\d{4}-\d{2}-\d{2}$/;
|
|
|
5560
5567
|
*/
|
|
5561
5568
|
function validateConfig(ctx) {
|
|
5562
5569
|
const { config } = ctx;
|
|
5563
|
-
if (config.target !== "cloudflare-pages") throw deployError("ERR_DEPLOY_CONFIG", `${ERROR_PREFIX$
|
|
5564
|
-
if (typeof config.outDir !== "string" || config.outDir.length === 0) throw deployError("ERR_DEPLOY_CONFIG", `${ERROR_PREFIX$
|
|
5565
|
-
if (!Array.isArray(config.scrubAllowlist) || !config.scrubAllowlist.every((item) => typeof item === "string")) throw deployError("ERR_DEPLOY_CONFIG", `${ERROR_PREFIX$
|
|
5566
|
-
if (config.compatibilityDate !== void 0 && !COMPAT_DATE_REGEX.test(config.compatibilityDate)) throw deployError("ERR_DEPLOY_CONFIG", `${ERROR_PREFIX$
|
|
5570
|
+
if (config.target !== "cloudflare-pages") throw deployError("ERR_DEPLOY_CONFIG", `${ERROR_PREFIX$3}: target ${JSON.stringify(config.target)} is unsupported.\n Only "cloudflare-pages" is supported in this version.`);
|
|
5571
|
+
if (typeof config.outDir !== "string" || config.outDir.length === 0) throw deployError("ERR_DEPLOY_CONFIG", `${ERROR_PREFIX$3}: outDir must be a non-empty string.\n Set pluginConfigs.deploy.outDir to your build output directory (e.g. "dist").`);
|
|
5572
|
+
if (!Array.isArray(config.scrubAllowlist) || !config.scrubAllowlist.every((item) => typeof item === "string")) throw deployError("ERR_DEPLOY_CONFIG", `${ERROR_PREFIX$3}: scrubAllowlist must be an array of strings.`);
|
|
5573
|
+
if (config.compatibilityDate !== void 0 && !COMPAT_DATE_REGEX.test(config.compatibilityDate)) throw deployError("ERR_DEPLOY_CONFIG", `${ERROR_PREFIX$3}: compatibilityDate ${JSON.stringify(config.compatibilityDate)} must be in YYYY-MM-DD form.`);
|
|
5567
5574
|
ctx.require(sitePlugin);
|
|
5568
5575
|
}
|
|
5569
5576
|
/**
|
|
@@ -5842,7 +5849,38 @@ const COMPONENT_HOOK_NAMES = [
|
|
|
5842
5849
|
"onUnMount",
|
|
5843
5850
|
"onDestroy"
|
|
5844
5851
|
];
|
|
5845
|
-
|
|
5852
|
+
//#endregion
|
|
5853
|
+
//#region src/plugins/spa/components.ts
|
|
5854
|
+
/** Error prefix for spa fail-fast failures (spec/11 Part-3). */
|
|
5855
|
+
const ERROR_PREFIX$2 = "[web]";
|
|
5856
|
+
/** The set of legal hook names, frozen for O(1) membership checks. */
|
|
5857
|
+
const HOOK_NAME_SET = new Set(COMPONENT_HOOK_NAMES);
|
|
5858
|
+
/**
|
|
5859
|
+
* Create a validated component definition. Validates hook names at registration
|
|
5860
|
+
* for fail-fast typo detection (e.g. `onMout` throws immediately) and asserts
|
|
5861
|
+
* each provided hook is a function.
|
|
5862
|
+
*
|
|
5863
|
+
* @param name - Unique component name.
|
|
5864
|
+
* @param hooks - Lifecycle hook implementations.
|
|
5865
|
+
* @returns A `ComponentDef` ready to `register`.
|
|
5866
|
+
* @throws {Error} If `name` is empty, any hook key is not in
|
|
5867
|
+
* `COMPONENT_HOOK_NAMES`, or any provided hook value is not a function.
|
|
5868
|
+
* @example
|
|
5869
|
+
* const counter = createComponent("counter", {
|
|
5870
|
+
* onMount({ el }) { el.textContent = "0"; }
|
|
5871
|
+
* });
|
|
5872
|
+
*/
|
|
5873
|
+
function createComponent(name, hooks) {
|
|
5874
|
+
if (name.trim() === "") throw new Error(`${ERROR_PREFIX$2} component name must be a non-empty string\n → pass a unique name to createComponent("name", hooks)`);
|
|
5875
|
+
for (const key of Object.keys(hooks)) {
|
|
5876
|
+
if (!HOOK_NAME_SET.has(key)) throw new Error(`${ERROR_PREFIX$2} unknown component hook "${key}" on "${name}"\n → valid hooks: ${COMPONENT_HOOK_NAMES.join(", ")}`);
|
|
5877
|
+
if (typeof hooks[key] !== "function") throw new TypeError(`${ERROR_PREFIX$2} component hook "${key}" on "${name}" must be a function\n → provide a function or omit the hook`);
|
|
5878
|
+
}
|
|
5879
|
+
return {
|
|
5880
|
+
name,
|
|
5881
|
+
hooks
|
|
5882
|
+
};
|
|
5883
|
+
}
|
|
5846
5884
|
/**
|
|
5847
5885
|
* Extracts the page data payload from the inline `script#__DATA__` element.
|
|
5848
5886
|
* Returns an empty object when the script is absent, empty, or invalid JSON.
|
|
@@ -7042,9 +7080,13 @@ function cloudflareBindings() {
|
|
|
7042
7080
|
* `createApp({ plugins: [...] })` in a Node build; omit them in a browser app.
|
|
7043
7081
|
* The framework never hard-blocks either runtime — the consumer composes the
|
|
7044
7082
|
* variant it needs and supplies the matching `env` provider.
|
|
7083
|
+
*
|
|
7084
|
+
* This is the full surface (dual ESM+CJS). For a guaranteed node-free client
|
|
7085
|
+
* bundle, import the `@moku-labs/web/browser` entry instead of relying on
|
|
7086
|
+
* tree-shaking this one — see `src/browser.ts`.
|
|
7045
7087
|
* @see README.md
|
|
7046
7088
|
*/
|
|
7047
|
-
const
|
|
7089
|
+
const core = createCore(coreConfig, {
|
|
7048
7090
|
plugins: [
|
|
7049
7091
|
sitePlugin,
|
|
7050
7092
|
i18nPlugin,
|
|
@@ -7083,7 +7125,7 @@ const framework = createCore(coreConfig, {
|
|
|
7083
7125
|
* await app.build.run();
|
|
7084
7126
|
* ```
|
|
7085
7127
|
*/
|
|
7086
|
-
const createApp =
|
|
7128
|
+
const createApp = core.createApp;
|
|
7087
7129
|
/**
|
|
7088
7130
|
* Create a custom plugin bound to this framework's `Config`/`Events` and core
|
|
7089
7131
|
* APIs. Plugin types are inferred from the spec object — never written explicitly.
|
|
@@ -7099,6 +7141,6 @@ const createApp = framework.createApp;
|
|
|
7099
7141
|
* const app = createApp({ plugins: [analytics] });
|
|
7100
7142
|
* ```
|
|
7101
7143
|
*/
|
|
7102
|
-
const createPlugin =
|
|
7144
|
+
const createPlugin = core.createPlugin;
|
|
7103
7145
|
//#endregion
|
|
7104
|
-
export { types_exports as Build, types_exports$1 as Content, types_exports$2 as Data, types_exports$3 as Deploy, types_exports$4 as Env, types_exports$5 as Head, types_exports$6 as Log, types_exports$7 as Router, types_exports$8 as Spa, browserEnv, buildArticleHead, buildPlugin, canonical, cloudflareBindings, contentPlugin, createApp, createPlugin, dataPlugin, defineRoutes, deployPlugin, dotenv, envPlugin, feedLink, headPlugin, hreflang, i18nPlugin, jsonLd, logPlugin, meta, og, processEnv, route, routerPlugin, sitePlugin, spaPlugin, twitter };
|
|
7146
|
+
export { types_exports as Build, types_exports$1 as Content, types_exports$2 as Data, types_exports$3 as Deploy, types_exports$4 as Env, types_exports$5 as Head, types_exports$6 as Log, types_exports$7 as Router, types_exports$8 as Spa, browserEnv, buildArticleHead, buildPlugin, canonical, cloudflareBindings, contentPlugin, createApp, createComponent, createPlugin, dataPlugin, defineRoutes, deployPlugin, dotenv, envPlugin, feedLink, headPlugin, hreflang, i18nPlugin, jsonLd, logPlugin, meta, og, processEnv, route, routerPlugin, sitePlugin, spaPlugin, twitter };
|
package/package.json
CHANGED
|
@@ -39,6 +39,12 @@
|
|
|
39
39
|
"types": "./dist/index.d.cts",
|
|
40
40
|
"default": "./dist/index.cjs"
|
|
41
41
|
}
|
|
42
|
+
},
|
|
43
|
+
"./browser": {
|
|
44
|
+
"import": {
|
|
45
|
+
"types": "./dist/browser.d.mts",
|
|
46
|
+
"default": "./dist/browser.mjs"
|
|
47
|
+
}
|
|
42
48
|
}
|
|
43
49
|
},
|
|
44
50
|
"sideEffects": false,
|
|
@@ -97,6 +103,7 @@
|
|
|
97
103
|
"scripts": {
|
|
98
104
|
"build": "tsdown",
|
|
99
105
|
"validate": "publint",
|
|
106
|
+
"check:bundle": "bun scripts/verify-browser-bundle.ts",
|
|
100
107
|
"lint": "biome check . && eslint .",
|
|
101
108
|
"lint:fix": "biome check --write . && eslint --fix .",
|
|
102
109
|
"format": "biome format --write .",
|
|
@@ -105,5 +112,5 @@
|
|
|
105
112
|
"test:integration": "vitest run --project integration",
|
|
106
113
|
"test:coverage": "vitest run --project unit --project integration --coverage"
|
|
107
114
|
},
|
|
108
|
-
"version": "0.
|
|
115
|
+
"version": "0.5.1"
|
|
109
116
|
}
|