@smthrs/plugin 0.0.0-stage → 1.0.0-rc.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.
Files changed (118) hide show
  1. package/CHANGELOG.md +79 -0
  2. package/LICENSE +21 -0
  3. package/README.md +86 -2
  4. package/dist/cjs/Config.d.ts +129 -0
  5. package/dist/cjs/Config.d.ts.map +1 -0
  6. package/dist/cjs/Config.js +115 -0
  7. package/dist/cjs/Config.js.map +7 -0
  8. package/dist/cjs/Hooks.d.ts +176 -0
  9. package/dist/cjs/Hooks.d.ts.map +1 -0
  10. package/dist/cjs/Hooks.js +34 -0
  11. package/dist/cjs/Hooks.js.map +7 -0
  12. package/dist/cjs/Kernel.d.ts +81 -0
  13. package/dist/cjs/Kernel.d.ts.map +1 -0
  14. package/dist/cjs/Kernel.js +57 -0
  15. package/dist/cjs/Kernel.js.map +7 -0
  16. package/dist/cjs/Plugin.d.ts +71 -0
  17. package/dist/cjs/Plugin.d.ts.map +1 -0
  18. package/dist/cjs/Plugin.js +25 -0
  19. package/dist/cjs/Plugin.js.map +7 -0
  20. package/dist/cjs/PluginError.d.ts +50 -0
  21. package/dist/cjs/PluginError.d.ts.map +1 -0
  22. package/dist/cjs/PluginError.js +58 -0
  23. package/dist/cjs/PluginError.js.map +7 -0
  24. package/dist/cjs/Plugins.d.ts +97 -0
  25. package/dist/cjs/Plugins.d.ts.map +1 -0
  26. package/dist/cjs/Plugins.js +160 -0
  27. package/dist/cjs/Plugins.js.map +7 -0
  28. package/dist/cjs/Resolve.d.ts +128 -0
  29. package/dist/cjs/Resolve.d.ts.map +1 -0
  30. package/dist/cjs/Resolve.js +343 -0
  31. package/dist/cjs/Resolve.js.map +7 -0
  32. package/dist/cjs/index.d.ts +83 -0
  33. package/dist/cjs/index.d.ts.map +1 -0
  34. package/dist/cjs/index.js +45 -0
  35. package/dist/cjs/index.js.map +7 -0
  36. package/dist/cjs/internal/Boundary.d.ts +96 -0
  37. package/dist/cjs/internal/Boundary.d.ts.map +1 -0
  38. package/dist/cjs/internal/Boundary.js +129 -0
  39. package/dist/cjs/internal/Boundary.js.map +7 -0
  40. package/dist/cjs/internal/mergePluginLayers.d.ts +21 -0
  41. package/dist/cjs/internal/mergePluginLayers.d.ts.map +1 -0
  42. package/dist/cjs/internal/mergePluginLayers.js +57 -0
  43. package/dist/cjs/internal/mergePluginLayers.js.map +7 -0
  44. package/dist/cjs/internal/snapshotCacheEnvironment.d.ts +19 -0
  45. package/dist/cjs/internal/snapshotCacheEnvironment.d.ts.map +1 -0
  46. package/dist/cjs/internal/snapshotCacheEnvironment.js +92 -0
  47. package/dist/cjs/internal/snapshotCacheEnvironment.js.map +7 -0
  48. package/dist/cjs/package.json +1 -0
  49. package/dist/esm/Config.d.ts +129 -0
  50. package/dist/esm/Config.d.ts.map +1 -0
  51. package/dist/esm/Config.js +160 -0
  52. package/dist/esm/Config.js.map +1 -0
  53. package/dist/esm/Hooks.d.ts +176 -0
  54. package/dist/esm/Hooks.d.ts.map +1 -0
  55. package/dist/esm/Hooks.js +56 -0
  56. package/dist/esm/Hooks.js.map +1 -0
  57. package/dist/esm/Kernel.d.ts +81 -0
  58. package/dist/esm/Kernel.d.ts.map +1 -0
  59. package/dist/esm/Kernel.js +58 -0
  60. package/dist/esm/Kernel.js.map +1 -0
  61. package/dist/esm/Plugin.d.ts +71 -0
  62. package/dist/esm/Plugin.d.ts.map +1 -0
  63. package/dist/esm/Plugin.js +20 -0
  64. package/dist/esm/Plugin.js.map +1 -0
  65. package/dist/esm/PluginError.d.ts +50 -0
  66. package/dist/esm/PluginError.d.ts.map +1 -0
  67. package/dist/esm/PluginError.js +53 -0
  68. package/dist/esm/PluginError.js.map +1 -0
  69. package/dist/esm/Plugins.d.ts +97 -0
  70. package/dist/esm/Plugins.d.ts.map +1 -0
  71. package/dist/esm/Plugins.js +178 -0
  72. package/dist/esm/Plugins.js.map +1 -0
  73. package/dist/esm/Resolve.d.ts +128 -0
  74. package/dist/esm/Resolve.d.ts.map +1 -0
  75. package/dist/esm/Resolve.js +367 -0
  76. package/dist/esm/Resolve.js.map +1 -0
  77. package/dist/esm/index.d.ts +83 -0
  78. package/dist/esm/index.d.ts.map +1 -0
  79. package/dist/esm/index.js +48 -0
  80. package/dist/esm/index.js.map +1 -0
  81. package/dist/esm/internal/Boundary.d.ts +96 -0
  82. package/dist/esm/internal/Boundary.d.ts.map +1 -0
  83. package/dist/esm/internal/Boundary.js +162 -0
  84. package/dist/esm/internal/Boundary.js.map +1 -0
  85. package/dist/esm/internal/mergePluginLayers.d.ts +21 -0
  86. package/dist/esm/internal/mergePluginLayers.d.ts.map +1 -0
  87. package/dist/esm/internal/mergePluginLayers.js +41 -0
  88. package/dist/esm/internal/mergePluginLayers.js.map +1 -0
  89. package/dist/esm/internal/snapshotCacheEnvironment.d.ts +19 -0
  90. package/dist/esm/internal/snapshotCacheEnvironment.d.ts.map +1 -0
  91. package/dist/esm/internal/snapshotCacheEnvironment.js +63 -0
  92. package/dist/esm/internal/snapshotCacheEnvironment.js.map +1 -0
  93. package/docs/README.md +131 -0
  94. package/docs/api.md +522 -0
  95. package/docs/concepts/configuration.md +111 -0
  96. package/docs/concepts/hook-kinds.md +107 -0
  97. package/docs/concepts/resolution.md +132 -0
  98. package/docs/guides/cache-identity.md +106 -0
  99. package/docs/guides/contribute-services.md +84 -0
  100. package/docs/guides/host-your-own-hooks.md +129 -0
  101. package/docs/guides/order-handlers.md +76 -0
  102. package/docs/guides/select-plugins.md +72 -0
  103. package/docs/guides/testing.md +149 -0
  104. package/docs/installation.md +71 -0
  105. package/docs/quickstart.md +151 -0
  106. package/docs/troubleshooting.md +179 -0
  107. package/package.json +179 -3
  108. package/src/Config.ts +207 -0
  109. package/src/Hooks.ts +212 -0
  110. package/src/Kernel.ts +119 -0
  111. package/src/Plugin.ts +80 -0
  112. package/src/PluginError.ts +62 -0
  113. package/src/Plugins.ts +254 -0
  114. package/src/Resolve.ts +535 -0
  115. package/src/index.ts +91 -0
  116. package/src/internal/Boundary.ts +252 -0
  117. package/src/internal/mergePluginLayers.ts +57 -0
  118. package/src/internal/snapshotCacheEnvironment.ts +77 -0
