apcore-a2a 0.6.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -32,6 +32,7 @@ Built on [`@a2a-js/sdk`](https://www.npmjs.com/package/@a2a-js/sdk) and [Express
32
32
  - **JWT authentication** — tokens bridged to apcore's Identity context
33
33
  - **A2A Explorer UI** — browser UI for discovering and testing skills, with auth bar and cURL generation
34
34
  - **Built-in client** — `A2AClient` for calling remote A2A agents
35
+ - **OpenAPI backend** — point the adapter at an OpenAPI 3.0/3.1 document and every operation becomes an A2A Skill, proxied over HTTP, with no apcore project on the other end
35
36
  - **CLI support** — `npx apcore-a2a serve` for zero-code startup
36
37
  - **Pluggable storage** — swap in Redis or PostgreSQL via the `TaskStore` interface
37
38
  - **Observability** — `/health`, `/metrics` endpoints
@@ -40,7 +41,15 @@ Built on [`@a2a-js/sdk`](https://www.npmjs.com/package/@a2a-js/sdk) and [Express
40
41
  ## Requirements
41
42
 
42
43
  - Node.js >= 18.0.0
43
- - `apcore-js` >= 0.28.0
44
+ - `apcore-js` >= 0.30.0
45
+ - `apcore-toolkit` >= 0.11.1
46
+
47
+ > **OpenAPI backend.** No extra install. The backend needs apcore-toolkit's
48
+ > `OpenAPIScanner`, `loadSpec` and `HTTPProxyRegistryWriter`, all of which ship in
49
+ > the `apcore-toolkit` dependency above and use the global `fetch` available on
50
+ > Node 18+ — so this package declares no `openapi` optional dependency. (The
51
+ > Python distribution declares an `apcore-a2a[openapi]` extra because there the
52
+ > same three pieces sit behind `apcore-toolkit[http-proxy]`.)
44
53
 
45
54
  ---
46
55
 
@@ -80,6 +89,68 @@ npx apcore-a2a serve --extensions-dir ./extensions --port 3000 --explorer --metr
80
89
  npx apcore-a2a serve --extensions-dir ./extensions --auth-type bearer --auth-key mysecret
81
90
  ```
82
91
 
92
+ ### Serve an OpenAPI document as A2A Skills
93
+
94
+ Point the adapter at an OpenAPI 3.0/3.1 document and every operation becomes a
95
+ skill, proxied over HTTP to the API that published it. No apcore project required
96
+ on the other end.
97
+
98
+ ```bash
99
+ npx apcore-a2a serve \
100
+ --from-openapi https://petstore3.swagger.io/api/v3/openapi.json \
101
+ --openapi-prefix petstore \
102
+ --openapi-header "X-Api-Key: $PETSTORE_SPEC_KEY" \
103
+ --openapi-no-deprecated
104
+ ```
105
+
106
+ ```typescript
107
+ import { openapiBackend, serve } from "apcore-a2a";
108
+
109
+ const registry = await openapiBackend("https://api.example.com/openapi.json", {
110
+ prefix: "petstore", // prepended to every derived module ID
111
+ baseUrl: "https://api.example.com", // defaults to servers[0].url
112
+ include: "pets\\..*", // scanner filters
113
+ timeout: 30, // SPEC-FETCH timeout, in SECONDS
114
+ headers: { "X-Api-Key": process.env.PETSTORE_SPEC_KEY! }, // spec fetch only
115
+ authHeaderFactory: () => ({ Authorization: `Bearer ${mintToken()}` }), // proxied calls
116
+ });
117
+
118
+ serve(registry);
119
+ ```
120
+
121
+ Or configure it entirely through the Config Bus:
122
+
123
+ ```yaml
124
+ apcore-a2a:
125
+ openapi:
126
+ spec: "https://api.example.com/openapi.json" # URL, or a path resolved against Config.projectRoot
127
+ base_url: "https://api.example.com"
128
+ prefix: petstore
129
+ include: "pets.*"
130
+ exclude: "*.internal.*"
131
+ include_deprecated: false
132
+ acknowledge_unapproved_writes: false
133
+ timeout: 30.0 # spec fetch, seconds — never the per-call proxy timeout
134
+ headers:
135
+ X-Api-Key: "${PETSTORE_SPEC_KEY}"
136
+ ```
137
+
138
+ Three things are worth knowing before pointing this at a production API:
139
+
140
+ - **Write operations reach the PUBLIC Agent Card.** apcore-toolkit infers
141
+ annotations from the HTTP method and never infers `requiresApproval`, so a
142
+ `POST /charges` is annotated exactly like a `POST /echo` and appears on
143
+ `/.well-known/agent-card.json`, a route that is auth-exempt by design. The
144
+ backend logs a warning naming that exposure; close it with an ACL rule carrying
145
+ `approval: required` (which also withholds the skill from the public card), or
146
+ record the decision with `acknowledge_unapproved_writes: true`.
147
+ - **`headers` authenticate the spec fetch only.** They are never forwarded to
148
+ proxied calls: a document is often public while the API behind it is not.
149
+ Per-request credentials belong in `authHeaderFactory`.
150
+ - **ACL targets move when the upstream renames an operation.** Set `prefix` and
151
+ write the catch-all deny against the prefix (`targets: ["petstore.*"]`), not
152
+ against operation names.
153
+
83
154
  ### Call a remote A2A Agent
84
155
 
85
156
  Use the built-in client to discover and invoke any A2A-compliant agent:
package/dist/cli.d.ts CHANGED
@@ -1,4 +1,67 @@
1
1
  #!/usr/bin/env node
2
+ import { parseArgs } from "node:util";
3
+ /**
4
+ * The `values` half of a `parseArgs` result under `strict: false`.
5
+ *
6
+ * Wider than the flag table suggests on purpose: with `strict: false` node
7
+ * accepts `--metrics=x` for a boolean and repeats for a non-`multiple` option,
8
+ * so every entry may arrive as a string, a boolean, or an array of either.
9
+ */
10
+ type CliValues = Record<string, string | boolean | (string | boolean)[] | undefined>;
11
+ /**
12
+ * Exit `2` — a usage error. The command line itself is wrong.
13
+ *
14
+ * Distinguished from {@link fail} because retrying an exit-2 command unchanged
15
+ * will always fail, while an exit-1 command may succeed once the directory,
16
+ * config or network it named is fixed. That is a difference a supervisor or CI
17
+ * job can act on, and this SDK previously collapsed both onto `1` — losing a
18
+ * distinction Python's argparse and Rust's clap each provide for free.
19
+ *
20
+ * `2` rather than some other number because it is what argparse, clap and GNU
21
+ * getopt all use for a usage fault, so the three bindings agree with each other
22
+ * and with the tools around them.
23
+ */
24
+ export declare function failUsage(message: string): never;
2
25
  export declare function resolveAuthKey(authKey?: string): string | undefined;
26
+ /**
27
+ * Parse `serve`'s argv.
28
+ *
29
+ * Split out of {@link main} so the flag surface is reachable without starting a
30
+ * server: the `--openapi-no-deprecated` contract is half in this table (no
31
+ * `default`) and half in {@link mergeOpenapiSettings} (the presence check), and
32
+ * either half alone silently reverses a config `include_deprecated: false`.
33
+ */
34
+ export declare function parseCliArgs(args?: string[]): ReturnType<typeof parseArgs>;
3
35
  export declare function main(): Promise<void>;
36
+ /**
37
+ * Parse repeated `--openapi-header "Key: Value"` flags into a header map.
38
+ *
39
+ * These authenticate the **spec fetch only**. They are deliberately not reused
40
+ * for proxied calls: a document is often public while the API behind it is not,
41
+ * and broadcasting a spec-read key on every skill invocation would be a
42
+ * privilege escalation the operator never wrote down.
43
+ */
44
+ export declare function parseOpenapiHeaders(raw: string[] | undefined): Record<string, string> | undefined;
45
+ /**
46
+ * Resolve the OpenAPI backend settings: CLI flags over the Config Bus.
47
+ *
48
+ * Implements the precedence the feature spec states — **an explicit CLI flag
49
+ * beats the `apcore-a2a.openapi` Config Bus section, which beats the default** —
50
+ * and implements it PER KEY, not per source. Choosing the whole source by
51
+ * whoever named `spec` would make a `--openapi-prefix` alongside a
52
+ * config-declared `spec` a silent no-op: the same shape as the apcore-mcp
53
+ * `--openapi-header` defect this project filed upstream (apcore-mcp-rust#8).
54
+ *
55
+ * The returned mapping is in the Config Bus's own snake_case, so it can be
56
+ * handed straight to `buildOpenapiBackendFromConfig` — which is also what makes
57
+ * `timeout`, `include`, `exclude` and `acknowledge_unapproved_writes` reachable
58
+ * from a running server: none of them has a CLI flag, and before this the
59
+ * section had no reader anywhere in `src/`.
60
+ *
61
+ * Returns `null` when neither route yields a `spec`, which is the ordinary "no
62
+ * OpenAPI configured" outcome rather than an error. A section that is not a
63
+ * mapping is returned UNCHANGED — see below.
64
+ */
65
+ export declare function mergeOpenapiSettings(values: CliValues): Promise<unknown>;
66
+ export {};
4
67
  //# sourceMappingURL=cli.d.ts.map
package/dist/cli.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AA4CA,wBAAgB,cAAc,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAYnE;AAED,wBAAsB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAsD1C"}
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAKA,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAqDtC;;;;;;GAMG;AACH,KAAK,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,GAAG,CAAC,MAAM,GAAG,OAAO,CAAC,EAAE,GAAG,SAAS,CAAC,CAAC;AAarF;;;;;;;;;;;;GAYG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,KAAK,CAEhD;AAED,wBAAgB,cAAc,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAYnE;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,GAAG,UAAU,CAAC,OAAO,SAAS,CAAC,CA6C1E;AAwDD,wBAAsB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CA+B1C;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,MAAM,EAAE,GAAG,SAAS,GACxB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAmBpC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,oBAAoB,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,CAuC9E"}
package/dist/cli.js CHANGED
@@ -9,9 +9,27 @@ apcore-a2a - A2A Protocol Server for apcore modules
9
9
 
10
10
  Usage:
11
11
  apcore-a2a serve --extensions-dir <path> [options]
12
+ apcore-a2a serve --from-openapi <url|path> [options]
12
13
 
13
- Required:
14
+ Required (at least one backend source):
14
15
  --extensions-dir <path> Path to apcore extensions directory
16
+ --from-openapi <url|path> OpenAPI 3.0/3.1 document to serve as A2A Skills.
17
+ Combine with --extensions-dir only when
18
+ --openapi-prefix is also given
19
+
20
+ An apcore-a2a.openapi.spec in your apcore config counts as a backend source
21
+ too, so neither flag is required when the config file names one.
22
+
23
+ OpenAPI backend options (each overrides the matching apcore-a2a.openapi key;
24
+ keys with no flag -- timeout, headers, acknowledge_unapproved_writes -- are
25
+ configured there):
26
+ --openapi-base-url <url> Base URL for proxied calls (default: servers[0].url)
27
+ --openapi-prefix <string> Prefix for every derived module ID
28
+ --openapi-include <regex> Scanner include filter
29
+ --openapi-exclude <regex> Scanner exclude filter
30
+ --openapi-header <K:V> Header for the SPEC FETCH only, repeatable.
31
+ Never forwarded to proxied calls
32
+ --openapi-no-deprecated Skip operations marked deprecated: true
15
33
 
16
34
  Options:
17
35
  --host <address> Bind host (default: 127.0.0.1)
@@ -34,10 +52,32 @@ Options:
34
52
  --help Show this help
35
53
  `);
36
54
  }
