@moku-labs/core 0.1.0-alpha.2 → 0.1.0-alpha.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/README.md +4 -4
- package/dist/index.cjs +247 -11
- package/dist/index.d.cts +272 -124
- package/dist/index.d.mts +272 -124
- package/dist/index.mjs +246 -11
- package/package.json +1 -1
package/dist/index.d.cts
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> = {}> = {
|
|
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,7 @@ 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> };
|
|
754
896
|
};
|
|
755
897
|
/**
|
|
756
898
|
* Bound createPlugin function type, parameterized by the framework's Config and Events.
|
|
@@ -764,9 +906,9 @@ type CreatePluginSpec<GlobalConfig extends FrameworkConfig, GlobalEventMap exten
|
|
|
764
906
|
* const router = createPlugin("router", { config: { basePath: "/" } });
|
|
765
907
|
* ```
|
|
766
908
|
*/
|
|
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 };
|
|
909
|
+
type BoundCreatePluginFunction<GlobalConfig extends FrameworkConfig, GlobalEventMap extends FrameworkEventMap, CoreApis extends Record<string, unknown> = {}> = {
|
|
910
|
+
<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, CoreApis>, "hooks"> & {
|
|
911
|
+
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 };
|
|
770
912
|
}): PluginInstance<PluginName, PluginConfig, PluginState, PluginApi, PluginEventMap>;
|
|
771
913
|
};
|
|
772
914
|
/**
|
|
@@ -815,7 +957,7 @@ interface CreateCoreOptions<Config> {
|
|
|
815
957
|
* const { createApp, createPlugin } = createCore(coreConfig, { plugins: [...] });
|
|
816
958
|
* ```
|
|
817
959
|
*/
|
|
818
|
-
interface CreateCoreResult<Config extends Record<string, unknown>, Events extends Record<string, unknown>, Plugins extends readonly AnyPluginInstance[] = readonly AnyPluginInstance[]> {
|
|
960
|
+
interface CreateCoreResult<Config extends Record<string, unknown>, Events extends Record<string, unknown>, Plugins extends readonly AnyPluginInstance[] = readonly AnyPluginInstance[], CorePlugins extends readonly AnyCorePluginInstance[] = readonly []> {
|
|
819
961
|
/**
|
|
820
962
|
* Step 3: Creates and initializes the application.
|
|
821
963
|
* Generic over ExtraPlugins to merge consumer plugins into the return type.
|
|
@@ -823,9 +965,9 @@ interface CreateCoreResult<Config extends Record<string, unknown>, Events extend
|
|
|
823
965
|
* @param options - Consumer-level config overrides, plugin configs, extra plugins.
|
|
824
966
|
* @returns The frozen, fully typed App object.
|
|
825
967
|
*/
|
|
826
|
-
readonly createApp: <const ExtraPlugins extends readonly AnyPluginInstance[] = readonly []>(options?: CreateAppOptions<Config, Events, Plugins[number] | ExtraPlugins[number], [...ExtraPlugins]
|
|
968
|
+
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
969
|
/** Re-exported createPlugin for consumer convenience. */
|
|
828
|
-
readonly createPlugin: BoundCreatePluginFunction<Config, Events
|
|
970
|
+
readonly createPlugin: BoundCreatePluginFunction<Config, Events, CoreApisFromTuple<CorePlugins>>;
|
|
829
971
|
}
|
|
830
972
|
/**
|
|
831
973
|
* Bound createCore function type. Generic method captures the Plugins tuple
|
|
@@ -836,11 +978,11 @@ interface CreateCoreResult<Config extends Record<string, unknown>, Events extend
|
|
|
836
978
|
* const framework = createCore(coreConfig, { plugins: [routerPlugin] });
|
|
837
979
|
* ```
|
|
838
980
|
*/
|
|
839
|
-
type BoundCreateCoreFunction<Config extends Record<string, unknown>, Events extends Record<string, unknown
|
|
840
|
-
readonly createPlugin: BoundCreatePluginFunction<Config, Events
|
|
981
|
+
type BoundCreateCoreFunction<Config extends Record<string, unknown>, Events extends Record<string, unknown>, CorePlugins extends readonly AnyCorePluginInstance[] = readonly []> = <const Plugins extends readonly AnyPluginInstance[]>(coreConfig: {
|
|
982
|
+
readonly createPlugin: BoundCreatePluginFunction<Config, Events, CoreApisFromTuple<CorePlugins>>;
|
|
841
983
|
}, options: CreateCoreOptions<Config> & {
|
|
842
984
|
readonly plugins: [...Plugins];
|
|
843
|
-
}) => CreateCoreResult<Config, Events, Plugins>;
|
|
985
|
+
}) => CreateCoreResult<Config, Events, Plugins, CorePlugins>;
|
|
844
986
|
/**
|
|
845
987
|
* Creates a bound `createCore` function that captures framework context.
|
|
846
988
|
*
|
|
@@ -851,6 +993,8 @@ type BoundCreateCoreFunction<Config extends Record<string, unknown>, Events exte
|
|
|
851
993
|
* @param frameworkId - The framework identifier for error messages.
|
|
852
994
|
* @param configDefaults - Default config values captured from Step 1.
|
|
853
995
|
* @param createPlugin - Bound createPlugin function from Step 1.
|
|
996
|
+
* @param corePlugins - Core plugin instances from createCoreConfig.
|
|
997
|
+
* @param corePluginConfigs - Core plugin config overrides from createCoreConfig.
|
|
854
998
|
* @returns A createCore function bound to the framework's Config and Events types.
|
|
855
999
|
* @example
|
|
856
1000
|
* ```ts
|
|
@@ -869,11 +1013,11 @@ type BoundCreateCoreFunction<Config extends Record<string, unknown>, Events exte
|
|
|
869
1013
|
* const result: CoreConfigResult<SiteConfig, SiteEvents> = createCoreConfig("app", { config: defaults });
|
|
870
1014
|
* ```
|
|
871
1015
|
*/
|
|
872
|
-
interface CoreConfigResult<Config extends Record<string, unknown>, Events extends Record<string, unknown
|
|
1016
|
+
interface CoreConfigResult<Config extends Record<string, unknown>, Events extends Record<string, unknown>, CorePlugins extends readonly AnyCorePluginInstance[] = readonly []> {
|
|
873
1017
|
/** Creates a plugin instance with all types inferred from the spec object. */
|
|
874
|
-
readonly createPlugin: BoundCreatePluginFunction<Config, Events
|
|
1018
|
+
readonly createPlugin: BoundCreatePluginFunction<Config, Events, CoreApisFromTuple<CorePlugins>>;
|
|
875
1019
|
/** Step 2 factory: captures default plugins and returns createApp + createPlugin. */
|
|
876
|
-
readonly createCore: BoundCreateCoreFunction<Config, Events>;
|
|
1020
|
+
readonly createCore: BoundCreateCoreFunction<Config, Events, CorePlugins>;
|
|
877
1021
|
}
|
|
878
1022
|
/**
|
|
879
1023
|
* Step 1 of the 3-step factory chain. Captures Config and Events generics
|
|
@@ -885,6 +1029,8 @@ interface CoreConfigResult<Config extends Record<string, unknown>, Events extend
|
|
|
885
1029
|
* @param id - Framework identifier used in error messages.
|
|
886
1030
|
* @param options - Configuration options containing the default config values.
|
|
887
1031
|
* @param options.config - Default configuration values for the framework.
|
|
1032
|
+
* @param options.plugins - Optional core plugin instances to register.
|
|
1033
|
+
* @param options.pluginConfigs - Optional config overrides for core plugins.
|
|
888
1034
|
* @returns An object with createPlugin (bound to Config/Events) and createCore.
|
|
889
1035
|
* @example
|
|
890
1036
|
* ```ts
|
|
@@ -894,8 +1040,10 @@ interface CoreConfigResult<Config extends Record<string, unknown>, Events extend
|
|
|
894
1040
|
* const { createPlugin, createCore } = coreConfig;
|
|
895
1041
|
* ```
|
|
896
1042
|
*/
|
|
897
|
-
declare function createCoreConfig<Config extends Record<string, unknown>, Events extends Record<string, unknown> = Record<string, never
|
|
1043
|
+
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
1044
|
config: Config;
|
|
899
|
-
|
|
1045
|
+
plugins?: [...CorePlugins];
|
|
1046
|
+
pluginConfigs?: { [K in CorePlugins[number] as ExtractCoreConfig<K> extends Record<string, never> ? never : IsLiteralString<ExtractCoreName<K>> extends true ? ExtractCoreName<K> : never]?: Partial<ExtractCoreConfig<K>> };
|
|
1047
|
+
}): CoreConfigResult<Config, Events, CorePlugins>;
|
|
900
1048
|
//#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 };
|
|
1049
|
+
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 };
|