@smthrs/plugin 0.0.0-stage → 1.0.0-rc.3
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/CHANGELOG.md +79 -0
- package/LICENSE +21 -0
- package/README.md +86 -2
- package/dist/cjs/Config.d.ts +129 -0
- package/dist/cjs/Config.d.ts.map +1 -0
- package/dist/cjs/Config.js +115 -0
- package/dist/cjs/Config.js.map +7 -0
- package/dist/cjs/Hooks.d.ts +176 -0
- package/dist/cjs/Hooks.d.ts.map +1 -0
- package/dist/cjs/Hooks.js +34 -0
- package/dist/cjs/Hooks.js.map +7 -0
- package/dist/cjs/Kernel.d.ts +81 -0
- package/dist/cjs/Kernel.d.ts.map +1 -0
- package/dist/cjs/Kernel.js +57 -0
- package/dist/cjs/Kernel.js.map +7 -0
- package/dist/cjs/Plugin.d.ts +71 -0
- package/dist/cjs/Plugin.d.ts.map +1 -0
- package/dist/cjs/Plugin.js +25 -0
- package/dist/cjs/Plugin.js.map +7 -0
- package/dist/cjs/PluginError.d.ts +50 -0
- package/dist/cjs/PluginError.d.ts.map +1 -0
- package/dist/cjs/PluginError.js +58 -0
- package/dist/cjs/PluginError.js.map +7 -0
- package/dist/cjs/Plugins.d.ts +97 -0
- package/dist/cjs/Plugins.d.ts.map +1 -0
- package/dist/cjs/Plugins.js +160 -0
- package/dist/cjs/Plugins.js.map +7 -0
- package/dist/cjs/Resolve.d.ts +128 -0
- package/dist/cjs/Resolve.d.ts.map +1 -0
- package/dist/cjs/Resolve.js +343 -0
- package/dist/cjs/Resolve.js.map +7 -0
- package/dist/cjs/index.d.ts +83 -0
- package/dist/cjs/index.d.ts.map +1 -0
- package/dist/cjs/index.js +45 -0
- package/dist/cjs/index.js.map +7 -0
- package/dist/cjs/internal/Boundary.d.ts +96 -0
- package/dist/cjs/internal/Boundary.d.ts.map +1 -0
- package/dist/cjs/internal/Boundary.js +129 -0
- package/dist/cjs/internal/Boundary.js.map +7 -0
- package/dist/cjs/internal/mergePluginLayers.d.ts +21 -0
- package/dist/cjs/internal/mergePluginLayers.d.ts.map +1 -0
- package/dist/cjs/internal/mergePluginLayers.js +57 -0
- package/dist/cjs/internal/mergePluginLayers.js.map +7 -0
- package/dist/cjs/internal/snapshotCacheEnvironment.d.ts +19 -0
- package/dist/cjs/internal/snapshotCacheEnvironment.d.ts.map +1 -0
- package/dist/cjs/internal/snapshotCacheEnvironment.js +92 -0
- package/dist/cjs/internal/snapshotCacheEnvironment.js.map +7 -0
- package/dist/cjs/package.json +1 -0
- package/dist/esm/Config.d.ts +129 -0
- package/dist/esm/Config.d.ts.map +1 -0
- package/dist/esm/Config.js +160 -0
- package/dist/esm/Config.js.map +1 -0
- package/dist/esm/Hooks.d.ts +176 -0
- package/dist/esm/Hooks.d.ts.map +1 -0
- package/dist/esm/Hooks.js +56 -0
- package/dist/esm/Hooks.js.map +1 -0
- package/dist/esm/Kernel.d.ts +81 -0
- package/dist/esm/Kernel.d.ts.map +1 -0
- package/dist/esm/Kernel.js +58 -0
- package/dist/esm/Kernel.js.map +1 -0
- package/dist/esm/Plugin.d.ts +71 -0
- package/dist/esm/Plugin.d.ts.map +1 -0
- package/dist/esm/Plugin.js +20 -0
- package/dist/esm/Plugin.js.map +1 -0
- package/dist/esm/PluginError.d.ts +50 -0
- package/dist/esm/PluginError.d.ts.map +1 -0
- package/dist/esm/PluginError.js +53 -0
- package/dist/esm/PluginError.js.map +1 -0
- package/dist/esm/Plugins.d.ts +97 -0
- package/dist/esm/Plugins.d.ts.map +1 -0
- package/dist/esm/Plugins.js +178 -0
- package/dist/esm/Plugins.js.map +1 -0
- package/dist/esm/Resolve.d.ts +128 -0
- package/dist/esm/Resolve.d.ts.map +1 -0
- package/dist/esm/Resolve.js +367 -0
- package/dist/esm/Resolve.js.map +1 -0
- package/dist/esm/index.d.ts +83 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +48 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/internal/Boundary.d.ts +96 -0
- package/dist/esm/internal/Boundary.d.ts.map +1 -0
- package/dist/esm/internal/Boundary.js +162 -0
- package/dist/esm/internal/Boundary.js.map +1 -0
- package/dist/esm/internal/mergePluginLayers.d.ts +21 -0
- package/dist/esm/internal/mergePluginLayers.d.ts.map +1 -0
- package/dist/esm/internal/mergePluginLayers.js +41 -0
- package/dist/esm/internal/mergePluginLayers.js.map +1 -0
- package/dist/esm/internal/snapshotCacheEnvironment.d.ts +19 -0
- package/dist/esm/internal/snapshotCacheEnvironment.d.ts.map +1 -0
- package/dist/esm/internal/snapshotCacheEnvironment.js +63 -0
- package/dist/esm/internal/snapshotCacheEnvironment.js.map +1 -0
- package/docs/README.md +131 -0
- package/docs/api.md +522 -0
- package/docs/concepts/configuration.md +111 -0
- package/docs/concepts/hook-kinds.md +107 -0
- package/docs/concepts/resolution.md +132 -0
- package/docs/guides/cache-identity.md +106 -0
- package/docs/guides/contribute-services.md +84 -0
- package/docs/guides/host-your-own-hooks.md +129 -0
- package/docs/guides/order-handlers.md +76 -0
- package/docs/guides/select-plugins.md +72 -0
- package/docs/guides/testing.md +149 -0
- package/docs/installation.md +71 -0
- package/docs/quickstart.md +151 -0
- package/docs/troubleshooting.md +179 -0
- package/package.json +179 -3
- package/src/Config.ts +207 -0
- package/src/Hooks.ts +212 -0
- package/src/Kernel.ts +119 -0
- package/src/Plugin.ts +80 -0
- package/src/PluginError.ts +62 -0
- package/src/Plugins.ts +254 -0
- package/src/Resolve.ts +535 -0
- package/src/index.ts +91 -0
- package/src/internal/Boundary.ts +252 -0
- package/src/internal/mergePluginLayers.ts +57 -0
- package/src/internal/snapshotCacheEnvironment.ts +77 -0
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
var snapshotCacheEnvironment_exports = {};
|
|
30
|
+
__export(snapshotCacheEnvironment_exports, {
|
|
31
|
+
snapshotCacheEnvironment: () => snapshotCacheEnvironment
|
|
32
|
+
});
|
|
33
|
+
module.exports = __toCommonJS(snapshotCacheEnvironment_exports);
|
|
34
|
+
var import_flow = require("@smthrs/flow");
|
|
35
|
+
var Effect = __toESM(require("effect/Effect"), 1);
|
|
36
|
+
var Schema = __toESM(require("effect/Schema"), 1);
|
|
37
|
+
var import_PluginError = require("../PluginError.js");
|
|
38
|
+
var Boundary = __toESM(require("./Boundary.js"), 1);
|
|
39
|
+
const escapePluginIdentityPart = (value) => (
|
|
40
|
+
// Percent must be escaped first so literal escape-looking text remains distinct from the `@` escape added next.
|
|
41
|
+
value.replaceAll("%", "%25").replaceAll("@", "%40")
|
|
42
|
+
);
|
|
43
|
+
const snapshotCacheEnvironment = (input, plugins) => {
|
|
44
|
+
if (input === void 0) return Effect.succeed(void 0);
|
|
45
|
+
const pluginIdentities = [];
|
|
46
|
+
for (const plugin of plugins) {
|
|
47
|
+
if (plugin.version === void 0) {
|
|
48
|
+
return Effect.fail(
|
|
49
|
+
new import_PluginError.PluginError({
|
|
50
|
+
code: "cache_environment_invalid",
|
|
51
|
+
message: `cache environment requires a version for plugin "${plugin.name}"`,
|
|
52
|
+
path: "$.version",
|
|
53
|
+
plugin: plugin.name
|
|
54
|
+
})
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
pluginIdentities.push(`${escapePluginIdentityPart(plugin.name)}@${escapePluginIdentityPart(plugin.version)}`);
|
|
58
|
+
}
|
|
59
|
+
const admitted = Boundary.record(input);
|
|
60
|
+
if (!admitted.ok) {
|
|
61
|
+
return Effect.fail(
|
|
62
|
+
new import_PluginError.PluginError({
|
|
63
|
+
code: "cache_environment_invalid",
|
|
64
|
+
message: `cache environment ${admitted.complaint}`,
|
|
65
|
+
path: `$options.cacheEnvironment${admitted.path.slice(1)}`
|
|
66
|
+
})
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
return Schema.decodeUnknownEffect(import_flow.Action.CacheEnvironment)(admitted.value).pipe(
|
|
70
|
+
Effect.mapError(
|
|
71
|
+
() => new import_PluginError.PluginError({
|
|
72
|
+
code: "cache_environment_invalid",
|
|
73
|
+
message: "cache environment does not match the complete cache identity schema",
|
|
74
|
+
path: "$options.cacheEnvironment"
|
|
75
|
+
})
|
|
76
|
+
),
|
|
77
|
+
Effect.map((environment) => {
|
|
78
|
+
const capabilities = {};
|
|
79
|
+
for (const name of Object.keys(environment.capabilities)) {
|
|
80
|
+
Object.defineProperty(capabilities, name, {
|
|
81
|
+
value: Object.freeze([...environment.capabilities[name]]),
|
|
82
|
+
enumerable: true
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
return Object.freeze({
|
|
86
|
+
layers: Object.freeze([...pluginIdentities, ...environment.layers]),
|
|
87
|
+
capabilities: Object.freeze(capabilities)
|
|
88
|
+
});
|
|
89
|
+
})
|
|
90
|
+
);
|
|
91
|
+
};
|
|
92
|
+
//# sourceMappingURL=snapshotCacheEnvironment.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/internal/snapshotCacheEnvironment.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Cache identity admission for a resolved plugin list.\n *\n * @private\n * @since 1.0.0-rc.0\n */\n\nimport { Action } from \"@smthrs/flow\"\nimport * as Effect from \"effect/Effect\"\nimport * as Schema from \"effect/Schema\"\nimport type { FlowsPlugin } from \"../Plugin.ts\"\nimport { PluginError } from \"../PluginError.ts\"\nimport * as Boundary from \"./Boundary.ts\"\n\nconst escapePluginIdentityPart = (value: string): string =>\n // Percent must be escaped first so literal escape-looking text remains distinct from the `@` escape added next.\n value.replaceAll(\"%\", \"%25\").replaceAll(\"@\", \"%40\")\n\n/**\n * Admits a caller cache environment and prepends one escaped `name@version`\n * identity per plugin, in resolved order. An absent input stays absent.\n *\n * @private\n * @since 1.0.0-rc.0\n */\nexport const snapshotCacheEnvironment = <H>(\n input: unknown,\n plugins: ReadonlyArray<FlowsPlugin<H>>\n): Effect.Effect<Action.CacheEnvironment | undefined, PluginError> => {\n if (input === undefined) return Effect.succeed(undefined)\n const pluginIdentities: Array<string> = []\n for (const plugin of plugins) {\n if (plugin.version === undefined) {\n return Effect.fail(\n new PluginError({\n code: \"cache_environment_invalid\",\n message: `cache environment requires a version for plugin \"${plugin.name}\"`,\n path: \"$.version\",\n plugin: plugin.name\n })\n )\n }\n pluginIdentities.push(`${escapePluginIdentityPart(plugin.name)}@${escapePluginIdentityPart(plugin.version)}`)\n }\n const admitted = Boundary.record(input)\n if (!admitted.ok) {\n return Effect.fail(\n new PluginError({\n code: \"cache_environment_invalid\",\n message: `cache environment ${admitted.complaint}`,\n path: `$options.cacheEnvironment${admitted.path.slice(1)}`\n })\n )\n }\n return Schema.decodeUnknownEffect(Action.CacheEnvironment)(admitted.value).pipe(\n Effect.mapError(() =>\n new PluginError({\n code: \"cache_environment_invalid\",\n message: \"cache environment does not match the complete cache identity schema\",\n path: \"$options.cacheEnvironment\"\n })\n ),\n Effect.map((environment) => {\n const capabilities: Record<string, ReadonlyArray<string>> = {}\n for (const name of Object.keys(environment.capabilities)) {\n Object.defineProperty(capabilities, name, {\n value: Object.freeze([...environment.capabilities[name]!]),\n enumerable: true\n })\n }\n return Object.freeze({\n layers: Object.freeze([...pluginIdentities, ...environment.layers]),\n capabilities: Object.freeze(capabilities)\n })\n })\n )\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAOA,kBAAuB;AACvB,aAAwB;AACxB,aAAwB;AAExB,yBAA4B;AAC5B,eAA0B;AAE1B,MAAM,2BAA2B,CAAC;AAAA;AAAA,EAEhC,MAAM,WAAW,KAAK,KAAK,EAAE,WAAW,KAAK,KAAK;AAAA;AAS7C,MAAM,2BAA2B,CACtC,OACA,YACoE;AACpE,MAAI,UAAU,OAAW,QAAO,OAAO,QAAQ,MAAS;AACxD,QAAM,mBAAkC,CAAC;AACzC,aAAW,UAAU,SAAS;AAC5B,QAAI,OAAO,YAAY,QAAW;AAChC,aAAO,OAAO;AAAA,QACZ,IAAI,+BAAY;AAAA,UACd,MAAM;AAAA,UACN,SAAS,oDAAoD,OAAO,IAAI;AAAA,UACxE,MAAM;AAAA,UACN,QAAQ,OAAO;AAAA,QACjB,CAAC;AAAA,MACH;AAAA,IACF;AACA,qBAAiB,KAAK,GAAG,yBAAyB,OAAO,IAAI,CAAC,IAAI,yBAAyB,OAAO,OAAO,CAAC,EAAE;AAAA,EAC9G;AACA,QAAM,WAAW,SAAS,OAAO,KAAK;AACtC,MAAI,CAAC,SAAS,IAAI;AAChB,WAAO,OAAO;AAAA,MACZ,IAAI,+BAAY;AAAA,QACd,MAAM;AAAA,QACN,SAAS,qBAAqB,SAAS,SAAS;AAAA,QAChD,MAAM,4BAA4B,SAAS,KAAK,MAAM,CAAC,CAAC;AAAA,MAC1D,CAAC;AAAA,IACH;AAAA,EACF;AACA,SAAO,OAAO,oBAAoB,mBAAO,gBAAgB,EAAE,SAAS,KAAK,EAAE;AAAA,IACzE,OAAO;AAAA,MAAS,MACd,IAAI,+BAAY;AAAA,QACd,MAAM;AAAA,QACN,SAAS;AAAA,QACT,MAAM;AAAA,MACR,CAAC;AAAA,IACH;AAAA,IACA,OAAO,IAAI,CAAC,gBAAgB;AAC1B,YAAM,eAAsD,CAAC;AAC7D,iBAAW,QAAQ,OAAO,KAAK,YAAY,YAAY,GAAG;AACxD,eAAO,eAAe,cAAc,MAAM;AAAA,UACxC,OAAO,OAAO,OAAO,CAAC,GAAG,YAAY,aAAa,IAAI,CAAE,CAAC;AAAA,UACzD,YAAY;AAAA,QACd,CAAC;AAAA,MACH;AACA,aAAO,OAAO,OAAO;AAAA,QACnB,QAAQ,OAAO,OAAO,CAAC,GAAG,kBAAkB,GAAG,YAAY,MAAM,CAAC;AAAA,QAClE,cAAc,OAAO,OAAO,YAAY;AAAA,MAC1C,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"type":"commonjs"}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bounded JSON configuration consumed and produced by the plugin kernel.
|
|
3
|
+
*
|
|
4
|
+
* Configuration is an extension namespace, not an engine-policy surface.
|
|
5
|
+
* Durable retry, concurrency, and storage policy stay on their owning Effect
|
|
6
|
+
* services and constructor options. Every accepted value is copied before any
|
|
7
|
+
* plugin observes it, then frozen recursively.
|
|
8
|
+
*
|
|
9
|
+
* @since 1.0.0-rc.0
|
|
10
|
+
*/
|
|
11
|
+
import * as Effect from "effect/Effect";
|
|
12
|
+
import * as Schema from "effect/Schema";
|
|
13
|
+
import { PluginError } from "./PluginError.ts";
|
|
14
|
+
/**
|
|
15
|
+
* Maximum encoded bytes accepted for one plugin configuration.
|
|
16
|
+
*
|
|
17
|
+
* @category limits
|
|
18
|
+
* @since 1.0.0-rc.0
|
|
19
|
+
*/
|
|
20
|
+
export declare const maximumConfigBytes: number;
|
|
21
|
+
/**
|
|
22
|
+
* Maximum nesting accepted for one plugin configuration.
|
|
23
|
+
*
|
|
24
|
+
* @category limits
|
|
25
|
+
* @since 1.0.0-rc.0
|
|
26
|
+
*/
|
|
27
|
+
export declare const maximumConfigDepth: number;
|
|
28
|
+
/**
|
|
29
|
+
* Maximum aggregate members accepted for one plugin configuration.
|
|
30
|
+
*
|
|
31
|
+
* @category limits
|
|
32
|
+
* @since 1.0.0-rc.0
|
|
33
|
+
*/
|
|
34
|
+
export declare const maximumConfigMembers: number;
|
|
35
|
+
/**
|
|
36
|
+
* Maximum aggregate values accepted for one plugin configuration.
|
|
37
|
+
*
|
|
38
|
+
* @category limits
|
|
39
|
+
* @since 1.0.0-rc.0
|
|
40
|
+
*/
|
|
41
|
+
export declare const maximumConfigNodes: number;
|
|
42
|
+
/**
|
|
43
|
+
* One value accepted in a plugin-owned configuration namespace.
|
|
44
|
+
*
|
|
45
|
+
* @category models
|
|
46
|
+
* @since 1.0.0-rc.0
|
|
47
|
+
*/
|
|
48
|
+
export declare const ConfigValue: Schema.Codec<Schema.Json, Schema.Json, never, never>;
|
|
49
|
+
/**
|
|
50
|
+
* One value accepted in a plugin-owned configuration namespace.
|
|
51
|
+
*
|
|
52
|
+
* @category models
|
|
53
|
+
* @since 1.0.0-rc.0
|
|
54
|
+
*/
|
|
55
|
+
export type ConfigValue = typeof ConfigValue.Type;
|
|
56
|
+
/**
|
|
57
|
+
* Admits pre-resolution configuration as a detached, recursively frozen snapshot.
|
|
58
|
+
*
|
|
59
|
+
* Keys name plugin-owned namespaces. `engine`, `retry`, `store`, and
|
|
60
|
+
* `plugins` are refused because accepting those names would imply policy the
|
|
61
|
+
* plugin kernel does not own or apply.
|
|
62
|
+
*
|
|
63
|
+
* @category models
|
|
64
|
+
* @since 1.0.0-rc.0
|
|
65
|
+
*/
|
|
66
|
+
export declare const FlowsConfig: Schema.decodeTo<Schema.declare<Readonly<Record<string, Schema.Json>>, Readonly<Record<string, Schema.Json>>>, Schema.Unknown, never, never>;
|
|
67
|
+
/**
|
|
68
|
+
* The decoded form of {@link FlowsConfig}.
|
|
69
|
+
*
|
|
70
|
+
* @category models
|
|
71
|
+
* @since 1.0.0-rc.0
|
|
72
|
+
*/
|
|
73
|
+
export type FlowsConfig = typeof FlowsConfig.Type;
|
|
74
|
+
/**
|
|
75
|
+
* Admits the detached, recursively frozen configuration handed to plugins.
|
|
76
|
+
*
|
|
77
|
+
* @category models
|
|
78
|
+
* @since 1.0.0-rc.0
|
|
79
|
+
*/
|
|
80
|
+
export declare const ResolvedConfig: Schema.decodeTo<Schema.declare<Readonly<Record<string, Schema.Json>>, Readonly<Record<string, Schema.Json>>>, Schema.Unknown, never, never>;
|
|
81
|
+
/**
|
|
82
|
+
* The decoded form of {@link ResolvedConfig}.
|
|
83
|
+
*
|
|
84
|
+
* @category models
|
|
85
|
+
* @since 1.0.0-rc.0
|
|
86
|
+
*/
|
|
87
|
+
export type ResolvedConfig = typeof ResolvedConfig.Type;
|
|
88
|
+
/**
|
|
89
|
+
* Empty defaults. Engine policy is deliberately not defaulted here.
|
|
90
|
+
*
|
|
91
|
+
* @category constructors
|
|
92
|
+
* @since 1.0.0-rc.0
|
|
93
|
+
*/
|
|
94
|
+
export declare const defaults: ResolvedConfig;
|
|
95
|
+
/**
|
|
96
|
+
* Copies and deep-merges a configuration patch over a base configuration.
|
|
97
|
+
*
|
|
98
|
+
* Records merge key-by-key and every other JSON value replaces wholesale.
|
|
99
|
+
* Raw operands are admitted; known snapshots retain unchanged subtrees.
|
|
100
|
+
* Cached subtree totals enforce merged output bounds. Unsafe property names,
|
|
101
|
+
* accessors, cycles, exotic prototypes, and aggregate values outside the
|
|
102
|
+
* resource limits fail with `config_invalid`.
|
|
103
|
+
*
|
|
104
|
+
* @category combinators
|
|
105
|
+
* @since 1.0.0-rc.0
|
|
106
|
+
*/
|
|
107
|
+
export declare const merge: (base: FlowsConfig, patch: unknown) => FlowsConfig;
|
|
108
|
+
/**
|
|
109
|
+
* Copies and freezes one JSON value without retaining caller-owned objects.
|
|
110
|
+
*
|
|
111
|
+
* @category utils
|
|
112
|
+
* @since 1.0.0-rc.0
|
|
113
|
+
*/
|
|
114
|
+
export declare const deepFreeze: <A extends ConfigValue>(value: A) => A;
|
|
115
|
+
/**
|
|
116
|
+
* Admits a raw pre-resolution configuration as an immutable snapshot.
|
|
117
|
+
*
|
|
118
|
+
* @category constructors
|
|
119
|
+
* @since 1.0.0-rc.0
|
|
120
|
+
*/
|
|
121
|
+
export declare const snapshot: (config: unknown) => Effect.Effect<FlowsConfig, PluginError>;
|
|
122
|
+
/**
|
|
123
|
+
* Decodes the post-waterfall configuration into its final immutable form.
|
|
124
|
+
*
|
|
125
|
+
* @category constructors
|
|
126
|
+
* @since 1.0.0-rc.0
|
|
127
|
+
*/
|
|
128
|
+
export declare const resolve: (config: unknown) => Effect.Effect<ResolvedConfig, PluginError>;
|
|
129
|
+
//# sourceMappingURL=Config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Config.d.ts","sourceRoot":"","sources":["../../src/Config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AAIvC,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAE9C;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,QAAkC,CAAA;AAEjE;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,QAAkC,CAAA;AAEjE;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,QAAoC,CAAA;AAErE;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,QAAkC,CAAA;AAEjE;;;;;GAKG;AACH,eAAO,MAAM,WAAW,sDAAc,CAAA;AAEtC;;;;;GAKG;AACH,MAAM,MAAM,WAAW,GAAG,OAAO,WAAW,CAAC,IAAI,CAAA;AAwBjD;;;;;;;;;GASG;AACH,eAAO,MAAM,WAAW,6IAAsB,CAAA;AAE9C;;;;;GAKG;AACH,MAAM,MAAM,WAAW,GAAG,OAAO,WAAW,CAAC,IAAI,CAAA;AAEjD;;;;;GAKG;AACH,eAAO,MAAM,cAAc,6IAAsB,CAAA;AAEjD;;;;;GAKG;AACH,MAAM,MAAM,cAAc,GAAG,OAAO,cAAc,CAAC,IAAI,CAAA;AAyBvD;;;;;GAKG;AACH,eAAO,MAAM,QAAQ,EAAE,cAAmC,CAAA;AAE1D;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,KAAK,GAAI,MAAM,WAAW,EAAE,OAAO,OAAO,KAAG,WAUzD,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,UAAU,GAAI,CAAC,SAAS,WAAW,EAAE,OAAO,CAAC,KAAG,CAI5D,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,QAAQ,GAAI,QAAQ,OAAO,KAAG,MAAM,CAAC,MAAM,CAAC,WAAW,EAAE,WAAW,CACU,CAAA;AAE3F;;;;;GAKG;AACH,eAAO,MAAM,OAAO,GAAI,QAAQ,OAAO,KAAG,MAAM,CAAC,MAAM,CAAC,cAAc,EAAE,WAAW,CAAqB,CAAA"}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bounded JSON configuration consumed and produced by the plugin kernel.
|
|
3
|
+
*
|
|
4
|
+
* Configuration is an extension namespace, not an engine-policy surface.
|
|
5
|
+
* Durable retry, concurrency, and storage policy stay on their owning Effect
|
|
6
|
+
* services and constructor options. Every accepted value is copied before any
|
|
7
|
+
* plugin observes it, then frozen recursively.
|
|
8
|
+
*
|
|
9
|
+
* @since 1.0.0-rc.0
|
|
10
|
+
*/
|
|
11
|
+
import * as Effect from "effect/Effect";
|
|
12
|
+
import * as Schema from "effect/Schema";
|
|
13
|
+
import * as SchemaGetter from "effect/SchemaGetter";
|
|
14
|
+
import * as SchemaIssue from "effect/SchemaIssue";
|
|
15
|
+
import * as Boundary from "./internal/Boundary.js";
|
|
16
|
+
import { PluginError } from "./PluginError.js";
|
|
17
|
+
/**
|
|
18
|
+
* Maximum encoded bytes accepted for one plugin configuration.
|
|
19
|
+
*
|
|
20
|
+
* @category limits
|
|
21
|
+
* @since 1.0.0-rc.0
|
|
22
|
+
*/
|
|
23
|
+
export const maximumConfigBytes = Boundary.defaultLimits.maxBytes;
|
|
24
|
+
/**
|
|
25
|
+
* Maximum nesting accepted for one plugin configuration.
|
|
26
|
+
*
|
|
27
|
+
* @category limits
|
|
28
|
+
* @since 1.0.0-rc.0
|
|
29
|
+
*/
|
|
30
|
+
export const maximumConfigDepth = Boundary.defaultLimits.maxDepth;
|
|
31
|
+
/**
|
|
32
|
+
* Maximum aggregate members accepted for one plugin configuration.
|
|
33
|
+
*
|
|
34
|
+
* @category limits
|
|
35
|
+
* @since 1.0.0-rc.0
|
|
36
|
+
*/
|
|
37
|
+
export const maximumConfigMembers = Boundary.defaultLimits.maxMembers;
|
|
38
|
+
/**
|
|
39
|
+
* Maximum aggregate values accepted for one plugin configuration.
|
|
40
|
+
*
|
|
41
|
+
* @category limits
|
|
42
|
+
* @since 1.0.0-rc.0
|
|
43
|
+
*/
|
|
44
|
+
export const maximumConfigNodes = Boundary.defaultLimits.maxNodes;
|
|
45
|
+
/**
|
|
46
|
+
* One value accepted in a plugin-owned configuration namespace.
|
|
47
|
+
*
|
|
48
|
+
* @category models
|
|
49
|
+
* @since 1.0.0-rc.0
|
|
50
|
+
*/
|
|
51
|
+
export const ConfigValue = Schema.Json;
|
|
52
|
+
const admittedConfigs = new WeakSet();
|
|
53
|
+
const configurationSchema = Schema.Unknown.pipe(Schema.decodeTo(Schema.declare((value) => typeof value === "object" && value !== null && admittedConfigs.has(value)), {
|
|
54
|
+
decode: SchemaGetter.transformEffect((value) => Effect.try({
|
|
55
|
+
try: () => snapshotRecord(value),
|
|
56
|
+
catch: (cause) => {
|
|
57
|
+
const error = cause;
|
|
58
|
+
return new SchemaIssue.InvalidValue({ message: `${error.path}: ${error.message}` });
|
|
59
|
+
}
|
|
60
|
+
})),
|
|
61
|
+
encode: SchemaGetter.transform((value) => value)
|
|
62
|
+
}));
|
|
63
|
+
/**
|
|
64
|
+
* Admits pre-resolution configuration as a detached, recursively frozen snapshot.
|
|
65
|
+
*
|
|
66
|
+
* Keys name plugin-owned namespaces. `engine`, `retry`, `store`, and
|
|
67
|
+
* `plugins` are refused because accepting those names would imply policy the
|
|
68
|
+
* plugin kernel does not own or apply.
|
|
69
|
+
*
|
|
70
|
+
* @category models
|
|
71
|
+
* @since 1.0.0-rc.0
|
|
72
|
+
*/
|
|
73
|
+
export const FlowsConfig = configurationSchema;
|
|
74
|
+
/**
|
|
75
|
+
* Admits the detached, recursively frozen configuration handed to plugins.
|
|
76
|
+
*
|
|
77
|
+
* @category models
|
|
78
|
+
* @since 1.0.0-rc.0
|
|
79
|
+
*/
|
|
80
|
+
export const ResolvedConfig = configurationSchema;
|
|
81
|
+
const reservedRootKeys = new Set(["engine", "retry", "store", "plugins"]);
|
|
82
|
+
const invalid = (path, complaint) => new PluginError({
|
|
83
|
+
code: "config_invalid",
|
|
84
|
+
message: `plugin configuration ${complaint}`,
|
|
85
|
+
path
|
|
86
|
+
});
|
|
87
|
+
const snapshotRecord = (input, reuse = true) => {
|
|
88
|
+
if (reuse && typeof input === "object" && input !== null && admittedConfigs.has(input))
|
|
89
|
+
return input;
|
|
90
|
+
const admitted = Boundary.record(input);
|
|
91
|
+
if (!admitted.ok)
|
|
92
|
+
throw invalid(admitted.path, admitted.complaint);
|
|
93
|
+
const record = admitted.value;
|
|
94
|
+
for (const key of Object.keys(record)) {
|
|
95
|
+
if (reservedRootKeys.has(key)) {
|
|
96
|
+
throw invalid(`$.${key}`, "uses a runtime-policy key that the plugin kernel does not own");
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
admittedConfigs.add(record);
|
|
100
|
+
return record;
|
|
101
|
+
};
|
|
102
|
+
/**
|
|
103
|
+
* Empty defaults. Engine policy is deliberately not defaulted here.
|
|
104
|
+
*
|
|
105
|
+
* @category constructors
|
|
106
|
+
* @since 1.0.0-rc.0
|
|
107
|
+
*/
|
|
108
|
+
export const defaults = snapshotRecord({});
|
|
109
|
+
/**
|
|
110
|
+
* Copies and deep-merges a configuration patch over a base configuration.
|
|
111
|
+
*
|
|
112
|
+
* Records merge key-by-key and every other JSON value replaces wholesale.
|
|
113
|
+
* Raw operands are admitted; known snapshots retain unchanged subtrees.
|
|
114
|
+
* Cached subtree totals enforce merged output bounds. Unsafe property names,
|
|
115
|
+
* accessors, cycles, exotic prototypes, and aggregate values outside the
|
|
116
|
+
* resource limits fail with `config_invalid`.
|
|
117
|
+
*
|
|
118
|
+
* @category combinators
|
|
119
|
+
* @since 1.0.0-rc.0
|
|
120
|
+
*/
|
|
121
|
+
export const merge = (base, patch) => {
|
|
122
|
+
const safeBase = snapshotRecord(base);
|
|
123
|
+
if (patch === undefined)
|
|
124
|
+
return safeBase;
|
|
125
|
+
// Even a known patch is copied so its tree cannot alias the retained base.
|
|
126
|
+
const safePatch = snapshotRecord(patch, false);
|
|
127
|
+
const merged = Boundary.mergeRecords(safeBase, safePatch);
|
|
128
|
+
if (!merged.ok)
|
|
129
|
+
throw invalid(merged.path, merged.complaint);
|
|
130
|
+
const record = merged.value;
|
|
131
|
+
admittedConfigs.add(record);
|
|
132
|
+
return record;
|
|
133
|
+
};
|
|
134
|
+
/**
|
|
135
|
+
* Copies and freezes one JSON value without retaining caller-owned objects.
|
|
136
|
+
*
|
|
137
|
+
* @category utils
|
|
138
|
+
* @since 1.0.0-rc.0
|
|
139
|
+
*/
|
|
140
|
+
export const deepFreeze = (value) => {
|
|
141
|
+
const admitted = Boundary.admit(value);
|
|
142
|
+
if (!admitted.ok)
|
|
143
|
+
throw invalid(admitted.path, admitted.complaint);
|
|
144
|
+
return admitted.value;
|
|
145
|
+
};
|
|
146
|
+
/**
|
|
147
|
+
* Admits a raw pre-resolution configuration as an immutable snapshot.
|
|
148
|
+
*
|
|
149
|
+
* @category constructors
|
|
150
|
+
* @since 1.0.0-rc.0
|
|
151
|
+
*/
|
|
152
|
+
export const snapshot = (config) => Effect.try({ try: () => snapshotRecord(config), catch: (cause) => cause });
|
|
153
|
+
/**
|
|
154
|
+
* Decodes the post-waterfall configuration into its final immutable form.
|
|
155
|
+
*
|
|
156
|
+
* @category constructors
|
|
157
|
+
* @since 1.0.0-rc.0
|
|
158
|
+
*/
|
|
159
|
+
export const resolve = (config) => snapshot(config);
|
|
160
|
+
//# sourceMappingURL=Config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Config.js","sourceRoot":"","sources":["../../src/Config.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Bounded JSON configuration consumed and produced by the plugin kernel.\n *\n * Configuration is an extension namespace, not an engine-policy surface.\n * Durable retry, concurrency, and storage policy stay on their owning Effect\n * services and constructor options. Every accepted value is copied before any\n * plugin observes it, then frozen recursively.\n *\n * @since 1.0.0-rc.0\n */\n\nimport * as Effect from \"effect/Effect\"\nimport * as Schema from \"effect/Schema\"\nimport * as SchemaGetter from \"effect/SchemaGetter\"\nimport * as SchemaIssue from \"effect/SchemaIssue\"\nimport * as Boundary from \"./internal/Boundary.ts\"\nimport { PluginError } from \"./PluginError.ts\"\n\n/**\n * Maximum encoded bytes accepted for one plugin configuration.\n *\n * @category limits\n * @since 1.0.0-rc.0\n */\nexport const maximumConfigBytes = Boundary.defaultLimits.maxBytes\n\n/**\n * Maximum nesting accepted for one plugin configuration.\n *\n * @category limits\n * @since 1.0.0-rc.0\n */\nexport const maximumConfigDepth = Boundary.defaultLimits.maxDepth\n\n/**\n * Maximum aggregate members accepted for one plugin configuration.\n *\n * @category limits\n * @since 1.0.0-rc.0\n */\nexport const maximumConfigMembers = Boundary.defaultLimits.maxMembers\n\n/**\n * Maximum aggregate values accepted for one plugin configuration.\n *\n * @category limits\n * @since 1.0.0-rc.0\n */\nexport const maximumConfigNodes = Boundary.defaultLimits.maxNodes\n\n/**\n * One value accepted in a plugin-owned configuration namespace.\n *\n * @category models\n * @since 1.0.0-rc.0\n */\nexport const ConfigValue = Schema.Json\n\n/**\n * One value accepted in a plugin-owned configuration namespace.\n *\n * @category models\n * @since 1.0.0-rc.0\n */\nexport type ConfigValue = typeof ConfigValue.Type\n\nconst admittedConfigs = new WeakSet<object>()\n\nconst configurationSchema = Schema.Unknown.pipe(\n Schema.decodeTo(\n Schema.declare<Readonly<Record<string, ConfigValue>>>((value): value is Readonly<Record<string, ConfigValue>> =>\n typeof value === \"object\" && value !== null && admittedConfigs.has(value)\n ),\n {\n decode: SchemaGetter.transformEffect((value) =>\n Effect.try({\n try: () => snapshotRecord(value),\n catch: (cause) => {\n const error = cause as PluginError\n return new SchemaIssue.InvalidValue({ message: `${error.path}: ${error.message}` })\n }\n })\n ),\n encode: SchemaGetter.transform((value) => value)\n }\n )\n)\n\n/**\n * Admits pre-resolution configuration as a detached, recursively frozen snapshot.\n *\n * Keys name plugin-owned namespaces. `engine`, `retry`, `store`, and\n * `plugins` are refused because accepting those names would imply policy the\n * plugin kernel does not own or apply.\n *\n * @category models\n * @since 1.0.0-rc.0\n */\nexport const FlowsConfig = configurationSchema\n\n/**\n * The decoded form of {@link FlowsConfig}.\n *\n * @category models\n * @since 1.0.0-rc.0\n */\nexport type FlowsConfig = typeof FlowsConfig.Type\n\n/**\n * Admits the detached, recursively frozen configuration handed to plugins.\n *\n * @category models\n * @since 1.0.0-rc.0\n */\nexport const ResolvedConfig = configurationSchema\n\n/**\n * The decoded form of {@link ResolvedConfig}.\n *\n * @category models\n * @since 1.0.0-rc.0\n */\nexport type ResolvedConfig = typeof ResolvedConfig.Type\n\nconst reservedRootKeys = new Set([\"engine\", \"retry\", \"store\", \"plugins\"])\n\nconst invalid = (path: string, complaint: string): PluginError =>\n new PluginError({\n code: \"config_invalid\",\n message: `plugin configuration ${complaint}`,\n path\n })\n\nconst snapshotRecord = (input: unknown, reuse = true): Readonly<Record<string, ConfigValue>> => {\n if (reuse && typeof input === \"object\" && input !== null && admittedConfigs.has(input)) return input as ResolvedConfig\n const admitted = Boundary.record(input)\n if (!admitted.ok) throw invalid(admitted.path, admitted.complaint)\n const record = admitted.value as Readonly<Record<string, ConfigValue>>\n for (const key of Object.keys(record)) {\n if (reservedRootKeys.has(key)) {\n throw invalid(`$.${key}`, \"uses a runtime-policy key that the plugin kernel does not own\")\n }\n }\n admittedConfigs.add(record)\n return record\n}\n\n/**\n * Empty defaults. Engine policy is deliberately not defaulted here.\n *\n * @category constructors\n * @since 1.0.0-rc.0\n */\nexport const defaults: ResolvedConfig = snapshotRecord({})\n\n/**\n * Copies and deep-merges a configuration patch over a base configuration.\n *\n * Records merge key-by-key and every other JSON value replaces wholesale.\n * Raw operands are admitted; known snapshots retain unchanged subtrees.\n * Cached subtree totals enforce merged output bounds. Unsafe property names,\n * accessors, cycles, exotic prototypes, and aggregate values outside the\n * resource limits fail with `config_invalid`.\n *\n * @category combinators\n * @since 1.0.0-rc.0\n */\nexport const merge = (base: FlowsConfig, patch: unknown): FlowsConfig => {\n const safeBase = snapshotRecord(base)\n if (patch === undefined) return safeBase\n // Even a known patch is copied so its tree cannot alias the retained base.\n const safePatch = snapshotRecord(patch, false)\n const merged = Boundary.mergeRecords(safeBase, safePatch)\n if (!merged.ok) throw invalid(merged.path, merged.complaint)\n const record = merged.value as ResolvedConfig\n admittedConfigs.add(record)\n return record\n}\n\n/**\n * Copies and freezes one JSON value without retaining caller-owned objects.\n *\n * @category utils\n * @since 1.0.0-rc.0\n */\nexport const deepFreeze = <A extends ConfigValue>(value: A): A => {\n const admitted = Boundary.admit(value)\n if (!admitted.ok) throw invalid(admitted.path, admitted.complaint)\n return admitted.value as A\n}\n\n/**\n * Admits a raw pre-resolution configuration as an immutable snapshot.\n *\n * @category constructors\n * @since 1.0.0-rc.0\n */\nexport const snapshot = (config: unknown): Effect.Effect<FlowsConfig, PluginError> =>\n Effect.try({ try: () => snapshotRecord(config), catch: (cause) => cause as PluginError })\n\n/**\n * Decodes the post-waterfall configuration into its final immutable form.\n *\n * @category constructors\n * @since 1.0.0-rc.0\n */\nexport const resolve = (config: unknown): Effect.Effect<ResolvedConfig, PluginError> => snapshot(config)\n"]}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The typed hook surface: hook kinds, the hook entry shape, and the shared
|
|
3
|
+
* kernel's base hook catalog.
|
|
4
|
+
*
|
|
5
|
+
* The public package contract is documented at
|
|
6
|
+
* {@link https://smithers.sh/docs/reference/api/plugin}. The shared catalog is limited to
|
|
7
|
+
* `config` and `configResolved`;
|
|
8
|
+
* `@smthrs/agent` adds only `cellRegistry`, `cellFlows`, and
|
|
9
|
+
* `cellModelRequest`. Durable-core lifecycle policy is not a hook catalog.
|
|
10
|
+
*
|
|
11
|
+
* `FlowsHooks` is **open for augmentation, closed for dispatch**: a host
|
|
12
|
+
* declares its hooks with `declare module "@smthrs/plugin"`, supplies the
|
|
13
|
+
* matching runtime catalog, and dispatches only that bounded set.
|
|
14
|
+
*
|
|
15
|
+
* @since 1.0.0-rc.0
|
|
16
|
+
*/
|
|
17
|
+
import type * as Effect from "effect/Effect";
|
|
18
|
+
/**
|
|
19
|
+
* Dispatch semantics of a hook, fixed by the core.
|
|
20
|
+
*
|
|
21
|
+
* @category models
|
|
22
|
+
* @since 1.0.0-rc.0
|
|
23
|
+
*/
|
|
24
|
+
export type HookKind = "sequential" | "parallel" | "first" | "waterfall";
|
|
25
|
+
declare const HookTypeId: unique symbol;
|
|
26
|
+
/**
|
|
27
|
+
* Phantom carrier that records a hook's kind and handler type in the type
|
|
28
|
+
* system without adding anything at runtime.
|
|
29
|
+
*
|
|
30
|
+
* @category models
|
|
31
|
+
* @since 1.0.0-rc.0
|
|
32
|
+
*/
|
|
33
|
+
export interface HookMeta<K extends HookKind, F> {
|
|
34
|
+
readonly [HookTypeId]?: {
|
|
35
|
+
readonly kind: K;
|
|
36
|
+
readonly handler: F;
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* The object form of a hook entry: Vite's per-hook ordering object, verbatim.
|
|
41
|
+
*
|
|
42
|
+
* @category models
|
|
43
|
+
* @since 1.0.0-rc.0
|
|
44
|
+
*/
|
|
45
|
+
export interface HookObject<F> {
|
|
46
|
+
readonly order?: "pre" | "post" | undefined;
|
|
47
|
+
readonly handler: F;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* A hook entry is either the bare handler or `{ order?, handler }`.
|
|
51
|
+
*
|
|
52
|
+
* @category models
|
|
53
|
+
* @since 1.0.0-rc.0
|
|
54
|
+
*/
|
|
55
|
+
export type HookEntry<K extends HookKind, F> = (F | HookObject<F>) & HookMeta<K, F>;
|
|
56
|
+
/**
|
|
57
|
+
* Every handler runs, in resolved order, one at a time.
|
|
58
|
+
*
|
|
59
|
+
* @category models
|
|
60
|
+
* @since 1.0.0-rc.0
|
|
61
|
+
*/
|
|
62
|
+
export type SequentialHook<F> = HookEntry<"sequential", F>;
|
|
63
|
+
/**
|
|
64
|
+
* Every handler runs concurrently; results are ignored and failures are
|
|
65
|
+
* returned to the caller rather than failing it.
|
|
66
|
+
*
|
|
67
|
+
* @category models
|
|
68
|
+
* @since 1.0.0-rc.0
|
|
69
|
+
*/
|
|
70
|
+
export type ParallelHook<F> = HookEntry<"parallel", F>;
|
|
71
|
+
/**
|
|
72
|
+
* Handlers run in order until one returns `Option.some`.
|
|
73
|
+
*
|
|
74
|
+
* @category models
|
|
75
|
+
* @since 1.0.0-rc.0
|
|
76
|
+
*/
|
|
77
|
+
export type FirstHook<F> = HookEntry<"first", F>;
|
|
78
|
+
/**
|
|
79
|
+
* Each handler receives the previous handler's output.
|
|
80
|
+
*
|
|
81
|
+
* @category models
|
|
82
|
+
* @since 1.0.0-rc.0
|
|
83
|
+
*/
|
|
84
|
+
export type WaterfallHook<F> = HookEntry<"waterfall", F>;
|
|
85
|
+
/**
|
|
86
|
+
* Extracts the declared kind of a hook entry type.
|
|
87
|
+
*
|
|
88
|
+
* @category type-level
|
|
89
|
+
* @since 1.0.0-rc.0
|
|
90
|
+
*/
|
|
91
|
+
export type KindOf<T> = T extends HookMeta<infer K, any> ? K : never;
|
|
92
|
+
/**
|
|
93
|
+
* The runtime catalog a host supplies for a hook interface: each hook name
|
|
94
|
+
* mapped to its kind. A name declared in `H` must carry the kind its type
|
|
95
|
+
* declares. Names outside `H` are admitted with any kind, because the type
|
|
96
|
+
* system cannot enumerate an augmentable interface; resolution checks them
|
|
97
|
+
* at runtime and dispatch refuses a kind that disagrees with the catalog.
|
|
98
|
+
*
|
|
99
|
+
* @category type-level
|
|
100
|
+
* @since 1.0.0-rc.0
|
|
101
|
+
*/
|
|
102
|
+
export type HookCatalog<H> = {
|
|
103
|
+
readonly [K in keyof H & string]?: KindOf<H[K]>;
|
|
104
|
+
} & {
|
|
105
|
+
readonly [name: string]: HookKind | undefined;
|
|
106
|
+
};
|
|
107
|
+
/**
|
|
108
|
+
* Extracts the handler type of a hook entry type.
|
|
109
|
+
*
|
|
110
|
+
* @category type-level
|
|
111
|
+
* @since 1.0.0-rc.0
|
|
112
|
+
*/
|
|
113
|
+
export type HandlerOf<T> = T extends HookMeta<any, infer F> ? F : never;
|
|
114
|
+
/**
|
|
115
|
+
* Selects the hook names of a given kind from a hook interface.
|
|
116
|
+
*
|
|
117
|
+
* @category type-level
|
|
118
|
+
* @since 1.0.0-rc.0
|
|
119
|
+
*/
|
|
120
|
+
export type KeysOfKind<H, K extends HookKind> = {
|
|
121
|
+
[P in keyof H]: KindOf<H[P]> extends K ? P : never;
|
|
122
|
+
}[keyof H] & string;
|
|
123
|
+
/**
|
|
124
|
+
* Extracts the positional argument tuple accepted by a hook entry.
|
|
125
|
+
*
|
|
126
|
+
* @category type-level
|
|
127
|
+
* @since 1.0.0-rc.0
|
|
128
|
+
*/
|
|
129
|
+
export type ArgsOf<T> = HandlerOf<T> extends (...args: infer A) => any ? A : never;
|
|
130
|
+
/**
|
|
131
|
+
* Extracts the Effect returned by a hook entry.
|
|
132
|
+
*
|
|
133
|
+
* @category type-level
|
|
134
|
+
* @since 1.0.0-rc.0
|
|
135
|
+
*/
|
|
136
|
+
export type ReturnOf<T> = HandlerOf<T> extends (...args: any) => infer R ? R : never;
|
|
137
|
+
/**
|
|
138
|
+
* Extracts the success value returned by a hook entry's Effect.
|
|
139
|
+
*
|
|
140
|
+
* @category type-level
|
|
141
|
+
* @since 1.0.0-rc.0
|
|
142
|
+
*/
|
|
143
|
+
export type SuccessOf<T> = ReturnOf<T> extends Effect.Effect<infer A, any, any> ? A : never;
|
|
144
|
+
/**
|
|
145
|
+
* Extracts the context required by a hook entry's Effect.
|
|
146
|
+
*
|
|
147
|
+
* @category type-level
|
|
148
|
+
* @since 1.0.0-rc.0
|
|
149
|
+
*/
|
|
150
|
+
export type ContextOf<T> = ReturnOf<T> extends Effect.Effect<any, any, infer R> ? R : never;
|
|
151
|
+
/**
|
|
152
|
+
* Frozen runtime catalog for the shared configuration hooks.
|
|
153
|
+
*
|
|
154
|
+
* @category models
|
|
155
|
+
* @since 1.0.0-rc.0
|
|
156
|
+
*/
|
|
157
|
+
export declare const engineHooks: Readonly<{
|
|
158
|
+
readonly config: "waterfall";
|
|
159
|
+
readonly configResolved: "parallel";
|
|
160
|
+
}>;
|
|
161
|
+
/**
|
|
162
|
+
* Normalizes a hook entry to its handler.
|
|
163
|
+
*
|
|
164
|
+
* @category utils
|
|
165
|
+
* @since 1.0.0-rc.0
|
|
166
|
+
*/
|
|
167
|
+
export declare const handlerOf: (entry: unknown) => (...args: Array<any>) => unknown;
|
|
168
|
+
/**
|
|
169
|
+
* Reads the per-hook `order` of a hook entry.
|
|
170
|
+
*
|
|
171
|
+
* @category utils
|
|
172
|
+
* @since 1.0.0-rc.0
|
|
173
|
+
*/
|
|
174
|
+
export declare const orderOf: (entry: unknown) => "pre" | "post" | undefined;
|
|
175
|
+
export {};
|
|
176
|
+
//# sourceMappingURL=Hooks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Hooks.d.ts","sourceRoot":"","sources":["../../src/Hooks.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The typed hook surface: hook kinds, the hook entry shape, and the shared
|
|
3
|
+
* kernel's base hook catalog.
|
|
4
|
+
*
|
|
5
|
+
* The public package contract is documented at
|
|
6
|
+
* {@link https://smithers.sh/docs/reference/api/plugin}. The shared catalog is limited to
|
|
7
|
+
* `config` and `configResolved`;
|
|
8
|
+
* `@smthrs/agent` adds only `cellRegistry`, `cellFlows`, and
|
|
9
|
+
* `cellModelRequest`. Durable-core lifecycle policy is not a hook catalog.
|
|
10
|
+
*
|
|
11
|
+
* `FlowsHooks` is **open for augmentation, closed for dispatch**: a host
|
|
12
|
+
* declares its hooks with `declare module "@smthrs/plugin"`, supplies the
|
|
13
|
+
* matching runtime catalog, and dispatches only that bounded set.
|
|
14
|
+
*
|
|
15
|
+
* @since 1.0.0-rc.0
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* Runtime catalog of the shared kernel's hook names and kinds.
|
|
19
|
+
*
|
|
20
|
+
* The type system cannot enumerate an augmentable interface, so this constant
|
|
21
|
+
* is what the `unknown_hook` guard checks against. A host passes its own
|
|
22
|
+
* superset to {@link resolve}. The cell harness adds only the hooks it
|
|
23
|
+
* dispatches; lifecycle and engine-policy hooks do not belong here.
|
|
24
|
+
*
|
|
25
|
+
* @category models
|
|
26
|
+
* @since 1.0.0-rc.0
|
|
27
|
+
*/
|
|
28
|
+
const sharedHooks = Object.create(null);
|
|
29
|
+
Object.defineProperties(sharedHooks, {
|
|
30
|
+
config: { value: "waterfall", enumerable: true },
|
|
31
|
+
configResolved: { value: "parallel", enumerable: true }
|
|
32
|
+
});
|
|
33
|
+
/**
|
|
34
|
+
* Frozen runtime catalog for the shared configuration hooks.
|
|
35
|
+
*
|
|
36
|
+
* @category models
|
|
37
|
+
* @since 1.0.0-rc.0
|
|
38
|
+
*/
|
|
39
|
+
export const engineHooks = Object.freeze(sharedHooks);
|
|
40
|
+
/**
|
|
41
|
+
* Normalizes a hook entry to its handler.
|
|
42
|
+
*
|
|
43
|
+
* @category utils
|
|
44
|
+
* @since 1.0.0-rc.0
|
|
45
|
+
*/
|
|
46
|
+
export const handlerOf = (entry) => typeof entry === "function"
|
|
47
|
+
? entry
|
|
48
|
+
: entry.handler;
|
|
49
|
+
/**
|
|
50
|
+
* Reads the per-hook `order` of a hook entry.
|
|
51
|
+
*
|
|
52
|
+
* @category utils
|
|
53
|
+
* @since 1.0.0-rc.0
|
|
54
|
+
*/
|
|
55
|
+
export const orderOf = (entry) => typeof entry === "function" ? undefined : entry.order;
|
|
56
|
+
//# sourceMappingURL=Hooks.js.map
|