@moku-labs/web 0.4.2 → 0.5.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 +40 -7
- package/dist/browser.d.mts +1852 -0
- package/dist/browser.mjs +3866 -0
- package/dist/index.cjs +94 -52
- package/dist/index.d.cts +19 -1
- package/dist/index.d.mts +19 -1
- package/dist/index.mjs +94 -53
- package/package.json +8 -1
package/dist/index.cjs
CHANGED
|
@@ -37,7 +37,7 @@ let preact = require("preact");
|
|
|
37
37
|
let preact_render_to_string = require("preact-render-to-string");
|
|
38
38
|
//#region src/plugins/env/api.ts
|
|
39
39
|
/** Error prefix for all env API failures. */
|
|
40
|
-
const ERROR_PREFIX$
|
|
40
|
+
const ERROR_PREFIX$14 = "[web]";
|
|
41
41
|
/**
|
|
42
42
|
* Creates the env plugin API surface mounted at `ctx.env`. Closes over
|
|
43
43
|
* `ctx.state` ({@link EnvState}) and reads the frozen `resolved` / `publicMap`
|
|
@@ -81,7 +81,7 @@ function createEnvApi(ctx) {
|
|
|
81
81
|
*/
|
|
82
82
|
require(key) {
|
|
83
83
|
const value = resolved.get(key);
|
|
84
|
-
if (value === void 0) throw new Error(`${ERROR_PREFIX$
|
|
84
|
+
if (value === void 0) throw new Error(`${ERROR_PREFIX$14} env: required variable "${key}" is not defined.`);
|
|
85
85
|
return value;
|
|
86
86
|
},
|
|
87
87
|
/**
|
|
@@ -148,7 +148,7 @@ function createEnvState() {
|
|
|
148
148
|
/** Error message thrown by every frozen-map mutator. */
|
|
149
149
|
const FROZEN_MESSAGE = "env: map is frozen and cannot be mutated";
|
|
150
150
|
/** Error prefix for all resolution-pipeline failures. */
|
|
151
|
-
const ERROR_PREFIX$
|
|
151
|
+
const ERROR_PREFIX$13 = "[web]";
|
|
152
152
|
/**
|
|
153
153
|
* Throws the canonical frozen-map error; installed as a map's `set`/`clear`/`delete`.
|
|
154
154
|
*
|
|
@@ -199,8 +199,8 @@ function crossCheckPublicPrefix(config) {
|
|
|
199
199
|
const { schema, publicPrefix } = config;
|
|
200
200
|
for (const [key, spec] of Object.entries(schema)) {
|
|
201
201
|
const hasPrefix = key.startsWith(publicPrefix);
|
|
202
|
-
if (spec.public === true && !hasPrefix) throw new Error(`${ERROR_PREFIX$
|
|
203
|
-
if (hasPrefix && spec.public !== true) throw new Error(`${ERROR_PREFIX$
|
|
202
|
+
if (spec.public === true && !hasPrefix) throw new Error(`${ERROR_PREFIX$13} env: "${key}" is marked public but does not start with "${publicPrefix}".`);
|
|
203
|
+
if (hasPrefix && spec.public !== true) throw new Error(`${ERROR_PREFIX$13} env: "${key}" starts with "${publicPrefix}" but is not marked public:true.`);
|
|
204
204
|
}
|
|
205
205
|
}
|
|
206
206
|
/**
|
|
@@ -251,7 +251,7 @@ function validateSchema(ctx) {
|
|
|
251
251
|
crossCheckPublicPrefix(config);
|
|
252
252
|
for (const [key, spec] of Object.entries(schema)) {
|
|
253
253
|
if (merged[key] === void 0 && spec.default !== void 0) merged[key] = spec.default;
|
|
254
|
-
if (merged[key] === void 0 && spec.required === true) throw new Error(`${ERROR_PREFIX$
|
|
254
|
+
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.`);
|
|
255
255
|
}
|
|
256
256
|
for (const [key, spec] of Object.entries(schema)) {
|
|
257
257
|
const value = merged[key];
|
|
@@ -743,6 +743,12 @@ const logPlugin = (0, _moku_labs_core.createCorePlugin)("log", {
|
|
|
743
743
|
api: createLogApi,
|
|
744
744
|
onInit: installDefaultSinks
|
|
745
745
|
});
|
|
746
|
+
//#endregion
|
|
747
|
+
//#region src/config.ts
|
|
748
|
+
/**
|
|
749
|
+
* @file Framework configuration — Config + Events types, core plugin registration.
|
|
750
|
+
* @see README.md
|
|
751
|
+
*/
|
|
746
752
|
const coreConfig = (0, _moku_labs_core.createCoreConfig)("web", {
|
|
747
753
|
config: { mode: "production" },
|
|
748
754
|
plugins: [logPlugin, envPlugin],
|
|
@@ -772,7 +778,7 @@ const createCore = coreConfig.createCore;
|
|
|
772
778
|
//#endregion
|
|
773
779
|
//#region src/plugins/i18n/api.ts
|
|
774
780
|
/** Error prefix for all i18n lifecycle failures. */
|
|
775
|
-
const ERROR_PREFIX$
|
|
781
|
+
const ERROR_PREFIX$12 = "[web]";
|
|
776
782
|
/**
|
|
777
783
|
* Validates the resolved i18n config (fail-fast at `createApp`). Throws when
|
|
778
784
|
* `locales` is empty or when `defaultLocale` is not a member of `locales`.
|
|
@@ -788,8 +794,8 @@ const ERROR_PREFIX$11 = "[web]";
|
|
|
788
794
|
*/
|
|
789
795
|
function validateI18nConfig(ctx) {
|
|
790
796
|
const { locales, defaultLocale } = ctx.config;
|
|
791
|
-
if (locales.length === 0) throw new Error(`${ERROR_PREFIX$
|
|
792
|
-
if (!locales.includes(defaultLocale)) throw new Error(`${ERROR_PREFIX$
|
|
797
|
+
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"].`);
|
|
798
|
+
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.`);
|
|
793
799
|
}
|
|
794
800
|
/**
|
|
795
801
|
* Creates the i18n plugin API surface — locale registry accessors plus the
|
|
@@ -1764,7 +1770,7 @@ const contentPlugin = createPlugin$1("content", {
|
|
|
1764
1770
|
//#endregion
|
|
1765
1771
|
//#region src/plugins/site/api.ts
|
|
1766
1772
|
/** Error prefix for all site lifecycle/validation failures. */
|
|
1767
|
-
const ERROR_PREFIX$
|
|
1773
|
+
const ERROR_PREFIX$11 = "[web]";
|
|
1768
1774
|
/**
|
|
1769
1775
|
* Joins a relative path against an absolute base URL, normalizing the slash
|
|
1770
1776
|
* boundary to exactly one "/". Returns the base unchanged for an empty or
|
|
@@ -1832,8 +1838,8 @@ function isAbsoluteUrl(value) {
|
|
|
1832
1838
|
* ```
|
|
1833
1839
|
*/
|
|
1834
1840
|
function validateSiteConfig(ctx) {
|
|
1835
|
-
if (!isNonEmpty(ctx.config.name)) throw new Error(`${ERROR_PREFIX$
|
|
1836
|
-
if (!isAbsoluteUrl(ctx.config.url)) throw new Error(`${ERROR_PREFIX$
|
|
1841
|
+
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.`);
|
|
1842
|
+
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".`);
|
|
1837
1843
|
}
|
|
1838
1844
|
/**
|
|
1839
1845
|
* Creates the site plugin API surface — read-only accessors over frozen config
|
|
@@ -2023,7 +2029,7 @@ function matchRoute(compiled, pathname) {
|
|
|
2023
2029
|
* `manifest`. Returns values/copies, never the raw `ctx.state` reference (spec/11 §2.4).
|
|
2024
2030
|
*/
|
|
2025
2031
|
/** Error prefix for router API failures. */
|
|
2026
|
-
const ERROR_PREFIX$
|
|
2032
|
+
const ERROR_PREFIX$10 = "[web] router";
|
|
2027
2033
|
/**
|
|
2028
2034
|
* Read the compiled matcher table, throwing if `onInit` has not run yet. This
|
|
2029
2035
|
* `null` cannot occur in practice post-`onInit`; the guard documents the invariant.
|
|
@@ -2037,7 +2043,7 @@ const ERROR_PREFIX$9 = "[web] router";
|
|
|
2037
2043
|
* ```
|
|
2038
2044
|
*/
|
|
2039
2045
|
function readTable(state) {
|
|
2040
|
-
if (state.table === null) throw new Error(`${ERROR_PREFIX$
|
|
2046
|
+
if (state.table === null) throw new Error(`${ERROR_PREFIX$10}: matcher table accessed before onInit compiled it.`);
|
|
2041
2047
|
return state.table;
|
|
2042
2048
|
}
|
|
2043
2049
|
/**
|
|
@@ -2121,7 +2127,7 @@ function createApi$4(ctx) {
|
|
|
2121
2127
|
*/
|
|
2122
2128
|
toUrl(routeName, params) {
|
|
2123
2129
|
const entry = readTable(state).byName.get(routeName);
|
|
2124
|
-
if (!entry) throw new Error(`${ERROR_PREFIX$
|
|
2130
|
+
if (!entry) throw new Error(`${ERROR_PREFIX$10}: unknown route name "${routeName}".`);
|
|
2125
2131
|
return entry.toUrl(params);
|
|
2126
2132
|
},
|
|
2127
2133
|
/**
|
|
@@ -2256,7 +2262,7 @@ function bySpecificity(a, b) {
|
|
|
2256
2262
|
* only (`CompileInput`) — never the plugin ctx.
|
|
2257
2263
|
*/
|
|
2258
2264
|
/** Shared `[web]` error prefix for router validation failures. */
|
|
2259
|
-
const ERROR_PREFIX$
|
|
2265
|
+
const ERROR_PREFIX$9 = "[web] router";
|
|
2260
2266
|
/**
|
|
2261
2267
|
* Validate the route map (fail-fast in `onInit`). Throws with the `[web]` prefix
|
|
2262
2268
|
* naming the offending route/pattern on any failure: empty map, a pattern not
|
|
@@ -2271,12 +2277,12 @@ const ERROR_PREFIX$8 = "[web] router";
|
|
|
2271
2277
|
*/
|
|
2272
2278
|
function validateRoutes(routes) {
|
|
2273
2279
|
const names = Object.keys(routes);
|
|
2274
|
-
if (names.length === 0) throw new Error(`${ERROR_PREFIX$
|
|
2280
|
+
if (names.length === 0) throw new Error(`${ERROR_PREFIX$9}: route map is empty — provide at least one route via pluginConfigs.router.routes.`);
|
|
2275
2281
|
for (const name of names) {
|
|
2276
2282
|
const pattern = routes[name]?.pattern ?? "";
|
|
2277
|
-
if (!pattern.startsWith("/")) throw new Error(`${ERROR_PREFIX$
|
|
2278
|
-
if ((pattern.match(/\{/g) ?? []).length !== (pattern.match(/\}/g) ?? []).length) throw new Error(`${ERROR_PREFIX$
|
|
2279
|
-
if ((pattern.match(/\{lang:\?\}/g) ?? []).length > 1) throw new Error(`${ERROR_PREFIX$
|
|
2283
|
+
if (!pattern.startsWith("/")) throw new Error(`${ERROR_PREFIX$9}: route "${name}" pattern must start with "/" (got "${pattern}").`);
|
|
2284
|
+
if ((pattern.match(/\{/g) ?? []).length !== (pattern.match(/\}/g) ?? []).length) throw new Error(`${ERROR_PREFIX$9}: route "${name}" pattern has unbalanced braces ("${pattern}").`);
|
|
2285
|
+
if ((pattern.match(/\{lang:\?\}/g) ?? []).length > 1) throw new Error(`${ERROR_PREFIX$9}: route "${name}" pattern has more than one {lang:?} segment ("${pattern}").`);
|
|
2280
2286
|
}
|
|
2281
2287
|
}
|
|
2282
2288
|
/**
|
|
@@ -3058,7 +3064,7 @@ function serializeHead(elements) {
|
|
|
3058
3064
|
* it to a string. It holds no resource and caches no subscription.
|
|
3059
3065
|
*/
|
|
3060
3066
|
/** Error prefix for head API invariant failures. */
|
|
3061
|
-
const ERROR_PREFIX$
|
|
3067
|
+
const ERROR_PREFIX$8 = "[head]";
|
|
3062
3068
|
/**
|
|
3063
3069
|
* Read the normalized defaults, asserting the post-`onInit` invariant (the slot is
|
|
3064
3070
|
* `null` only before `onInit` assigns it, which cannot occur at render time).
|
|
@@ -3072,7 +3078,7 @@ const ERROR_PREFIX$7 = "[head]";
|
|
|
3072
3078
|
* ```
|
|
3073
3079
|
*/
|
|
3074
3080
|
function readDefaults(state) {
|
|
3075
|
-
if (state.defaults === null) throw new Error(`${ERROR_PREFIX$
|
|
3081
|
+
if (state.defaults === null) throw new Error(`${ERROR_PREFIX$8}: defaults accessed before onInit normalized them.`);
|
|
3076
3082
|
return state.defaults;
|
|
3077
3083
|
}
|
|
3078
3084
|
/**
|
|
@@ -3115,7 +3121,7 @@ render(route, data) {
|
|
|
3115
3121
|
//#endregion
|
|
3116
3122
|
//#region src/plugins/head/config.ts
|
|
3117
3123
|
/** Error prefix for all head config-validation failures. */
|
|
3118
|
-
const ERROR_PREFIX$
|
|
3124
|
+
const ERROR_PREFIX$7 = "[head] config:";
|
|
3119
3125
|
/** The allowed `twitterCard` literals (also the runtime guard set). */
|
|
3120
3126
|
const VALID_TWITTER_CARDS = ["summary", "summary_large_image"];
|
|
3121
3127
|
/**
|
|
@@ -3142,8 +3148,8 @@ const defaultConfig$2 = { twitterCard: "summary_large_image" };
|
|
|
3142
3148
|
* ```
|
|
3143
3149
|
*/
|
|
3144
3150
|
function validateHeadConfig(config) {
|
|
3145
|
-
if (config.titleTemplate !== void 0 && !config.titleTemplate.includes("%s")) throw new Error(`${ERROR_PREFIX$
|
|
3146
|
-
if (config.twitterCard !== void 0 && !VALID_TWITTER_CARDS.includes(config.twitterCard)) throw new Error(`${ERROR_PREFIX$
|
|
3151
|
+
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)}.`);
|
|
3152
|
+
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)}.`);
|
|
3147
3153
|
}
|
|
3148
3154
|
/**
|
|
3149
3155
|
* Validate then build the frozen, normalized {@link HeadDefaults} snapshot read by
|
|
@@ -4788,7 +4794,7 @@ async function runPipeline(ctx, options) {
|
|
|
4788
4794
|
* @file build plugin — API factory (run + phases), cross-plugin wiring, and onInit config validation.
|
|
4789
4795
|
*/
|
|
4790
4796
|
/** Error prefix for build config/validation failures (spec/11 Part-3). */
|
|
4791
|
-
const ERROR_PREFIX$
|
|
4797
|
+
const ERROR_PREFIX$6 = "[web] build";
|
|
4792
4798
|
/** Recognized font file extensions for OG-image validation. */
|
|
4793
4799
|
const FONT_EXTENSIONS = [
|
|
4794
4800
|
".ttf",
|
|
@@ -4859,8 +4865,8 @@ function createApi$2(ctx) {
|
|
|
4859
4865
|
* ```
|
|
4860
4866
|
*/
|
|
4861
4867
|
function validateFonts(og) {
|
|
4862
|
-
if (typeof og.fontDir !== "string" || og.fontDir.length === 0 || !(0, node_fs.existsSync)(og.fontDir)) throw new Error(`${ERROR_PREFIX$
|
|
4863
|
-
if (!(0, node_fs.readdirSync)(og.fontDir).some((name) => FONT_EXTENSIONS.some((extension) => name.endsWith(extension)))) throw new Error(`${ERROR_PREFIX$
|
|
4868
|
+
if (typeof og.fontDir !== "string" || og.fontDir.length === 0 || !(0, node_fs.existsSync)(og.fontDir)) throw new Error(`${ERROR_PREFIX$6}.ogImage: fontDir "${og.fontDir}" does not exist — provide a directory with at least one font.`);
|
|
4869
|
+
if (!(0, node_fs.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.`);
|
|
4864
4870
|
}
|
|
4865
4871
|
/**
|
|
4866
4872
|
* Validates `build` config synchronously in `onInit` (return value discarded).
|
|
@@ -4874,10 +4880,10 @@ function validateFonts(og) {
|
|
|
4874
4880
|
* ```
|
|
4875
4881
|
*/
|
|
4876
4882
|
function validateConfig$1(config) {
|
|
4877
|
-
if (typeof config.outDir !== "string" || config.outDir.trim().length === 0) throw new Error(`${ERROR_PREFIX$
|
|
4878
|
-
if (config.publicDir !== void 0 && typeof config.publicDir !== "string") throw new Error(`${ERROR_PREFIX$
|
|
4879
|
-
if (config.template !== void 0 && typeof config.template !== "string") throw new Error(`${ERROR_PREFIX$
|
|
4880
|
-
if (config.clientEntry !== void 0 && typeof config.clientEntry !== "string") throw new Error(`${ERROR_PREFIX$
|
|
4883
|
+
if (typeof config.outDir !== "string" || config.outDir.trim().length === 0) throw new Error(`${ERROR_PREFIX$6}.outDir: must be a non-empty string.`);
|
|
4884
|
+
if (config.publicDir !== void 0 && typeof config.publicDir !== "string") throw new Error(`${ERROR_PREFIX$6}.publicDir: must be a string when set.`);
|
|
4885
|
+
if (config.template !== void 0 && typeof config.template !== "string") throw new Error(`${ERROR_PREFIX$6}.template: must be a string path when set.`);
|
|
4886
|
+
if (config.clientEntry !== void 0 && typeof config.clientEntry !== "string") throw new Error(`${ERROR_PREFIX$6}.clientEntry: must be a string path when set.`);
|
|
4881
4887
|
if (config.ogImage) validateFonts(config.ogImage);
|
|
4882
4888
|
}
|
|
4883
4889
|
//#endregion
|
|
@@ -4979,7 +4985,7 @@ const buildPlugin = createPlugin$1("build", {
|
|
|
4979
4985
|
*/
|
|
4980
4986
|
const MOKU_WRANGLER_VERSION = "4.34.0";
|
|
4981
4987
|
/** Error prefix for deploy runtime failures (spec/11 Part-3). */
|
|
4982
|
-
const ERROR_PREFIX$
|
|
4988
|
+
const ERROR_PREFIX$5 = "[web] deploy";
|
|
4983
4989
|
/** Mask substituted for a detected secret-like token. */
|
|
4984
4990
|
const MASK = "***";
|
|
4985
4991
|
/** Minimum token length eligible for entropy-gated scrubbing. */
|
|
@@ -5057,7 +5063,7 @@ function scrubSecrets(text, allowlist) {
|
|
|
5057
5063
|
* guardBranch("preview/landing"); // "preview/landing"
|
|
5058
5064
|
*/
|
|
5059
5065
|
function guardBranch(branch) {
|
|
5060
|
-
if (!BRANCH_REGEX.test(branch) || branch.startsWith("-")) throw deployError("ERR_DEPLOY_INVALID_BRANCH", `${ERROR_PREFIX$
|
|
5066
|
+
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.`);
|
|
5061
5067
|
return branch;
|
|
5062
5068
|
}
|
|
5063
5069
|
/**
|
|
@@ -5074,7 +5080,7 @@ function guardBranch(branch) {
|
|
|
5074
5080
|
function assertWithinRoot(outDir, root) {
|
|
5075
5081
|
const resolved = node_path$1.default.isAbsolute(outDir) ? node_path$1.default.resolve(outDir) : node_path$1.default.resolve(root, outDir);
|
|
5076
5082
|
const rootResolved = node_path$1.default.resolve(root);
|
|
5077
|
-
if (resolved !== rootResolved && !resolved.startsWith(rootResolved + node_path$1.default.sep)) throw deployError("ERR_DEPLOY_PATH_TRAVERSAL", `${ERROR_PREFIX$
|
|
5083
|
+
if (resolved !== rootResolved && !resolved.startsWith(rootResolved + node_path$1.default.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)}.`);
|
|
5078
5084
|
return resolved;
|
|
5079
5085
|
}
|
|
5080
5086
|
/**
|
|
@@ -5159,11 +5165,11 @@ function classifyWranglerError(exitCode, scrubbedStderr) {
|
|
|
5159
5165
|
const haystack = scrubbedStderr.toLowerCase();
|
|
5160
5166
|
for (const signature of ERROR_SIGNATURES) if (signature.match.some((needle) => haystack.includes(needle))) return {
|
|
5161
5167
|
code: signature.kind,
|
|
5162
|
-
message: `${ERROR_PREFIX$
|
|
5168
|
+
message: `${ERROR_PREFIX$5}: wrangler failed (exit ${exitCode}).\n ${signature.advice}`
|
|
5163
5169
|
};
|
|
5164
5170
|
return {
|
|
5165
5171
|
code: "ERR_DEPLOY_WRANGLER_FAILED",
|
|
5166
|
-
message: `${ERROR_PREFIX$
|
|
5172
|
+
message: `${ERROR_PREFIX$5}: wrangler failed (exit ${exitCode}).\n ${scrubbedStderr.trim().slice(-500)}`
|
|
5167
5173
|
};
|
|
5168
5174
|
}
|
|
5169
5175
|
/**
|
|
@@ -5429,7 +5435,7 @@ async function reconcile(input) {
|
|
|
5429
5435
|
* and short-circuiting on the first failure.
|
|
5430
5436
|
*/
|
|
5431
5437
|
/** Error prefix for deploy preflight failures (spec/11 Part-3). */
|
|
5432
|
-
const ERROR_PREFIX$
|
|
5438
|
+
const ERROR_PREFIX$4 = "[web] deploy";
|
|
5433
5439
|
/** Cloudflare Pages free-tier file-count limit. */
|
|
5434
5440
|
const FREE_TIER_FILE_LIMIT = 2e4;
|
|
5435
5441
|
/** Cloudflare Pages paid-tier file-count limit (env override target). */
|
|
@@ -5505,15 +5511,15 @@ async function runPreflight(config, root, env = process.env) {
|
|
|
5505
5511
|
try {
|
|
5506
5512
|
await (0, node_fs_promises.stat)(wranglerPath);
|
|
5507
5513
|
} catch {
|
|
5508
|
-
throw deployError("ERR_DEPLOY_NO_WRANGLER_CONFIG", `${ERROR_PREFIX$
|
|
5514
|
+
throw deployError("ERR_DEPLOY_NO_WRANGLER_CONFIG", `${ERROR_PREFIX$4}: wrangler.jsonc not found.\n Run \`app.deploy.init()\` to scaffold it, then retry.`);
|
|
5509
5515
|
}
|
|
5510
5516
|
const stats = await inspectOutdir(node_path$1.default.isAbsolute(config.outDir) ? node_path$1.default.resolve(config.outDir) : node_path$1.default.resolve(root, config.outDir)).catch(() => {
|
|
5511
|
-
throw deployError("ERR_DEPLOY_EMPTY_OUTDIR", `${ERROR_PREFIX$
|
|
5517
|
+
throw deployError("ERR_DEPLOY_EMPTY_OUTDIR", `${ERROR_PREFIX$4}: outDir ${JSON.stringify(config.outDir)} is missing.\n Run your build first, then retry.`);
|
|
5512
5518
|
});
|
|
5513
|
-
if (stats.fileCount === 0) throw deployError("ERR_DEPLOY_EMPTY_OUTDIR", `${ERROR_PREFIX$
|
|
5519
|
+
if (stats.fileCount === 0) throw deployError("ERR_DEPLOY_EMPTY_OUTDIR", `${ERROR_PREFIX$4}: outDir ${JSON.stringify(config.outDir)} is empty — nothing to deploy.`);
|
|
5514
5520
|
const limit = resolveFileLimit(env);
|
|
5515
|
-
if (stats.fileCount > limit) throw deployError("ERR_DEPLOY_TOO_MANY_FILES", `${ERROR_PREFIX$
|
|
5516
|
-
if (stats.oversizePath !== null) throw deployError("ERR_DEPLOY_FILE_TOO_LARGE", `${ERROR_PREFIX$
|
|
5521
|
+
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.`);
|
|
5522
|
+
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.`);
|
|
5517
5523
|
}
|
|
5518
5524
|
//#endregion
|
|
5519
5525
|
//#region src/plugins/deploy/slug.ts
|
|
@@ -5558,7 +5564,7 @@ function toSlug(name) {
|
|
|
5558
5564
|
//#endregion
|
|
5559
5565
|
//#region src/plugins/deploy/api.ts
|
|
5560
5566
|
/** Error prefix for deploy config/validation failures (spec/11 Part-3). */
|
|
5561
|
-
const ERROR_PREFIX$
|
|
5567
|
+
const ERROR_PREFIX$3 = "[web] deploy";
|
|
5562
5568
|
/** `YYYY-MM-DD` validator for the compatibility date config field. */
|
|
5563
5569
|
const COMPAT_DATE_REGEX = /^\d{4}-\d{2}-\d{2}$/;
|
|
5564
5570
|
/**
|
|
@@ -5573,10 +5579,10 @@ const COMPAT_DATE_REGEX = /^\d{4}-\d{2}-\d{2}$/;
|
|
|
5573
5579
|
*/
|
|
5574
5580
|
function validateConfig(ctx) {
|
|
5575
5581
|
const { config } = ctx;
|
|
5576
|
-
if (config.target !== "cloudflare-pages") throw deployError("ERR_DEPLOY_CONFIG", `${ERROR_PREFIX$
|
|
5577
|
-
if (typeof config.outDir !== "string" || config.outDir.length === 0) throw deployError("ERR_DEPLOY_CONFIG", `${ERROR_PREFIX$
|
|
5578
|
-
if (!Array.isArray(config.scrubAllowlist) || !config.scrubAllowlist.every((item) => typeof item === "string")) throw deployError("ERR_DEPLOY_CONFIG", `${ERROR_PREFIX$
|
|
5579
|
-
if (config.compatibilityDate !== void 0 && !COMPAT_DATE_REGEX.test(config.compatibilityDate)) throw deployError("ERR_DEPLOY_CONFIG", `${ERROR_PREFIX$
|
|
5582
|
+
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.`);
|
|
5583
|
+
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").`);
|
|
5584
|
+
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.`);
|
|
5585
|
+
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.`);
|
|
5580
5586
|
ctx.require(sitePlugin);
|
|
5581
5587
|
}
|
|
5582
5588
|
/**
|
|
@@ -5855,7 +5861,38 @@ const COMPONENT_HOOK_NAMES = [
|
|
|
5855
5861
|
"onUnMount",
|
|
5856
5862
|
"onDestroy"
|
|
5857
5863
|
];
|
|
5858
|
-
|
|
5864
|
+
//#endregion
|
|
5865
|
+
//#region src/plugins/spa/components.ts
|
|
5866
|
+
/** Error prefix for spa fail-fast failures (spec/11 Part-3). */
|
|
5867
|
+
const ERROR_PREFIX$2 = "[web]";
|
|
5868
|
+
/** The set of legal hook names, frozen for O(1) membership checks. */
|
|
5869
|
+
const HOOK_NAME_SET = new Set(COMPONENT_HOOK_NAMES);
|
|
5870
|
+
/**
|
|
5871
|
+
* Create a validated component definition. Validates hook names at registration
|
|
5872
|
+
* for fail-fast typo detection (e.g. `onMout` throws immediately) and asserts
|
|
5873
|
+
* each provided hook is a function.
|
|
5874
|
+
*
|
|
5875
|
+
* @param name - Unique component name.
|
|
5876
|
+
* @param hooks - Lifecycle hook implementations.
|
|
5877
|
+
* @returns A `ComponentDef` ready to `register`.
|
|
5878
|
+
* @throws {Error} If `name` is empty, any hook key is not in
|
|
5879
|
+
* `COMPONENT_HOOK_NAMES`, or any provided hook value is not a function.
|
|
5880
|
+
* @example
|
|
5881
|
+
* const counter = createComponent("counter", {
|
|
5882
|
+
* onMount({ el }) { el.textContent = "0"; }
|
|
5883
|
+
* });
|
|
5884
|
+
*/
|
|
5885
|
+
function createComponent(name, hooks) {
|
|
5886
|
+
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)`);
|
|
5887
|
+
for (const key of Object.keys(hooks)) {
|
|
5888
|
+
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(", ")}`);
|
|
5889
|
+
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`);
|
|
5890
|
+
}
|
|
5891
|
+
return {
|
|
5892
|
+
name,
|
|
5893
|
+
hooks
|
|
5894
|
+
};
|
|
5895
|
+
}
|
|
5859
5896
|
/**
|
|
5860
5897
|
* Extracts the page data payload from the inline `script#__DATA__` element.
|
|
5861
5898
|
* Returns an empty object when the script is absent, empty, or invalid JSON.
|
|
@@ -7055,9 +7092,13 @@ function cloudflareBindings() {
|
|
|
7055
7092
|
* `createApp({ plugins: [...] })` in a Node build; omit them in a browser app.
|
|
7056
7093
|
* The framework never hard-blocks either runtime — the consumer composes the
|
|
7057
7094
|
* variant it needs and supplies the matching `env` provider.
|
|
7095
|
+
*
|
|
7096
|
+
* This is the full surface (dual ESM+CJS). For a guaranteed node-free client
|
|
7097
|
+
* bundle, import the `@moku-labs/web/browser` entry instead of relying on
|
|
7098
|
+
* tree-shaking this one — see `src/browser.ts`.
|
|
7058
7099
|
* @see README.md
|
|
7059
7100
|
*/
|
|
7060
|
-
const
|
|
7101
|
+
const core = createCore(coreConfig, {
|
|
7061
7102
|
plugins: [
|
|
7062
7103
|
sitePlugin,
|
|
7063
7104
|
i18nPlugin,
|
|
@@ -7096,7 +7137,7 @@ const framework = createCore(coreConfig, {
|
|
|
7096
7137
|
* await app.build.run();
|
|
7097
7138
|
* ```
|
|
7098
7139
|
*/
|
|
7099
|
-
const createApp =
|
|
7140
|
+
const createApp = core.createApp;
|
|
7100
7141
|
/**
|
|
7101
7142
|
* Create a custom plugin bound to this framework's `Config`/`Events` and core
|
|
7102
7143
|
* APIs. Plugin types are inferred from the spec object — never written explicitly.
|
|
@@ -7112,7 +7153,7 @@ const createApp = framework.createApp;
|
|
|
7112
7153
|
* const app = createApp({ plugins: [analytics] });
|
|
7113
7154
|
* ```
|
|
7114
7155
|
*/
|
|
7115
|
-
const createPlugin =
|
|
7156
|
+
const createPlugin = core.createPlugin;
|
|
7116
7157
|
//#endregion
|
|
7117
7158
|
Object.defineProperty(exports, "Build", {
|
|
7118
7159
|
enumerable: true,
|
|
@@ -7175,6 +7216,7 @@ exports.canonical = canonical;
|
|
|
7175
7216
|
exports.cloudflareBindings = cloudflareBindings;
|
|
7176
7217
|
exports.contentPlugin = contentPlugin;
|
|
7177
7218
|
exports.createApp = createApp;
|
|
7219
|
+
exports.createComponent = createComponent;
|
|
7178
7220
|
exports.createPlugin = createPlugin;
|
|
7179
7221
|
exports.dataPlugin = dataPlugin;
|
|
7180
7222
|
exports.defineRoutes = defineRoutes;
|
package/dist/index.d.cts
CHANGED
|
@@ -2455,6 +2455,24 @@ declare const routerPlugin: import("@moku-labs/core").PluginInstance<"router", R
|
|
|
2455
2455
|
*/
|
|
2456
2456
|
declare const sitePlugin: import("@moku-labs/core").PluginInstance<"site", Config$6, Record<string, never>, Api$6, {}> & Record<never, never>;
|
|
2457
2457
|
//#endregion
|
|
2458
|
+
//#region src/plugins/spa/components.d.ts
|
|
2459
|
+
/**
|
|
2460
|
+
* Create a validated component definition. Validates hook names at registration
|
|
2461
|
+
* for fail-fast typo detection (e.g. `onMout` throws immediately) and asserts
|
|
2462
|
+
* each provided hook is a function.
|
|
2463
|
+
*
|
|
2464
|
+
* @param name - Unique component name.
|
|
2465
|
+
* @param hooks - Lifecycle hook implementations.
|
|
2466
|
+
* @returns A `ComponentDef` ready to `register`.
|
|
2467
|
+
* @throws {Error} If `name` is empty, any hook key is not in
|
|
2468
|
+
* `COMPONENT_HOOK_NAMES`, or any provided hook value is not a function.
|
|
2469
|
+
* @example
|
|
2470
|
+
* const counter = createComponent("counter", {
|
|
2471
|
+
* onMount({ el }) { el.textContent = "0"; }
|
|
2472
|
+
* });
|
|
2473
|
+
*/
|
|
2474
|
+
declare function createComponent(name: string, hooks: ComponentHooks): ComponentDef;
|
|
2475
|
+
//#endregion
|
|
2458
2476
|
//#region src/plugins/spa/index.d.ts
|
|
2459
2477
|
/**
|
|
2460
2478
|
* SPA plugin — progressive client-side navigation layered over the static site:
|
|
@@ -2640,4 +2658,4 @@ declare const createApp: <const ExtraPlugins extends readonly import("@moku-labs
|
|
|
2640
2658
|
*/
|
|
2641
2659
|
declare const createPlugin: import("@moku-labs/core").BoundCreatePluginFunction<Config$7, Events, import("@moku-labs/core").CoreApisFromTuple<[import("@moku-labs/core").CorePluginInstance<"log", LogConfig, LogState, LogApi>, import("@moku-labs/core").CorePluginInstance<"env", EnvConfig, EnvState, EnvApi>]>>;
|
|
2642
2660
|
//#endregion
|
|
2643
|
-
export { types_d_exports as Build, types_d_exports$1 as Content, types_d_exports$2 as Data, types_d_exports$3 as Deploy, types_d_exports$4 as Env, types_d_exports$5 as Head, types_d_exports$6 as Log, types_d_exports$7 as Router, types_d_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 };
|
|
2661
|
+
export { types_d_exports as Build, types_d_exports$1 as Content, types_d_exports$2 as Data, types_d_exports$3 as Deploy, types_d_exports$4 as Env, types_d_exports$5 as Head, types_d_exports$6 as Log, types_d_exports$7 as Router, types_d_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/dist/index.d.mts
CHANGED
|
@@ -2455,6 +2455,24 @@ declare const routerPlugin: import("@moku-labs/core").PluginInstance<"router", R
|
|
|
2455
2455
|
*/
|
|
2456
2456
|
declare const sitePlugin: import("@moku-labs/core").PluginInstance<"site", Config$6, Record<string, never>, Api$6, {}> & Record<never, never>;
|
|
2457
2457
|
//#endregion
|
|
2458
|
+
//#region src/plugins/spa/components.d.ts
|
|
2459
|
+
/**
|
|
2460
|
+
* Create a validated component definition. Validates hook names at registration
|
|
2461
|
+
* for fail-fast typo detection (e.g. `onMout` throws immediately) and asserts
|
|
2462
|
+
* each provided hook is a function.
|
|
2463
|
+
*
|
|
2464
|
+
* @param name - Unique component name.
|
|
2465
|
+
* @param hooks - Lifecycle hook implementations.
|
|
2466
|
+
* @returns A `ComponentDef` ready to `register`.
|
|
2467
|
+
* @throws {Error} If `name` is empty, any hook key is not in
|
|
2468
|
+
* `COMPONENT_HOOK_NAMES`, or any provided hook value is not a function.
|
|
2469
|
+
* @example
|
|
2470
|
+
* const counter = createComponent("counter", {
|
|
2471
|
+
* onMount({ el }) { el.textContent = "0"; }
|
|
2472
|
+
* });
|
|
2473
|
+
*/
|
|
2474
|
+
declare function createComponent(name: string, hooks: ComponentHooks): ComponentDef;
|
|
2475
|
+
//#endregion
|
|
2458
2476
|
//#region src/plugins/spa/index.d.ts
|
|
2459
2477
|
/**
|
|
2460
2478
|
* SPA plugin — progressive client-side navigation layered over the static site:
|
|
@@ -2640,4 +2658,4 @@ declare const createApp: <const ExtraPlugins extends readonly import("@moku-labs
|
|
|
2640
2658
|
*/
|
|
2641
2659
|
declare const createPlugin: import("@moku-labs/core").BoundCreatePluginFunction<Config$7, Events, import("@moku-labs/core").CoreApisFromTuple<[import("@moku-labs/core").CorePluginInstance<"log", LogConfig, LogState, LogApi>, import("@moku-labs/core").CorePluginInstance<"env", EnvConfig, EnvState, EnvApi>]>>;
|
|
2642
2660
|
//#endregion
|
|
2643
|
-
export { types_d_exports as Build, types_d_exports$1 as Content, types_d_exports$2 as Data, types_d_exports$3 as Deploy, types_d_exports$4 as Env, types_d_exports$5 as Head, types_d_exports$6 as Log, types_d_exports$7 as Router, types_d_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 };
|
|
2661
|
+
export { types_d_exports as Build, types_d_exports$1 as Content, types_d_exports$2 as Data, types_d_exports$3 as Deploy, types_d_exports$4 as Env, types_d_exports$5 as Head, types_d_exports$6 as Log, types_d_exports$7 as Router, types_d_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 };
|