@moku-labs/core 0.1.0-alpha.3 → 0.1.0-alpha.5
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/index.cjs +276 -12
- package/dist/index.d.cts +288 -125
- package/dist/index.d.mts +288 -125
- package/dist/index.mjs +275 -12
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -1,89 +1,3 @@
|
|
|
1
|
-
//#region src/utilities.d.ts
|
|
2
|
-
/**
|
|
3
|
-
* Base constraint for framework configuration objects.
|
|
4
|
-
*
|
|
5
|
-
* @example
|
|
6
|
-
* ```ts
|
|
7
|
-
* function createConfig<C extends FrameworkConfig>(defaults: C): C { return defaults; }
|
|
8
|
-
* ```
|
|
9
|
-
*/
|
|
10
|
-
type FrameworkConfig = Record<string, unknown>;
|
|
11
|
-
/**
|
|
12
|
-
* Base constraint for framework event maps.
|
|
13
|
-
*
|
|
14
|
-
* @example
|
|
15
|
-
* ```ts
|
|
16
|
-
* function createEvents<E extends FrameworkEventMap>(events: E): E { return events; }
|
|
17
|
-
* ```
|
|
18
|
-
*/
|
|
19
|
-
type FrameworkEventMap = Record<string, unknown>;
|
|
20
|
-
/**
|
|
21
|
-
* Empty event map used as the default when a plugin declares no custom events.
|
|
22
|
-
* `Record<never, never>` is the identity element for intersection (`T & {} = T`).
|
|
23
|
-
*
|
|
24
|
-
* @example
|
|
25
|
-
* ```ts
|
|
26
|
-
* type PluginEvents = EmptyPluginEventMap; // default when no events declared
|
|
27
|
-
* ```
|
|
28
|
-
*/
|
|
29
|
-
type EmptyPluginEventMap = Record<never, never>;
|
|
30
|
-
/**
|
|
31
|
-
* Convert a union to an intersection via distributive conditional + contra-variance.
|
|
32
|
-
*
|
|
33
|
-
* @example
|
|
34
|
-
* ```ts
|
|
35
|
-
* type Result = UnionToIntersection<{ a: 1 } | { b: 2 }>; // { a: 1 } & { b: 2 }
|
|
36
|
-
* ```
|
|
37
|
-
*/
|
|
38
|
-
type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never;
|
|
39
|
-
/**
|
|
40
|
-
* Detect if a string type is a literal (e.g. "router") vs the general `string` type.
|
|
41
|
-
* Used by BuildPluginApis to exclude plugins with non-literal names from the mapped type.
|
|
42
|
-
*
|
|
43
|
-
* @example
|
|
44
|
-
* ```ts
|
|
45
|
-
* type Yes = IsLiteralString<"router">; // true
|
|
46
|
-
* type No = IsLiteralString<string>; // false
|
|
47
|
-
* ```
|
|
48
|
-
*/
|
|
49
|
-
type IsLiteralString<S extends string> = string extends S ? false : true;
|
|
50
|
-
/**
|
|
51
|
-
* Auto-generate overloaded emit call signatures from an event map type.
|
|
52
|
-
*
|
|
53
|
-
* Converts `{ "a": X; "b": Y }` into `((name: "a", payload: X) => void) & ((name: "b", payload: Y) => void)`.
|
|
54
|
-
* Uses `UnionToIntersection` to transform a union of per-event functions into
|
|
55
|
-
* an intersection (overloaded call signatures).
|
|
56
|
-
*
|
|
57
|
-
* When `E` has no keys, produces an uncallable but constructible function type
|
|
58
|
-
* so `vi.fn()` and `() => {}` remain assignable while calling emit is a compile error.
|
|
59
|
-
*
|
|
60
|
-
* Exported from the package entry point for plugin authors at Standard+ tier.
|
|
61
|
-
*
|
|
62
|
-
* @example
|
|
63
|
-
* ```ts
|
|
64
|
-
* type CmsEmit = EmitFn<{
|
|
65
|
-
* "cms:publish": { contentId: string; path: string };
|
|
66
|
-
* "cms:draft": { contentId: string };
|
|
67
|
-
* }>;
|
|
68
|
-
* // Equivalent to:
|
|
69
|
-
* // ((name: "cms:publish", payload: { contentId: string; path: string }) => void)
|
|
70
|
-
* // & ((name: "cms:draft", payload: { contentId: string }) => void)
|
|
71
|
-
* ```
|
|
72
|
-
*/
|
|
73
|
-
type EmitFunction<E extends Record<string, unknown>> = [keyof E] extends [never] ? (...arguments_: never[]) => void : UnionToIntersection<{ [K in string & keyof E]: (name: K, payload: E[K]) => void }[string & keyof E]>;
|
|
74
|
-
/**
|
|
75
|
-
* Checks whether a value is a non-null, non-array object record.
|
|
76
|
-
*
|
|
77
|
-
* @param value - Value to inspect.
|
|
78
|
-
* @returns `true` when value is an object record.
|
|
79
|
-
* @example
|
|
80
|
-
* ```ts
|
|
81
|
-
* isRecord({ key: "value" }); // => true
|
|
82
|
-
* isRecord([1, 2, 3]); // => false
|
|
83
|
-
* isRecord(null); // => false
|
|
84
|
-
* ```
|
|
85
|
-
*/
|
|
86
|
-
//#endregion
|
|
87
1
|
//#region src/types.d.ts
|
|
88
2
|
/**
|
|
89
3
|
* Teardown context — the most minimal context tier.
|
|
@@ -147,14 +61,14 @@ type MinimalContext<Config, C> = {
|
|
|
147
61
|
* })
|
|
148
62
|
* ```
|
|
149
63
|
*/
|
|
150
|
-
type PluginContext<Config, Events extends Record<string, unknown>, C, S> = {
|
|
64
|
+
type PluginContext<Config, Events extends Record<string, unknown>, C, S, CoreApis extends Record<string, unknown> = {}> = {
|
|
151
65
|
readonly global: Readonly<Config>;
|
|
152
66
|
readonly config: Readonly<C>;
|
|
153
67
|
state: S;
|
|
154
68
|
emit: EmitFunction$1<Events>;
|
|
155
69
|
require: RequireFunction;
|
|
156
70
|
has: HasFunction;
|
|
157
|
-
};
|
|
71
|
+
} & { readonly [K in keyof CoreApis]: CoreApis[K] };
|
|
158
72
|
/**
|
|
159
73
|
* Strictly typed emit function (kernel-layer generic signature).
|
|
160
74
|
* Only known event names are accepted, with matching payload required.
|
|
@@ -216,15 +130,15 @@ type HasFunction = (name: string) => boolean;
|
|
|
216
130
|
* { navigate(path: string): void }, readonly []>;
|
|
217
131
|
* ```
|
|
218
132
|
*/
|
|
219
|
-
type PluginSpec<Config, Events extends Record<string, unknown>, PluginEvents extends Record<string, unknown>, C, S, A extends Record<string, any>, Deps extends ReadonlyArray<PluginInstance<string, any, any, any, any
|
|
133
|
+
type PluginSpec<Config, Events extends Record<string, unknown>, PluginEvents extends Record<string, unknown>, C, S, A extends Record<string, any>, Deps extends ReadonlyArray<PluginInstance<string, any, any, any, any>>, CoreApis extends Record<string, unknown> = {}> = {
|
|
220
134
|
config?: C;
|
|
221
135
|
depends?: Deps;
|
|
222
136
|
createState?: (context: MinimalContext<Config, C>) => S;
|
|
223
|
-
api?: (context: PluginContext<Config, Events & PluginEvents & DepsEvents<Deps>, C, S>) => A;
|
|
224
|
-
onInit?: (context: PluginContext<Config, Events & PluginEvents & DepsEvents<Deps>, C, S>) => void;
|
|
225
|
-
onStart?: (context: PluginContext<Config, Events & PluginEvents & DepsEvents<Deps>, C, S>) => void | Promise<void>;
|
|
137
|
+
api?: (context: PluginContext<Config, Events & PluginEvents & DepsEvents<Deps>, C, S, CoreApis>) => A;
|
|
138
|
+
onInit?: (context: PluginContext<Config, Events & PluginEvents & DepsEvents<Deps>, C, S, CoreApis>) => void;
|
|
139
|
+
onStart?: (context: PluginContext<Config, Events & PluginEvents & DepsEvents<Deps>, C, S, CoreApis>) => void | Promise<void>;
|
|
226
140
|
onStop?: (context: TeardownContext<Config>) => void | Promise<void>;
|
|
227
|
-
hooks?: (context: PluginContext<Config, Events & PluginEvents & DepsEvents<Deps>, C, S>) => { [K in string & keyof (Events & PluginEvents & DepsEvents<Deps>)]?: (payload: (Events & PluginEvents & DepsEvents<Deps>)[K]) => void | Promise<void> };
|
|
141
|
+
hooks?: (context: PluginContext<Config, Events & PluginEvents & DepsEvents<Deps>, C, S, CoreApis>) => { [K in string & keyof (Events & PluginEvents & DepsEvents<Deps>)]?: (payload: (Events & PluginEvents & DepsEvents<Deps>)[K]) => void | Promise<void> };
|
|
228
142
|
};
|
|
229
143
|
/**
|
|
230
144
|
* Plugin instance — the return value of createPlugin.
|
|
@@ -343,13 +257,13 @@ type BuildPluginApis<P extends PluginInstance<string, any, any, any, any>> = { [
|
|
|
343
257
|
* app.router.navigate("/about");
|
|
344
258
|
* ```
|
|
345
259
|
*/
|
|
346
|
-
type App<_Config extends Record<string, unknown>, Events extends Record<string, unknown>, P extends PluginInstance<string, any, any, any, any
|
|
260
|
+
type App<_Config extends Record<string, unknown>, Events extends Record<string, unknown>, P extends PluginInstance<string, any, any, any, any>, CoreApis extends Record<string, unknown> = {}> = {
|
|
347
261
|
readonly start: () => Promise<void>;
|
|
348
262
|
readonly stop: () => Promise<void>;
|
|
349
263
|
readonly emit: EmitFunction$1<Events>;
|
|
350
264
|
readonly require: RequireFunction;
|
|
351
265
|
readonly has: HasFunction;
|
|
352
|
-
} & BuildPluginApis<P
|
|
266
|
+
} & BuildPluginApis<P> & { readonly [K in keyof CoreApis]: CoreApis[K] };
|
|
353
267
|
/**
|
|
354
268
|
* Context passed to consumer lifecycle callbacks (onReady, onStart, onStop).
|
|
355
269
|
* Includes frozen config, event emission, plugin lookup, and mounted plugin APIs.
|
|
@@ -363,12 +277,12 @@ type App<_Config extends Record<string, unknown>, Events extends Record<string,
|
|
|
363
277
|
* onReady: (ctx: Ctx) => { ctx.router.navigate("/home"); }
|
|
364
278
|
* ```
|
|
365
279
|
*/
|
|
366
|
-
type AppCallbackContext<Config extends Record<string, unknown>, Events extends Record<string, unknown>, P extends PluginInstance<string, any, any, any, any
|
|
280
|
+
type AppCallbackContext<Config extends Record<string, unknown>, Events extends Record<string, unknown>, P extends PluginInstance<string, any, any, any, any>, CoreApis extends Record<string, unknown> = {}> = {
|
|
367
281
|
readonly config: Readonly<Config>;
|
|
368
282
|
readonly emit: EmitFunction$1<Events>;
|
|
369
283
|
readonly require: RequireFunction;
|
|
370
284
|
readonly has: HasFunction;
|
|
371
|
-
} & BuildPluginApis<P
|
|
285
|
+
} & BuildPluginApis<P> & { readonly [K in keyof CoreApis]: CoreApis[K] };
|
|
372
286
|
/**
|
|
373
287
|
* Options for createApp (Step 3). Structured namespaces replace flat key discrimination:
|
|
374
288
|
* - `plugins`: extra consumer plugins
|
|
@@ -385,14 +299,14 @@ type AppCallbackContext<Config extends Record<string, unknown>, Events extends R
|
|
|
385
299
|
* });
|
|
386
300
|
* ```
|
|
387
301
|
*/
|
|
388
|
-
type CreateAppOptions<Config extends Record<string, unknown>, Events extends Record<string, unknown>, P extends PluginInstance<string, any, any, any, any>, ExtraPlugins extends readonly PluginInstance<string, any, any, any, any>[]> = {
|
|
302
|
+
type CreateAppOptions<Config extends Record<string, unknown>, Events extends Record<string, unknown>, P extends PluginInstance<string, any, any, any, any>, ExtraPlugins extends readonly PluginInstance<string, any, any, any, any>[], CoreApis extends Record<string, unknown> = {}> = {
|
|
389
303
|
plugins?: ExtraPlugins;
|
|
390
304
|
config?: { [K in keyof Config]?: Config[K] };
|
|
391
305
|
pluginConfigs?: { [K in P as ExtractConfig<K> extends Record<string, never> ? never : IsLiteralString<ExtractName<K>> extends true ? ExtractName<K> : never]?: Partial<ExtractConfig<K>> };
|
|
392
|
-
onReady?: (context: AppCallbackContext<Config, Events, P>) => void;
|
|
393
|
-
onError?: (error: Error, context: AppCallbackContext<Config, Events, P>) => void;
|
|
394
|
-
onStart?: (context: AppCallbackContext<Config, Events, P>) => void | Promise<void>;
|
|
395
|
-
onStop?: (context: AppCallbackContext<Config, Events, P>) => void | Promise<void>;
|
|
306
|
+
onReady?: (context: AppCallbackContext<Config, Events, P, CoreApis>) => void;
|
|
307
|
+
onError?: (error: Error, context: AppCallbackContext<Config, Events, P, CoreApis>) => void;
|
|
308
|
+
onStart?: (context: AppCallbackContext<Config, Events, P, CoreApis>) => void | Promise<void>;
|
|
309
|
+
onStop?: (context: AppCallbackContext<Config, Events, P, CoreApis>) => void | Promise<void>;
|
|
396
310
|
};
|
|
397
311
|
/**
|
|
398
312
|
* Domain context type for extracted plugin files (api.ts, handlers.ts, etc.).
|
|
@@ -430,6 +344,234 @@ type PluginContext_<C, S, E extends Record<string, unknown> = Record<never, neve
|
|
|
430
344
|
emit: EmitFunction<E>;
|
|
431
345
|
};
|
|
432
346
|
//#endregion
|
|
347
|
+
//#region src/utilities.d.ts
|
|
348
|
+
/**
|
|
349
|
+
* Base constraint for framework configuration objects.
|
|
350
|
+
*
|
|
351
|
+
* @example
|
|
352
|
+
* ```ts
|
|
353
|
+
* function createConfig<C extends FrameworkConfig>(defaults: C): C { return defaults; }
|
|
354
|
+
* ```
|
|
355
|
+
*/
|
|
356
|
+
type FrameworkConfig = Record<string, unknown>;
|
|
357
|
+
/**
|
|
358
|
+
* Base constraint for framework event maps.
|
|
359
|
+
*
|
|
360
|
+
* @example
|
|
361
|
+
* ```ts
|
|
362
|
+
* function createEvents<E extends FrameworkEventMap>(events: E): E { return events; }
|
|
363
|
+
* ```
|
|
364
|
+
*/
|
|
365
|
+
type FrameworkEventMap = Record<string, unknown>;
|
|
366
|
+
/**
|
|
367
|
+
* Empty event map used as the default when a plugin declares no custom events.
|
|
368
|
+
* `Record<never, never>` is the identity element for intersection (`T & {} = T`).
|
|
369
|
+
*
|
|
370
|
+
* @example
|
|
371
|
+
* ```ts
|
|
372
|
+
* type PluginEvents = EmptyPluginEventMap; // default when no events declared
|
|
373
|
+
* ```
|
|
374
|
+
*/
|
|
375
|
+
type EmptyPluginEventMap = Record<never, never>;
|
|
376
|
+
/**
|
|
377
|
+
* Convert a union to an intersection via distributive conditional + contra-variance.
|
|
378
|
+
*
|
|
379
|
+
* @example
|
|
380
|
+
* ```ts
|
|
381
|
+
* type Result = UnionToIntersection<{ a: 1 } | { b: 2 }>; // { a: 1 } & { b: 2 }
|
|
382
|
+
* ```
|
|
383
|
+
*/
|
|
384
|
+
type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never;
|
|
385
|
+
/**
|
|
386
|
+
* Detect if a string type is a literal (e.g. "router") vs the general `string` type.
|
|
387
|
+
* Used by BuildPluginApis to exclude plugins with non-literal names from the mapped type.
|
|
388
|
+
*
|
|
389
|
+
* @example
|
|
390
|
+
* ```ts
|
|
391
|
+
* type Yes = IsLiteralString<"router">; // true
|
|
392
|
+
* type No = IsLiteralString<string>; // false
|
|
393
|
+
* ```
|
|
394
|
+
*/
|
|
395
|
+
type IsLiteralString<S extends string> = string extends S ? false : true;
|
|
396
|
+
/**
|
|
397
|
+
* Auto-generate overloaded emit call signatures from an event map type.
|
|
398
|
+
*
|
|
399
|
+
* Converts `{ "a": X; "b": Y }` into `((name: "a", payload: X) => void) & ((name: "b", payload: Y) => void)`.
|
|
400
|
+
* Uses `UnionToIntersection` to transform a union of per-event functions into
|
|
401
|
+
* an intersection (overloaded call signatures).
|
|
402
|
+
*
|
|
403
|
+
* When `E` has no keys, produces an uncallable but constructible function type
|
|
404
|
+
* so `vi.fn()` and `() => {}` remain assignable while calling emit is a compile error.
|
|
405
|
+
*
|
|
406
|
+
* Exported from the package entry point for plugin authors at Standard+ tier.
|
|
407
|
+
*
|
|
408
|
+
* @example
|
|
409
|
+
* ```ts
|
|
410
|
+
* type CmsEmit = EmitFn<{
|
|
411
|
+
* "cms:publish": { contentId: string; path: string };
|
|
412
|
+
* "cms:draft": { contentId: string };
|
|
413
|
+
* }>;
|
|
414
|
+
* // Equivalent to:
|
|
415
|
+
* // ((name: "cms:publish", payload: { contentId: string; path: string }) => void)
|
|
416
|
+
* // & ((name: "cms:draft", payload: { contentId: string }) => void)
|
|
417
|
+
* ```
|
|
418
|
+
*/
|
|
419
|
+
type EmitFunction<E extends Record<string, unknown>> = [keyof E] extends [never] ? (...arguments_: never[]) => void : UnionToIntersection<{ [K in string & keyof E]: (name: K, payload: E[K]) => void }[string & keyof E]>;
|
|
420
|
+
/**
|
|
421
|
+
* Checks whether a value is a non-null, non-array object record.
|
|
422
|
+
*
|
|
423
|
+
* @param value - Value to inspect.
|
|
424
|
+
* @returns `true` when value is an object record.
|
|
425
|
+
* @example
|
|
426
|
+
* ```ts
|
|
427
|
+
* isRecord({ key: "value" }); // => true
|
|
428
|
+
* isRecord([1, 2, 3]); // => false
|
|
429
|
+
* isRecord(null); // => false
|
|
430
|
+
* ```
|
|
431
|
+
*/
|
|
432
|
+
//#endregion
|
|
433
|
+
//#region src/core-plugin.d.ts
|
|
434
|
+
/**
|
|
435
|
+
* Minimal context for core plugins. Only config and state — no global, emit,
|
|
436
|
+
* require, or has. Core plugins are self-contained infrastructure.
|
|
437
|
+
*
|
|
438
|
+
* @example
|
|
439
|
+
* ```ts
|
|
440
|
+
* type LogCtx = CorePluginContext<{ level: string }, { entries: string[] }>;
|
|
441
|
+
* // => { readonly config: Readonly<{ level: string }>; state: { entries: string[] } }
|
|
442
|
+
* ```
|
|
443
|
+
*/
|
|
444
|
+
type CorePluginContext<C, S> = {
|
|
445
|
+
readonly config: Readonly<C>;
|
|
446
|
+
state: S;
|
|
447
|
+
};
|
|
448
|
+
/**
|
|
449
|
+
* Core plugin specification — the shape passed to createCorePlugin.
|
|
450
|
+
*
|
|
451
|
+
* Same lifecycle methods as regular plugins (config, createState, api, onInit,
|
|
452
|
+
* onStart, onStop) but NO depends, events, or hooks.
|
|
453
|
+
*
|
|
454
|
+
* @example
|
|
455
|
+
* ```ts
|
|
456
|
+
* const spec: CorePluginSpec<{ level: string }, { entries: string[] }, { info(msg: string): void }> = {
|
|
457
|
+
* config: { level: "info" },
|
|
458
|
+
* createState: () => ({ entries: [] }),
|
|
459
|
+
* api: ctx => ({ info: (msg) => { ctx.state.entries.push(msg); } }),
|
|
460
|
+
* };
|
|
461
|
+
* ```
|
|
462
|
+
*/
|
|
463
|
+
type CorePluginSpec<C extends Record<string, unknown>, S, A extends Record<string, any>> = {
|
|
464
|
+
/** Default config values for this core plugin. Consumers can override via pluginConfigs. */config?: C; /** Factory for mutable state. Called once with { config } only. */
|
|
465
|
+
createState?: (context: {
|
|
466
|
+
readonly config: Readonly<C>;
|
|
467
|
+
}) => S; /** API factory. The returned object is injected directly onto every regular plugin's context. */
|
|
468
|
+
api?: (context: CorePluginContext<C, S>) => A; /** Called after core plugin APIs are built. Synchronous. */
|
|
469
|
+
onInit?: (context: CorePluginContext<C, S>) => void; /** Called when app starts. Core plugins start before regular plugins. */
|
|
470
|
+
onStart?: (context: CorePluginContext<C, S>) => void | Promise<void>; /** Called when app stops. Core plugins stop after regular plugins. */
|
|
471
|
+
onStop?: (context: CorePluginContext<C, S>) => void | Promise<void>;
|
|
472
|
+
};
|
|
473
|
+
/**
|
|
474
|
+
* Core plugin instance — the return value of createCorePlugin.
|
|
475
|
+
*
|
|
476
|
+
* Carries phantom types for compile-time inference and a `_corePlugin: true`
|
|
477
|
+
* brand to distinguish from regular PluginInstance.
|
|
478
|
+
*
|
|
479
|
+
* @example
|
|
480
|
+
* ```ts
|
|
481
|
+
* const log = createCorePlugin("log", { api: ctx => ({ info: () => {} }) });
|
|
482
|
+
* // log: CorePluginInstance<"log", Record<string, never>, Record<string, never>, { info(): void }>
|
|
483
|
+
* ```
|
|
484
|
+
*/
|
|
485
|
+
interface CorePluginInstance<N extends string = string, C = void, S = void, A extends Record<string, any> = Record<string, never>> {
|
|
486
|
+
readonly name: N;
|
|
487
|
+
readonly spec: CorePluginSpec<any, any, any>;
|
|
488
|
+
readonly _corePlugin: true;
|
|
489
|
+
readonly _phantom: {
|
|
490
|
+
config: C;
|
|
491
|
+
state: S;
|
|
492
|
+
api: A;
|
|
493
|
+
};
|
|
494
|
+
}
|
|
495
|
+
/**
|
|
496
|
+
* Widened CorePluginInstance type for generic constraints on arrays.
|
|
497
|
+
*
|
|
498
|
+
* @example
|
|
499
|
+
* ```ts
|
|
500
|
+
* function processCorePlugins(plugins: AnyCorePluginInstance[]): void { ... }
|
|
501
|
+
* ```
|
|
502
|
+
*/
|
|
503
|
+
type AnyCorePluginInstance = CorePluginInstance<string, any, any, any>;
|
|
504
|
+
/**
|
|
505
|
+
* Extract the name literal type from a CorePluginInstance.
|
|
506
|
+
*
|
|
507
|
+
* @example
|
|
508
|
+
* ```ts
|
|
509
|
+
* type Name = ExtractCoreName<typeof logPlugin>; // "log"
|
|
510
|
+
* ```
|
|
511
|
+
*/
|
|
512
|
+
type ExtractCoreName<P> = P extends CorePluginInstance<infer N, any, any, any> ? N : never;
|
|
513
|
+
/**
|
|
514
|
+
* Extract the API phantom type from a CorePluginInstance.
|
|
515
|
+
*
|
|
516
|
+
* @example
|
|
517
|
+
* ```ts
|
|
518
|
+
* type LogApi = ExtractCoreApi<typeof logPlugin>; // { info(msg: string): void }
|
|
519
|
+
* ```
|
|
520
|
+
*/
|
|
521
|
+
type ExtractCoreApi<P> = P extends CorePluginInstance<string, any, any, infer A> ? A : never;
|
|
522
|
+
/**
|
|
523
|
+
* Extract the config phantom type from a CorePluginInstance.
|
|
524
|
+
*
|
|
525
|
+
* @example
|
|
526
|
+
* ```ts
|
|
527
|
+
* type LogConfig = ExtractCoreConfig<typeof logPlugin>; // { level: string }
|
|
528
|
+
* ```
|
|
529
|
+
*/
|
|
530
|
+
type ExtractCoreConfig<P> = P extends CorePluginInstance<string, infer C, any, any> ? C : never;
|
|
531
|
+
/**
|
|
532
|
+
* Map a core plugin union to `{ readonly [Name]: Api }` for context injection.
|
|
533
|
+
* Core plugins with empty API (Record<string, never>) are excluded.
|
|
534
|
+
* Core plugins with non-literal name type (string) are excluded.
|
|
535
|
+
*
|
|
536
|
+
* @example
|
|
537
|
+
* ```ts
|
|
538
|
+
* type Apis = BuildCorePluginApis<typeof logPlugin | typeof envPlugin>;
|
|
539
|
+
* // => { readonly log: { info(msg: string): void }; readonly env: { isDev(): boolean } }
|
|
540
|
+
* ```
|
|
541
|
+
*/
|
|
542
|
+
type BuildCorePluginApis<P extends CorePluginInstance<string, any, any, any>> = { readonly [K in P as ExtractCoreApi<K> extends Record<string, never> ? never : IsLiteralString<ExtractCoreName<K>> extends true ? ExtractCoreName<K> : never]: ExtractCoreApi<K> };
|
|
543
|
+
/**
|
|
544
|
+
* Compute core API map from a core plugin tuple.
|
|
545
|
+
* Convenience alias: extracts the union from the tuple, then builds the map.
|
|
546
|
+
*
|
|
547
|
+
* @example
|
|
548
|
+
* ```ts
|
|
549
|
+
* type Apis = CoreApisFromTuple<readonly [typeof logPlugin, typeof envPlugin]>;
|
|
550
|
+
* // => { readonly log: LogApi; readonly env: EnvApi }
|
|
551
|
+
* ```
|
|
552
|
+
*/
|
|
553
|
+
type CoreApisFromTuple<T extends readonly AnyCorePluginInstance[]> = BuildCorePluginApis<T[number]>;
|
|
554
|
+
/**
|
|
555
|
+
* Creates a core plugin instance. Core plugins are standalone, self-contained
|
|
556
|
+
* infrastructure plugins (log, storage, env) whose APIs are injected directly
|
|
557
|
+
* onto every regular plugin's context.
|
|
558
|
+
*
|
|
559
|
+
* @param name - Unique core plugin name (inferred as literal string type).
|
|
560
|
+
* @param spec - Core plugin specification: config, createState, api, lifecycle.
|
|
561
|
+
* @returns A CorePluginInstance carrying phantom types for compile-time inference.
|
|
562
|
+
* @example
|
|
563
|
+
* ```ts
|
|
564
|
+
* const logPlugin = createCorePlugin("log", {
|
|
565
|
+
* config: { level: "info" },
|
|
566
|
+
* createState: () => ({ entries: [] as string[] }),
|
|
567
|
+
* api: ctx => ({
|
|
568
|
+
* info: (msg: string) => { ctx.state.entries.push(msg); console.log(msg); },
|
|
569
|
+
* }),
|
|
570
|
+
* });
|
|
571
|
+
* ```
|
|
572
|
+
*/
|
|
573
|
+
declare function createCorePlugin<const N extends string, C extends Record<string, unknown> = Record<string, never>, S = Record<string, never>, A extends Record<string, any> = Record<string, never>>(name: N, spec: CorePluginSpec<C, S, A>): CorePluginInstance<N, C, S, A>;
|
|
574
|
+
//#endregion
|
|
433
575
|
//#region src/plugin.d.ts
|
|
434
576
|
/**
|
|
435
577
|
* Structural plugin shape used for generic constraints without variance issues.
|
|
@@ -521,7 +663,7 @@ type MergedPluginEvents<GlobalEventMap extends FrameworkEventMap, PluginEventMap
|
|
|
521
663
|
* >;
|
|
522
664
|
* ```
|
|
523
665
|
*/
|
|
524
|
-
type PluginExecutionContext<GlobalConfig extends FrameworkConfig, AllEvents extends Record<string, unknown>, PluginConfig, PluginState> = {
|
|
666
|
+
type PluginExecutionContext<GlobalConfig extends FrameworkConfig, AllEvents extends Record<string, unknown>, PluginConfig, PluginState, CoreApis extends Record<string, unknown> = {}> = {
|
|
525
667
|
/**
|
|
526
668
|
* Frozen app-wide config from `createCoreConfig`. Shared by all plugins.
|
|
527
669
|
*
|
|
@@ -580,7 +722,7 @@ type PluginExecutionContext<GlobalConfig extends FrameworkConfig, AllEvents exte
|
|
|
580
722
|
* ```
|
|
581
723
|
*/
|
|
582
724
|
has: (name: string) => boolean;
|
|
583
|
-
};
|
|
725
|
+
} & { readonly [K in keyof CoreApis]: CoreApis[K] };
|
|
584
726
|
/**
|
|
585
727
|
* Descriptor returned by register(). Carries the payload type.
|
|
586
728
|
* and an optional description string for runtime event catalogs.
|
|
@@ -639,7 +781,7 @@ type RegisterFunction = {
|
|
|
639
781
|
* >;
|
|
640
782
|
* ```
|
|
641
783
|
*/
|
|
642
|
-
type CreatePluginSpec<GlobalConfig extends FrameworkConfig, GlobalEventMap extends FrameworkEventMap, PluginEventMap extends Record<string, unknown>, PluginConfig extends Record<string, unknown>, PluginState, PluginApi extends Record<string, unknown>, DependencyPlugins extends DependencyPluginTuple> = {
|
|
784
|
+
type CreatePluginSpec<GlobalConfig extends FrameworkConfig, GlobalEventMap extends FrameworkEventMap, PluginEventMap extends Record<string, unknown>, PluginConfig extends Record<string, unknown>, PluginState, PluginApi extends Record<string, unknown>, DependencyPlugins extends DependencyPluginTuple, CoreApis extends Record<string, unknown> = {}, Helpers extends Record<string, (...arguments_: any[]) => any> = Record<never, never>> = {
|
|
643
785
|
/**
|
|
644
786
|
* Declare plugin-specific events via a register callback.
|
|
645
787
|
* Used for compile-time type inference only — the kernel does not call this at runtime.
|
|
@@ -696,7 +838,7 @@ type CreatePluginSpec<GlobalConfig extends FrameworkConfig, GlobalEventMap exten
|
|
|
696
838
|
* })
|
|
697
839
|
* ```
|
|
698
840
|
*/
|
|
699
|
-
api?: (context: PluginExecutionContext<GlobalConfig, MergedPluginEvents<GlobalEventMap, PluginEventMap, DependencyPlugins>, PluginConfig, PluginState>) => PluginApi;
|
|
841
|
+
api?: (context: PluginExecutionContext<GlobalConfig, MergedPluginEvents<GlobalEventMap, PluginEventMap, DependencyPlugins>, PluginConfig, PluginState, CoreApis>) => PluginApi;
|
|
700
842
|
/**
|
|
701
843
|
* Called after all plugins are registered and APIs are built. Runs in forward
|
|
702
844
|
* plugin order, synchronously. Use for setup that depends on other plugins.
|
|
@@ -710,7 +852,7 @@ type CreatePluginSpec<GlobalConfig extends FrameworkConfig, GlobalEventMap exten
|
|
|
710
852
|
* }
|
|
711
853
|
* ```
|
|
712
854
|
*/
|
|
713
|
-
onInit?: (context: PluginExecutionContext<GlobalConfig, MergedPluginEvents<GlobalEventMap, PluginEventMap, DependencyPlugins>, PluginConfig, PluginState>) => void;
|
|
855
|
+
onInit?: (context: PluginExecutionContext<GlobalConfig, MergedPluginEvents<GlobalEventMap, PluginEventMap, DependencyPlugins>, PluginConfig, PluginState, CoreApis>) => void;
|
|
714
856
|
/**
|
|
715
857
|
* Called when the app starts. Runs in forward plugin order, sequentially awaited.
|
|
716
858
|
* Use for runtime startup (open connections, start listeners).
|
|
@@ -722,7 +864,7 @@ type CreatePluginSpec<GlobalConfig extends FrameworkConfig, GlobalEventMap exten
|
|
|
722
864
|
* }
|
|
723
865
|
* ```
|
|
724
866
|
*/
|
|
725
|
-
onStart?: (context: PluginExecutionContext<GlobalConfig, MergedPluginEvents<GlobalEventMap, PluginEventMap, DependencyPlugins>, PluginConfig, PluginState>) => void | Promise<void>;
|
|
867
|
+
onStart?: (context: PluginExecutionContext<GlobalConfig, MergedPluginEvents<GlobalEventMap, PluginEventMap, DependencyPlugins>, PluginConfig, PluginState, CoreApis>) => void | Promise<void>;
|
|
726
868
|
/**
|
|
727
869
|
* Called when the app stops. Runs in **reverse** plugin order, sequentially awaited.
|
|
728
870
|
* Use for teardown (close connections, flush buffers). Receives only global config.
|
|
@@ -750,7 +892,21 @@ type CreatePluginSpec<GlobalConfig extends FrameworkConfig, GlobalEventMap exten
|
|
|
750
892
|
* })
|
|
751
893
|
* ```
|
|
752
894
|
*/
|
|
753
|
-
hooks?: (context: PluginExecutionContext<GlobalConfig, MergedPluginEvents<GlobalEventMap, PluginEventMap, DependencyPlugins>, PluginConfig, PluginState>) => { [EventName in string & keyof MergedPluginEvents<GlobalEventMap, PluginEventMap, DependencyPlugins>]?: (payload: MergedPluginEvents<GlobalEventMap, PluginEventMap, DependencyPlugins>[EventName]) => void | Promise<void> };
|
|
895
|
+
hooks?: (context: PluginExecutionContext<GlobalConfig, MergedPluginEvents<GlobalEventMap, PluginEventMap, DependencyPlugins>, PluginConfig, PluginState, CoreApis>) => { [EventName in string & keyof MergedPluginEvents<GlobalEventMap, PluginEventMap, DependencyPlugins>]?: (payload: MergedPluginEvents<GlobalEventMap, PluginEventMap, DependencyPlugins>[EventName]) => void | Promise<void> };
|
|
896
|
+
/**
|
|
897
|
+
* Static helper functions exposed directly on the plugin instance.
|
|
898
|
+
* Helpers run before createApp — they receive no context.
|
|
899
|
+
* Use for typed factories and builders that produce config values.
|
|
900
|
+
*
|
|
901
|
+
* @example
|
|
902
|
+
* ```ts
|
|
903
|
+
* helpers: {
|
|
904
|
+
* route: (path: string, component: string) => ({ path, component }),
|
|
905
|
+
* redirect: (from: string, to: string) => ({ from, to, type: 'redirect' as const }),
|
|
906
|
+
* }
|
|
907
|
+
* ```
|
|
908
|
+
*/
|
|
909
|
+
helpers?: Helpers;
|
|
754
910
|
};
|
|
755
911
|
/**
|
|
756
912
|
* Bound createPlugin function type, parameterized by the framework's Config and Events.
|
|
@@ -764,10 +920,11 @@ type CreatePluginSpec<GlobalConfig extends FrameworkConfig, GlobalEventMap exten
|
|
|
764
920
|
* const router = createPlugin("router", { config: { basePath: "/" } });
|
|
765
921
|
* ```
|
|
766
922
|
*/
|
|
767
|
-
type BoundCreatePluginFunction<GlobalConfig extends FrameworkConfig, GlobalEventMap extends FrameworkEventMap> = {
|
|
768
|
-
<const PluginName extends string = string, PluginConfig extends Record<string, unknown> = Record<string, never>, PluginState = Record<string, never>, PluginApi extends Record<string, unknown> = Record<string, never>, DependencyPlugins extends DependencyPluginTuple = readonly [], PluginEventMap extends Record<string, unknown> = EmptyPluginEventMap, HookHandlerMap extends Record<string, any> = Record<never, never>>(name: PluginName, spec: Omit<CreatePluginSpec<GlobalConfig, GlobalEventMap, PluginEventMap, PluginConfig, PluginState, PluginApi, DependencyPlugins>, "hooks"> & {
|
|
769
|
-
hooks?: (context: PluginExecutionContext<GlobalConfig, MergedPluginEvents<GlobalEventMap, PluginEventMap, DependencyPlugins>, PluginConfig, PluginState>) => { [K in keyof HookHandlerMap]: K extends string & keyof MergedPluginEvents<GlobalEventMap, PluginEventMap, DependencyPlugins> ? (payload: MergedPluginEvents<GlobalEventMap, PluginEventMap, DependencyPlugins>[K & keyof MergedPluginEvents<GlobalEventMap, PluginEventMap, DependencyPlugins>]) => void | Promise<void> : never };
|
|
770
|
-
|
|
923
|
+
type BoundCreatePluginFunction<GlobalConfig extends FrameworkConfig, GlobalEventMap extends FrameworkEventMap, CoreApis extends Record<string, unknown> = {}> = {
|
|
924
|
+
<const PluginName extends string = string, PluginConfig extends Record<string, unknown> = Record<string, never>, PluginState = Record<string, never>, PluginApi extends Record<string, unknown> = Record<string, never>, DependencyPlugins extends DependencyPluginTuple = readonly [], PluginEventMap extends Record<string, unknown> = EmptyPluginEventMap, HookHandlerMap extends Record<string, any> = Record<never, never>, Helpers extends Record<string, (...arguments_: any[]) => any> = Record<never, never>>(name: PluginName, spec: Omit<CreatePluginSpec<GlobalConfig, GlobalEventMap, PluginEventMap, PluginConfig, PluginState, PluginApi, DependencyPlugins, CoreApis>, "hooks" | "helpers"> & {
|
|
925
|
+
hooks?: (context: PluginExecutionContext<GlobalConfig, MergedPluginEvents<GlobalEventMap, PluginEventMap, DependencyPlugins>, PluginConfig, PluginState, CoreApis>) => { [K in keyof HookHandlerMap]: K extends string & keyof MergedPluginEvents<GlobalEventMap, PluginEventMap, DependencyPlugins> ? (payload: MergedPluginEvents<GlobalEventMap, PluginEventMap, DependencyPlugins>[K & keyof MergedPluginEvents<GlobalEventMap, PluginEventMap, DependencyPlugins>]) => void | Promise<void> : never };
|
|
926
|
+
helpers?: Helpers;
|
|
927
|
+
}): PluginInstance<PluginName, PluginConfig, PluginState, PluginApi, PluginEventMap> & Helpers;
|
|
771
928
|
};
|
|
772
929
|
/**
|
|
773
930
|
* Creates a bound `createPlugin` function that captures framework generics.
|
|
@@ -815,7 +972,7 @@ interface CreateCoreOptions<Config> {
|
|
|
815
972
|
* const { createApp, createPlugin } = createCore(coreConfig, { plugins: [...] });
|
|
816
973
|
* ```
|
|
817
974
|
*/
|
|
818
|
-
interface CreateCoreResult<Config extends Record<string, unknown>, Events extends Record<string, unknown>, Plugins extends readonly AnyPluginInstance[] = readonly AnyPluginInstance[]> {
|
|
975
|
+
interface CreateCoreResult<Config extends Record<string, unknown>, Events extends Record<string, unknown>, Plugins extends readonly AnyPluginInstance[] = readonly AnyPluginInstance[], CorePlugins extends readonly AnyCorePluginInstance[] = readonly []> {
|
|
819
976
|
/**
|
|
820
977
|
* Step 3: Creates and initializes the application.
|
|
821
978
|
* Generic over ExtraPlugins to merge consumer plugins into the return type.
|
|
@@ -823,9 +980,9 @@ interface CreateCoreResult<Config extends Record<string, unknown>, Events extend
|
|
|
823
980
|
* @param options - Consumer-level config overrides, plugin configs, extra plugins.
|
|
824
981
|
* @returns The frozen, fully typed App object.
|
|
825
982
|
*/
|
|
826
|
-
readonly createApp: <const ExtraPlugins extends readonly AnyPluginInstance[] = readonly []>(options?: CreateAppOptions<Config, Events, Plugins[number] | ExtraPlugins[number], [...ExtraPlugins]
|
|
983
|
+
readonly createApp: <const ExtraPlugins extends readonly AnyPluginInstance[] = readonly []>(options?: CreateAppOptions<Config, Events, Plugins[number] | ExtraPlugins[number], [...ExtraPlugins], CoreApisFromTuple<CorePlugins>>) => App<Config, Events, Plugins[number] | ExtraPlugins[number], CoreApisFromTuple<CorePlugins>>;
|
|
827
984
|
/** Re-exported createPlugin for consumer convenience. */
|
|
828
|
-
readonly createPlugin: BoundCreatePluginFunction<Config, Events
|
|
985
|
+
readonly createPlugin: BoundCreatePluginFunction<Config, Events, CoreApisFromTuple<CorePlugins>>;
|
|
829
986
|
}
|
|
830
987
|
/**
|
|
831
988
|
* Bound createCore function type. Generic method captures the Plugins tuple
|
|
@@ -836,11 +993,11 @@ interface CreateCoreResult<Config extends Record<string, unknown>, Events extend
|
|
|
836
993
|
* const framework = createCore(coreConfig, { plugins: [routerPlugin] });
|
|
837
994
|
* ```
|
|
838
995
|
*/
|
|
839
|
-
type BoundCreateCoreFunction<Config extends Record<string, unknown>, Events extends Record<string, unknown
|
|
840
|
-
readonly createPlugin: BoundCreatePluginFunction<Config, Events
|
|
996
|
+
type BoundCreateCoreFunction<Config extends Record<string, unknown>, Events extends Record<string, unknown>, CorePlugins extends readonly AnyCorePluginInstance[] = readonly []> = <const Plugins extends readonly AnyPluginInstance[]>(coreConfig: {
|
|
997
|
+
readonly createPlugin: BoundCreatePluginFunction<Config, Events, CoreApisFromTuple<CorePlugins>>;
|
|
841
998
|
}, options: CreateCoreOptions<Config> & {
|
|
842
999
|
readonly plugins: [...Plugins];
|
|
843
|
-
}) => CreateCoreResult<Config, Events, Plugins>;
|
|
1000
|
+
}) => CreateCoreResult<Config, Events, Plugins, CorePlugins>;
|
|
844
1001
|
/**
|
|
845
1002
|
* Creates a bound `createCore` function that captures framework context.
|
|
846
1003
|
*
|
|
@@ -851,6 +1008,8 @@ type BoundCreateCoreFunction<Config extends Record<string, unknown>, Events exte
|
|
|
851
1008
|
* @param frameworkId - The framework identifier for error messages.
|
|
852
1009
|
* @param configDefaults - Default config values captured from Step 1.
|
|
853
1010
|
* @param createPlugin - Bound createPlugin function from Step 1.
|
|
1011
|
+
* @param corePlugins - Core plugin instances from createCoreConfig.
|
|
1012
|
+
* @param corePluginConfigs - Core plugin config overrides from createCoreConfig.
|
|
854
1013
|
* @returns A createCore function bound to the framework's Config and Events types.
|
|
855
1014
|
* @example
|
|
856
1015
|
* ```ts
|
|
@@ -869,11 +1028,11 @@ type BoundCreateCoreFunction<Config extends Record<string, unknown>, Events exte
|
|
|
869
1028
|
* const result: CoreConfigResult<SiteConfig, SiteEvents> = createCoreConfig("app", { config: defaults });
|
|
870
1029
|
* ```
|
|
871
1030
|
*/
|
|
872
|
-
interface CoreConfigResult<Config extends Record<string, unknown>, Events extends Record<string, unknown
|
|
1031
|
+
interface CoreConfigResult<Config extends Record<string, unknown>, Events extends Record<string, unknown>, CorePlugins extends readonly AnyCorePluginInstance[] = readonly []> {
|
|
873
1032
|
/** Creates a plugin instance with all types inferred from the spec object. */
|
|
874
|
-
readonly createPlugin: BoundCreatePluginFunction<Config, Events
|
|
1033
|
+
readonly createPlugin: BoundCreatePluginFunction<Config, Events, CoreApisFromTuple<CorePlugins>>;
|
|
875
1034
|
/** Step 2 factory: captures default plugins and returns createApp + createPlugin. */
|
|
876
|
-
readonly createCore: BoundCreateCoreFunction<Config, Events>;
|
|
1035
|
+
readonly createCore: BoundCreateCoreFunction<Config, Events, CorePlugins>;
|
|
877
1036
|
}
|
|
878
1037
|
/**
|
|
879
1038
|
* Step 1 of the 3-step factory chain. Captures Config and Events generics
|
|
@@ -885,6 +1044,8 @@ interface CoreConfigResult<Config extends Record<string, unknown>, Events extend
|
|
|
885
1044
|
* @param id - Framework identifier used in error messages.
|
|
886
1045
|
* @param options - Configuration options containing the default config values.
|
|
887
1046
|
* @param options.config - Default configuration values for the framework.
|
|
1047
|
+
* @param options.plugins - Optional core plugin instances to register.
|
|
1048
|
+
* @param options.pluginConfigs - Optional config overrides for core plugins.
|
|
888
1049
|
* @returns An object with createPlugin (bound to Config/Events) and createCore.
|
|
889
1050
|
* @example
|
|
890
1051
|
* ```ts
|
|
@@ -894,8 +1055,10 @@ interface CoreConfigResult<Config extends Record<string, unknown>, Events extend
|
|
|
894
1055
|
* const { createPlugin, createCore } = coreConfig;
|
|
895
1056
|
* ```
|
|
896
1057
|
*/
|
|
897
|
-
declare function createCoreConfig<Config extends Record<string, unknown>, Events extends Record<string, unknown> = Record<string, never
|
|
1058
|
+
declare function createCoreConfig<Config extends Record<string, unknown>, Events extends Record<string, unknown> = Record<string, never>, const CorePlugins extends readonly AnyCorePluginInstance[] = readonly []>(id: string, options: {
|
|
898
1059
|
config: Config;
|
|
899
|
-
|
|
1060
|
+
plugins?: [...CorePlugins];
|
|
1061
|
+
pluginConfigs?: { [K in CorePlugins[number] as ExtractCoreConfig<K> extends Record<string, never> ? never : IsLiteralString<ExtractCoreName<K>> extends true ? ExtractCoreName<K> : never]?: Partial<ExtractCoreConfig<K>> };
|
|
1062
|
+
}): CoreConfigResult<Config, Events, CorePlugins>;
|
|
900
1063
|
//#endregion
|
|
901
|
-
export { type AnyPluginInstance, type App, type BoundCreateCoreFunction, type BoundCreatePluginFunction, type CoreConfigResult, type CreateAppOptions, type CreateCoreOptions, type CreateCoreResult, type EmitFunction as EmitFn, type PluginContext_ as PluginCtx, type PluginInstance, createCoreConfig };
|
|
1064
|
+
export { type AnyCorePluginInstance, type AnyPluginInstance, type App, type BoundCreateCoreFunction, type BoundCreatePluginFunction, type CoreApisFromTuple, type CoreConfigResult, type CorePluginInstance, type CreateAppOptions, type CreateCoreOptions, type CreateCoreResult, type EmitFunction as EmitFn, type PluginContext_ as PluginCtx, type PluginInstance, createCoreConfig, createCorePlugin };
|