@moku-labs/web 1.12.2 → 1.12.4
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/browser.d.mts +13 -351
- package/dist/browser.mjs +9 -838
- package/dist/index.cjs +41 -1012
- package/dist/index.d.cts +12 -391
- package/dist/index.d.mts +12 -393
- package/dist/index.mjs +7 -996
- package/package.json +3 -2
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { t as __exportAll } from "./chunk-D7D4PA-g.mjs";
|
|
2
2
|
import { n as relativeDataFile, t as dataSuffix } from "./convention-Dp650o3y.mjs";
|
|
3
|
-
import {
|
|
3
|
+
import { browserEnv, cloudflareBindings, dotenv, envPlugin, envPlugin as envPlugin$1, logPlugin, logPlugin as logPlugin$1, processEnv } from "@moku-labs/common";
|
|
4
|
+
import { createCoreConfig } from "@moku-labs/core";
|
|
4
5
|
import { appendFileSync, existsSync, readFileSync, readdirSync, realpathSync, statSync, watch } from "node:fs";
|
|
5
6
|
import { createHash, randomUUID } from "node:crypto";
|
|
6
7
|
import { cp, mkdir, readFile, readdir, rm, stat, writeFile } from "node:fs/promises";
|
|
@@ -28,831 +29,6 @@ import { visit } from "unist-util-visit";
|
|
|
28
29
|
import { jsx } from "preact/jsx-runtime";
|
|
29
30
|
import { defaultSchema } from "hast-util-sanitize";
|
|
30
31
|
import readingTime from "reading-time";
|
|
31
|
-
//#region src/plugins/env/api.ts
|
|
32
|
-
/** Error prefix for all env API failures. */
|
|
33
|
-
const ERROR_PREFIX$16 = "[web]";
|
|
34
|
-
/**
|
|
35
|
-
* Creates the env plugin API surface mounted at `ctx.env`. Closes over
|
|
36
|
-
* `ctx.state` ({@link EnvState}) and reads the frozen `resolved` / `publicMap`
|
|
37
|
-
* maps; closures never return a raw `ctx.state` reference.
|
|
38
|
-
*
|
|
39
|
-
* @param ctx - Core plugin context carrying the frozen env state.
|
|
40
|
-
* @param ctx.state - The resolved + public {@link EnvState} maps.
|
|
41
|
-
* @returns The {@link EnvApi} accessor surface mounted at `ctx.env`.
|
|
42
|
-
* @example
|
|
43
|
-
* ```ts
|
|
44
|
-
* const api = createEnvApi(ctx);
|
|
45
|
-
* api.get("PUBLIC_API_URL");
|
|
46
|
-
* ```
|
|
47
|
-
*/
|
|
48
|
-
function createEnvApi(ctx) {
|
|
49
|
-
const { resolved, publicMap } = ctx.state;
|
|
50
|
-
return {
|
|
51
|
-
/**
|
|
52
|
-
* Reads a resolved variable.
|
|
53
|
-
*
|
|
54
|
-
* @param key - Variable name.
|
|
55
|
-
* @returns The value, or `undefined` if not present.
|
|
56
|
-
* @example
|
|
57
|
-
* ```ts
|
|
58
|
-
* api.get("PUBLIC_API_URL");
|
|
59
|
-
* ```
|
|
60
|
-
*/
|
|
61
|
-
get(key) {
|
|
62
|
-
return resolved.get(key);
|
|
63
|
-
},
|
|
64
|
-
/**
|
|
65
|
-
* Reads a variable that must exist.
|
|
66
|
-
*
|
|
67
|
-
* @param key - Variable name.
|
|
68
|
-
* @returns The value.
|
|
69
|
-
* @throws {Error} If the variable is undefined.
|
|
70
|
-
* @example
|
|
71
|
-
* ```ts
|
|
72
|
-
* api.require("DEPLOY_TOKEN");
|
|
73
|
-
* ```
|
|
74
|
-
*/
|
|
75
|
-
require(key) {
|
|
76
|
-
const value = resolved.get(key);
|
|
77
|
-
if (value === void 0) throw new Error(`${ERROR_PREFIX$16} env: required variable "${key}" is not defined.`);
|
|
78
|
-
return value;
|
|
79
|
-
},
|
|
80
|
-
/**
|
|
81
|
-
* Tests presence of a resolved variable.
|
|
82
|
-
*
|
|
83
|
-
* @param key - Variable name.
|
|
84
|
-
* @returns `true` if a value is present.
|
|
85
|
-
* @example
|
|
86
|
-
* ```ts
|
|
87
|
-
* api.has("PUBLIC_API_URL");
|
|
88
|
-
* ```
|
|
89
|
-
*/
|
|
90
|
-
has(key) {
|
|
91
|
-
return resolved.has(key);
|
|
92
|
-
},
|
|
93
|
-
/**
|
|
94
|
-
* Returns all public variables as a frozen plain object — a fresh copy,
|
|
95
|
-
* never the raw state map.
|
|
96
|
-
*
|
|
97
|
-
* @returns A frozen `Record` of public variable names to values.
|
|
98
|
-
* @example
|
|
99
|
-
* ```ts
|
|
100
|
-
* const payload = { ...api.getPublic() };
|
|
101
|
-
* ```
|
|
102
|
-
*/
|
|
103
|
-
getPublic() {
|
|
104
|
-
return Object.freeze(Object.fromEntries(publicMap));
|
|
105
|
-
},
|
|
106
|
-
/**
|
|
107
|
-
* Returns the already-frozen map of public variables.
|
|
108
|
-
*
|
|
109
|
-
* @returns The frozen public map.
|
|
110
|
-
* @example
|
|
111
|
-
* ```ts
|
|
112
|
-
* [...api.getPublicMap()];
|
|
113
|
-
* ```
|
|
114
|
-
*/
|
|
115
|
-
getPublicMap() {
|
|
116
|
-
return publicMap;
|
|
117
|
-
}
|
|
118
|
-
};
|
|
119
|
-
}
|
|
120
|
-
//#endregion
|
|
121
|
-
//#region src/plugins/env/state.ts
|
|
122
|
-
/**
|
|
123
|
-
* Creates initial env plugin state: two empty, mutable maps that are populated
|
|
124
|
-
* and frozen by `validateSchema` (the `onInit`) at `createApp` time.
|
|
125
|
-
*
|
|
126
|
-
* @returns A fresh `EnvState` with empty `resolved` and `publicMap` maps.
|
|
127
|
-
* @example
|
|
128
|
-
* ```ts
|
|
129
|
-
* const state = createEnvState();
|
|
130
|
-
* state.resolved.size; // 0
|
|
131
|
-
* ```
|
|
132
|
-
*/
|
|
133
|
-
function createEnvState() {
|
|
134
|
-
return {
|
|
135
|
-
resolved: /* @__PURE__ */ new Map(),
|
|
136
|
-
publicMap: /* @__PURE__ */ new Map()
|
|
137
|
-
};
|
|
138
|
-
}
|
|
139
|
-
//#endregion
|
|
140
|
-
//#region src/plugins/env/validate.ts
|
|
141
|
-
/** Error message thrown by every frozen-map mutator. */
|
|
142
|
-
const FROZEN_MESSAGE = "env: map is frozen and cannot be mutated";
|
|
143
|
-
/** Error prefix for all resolution-pipeline failures. */
|
|
144
|
-
const ERROR_PREFIX$15 = "[web]";
|
|
145
|
-
/** The `Map` mutators redefined as throwers when a map is frozen. */
|
|
146
|
-
const FROZEN_METHODS = [
|
|
147
|
-
"set",
|
|
148
|
-
"clear",
|
|
149
|
-
"delete"
|
|
150
|
-
];
|
|
151
|
-
/**
|
|
152
|
-
* Throws the canonical frozen-map error; installed as a map's `set`/`clear`/`delete`.
|
|
153
|
-
*
|
|
154
|
-
* @throws {TypeError} Always, signalling the map is frozen.
|
|
155
|
-
* @example
|
|
156
|
-
* ```ts
|
|
157
|
-
* frozenThrower(); // throws TypeError
|
|
158
|
-
* ```
|
|
159
|
-
*/
|
|
160
|
-
function frozenThrower() {
|
|
161
|
-
throw new TypeError(FROZEN_MESSAGE);
|
|
162
|
-
}
|
|
163
|
-
/**
|
|
164
|
-
* Coerces a raw provider value to its effective presence: an empty string counts
|
|
165
|
-
* as "absent" so a `KEY=""` falls through to later providers.
|
|
166
|
-
*
|
|
167
|
-
* @param raw - The raw value a provider supplied for a key (possibly `undefined`).
|
|
168
|
-
* @returns The value, or `undefined` when it is missing or an empty string.
|
|
169
|
-
* @example
|
|
170
|
-
* ```ts
|
|
171
|
-
* coerceEmpty(""); // => undefined
|
|
172
|
-
* coerceEmpty("3000"); // => "3000"
|
|
173
|
-
* ```
|
|
174
|
-
*/
|
|
175
|
-
function coerceEmpty(raw) {
|
|
176
|
-
return raw === "" ? void 0 : raw;
|
|
177
|
-
}
|
|
178
|
-
/**
|
|
179
|
-
* Merges providers in array order, coercing empty strings to `undefined` before
|
|
180
|
-
* precedence so a `KEY=""` falls through to later providers. First non-empty
|
|
181
|
-
* value wins.
|
|
182
|
-
*
|
|
183
|
-
* @param config - The resolved env config carrying the ordered providers.
|
|
184
|
-
* @returns A flat record of the first defined value found per key.
|
|
185
|
-
* @example
|
|
186
|
-
* ```ts
|
|
187
|
-
* mergeProviders({ providers: [a, b], schema: {}, publicPrefix: "PUBLIC_" });
|
|
188
|
-
* ```
|
|
189
|
-
*/
|
|
190
|
-
function mergeProviders$1(config) {
|
|
191
|
-
const merged = {};
|
|
192
|
-
for (const provider of config.providers) for (const [key, raw] of Object.entries(provider.load())) {
|
|
193
|
-
const value = coerceEmpty(raw);
|
|
194
|
-
if (value !== void 0 && merged[key] === void 0) merged[key] = value;
|
|
195
|
-
}
|
|
196
|
-
return merged;
|
|
197
|
-
}
|
|
198
|
-
/**
|
|
199
|
-
* Bidirectionally enforces the `PUBLIC_` naming convention against each schema
|
|
200
|
-
* entry's `public` flag. Throws on either violation direction.
|
|
201
|
-
*
|
|
202
|
-
* @param config - The resolved env config carrying `schema` + `publicPrefix`.
|
|
203
|
-
* @throws {Error} If a public var lacks the prefix, or a prefixed var is not public.
|
|
204
|
-
* @example
|
|
205
|
-
* ```ts
|
|
206
|
-
* crossCheckPublicPrefix(config); // throws if PUBLIC_X is not public:true
|
|
207
|
-
* ```
|
|
208
|
-
*/
|
|
209
|
-
function crossCheckPublicPrefix(config) {
|
|
210
|
-
const { schema, publicPrefix } = config;
|
|
211
|
-
for (const [key, spec] of Object.entries(schema)) {
|
|
212
|
-
const hasPrefix = key.startsWith(publicPrefix);
|
|
213
|
-
if (spec.public === true && !hasPrefix) throw new Error(`${ERROR_PREFIX$15} env: "${key}" is marked public but does not start with "${publicPrefix}".`);
|
|
214
|
-
if (hasPrefix && spec.public !== true) throw new Error(`${ERROR_PREFIX$15} env: "${key}" starts with "${publicPrefix}" but is not marked public:true.`);
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
/**
|
|
218
|
-
* Seals a map so `set`, `clear`, and `delete` throw, then `Object.freeze`s it
|
|
219
|
-
* for defense in depth. Closes the `Object.freeze`-on-`Map` mutability hole by
|
|
220
|
-
* redefining the mutators as non-writable, non-configurable throwers.
|
|
221
|
-
*
|
|
222
|
-
* @param map - The map to freeze in place.
|
|
223
|
-
* @example
|
|
224
|
-
* ```ts
|
|
225
|
-
* freezeMap(state.resolved); // resolved.set(...) now throws
|
|
226
|
-
* ```
|
|
227
|
-
*/
|
|
228
|
-
function freezeMap(map) {
|
|
229
|
-
for (const method of FROZEN_METHODS) Object.defineProperty(map, method, {
|
|
230
|
-
value: frozenThrower,
|
|
231
|
-
writable: false,
|
|
232
|
-
configurable: false,
|
|
233
|
-
enumerable: false
|
|
234
|
-
});
|
|
235
|
-
Object.freeze(map);
|
|
236
|
-
}
|
|
237
|
-
/**
|
|
238
|
-
* Populates `state.publicMap` with the schema-driven public subset: every
|
|
239
|
-
* `public:true` schema key that resolved to a defined value. This map is the only
|
|
240
|
-
* sanctioned input to a browser-facing `define`, so it stays schema-scoped (never
|
|
241
|
-
* includes non-schema provider keys).
|
|
242
|
-
*
|
|
243
|
-
* @param schema - The per-variable schema from {@link EnvConfig}.
|
|
244
|
-
* @param merged - The merged provider values keyed by variable name.
|
|
245
|
-
* @param publicMap - The mutable public map to fill in place.
|
|
246
|
-
* @example
|
|
247
|
-
* ```ts
|
|
248
|
-
* populatePublicMap(config.schema, merged, state.publicMap);
|
|
249
|
-
* ```
|
|
250
|
-
*/
|
|
251
|
-
function populatePublicMap(schema, merged, publicMap) {
|
|
252
|
-
for (const [key, spec] of Object.entries(schema)) {
|
|
253
|
-
const value = merged[key];
|
|
254
|
-
if (spec.public === true && value !== void 0) publicMap.set(key, value);
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
/**
|
|
258
|
-
* Populates `state.resolved` with EVERY merged key that carries a defined value
|
|
259
|
-
* (spec/02 Lifecycle §5), including non-schema provider keys so
|
|
260
|
-
* `ctx.env.require()` works for dynamic keys.
|
|
261
|
-
*
|
|
262
|
-
* @param merged - The merged provider values keyed by variable name.
|
|
263
|
-
* @param resolved - The mutable resolved map to fill in place.
|
|
264
|
-
* @example
|
|
265
|
-
* ```ts
|
|
266
|
-
* populateResolved(merged, state.resolved);
|
|
267
|
-
* ```
|
|
268
|
-
*/
|
|
269
|
-
function populateResolved(merged, resolved) {
|
|
270
|
-
for (const [key, value] of Object.entries(merged)) resolved.set(key, value);
|
|
271
|
-
}
|
|
272
|
-
/**
|
|
273
|
-
* Resolves, validates, and freezes the environment table at `onInit`.
|
|
274
|
-
*
|
|
275
|
-
* Pipeline order: merge providers (with empty-string → undefined coercion) →
|
|
276
|
-
* `PUBLIC_` bidirectional cross-check → apply defaults → assert required →
|
|
277
|
-
* populate `state.resolved` / `state.publicMap` → freeze both via
|
|
278
|
-
* {@link freezeMap}. Fail-fast: any violation throws at `createApp` time.
|
|
279
|
-
*
|
|
280
|
-
* @param ctx - Core plugin context (`{ config, state }`).
|
|
281
|
-
* @param ctx.config - The resolved {@link EnvConfig}.
|
|
282
|
-
* @param ctx.state - The mutable {@link EnvState} to populate and freeze.
|
|
283
|
-
* @throws {Error} On a `PUBLIC_` cross-check violation or a missing required variable.
|
|
284
|
-
* @example
|
|
285
|
-
* ```ts
|
|
286
|
-
* validateSchema(ctx); // throws on missing required / PUBLIC_ violation
|
|
287
|
-
* ```
|
|
288
|
-
*/
|
|
289
|
-
function validateSchema(ctx) {
|
|
290
|
-
const { config, state } = ctx;
|
|
291
|
-
const { schema } = config;
|
|
292
|
-
const merged = mergeProviders$1(config);
|
|
293
|
-
crossCheckPublicPrefix(config);
|
|
294
|
-
for (const [key, spec] of Object.entries(schema)) {
|
|
295
|
-
if (merged[key] === void 0 && spec.default !== void 0) merged[key] = spec.default;
|
|
296
|
-
if (merged[key] === void 0 && spec.required === true) throw new Error(`${ERROR_PREFIX$15} env: required variable "${key}" is not defined by any provider or default.`);
|
|
297
|
-
}
|
|
298
|
-
populatePublicMap(schema, merged, state.publicMap);
|
|
299
|
-
populateResolved(merged, state.resolved);
|
|
300
|
-
freezeMap(state.resolved);
|
|
301
|
-
freezeMap(state.publicMap);
|
|
302
|
-
}
|
|
303
|
-
//#endregion
|
|
304
|
-
//#region src/plugins/env/providers.browser.ts
|
|
305
|
-
/** Default `globalThis` property holding a runtime-injected public-env snapshot. */
|
|
306
|
-
const DEFAULT_GLOBAL_KEY = "__ENV__";
|
|
307
|
-
/**
|
|
308
|
-
* A browser-safe {@link EnvProvider} that reads `import.meta.env` and an optional
|
|
309
|
-
* `globalThis[globalKey]` snapshot, merging them with the runtime global winning.
|
|
310
|
-
* Contains zero `node:*` imports, so it is safe to include in the client bundle.
|
|
311
|
-
* Never throws on missing sources — each absent source resolves to `{}`.
|
|
312
|
-
*
|
|
313
|
-
* @param options - Optional settings.
|
|
314
|
-
* @param options.globalKey - `globalThis` key to read a public-env snapshot from. Defaults to `"__ENV__"`.
|
|
315
|
-
* @returns An {@link EnvProvider} named `browser-env`.
|
|
316
|
-
* @example
|
|
317
|
-
* ```ts
|
|
318
|
-
* const provider = browserEnv();
|
|
319
|
-
* provider.load(); // { PUBLIC_API_URL: "/api", ... }
|
|
320
|
-
* ```
|
|
321
|
-
*/
|
|
322
|
-
function browserEnv(options) {
|
|
323
|
-
const globalKey = options?.globalKey ?? DEFAULT_GLOBAL_KEY;
|
|
324
|
-
return {
|
|
325
|
-
name: "browser-env",
|
|
326
|
-
/**
|
|
327
|
-
* Merges `import.meta.env` with `globalThis[globalKey]`, the runtime global
|
|
328
|
-
* winning. Each absent source resolves to `{}`; never throws.
|
|
329
|
-
*
|
|
330
|
-
* @returns The merged environment record.
|
|
331
|
-
* @example
|
|
332
|
-
* ```ts
|
|
333
|
-
* browserEnv().load();
|
|
334
|
-
* ```
|
|
335
|
-
*/
|
|
336
|
-
load() {
|
|
337
|
-
const importEnv = import.meta.env ?? {};
|
|
338
|
-
const globalObject = globalThis[globalKey] ?? {};
|
|
339
|
-
return {
|
|
340
|
-
...importEnv,
|
|
341
|
-
...globalObject
|
|
342
|
-
};
|
|
343
|
-
}
|
|
344
|
-
};
|
|
345
|
-
}
|
|
346
|
-
/**
|
|
347
|
-
* Core plugin that resolves, validates, and freezes the environment at `onInit`,
|
|
348
|
-
* exposing a read-only accessor at `ctx.env`. No `onStart`/`onStop` — holds no resource.
|
|
349
|
-
*
|
|
350
|
-
* @example
|
|
351
|
-
* ```ts
|
|
352
|
-
* createApp({ pluginConfigs: { env: { schema: { PUBLIC_API_URL: { public: true } } } } });
|
|
353
|
-
* ```
|
|
354
|
-
*/
|
|
355
|
-
const envPlugin = createCorePlugin("env", {
|
|
356
|
-
config: {
|
|
357
|
-
schema: {},
|
|
358
|
-
providers: [],
|
|
359
|
-
publicPrefix: "PUBLIC_"
|
|
360
|
-
},
|
|
361
|
-
createState: createEnvState,
|
|
362
|
-
api: createEnvApi,
|
|
363
|
-
onInit: validateSchema
|
|
364
|
-
});
|
|
365
|
-
//#endregion
|
|
366
|
-
//#region src/plugins/log/expect.ts
|
|
367
|
-
/**
|
|
368
|
-
* Named error thrown by `expect()` assertions when a trace condition fails.
|
|
369
|
-
*
|
|
370
|
-
* @example
|
|
371
|
-
* ```ts
|
|
372
|
-
* throw new LogExpectAssertionError("missing event build:complete");
|
|
373
|
-
* ```
|
|
374
|
-
*/
|
|
375
|
-
var LogExpectAssertionError = class extends Error {
|
|
376
|
-
/**
|
|
377
|
-
* Construct a new assertion error with a descriptive failure message.
|
|
378
|
-
*
|
|
379
|
-
* @param message - Descriptive failure message (event name, partial, index).
|
|
380
|
-
* @example
|
|
381
|
-
* ```ts
|
|
382
|
-
* throw new LogExpectAssertionError("missing event build:complete");
|
|
383
|
-
* ```
|
|
384
|
-
*/
|
|
385
|
-
constructor(message) {
|
|
386
|
-
super(message);
|
|
387
|
-
this.name = "LogExpectAssertionError";
|
|
388
|
-
}
|
|
389
|
-
};
|
|
390
|
-
/**
|
|
391
|
-
* Tests whether a value is a non-null, non-array plain object.
|
|
392
|
-
*
|
|
393
|
-
* @param value - The value to test.
|
|
394
|
-
* @returns `true` when `value` is a non-null object that is not an array.
|
|
395
|
-
* @example
|
|
396
|
-
* ```ts
|
|
397
|
-
* isPlainObject({ a: 1 }); // true
|
|
398
|
-
* isPlainObject([1]); // false
|
|
399
|
-
* ```
|
|
400
|
-
*/
|
|
401
|
-
function isPlainObject$1(value) {
|
|
402
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
403
|
-
}
|
|
404
|
-
/**
|
|
405
|
-
* Tests whether `actual` is an array that recursively matches every element of
|
|
406
|
-
* the `partial` array (element-wise, with equal length).
|
|
407
|
-
*
|
|
408
|
-
* @param actual - The value to test against (must be an array of equal length).
|
|
409
|
-
* @param partial - The expected partial array shape.
|
|
410
|
-
* @returns `true` when `actual` is an equal-length array matching `partial` element-wise.
|
|
411
|
-
* @example
|
|
412
|
-
* ```ts
|
|
413
|
-
* matchesPartialArray([1, 2], [1, 2]); // true
|
|
414
|
-
* matchesPartialArray([1], [1, 2]); // false (length mismatch)
|
|
415
|
-
* ```
|
|
416
|
-
*/
|
|
417
|
-
function matchesPartialArray(actual, partial) {
|
|
418
|
-
if (!Array.isArray(actual) || actual.length !== partial.length) return false;
|
|
419
|
-
return partial.every((value, index) => matchesPartial(actual[index], value));
|
|
420
|
-
}
|
|
421
|
-
/**
|
|
422
|
-
* Tests whether `actual` is a plain object in which every `partial` key
|
|
423
|
-
* recursively matches (extra `actual` keys are ignored).
|
|
424
|
-
*
|
|
425
|
-
* @param actual - The value to test against (must be a plain object).
|
|
426
|
-
* @param partial - The expected partial object shape.
|
|
427
|
-
* @returns `true` when every `partial` key exists in `actual` and matches recursively.
|
|
428
|
-
* @example
|
|
429
|
-
* ```ts
|
|
430
|
-
* matchesPartialObject({ a: 1, b: 2 }, { a: 1 }); // true
|
|
431
|
-
* matchesPartialObject({ a: 1 }, { b: 1 }); // false (missing key)
|
|
432
|
-
* ```
|
|
433
|
-
*/
|
|
434
|
-
function matchesPartialObject(actual, partial) {
|
|
435
|
-
if (!isPlainObject$1(actual)) return false;
|
|
436
|
-
return Object.keys(partial).every((key) => key in actual && matchesPartial(actual[key], partial[key]));
|
|
437
|
-
}
|
|
438
|
-
/**
|
|
439
|
-
* Subset-equality matcher: is `partial` a recursive subset of `actual`?
|
|
440
|
-
*
|
|
441
|
-
* Fast path via `Object.is` (covers identical primitives/references and
|
|
442
|
-
* `null`/`NaN`); primitives compare with `Object.is`; arrays match element-wise
|
|
443
|
-
* with equal length; plain objects require every `partial` key to recursively
|
|
444
|
-
* match (extra `actual` keys ignored).
|
|
445
|
-
*
|
|
446
|
-
* @param actual - The value to test against (typically `entry.data`).
|
|
447
|
-
* @param partial - The expected partial shape.
|
|
448
|
-
* @returns `true` when `partial` is a recursive subset of `actual`.
|
|
449
|
-
* @example
|
|
450
|
-
* ```ts
|
|
451
|
-
* matchesPartial({ a: 1, b: 2 }, { a: 1 }); // true
|
|
452
|
-
* matchesPartial([1, 2], [1]); // false (length mismatch)
|
|
453
|
-
* ```
|
|
454
|
-
*/
|
|
455
|
-
function matchesPartial(actual, partial) {
|
|
456
|
-
if (Object.is(actual, partial)) return true;
|
|
457
|
-
if (Array.isArray(partial)) return matchesPartialArray(actual, partial);
|
|
458
|
-
if (isPlainObject$1(partial)) return matchesPartialObject(actual, partial);
|
|
459
|
-
return false;
|
|
460
|
-
}
|
|
461
|
-
/**
|
|
462
|
-
* Tests whether an entry matches `event` and (when provided) `partial`.
|
|
463
|
-
*
|
|
464
|
-
* @param entry - The candidate trace entry.
|
|
465
|
-
* @param event - Required event name.
|
|
466
|
-
* @param partial - Optional partial data shape (subset-matched against `entry.data`).
|
|
467
|
-
* @returns `true` when the entry matches the event and optional partial.
|
|
468
|
-
* @example
|
|
469
|
-
* ```ts
|
|
470
|
-
* entryMatches({ level: "info", event: "a", data: { x: 1 }, ts: 0 }, "a", { x: 1 }); // true
|
|
471
|
-
* ```
|
|
472
|
-
*/
|
|
473
|
-
function entryMatches(entry, event, partial) {
|
|
474
|
-
if (entry.event !== event) return false;
|
|
475
|
-
return partial === void 0 ? true : matchesPartial(entry.data, partial);
|
|
476
|
-
}
|
|
477
|
-
/**
|
|
478
|
-
* Render a `partial` for an error message, prefixed with a space when present.
|
|
479
|
-
*
|
|
480
|
-
* @param partial - Optional partial data shape.
|
|
481
|
-
* @returns A ` matching <json>` suffix, or an empty string when absent.
|
|
482
|
-
* @example
|
|
483
|
-
* ```ts
|
|
484
|
-
* describePartial({ ok: true }); // ' matching {"ok":true}'
|
|
485
|
-
* ```
|
|
486
|
-
*/
|
|
487
|
-
function describePartial(partial) {
|
|
488
|
-
return partial === void 0 ? "" : ` matching ${JSON.stringify(partial)}`;
|
|
489
|
-
}
|
|
490
|
-
/**
|
|
491
|
-
* Find the first entry with `event` at or after `startIndex`, scanning forward.
|
|
492
|
-
*
|
|
493
|
-
* @param entries - The trace array to scan.
|
|
494
|
-
* @param event - Event name to find.
|
|
495
|
-
* @param startIndex - Index to begin scanning from (inclusive).
|
|
496
|
-
* @returns The index of the first match, or `-1` when none exists from `startIndex` on.
|
|
497
|
-
* @example
|
|
498
|
-
* ```ts
|
|
499
|
-
* findEventAtOrAfter([{ event: "a" }, { event: "b" }] as LogEntry[], "b", 0); // 1
|
|
500
|
-
* ```
|
|
501
|
-
*/
|
|
502
|
-
function findEventAtOrAfter(entries, event, startIndex) {
|
|
503
|
-
for (let index = startIndex; index < entries.length; index++) if (entries[index]?.event === event) return index;
|
|
504
|
-
return -1;
|
|
505
|
-
}
|
|
506
|
-
/**
|
|
507
|
-
* Create a fluent assertion chain bound to the live `entries` array. Each method
|
|
508
|
-
* reads `entries` at call time, so assertions reflect later logging.
|
|
509
|
-
*
|
|
510
|
-
* @param entries - The live trace array (read on each assertion call).
|
|
511
|
-
* @returns A fresh {@link ExpectChain} backed by `entries`.
|
|
512
|
-
* @example
|
|
513
|
-
* ```ts
|
|
514
|
-
* createExpectChain(state.entries).toHaveEvent("build:complete");
|
|
515
|
-
* ```
|
|
516
|
-
*/
|
|
517
|
-
function createExpectChain(entries) {
|
|
518
|
-
const chain = {
|
|
519
|
-
/**
|
|
520
|
-
* Assert at least one entry has `event`, optionally matching `partial`.
|
|
521
|
-
*
|
|
522
|
-
* @param event - Event name to find.
|
|
523
|
-
* @param partial - Optional partial data shape (subset-matched).
|
|
524
|
-
* @returns The same chain for chaining.
|
|
525
|
-
* @throws {LogExpectAssertionError} When no matching entry exists.
|
|
526
|
-
* @example
|
|
527
|
-
* ```ts
|
|
528
|
-
* chain.toHaveEvent("build:phase", { status: "start" });
|
|
529
|
-
* ```
|
|
530
|
-
*/
|
|
531
|
-
toHaveEvent(event, partial) {
|
|
532
|
-
if (!entries.some((entry) => entryMatches(entry, event, partial))) throw new LogExpectAssertionError(`Expected trace to contain event "${event}"${describePartial(partial)}, but none was found.`);
|
|
533
|
-
return chain;
|
|
534
|
-
},
|
|
535
|
-
/**
|
|
536
|
-
* Assert all of `events` appear in the trace in the given relative order.
|
|
537
|
-
*
|
|
538
|
-
* @param events - Ordered list of event names (gaps allowed).
|
|
539
|
-
* @returns The same chain for chaining.
|
|
540
|
-
* @throws {LogExpectAssertionError} When the ordering cannot be satisfied.
|
|
541
|
-
* @example
|
|
542
|
-
* ```ts
|
|
543
|
-
* chain.toHaveEventInOrder(["build:phase", "build:complete"]);
|
|
544
|
-
* ```
|
|
545
|
-
*/
|
|
546
|
-
toHaveEventInOrder(events) {
|
|
547
|
-
let cursor = 0;
|
|
548
|
-
for (const [position, event] of events.entries()) {
|
|
549
|
-
const matchIndex = findEventAtOrAfter(entries, event, cursor);
|
|
550
|
-
if (matchIndex === -1) throw new LogExpectAssertionError(`Expected events in order ${JSON.stringify(events)}, but "${event}" (index ${position}) was not found at or after position ${cursor}.`);
|
|
551
|
-
cursor = matchIndex + 1;
|
|
552
|
-
}
|
|
553
|
-
return chain;
|
|
554
|
-
},
|
|
555
|
-
/**
|
|
556
|
-
* Assert NO entry has `event` (optionally narrowed by `partial`).
|
|
557
|
-
*
|
|
558
|
-
* @param event - Event name that must be absent.
|
|
559
|
-
* @param partial - Optional partial data shape; only matching entries violate.
|
|
560
|
-
* @returns The same chain for chaining.
|
|
561
|
-
* @throws {LogExpectAssertionError} When a matching entry exists.
|
|
562
|
-
* @example
|
|
563
|
-
* ```ts
|
|
564
|
-
* chain.toNotHaveEvent("deploy:failed");
|
|
565
|
-
* ```
|
|
566
|
-
*/
|
|
567
|
-
toNotHaveEvent(event, partial) {
|
|
568
|
-
const offending = entries.findIndex((entry) => entryMatches(entry, event, partial));
|
|
569
|
-
if (offending !== -1) throw new LogExpectAssertionError(`Expected trace to NOT contain event "${event}"${describePartial(partial)}, but found one at index ${offending}.`);
|
|
570
|
-
return chain;
|
|
571
|
-
}
|
|
572
|
-
};
|
|
573
|
-
return chain;
|
|
574
|
-
}
|
|
575
|
-
//#endregion
|
|
576
|
-
//#region src/plugins/log/api.ts
|
|
577
|
-
/**
|
|
578
|
-
* @file log plugin — API factory.
|
|
579
|
-
*
|
|
580
|
-
* Builds the `LogApi` over the plugin's `{ config, state }` core context:
|
|
581
|
-
* the leveled loggers (via a shared `append`), the frozen `trace()` snapshot,
|
|
582
|
-
* the live `expect()` chain, `addSink`, and `reset`.
|
|
583
|
-
*/
|
|
584
|
-
/**
|
|
585
|
-
* Append a new entry to the trace and fan it out to every sink in order.
|
|
586
|
-
*
|
|
587
|
-
* @param state - The mutable log state to append to.
|
|
588
|
-
* @param level - Severity level for the entry.
|
|
589
|
-
* @param event - Event identifier.
|
|
590
|
-
* @param data - Optional structured payload.
|
|
591
|
-
* @example
|
|
592
|
-
* ```ts
|
|
593
|
-
* append(state, "info", "content:ready", { count: 12 });
|
|
594
|
-
* ```
|
|
595
|
-
*/
|
|
596
|
-
function append(state, level, event, data) {
|
|
597
|
-
const entry = {
|
|
598
|
-
level,
|
|
599
|
-
event,
|
|
600
|
-
data,
|
|
601
|
-
ts: Date.now()
|
|
602
|
-
};
|
|
603
|
-
state.entries.push(entry);
|
|
604
|
-
for (const sink of state.sinks) sink.write(entry);
|
|
605
|
-
}
|
|
606
|
-
/**
|
|
607
|
-
* Tests whether a value is a non-null, non-array plain object.
|
|
608
|
-
*
|
|
609
|
-
* @param value - The value to test.
|
|
610
|
-
* @returns `true` when `value` is a non-null object that is not an array.
|
|
611
|
-
* @example
|
|
612
|
-
* ```ts
|
|
613
|
-
* isPlainObject({ a: 1 }); // true
|
|
614
|
-
* isPlainObject([1]); // false
|
|
615
|
-
* ```
|
|
616
|
-
*/
|
|
617
|
-
function isPlainObject(value) {
|
|
618
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
619
|
-
}
|
|
620
|
-
/**
|
|
621
|
-
* Merge an `Error`'s `message`/`stack` into `data` under an `error` key. The
|
|
622
|
-
* `error` field is always preserved; only a plain object `data` contributes its
|
|
623
|
-
* keys. Non-plain-object `data` (arrays and primitives) is replaced by `{}` —
|
|
624
|
-
* its original value is not retained — so the merge target is always a record.
|
|
625
|
-
*
|
|
626
|
-
* @param data - Original payload (any shape).
|
|
627
|
-
* @param error - The originating error to merge.
|
|
628
|
-
* @returns A new object carrying any plain-object keys plus the `error` field.
|
|
629
|
-
* @example
|
|
630
|
-
* ```ts
|
|
631
|
-
* mergeError({ target: "cf" }, new Error("boom"));
|
|
632
|
-
* // { target: "cf", error: { message: "boom", stack: "..." } }
|
|
633
|
-
* ```
|
|
634
|
-
*/
|
|
635
|
-
function mergeError(data, error) {
|
|
636
|
-
return {
|
|
637
|
-
...isPlainObject(data) ? data : {},
|
|
638
|
-
error: {
|
|
639
|
-
message: error.message,
|
|
640
|
-
stack: error.stack
|
|
641
|
-
}
|
|
642
|
-
};
|
|
643
|
-
}
|
|
644
|
-
/**
|
|
645
|
-
* Create the log plugin API surface injected as `ctx.log` / `app.log`.
|
|
646
|
-
*
|
|
647
|
-
* @param ctx - Core plugin context (`{ config, state }`).
|
|
648
|
-
* @returns The {@link LogApi} bound to `ctx.state`.
|
|
649
|
-
* @example
|
|
650
|
-
* ```ts
|
|
651
|
-
* const log = createLogApi(ctx);
|
|
652
|
-
* log.info("content:ready", { articleCount: 12 });
|
|
653
|
-
* ```
|
|
654
|
-
*/
|
|
655
|
-
function createLogApi(ctx) {
|
|
656
|
-
const { state } = ctx;
|
|
657
|
-
return {
|
|
658
|
-
/**
|
|
659
|
-
* Append an `info` entry and fan it out to every sink.
|
|
660
|
-
*
|
|
661
|
-
* @param event - Event identifier (convention: `domain:action`).
|
|
662
|
-
* @param data - Optional structured payload.
|
|
663
|
-
* @example
|
|
664
|
-
* ```ts
|
|
665
|
-
* log.info("content:ready", { count: 12 });
|
|
666
|
-
* ```
|
|
667
|
-
*/
|
|
668
|
-
info(event, data) {
|
|
669
|
-
append(state, "info", event, data);
|
|
670
|
-
},
|
|
671
|
-
/**
|
|
672
|
-
* Append a `debug` entry and fan it out to every sink.
|
|
673
|
-
*
|
|
674
|
-
* @param event - Event identifier (convention: `domain:action`).
|
|
675
|
-
* @param data - Optional structured payload.
|
|
676
|
-
* @example
|
|
677
|
-
* ```ts
|
|
678
|
-
* log.debug("router:match", { path: "/blog/" });
|
|
679
|
-
* ```
|
|
680
|
-
*/
|
|
681
|
-
debug(event, data) {
|
|
682
|
-
append(state, "debug", event, data);
|
|
683
|
-
},
|
|
684
|
-
/**
|
|
685
|
-
* Append a `warn` entry and fan it out to every sink.
|
|
686
|
-
*
|
|
687
|
-
* @param event - Event identifier (convention: `domain:action`).
|
|
688
|
-
* @param data - Optional structured payload.
|
|
689
|
-
* @example
|
|
690
|
-
* ```ts
|
|
691
|
-
* log.warn("build:skip", { reason: "no sitemap" });
|
|
692
|
-
* ```
|
|
693
|
-
*/
|
|
694
|
-
warn(event, data) {
|
|
695
|
-
append(state, "warn", event, data);
|
|
696
|
-
},
|
|
697
|
-
/**
|
|
698
|
-
* Append an `error` entry. When `error` is provided, its `message`/`stack`
|
|
699
|
-
* are merged into `data` under an `error` key (existing keys preserved);
|
|
700
|
-
* otherwise `data` is recorded as-is.
|
|
701
|
-
*
|
|
702
|
-
* @param event - Event identifier (convention: `domain:action`).
|
|
703
|
-
* @param data - Optional structured payload.
|
|
704
|
-
* @param error - Optional originating Error to merge into `data`.
|
|
705
|
-
* @example
|
|
706
|
-
* ```ts
|
|
707
|
-
* log.error("deploy:failed", { target: "cf" }, err);
|
|
708
|
-
* ```
|
|
709
|
-
*/
|
|
710
|
-
error(event, data, error) {
|
|
711
|
-
append(state, "error", event, error === void 0 ? data : mergeError(data, error));
|
|
712
|
-
},
|
|
713
|
-
/**
|
|
714
|
-
* Return a frozen snapshot (fresh copy) of the entries recorded so far.
|
|
715
|
-
*
|
|
716
|
-
* @returns A readonly, frozen copy of the recorded entries.
|
|
717
|
-
* @example
|
|
718
|
-
* ```ts
|
|
719
|
-
* const entries = log.trace();
|
|
720
|
-
* ```
|
|
721
|
-
*/
|
|
722
|
-
trace() {
|
|
723
|
-
return Object.freeze([...state.entries]);
|
|
724
|
-
},
|
|
725
|
-
/**
|
|
726
|
-
* Return a fluent assertion chain bound to the live entries array.
|
|
727
|
-
*
|
|
728
|
-
* @returns A fresh {@link ExpectChain} reading `state.entries` live.
|
|
729
|
-
* @example
|
|
730
|
-
* ```ts
|
|
731
|
-
* log.expect().toHaveEvent("build:complete");
|
|
732
|
-
* ```
|
|
733
|
-
*/
|
|
734
|
-
expect() {
|
|
735
|
-
return createExpectChain(state.entries);
|
|
736
|
-
},
|
|
737
|
-
/**
|
|
738
|
-
* Register an additional output sink at runtime.
|
|
739
|
-
*
|
|
740
|
-
* @param sink - The sink to add to the fan-out list.
|
|
741
|
-
* @example
|
|
742
|
-
* ```ts
|
|
743
|
-
* log.addSink({ write: (e) => stream.write(JSON.stringify(e)) });
|
|
744
|
-
* ```
|
|
745
|
-
*/
|
|
746
|
-
addSink(sink) {
|
|
747
|
-
state.sinks.push(sink);
|
|
748
|
-
},
|
|
749
|
-
/**
|
|
750
|
-
* Clear all recorded entries while keeping registered sinks.
|
|
751
|
-
*
|
|
752
|
-
* @example
|
|
753
|
-
* ```ts
|
|
754
|
-
* log.reset();
|
|
755
|
-
* ```
|
|
756
|
-
*/
|
|
757
|
-
reset() {
|
|
758
|
-
state.entries.length = 0;
|
|
759
|
-
}
|
|
760
|
-
};
|
|
761
|
-
}
|
|
762
|
-
//#endregion
|
|
763
|
-
//#region src/plugins/log/sinks.ts
|
|
764
|
-
/** Severity rank for threshold comparison (higher = more severe). */
|
|
765
|
-
const LEVEL_RANK = {
|
|
766
|
-
debug: 10,
|
|
767
|
-
info: 20,
|
|
768
|
-
warn: 30,
|
|
769
|
-
error: 40
|
|
770
|
-
};
|
|
771
|
-
/**
|
|
772
|
-
* Build the console sink: routes entries by channel — `error` → `console.error`,
|
|
773
|
-
* `warn` → `console.warn`, and `debug`/`info` → `console.log`. The full entry
|
|
774
|
-
* object is forwarded so the console serializes its `event` and `data`. Entries
|
|
775
|
-
* below `minLevel` are dropped (the in-memory trace still records everything).
|
|
776
|
-
*
|
|
777
|
-
* @param minLevel - Lowest severity to print. Defaults to `"debug"` (print all).
|
|
778
|
-
* @returns A {@link LogSink} that writes to the matching `console` channel.
|
|
779
|
-
* @example
|
|
780
|
-
* ```ts
|
|
781
|
-
* state.sinks.push(consoleSink("info")); // suppress debug spam
|
|
782
|
-
* ```
|
|
783
|
-
*/
|
|
784
|
-
function consoleSink(minLevel = "debug") {
|
|
785
|
-
const threshold = LEVEL_RANK[minLevel];
|
|
786
|
-
return {
|
|
787
|
-
/**
|
|
788
|
-
* Route a single entry to the console channel matching its level.
|
|
789
|
-
*
|
|
790
|
-
* @param entry - The entry to emit.
|
|
791
|
-
* @example
|
|
792
|
-
* ```ts
|
|
793
|
-
* sink.write({ level: "warn", event: "build:skip", ts: Date.now() });
|
|
794
|
-
* ```
|
|
795
|
-
*/
|
|
796
|
-
write(entry) {
|
|
797
|
-
if (LEVEL_RANK[entry.level] < threshold) return;
|
|
798
|
-
if (entry.level === "error") console.error(entry);
|
|
799
|
-
else if (entry.level === "warn") console.warn(entry);
|
|
800
|
-
else console.log(entry);
|
|
801
|
-
} };
|
|
802
|
-
}
|
|
803
|
-
/**
|
|
804
|
-
* Install mode-selected default sinks at onInit. The in-memory trace is always
|
|
805
|
-
* on (`state.entries`); the console sink is added only in dev/production. `dev`
|
|
806
|
-
* prints everything (debug+); `production` prints `info`+ only, so the per-phase
|
|
807
|
-
* `debug` events (build:bundle, build:pages, …) don't spam a prod build. Both
|
|
808
|
-
* modes still record all levels in the in-memory trace.
|
|
809
|
-
*
|
|
810
|
-
* @param ctx - Core plugin context (`{ config, state }`).
|
|
811
|
-
* @param ctx.config - Resolved log config (`{ mode }`).
|
|
812
|
-
* @param ctx.state - Mutable log state (`{ entries, sinks }`).
|
|
813
|
-
* @example
|
|
814
|
-
* ```ts
|
|
815
|
-
* // "dev" -> [consoleSink("debug")]; "production" -> [consoleSink("info")]; "test"/"silent" -> []
|
|
816
|
-
* ```
|
|
817
|
-
*/
|
|
818
|
-
function installDefaultSinks(ctx) {
|
|
819
|
-
if (ctx.config.mode === "dev") ctx.state.sinks.push(consoleSink("debug"));
|
|
820
|
-
else if (ctx.config.mode === "production") ctx.state.sinks.push(consoleSink("info"));
|
|
821
|
-
}
|
|
822
|
-
//#endregion
|
|
823
|
-
//#region src/plugins/log/state.ts
|
|
824
|
-
/**
|
|
825
|
-
* Create fresh log state: an empty append-only trace and an empty sink list.
|
|
826
|
-
* No module-level singletons — guarantees per-`createApp` isolation (two
|
|
827
|
-
* `createApp` calls never share `entries` or `sinks`).
|
|
828
|
-
*
|
|
829
|
-
* @param _ctx - Core plugin context (`{ config }`); unused at construction.
|
|
830
|
-
* @returns A fresh `LogState` with empty `entries` and `sinks` arrays.
|
|
831
|
-
* @example
|
|
832
|
-
* ```ts
|
|
833
|
-
* const state = createLogState({ config: { mode: "test" } }); // { entries: [], sinks: [] }
|
|
834
|
-
* ```
|
|
835
|
-
*/
|
|
836
|
-
function createLogState(_ctx) {
|
|
837
|
-
return {
|
|
838
|
-
entries: [],
|
|
839
|
-
sinks: []
|
|
840
|
-
};
|
|
841
|
-
}
|
|
842
|
-
/**
|
|
843
|
-
* Core logging plugin — always-on in-memory trace + `expect()` event-trace DSL.
|
|
844
|
-
* API injected as `ctx.log` on every regular plugin and surfaced as `app.log`.
|
|
845
|
-
* No depends / events / hooks (core plugin per spec/03 §5).
|
|
846
|
-
*
|
|
847
|
-
* @see README.md
|
|
848
|
-
*/
|
|
849
|
-
const logPlugin = createCorePlugin("log", {
|
|
850
|
-
config: { mode: "production" },
|
|
851
|
-
createState: createLogState,
|
|
852
|
-
api: createLogApi,
|
|
853
|
-
onInit: installDefaultSinks
|
|
854
|
-
});
|
|
855
|
-
//#endregion
|
|
856
32
|
//#region src/config.ts
|
|
857
33
|
/**
|
|
858
34
|
* @file Framework configuration — Config + Events types, core plugin registration.
|
|
@@ -874,7 +50,7 @@ const coreConfig = createCoreConfig("web", {
|
|
|
874
50
|
stage: "production",
|
|
875
51
|
mode: "hybrid"
|
|
876
52
|
},
|
|
877
|
-
plugins: [logPlugin, envPlugin],
|
|
53
|
+
plugins: [logPlugin$1, envPlugin$1],
|
|
878
54
|
pluginConfigs: { log: { mode: "production" } }
|
|
879
55
|
});
|
|
880
56
|
/**
|
|
@@ -10135,7 +9311,7 @@ function spaEvents(register) {
|
|
|
10135
9311
|
}
|
|
10136
9312
|
//#endregion
|
|
10137
9313
|
//#region src/plugins/spa/types.ts
|
|
10138
|
-
var types_exports$
|
|
9314
|
+
var types_exports$7 = /* @__PURE__ */ __exportAll({ COMPONENT_HOOK_NAMES: () => COMPONENT_HOOK_NAMES });
|
|
10139
9315
|
/** Allowed hook names — single source of truth for fail-fast validation. */
|
|
10140
9316
|
const COMPONENT_HOOK_NAMES = [
|
|
10141
9317
|
"onCreate",
|
|
@@ -11471,176 +10647,11 @@ var types_exports$3 = /* @__PURE__ */ __exportAll({});
|
|
|
11471
10647
|
//#region src/plugins/deploy/types.ts
|
|
11472
10648
|
var types_exports$4 = /* @__PURE__ */ __exportAll({});
|
|
11473
10649
|
//#endregion
|
|
11474
|
-
//#region src/plugins/env/types.ts
|
|
11475
|
-
var types_exports$5 = /* @__PURE__ */ __exportAll({});
|
|
11476
|
-
//#endregion
|
|
11477
10650
|
//#region src/plugins/head/types.ts
|
|
11478
|
-
var types_exports$
|
|
11479
|
-
//#endregion
|
|
11480
|
-
//#region src/plugins/log/types.ts
|
|
11481
|
-
var types_exports$7 = /* @__PURE__ */ __exportAll({});
|
|
10651
|
+
var types_exports$5 = /* @__PURE__ */ __exportAll({});
|
|
11482
10652
|
//#endregion
|
|
11483
10653
|
//#region src/plugins/router/types.ts
|
|
11484
|
-
var types_exports$
|
|
11485
|
-
//#endregion
|
|
11486
|
-
//#region src/plugins/env/providers.ts
|
|
11487
|
-
/**
|
|
11488
|
-
* @file env plugin — built-in providers: dotenv, processEnv, cloudflareBindings.
|
|
11489
|
-
*/
|
|
11490
|
-
/** Default dotenv file path: optional local overrides. */
|
|
11491
|
-
const DEFAULT_DOTENV_PATH = ".env.local";
|
|
11492
|
-
/** Property on `globalThis` that the consumer sets per Cloudflare request. */
|
|
11493
|
-
const CLOUDFLARE_GLOBAL = "__CLOUDFLARE_ENV__";
|
|
11494
|
-
/** `String.indexOf` sentinel meaning "no `=` separator on this line". */
|
|
11495
|
-
const NO_SEPARATOR = -1;
|
|
11496
|
-
/**
|
|
11497
|
-
* Strips a single matching pair of surrounding double or single quotes from a
|
|
11498
|
-
* value. Leaves unquoted values (and trailing inline comments) untouched.
|
|
11499
|
-
*
|
|
11500
|
-
* @param value - The already-trimmed raw value.
|
|
11501
|
-
* @returns The value with one outer quote pair removed, if present.
|
|
11502
|
-
* @example
|
|
11503
|
-
* ```ts
|
|
11504
|
-
* stripQuotes('"a"'); // "a"
|
|
11505
|
-
* stripQuotes("plain # c"); // "plain # c"
|
|
11506
|
-
* ```
|
|
11507
|
-
*/
|
|
11508
|
-
function stripQuotes(value) {
|
|
11509
|
-
if (value.length < 2) return value;
|
|
11510
|
-
const first = value[0];
|
|
11511
|
-
const last = value.at(-1);
|
|
11512
|
-
if ((first === "\"" || first === "'") && first === last) return value.slice(1, -1);
|
|
11513
|
-
return value;
|
|
11514
|
-
}
|
|
11515
|
-
/**
|
|
11516
|
-
* Reports whether a trimmed line carries no assignment — a blank line or a
|
|
11517
|
-
* full-line `#` comment — and should be skipped by the parser.
|
|
11518
|
-
*
|
|
11519
|
-
* @param trimmed - A whitespace-trimmed line from the dotenv text.
|
|
11520
|
-
* @returns `true` when the line is empty or a comment.
|
|
11521
|
-
* @example
|
|
11522
|
-
* ```ts
|
|
11523
|
-
* isIgnoredLine(""); // true
|
|
11524
|
-
* isIgnoredLine("# note"); // true
|
|
11525
|
-
* isIgnoredLine("A=1"); // false
|
|
11526
|
-
* ```
|
|
11527
|
-
*/
|
|
11528
|
-
function isIgnoredLine(trimmed) {
|
|
11529
|
-
return trimmed === "" || trimmed.startsWith("#");
|
|
11530
|
-
}
|
|
11531
|
-
/**
|
|
11532
|
-
* Parses `.env`-style text into a flat record. Handles CRLF/LF, blank lines,
|
|
11533
|
-
* full-line `#` comments, first-`=` splitting, key/value trimming, and a single
|
|
11534
|
-
* outer quote pair. Does not strip trailing inline comments on unquoted values.
|
|
11535
|
-
*
|
|
11536
|
-
* @param text - The raw file contents.
|
|
11537
|
-
* @returns A flat record of parsed key/value pairs.
|
|
11538
|
-
* @example
|
|
11539
|
-
* ```ts
|
|
11540
|
-
* parseDotenv('A=1\nB="two"'); // { A: "1", B: "two" }
|
|
11541
|
-
* ```
|
|
11542
|
-
*/
|
|
11543
|
-
function parseDotenv(text) {
|
|
11544
|
-
const out = {};
|
|
11545
|
-
for (const line of text.split(/\r?\n/)) {
|
|
11546
|
-
const trimmed = line.trim();
|
|
11547
|
-
if (isIgnoredLine(trimmed)) continue;
|
|
11548
|
-
const eq = trimmed.indexOf("=");
|
|
11549
|
-
if (eq === NO_SEPARATOR) continue;
|
|
11550
|
-
const key = trimmed.slice(0, eq).trim();
|
|
11551
|
-
out[key] = stripQuotes(trimmed.slice(eq + 1).trim());
|
|
11552
|
-
}
|
|
11553
|
-
return out;
|
|
11554
|
-
}
|
|
11555
|
-
/**
|
|
11556
|
-
* A zero-dependency `.env`-style provider that re-reads and re-parses the file
|
|
11557
|
-
* from disk on every `load()`. Missing file resolves to `{}` (optional
|
|
11558
|
-
* overrides). Strips a single outer quote pair; does not strip trailing inline
|
|
11559
|
-
* comments on unquoted values.
|
|
11560
|
-
*
|
|
11561
|
-
* @param path - Path to the dotenv file. Defaults to `.env.local`.
|
|
11562
|
-
* @returns An {@link EnvProvider} named `dotenv:<path>` that reads fresh per call.
|
|
11563
|
-
* @example
|
|
11564
|
-
* ```ts
|
|
11565
|
-
* const provider = dotenv(".env.local");
|
|
11566
|
-
* provider.load(); // { PUBLIC_API_URL: "/api", ... }
|
|
11567
|
-
* ```
|
|
11568
|
-
*/
|
|
11569
|
-
function dotenv(path = DEFAULT_DOTENV_PATH) {
|
|
11570
|
-
return {
|
|
11571
|
-
name: `dotenv:${path}`,
|
|
11572
|
-
/**
|
|
11573
|
-
* Reads and parses the dotenv file fresh from disk; `{}` if it is missing.
|
|
11574
|
-
*
|
|
11575
|
-
* @returns The parsed environment record, or `{}` when the file is absent.
|
|
11576
|
-
* @example
|
|
11577
|
-
* ```ts
|
|
11578
|
-
* dotenv(".env.local").load();
|
|
11579
|
-
* ```
|
|
11580
|
-
*/
|
|
11581
|
-
load() {
|
|
11582
|
-
if (!existsSync(path)) return {};
|
|
11583
|
-
return parseDotenv(readFileSync(path, "utf8"));
|
|
11584
|
-
}
|
|
11585
|
-
};
|
|
11586
|
-
}
|
|
11587
|
-
/**
|
|
11588
|
-
* A provider that returns a shallow copy of `process.env` at `load()` time.
|
|
11589
|
-
*
|
|
11590
|
-
* @returns An {@link EnvProvider} named `process-env`.
|
|
11591
|
-
* @example
|
|
11592
|
-
* ```ts
|
|
11593
|
-
* const provider = processEnv();
|
|
11594
|
-
* provider.load().HOME; // current process value
|
|
11595
|
-
* ```
|
|
11596
|
-
*/
|
|
11597
|
-
function processEnv() {
|
|
11598
|
-
return {
|
|
11599
|
-
name: "process-env",
|
|
11600
|
-
/**
|
|
11601
|
-
* Returns a shallow copy of `process.env` at call time.
|
|
11602
|
-
*
|
|
11603
|
-
* @returns A fresh shallow copy of `process.env`.
|
|
11604
|
-
* @example
|
|
11605
|
-
* ```ts
|
|
11606
|
-
* processEnv().load();
|
|
11607
|
-
* ```
|
|
11608
|
-
*/
|
|
11609
|
-
load() {
|
|
11610
|
-
return { ...process.env };
|
|
11611
|
-
}
|
|
11612
|
-
};
|
|
11613
|
-
}
|
|
11614
|
-
/**
|
|
11615
|
-
* A provider that reads live, per-request Cloudflare bindings from
|
|
11616
|
-
* `globalThis.__CLOUDFLARE_ENV__` at `load()` time (`?? {}` when absent). Never
|
|
11617
|
-
* caches the binding object; the consumer owns the global's request lifecycle.
|
|
11618
|
-
*
|
|
11619
|
-
* @returns An {@link EnvProvider} named `cloudflare`.
|
|
11620
|
-
* @example
|
|
11621
|
-
* ```ts
|
|
11622
|
-
* globalThis.__CLOUDFLARE_ENV__ = env; // set by the request handler
|
|
11623
|
-
* const provider = cloudflareBindings();
|
|
11624
|
-
* provider.load(); // reads the current request's bindings
|
|
11625
|
-
* ```
|
|
11626
|
-
*/
|
|
11627
|
-
function cloudflareBindings() {
|
|
11628
|
-
return {
|
|
11629
|
-
name: "cloudflare",
|
|
11630
|
-
/**
|
|
11631
|
-
* Reads `globalThis.__CLOUDFLARE_ENV__` fresh, never caching the bindings.
|
|
11632
|
-
*
|
|
11633
|
-
* @returns The current Cloudflare bindings, or `{}` when the global is unset.
|
|
11634
|
-
* @example
|
|
11635
|
-
* ```ts
|
|
11636
|
-
* cloudflareBindings().load();
|
|
11637
|
-
* ```
|
|
11638
|
-
*/
|
|
11639
|
-
load() {
|
|
11640
|
-
return globalThis[CLOUDFLARE_GLOBAL] ?? {};
|
|
11641
|
-
}
|
|
11642
|
-
};
|
|
11643
|
-
}
|
|
10654
|
+
var types_exports$6 = /* @__PURE__ */ __exportAll({});
|
|
11644
10655
|
//#endregion
|
|
11645
10656
|
//#region node_modules/unist-util-stringify-position/lib/index.js
|
|
11646
10657
|
/**
|
|
@@ -13840,4 +12851,4 @@ const createApp = core.createApp;
|
|
|
13840
12851
|
*/
|
|
13841
12852
|
const createPlugin = core.createPlugin;
|
|
13842
12853
|
//#endregion
|
|
13843
|
-
export { types_exports as Build, types_exports$1 as Cli, types_exports$2 as Content, types_exports$3 as Data, types_exports$4 as Deploy, EmbedFacadeButton,
|
|
12854
|
+
export { types_exports as Build, types_exports$1 as Cli, types_exports$2 as Content, types_exports$3 as Data, types_exports$4 as Deploy, EmbedFacadeButton, GalleryTrack, types_exports$5 as Head, types_exports$6 as Router, types_exports$7 as Spa, browserEnv, buildArticleHead, buildPlugin, canonical, cliPlugin, cloudflareBindings, contentPlugin, createApp, createComponent, createPlugin, createUrls, dataPlugin, defineRoutes, deployPlugin, dotenv, envPlugin, feedLink, fileSystemContent, headPlugin, hreflang, i18nPlugin, jsonLd, lazyEmbed, logPlugin, meta, og, processEnv, route, routerPlugin, sitePlugin, spaPlugin, twitter };
|