55
+ /**
56
+ * Exit `1` — a configuration or runtime error.
57
+ *
58
+ * The command line was well-formed; the environment it named was not. A
59
+ * supervisor may retry these, because the world can become ready.
60
+ */
37
61
  function fail(message, exitCode = 1) {
38
62
  console.error(`Error: ${message}`);
39
63
  process.exit(exitCode);
40
64
  }
65
+ /**
66
+ * Exit `2` — a usage error. The command line itself is wrong.
67
+ *
68
+ * Distinguished from {@link fail} because retrying an exit-2 command unchanged
69
+ * will always fail, while an exit-1 command may succeed once the directory,
70
+ * config or network it named is fixed. That is a difference a supervisor or CI
71
+ * job can act on, and this SDK previously collapsed both onto `1` — losing a
72
+ * distinction Python's argparse and Rust's clap each provide for free.
73
+ *
74
+ * `2` rather than some other number because it is what argparse, clap and GNU
75
+ * getopt all use for a usage fault, so the three bindings agree with each other
76
+ * and with the tools around them.
77
+ */
78
+ export function failUsage(message) {
79
+ return fail(message, 2);
80
+ }
41
81
  export function resolveAuthKey(authKey) {
42
82
  if (authKey) {
43
83
  try {
@@ -52,37 +92,113 @@ export function resolveAuthKey(authKey) {
52
92
  }
53
93
  return process.env.APCORE_JWT_SECRET;
54
94
  }
95
+ /**
96
+ * Parse `serve`'s argv.
97
+ *
98
+ * Split out of {@link main} so the flag surface is reachable without starting a
99
+ * server: the `--openapi-no-deprecated` contract is half in this table (no
100
+ * `default`) and half in {@link mergeOpenapiSettings} (the presence check), and
101
+ * either half alone silently reverses a config `include_deprecated: false`.
102
+ */
103
+ export function parseCliArgs(args) {
104
+ const config = {
105
+ options: {
106
+ "extensions-dir": { type: "string" },
107
+ "from-openapi": { type: "string" },
108
+ "openapi-base-url": { type: "string" },
109
+ "openapi-prefix": { type: "string" },
110
+ "openapi-include": { type: "string" },
111
+ "openapi-exclude": { type: "string" },
112
+ "openapi-header": { type: "string", multiple: true },
113
+ // Deliberately NO `default: false`. `mergeOpenapiSettings` has to tell
114
+ // "not passed" from "passed", because a `false` default would make an
115
+ // absent flag overwrite a config `include_deprecated: false` with `true`
116
+ // — an unpassed flag silently reversing a setting the operator wrote.
117
+ // Same reason the Python binding uses `default=None`.
118
+ "openapi-no-deprecated": { type: "boolean" },
119
+ host: { type: "string", default: "127.0.0.1" },
120
+ port: { type: "string", default: "8000" },
121
+ name: { type: "string" },
122
+ description: { type: "string" },
123
+ "version-str": { type: "string" },
124
+ url: { type: "string" },
125
+ "auth-type": { type: "string" },
126
+ "auth-key": { type: "string" },
127
+ "auth-issuer": { type: "string" },
128
+ "auth-audience": { type: "string" },
129
+ "push-notifications": { type: "boolean", default: false },
130
+ explorer: { type: "boolean", default: false },
131
+ "cors-origins": { type: "string" },
132
+ "execution-timeout": { type: "string", default: "300" },
133
+ "log-level": { type: "string", default: "info" },
134
+ metrics: { type: "boolean", default: false },
135
+ version: { type: "boolean", default: false },
136
+ help: { type: "boolean", default: false },
137
+ },
138
+ allowPositionals: true,
139
+ strict: false,
140
+ };
141
+ // `args: undefined` is NOT the same as omitting it — node's own default
142
+ // (`process.argv` minus the execPath and script) knows about `node --` and
143
+ // single-executable builds, and re-deriving it here would drop that.
144
+ const parsed = args === undefined ? parseArgs(config) : parseArgs({ ...config, args });
145
+ rejectUnknownArguments(parsed, Object.keys(config.options));
146
+ return parsed;
147
+ }
148
+ /**
149
+ * Refuse an argument the flag table does not define.
150
+ *
151
+ * `strict: false` is kept deliberately — it is what lets this CLI tolerate
152
+ * `--metrics=x` for a boolean and a repeat of a non-`multiple` option, both of
153
+ * which `strict: true` would turn into throws — but node's tolerance extends to
154
+ * *unknown* flags too, and there it is not tolerance, it is silence.
155
+ *
156
+ * Measured before this check existed, with a one-letter typo:
157
+ *
158
+ * ```
159
+ * apcore-a2a serve --extensions-dir ./ext --openapi-exclde 'secret.*'
160
+ * values: { "openapi-exclde": true, ... } ← the flag became a boolean
161
+ * positionals: [ "serve", "secret.*" ] ← its value became a positional
162
+ * ```
163
+ *
164
+ * The exclusion silently did not apply, and every operation it was meant to hold
165
+ * back was scanned, registered, and published to the **public** Agent Card — a
166
+ * route served without authentication and built to be crawled. The server
167
+ * started and reported success.
168
+ *
169
+ * Python's argparse (`unrecognized arguments`) and Rust's clap (`unexpected
170
+ * argument ... found`) both refuse this and exit 2; TypeScript was the only
171
+ * binding that did not, so the tolerant behaviour was never portable — the same
172
+ * argv already failed on the other two.
173
+ *
174
+ * Note argparse additionally accepts unambiguous *abbreviations*, so
175
+ * `--openapi-exclud` is a legal spelling there. That is an argparse feature, not
176
+ * a parity requirement: clap does not do it either, and this check is only about
177
+ * spellings no binding recognises.
178
+ */
179
+ function rejectUnknownArguments(parsed, known) {
180
+ const unknown = Object.keys(parsed.values).filter((key) => !known.includes(key));
181
+ if (unknown.length > 0) {
182
+ failUsage(`unrecognized argument${unknown.length > 1 ? "s" : ""}: ` +
183
+ `${unknown.map((k) => `--${k}`).join(", ")}. Run with --help for the flag list`);
184
+ }
185
+ // A stray positional is the same mistake seen from the other side: the value
186
+ // of a misspelled flag lands here, so reporting only the flag would leave the
187
+ // operator wondering where their argument went.
188
+ const strays = parsed.positionals.slice(1);
189
+ if (strays.length > 0) {
190
+ failUsage(`unexpected argument${strays.length > 1 ? "s" : ""}: ${strays.join(", ")}. ` +
191
+ "Run with --help for the flag list");
192
+ }
193
+ }
55
194
  export async function main() {
56
195
  let parsed;
57
196
  try {
58
- parsed = parseArgs({
59
- options: {
60
- "extensions-dir": { type: "string" },
61
- host: { type: "string", default: "127.0.0.1" },
62
- port: { type: "string", default: "8000" },
63
- name: { type: "string" },
64
- description: { type: "string" },
65
- "version-str": { type: "string" },
66
- url: { type: "string" },
67
- "auth-type": { type: "string" },
68
- "auth-key": { type: "string" },
69
- "auth-issuer": { type: "string" },
70
- "auth-audience": { type: "string" },
71
- "push-notifications": { type: "boolean", default: false },
72
- explorer: { type: "boolean", default: false },
73
- "cors-origins": { type: "string" },
74
- "execution-timeout": { type: "string", default: "300" },
75
- "log-level": { type: "string", default: "info" },
76
- metrics: { type: "boolean", default: false },
77
- version: { type: "boolean", default: false },
78
- help: { type: "boolean", default: false },
79
- },
80
- allowPositionals: true,
81
- strict: false,
82
- });
197
+ parsed = parseCliArgs();
83
198
  }
84
199
  catch (e) {
85
- fail(String(e));
200
+ // A parseArgs throw is an unknown flag or a missing value: a usage fault.
201
+ failUsage(String(e));
86
202
  }
87
203
  const { values, positionals } = parsed;
88
204
  if (values.help) {
@@ -101,24 +217,149 @@ export async function main() {
101
217
  }
102
218
  await runServe(values);
103
219
  }
220
+ /**
221
+ * Parse repeated `--openapi-header "Key: Value"` flags into a header map.
222
+ *
223
+ * These authenticate the **spec fetch only**. They are deliberately not reused
224
+ * for proxied calls: a document is often public while the API behind it is not,
225
+ * and broadcasting a spec-read key on every skill invocation would be a
226
+ * privilege escalation the operator never wrote down.
227
+ */
228
+ export function parseOpenapiHeaders(raw) {
229
+ if (!raw || raw.length === 0)
230
+ return undefined;
231
+ const headers = {};
232
+ for (const entry of raw) {
233
+ const separator = entry.indexOf(":");
234
+ // The separator index alone is not the test. `separator <= 0` rejects ":v"
235
+ // but ACCEPTS " :v" — the colon is at index 1 — and the `.trim()` below then
236
+ // yields an EMPTY header name. Python checks `not key.strip()` and Rust
237
+ // `key.trim().is_empty()`; both reject, so the key is trimmed first and
238
+ // judged afterwards.
239
+ const key = separator > 0 ? entry.slice(0, separator).trim() : "";
240
+ if (!key) {
241
+ // Never echo the value back: the whole point of the flag is that it may
242
+ // carry a credential.
243
+ failUsage(`--openapi-header must be "Key: Value" (got an entry with no ':' or no key)`);
244
+ }
245
+ headers[key] = entry.slice(separator + 1).trim();
246
+ }
247
+ return headers;
248
+ }
249
+ /**
250
+ * Resolve the OpenAPI backend settings: CLI flags over the Config Bus.
251
+ *
252
+ * Implements the precedence the feature spec states — **an explicit CLI flag
253
+ * beats the `apcore-a2a.openapi` Config Bus section, which beats the default** —
254
+ * and implements it PER KEY, not per source. Choosing the whole source by
255
+ * whoever named `spec` would make a `--openapi-prefix` alongside a
256
+ * config-declared `spec` a silent no-op: the same shape as the apcore-mcp
257
+ * `--openapi-header` defect this project filed upstream (apcore-mcp-rust#8).
258
+ *
259
+ * The returned mapping is in the Config Bus's own snake_case, so it can be
260
+ * handed straight to `buildOpenapiBackendFromConfig` — which is also what makes
261
+ * `timeout`, `include`, `exclude` and `acknowledge_unapproved_writes` reachable
262
+ * from a running server: none of them has a CLI flag, and before this the
263
+ * section had no reader anywhere in `src/`.
264
+ *
265
+ * Returns `null` when neither route yields a `spec`, which is the ordinary "no
266
+ * OpenAPI configured" outcome rather than an error. A section that is not a
267
+ * mapping is returned UNCHANGED — see below.
268
+ */
269
+ export async function mergeOpenapiSettings(values) {
270
+ // Imported lazily so `--help` and `--version` never pay for loading apcore's
271
+ // Config, mirroring the Python binding's function-local import.
272
+ const { getA2aSetting } = await import("./config.js");
273
+ const section = getA2aSetting("openapi");
274
+ // A section that is not a mapping is passed through untouched, so that
275
+ // `buildOpenapiBackendFromConfig` reports it by name ("apcore-a2a.openapi
276
+ // must be a mapping."). Discarding it instead would turn the typo
277
+ // `openapi: ./spec.json` — a mapping's one key written as the whole value —
278
+ // into "a backend source is required", which sends the operator hunting for a
279
+ // missing flag rather than at the line they wrote. Follows the Rust binding,
280
+ // which diverged from the Python reference here for this reason.
281
+ if (section !== undefined && (typeof section !== "object" || Array.isArray(section))) {
282
+ return section;
283
+ }
284
+ const merged = {
285
+ ...(section ?? {}),
286
+ };
287
+ // Only a flag the operator actually passed is overlaid. Every OpenAPI flag is
288
+ // `undefined` when absent precisely so that "absent" stays distinguishable
289
+ // from "explicitly set to a falsy value".
290
+ const overlay = {
291
+ spec: values["from-openapi"],
292
+ base_url: values["openapi-base-url"],
293
+ prefix: values["openapi-prefix"],
294
+ include: values["openapi-include"],
295
+ exclude: values["openapi-exclude"],
296
+ headers: parseOpenapiHeaders(values["openapi-header"]),
297
+ };
298
+ if (values["openapi-no-deprecated"] !== undefined) {
299
+ overlay.include_deprecated = !values["openapi-no-deprecated"];
300
+ }
301
+ for (const [key, value] of Object.entries(overlay)) {
302
+ if (value !== undefined && value !== null)
303
+ merged[key] = value;
304
+ }
305
+ return merged.spec ? merged : null;
306
+ }
307
+ /** The `spec` of merged settings, when they are a mapping that names one. */
308
+ function specOf(openapi) {
309
+ if (typeof openapi !== "object" || openapi === null)
310
+ return undefined;
311
+ const spec = openapi.spec;
312
+ return typeof spec === "string" ? spec : undefined;
313
+ }
104
314
  async function runServe(values) {
105
315
  const extensionsDir = values["extensions-dir"];
106
- if (!extensionsDir) {
107
- fail("--extensions-dir is required");
316
+ // A backend source may also come from the Config Bus, so the usage check has
317
+ // to consult it — otherwise a valid `apcore-a2a.openapi.spec` in the config
318
+ // file would be rejected for naming no flag.
319
+ const openapi = await mergeOpenapiSettings(values);
320
+ if (!extensionsDir && !openapi) {
321
+ failUsage("one of --extensions-dir or --from-openapi is required " +
322
+ "(or an apcore-a2a.openapi.spec in your apcore config)");
323
+ }
324
+ const { Registry } = await import("apcore-js");
325
+ let registry;
326
+ if (extensionsDir) {
327
+ const resolved = resolve(extensionsDir);
328
+ if (!existsSync(resolved)) {
329
+ fail(`Extensions directory not found: ${resolved}`);
330
+ }
331
+ if (!statSync(resolved).isDirectory()) {
332
+ fail(`Not a directory: ${resolved}`);
333
+ }
334
+ registry = new Registry({ extensionsDir: resolved });
108
335
  }
109
- const resolved = resolve(extensionsDir);
110
- if (!existsSync(resolved)) {
111
- fail(`Extensions directory not found: ${resolved}`);
336
+ else {
337
+ registry = new Registry();
112
338
  }
113
- if (!statSync(resolved).isDirectory()) {
114
- fail(`Not a directory: ${resolved}`);
339
+ if (openapi) {
340
+ const { buildOpenapiBackendFromConfig } = await import("./openapi-backend.js");
341
+ try {
342
+ // The merged mapping, not the raw flags: this is the one route that reads
343
+ // `timeout` and `acknowledge_unapproved_writes`, applies the documented
344
+ // defaults, and resolves a relative `spec` against `Config.projectRoot`
345
+ // rather than the process CWD (FR-OAS-004 AC 5).
346
+ registry =
347
+ (await buildOpenapiBackendFromConfig(openapi, {
348
+ registry,
349
+ // `prefix` is mandatory in a mixed deployment: the scanner
350
+ // deduplicates within one scan only and knows nothing about the
351
+ // project modules already in the registry.
352
+ hasOtherBackendSource: !!extensionsDir,
353
+ })) ?? registry;
354
+ }
355
+ catch (e) {
356
+ // The resolved spec location may appear here; the fetch headers never do.
357
+ fail(`OpenAPI backend: ${e instanceof Error ? e.message : String(e)}`);
358
+ }
115
359
  }
116
- // Load registry
117
- const { Registry } = await import("apcore-js");
118
- const registry = new Registry({ extensionsDir: resolved });
119
360
  const modules = registry.list();
120
361
  if (modules.length === 0) {
121
- fail(`No modules discovered in ${resolved}`);
362
+ fail(`No modules discovered in ${specOf(openapi) ?? extensionsDir}`);
122
363
  }
123
364
  console.log(`Discovered ${modules.length} module(s): ${modules.join(", ")}`);
124
365
  // Build auth
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Config namespace registration and resolution for `apcore-a2a`.
3
+ *
4
+ * Mirrors the Python binding's `apcore_a2a._config`. It lives in its own module
5
+ * rather than in `server/factory.ts` because the CLI has to read the
6
+ * `apcore-a2a.openapi` section *before* it builds a Registry, and therefore long
7
+ * before anything in the server stack is imported — pulling in the factory (and
8
+ * with it express and the whole A2A SDK) just to register a namespace would put
9
+ * the entire server on the startup path of `apcore-a2a serve --help`.
10
+ *
11
+ * Registration must happen from exactly ONE place: apcore's
12
+ * `Config.registerNamespace` throws `ConfigNamespaceDuplicateError` on a second
13
+ * call for the same name, so a second registration site would crash the process
14
+ * at import time rather than being ignored.
15
+ */
16
+ export declare const A2A_NAMESPACE = "apcore-a2a";
17
+ export declare const A2A_ENV_PREFIX = "APCORE_A2A";
18
+ /** The registered namespace defaults (stable in apcore-js >= 0.22.0). */
19
+ export declare const A2A_DEFAULTS: Record<string, unknown>;
20
+ /**
21
+ * Register the `apcore-a2a` config namespace. Safe to call repeatedly.
22
+ *
23
+ * The already-registered case is detected rather than caught: swallowing every
24
+ * exception here would also swallow a genuine `ConfigEnvPrefixConflictError`
25
+ * from another package claiming `APCORE_A2A`, which is a misconfiguration the
26
+ * operator needs to see.
27
+ */
28
+ export declare function registerA2aNamespace(): void;
29
+ /**
30
+ * Resolve one `apcore-a2a` namespace setting through apcore's Config.
31
+ *
32
+ * Delegates to `Config.load` so that values from an apcore config file and
33
+ * `APCORE_A2A_*` environment overrides are applied by apcore itself (namespace
34
+ * mode), exactly like the other apcore bindings. Falls back to `fallback` when
35
+ * the key is unset.
36
+ */
37
+ export declare function getA2aSetting(key: string, fallback?: unknown): unknown;
38
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAIH,eAAO,MAAM,aAAa,eAAe,CAAC;AAC1C,eAAO,MAAM,cAAc,eAAe,CAAC;AAE3C,yEAAyE;AACzE,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAoBhD,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,IAAI,IAAI,CAO3C;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,OAAO,GAAG,OAAO,CAMtE"}