@executor-js/config 0.1.0 → 1.4.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +87 -46
- package/dist/index.js.map +1 -1
- package/dist/load-plugins.d.ts +8 -0
- package/dist/load-plugins.d.ts.map +1 -1
- package/dist/load.d.ts +7 -6
- package/dist/load.d.ts.map +1 -1
- package/dist/sink.d.ts.map +1 -1
- package/dist/write.d.ts +7 -1
- package/dist/write.d.ts.map +1 -1
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -4,5 +4,5 @@ export { loadPluginsFromJsonc } from "./load-plugins";
|
|
|
4
4
|
export type { LoadPluginsFromJsoncOptions } from "./load-plugins";
|
|
5
5
|
export { addSourceToConfig, removeSourceFromConfig, writeConfig, addSecretToConfig, removeSecretFromConfig, } from "./write";
|
|
6
6
|
export type { ConfigFileSink, ConfigFileSinkOptions } from "./sink";
|
|
7
|
-
export { makeFileConfigSink, headerToConfigValue, headersToConfigValues
|
|
7
|
+
export { makeFileConfigSink, headerToConfigValue, headersToConfigValues } from "./sink";
|
|
8
8
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,YAAY,EACZ,YAAY,EACZ,mBAAmB,EACnB,mBAAmB,EACnB,qBAAqB,EACrB,oBAAoB,EACpB,aAAa,EACb,cAAc,EACd,iBAAiB,EACjB,iBAAiB,GAClB,MAAM,UAAU,CAAC;AAElB,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,QAAQ,CAAC;AACtD,OAAO,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AACtD,YAAY,EAAE,2BAA2B,EAAE,MAAM,gBAAgB,CAAC;AAElE,OAAO,EACL,iBAAiB,EACjB,sBAAsB,EACtB,WAAW,EACX,iBAAiB,EACjB,sBAAsB,GACvB,MAAM,SAAS,CAAC;AAEjB,YAAY,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,QAAQ,CAAC;AACpE,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,YAAY,EACZ,YAAY,EACZ,mBAAmB,EACnB,mBAAmB,EACnB,qBAAqB,EACrB,oBAAoB,EACpB,aAAa,EACb,cAAc,EACd,iBAAiB,EACjB,iBAAiB,GAClB,MAAM,UAAU,CAAC;AAElB,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,QAAQ,CAAC;AACtD,OAAO,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AACtD,YAAY,EAAE,2BAA2B,EAAE,MAAM,gBAAgB,CAAC;AAElE,OAAO,EACL,iBAAiB,EACjB,sBAAsB,EACtB,WAAW,EACX,iBAAiB,EACjB,sBAAsB,GACvB,MAAM,SAAS,CAAC;AAEjB,YAAY,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,QAAQ,CAAC;AACpE,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,QAAQ,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -88,14 +88,13 @@ var ExecutorFileConfig = Schema.Struct({
|
|
|
88
88
|
import { Effect, Schema as Schema2 } from "effect";
|
|
89
89
|
import { FileSystem } from "effect";
|
|
90
90
|
import * as jsonc from "jsonc-parser";
|
|
91
|
-
var ConfigParseError = class
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
91
|
+
var ConfigParseError = class extends Schema2.TaggedErrorClass()(
|
|
92
|
+
"ConfigParseError",
|
|
93
|
+
{
|
|
94
|
+
path: Schema2.String,
|
|
95
|
+
message: Schema2.String
|
|
95
96
|
}
|
|
96
|
-
|
|
97
|
-
message;
|
|
98
|
-
_tag = "ConfigParseError";
|
|
97
|
+
) {
|
|
99
98
|
};
|
|
100
99
|
var loadConfig = (path) => Effect.gen(function* () {
|
|
101
100
|
const fs2 = yield* FileSystem.FileSystem;
|
|
@@ -106,10 +105,15 @@ var loadConfig = (path) => Effect.gen(function* () {
|
|
|
106
105
|
const parsed = jsonc.parse(raw, errors);
|
|
107
106
|
if (errors.length > 0) {
|
|
108
107
|
const msg = errors.map((e) => `offset ${e.offset}: ${jsonc.printParseErrorCode(e.error)}`).join("; ");
|
|
109
|
-
return yield*
|
|
108
|
+
return yield* new ConfigParseError({ path, message: msg });
|
|
110
109
|
}
|
|
111
110
|
const decoded = yield* Schema2.decodeUnknownEffect(ExecutorFileConfig)(parsed).pipe(
|
|
112
|
-
Effect.mapError(
|
|
111
|
+
Effect.mapError(
|
|
112
|
+
(error) => new ConfigParseError({
|
|
113
|
+
path,
|
|
114
|
+
message: error.issue.toString()
|
|
115
|
+
})
|
|
116
|
+
)
|
|
113
117
|
);
|
|
114
118
|
return decoded;
|
|
115
119
|
});
|
|
@@ -120,7 +124,17 @@ import { dirname, isAbsolute, resolve as resolvePath } from "path";
|
|
|
120
124
|
import { pathToFileURL } from "url";
|
|
121
125
|
import * as fs from "fs";
|
|
122
126
|
import * as jsonc2 from "jsonc-parser";
|
|
123
|
-
|
|
127
|
+
import { Effect as Effect2, Schema as Schema3 } from "effect";
|
|
128
|
+
var LoadPluginsError = class extends Schema3.TaggedErrorClass()(
|
|
129
|
+
"LoadPluginsError",
|
|
130
|
+
{
|
|
131
|
+
message: Schema3.String,
|
|
132
|
+
cause: Schema3.optional(Schema3.Unknown)
|
|
133
|
+
}
|
|
134
|
+
) {
|
|
135
|
+
};
|
|
136
|
+
var loadPluginsFromJsonc = async (options) => Effect2.runPromise(loadPluginsFromJsoncEffect(options));
|
|
137
|
+
var loadPluginsFromJsoncEffect = (options) => Effect2.gen(function* () {
|
|
124
138
|
const { path, deps } = options;
|
|
125
139
|
if (!fs.existsSync(path)) return null;
|
|
126
140
|
const raw = fs.readFileSync(path, "utf8");
|
|
@@ -128,47 +142,75 @@ var loadPluginsFromJsonc = async (options) => {
|
|
|
128
142
|
const parsed = jsonc2.parse(raw, errors);
|
|
129
143
|
if (errors.length > 0) {
|
|
130
144
|
const msg = errors.map((e) => `offset ${e.offset}: ${jsonc2.printParseErrorCode(e.error)}`).join("; ");
|
|
131
|
-
|
|
145
|
+
return yield* new LoadPluginsError({
|
|
146
|
+
message: `[load-plugins] failed to parse ${path}: ${msg}`
|
|
147
|
+
});
|
|
132
148
|
}
|
|
133
|
-
const
|
|
149
|
+
const config = yield* Schema3.decodeUnknownEffect(ExecutorFileConfig)(parsed).pipe(
|
|
150
|
+
Effect2.mapError(
|
|
151
|
+
(error) => new LoadPluginsError({
|
|
152
|
+
message: `[load-plugins] failed to decode ${path}: ${error.issue.toString()}`,
|
|
153
|
+
cause: error
|
|
154
|
+
})
|
|
155
|
+
)
|
|
156
|
+
);
|
|
157
|
+
const entries = config.plugins ?? null;
|
|
134
158
|
if (!entries || entries.length === 0) return null;
|
|
135
|
-
const { createJiti } =
|
|
159
|
+
const { createJiti } = yield* Effect2.tryPromise({
|
|
160
|
+
try: () => import("jiti"),
|
|
161
|
+
catch: (cause) => new LoadPluginsError({
|
|
162
|
+
message: `[load-plugins] failed to import jiti.`,
|
|
163
|
+
cause
|
|
164
|
+
})
|
|
165
|
+
});
|
|
136
166
|
const jiti = createJiti(pathToFileURL(path).href, {
|
|
137
167
|
interopDefault: true,
|
|
138
168
|
moduleCache: false
|
|
139
169
|
});
|
|
140
170
|
const fromDir = dirname(path);
|
|
141
|
-
const require2 = createRequire(
|
|
142
|
-
isAbsolute(path) ? path : resolvePath(fromDir, "_anchor.js")
|
|
143
|
-
);
|
|
171
|
+
const require2 = createRequire(isAbsolute(path) ? path : resolvePath(fromDir, "_anchor.js"));
|
|
144
172
|
const loaded = [];
|
|
145
173
|
for (const entry of entries) {
|
|
146
174
|
const serverEntry = `${entry.package}/server`;
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
175
|
+
const resolved = yield* Effect2.try({
|
|
176
|
+
try: () => require2.resolve(serverEntry),
|
|
177
|
+
catch: (cause) => new LoadPluginsError({
|
|
178
|
+
message: `[load-plugins] cannot resolve "${serverEntry}" from ${fromDir}. Is "${entry.package}" installed and does it export "./server"?`,
|
|
179
|
+
cause
|
|
180
|
+
})
|
|
181
|
+
});
|
|
182
|
+
const mod = yield* Effect2.tryPromise({
|
|
183
|
+
try: () => jiti.import(resolved),
|
|
184
|
+
catch: (cause) => new LoadPluginsError({
|
|
185
|
+
message: `[load-plugins] failed to import "${serverEntry}" from ${resolved}.`,
|
|
186
|
+
cause
|
|
187
|
+
})
|
|
188
|
+
});
|
|
156
189
|
const factory = typeof mod === "function" ? mod : mod.default ?? null;
|
|
157
190
|
if (!factory || typeof factory !== "function") {
|
|
158
|
-
|
|
159
|
-
`[load-plugins] "${serverEntry}" did not export a default definePlugin(...) factory.`
|
|
160
|
-
);
|
|
191
|
+
return yield* new LoadPluginsError({
|
|
192
|
+
message: `[load-plugins] "${serverEntry}" did not export a default definePlugin(...) factory.`
|
|
193
|
+
});
|
|
161
194
|
}
|
|
162
195
|
const merged = { ...deps ?? {}, ...entry.options ?? {} };
|
|
163
196
|
loaded.push(factory(merged));
|
|
164
197
|
}
|
|
165
198
|
return loaded;
|
|
166
|
-
};
|
|
199
|
+
});
|
|
167
200
|
|
|
168
201
|
// src/write.ts
|
|
169
|
-
import { Effect as
|
|
202
|
+
import { Effect as Effect3 } from "effect";
|
|
170
203
|
import { FileSystem as FileSystem2 } from "effect";
|
|
171
204
|
import * as jsonc3 from "jsonc-parser";
|
|
205
|
+
var ConfigWriteError = class {
|
|
206
|
+
constructor(path, cause) {
|
|
207
|
+
this.path = path;
|
|
208
|
+
this.cause = cause;
|
|
209
|
+
}
|
|
210
|
+
path;
|
|
211
|
+
cause;
|
|
212
|
+
_tag = "ConfigWriteError";
|
|
213
|
+
};
|
|
172
214
|
var FORMATTING = {
|
|
173
215
|
tabSize: 2,
|
|
174
216
|
insertSpaces: true,
|
|
@@ -178,13 +220,13 @@ var DEFAULT_CONFIG = `{
|
|
|
178
220
|
"sources": []
|
|
179
221
|
}
|
|
180
222
|
`;
|
|
181
|
-
var readOrCreate = (fs2, path) =>
|
|
223
|
+
var readOrCreate = (fs2, path) => Effect3.gen(function* () {
|
|
182
224
|
const exists = yield* fs2.exists(path);
|
|
183
225
|
if (exists) return yield* fs2.readFileString(path);
|
|
184
226
|
yield* fs2.writeFileString(path, DEFAULT_CONFIG);
|
|
185
227
|
return DEFAULT_CONFIG;
|
|
186
228
|
});
|
|
187
|
-
var addSourceToConfig = (path, source) =>
|
|
229
|
+
var addSourceToConfig = (path, source) => Effect3.gen(function* () {
|
|
188
230
|
const fs2 = yield* FileSystem2.FileSystem;
|
|
189
231
|
let text = yield* readOrCreate(fs2, path);
|
|
190
232
|
let tree = jsonc3.parseTree(text);
|
|
@@ -218,7 +260,7 @@ var addSourceToConfig = (path, source) => Effect2.gen(function* () {
|
|
|
218
260
|
}
|
|
219
261
|
yield* fs2.writeFileString(path, text);
|
|
220
262
|
});
|
|
221
|
-
var removeSourceFromConfig = (path, namespace) =>
|
|
263
|
+
var removeSourceFromConfig = (path, namespace) => Effect3.gen(function* () {
|
|
222
264
|
const fs2 = yield* FileSystem2.FileSystem;
|
|
223
265
|
const exists = yield* fs2.exists(path);
|
|
224
266
|
if (!exists) return;
|
|
@@ -239,15 +281,15 @@ var removeSourceFromConfig = (path, namespace) => Effect2.gen(function* () {
|
|
|
239
281
|
}
|
|
240
282
|
yield* fs2.writeFileString(path, text);
|
|
241
283
|
});
|
|
242
|
-
var writeConfig = (path, config) =>
|
|
284
|
+
var writeConfig = (path, config) => Effect3.gen(function* () {
|
|
243
285
|
const fs2 = yield* FileSystem2.FileSystem;
|
|
244
|
-
const text = yield*
|
|
286
|
+
const text = yield* Effect3.try({
|
|
245
287
|
try: () => JSON.stringify(config, null, 2) + "\n",
|
|
246
|
-
catch: (cause) => cause
|
|
247
|
-
})
|
|
288
|
+
catch: (cause) => new ConfigWriteError(path, cause)
|
|
289
|
+
});
|
|
248
290
|
yield* fs2.writeFileString(path, text);
|
|
249
291
|
});
|
|
250
|
-
var addSecretToConfig = (path, secretId, metadata) =>
|
|
292
|
+
var addSecretToConfig = (path, secretId, metadata) => Effect3.gen(function* () {
|
|
251
293
|
const fs2 = yield* FileSystem2.FileSystem;
|
|
252
294
|
let text = yield* readOrCreate(fs2, path);
|
|
253
295
|
const edits = jsonc3.modify(text, ["secrets", secretId], metadata, {
|
|
@@ -256,7 +298,7 @@ var addSecretToConfig = (path, secretId, metadata) => Effect2.gen(function* () {
|
|
|
256
298
|
text = jsonc3.applyEdits(text, edits);
|
|
257
299
|
yield* fs2.writeFileString(path, text);
|
|
258
300
|
});
|
|
259
|
-
var removeSecretFromConfig = (path, secretId) =>
|
|
301
|
+
var removeSecretFromConfig = (path, secretId) => Effect3.gen(function* () {
|
|
260
302
|
const fs2 = yield* FileSystem2.FileSystem;
|
|
261
303
|
const exists = yield* fs2.exists(path);
|
|
262
304
|
if (!exists) return;
|
|
@@ -269,7 +311,7 @@ var removeSecretFromConfig = (path, secretId) => Effect2.gen(function* () {
|
|
|
269
311
|
});
|
|
270
312
|
|
|
271
313
|
// src/sink.ts
|
|
272
|
-
import { Effect as
|
|
314
|
+
import { Effect as Effect4 } from "effect";
|
|
273
315
|
var headerToConfigValue = (value) => {
|
|
274
316
|
if (typeof value === "string") return value;
|
|
275
317
|
const ref = `${SECRET_REF_PREFIX}${value.secretId}`;
|
|
@@ -282,19 +324,18 @@ var headersToConfigValues = (headers) => {
|
|
|
282
324
|
return out;
|
|
283
325
|
};
|
|
284
326
|
var defaultOnError = (op, err) => {
|
|
285
|
-
|
|
286
|
-
console.warn(`[config-sink] ${op} failed: ${msg}`);
|
|
327
|
+
console.warn(`[config-sink] ${op} failed`, err);
|
|
287
328
|
};
|
|
288
329
|
var makeFileConfigSink = (options) => {
|
|
289
330
|
const { path, fsLayer, onError = defaultOnError } = options;
|
|
290
331
|
return {
|
|
291
332
|
upsertSource: (source) => addSourceToConfig(path, source).pipe(
|
|
292
|
-
|
|
293
|
-
|
|
333
|
+
Effect4.provide(fsLayer),
|
|
334
|
+
Effect4.catch((err) => Effect4.sync(() => onError("upsert", err)))
|
|
294
335
|
),
|
|
295
336
|
removeSource: (namespace) => removeSourceFromConfig(path, namespace).pipe(
|
|
296
|
-
|
|
297
|
-
|
|
337
|
+
Effect4.provide(fsLayer),
|
|
338
|
+
Effect4.catch((err) => Effect4.sync(() => onError("remove", err)))
|
|
298
339
|
)
|
|
299
340
|
};
|
|
300
341
|
};
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/schema.ts","../src/load.ts","../src/load-plugins.ts","../src/write.ts","../src/sink.ts"],"sourcesContent":["import { Schema } from \"effect\";\n\n// ---------------------------------------------------------------------------\n// Header values\n//\n// Three forms:\n// \"static-value\" — literal string\n// \"secret-public-ref:my-token\" — secret reference (no prefix)\n// { value: \"secret-public-ref:x\", prefix } — secret reference with prefix\n// ---------------------------------------------------------------------------\n\nexport const SECRET_REF_PREFIX = \"secret-public-ref:\";\n\nexport const ConfigHeaderValue = Schema.Union([\n Schema.String,\n Schema.Struct({\n value: Schema.String,\n prefix: Schema.optional(Schema.String),\n }),\n]);\nexport type ConfigHeaderValue = typeof ConfigHeaderValue.Type;\n\nconst ConfigHeaders = Schema.Record(Schema.String, ConfigHeaderValue);\n\n// ---------------------------------------------------------------------------\n// Source configs — discriminated union on \"kind\"\n// ---------------------------------------------------------------------------\n\nexport const OpenApiSourceConfig = Schema.Struct({\n kind: Schema.Literal(\"openapi\"),\n spec: Schema.String,\n baseUrl: Schema.optional(Schema.String),\n namespace: Schema.optional(Schema.String),\n headers: Schema.optional(ConfigHeaders),\n});\nexport type OpenApiSourceConfig = typeof OpenApiSourceConfig.Type;\n\nexport const GraphqlSourceConfig = Schema.Struct({\n kind: Schema.Literal(\"graphql\"),\n endpoint: Schema.String,\n introspectionJson: Schema.optional(Schema.NullOr(Schema.String)),\n namespace: Schema.optional(Schema.String),\n headers: Schema.optional(ConfigHeaders),\n});\nexport type GraphqlSourceConfig = typeof GraphqlSourceConfig.Type;\n\nconst StringMap = Schema.Record(Schema.String, Schema.String);\n\nexport const McpAuthConfig = Schema.Union([\n Schema.Struct({ kind: Schema.Literal(\"none\") }),\n Schema.Struct({\n kind: Schema.Literal(\"header\"),\n headerName: Schema.String,\n secret: Schema.String,\n prefix: Schema.optional(Schema.String),\n }),\n Schema.Struct({\n kind: Schema.Literal(\"oauth2\"),\n /** Stable id of the SDK Connection holding access + refresh token\n * material. Scope shadowing means the same id resolves per-user\n * via the executor's innermost-wins lookup. */\n connectionId: Schema.String,\n }),\n]);\nexport type McpAuthConfig = typeof McpAuthConfig.Type;\n\nexport const McpRemoteSourceConfig = Schema.Struct({\n kind: Schema.Literal(\"mcp\"),\n transport: Schema.Literal(\"remote\"),\n name: Schema.String,\n endpoint: Schema.String,\n remoteTransport: Schema.optional(Schema.Literals([\"streamable-http\", \"sse\", \"auto\"])),\n namespace: Schema.optional(Schema.String),\n queryParams: Schema.optional(StringMap),\n headers: Schema.optional(StringMap),\n auth: Schema.optional(McpAuthConfig),\n});\nexport type McpRemoteSourceConfig = typeof McpRemoteSourceConfig.Type;\n\nexport const McpStdioSourceConfig = Schema.Struct({\n kind: Schema.Literal(\"mcp\"),\n transport: Schema.Literal(\"stdio\"),\n name: Schema.String,\n command: Schema.String,\n args: Schema.optional(Schema.Array(Schema.String)),\n env: Schema.optional(StringMap),\n cwd: Schema.optional(Schema.String),\n namespace: Schema.optional(Schema.String),\n});\nexport type McpStdioSourceConfig = typeof McpStdioSourceConfig.Type;\n\nexport const SourceConfig = Schema.Union([\n OpenApiSourceConfig,\n GraphqlSourceConfig,\n McpRemoteSourceConfig,\n McpStdioSourceConfig,\n]);\nexport type SourceConfig = typeof SourceConfig.Type;\n\n// ---------------------------------------------------------------------------\n// Secret metadata\n// ---------------------------------------------------------------------------\n\nexport const SecretMetadata = Schema.Struct({\n name: Schema.String,\n provider: Schema.optional(Schema.String),\n purpose: Schema.optional(Schema.String),\n});\nexport type SecretMetadata = typeof SecretMetadata.Type;\n\n// ---------------------------------------------------------------------------\n// Plugin manifest\n//\n// `plugins` is the install list. Each entry is a published npm package\n// that exports a `definePlugin(...)` factory under `./server`. The host\n// loads each at boot via jiti and calls the factory with merged\n// `options` plus host-injected deps (`configFile`, etc.). This is the\n// dynamic sibling of the static `executor.config.ts` plugin tuple — when\n// `plugins` is set, the host uses it; otherwise it falls back to the\n// statically-typed config.\n// ---------------------------------------------------------------------------\n\nexport const PluginConfig = Schema.Struct({\n package: Schema.String,\n options: Schema.optional(Schema.Record(Schema.String, Schema.Unknown)),\n});\nexport type PluginConfig = typeof PluginConfig.Type;\n\n// ---------------------------------------------------------------------------\n// Top-level config\n// ---------------------------------------------------------------------------\n\nexport const ExecutorFileConfig = Schema.Struct({\n $schema: Schema.optional(Schema.String),\n name: Schema.optional(Schema.String),\n plugins: Schema.optional(Schema.Array(PluginConfig)),\n sources: Schema.optional(Schema.Array(SourceConfig)),\n secrets: Schema.optional(Schema.Record(Schema.String, SecretMetadata)),\n});\nexport type ExecutorFileConfig = typeof ExecutorFileConfig.Type;\n","import { Effect, Schema } from \"effect\";\nimport { FileSystem } from \"effect\";\nimport type { PlatformError } from \"effect/PlatformError\";\nimport * as jsonc from \"jsonc-parser\";\nimport { ExecutorFileConfig } from \"./schema\";\n\nexport class ConfigParseError {\n readonly _tag = \"ConfigParseError\";\n constructor(\n readonly path: string,\n readonly message: string,\n ) {}\n}\n\n/**\n * Load and validate an executor config file.\n * Returns null if the file doesn't exist.\n */\nexport const loadConfig = (\n path: string,\n): Effect.Effect<\n ExecutorFileConfig | null,\n ConfigParseError | PlatformError,\n FileSystem.FileSystem\n> =>\n Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n\n const exists = yield* fs.exists(path);\n if (!exists) return null;\n\n const raw = yield* fs.readFileString(path);\n\n const errors: jsonc.ParseError[] = [];\n const parsed = jsonc.parse(raw, errors);\n\n if (errors.length > 0) {\n const msg = errors\n .map((e) => `offset ${e.offset}: ${jsonc.printParseErrorCode(e.error)}`)\n .join(\"; \");\n return yield* Effect.fail(new ConfigParseError(path, msg));\n }\n\n const decoded = yield* Schema.decodeUnknownEffect(ExecutorFileConfig)(parsed).pipe(\n Effect.mapError((e) => new ConfigParseError(path, String(e))),\n );\n\n return decoded;\n });\n","// ---------------------------------------------------------------------------\n// loadPluginsFromJsonc — runtime plugin loader.\n//\n// Reads `executor.jsonc#plugins`, dynamically imports each package's\n// `./server` entry via jiti (so workspace TS sources work in dev and\n// published `dist/*.js` works after install), and calls the exported\n// `definePlugin(...)` factory with merged `options` plus host-injected\n// deps. Returns the resulting `Plugin[]` ready to hand to\n// `composePluginApi` / `createExecutor`.\n//\n// jiti is used instead of bare `import()` because:\n// - workspace plugins under monorepo dev expose `.ts` source via the\n// `bun` export condition; Node's loader can't read those directly,\n// jiti transpiles on the fly.\n// - in a published environment the package's `default` condition\n// points at `dist/*.js`, which jiti loads as a normal ESM module.\n//\n// The convention is: every plugin package exports a `./server` subpath\n// whose default export is a `ConfiguredPlugin` (the result of\n// `definePlugin(...)`). Calling that with `{ ...options, ...deps }`\n// returns a concrete `Plugin`.\n// ---------------------------------------------------------------------------\n\nimport { createRequire } from \"node:module\";\nimport { dirname, isAbsolute, resolve as resolvePath } from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\nimport * as fs from \"node:fs\";\nimport * as jsonc from \"jsonc-parser\";\n\nimport type { AnyPlugin } from \"@executor-js/sdk\";\n\n// Plugins are invoked dynamically by name — exact author types are\n// unknown at the call site, so the loader treats every factory as\n// `(options?: unknown) => AnyPlugin`. The plugin author's types still\n// hold inside the plugin's own module; we just don't propagate them\n// across the runtime boundary.\ntype LooseConfiguredPlugin = (options?: Record<string, unknown>) => AnyPlugin;\n\nimport type { PluginConfig } from \"./schema\";\n\nexport interface LoadPluginsFromJsoncOptions {\n /** Absolute path to `executor.jsonc` (or compatible). */\n readonly path: string;\n /**\n * Host-injected deps merged into each plugin's options. Common keys:\n * `configFile` (the `ConfigFileSink`), env-derived credentials, etc.\n * Plugins ignore deps they don't accept — `definePlugin` strips\n * unknown keys before forwarding to the author factory.\n */\n readonly deps?: Readonly<Record<string, unknown>>;\n}\n\n/**\n * Returns the plugins listed in jsonc, or `null` if the file is missing\n * or has no `plugins` array. The host treats `null` as \"fall back to\n * the static `executor.config.ts` factory.\"\n */\nexport const loadPluginsFromJsonc = async (\n options: LoadPluginsFromJsoncOptions,\n): Promise<readonly AnyPlugin[] | null> => {\n const { path, deps } = options;\n if (!fs.existsSync(path)) return null;\n\n const raw = fs.readFileSync(path, \"utf8\");\n const errors: jsonc.ParseError[] = [];\n const parsed = jsonc.parse(raw, errors) as\n | { plugins?: readonly PluginConfig[] }\n | undefined;\n if (errors.length > 0) {\n const msg = errors\n .map((e) => `offset ${e.offset}: ${jsonc.printParseErrorCode(e.error)}`)\n .join(\"; \");\n throw new Error(`[load-plugins] failed to parse ${path}: ${msg}`);\n }\n\n const entries = parsed?.plugins ?? null;\n if (!entries || entries.length === 0) return null;\n\n // jiti is created once per call; `moduleCache: false` ensures a\n // restart picks up freshly-installed packages without process restart\n // (relevant when the dev server kicks a reload after `executor plugin\n // install`).\n const { createJiti } = await import(\"jiti\");\n const jiti = createJiti(pathToFileURL(path).href, {\n interopDefault: true,\n moduleCache: false,\n });\n\n const fromDir = dirname(path);\n // require.resolve is anchored to the jsonc's directory so plugin\n // packages resolve from the host app's `node_modules` regardless of\n // CWD.\n const require = createRequire(\n isAbsolute(path) ? path : resolvePath(fromDir, \"_anchor.js\"),\n );\n\n const loaded: AnyPlugin[] = [];\n for (const entry of entries) {\n const serverEntry = `${entry.package}/server`;\n let resolved: string;\n try {\n resolved = require.resolve(serverEntry);\n } catch {\n throw new Error(\n `[load-plugins] cannot resolve \"${serverEntry}\" from ${fromDir}. ` +\n `Is \"${entry.package}\" installed and does it export \"./server\"?`,\n );\n }\n const mod = (await jiti.import(resolved)) as\n | { default?: LooseConfiguredPlugin }\n | LooseConfiguredPlugin;\n const factory = (\n typeof mod === \"function\" ? mod : (mod.default ?? null)\n ) as LooseConfiguredPlugin | null;\n if (!factory || typeof factory !== \"function\") {\n throw new Error(\n `[load-plugins] \"${serverEntry}\" did not export a default ` +\n `definePlugin(...) factory.`,\n );\n }\n const merged = { ...(deps ?? {}), ...(entry.options ?? {}) };\n loaded.push(factory(merged));\n }\n\n return loaded;\n};\n","import { Effect } from \"effect\";\nimport { FileSystem } from \"effect\";\nimport type { PlatformError } from \"effect/PlatformError\";\nimport * as jsonc from \"jsonc-parser\";\nimport type { SourceConfig, ExecutorFileConfig } from \"./schema\";\n\nconst FORMATTING: jsonc.FormattingOptions = {\n tabSize: 2,\n insertSpaces: true,\n eol: \"\\n\",\n};\n\nconst DEFAULT_CONFIG = `{\n \"sources\": []\n}\n`;\n\n/** Read the raw JSONC text from a config file, or create a default one. */\nconst readOrCreate = (\n fs: FileSystem.FileSystem,\n path: string,\n): Effect.Effect<string, PlatformError> =>\n Effect.gen(function* () {\n const exists = yield* fs.exists(path);\n if (exists) return yield* fs.readFileString(path);\n yield* fs.writeFileString(path, DEFAULT_CONFIG);\n return DEFAULT_CONFIG;\n });\n\n/**\n * Add a source entry to the config file. Creates the file if it doesn't exist.\n * Preserves existing comments and formatting.\n */\nexport const addSourceToConfig = (\n path: string,\n source: SourceConfig,\n): Effect.Effect<void, PlatformError, FileSystem.FileSystem> =>\n Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n let text = yield* readOrCreate(fs, path);\n\n // Ensure \"sources\" array exists\n let tree = jsonc.parseTree(text);\n let sourcesNode = tree ? jsonc.findNodeAtLocation(tree, [\"sources\"]) : undefined;\n\n if (!sourcesNode) {\n const edits = jsonc.modify(text, [\"sources\"], [source], {\n formattingOptions: FORMATTING,\n });\n text = jsonc.applyEdits(text, edits);\n } else {\n // Remove existing entry with same namespace (if any) to avoid duplicates\n const ns = \"namespace\" in source ? source.namespace : undefined;\n if (ns && sourcesNode.children) {\n for (let i = sourcesNode.children.length - 1; i >= 0; i--) {\n const child = sourcesNode.children[i]!;\n const nsNode = jsonc.findNodeAtLocation(child, [\"namespace\"]);\n if (nsNode && jsonc.getNodeValue(nsNode) === ns) {\n const edits = jsonc.modify(text, [\"sources\", i], undefined, {\n formattingOptions: FORMATTING,\n });\n text = jsonc.applyEdits(text, edits);\n }\n }\n // Re-parse after removals\n tree = jsonc.parseTree(text);\n sourcesNode = tree ? jsonc.findNodeAtLocation(tree, [\"sources\"]) : undefined;\n }\n\n const count = sourcesNode?.children?.length ?? 0;\n const edits = jsonc.modify(text, [\"sources\", count], source, {\n formattingOptions: FORMATTING,\n });\n text = jsonc.applyEdits(text, edits);\n }\n\n yield* fs.writeFileString(path, text);\n });\n\n/**\n * Remove a source from the config file by namespace.\n */\nexport const removeSourceFromConfig = (\n path: string,\n namespace: string,\n): Effect.Effect<void, PlatformError, FileSystem.FileSystem> =>\n Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n\n const exists = yield* fs.exists(path);\n if (!exists) return;\n\n let text = yield* fs.readFileString(path);\n const tree = jsonc.parseTree(text);\n if (!tree) return;\n\n const sourcesNode = jsonc.findNodeAtLocation(tree, [\"sources\"]);\n if (!sourcesNode?.children) return;\n\n // Walk backwards so indices stay valid after each removal\n for (let i = sourcesNode.children.length - 1; i >= 0; i--) {\n const child = sourcesNode.children[i]!;\n const nsNode = jsonc.findNodeAtLocation(child, [\"namespace\"]);\n if (nsNode && jsonc.getNodeValue(nsNode) === namespace) {\n const edits = jsonc.modify(text, [\"sources\", i], undefined, {\n formattingOptions: FORMATTING,\n });\n text = jsonc.applyEdits(text, edits);\n }\n }\n\n yield* fs.writeFileString(path, text);\n });\n\n/**\n * Write a full config object to a file.\n */\nexport const writeConfig = (\n path: string,\n config: ExecutorFileConfig,\n): Effect.Effect<void, PlatformError, FileSystem.FileSystem> =>\n Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const text = yield* Effect.try({\n try: () => JSON.stringify(config, null, 2) + \"\\n\",\n catch: (cause) => cause,\n }).pipe(Effect.orDie);\n yield* fs.writeFileString(path, text);\n });\n\n/**\n * Add secret metadata to the config file.\n */\nexport const addSecretToConfig = (\n path: string,\n secretId: string,\n metadata: { name: string; provider?: string; purpose?: string },\n): Effect.Effect<void, PlatformError, FileSystem.FileSystem> =>\n Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n let text = yield* readOrCreate(fs, path);\n\n const edits = jsonc.modify(text, [\"secrets\", secretId], metadata, {\n formattingOptions: FORMATTING,\n });\n text = jsonc.applyEdits(text, edits);\n\n yield* fs.writeFileString(path, text);\n });\n\n/**\n * Remove secret metadata from the config file.\n */\nexport const removeSecretFromConfig = (\n path: string,\n secretId: string,\n): Effect.Effect<void, PlatformError, FileSystem.FileSystem> =>\n Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n\n const exists = yield* fs.exists(path);\n if (!exists) return;\n\n let text = yield* fs.readFileString(path);\n const edits = jsonc.modify(text, [\"secrets\", secretId], undefined, {\n formattingOptions: FORMATTING,\n });\n text = jsonc.applyEdits(text, edits);\n\n yield* fs.writeFileString(path, text);\n });\n","// ---------------------------------------------------------------------------\n// ConfigFileSink — best-effort write-back of source changes to executor.jsonc.\n//\n// Plugins (openapi, graphql, mcp) call `sink.upsertSource` after their DB\n// writes so the committable file stays in sync with runtime state. Errors\n// are logged and swallowed — a failed file write must never fail a DB\n// mutation, and the next successful mutation (or a boot-time sync) will\n// eventually reconcile.\n//\n// The FileSystem layer is injected so library code here doesn't pick a\n// platform binding. The host app provides NodeFileSystem (or BunFileSystem).\n// ---------------------------------------------------------------------------\n\nimport { Effect } from \"effect\";\nimport type { Layer } from \"effect\";\nimport type { FileSystem } from \"effect\";\n\nimport { SECRET_REF_PREFIX, type ConfigHeaderValue, type SourceConfig } from \"./schema\";\nimport { addSourceToConfig, removeSourceFromConfig } from \"./write\";\n\n// Translate a plugin-side header value (`{ secretId, prefix? }` for secret\n// refs) into the config file's `secret-public-ref:<id>` string form.\ntype PluginHeaderValue = string | { secretId: string; prefix?: string };\n\nexport const headerToConfigValue = (\n value: PluginHeaderValue,\n): ConfigHeaderValue => {\n if (typeof value === \"string\") return value;\n const ref = `${SECRET_REF_PREFIX}${value.secretId}`;\n return value.prefix ? { value: ref, prefix: value.prefix } : ref;\n};\n\nexport const headersToConfigValues = (\n headers: Record<string, PluginHeaderValue> | undefined,\n): Record<string, ConfigHeaderValue> | undefined => {\n if (!headers) return undefined;\n const out: Record<string, ConfigHeaderValue> = {};\n for (const [k, v] of Object.entries(headers)) out[k] = headerToConfigValue(v);\n return out;\n};\n\nexport interface ConfigFileSink {\n readonly upsertSource: (source: SourceConfig) => Effect.Effect<void>;\n readonly removeSource: (namespace: string) => Effect.Effect<void>;\n}\n\nexport interface ConfigFileSinkOptions {\n readonly path: string;\n readonly fsLayer: Layer.Layer<FileSystem.FileSystem>;\n /** Called when a file operation fails. Defaults to console.warn. */\n readonly onError?: (op: \"upsert\" | \"remove\", err: unknown) => void;\n}\n\nconst defaultOnError = (op: \"upsert\" | \"remove\", err: unknown): void => {\n const msg = err instanceof Error ? err.message : String(err);\n console.warn(`[config-sink] ${op} failed: ${msg}`);\n};\n\nexport const makeFileConfigSink = (\n options: ConfigFileSinkOptions,\n): ConfigFileSink => {\n const { path, fsLayer, onError = defaultOnError } = options;\n\n return {\n upsertSource: (source) =>\n addSourceToConfig(path, source).pipe(\n Effect.provide(fsLayer),\n Effect.catch((err: unknown) => Effect.sync(() => onError(\"upsert\", err))),\n ),\n\n removeSource: (namespace) =>\n removeSourceFromConfig(path, namespace).pipe(\n Effect.provide(fsLayer),\n Effect.catch((err: unknown) => Effect.sync(() => onError(\"remove\", err))),\n ),\n };\n};\n"],"mappings":"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","names":["Schema","fs","Schema","jsonc","require","Effect","FileSystem","jsonc","fs","edits","Effect","Effect"]}
|
|
1
|
+
{"version":3,"sources":["../src/schema.ts","../src/load.ts","../src/load-plugins.ts","../src/write.ts","../src/sink.ts"],"sourcesContent":["import { Schema } from \"effect\";\n\n// ---------------------------------------------------------------------------\n// Header values\n//\n// Three forms:\n// \"static-value\" — literal string\n// \"secret-public-ref:my-token\" — secret reference (no prefix)\n// { value: \"secret-public-ref:x\", prefix } — secret reference with prefix\n// ---------------------------------------------------------------------------\n\nexport const SECRET_REF_PREFIX = \"secret-public-ref:\";\n\nexport const ConfigHeaderValue = Schema.Union([\n Schema.String,\n Schema.Struct({\n value: Schema.String,\n prefix: Schema.optional(Schema.String),\n }),\n]);\nexport type ConfigHeaderValue = typeof ConfigHeaderValue.Type;\n\nconst ConfigHeaders = Schema.Record(Schema.String, ConfigHeaderValue);\n\n// ---------------------------------------------------------------------------\n// Source configs — discriminated union on \"kind\"\n// ---------------------------------------------------------------------------\n\nexport const OpenApiSourceConfig = Schema.Struct({\n kind: Schema.Literal(\"openapi\"),\n spec: Schema.String,\n baseUrl: Schema.optional(Schema.String),\n namespace: Schema.optional(Schema.String),\n headers: Schema.optional(ConfigHeaders),\n});\nexport type OpenApiSourceConfig = typeof OpenApiSourceConfig.Type;\n\nexport const GraphqlSourceConfig = Schema.Struct({\n kind: Schema.Literal(\"graphql\"),\n endpoint: Schema.String,\n introspectionJson: Schema.optional(Schema.NullOr(Schema.String)),\n namespace: Schema.optional(Schema.String),\n headers: Schema.optional(ConfigHeaders),\n});\nexport type GraphqlSourceConfig = typeof GraphqlSourceConfig.Type;\n\nconst StringMap = Schema.Record(Schema.String, Schema.String);\n\nexport const McpAuthConfig = Schema.Union([\n Schema.Struct({ kind: Schema.Literal(\"none\") }),\n Schema.Struct({\n kind: Schema.Literal(\"header\"),\n headerName: Schema.String,\n secret: Schema.String,\n prefix: Schema.optional(Schema.String),\n }),\n Schema.Struct({\n kind: Schema.Literal(\"oauth2\"),\n /** Stable id of the SDK Connection holding access + refresh token\n * material. Scope shadowing means the same id resolves per-user\n * via the executor's innermost-wins lookup. */\n connectionId: Schema.String,\n }),\n]);\nexport type McpAuthConfig = typeof McpAuthConfig.Type;\n\nexport const McpRemoteSourceConfig = Schema.Struct({\n kind: Schema.Literal(\"mcp\"),\n transport: Schema.Literal(\"remote\"),\n name: Schema.String,\n endpoint: Schema.String,\n remoteTransport: Schema.optional(Schema.Literals([\"streamable-http\", \"sse\", \"auto\"])),\n namespace: Schema.optional(Schema.String),\n queryParams: Schema.optional(StringMap),\n headers: Schema.optional(StringMap),\n auth: Schema.optional(McpAuthConfig),\n});\nexport type McpRemoteSourceConfig = typeof McpRemoteSourceConfig.Type;\n\nexport const McpStdioSourceConfig = Schema.Struct({\n kind: Schema.Literal(\"mcp\"),\n transport: Schema.Literal(\"stdio\"),\n name: Schema.String,\n command: Schema.String,\n args: Schema.optional(Schema.Array(Schema.String)),\n env: Schema.optional(StringMap),\n cwd: Schema.optional(Schema.String),\n namespace: Schema.optional(Schema.String),\n});\nexport type McpStdioSourceConfig = typeof McpStdioSourceConfig.Type;\n\nexport const SourceConfig = Schema.Union([\n OpenApiSourceConfig,\n GraphqlSourceConfig,\n McpRemoteSourceConfig,\n McpStdioSourceConfig,\n]);\nexport type SourceConfig = typeof SourceConfig.Type;\n\n// ---------------------------------------------------------------------------\n// Secret metadata\n// ---------------------------------------------------------------------------\n\nexport const SecretMetadata = Schema.Struct({\n name: Schema.String,\n provider: Schema.optional(Schema.String),\n purpose: Schema.optional(Schema.String),\n});\nexport type SecretMetadata = typeof SecretMetadata.Type;\n\n// ---------------------------------------------------------------------------\n// Plugin manifest\n//\n// `plugins` is the install list. Each entry is a published npm package\n// that exports a `definePlugin(...)` factory under `./server`. The host\n// loads each at boot via jiti and calls the factory with merged\n// `options` plus host-injected deps (`configFile`, etc.). This is the\n// dynamic sibling of the static `executor.config.ts` plugin tuple — when\n// `plugins` is set, the host uses it; otherwise it falls back to the\n// statically-typed config.\n// ---------------------------------------------------------------------------\n\nexport const PluginConfig = Schema.Struct({\n package: Schema.String,\n options: Schema.optional(Schema.Record(Schema.String, Schema.Unknown)),\n});\nexport type PluginConfig = typeof PluginConfig.Type;\n\n// ---------------------------------------------------------------------------\n// Top-level config\n// ---------------------------------------------------------------------------\n\nexport const ExecutorFileConfig = Schema.Struct({\n $schema: Schema.optional(Schema.String),\n name: Schema.optional(Schema.String),\n plugins: Schema.optional(Schema.Array(PluginConfig)),\n sources: Schema.optional(Schema.Array(SourceConfig)),\n secrets: Schema.optional(Schema.Record(Schema.String, SecretMetadata)),\n});\nexport type ExecutorFileConfig = typeof ExecutorFileConfig.Type;\n","import { Effect, Schema } from \"effect\";\nimport { FileSystem } from \"effect\";\nimport type { PlatformError } from \"effect/PlatformError\";\nimport * as jsonc from \"jsonc-parser\";\nimport { ExecutorFileConfig } from \"./schema\";\n\nexport class ConfigParseError extends Schema.TaggedErrorClass<ConfigParseError>()(\n \"ConfigParseError\",\n {\n path: Schema.String,\n message: Schema.String,\n },\n) {}\n\n/**\n * Load and validate an executor config file.\n * Returns null if the file doesn't exist.\n */\nexport const loadConfig = (\n path: string,\n): Effect.Effect<\n ExecutorFileConfig | null,\n ConfigParseError | PlatformError,\n FileSystem.FileSystem\n> =>\n Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n\n const exists = yield* fs.exists(path);\n if (!exists) return null;\n\n const raw = yield* fs.readFileString(path);\n\n const errors: jsonc.ParseError[] = [];\n const parsed = jsonc.parse(raw, errors);\n\n if (errors.length > 0) {\n const msg = errors\n .map((e) => `offset ${e.offset}: ${jsonc.printParseErrorCode(e.error)}`)\n .join(\"; \");\n return yield* new ConfigParseError({ path, message: msg });\n }\n\n const decoded = yield* Schema.decodeUnknownEffect(ExecutorFileConfig)(parsed).pipe(\n Effect.mapError(\n (error) =>\n new ConfigParseError({\n path,\n message: error.issue.toString(),\n }),\n ),\n );\n\n return decoded;\n });\n","// ---------------------------------------------------------------------------\n// loadPluginsFromJsonc — runtime plugin loader.\n//\n// Reads `executor.jsonc#plugins`, dynamically imports each package's\n// `./server` entry via jiti (so workspace TS sources work in dev and\n// published `dist/*.js` works after install), and calls the exported\n// `definePlugin(...)` factory with merged `options` plus host-injected\n// deps. Returns the resulting `Plugin[]` ready to hand to\n// `composePluginApi` / `createExecutor`.\n//\n// jiti is used instead of bare `import()` because:\n// - workspace plugins under monorepo dev expose `.ts` source via the\n// `bun` export condition; Node's loader can't read those directly,\n// jiti transpiles on the fly.\n// - in a published environment the package's `default` condition\n// points at `dist/*.js`, which jiti loads as a normal ESM module.\n//\n// The convention is: every plugin package exports a `./server` subpath\n// whose default export is a `ConfiguredPlugin` (the result of\n// `definePlugin(...)`). Calling that with `{ ...options, ...deps }`\n// returns a concrete `Plugin`.\n// ---------------------------------------------------------------------------\n\nimport { createRequire } from \"node:module\";\nimport { dirname, isAbsolute, resolve as resolvePath } from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\nimport * as fs from \"node:fs\";\nimport * as jsonc from \"jsonc-parser\";\nimport { Effect, Schema } from \"effect\";\n\nimport type { AnyPlugin } from \"@executor-js/sdk\";\n\n// Plugins are invoked dynamically by name — exact author types are\n// unknown at the call site, so the loader treats every factory as\n// `(options?: unknown) => AnyPlugin`. The plugin author's types still\n// hold inside the plugin's own module; we just don't propagate them\n// across the runtime boundary.\ntype LooseConfiguredPlugin = (options?: Record<string, unknown>) => AnyPlugin;\n\nimport { ExecutorFileConfig } from \"./schema\";\n\nexport class LoadPluginsError extends Schema.TaggedErrorClass<LoadPluginsError>()(\n \"LoadPluginsError\",\n {\n message: Schema.String,\n cause: Schema.optional(Schema.Unknown),\n },\n) {}\n\nexport interface LoadPluginsFromJsoncOptions {\n /** Absolute path to `executor.jsonc` (or compatible). */\n readonly path: string;\n /**\n * Host-injected deps merged into each plugin's options. Common keys:\n * `configFile` (the `ConfigFileSink`), env-derived credentials, etc.\n * Plugins ignore deps they don't accept — `definePlugin` strips\n * unknown keys before forwarding to the author factory.\n */\n readonly deps?: Readonly<Record<string, unknown>>;\n}\n\n/**\n * Returns the plugins listed in jsonc, or `null` if the file is missing\n * or has no `plugins` array. The host treats `null` as \"fall back to\n * the static `executor.config.ts` factory.\"\n */\nexport const loadPluginsFromJsonc = async (\n options: LoadPluginsFromJsoncOptions,\n): Promise<readonly AnyPlugin[] | null> => Effect.runPromise(loadPluginsFromJsoncEffect(options));\n\nconst loadPluginsFromJsoncEffect = (\n options: LoadPluginsFromJsoncOptions,\n): Effect.Effect<readonly AnyPlugin[] | null, LoadPluginsError> =>\n Effect.gen(function* () {\n const { path, deps } = options;\n if (!fs.existsSync(path)) return null;\n\n const raw = fs.readFileSync(path, \"utf8\");\n const errors: jsonc.ParseError[] = [];\n const parsed = jsonc.parse(raw, errors);\n if (errors.length > 0) {\n const msg = errors\n .map((e) => `offset ${e.offset}: ${jsonc.printParseErrorCode(e.error)}`)\n .join(\"; \");\n return yield* new LoadPluginsError({\n message: `[load-plugins] failed to parse ${path}: ${msg}`,\n });\n }\n\n const config = yield* Schema.decodeUnknownEffect(ExecutorFileConfig)(parsed).pipe(\n Effect.mapError(\n (error) =>\n new LoadPluginsError({\n message: `[load-plugins] failed to decode ${path}: ${error.issue.toString()}`,\n cause: error,\n }),\n ),\n );\n\n const entries = config.plugins ?? null;\n if (!entries || entries.length === 0) return null;\n\n // jiti is created once per call; `moduleCache: false` ensures a\n // restart picks up freshly-installed packages without process restart\n // (relevant when the dev server kicks a reload after `executor plugin\n // install`).\n const { createJiti } = yield* Effect.tryPromise({\n try: () => import(\"jiti\"),\n catch: (cause) =>\n new LoadPluginsError({\n message: `[load-plugins] failed to import jiti.`,\n cause,\n }),\n });\n const jiti = createJiti(pathToFileURL(path).href, {\n interopDefault: true,\n moduleCache: false,\n });\n\n const fromDir = dirname(path);\n // require.resolve is anchored to the jsonc's directory so plugin\n // packages resolve from the host app's `node_modules` regardless of\n // CWD.\n const require = createRequire(isAbsolute(path) ? path : resolvePath(fromDir, \"_anchor.js\"));\n\n const loaded: AnyPlugin[] = [];\n for (const entry of entries) {\n const serverEntry = `${entry.package}/server`;\n const resolved = yield* Effect.try({\n try: () => require.resolve(serverEntry),\n catch: (cause) =>\n new LoadPluginsError({\n message:\n `[load-plugins] cannot resolve \"${serverEntry}\" from ${fromDir}. ` +\n `Is \"${entry.package}\" installed and does it export \"./server\"?`,\n cause,\n }),\n });\n const mod = (yield* Effect.tryPromise({\n try: () => jiti.import(resolved),\n catch: (cause) =>\n new LoadPluginsError({\n message: `[load-plugins] failed to import \"${serverEntry}\" from ${resolved}.`,\n cause,\n }),\n })) as { default?: LooseConfiguredPlugin } | LooseConfiguredPlugin;\n const factory = (\n typeof mod === \"function\" ? mod : (mod.default ?? null)\n ) as LooseConfiguredPlugin | null;\n if (!factory || typeof factory !== \"function\") {\n return yield* new LoadPluginsError({\n message:\n `[load-plugins] \"${serverEntry}\" did not export a default ` +\n `definePlugin(...) factory.`,\n });\n }\n const merged = { ...(deps ?? {}), ...(entry.options ?? {}) };\n loaded.push(factory(merged));\n }\n\n return loaded;\n });\n","import { Effect } from \"effect\";\nimport { FileSystem } from \"effect\";\nimport type { PlatformError } from \"effect/PlatformError\";\nimport * as jsonc from \"jsonc-parser\";\nimport type { SourceConfig, ExecutorFileConfig } from \"./schema\";\n\nexport class ConfigWriteError {\n readonly _tag = \"ConfigWriteError\";\n constructor(\n readonly path: string,\n readonly cause: unknown,\n ) {}\n}\n\nconst FORMATTING: jsonc.FormattingOptions = {\n tabSize: 2,\n insertSpaces: true,\n eol: \"\\n\",\n};\n\nconst DEFAULT_CONFIG = `{\n \"sources\": []\n}\n`;\n\n/** Read the raw JSONC text from a config file, or create a default one. */\nconst readOrCreate = (\n fs: FileSystem.FileSystem,\n path: string,\n): Effect.Effect<string, PlatformError> =>\n Effect.gen(function* () {\n const exists = yield* fs.exists(path);\n if (exists) return yield* fs.readFileString(path);\n yield* fs.writeFileString(path, DEFAULT_CONFIG);\n return DEFAULT_CONFIG;\n });\n\n/**\n * Add a source entry to the config file. Creates the file if it doesn't exist.\n * Preserves existing comments and formatting.\n */\nexport const addSourceToConfig = (\n path: string,\n source: SourceConfig,\n): Effect.Effect<void, PlatformError, FileSystem.FileSystem> =>\n Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n let text = yield* readOrCreate(fs, path);\n\n // Ensure \"sources\" array exists\n let tree = jsonc.parseTree(text);\n let sourcesNode = tree ? jsonc.findNodeAtLocation(tree, [\"sources\"]) : undefined;\n\n if (!sourcesNode) {\n const edits = jsonc.modify(text, [\"sources\"], [source], {\n formattingOptions: FORMATTING,\n });\n text = jsonc.applyEdits(text, edits);\n } else {\n // Remove existing entry with same namespace (if any) to avoid duplicates\n const ns = \"namespace\" in source ? source.namespace : undefined;\n if (ns && sourcesNode.children) {\n for (let i = sourcesNode.children.length - 1; i >= 0; i--) {\n const child = sourcesNode.children[i]!;\n const nsNode = jsonc.findNodeAtLocation(child, [\"namespace\"]);\n if (nsNode && jsonc.getNodeValue(nsNode) === ns) {\n const edits = jsonc.modify(text, [\"sources\", i], undefined, {\n formattingOptions: FORMATTING,\n });\n text = jsonc.applyEdits(text, edits);\n }\n }\n // Re-parse after removals\n tree = jsonc.parseTree(text);\n sourcesNode = tree ? jsonc.findNodeAtLocation(tree, [\"sources\"]) : undefined;\n }\n\n const count = sourcesNode?.children?.length ?? 0;\n const edits = jsonc.modify(text, [\"sources\", count], source, {\n formattingOptions: FORMATTING,\n });\n text = jsonc.applyEdits(text, edits);\n }\n\n yield* fs.writeFileString(path, text);\n });\n\n/**\n * Remove a source from the config file by namespace.\n */\nexport const removeSourceFromConfig = (\n path: string,\n namespace: string,\n): Effect.Effect<void, PlatformError, FileSystem.FileSystem> =>\n Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n\n const exists = yield* fs.exists(path);\n if (!exists) return;\n\n let text = yield* fs.readFileString(path);\n const tree = jsonc.parseTree(text);\n if (!tree) return;\n\n const sourcesNode = jsonc.findNodeAtLocation(tree, [\"sources\"]);\n if (!sourcesNode?.children) return;\n\n // Walk backwards so indices stay valid after each removal\n for (let i = sourcesNode.children.length - 1; i >= 0; i--) {\n const child = sourcesNode.children[i]!;\n const nsNode = jsonc.findNodeAtLocation(child, [\"namespace\"]);\n if (nsNode && jsonc.getNodeValue(nsNode) === namespace) {\n const edits = jsonc.modify(text, [\"sources\", i], undefined, {\n formattingOptions: FORMATTING,\n });\n text = jsonc.applyEdits(text, edits);\n }\n }\n\n yield* fs.writeFileString(path, text);\n });\n\n/**\n * Write a full config object to a file.\n */\nexport const writeConfig = (\n path: string,\n config: ExecutorFileConfig,\n): Effect.Effect<void, ConfigWriteError | PlatformError, FileSystem.FileSystem> =>\n Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const text = yield* Effect.try({\n try: () => JSON.stringify(config, null, 2) + \"\\n\",\n catch: (cause) => new ConfigWriteError(path, cause),\n });\n yield* fs.writeFileString(path, text);\n });\n\n/**\n * Add secret metadata to the config file.\n */\nexport const addSecretToConfig = (\n path: string,\n secretId: string,\n metadata: { name: string; provider?: string; purpose?: string },\n): Effect.Effect<void, PlatformError, FileSystem.FileSystem> =>\n Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n let text = yield* readOrCreate(fs, path);\n\n const edits = jsonc.modify(text, [\"secrets\", secretId], metadata, {\n formattingOptions: FORMATTING,\n });\n text = jsonc.applyEdits(text, edits);\n\n yield* fs.writeFileString(path, text);\n });\n\n/**\n * Remove secret metadata from the config file.\n */\nexport const removeSecretFromConfig = (\n path: string,\n secretId: string,\n): Effect.Effect<void, PlatformError, FileSystem.FileSystem> =>\n Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n\n const exists = yield* fs.exists(path);\n if (!exists) return;\n\n let text = yield* fs.readFileString(path);\n const edits = jsonc.modify(text, [\"secrets\", secretId], undefined, {\n formattingOptions: FORMATTING,\n });\n text = jsonc.applyEdits(text, edits);\n\n yield* fs.writeFileString(path, text);\n });\n","// ---------------------------------------------------------------------------\n// ConfigFileSink — best-effort write-back of source changes to executor.jsonc.\n//\n// Plugins (openapi, graphql, mcp) call `sink.upsertSource` after their DB\n// writes so the committable file stays in sync with runtime state. Errors\n// are logged and swallowed — a failed file write must never fail a DB\n// mutation, and the next successful mutation (or a boot-time sync) will\n// eventually reconcile.\n//\n// The FileSystem layer is injected so library code here doesn't pick a\n// platform binding. The host app provides NodeFileSystem (or BunFileSystem).\n// ---------------------------------------------------------------------------\n\nimport { Effect } from \"effect\";\nimport type { Layer } from \"effect\";\nimport type { FileSystem } from \"effect\";\n\nimport { SECRET_REF_PREFIX, type ConfigHeaderValue, type SourceConfig } from \"./schema\";\nimport { addSourceToConfig, removeSourceFromConfig } from \"./write\";\n\n// Translate a plugin-side header value (`{ secretId, prefix? }` for secret\n// refs) into the config file's `secret-public-ref:<id>` string form.\ntype PluginHeaderValue = string | { secretId: string; prefix?: string };\n\nexport const headerToConfigValue = (value: PluginHeaderValue): ConfigHeaderValue => {\n if (typeof value === \"string\") return value;\n const ref = `${SECRET_REF_PREFIX}${value.secretId}`;\n return value.prefix ? { value: ref, prefix: value.prefix } : ref;\n};\n\nexport const headersToConfigValues = (\n headers: Record<string, PluginHeaderValue> | undefined,\n): Record<string, ConfigHeaderValue> | undefined => {\n if (!headers) return undefined;\n const out: Record<string, ConfigHeaderValue> = {};\n for (const [k, v] of Object.entries(headers)) out[k] = headerToConfigValue(v);\n return out;\n};\n\nexport interface ConfigFileSink {\n readonly upsertSource: (source: SourceConfig) => Effect.Effect<void>;\n readonly removeSource: (namespace: string) => Effect.Effect<void>;\n}\n\nexport interface ConfigFileSinkOptions {\n readonly path: string;\n readonly fsLayer: Layer.Layer<FileSystem.FileSystem>;\n /** Called when a file operation fails. Defaults to console.warn. */\n readonly onError?: (op: \"upsert\" | \"remove\", err: unknown) => void;\n}\n\nconst defaultOnError = (op: \"upsert\" | \"remove\", err: unknown): void => {\n console.warn(`[config-sink] ${op} failed`, err);\n};\n\nexport const makeFileConfigSink = (options: ConfigFileSinkOptions): ConfigFileSink => {\n const { path, fsLayer, onError = defaultOnError } = options;\n\n return {\n upsertSource: (source) =>\n addSourceToConfig(path, source).pipe(\n Effect.provide(fsLayer),\n Effect.catch((err: unknown) => Effect.sync(() => onError(\"upsert\", err))),\n ),\n\n removeSource: (namespace) =>\n removeSourceFromConfig(path, namespace).pipe(\n Effect.provide(fsLayer),\n Effect.catch((err: unknown) => Effect.sync(() => onError(\"remove\", err))),\n ),\n };\n};\n"],"mappings":";AAAA,SAAS,cAAc;AAWhB,IAAM,oBAAoB;AAE1B,IAAM,oBAAoB,OAAO,MAAM;AAAA,EAC5C,OAAO;AAAA,EACP,OAAO,OAAO;AAAA,IACZ,OAAO,OAAO;AAAA,IACd,QAAQ,OAAO,SAAS,OAAO,MAAM;AAAA,EACvC,CAAC;AACH,CAAC;AAGD,IAAM,gBAAgB,OAAO,OAAO,OAAO,QAAQ,iBAAiB;AAM7D,IAAM,sBAAsB,OAAO,OAAO;AAAA,EAC/C,MAAM,OAAO,QAAQ,SAAS;AAAA,EAC9B,MAAM,OAAO;AAAA,EACb,SAAS,OAAO,SAAS,OAAO,MAAM;AAAA,EACtC,WAAW,OAAO,SAAS,OAAO,MAAM;AAAA,EACxC,SAAS,OAAO,SAAS,aAAa;AACxC,CAAC;AAGM,IAAM,sBAAsB,OAAO,OAAO;AAAA,EAC/C,MAAM,OAAO,QAAQ,SAAS;AAAA,EAC9B,UAAU,OAAO;AAAA,EACjB,mBAAmB,OAAO,SAAS,OAAO,OAAO,OAAO,MAAM,CAAC;AAAA,EAC/D,WAAW,OAAO,SAAS,OAAO,MAAM;AAAA,EACxC,SAAS,OAAO,SAAS,aAAa;AACxC,CAAC;AAGD,IAAM,YAAY,OAAO,OAAO,OAAO,QAAQ,OAAO,MAAM;AAErD,IAAM,gBAAgB,OAAO,MAAM;AAAA,EACxC,OAAO,OAAO,EAAE,MAAM,OAAO,QAAQ,MAAM,EAAE,CAAC;AAAA,EAC9C,OAAO,OAAO;AAAA,IACZ,MAAM,OAAO,QAAQ,QAAQ;AAAA,IAC7B,YAAY,OAAO;AAAA,IACnB,QAAQ,OAAO;AAAA,IACf,QAAQ,OAAO,SAAS,OAAO,MAAM;AAAA,EACvC,CAAC;AAAA,EACD,OAAO,OAAO;AAAA,IACZ,MAAM,OAAO,QAAQ,QAAQ;AAAA;AAAA;AAAA;AAAA,IAI7B,cAAc,OAAO;AAAA,EACvB,CAAC;AACH,CAAC;AAGM,IAAM,wBAAwB,OAAO,OAAO;AAAA,EACjD,MAAM,OAAO,QAAQ,KAAK;AAAA,EAC1B,WAAW,OAAO,QAAQ,QAAQ;AAAA,EAClC,MAAM,OAAO;AAAA,EACb,UAAU,OAAO;AAAA,EACjB,iBAAiB,OAAO,SAAS,OAAO,SAAS,CAAC,mBAAmB,OAAO,MAAM,CAAC,CAAC;AAAA,EACpF,WAAW,OAAO,SAAS,OAAO,MAAM;AAAA,EACxC,aAAa,OAAO,SAAS,SAAS;AAAA,EACtC,SAAS,OAAO,SAAS,SAAS;AAAA,EAClC,MAAM,OAAO,SAAS,aAAa;AACrC,CAAC;AAGM,IAAM,uBAAuB,OAAO,OAAO;AAAA,EAChD,MAAM,OAAO,QAAQ,KAAK;AAAA,EAC1B,WAAW,OAAO,QAAQ,OAAO;AAAA,EACjC,MAAM,OAAO;AAAA,EACb,SAAS,OAAO;AAAA,EAChB,MAAM,OAAO,SAAS,OAAO,MAAM,OAAO,MAAM,CAAC;AAAA,EACjD,KAAK,OAAO,SAAS,SAAS;AAAA,EAC9B,KAAK,OAAO,SAAS,OAAO,MAAM;AAAA,EAClC,WAAW,OAAO,SAAS,OAAO,MAAM;AAC1C,CAAC;AAGM,IAAM,eAAe,OAAO,MAAM;AAAA,EACvC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAOM,IAAM,iBAAiB,OAAO,OAAO;AAAA,EAC1C,MAAM,OAAO;AAAA,EACb,UAAU,OAAO,SAAS,OAAO,MAAM;AAAA,EACvC,SAAS,OAAO,SAAS,OAAO,MAAM;AACxC,CAAC;AAeM,IAAM,eAAe,OAAO,OAAO;AAAA,EACxC,SAAS,OAAO;AAAA,EAChB,SAAS,OAAO,SAAS,OAAO,OAAO,OAAO,QAAQ,OAAO,OAAO,CAAC;AACvE,CAAC;AAOM,IAAM,qBAAqB,OAAO,OAAO;AAAA,EAC9C,SAAS,OAAO,SAAS,OAAO,MAAM;AAAA,EACtC,MAAM,OAAO,SAAS,OAAO,MAAM;AAAA,EACnC,SAAS,OAAO,SAAS,OAAO,MAAM,YAAY,CAAC;AAAA,EACnD,SAAS,OAAO,SAAS,OAAO,MAAM,YAAY,CAAC;AAAA,EACnD,SAAS,OAAO,SAAS,OAAO,OAAO,OAAO,QAAQ,cAAc,CAAC;AACvE,CAAC;;;AC1ID,SAAS,QAAQ,UAAAA,eAAc;AAC/B,SAAS,kBAAkB;AAE3B,YAAY,WAAW;AAGhB,IAAM,mBAAN,cAA+BC,QAAO,iBAAmC;AAAA,EAC9E;AAAA,EACA;AAAA,IACE,MAAMA,QAAO;AAAA,IACb,SAASA,QAAO;AAAA,EAClB;AACF,EAAE;AAAC;AAMI,IAAM,aAAa,CACxB,SAMA,OAAO,IAAI,aAAa;AACtB,QAAMC,MAAK,OAAO,WAAW;AAE7B,QAAM,SAAS,OAAOA,IAAG,OAAO,IAAI;AACpC,MAAI,CAAC,OAAQ,QAAO;AAEpB,QAAM,MAAM,OAAOA,IAAG,eAAe,IAAI;AAEzC,QAAM,SAA6B,CAAC;AACpC,QAAM,SAAe,YAAM,KAAK,MAAM;AAEtC,MAAI,OAAO,SAAS,GAAG;AACrB,UAAM,MAAM,OACT,IAAI,CAAC,MAAM,UAAU,EAAE,MAAM,KAAW,0BAAoB,EAAE,KAAK,CAAC,EAAE,EACtE,KAAK,IAAI;AACZ,WAAO,OAAO,IAAI,iBAAiB,EAAE,MAAM,SAAS,IAAI,CAAC;AAAA,EAC3D;AAEA,QAAM,UAAU,OAAOD,QAAO,oBAAoB,kBAAkB,EAAE,MAAM,EAAE;AAAA,IAC5E,OAAO;AAAA,MACL,CAAC,UACC,IAAI,iBAAiB;AAAA,QACnB;AAAA,QACA,SAAS,MAAM,MAAM,SAAS;AAAA,MAChC,CAAC;AAAA,IACL;AAAA,EACF;AAEA,SAAO;AACT,CAAC;;;AC/BH,SAAS,qBAAqB;AAC9B,SAAS,SAAS,YAAY,WAAW,mBAAmB;AAC5D,SAAS,qBAAqB;AAC9B,YAAY,QAAQ;AACpB,YAAYE,YAAW;AACvB,SAAS,UAAAC,SAAQ,UAAAC,eAAc;AAaxB,IAAM,mBAAN,cAA+BC,QAAO,iBAAmC;AAAA,EAC9E;AAAA,EACA;AAAA,IACE,SAASA,QAAO;AAAA,IAChB,OAAOA,QAAO,SAASA,QAAO,OAAO;AAAA,EACvC;AACF,EAAE;AAAC;AAmBI,IAAM,uBAAuB,OAClC,YACyCC,QAAO,WAAW,2BAA2B,OAAO,CAAC;AAEhG,IAAM,6BAA6B,CACjC,YAEAA,QAAO,IAAI,aAAa;AACtB,QAAM,EAAE,MAAM,KAAK,IAAI;AACvB,MAAI,CAAI,cAAW,IAAI,EAAG,QAAO;AAEjC,QAAM,MAAS,gBAAa,MAAM,MAAM;AACxC,QAAM,SAA6B,CAAC;AACpC,QAAM,SAAe,aAAM,KAAK,MAAM;AACtC,MAAI,OAAO,SAAS,GAAG;AACrB,UAAM,MAAM,OACT,IAAI,CAAC,MAAM,UAAU,EAAE,MAAM,KAAW,2BAAoB,EAAE,KAAK,CAAC,EAAE,EACtE,KAAK,IAAI;AACZ,WAAO,OAAO,IAAI,iBAAiB;AAAA,MACjC,SAAS,kCAAkC,IAAI,KAAK,GAAG;AAAA,IACzD,CAAC;AAAA,EACH;AAEA,QAAM,SAAS,OAAOD,QAAO,oBAAoB,kBAAkB,EAAE,MAAM,EAAE;AAAA,IAC3EC,QAAO;AAAA,MACL,CAAC,UACC,IAAI,iBAAiB;AAAA,QACnB,SAAS,mCAAmC,IAAI,KAAK,MAAM,MAAM,SAAS,CAAC;AAAA,QAC3E,OAAO;AAAA,MACT,CAAC;AAAA,IACL;AAAA,EACF;AAEA,QAAM,UAAU,OAAO,WAAW;AAClC,MAAI,CAAC,WAAW,QAAQ,WAAW,EAAG,QAAO;AAM7C,QAAM,EAAE,WAAW,IAAI,OAAOA,QAAO,WAAW;AAAA,IAC9C,KAAK,MAAM,OAAO,MAAM;AAAA,IACxB,OAAO,CAAC,UACN,IAAI,iBAAiB;AAAA,MACnB,SAAS;AAAA,MACT;AAAA,IACF,CAAC;AAAA,EACL,CAAC;AACD,QAAM,OAAO,WAAW,cAAc,IAAI,EAAE,MAAM;AAAA,IAChD,gBAAgB;AAAA,IAChB,aAAa;AAAA,EACf,CAAC;AAED,QAAM,UAAU,QAAQ,IAAI;AAI5B,QAAMC,WAAU,cAAc,WAAW,IAAI,IAAI,OAAO,YAAY,SAAS,YAAY,CAAC;AAE1F,QAAM,SAAsB,CAAC;AAC7B,aAAW,SAAS,SAAS;AAC3B,UAAM,cAAc,GAAG,MAAM,OAAO;AACpC,UAAM,WAAW,OAAOD,QAAO,IAAI;AAAA,MACjC,KAAK,MAAMC,SAAQ,QAAQ,WAAW;AAAA,MACtC,OAAO,CAAC,UACN,IAAI,iBAAiB;AAAA,QACnB,SACE,kCAAkC,WAAW,UAAU,OAAO,SACvD,MAAM,OAAO;AAAA,QACtB;AAAA,MACF,CAAC;AAAA,IACL,CAAC;AACD,UAAM,MAAO,OAAOD,QAAO,WAAW;AAAA,MACpC,KAAK,MAAM,KAAK,OAAO,QAAQ;AAAA,MAC/B,OAAO,CAAC,UACN,IAAI,iBAAiB;AAAA,QACnB,SAAS,oCAAoC,WAAW,UAAU,QAAQ;AAAA,QAC1E;AAAA,MACF,CAAC;AAAA,IACL,CAAC;AACD,UAAM,UACJ,OAAO,QAAQ,aAAa,MAAO,IAAI,WAAW;AAEpD,QAAI,CAAC,WAAW,OAAO,YAAY,YAAY;AAC7C,aAAO,OAAO,IAAI,iBAAiB;AAAA,QACjC,SACE,mBAAmB,WAAW;AAAA,MAElC,CAAC;AAAA,IACH;AACA,UAAM,SAAS,EAAE,GAAI,QAAQ,CAAC,GAAI,GAAI,MAAM,WAAW,CAAC,EAAG;AAC3D,WAAO,KAAK,QAAQ,MAAM,CAAC;AAAA,EAC7B;AAEA,SAAO;AACT,CAAC;;;ACjKH,SAAS,UAAAE,eAAc;AACvB,SAAS,cAAAC,mBAAkB;AAE3B,YAAYC,YAAW;AAGhB,IAAM,mBAAN,MAAuB;AAAA,EAE5B,YACW,MACA,OACT;AAFS;AACA;AAAA,EACR;AAAA,EAFQ;AAAA,EACA;AAAA,EAHF,OAAO;AAKlB;AAEA,IAAM,aAAsC;AAAA,EAC1C,SAAS;AAAA,EACT,cAAc;AAAA,EACd,KAAK;AACP;AAEA,IAAM,iBAAiB;AAAA;AAAA;AAAA;AAMvB,IAAM,eAAe,CACnBC,KACA,SAEAH,QAAO,IAAI,aAAa;AACtB,QAAM,SAAS,OAAOG,IAAG,OAAO,IAAI;AACpC,MAAI,OAAQ,QAAO,OAAOA,IAAG,eAAe,IAAI;AAChD,SAAOA,IAAG,gBAAgB,MAAM,cAAc;AAC9C,SAAO;AACT,CAAC;AAMI,IAAM,oBAAoB,CAC/B,MACA,WAEAH,QAAO,IAAI,aAAa;AACtB,QAAMG,MAAK,OAAOF,YAAW;AAC7B,MAAI,OAAO,OAAO,aAAaE,KAAI,IAAI;AAGvC,MAAI,OAAa,iBAAU,IAAI;AAC/B,MAAI,cAAc,OAAa,0BAAmB,MAAM,CAAC,SAAS,CAAC,IAAI;AAEvE,MAAI,CAAC,aAAa;AAChB,UAAM,QAAc,cAAO,MAAM,CAAC,SAAS,GAAG,CAAC,MAAM,GAAG;AAAA,MACtD,mBAAmB;AAAA,IACrB,CAAC;AACD,WAAa,kBAAW,MAAM,KAAK;AAAA,EACrC,OAAO;AAEL,UAAM,KAAK,eAAe,SAAS,OAAO,YAAY;AACtD,QAAI,MAAM,YAAY,UAAU;AAC9B,eAAS,IAAI,YAAY,SAAS,SAAS,GAAG,KAAK,GAAG,KAAK;AACzD,cAAM,QAAQ,YAAY,SAAS,CAAC;AACpC,cAAM,SAAe,0BAAmB,OAAO,CAAC,WAAW,CAAC;AAC5D,YAAI,UAAgB,oBAAa,MAAM,MAAM,IAAI;AAC/C,gBAAMC,SAAc,cAAO,MAAM,CAAC,WAAW,CAAC,GAAG,QAAW;AAAA,YAC1D,mBAAmB;AAAA,UACrB,CAAC;AACD,iBAAa,kBAAW,MAAMA,MAAK;AAAA,QACrC;AAAA,MACF;AAEA,aAAa,iBAAU,IAAI;AAC3B,oBAAc,OAAa,0BAAmB,MAAM,CAAC,SAAS,CAAC,IAAI;AAAA,IACrE;AAEA,UAAM,QAAQ,aAAa,UAAU,UAAU;AAC/C,UAAM,QAAc,cAAO,MAAM,CAAC,WAAW,KAAK,GAAG,QAAQ;AAAA,MAC3D,mBAAmB;AAAA,IACrB,CAAC;AACD,WAAa,kBAAW,MAAM,KAAK;AAAA,EACrC;AAEA,SAAOD,IAAG,gBAAgB,MAAM,IAAI;AACtC,CAAC;AAKI,IAAM,yBAAyB,CACpC,MACA,cAEAH,QAAO,IAAI,aAAa;AACtB,QAAMG,MAAK,OAAOF,YAAW;AAE7B,QAAM,SAAS,OAAOE,IAAG,OAAO,IAAI;AACpC,MAAI,CAAC,OAAQ;AAEb,MAAI,OAAO,OAAOA,IAAG,eAAe,IAAI;AACxC,QAAM,OAAa,iBAAU,IAAI;AACjC,MAAI,CAAC,KAAM;AAEX,QAAM,cAAoB,0BAAmB,MAAM,CAAC,SAAS,CAAC;AAC9D,MAAI,CAAC,aAAa,SAAU;AAG5B,WAAS,IAAI,YAAY,SAAS,SAAS,GAAG,KAAK,GAAG,KAAK;AACzD,UAAM,QAAQ,YAAY,SAAS,CAAC;AACpC,UAAM,SAAe,0BAAmB,OAAO,CAAC,WAAW,CAAC;AAC5D,QAAI,UAAgB,oBAAa,MAAM,MAAM,WAAW;AACtD,YAAM,QAAc,cAAO,MAAM,CAAC,WAAW,CAAC,GAAG,QAAW;AAAA,QAC1D,mBAAmB;AAAA,MACrB,CAAC;AACD,aAAa,kBAAW,MAAM,KAAK;AAAA,IACrC;AAAA,EACF;AAEA,SAAOA,IAAG,gBAAgB,MAAM,IAAI;AACtC,CAAC;AAKI,IAAM,cAAc,CACzB,MACA,WAEAH,QAAO,IAAI,aAAa;AACtB,QAAMG,MAAK,OAAOF,YAAW;AAC7B,QAAM,OAAO,OAAOD,QAAO,IAAI;AAAA,IAC7B,KAAK,MAAM,KAAK,UAAU,QAAQ,MAAM,CAAC,IAAI;AAAA,IAC7C,OAAO,CAAC,UAAU,IAAI,iBAAiB,MAAM,KAAK;AAAA,EACpD,CAAC;AACD,SAAOG,IAAG,gBAAgB,MAAM,IAAI;AACtC,CAAC;AAKI,IAAM,oBAAoB,CAC/B,MACA,UACA,aAEAH,QAAO,IAAI,aAAa;AACtB,QAAMG,MAAK,OAAOF,YAAW;AAC7B,MAAI,OAAO,OAAO,aAAaE,KAAI,IAAI;AAEvC,QAAM,QAAc,cAAO,MAAM,CAAC,WAAW,QAAQ,GAAG,UAAU;AAAA,IAChE,mBAAmB;AAAA,EACrB,CAAC;AACD,SAAa,kBAAW,MAAM,KAAK;AAEnC,SAAOA,IAAG,gBAAgB,MAAM,IAAI;AACtC,CAAC;AAKI,IAAM,yBAAyB,CACpC,MACA,aAEAH,QAAO,IAAI,aAAa;AACtB,QAAMG,MAAK,OAAOF,YAAW;AAE7B,QAAM,SAAS,OAAOE,IAAG,OAAO,IAAI;AACpC,MAAI,CAAC,OAAQ;AAEb,MAAI,OAAO,OAAOA,IAAG,eAAe,IAAI;AACxC,QAAM,QAAc,cAAO,MAAM,CAAC,WAAW,QAAQ,GAAG,QAAW;AAAA,IACjE,mBAAmB;AAAA,EACrB,CAAC;AACD,SAAa,kBAAW,MAAM,KAAK;AAEnC,SAAOA,IAAG,gBAAgB,MAAM,IAAI;AACtC,CAAC;;;ACrKH,SAAS,UAAAE,eAAc;AAWhB,IAAM,sBAAsB,CAAC,UAAgD;AAClF,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,QAAM,MAAM,GAAG,iBAAiB,GAAG,MAAM,QAAQ;AACjD,SAAO,MAAM,SAAS,EAAE,OAAO,KAAK,QAAQ,MAAM,OAAO,IAAI;AAC/D;AAEO,IAAM,wBAAwB,CACnC,YACkD;AAClD,MAAI,CAAC,QAAS,QAAO;AACrB,QAAM,MAAyC,CAAC;AAChD,aAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,OAAO,EAAG,KAAI,CAAC,IAAI,oBAAoB,CAAC;AAC5E,SAAO;AACT;AAcA,IAAM,iBAAiB,CAAC,IAAyB,QAAuB;AACtE,UAAQ,KAAK,iBAAiB,EAAE,WAAW,GAAG;AAChD;AAEO,IAAM,qBAAqB,CAAC,YAAmD;AACpF,QAAM,EAAE,MAAM,SAAS,UAAU,eAAe,IAAI;AAEpD,SAAO;AAAA,IACL,cAAc,CAAC,WACb,kBAAkB,MAAM,MAAM,EAAE;AAAA,MAC9BC,QAAO,QAAQ,OAAO;AAAA,MACtBA,QAAO,MAAM,CAAC,QAAiBA,QAAO,KAAK,MAAM,QAAQ,UAAU,GAAG,CAAC,CAAC;AAAA,IAC1E;AAAA,IAEF,cAAc,CAAC,cACb,uBAAuB,MAAM,SAAS,EAAE;AAAA,MACtCA,QAAO,QAAQ,OAAO;AAAA,MACtBA,QAAO,MAAM,CAAC,QAAiBA,QAAO,KAAK,MAAM,QAAQ,UAAU,GAAG,CAAC,CAAC;AAAA,IAC1E;AAAA,EACJ;AACF;","names":["Schema","Schema","fs","jsonc","Effect","Schema","Schema","Effect","require","Effect","FileSystem","jsonc","fs","edits","Effect","Effect"]}
|
package/dist/load-plugins.d.ts
CHANGED
|
@@ -1,4 +1,11 @@
|
|
|
1
|
+
import { Schema } from "effect";
|
|
1
2
|
import type { AnyPlugin } from "@executor-js/sdk";
|
|
3
|
+
declare const LoadPluginsError_base: Schema.Class<LoadPluginsError, Schema.TaggedStruct<"LoadPluginsError", {
|
|
4
|
+
readonly message: Schema.String;
|
|
5
|
+
readonly cause: Schema.optional<Schema.Unknown>;
|
|
6
|
+
}>, import("effect/Cause").YieldableError>;
|
|
7
|
+
export declare class LoadPluginsError extends LoadPluginsError_base {
|
|
8
|
+
}
|
|
2
9
|
export interface LoadPluginsFromJsoncOptions {
|
|
3
10
|
/** Absolute path to `executor.jsonc` (or compatible). */
|
|
4
11
|
readonly path: string;
|
|
@@ -16,4 +23,5 @@ export interface LoadPluginsFromJsoncOptions {
|
|
|
16
23
|
* the static `executor.config.ts` factory."
|
|
17
24
|
*/
|
|
18
25
|
export declare const loadPluginsFromJsonc: (options: LoadPluginsFromJsoncOptions) => Promise<readonly AnyPlugin[] | null>;
|
|
26
|
+
export {};
|
|
19
27
|
//# sourceMappingURL=load-plugins.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"load-plugins.d.ts","sourceRoot":"","sources":["../src/load-plugins.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"load-plugins.d.ts","sourceRoot":"","sources":["../src/load-plugins.ts"],"names":[],"mappings":"AA4BA,OAAO,EAAU,MAAM,EAAE,MAAM,QAAQ,CAAC;AAExC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;;;;;AAWlD,qBAAa,gBAAiB,SAAQ,qBAMrC;CAAG;AAEJ,MAAM,WAAW,2BAA2B;IAC1C,yDAAyD;IACzD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;;;;;OAKG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CACnD;AAED;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,GAC/B,SAAS,2BAA2B,KACnC,OAAO,CAAC,SAAS,SAAS,EAAE,GAAG,IAAI,CAA2D,CAAC"}
|
package/dist/load.d.ts
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
|
-
import { Effect } from "effect";
|
|
1
|
+
import { Effect, Schema } from "effect";
|
|
2
2
|
import { FileSystem } from "effect";
|
|
3
3
|
import type { PlatformError } from "effect/PlatformError";
|
|
4
4
|
import { ExecutorFileConfig } from "./schema";
|
|
5
|
-
|
|
6
|
-
readonly path:
|
|
7
|
-
readonly message:
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
declare const ConfigParseError_base: Schema.Class<ConfigParseError, Schema.TaggedStruct<"ConfigParseError", {
|
|
6
|
+
readonly path: Schema.String;
|
|
7
|
+
readonly message: Schema.String;
|
|
8
|
+
}>, import("effect/Cause").YieldableError>;
|
|
9
|
+
export declare class ConfigParseError extends ConfigParseError_base {
|
|
10
10
|
}
|
|
11
11
|
/**
|
|
12
12
|
* Load and validate an executor config file.
|
|
13
13
|
* Returns null if the file doesn't exist.
|
|
14
14
|
*/
|
|
15
15
|
export declare const loadConfig: (path: string) => Effect.Effect<ExecutorFileConfig | null, ConfigParseError | PlatformError, FileSystem.FileSystem>;
|
|
16
|
+
export {};
|
|
16
17
|
//# sourceMappingURL=load.d.ts.map
|
package/dist/load.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"load.d.ts","sourceRoot":"","sources":["../src/load.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"load.d.ts","sourceRoot":"","sources":["../src/load.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AACxC,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AACpC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAE1D,OAAO,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;;;;;AAE9C,qBAAa,gBAAiB,SAAQ,qBAMrC;CAAG;AAEJ;;;GAGG;AACH,eAAO,MAAM,UAAU,GACrB,MAAM,MAAM,KACX,MAAM,CAAC,MAAM,CACd,kBAAkB,GAAG,IAAI,EACzB,gBAAgB,GAAG,aAAa,EAChC,UAAU,CAAC,UAAU,CA+BnB,CAAC"}
|
package/dist/sink.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sink.d.ts","sourceRoot":"","sources":["../src/sink.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AACpC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAEzC,OAAO,EAAqB,KAAK,iBAAiB,EAAE,KAAK,YAAY,EAAE,MAAM,UAAU,CAAC;AAKxF,KAAK,iBAAiB,GAAG,MAAM,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAExE,eAAO,MAAM,mBAAmB,
|
|
1
|
+
{"version":3,"file":"sink.d.ts","sourceRoot":"","sources":["../src/sink.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AACpC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAEzC,OAAO,EAAqB,KAAK,iBAAiB,EAAE,KAAK,YAAY,EAAE,MAAM,UAAU,CAAC;AAKxF,KAAK,iBAAiB,GAAG,MAAM,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAExE,eAAO,MAAM,mBAAmB,GAAI,OAAO,iBAAiB,KAAG,iBAI9D,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAChC,SAAS,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,GAAG,SAAS,KACrD,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,GAAG,SAKtC,CAAC;AAEF,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,YAAY,EAAE,CAAC,MAAM,EAAE,YAAY,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACrE,QAAQ,CAAC,YAAY,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;CACnE;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,KAAK,CAAC,KAAK,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;IACrD,oEAAoE;IACpE,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,EAAE,QAAQ,GAAG,QAAQ,EAAE,GAAG,EAAE,OAAO,KAAK,IAAI,CAAC;CACpE;AAMD,eAAO,MAAM,kBAAkB,GAAI,SAAS,qBAAqB,KAAG,cAgBnE,CAAC"}
|
package/dist/write.d.ts
CHANGED
|
@@ -2,6 +2,12 @@ import { Effect } from "effect";
|
|
|
2
2
|
import { FileSystem } from "effect";
|
|
3
3
|
import type { PlatformError } from "effect/PlatformError";
|
|
4
4
|
import type { SourceConfig, ExecutorFileConfig } from "./schema";
|
|
5
|
+
export declare class ConfigWriteError {
|
|
6
|
+
readonly path: string;
|
|
7
|
+
readonly cause: unknown;
|
|
8
|
+
readonly _tag = "ConfigWriteError";
|
|
9
|
+
constructor(path: string, cause: unknown);
|
|
10
|
+
}
|
|
5
11
|
/**
|
|
6
12
|
* Add a source entry to the config file. Creates the file if it doesn't exist.
|
|
7
13
|
* Preserves existing comments and formatting.
|
|
@@ -14,7 +20,7 @@ export declare const removeSourceFromConfig: (path: string, namespace: string) =
|
|
|
14
20
|
/**
|
|
15
21
|
* Write a full config object to a file.
|
|
16
22
|
*/
|
|
17
|
-
export declare const writeConfig: (path: string, config: ExecutorFileConfig) => Effect.Effect<void, PlatformError, FileSystem.FileSystem>;
|
|
23
|
+
export declare const writeConfig: (path: string, config: ExecutorFileConfig) => Effect.Effect<void, ConfigWriteError | PlatformError, FileSystem.FileSystem>;
|
|
18
24
|
/**
|
|
19
25
|
* Add secret metadata to the config file.
|
|
20
26
|
*/
|
package/dist/write.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"write.d.ts","sourceRoot":"","sources":["../src/write.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AACpC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAE1D,OAAO,KAAK,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"write.d.ts","sourceRoot":"","sources":["../src/write.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AACpC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAE1D,OAAO,KAAK,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAEjE,qBAAa,gBAAgB;IAGzB,QAAQ,CAAC,IAAI,EAAE,MAAM;IACrB,QAAQ,CAAC,KAAK,EAAE,OAAO;IAHzB,QAAQ,CAAC,IAAI,sBAAsB;gBAExB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,OAAO;CAE1B;AAyBD;;;GAGG;AACH,eAAO,MAAM,iBAAiB,GAC5B,MAAM,MAAM,EACZ,QAAQ,YAAY,KACnB,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,aAAa,EAAE,UAAU,CAAC,UAAU,CAyCvD,CAAC;AAEL;;GAEG;AACH,eAAO,MAAM,sBAAsB,GACjC,MAAM,MAAM,EACZ,WAAW,MAAM,KAChB,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,aAAa,EAAE,UAAU,CAAC,UAAU,CA2BvD,CAAC;AAEL;;GAEG;AACH,eAAO,MAAM,WAAW,GACtB,MAAM,MAAM,EACZ,QAAQ,kBAAkB,KACzB,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,gBAAgB,GAAG,aAAa,EAAE,UAAU,CAAC,UAAU,CAQ1E,CAAC;AAEL;;GAEG;AACH,eAAO,MAAM,iBAAiB,GAC5B,MAAM,MAAM,EACZ,UAAU,MAAM,EAChB,UAAU;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,KAC9D,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,aAAa,EAAE,UAAU,CAAC,UAAU,CAWvD,CAAC;AAEL;;GAEG;AACH,eAAO,MAAM,sBAAsB,GACjC,MAAM,MAAM,EACZ,UAAU,MAAM,KACf,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,aAAa,EAAE,UAAU,CAAC,UAAU,CAcvD,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@executor-js/config",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "1.4.20",
|
|
4
4
|
"homepage": "https://github.com/RhysSullivan/executor/tree/main/packages/core/config",
|
|
5
5
|
"bugs": {
|
|
6
6
|
"url": "https://github.com/RhysSullivan/executor/issues"
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"typecheck:slow": "tsc --noEmit"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@executor-js/sdk": "
|
|
36
|
+
"@executor-js/sdk": "1.4.20",
|
|
37
37
|
"effect": "4.0.0-beta.59",
|
|
38
38
|
"jiti": "^2.6.1",
|
|
39
39
|
"jsonc-parser": "^3.3.1"
|