@@ -0,0 +1,160 @@
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 Plugins_exports = {};
30
+ __export(Plugins_exports, {
31
+ Plugins: () => Plugins,
32
+ layer: () => layer,
33
+ layerNoop: () => layerNoop,
34
+ make: () => make,
35
+ makeNoop: () => makeNoop
36
+ });
37
+ module.exports = __toCommonJS(Plugins_exports);
38
+ var ImmutableMap = __toESM(require("@smthrs/canonical/ReadonlyMap"), 1);
39
+ var Context = __toESM(require("effect/Context"), 1);
40
+ var Effect = __toESM(require("effect/Effect"), 1);
41
+ var Layer = __toESM(require("effect/Layer"), 1);
42
+ var Option = __toESM(require("effect/Option"), 1);
43
+ var import_Hooks = require("./Hooks.js");
44
+ var import_PluginError = require("./PluginError.js");
45
+ var import_Resolve = require("./Resolve.js");
46
+ const empty = Object.freeze([]);
47
+ const kindMismatch = (resolved, hook, kind) => {
48
+ if (!Object.hasOwn(resolved.kinds, hook)) return void 0;
49
+ const declared = resolved.kinds[hook];
50
+ if (declared === kind) return void 0;
51
+ return new import_PluginError.PluginError({
52
+ code: "hook_kind_mismatch",
53
+ message: `hook "${hook}" is declared ${JSON.stringify(declared)} in the runtime catalog but was dispatched as ${JSON.stringify(kind)}`,
54
+ hook
55
+ });
56
+ };
57
+ const runHandler = (record, args) => {
58
+ const onCause = (cause) => Effect.fail(
59
+ new import_PluginError.PluginError({
60
+ code: "hook_failed",
61
+ message: `hook "${record.hook}" failed in plugin "${record.plugin}"`,
62
+ plugin: record.plugin,
63
+ hook: record.hook,
64
+ cause
65
+ })
66
+ );
67
+ return Effect.sync(() => record.handler(...args)).pipe(
68
+ Effect.catchCause(onCause),
69
+ Effect.flatMap(
70
+ (result) => Effect.isEffect(result) ? result.pipe(Effect.catchCause(onCause)) : Effect.fail(
71
+ new import_PluginError.PluginError({
72
+ code: "hook_failed",
73
+ message: `hook "${record.hook}" in plugin "${record.plugin}" returned a non-Effect (${typeof result})`,
74
+ plugin: record.plugin,
75
+ hook: record.hook
76
+ })
77
+ )
78
+ )
79
+ );
80
+ };
81
+ const make = (resolved) => {
82
+ const handlers = (hook) => resolved.handlers.get(hook) ?? empty;
83
+ const sequential = ((hook, ...args) => Effect.gen(function* () {
84
+ const mismatch = kindMismatch(resolved, hook, "sequential");
85
+ if (mismatch !== void 0) return yield* Effect.fail(mismatch);
86
+ const results = [];
87
+ for (const record of handlers(hook)) {
88
+ results.push(yield* runHandler(record, args));
89
+ }
90
+ return results;
91
+ }));
92
+ const parallel = ((hook, ...args) => {
93
+ const mismatch = kindMismatch(resolved, hook, "parallel");
94
+ if (mismatch !== void 0) return Effect.succeed([mismatch]);
95
+ return Effect.forEach(
96
+ handlers(hook),
97
+ (record) => runHandler(record, args).pipe(
98
+ Effect.match({ onFailure: (error) => [error], onSuccess: () => [] })
99
+ ),
100
+ { concurrency: resolved.parallelConcurrency }
101
+ ).pipe(Effect.map((chunks) => chunks.flat()));
102
+ });
103
+ const first = ((hook, ...args) => Effect.gen(function* () {
104
+ const mismatch = kindMismatch(resolved, hook, "first");
105
+ if (mismatch !== void 0) return yield* Effect.fail(mismatch);
106
+ for (const record of handlers(hook)) {
107
+ const result = yield* runHandler(record, args);
108
+ if (!Option.isOption(result)) {
109
+ return yield* Effect.fail(
110
+ new import_PluginError.PluginError({
111
+ code: "invalid_hook_result",
112
+ message: `first hook "${record.hook}" in plugin "${record.plugin}" did not return an Option`,
113
+ plugin: record.plugin,
114
+ hook: record.hook
115
+ })
116
+ );
117
+ }
118
+ if (Option.isSome(result)) return result;
119
+ }
120
+ return Option.none();
121
+ }));
122
+ const waterfall = ((hook, initial, merge) => Effect.gen(function* () {
123
+ const mismatch = kindMismatch(resolved, hook, "waterfall");
124
+ if (mismatch !== void 0) return yield* Effect.fail(mismatch);
125
+ let value = initial;
126
+ for (const record of handlers(hook)) {
127
+ const patch = yield* runHandler(record, [value]);
128
+ if (patch !== void 0) {
129
+ value = yield* Effect.try({
130
+ try: () => merge(value, patch),
131
+ catch: (cause) => cause instanceof import_PluginError.PluginError ? new import_PluginError.PluginError({
132
+ code: cause.code,
133
+ message: cause.message,
134
+ plugin: record.plugin,
135
+ hook: record.hook,
136
+ path: cause.path
137
+ }) : new import_PluginError.PluginError({
138
+ code: "config_invalid",
139
+ message: `waterfall hook "${record.hook}" in plugin "${record.plugin}" returned an invalid patch`,
140
+ plugin: record.plugin,
141
+ hook: record.hook
142
+ })
143
+ });
144
+ }
145
+ }
146
+ return value;
147
+ }));
148
+ return Object.freeze({ resolved, handlers, sequential, parallel, first, waterfall });
149
+ };
150
+ const makeNoop = () => make(Object.freeze({
151
+ plugins: Object.freeze([]),
152
+ handlers: ImmutableMap.make(),
153
+ kinds: import_Hooks.engineHooks,
154
+ parallelConcurrency: import_Resolve.defaultParallelConcurrency
155
+ }));
156
+ class Plugins extends Context.Service()("flows/plugin/Plugins") {
157
+ }
158
+ const layer = (resolved) => Layer.succeed(Plugins)(make(resolved));
159
+ const layerNoop = Layer.succeed(Plugins)(makeNoop());
160
+ //# sourceMappingURL=Plugins.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/Plugins.ts"],
4
+ "sourcesContent": ["/**\n * The dispatcher: a plain service over a resolved plugin list, generic over the\n * hook interface.\n *\n * The public package contract is documented at\n * {@link https://smithers.sh/docs/reference/api/plugin}. Each host holds an instance over its\n * augmented `FlowsHooks` and may dispatch only the runtime catalog it supplied.\n * The shipped cell host owns the three\n * waterfalls declared in `packages/smithers/agent/src/CellPlugin.ts`; there is\n * no engine-wide lifecycle dispatcher.\n *\n * Cancellation is fiber interruption via scope closure; nothing here threads an\n * `AbortSignal`.\n *\n * @since 1.0.0-rc.0\n */\n\nimport * as ImmutableMap from \"@smthrs/canonical/ReadonlyMap\"\nimport type * as Cause from \"effect/Cause\"\nimport * as Context from \"effect/Context\"\nimport * as Effect from \"effect/Effect\"\nimport * as Layer from \"effect/Layer\"\nimport * as Option from \"effect/Option\"\nimport type { ArgsOf, ContextOf, HookKind, KeysOfKind, SuccessOf } from \"./Hooks.ts\"\nimport { engineHooks } from \"./Hooks.ts\"\nimport type { FlowsHooks } from \"./index.ts\"\nimport { PluginError } from \"./PluginError.ts\"\nimport { defaultParallelConcurrency, type HandlerRecord, type Resolved } from \"./Resolve.ts\"\n\nconst empty: ReadonlyArray<HandlerRecord> = Object.freeze([])\n\n// The typed catalog and the runtime catalog can only drift when a host casts\n// around `KeysOfKind`; refuse before any handler runs rather than execute a\n// hook under semantics its declaration never promised.\nconst kindMismatch = (resolved: Resolved<unknown>, hook: string, kind: HookKind): PluginError | undefined => {\n if (!Object.hasOwn(resolved.kinds, hook)) return undefined\n const declared = resolved.kinds[hook]\n if (declared === kind) return undefined\n return new PluginError({\n code: \"hook_kind_mismatch\",\n message: `hook \"${hook}\" is declared ${JSON.stringify(declared)} in the runtime catalog but was dispatched as ${\n JSON.stringify(kind)\n }`,\n hook\n })\n}\n\nconst runHandler = (\n record: HandlerRecord,\n args: ReadonlyArray<unknown>\n): Effect.Effect<unknown, PluginError, any> => {\n const onCause = (cause: Cause.Cause<unknown>) =>\n Effect.fail(\n new PluginError({\n code: \"hook_failed\",\n message: `hook \"${record.hook}\" failed in plugin \"${record.plugin}\"`,\n plugin: record.plugin,\n hook: record.hook,\n cause\n })\n )\n\n return Effect.sync(() => record.handler(...args)).pipe(\n Effect.catchCause(onCause),\n Effect.flatMap((result) =>\n Effect.isEffect(result)\n ? result.pipe(Effect.catchCause(onCause))\n : Effect.fail(\n new PluginError({\n code: \"hook_failed\",\n message: `hook \"${record.hook}\" in plugin \"${record.plugin}\" returned a non-Effect (${typeof result})`,\n plugin: record.plugin,\n hook: record.hook\n })\n )\n )\n )\n}\n\n/**\n * The dispatch surface.\n *\n * @category models\n * @since 1.0.0-rc.0\n */\nexport interface Service<H = FlowsHooks> {\n /** The resolved list this dispatcher walks. */\n readonly resolved: Resolved<H>\n /** Frozen, ordered handler records for a hook. */\n readonly handlers: (hook: string) => ReadonlyArray<HandlerRecord>\n /** Runs every handler in resolved order, one at a time. */\n readonly sequential: <K extends KeysOfKind<H, \"sequential\">>(\n hook: K,\n ...args: ArgsOf<H[K]>\n ) => Effect.Effect<ReadonlyArray<SuccessOf<H[K]>>, PluginError, ContextOf<H[K]>>\n /**\n * Runs every handler concurrently, ignoring results. Never fails: handler\n * failures are returned so the caller can report them at its own boundary.\n */\n readonly parallel: <K extends KeysOfKind<H, \"parallel\">>(\n hook: K,\n ...args: ArgsOf<H[K]>\n ) => Effect.Effect<ReadonlyArray<PluginError>, never, ContextOf<H[K]>>\n /** Runs handlers in order until one returns `Option.some`. */\n readonly first: <K extends KeysOfKind<H, \"first\">>(\n hook: K,\n ...args: ArgsOf<H[K]>\n ) => Effect.Effect<SuccessOf<H[K]>, PluginError, ContextOf<H[K]>>\n /** Threads a value through every handler, merging each returned patch. */\n readonly waterfall: <K extends KeysOfKind<H, \"waterfall\">>(\n hook: K,\n initial: ArgsOf<H[K]>[0],\n merge: (previous: ArgsOf<H[K]>[0], patch: Exclude<SuccessOf<H[K]>, void>) => ArgsOf<H[K]>[0]\n ) => Effect.Effect<ArgsOf<H[K]>[0], PluginError, ContextOf<H[K]>>\n}\n\n/**\n * Builds a dispatcher over an already resolved plugin list.\n *\n * @category constructors\n * @since 1.0.0-rc.0\n */\nexport const make = <H = FlowsHooks>(resolved: Resolved<H>): Service<H> => {\n const handlers = (hook: string): ReadonlyArray<HandlerRecord> => resolved.handlers.get(hook) ?? empty\n\n const sequential = ((hook: string, ...args: Array<unknown>) =>\n Effect.gen(function*() {\n const mismatch = kindMismatch(resolved, hook, \"sequential\")\n if (mismatch !== undefined) return yield* Effect.fail(mismatch)\n const results: Array<unknown> = []\n for (const record of handlers(hook)) {\n results.push(yield* runHandler(record, args))\n }\n return results\n })) as Service<H>[\"sequential\"]\n\n const parallel = ((hook: string, ...args: Array<unknown>) => {\n const mismatch = kindMismatch(resolved, hook, \"parallel\")\n if (mismatch !== undefined) return Effect.succeed([mismatch])\n return Effect.forEach(\n handlers(hook),\n (record) =>\n runHandler(record, args).pipe(\n Effect.match({ onFailure: (error) => [error], onSuccess: () => [] as Array<PluginError> })\n ),\n { concurrency: resolved.parallelConcurrency }\n ).pipe(Effect.map((chunks) => chunks.flat()))\n }) as Service<H>[\"parallel\"]\n\n const first = ((hook: string, ...args: Array<unknown>) =>\n Effect.gen(function*() {\n const mismatch = kindMismatch(resolved, hook, \"first\")\n if (mismatch !== undefined) return yield* Effect.fail(mismatch)\n for (const record of handlers(hook)) {\n const result = yield* runHandler(record, args)\n if (!Option.isOption(result)) {\n return yield* Effect.fail(\n new PluginError({\n code: \"invalid_hook_result\",\n message: `first hook \"${record.hook}\" in plugin \"${record.plugin}\" did not return an Option`,\n plugin: record.plugin,\n hook: record.hook\n })\n )\n }\n if (Option.isSome(result)) return result\n }\n return Option.none()\n })) as unknown as Service<H>[\"first\"]\n\n const waterfall =\n ((hook: string, initial: unknown, merge: (previous: unknown, patch: unknown) => unknown) =>\n Effect.gen(function*() {\n const mismatch = kindMismatch(resolved, hook, \"waterfall\")\n if (mismatch !== undefined) return yield* Effect.fail(mismatch)\n let value = initial\n for (const record of handlers(hook)) {\n const patch = yield* runHandler(record, [value])\n if (patch !== undefined) {\n value = yield* Effect.try({\n try: () => merge(value, patch),\n catch: (cause) =>\n cause instanceof PluginError\n ? new PluginError({\n code: cause.code,\n message: cause.message,\n plugin: record.plugin,\n hook: record.hook,\n path: cause.path\n })\n : new PluginError({\n code: \"config_invalid\",\n message: `waterfall hook \"${record.hook}\" in plugin \"${record.plugin}\" returned an invalid patch`,\n plugin: record.plugin,\n hook: record.hook\n })\n })\n }\n }\n return value\n })) as Service<H>[\"waterfall\"]\n\n return Object.freeze({ resolved, handlers, sequential, parallel, first, waterfall })\n}\n\n/**\n * A dispatcher with no plugins at all.\n *\n * @category constructors\n * @since 1.0.0-rc.0\n */\nexport const makeNoop = <H = FlowsHooks>(): Service<H> =>\n make<H>(Object.freeze({\n plugins: Object.freeze([]),\n handlers: ImmutableMap.make<string, ReadonlyArray<HandlerRecord>>(),\n kinds: engineHooks,\n parallelConcurrency: defaultParallelConcurrency\n }))\n\n/**\n * The shared dispatcher, as a service tag.\n *\n * This tag holds one dispatcher over the process-wide augmented `FlowsHooks`.\n * `declare module \"@smthrs/plugin\"` augmentation is the supported extension\n * mechanism for values placed in the tag. A host typed against a separate hook\n * interface holds its `Service<H>` directly, as `@smthrs/agent` does, and does\n * not use this tag or its layers.\n *\n * @category context\n * @since 1.0.0-rc.0\n */\nexport class Plugins extends Context.Service<Plugins, Service>()(\"flows/plugin/Plugins\") {}\n\n/**\n * Layer providing a dispatcher over an already resolved plugin list.\n *\n * This layer targets the shared augmented `FlowsHooks` catalog only. A host\n * with a separate hook interface holds its `Service<H>` directly.\n *\n * @category layers\n * @since 1.0.0-rc.0\n */\nexport const layer = (resolved: Resolved): Layer.Layer<Plugins> => Layer.succeed(Plugins)(make(resolved))\n\n/**\n * Layer providing a dispatcher with no plugins.\n *\n * This layer targets the shared augmented `FlowsHooks` catalog only. A host\n * with a separate hook interface holds its `Service<H>` directly.\n *\n * @category layers\n * @since 1.0.0-rc.0\n */\nexport const layerNoop: Layer.Layer<Plugins> = Layer.succeed(Plugins)(makeNoop())\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,128 @@
1
+ /**
2
+ * Bounded plugin resolution: admit, filter, validate, order, and snapshot.
3
+ *
4
+ * The resulting catalog owns every record it exposes. Dispatch never reads a
5
+ * caller-owned map, plugin record, hook object, config value, or cache identity.
6
+ *
7
+ * @since 1.0.0-rc.0
8
+ */
9
+ import type { Action } from "@smthrs/flow";
10
+ import * as Effect from "effect/Effect";
11
+ import * as Layer from "effect/Layer";
12
+ import type { FlowsConfig } from "./Config.ts";
13
+ import type { HookCatalog, HookKind } from "./Hooks.ts";
14
+ import type { FlowsHooks } from "./index.ts";
15
+ import type { FlowsPlugin, PluginInput } from "./Plugin.ts";
16
+ import { PluginError } from "./PluginError.ts";
17
+ /**
18
+ * Maximum nested preset-array depth accepted at startup.
19
+ *
20
+ * @category limits
21
+ * @since 1.0.0-rc.0
22
+ */
23
+ export declare const maximumPluginDepth = 64;
24
+ /**
25
+ * Maximum plugins accepted by one kernel.
26
+ *
27
+ * @category limits
28
+ * @since 1.0.0-rc.0
29
+ */
30
+ export declare const maximumPlugins = 256;
31
+ /**
32
+ * Maximum aggregate hook handlers accepted by one kernel.
33
+ *
34
+ * @category limits
35
+ * @since 1.0.0-rc.0
36
+ */
37
+ export declare const maximumHandlers = 1024;
38
+ /**
39
+ * Maximum input nodes, including arrays and omitted entries.
40
+ *
41
+ * @category limits
42
+ * @since 1.0.0-rc.0
43
+ */
44
+ export declare const maximumPluginInputNodes = 4096;
45
+ /**
46
+ * Maximum UTF-16 length of one plugin or hook name.
47
+ *
48
+ * @category limits
49
+ * @since 1.0.0-rc.0
50
+ */
51
+ export declare const maximumPluginNameLength = 256;
52
+ /**
53
+ * Default fiber bound for parallel observers.
54
+ *
55
+ * @category limits
56
+ * @since 1.0.0-rc.0
57
+ */
58
+ export declare const defaultParallelConcurrency = 16;
59
+ /**
60
+ * Maximum configurable parallel-observer bound.
61
+ *
62
+ * @category limits
63
+ * @since 1.0.0-rc.0
64
+ */
65
+ export declare const maximumParallelConcurrency = 256;
66
+ /**
67
+ * One resolved handler with immutable attribution.
68
+ *
69
+ * @category models
70
+ * @since 1.0.0-rc.0
71
+ */
72
+ export interface HandlerRecord {
73
+ readonly plugin: string;
74
+ readonly hook: string;
75
+ readonly handler: (...args: Array<any>) => unknown;
76
+ }
77
+ /**
78
+ * The immutable output of plugin resolution.
79
+ *
80
+ * @category models
81
+ * @since 1.0.0-rc.0
82
+ */
83
+ export interface Resolved<H = FlowsHooks> {
84
+ readonly plugins: ReadonlyArray<FlowsPlugin<H>>;
85
+ readonly handlers: ReadonlyMap<string, ReadonlyArray<HandlerRecord>>;
86
+ /** The frozen runtime catalog this resolution admitted. Dispatch refuses a method whose kind differs from it. */
87
+ readonly kinds: Readonly<Record<string, HookKind>>;
88
+ readonly parallelConcurrency: number;
89
+ readonly cacheEnvironment?: Action.CacheEnvironment | undefined;
90
+ }
91
+ /**
92
+ * Options for {@link resolve}.
93
+ *
94
+ * @category models
95
+ * @since 1.0.0-rc.0
96
+ */
97
+ export interface Options<H = FlowsHooks> {
98
+ /** Pre-resolution config tested by `apply` predicates. */
99
+ readonly config?: FlowsConfig | undefined;
100
+ /** Host whose literal `apply` selectors are active. Defaults to `"engine"`. */
101
+ readonly target?: "engine" | "harness" | undefined;
102
+ /**
103
+ * Hook names recognized by this host, each with the kind `H` declares for
104
+ * it. The shared `config` and `configResolved` hooks are fixed to
105
+ * `waterfall` and `parallel`; another kind fails with `hook_kind_mismatch`.
106
+ */
107
+ readonly hooks?: HookCatalog<H> | undefined;
108
+ /** Complete composition identity for sealed activity keys. Requires every selected plugin to have a version. */
109
+ readonly cacheEnvironment?: Action.CacheEnvironment | undefined;
110
+ /** Maximum observers run at once. Defaults to 16 and cannot exceed 256. */
111
+ readonly parallelConcurrency?: number | undefined;
112
+ }
113
+ /**
114
+ * Resolves a plugin preset into an immutable, resource-bounded catalog.
115
+ *
116
+ * @category constructors
117
+ * @since 1.0.0-rc.0
118
+ */
119
+ export declare const resolve: <H = FlowsHooks>(input: PluginInput<NoInfer<H>>, options?: Options<NoInfer<H>>, configOverride?: FlowsConfig) => Effect.Effect<Resolved<H>, PluginError>;
120
+ /**
121
+ * Merges every resolved plugin layer left-to-right and supplies the detached
122
+ * cache environment captured during resolution.
123
+ *
124
+ * @category combinators
125
+ * @since 1.0.0-rc.0
126
+ */
127
+ export declare const layer: <H>(resolved: Resolved<H>) => Layer.Layer<any, PluginError, any>;
128
+ //# sourceMappingURL=Resolve.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Resolve.d.ts","sourceRoot":"","sources":["../../src/Resolve.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,343 @@
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 Resolve_exports = {};
30
+ __export(Resolve_exports, {
31
+ defaultParallelConcurrency: () => defaultParallelConcurrency,
32
+ layer: () => layer,
33
+ maximumHandlers: () => maximumHandlers,
34
+ maximumParallelConcurrency: () => maximumParallelConcurrency,
35
+ maximumPluginDepth: () => maximumPluginDepth,
36
+ maximumPluginInputNodes: () => maximumPluginInputNodes,
37
+ maximumPluginNameLength: () => maximumPluginNameLength,
38
+ maximumPlugins: () => maximumPlugins,
39
+ resolve: () => resolve
40
+ });
41
+ module.exports = __toCommonJS(Resolve_exports);
42
+ var ImmutableMap = __toESM(require("@smthrs/canonical/ReadonlyMap"), 1);
43
+ var Effect = __toESM(require("effect/Effect"), 1);
44
+ var Layer = __toESM(require("effect/Layer"), 1);
45
+ var Config = __toESM(require("./Config.js"), 1);
46
+ var import_Hooks = require("./Hooks.js");
47
+ var Boundary = __toESM(require("./internal/Boundary.js"), 1);
48
+ var import_mergePluginLayers = require("./internal/mergePluginLayers.js");
49
+ var import_snapshotCacheEnvironment = require("./internal/snapshotCacheEnvironment.js");
50
+ var import_PluginError = require("./PluginError.js");
51
+ const maximumPluginDepth = 64;
52
+ const maximumPlugins = 256;
53
+ const maximumHandlers = 1024;
54
+ const maximumPluginInputNodes = 4096;
55
+ const maximumPluginNameLength = 256;
56
+ const defaultParallelConcurrency = 16;
57
+ const maximumParallelConcurrency = 256;
58
+ const failure = (code, message, path, fields = {}) => new import_PluginError.PluginError({ code, message, path, ...fields });
59
+ const invalidPlugin = (path, complaint, fields = {}) => failure("invalid_plugin", `plugin input ${complaint}`, path, fields);
60
+ const diagnosticKey = (key) => key.length > 64 ? `${key.slice(0, 64)}...` : key;
61
+ const childPath = (path, key) => {
62
+ const bounded = diagnosticKey(key);
63
+ return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(bounded) ? `${path}.${bounded}` : `${path}[${JSON.stringify(bounded)}]`;
64
+ };
65
+ const ownData = (input, path, allowed) => {
66
+ if (typeof input !== "object" || input === null || Array.isArray(input)) {
67
+ throw invalidPlugin(path, "must be an ordinary record");
68
+ }
69
+ const prototype = Object.getPrototypeOf(input);
70
+ if (prototype !== Object.prototype && prototype !== null) throw invalidPlugin(path, "must be an ordinary record");
71
+ const output = {};
72
+ for (const key of Reflect.ownKeys(input)) {
73
+ if (typeof key !== "string") throw invalidPlugin(path, "must not contain symbol keys");
74
+ if (allowed !== void 0 && !allowed.has(key)) {
75
+ throw invalidPlugin(childPath(path, key), "contains an unknown property");
76
+ }
77
+ const descriptor = Object.getOwnPropertyDescriptor(input, key);
78
+ if (descriptor === void 0 || !("value" in descriptor) || !descriptor.enumerable) {
79
+ throw invalidPlugin(childPath(path, key), "must be an enumerable data property");
80
+ }
81
+ Object.defineProperty(output, key, { value: descriptor.value, enumerable: true });
82
+ }
83
+ return output;
84
+ };
85
+ const snapshotOptions = (input) => {
86
+ const values = ownData(
87
+ input,
88
+ "$options",
89
+ /* @__PURE__ */ new Set(["config", "target", "hooks", "cacheEnvironment", "parallelConcurrency"])
90
+ );
91
+ return {
92
+ config: values.config,
93
+ target: values.target,
94
+ hooks: values.hooks,
95
+ cacheEnvironment: values.cacheEnvironment,
96
+ parallelConcurrency: values.parallelConcurrency
97
+ };
98
+ };
99
+ const validName = (value) => typeof value === "string" && value.length > 0 && value.length <= maximumPluginNameLength && Boundary.isWellFormedText(value) && !/^\s*$/u.test(value) && !/\p{Cc}/u.test(value);
100
+ const snapshotCatalog = (input) => {
101
+ if (typeof input !== "object" || input === null || Array.isArray(input)) {
102
+ throw invalidPlugin("$options.hooks", "must be an ordinary hook catalog");
103
+ }
104
+ const prototype = Object.getPrototypeOf(input);
105
+ if (prototype !== Object.prototype && prototype !== null) {
106
+ throw invalidPlugin("$options.hooks", "must be an ordinary hook catalog");
107
+ }
108
+ const output = {};
109
+ for (const key of Reflect.ownKeys(input)) {
110
+ if (typeof key !== "string" || !validName(key)) {
111
+ throw invalidPlugin("$options.hooks", "contains an invalid hook name");
112
+ }
113
+ const descriptor = Object.getOwnPropertyDescriptor(input, key);
114
+ if (descriptor === void 0 || !("value" in descriptor) || !descriptor.enumerable) {
115
+ throw invalidPlugin(childPath("$options.hooks", key), "must be an enumerable data property");
116
+ }
117
+ if (!["sequential", "parallel", "first", "waterfall"].includes(descriptor.value)) {
118
+ throw invalidPlugin(childPath("$options.hooks", key), "contains an invalid hook kind");
119
+ }
120
+ Object.defineProperty(output, key, { value: descriptor.value, enumerable: true });
121
+ }
122
+ for (const hook of Object.keys(import_Hooks.engineHooks)) {
123
+ if (Object.hasOwn(output, hook) && output[hook] !== import_Hooks.engineHooks[hook]) {
124
+ throw failure(
125
+ "hook_kind_mismatch",
126
+ `hook catalog declares shared hook ${JSON.stringify(hook)} as ${JSON.stringify(output[hook])}, the kernel dispatches it as ${JSON.stringify(import_Hooks.engineHooks[hook])}`,
127
+ childPath("$options.hooks", hook),
128
+ { hook }
129
+ );
130
+ }
131
+ }
132
+ return Object.freeze(output);
133
+ };
134
+ const snapshotHook = (entry, path, plugin, hook) => {
135
+ if (typeof entry === "function") return entry;
136
+ if (entry === void 0) {
137
+ throw invalidPlugin(path, "must be a function or a hook object", { plugin, hook });
138
+ }
139
+ const values = ownData(entry, path, /* @__PURE__ */ new Set(["order", "handler"]));
140
+ if (typeof values.handler !== "function") {
141
+ throw invalidPlugin(`${path}.handler`, "must be a function", { plugin, hook });
142
+ }
143
+ if (values.order !== void 0 && values.order !== "pre" && values.order !== "post") {
144
+ throw invalidPlugin(`${path}.order`, "must be pre or post", { plugin, hook });
145
+ }
146
+ return Object.freeze({
147
+ ...values.order === void 0 ? {} : { order: values.order },
148
+ handler: values.handler
149
+ });
150
+ };
151
+ const snapshotPlugin = (input, path) => {
152
+ const values = ownData(input, path, /* @__PURE__ */ new Set(["name", "version", "enforce", "apply", "layer", "hooks"]));
153
+ if (!validName(values.name)) throw invalidPlugin(`${path}.name`, "requires a bounded non-empty name");
154
+ const name = values.name;
155
+ if (values.version !== void 0 && !validName(values.version)) {
156
+ throw invalidPlugin(`${path}.version`, "requires a bounded non-empty version", { plugin: name });
157
+ }
158
+ if (values.enforce !== void 0 && values.enforce !== "pre" && values.enforce !== "post") {
159
+ throw invalidPlugin(`${path}.enforce`, "must be pre or post", { plugin: name });
160
+ }
161
+ if (values.apply !== void 0 && values.apply !== "engine" && values.apply !== "harness" && typeof values.apply !== "function") throw invalidPlugin(`${path}.apply`, "must be engine, harness, or a predicate", { plugin: name });
162
+ if (values.layer !== void 0 && !Layer.isLayer(values.layer)) {
163
+ throw invalidPlugin(`${path}.layer`, "must be an Effect Layer", { plugin: name });
164
+ }
165
+ let hooks;
166
+ if (values.hooks !== void 0) {
167
+ const rawHooks = ownData(values.hooks, `${path}.hooks`);
168
+ const snapshot = /* @__PURE__ */ Object.create(null);
169
+ for (const [index, hook] of Object.keys(rawHooks).entries()) {
170
+ if (!validName(hook)) {
171
+ throw invalidPlugin(`${path}.hooks[${index}]`, "contains an invalid hook name");
172
+ }
173
+ const entry = rawHooks[hook];
174
+ Object.defineProperty(snapshot, hook, {
175
+ value: snapshotHook(entry, childPath(`${path}.hooks`, hook), name, hook),
176
+ enumerable: true
177
+ });
178
+ }
179
+ hooks = Object.freeze(snapshot);
180
+ }
181
+ return Object.freeze({
182
+ name,
183
+ ...values.version === void 0 ? {} : { version: values.version },
184
+ ...values.enforce === void 0 ? {} : { enforce: values.enforce },
185
+ ...values.apply === void 0 ? {} : { apply: values.apply },
186
+ ...values.layer === void 0 ? {} : { layer: values.layer },
187
+ ...hooks === void 0 ? {} : { hooks }
188
+ });
189
+ };
190
+ const flatten = (input) => {
191
+ const output = [];
192
+ const arrays = /* @__PURE__ */ new WeakSet();
193
+ const stack = [
194
+ { value: input, path: "$", depth: 0 }
195
+ ];
196
+ let nodes = 0;
197
+ while (stack.length > 0) {
198
+ const current = stack.pop();
199
+ nodes += 1;
200
+ if (current.value === false || current.value === null || current.value === void 0) continue;
201
+ if (Array.isArray(current.value)) {
202
+ if (current.depth >= maximumPluginDepth) {
203
+ throw failure("resource_limit", `plugin input exceeds the depth limit of ${maximumPluginDepth}`, current.path);
204
+ }
205
+ if (arrays.has(current.value)) throw invalidPlugin(current.path, "contains a cycle or repeated preset array");
206
+ arrays.add(current.value);
207
+ const length = current.value.length;
208
+ if (length > maximumPluginInputNodes - nodes - stack.length) {
209
+ throw failure("resource_limit", `plugin input exceeds the ${maximumPluginInputNodes}-node limit`, current.path);
210
+ }
211
+ const keys = Reflect.ownKeys(current.value);
212
+ if (keys.length !== length + 1 || !keys.includes("length")) {
213
+ throw invalidPlugin(current.path, "must be a dense preset array with no extra properties");
214
+ }
215
+ for (let index = length - 1; index >= 0; index--) {
216
+ const descriptor = Object.getOwnPropertyDescriptor(current.value, String(index));
217
+ if (descriptor === void 0 || !("value" in descriptor) || !descriptor.enumerable) {
218
+ throw invalidPlugin(`${current.path}[${index}]`, "must be an enumerable data property");
219
+ }
220
+ stack.push({ value: descriptor.value, path: `${current.path}[${index}]`, depth: current.depth + 1 });
221
+ }
222
+ continue;
223
+ }
224
+ output.push(Object.freeze({ plugin: snapshotPlugin(current.value, current.path), path: current.path }));
225
+ if (output.length > maximumPlugins) {
226
+ throw failure("resource_limit", `plugin input exceeds the ${maximumPlugins}-plugin limit`, current.path);
227
+ }
228
+ }
229
+ return output;
230
+ };
231
+ const included = (plugin, config, target) => {
232
+ const apply = plugin.apply;
233
+ if (apply === void 0) return Effect.succeed(true);
234
+ if (typeof apply !== "function") return Effect.succeed(apply === target);
235
+ return Effect.try({
236
+ try: () => apply(config),
237
+ catch: () => failure("apply_failed", `plugin "${plugin.name}" apply predicate failed`, "$.apply", {
238
+ plugin: plugin.name
239
+ })
240
+ }).pipe(
241
+ Effect.flatMap(
242
+ (result) => typeof result === "boolean" ? Effect.succeed(result) : Effect.fail(invalidPlugin("$.apply", "predicate must return a boolean", { plugin: plugin.name }))
243
+ )
244
+ );
245
+ };
246
+ const rank = (enforce) => enforce === "pre" ? 0 : enforce === "post" ? 2 : 1;
247
+ const resolve = (input, options = {}, configOverride) => Effect.gen(function* () {
248
+ const raw = yield* Effect.try({
249
+ try: () => snapshotOptions(options),
250
+ catch: (cause) => cause instanceof import_PluginError.PluginError ? cause : invalidPlugin("$options", "could not be inspected without executing user code")
251
+ });
252
+ if (configOverride !== void 0 && raw.config !== void 0) {
253
+ return yield* Effect.fail(invalidPlugin(
254
+ "$options.config",
255
+ "cannot declare config in options alongside the positional override"
256
+ ));
257
+ }
258
+ if (raw.target !== void 0 && raw.target !== "engine" && raw.target !== "harness") {
259
+ return yield* Effect.fail(invalidPlugin("$options.target", "must be engine or harness"));
260
+ }
261
+ if (raw.parallelConcurrency !== void 0 && (typeof raw.parallelConcurrency !== "number" || !Number.isSafeInteger(raw.parallelConcurrency) || raw.parallelConcurrency <= 0 || raw.parallelConcurrency > maximumParallelConcurrency)) {
262
+ return yield* Effect.fail(failure(
263
+ "resource_limit",
264
+ `parallel concurrency must be between 1 and ${maximumParallelConcurrency}`,
265
+ "$options.parallelConcurrency"
266
+ ));
267
+ }
268
+ const parallelConcurrency = raw.parallelConcurrency === void 0 ? defaultParallelConcurrency : raw.parallelConcurrency;
269
+ const config = yield* Config.snapshot(configOverride ?? raw.config ?? {});
270
+ const known = yield* Effect.try({
271
+ try: () => snapshotCatalog(raw.hooks ?? import_Hooks.engineHooks),
272
+ catch: (cause) => cause instanceof import_PluginError.PluginError ? cause : invalidPlugin("$options.hooks", "could not be inspected without executing user code")
273
+ });
274
+ const admitted = yield* Effect.try({
275
+ try: () => flatten(input),
276
+ catch: (cause) => cause instanceof import_PluginError.PluginError ? cause : invalidPlugin("$", "could not be inspected without executing user code")
277
+ });
278
+ const target = raw.target ?? "engine";
279
+ const selected = yield* Effect.filter(admitted, ({ plugin }) => included(plugin, config, target));
280
+ let handlerCount = 0;
281
+ for (const { path, plugin } of selected) {
282
+ const pluginHooks = plugin.hooks;
283
+ if (pluginHooks === void 0) continue;
284
+ for (const hook of Object.keys(pluginHooks)) {
285
+ if (!Object.hasOwn(known, hook)) {
286
+ return yield* Effect.fail(failure(
287
+ "unknown_hook",
288
+ `plugin ${JSON.stringify(plugin.name)} declares unknown hook ${JSON.stringify(diagnosticKey(hook))}`,
289
+ childPath(`${path}.hooks`, hook),
290
+ { plugin: plugin.name, hook }
291
+ ));
292
+ }
293
+ handlerCount += 1;
294
+ if (handlerCount > maximumHandlers) {
295
+ return yield* Effect.fail(failure(
296
+ "resource_limit",
297
+ `plugin handlers exceed the limit of ${maximumHandlers}`,
298
+ childPath(`${path}.hooks`, hook)
299
+ ));
300
+ }
301
+ }
302
+ }
303
+ const seen = /* @__PURE__ */ new Set();
304
+ for (const { plugin } of selected) {
305
+ if (seen.has(plugin.name)) {
306
+ return yield* Effect.fail(failure(
307
+ "duplicate_name",
308
+ `duplicate plugin name "${plugin.name}"`,
309
+ "$.name",
310
+ { plugin: plugin.name }
311
+ ));
312
+ }
313
+ seen.add(plugin.name);
314
+ }
315
+ const plugins = Object.freeze(
316
+ selected.map(({ plugin }, index) => ({ plugin, index })).sort((left, right) => rank(left.plugin.enforce) - rank(right.plugin.enforce) || left.index - right.index).map(({ plugin }) => plugin)
317
+ );
318
+ const entries = [];
319
+ for (const hook of Object.keys(known)) {
320
+ const records = [];
321
+ for (const [index, plugin] of plugins.entries()) {
322
+ const pluginHooks = plugin.hooks;
323
+ if (pluginHooks === void 0 || !Object.hasOwn(pluginHooks, hook)) continue;
324
+ const entry = pluginHooks[hook];
325
+ const record = Object.freeze({ plugin: plugin.name, hook, handler: (0, import_Hooks.handlerOf)(entry) });
326
+ records.push({ record, enforceRank: rank(plugin.enforce), orderRank: rank((0, import_Hooks.orderOf)(entry)), index });
327
+ }
328
+ const ordered = records.sort(
329
+ (left, right) => left.orderRank - right.orderRank || left.enforceRank - right.enforceRank || left.index - right.index
330
+ ).map(({ record }) => record);
331
+ if (ordered.length > 0) entries.push([hook, Object.freeze(ordered)]);
332
+ }
333
+ const cacheEnvironment = yield* (0, import_snapshotCacheEnvironment.snapshotCacheEnvironment)(raw.cacheEnvironment, plugins);
334
+ return Object.freeze({
335
+ plugins,
336
+ handlers: ImmutableMap.make(entries),
337
+ kinds: known,
338
+ parallelConcurrency,
339
+ ...cacheEnvironment === void 0 ? {} : { cacheEnvironment }
340
+ });
341
+ });
342
+ const layer = (resolved) => (0, import_mergePluginLayers.mergePluginLayers)(resolved.plugins, resolved.cacheEnvironment);
343
+ //# sourceMappingURL=Resolve.js.map