@a2a-exposed/control-core 0.8.22 → 0.8.24

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.js CHANGED
@@ -293,7 +293,10 @@ var WAKE_SECRET_KEYS = [
293
293
  "WAKE_HMAC_SECRET",
294
294
  "WAKE_ACCESS_CLIENT_ID",
295
295
  "WAKE_ACCESS_CLIENT_SECRET",
296
- "EVENT_SECRET"
296
+ "EVENT_SECRET",
297
+ "UPSTREAM_TOKEN",
298
+ "UPSTREAM_ACCESS_CLIENT_ID",
299
+ "UPSTREAM_ACCESS_CLIENT_SECRET"
297
300
  ];
298
301
  var MAX_WAKE_VALUE = 4096;
299
302
  var MAX_WAKE_PLAIN = (() => {
@@ -560,10 +563,13 @@ async function saveWakeSettings(db, plane, secretsKey, input) {
560
563
  const keyHeader = input.keyHeader.trim();
561
564
  const key = input.key.trim();
562
565
  const hmacSecret = (input.hmacSecret ?? "").trim();
566
+ const accessClientId = (input.accessClientId ?? "").trim();
567
+ const accessClientSecret = (input.accessClientSecret ?? "").trim();
563
568
  if (wakeUrlProblem(url)) return { ok: false, error: "url" };
564
569
  if (!WAKE_PRESETS.includes(preset)) return { ok: false, error: "preset" };
565
570
  if (wakeHeaderProblem(keyHeader)) return { ok: false, error: "header" };
566
- if ([key, hmacSecret].some((value) => value.length > 4096 || /[\u0000-\u001f]/.test(value))) return { ok: false, error: "key" };
571
+ if ([key, hmacSecret, accessClientId, accessClientSecret].some((value) => value.length > 4096 || /[\u0000-\u001f]/.test(value))) return { ok: false, error: "key" };
572
+ if (url && Boolean(accessClientId) !== Boolean(accessClientSecret)) return { ok: false, error: "key" };
567
573
  if (url && preset === "openbot" && (key || keyHeader)) return { ok: false, error: keyHeader ? "header" : "key" };
568
574
  const config = configFields(row.config_json);
569
575
  const plaintext = {};
@@ -576,7 +582,7 @@ async function saveWakeSettings(db, plane, secretsKey, input) {
576
582
  const sameKey = same && (config.WAKE_KEY_HEADER ?? "") === keyHeader;
577
583
  let secretsEnc = row.secrets_enc;
578
584
  const hasSecrets = !!secretsEnc || Object.keys(plaintext).length > 0;
579
- if (hasSecrets || key || hmacSecret || url && preset === "openbot") {
585
+ if (hasSecrets || key || hmacSecret || accessClientId || accessClientSecret || url && preset === "openbot") {
580
586
  const ikm = secretsKey.trim();
581
587
  if (!ikm) return { ok: false, error: "unavailable" };
582
588
  const current = secretsEnc ? await openWakeSecrets(ikm, row.id, secretsEnc) : { ...plaintext };
@@ -584,6 +590,14 @@ async function saveWakeSettings(db, plane, secretsKey, input) {
584
590
  const before = JSON.stringify(current);
585
591
  if (!url || !sameKey || preset === "openbot") delete current.WAKE_WEBHOOK_KEY;
586
592
  if (!url || !same) delete current.WAKE_HMAC_SECRET;
593
+ if (!url || config.WAKE_WEBHOOK_URL !== url) {
594
+ delete current.WAKE_ACCESS_CLIENT_ID;
595
+ delete current.WAKE_ACCESS_CLIENT_SECRET;
596
+ }
597
+ if (url && accessClientId && accessClientSecret) {
598
+ current.WAKE_ACCESS_CLIENT_ID = accessClientId;
599
+ current.WAKE_ACCESS_CLIENT_SECRET = accessClientSecret;
600
+ }
587
601
  if (url && key && preset !== "openbot") current.WAKE_WEBHOOK_KEY = key;
588
602
  if (url && hmacSecret) current.WAKE_HMAC_SECRET = hmacSecret;
589
603
  if (url && preset === "openbot" && !current.WAKE_HMAC_SECRET) return { ok: false, error: "key" };
@@ -3035,6 +3049,12 @@ var conversation_peer_owner_default = "-- One row per peer. The same context id
3035
3049
  // sql-raw:/home/runner/work/a2a-exposed/a2a-exposed/worker/migrations/0013_reply_delivery.sql
3036
3050
  var reply_delivery_default = "-- One delivery outcome for one logical owner reply. The key includes the inbound turn and reply content,\n-- so an HTTP/MCP retry is idempotent while a later peer message permits the same words to be sent again.\nCREATE TABLE IF NOT EXISTS reply_deliveries (\n delivery_key TEXT PRIMARY KEY,\n task_id TEXT NOT NULL,\n message_id TEXT NOT NULL,\n result_json TEXT,\n created_at TEXT NOT NULL,\n updated_at TEXT NOT NULL\n);\nCREATE INDEX IF NOT EXISTS reply_deliveries_task ON reply_deliveries(task_id, created_at);\n";
3037
3051
 
3052
+ // sql-raw:/home/runner/work/a2a-exposed/a2a-exposed/worker/migrations/0014_peer_address.sql
3053
+ var peer_address_default = "-- Pairing identity and the last verified callback address. Existing rows stay valid: every new column is nullable,\n-- so a peer paired before this migration keeps its token and has no callback until it announces one.\nALTER TABLE peers ADD COLUMN identity_key TEXT;\nALTER TABLE peers ADD COLUMN card_url TEXT;\nALTER TABLE peers ADD COLUMN previous_card_url TEXT;\nALTER TABLE peers ADD COLUMN previous_until_ms INTEGER;\n-- Sealed copy of a return token this inbox minted (source = 'reverse'). Null for every other peer.\n-- The owner API never selects this column. Export omits it.\nALTER TABLE peers ADD COLUMN token_enc TEXT;\nALTER TABLE device_requests ADD COLUMN identity_key TEXT;\n";
3054
+
3055
+ // sql-raw:/home/runner/work/a2a-exposed/a2a-exposed/worker/migrations/0015_outbound_source.sql
3056
+ var outbound_source_default = "-- Who created an outbound peer. NULL is an owner upload (`peers sync`). `announce` is a row this\n-- inbox created from a verified PeerAddressUpdate. An announcement must not repoint any other row.\nALTER TABLE outbound_peers ADD COLUMN source TEXT;\n";
3057
+
3038
3058
  // src/provision/inbox-migrations.ts
3039
3059
  var INBOX_MIGRATIONS = [
3040
3060
  { name: "0001_init.sql", sql: init_default },
@@ -3049,7 +3069,9 @@ var INBOX_MIGRATIONS = [
3049
3069
  { name: "0010_conversation_peer.sql", sql: conversation_peer_default },
3050
3070
  { name: "0011_conversation_owner.sql", sql: conversation_owner_default },
3051
3071
  { name: "0012_conversation_peer_owner.sql", sql: conversation_peer_owner_default },
3052
- { name: "0013_reply_delivery.sql", sql: reply_delivery_default }
3072
+ { name: "0013_reply_delivery.sql", sql: reply_delivery_default },
3073
+ { name: "0014_peer_address.sql", sql: peer_address_default },
3074
+ { name: "0015_outbound_source.sql", sql: outbound_source_default }
3053
3075
  ];
3054
3076
 
3055
3077
  // sql-raw:/home/runner/work/a2a-exposed/a2a-exposed/control/migrations/0001_auth.sql
@@ -25,8 +25,9 @@ export interface OwnerCall {
25
25
  /** Allowlisted query parameters only. */
26
26
  query?: Record<string, string>;
27
27
  /**
28
- * Tool arguments for `POST /owner/mcp/send`, `POST /owner/mcp/reply`, and `POST /owner/mcp/mark_working`.
29
- * Any other call refuses a body.
28
+ * Tool arguments for `POST /owner/mcp/send`, `POST /owner/mcp/reply`, `POST /owner/mcp/mark_working`,
29
+ * and `POST /owner/mcp/announce_address`. `PUT /owner/outbound-peers/:alias`, `PUT /owner/address-forward`,
30
+ * and `POST /owner/peers/announce` also take a body. Any other call refuses a body.
30
31
  */
31
32
  body?: unknown;
32
33
  /** Approve or deny after a recent sign-in. */
@@ -1,5 +1,5 @@
1
1
  /** Sealed secret fields. Anything else in the blob is ignored. */
2
- export declare const WAKE_SECRET_KEYS: readonly ["WAKE_WEBHOOK_KEY", "WAKE_HMAC_SECRET", "WAKE_ACCESS_CLIENT_ID", "WAKE_ACCESS_CLIENT_SECRET", "EVENT_SECRET"];
2
+ export declare const WAKE_SECRET_KEYS: readonly ["WAKE_WEBHOOK_KEY", "WAKE_HMAC_SECRET", "WAKE_ACCESS_CLIENT_ID", "WAKE_ACCESS_CLIENT_SECRET", "EVENT_SECRET", "UPSTREAM_TOKEN", "UPSTREAM_ACCESS_CLIENT_ID", "UPSTREAM_ACCESS_CLIENT_SECRET"];
3
3
  export type WakeSecretKey = (typeof WAKE_SECRET_KEYS)[number];
4
4
  export type WakeSecrets = Partial<Record<WakeSecretKey, string>>;
5
5
  /** One secret. The form uses the same cap. */
@@ -7,7 +7,7 @@ export interface WakeSettings {
7
7
  preset: string;
8
8
  keyHeader: string;
9
9
  }
10
- /** Blank credentials retain a saved value only for the same URL and authentication mode.
10
+ /** Blank webhook/signing credentials retain a saved value only for the same URL and authentication mode.
11
11
  * Callers validate public DNS before saving; the Worker enforces its delivery policy separately. */
12
12
  export interface WakeSaveInput {
13
13
  accountId: string;
@@ -17,6 +17,9 @@ export interface WakeSaveInput {
17
17
  keyHeader: string;
18
18
  key: string;
19
19
  hmacSecret?: string;
20
+ /** Both fields are required when replacing a tunnel Access service token. */
21
+ accessClientId?: string;
22
+ accessClientSecret?: string;
20
23
  /** Version of the settings the caller tested. A stale version makes no write. */
21
24
  expectedVersion?: number;
22
25
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@a2a-exposed/control-core",
3
- "version": "0.8.22",
3
+ "version": "0.8.24",
4
4
  "description": "A2A endpoint provisioning, routing, and D1 migrations for a2a-exposed.",
5
5
  "type": "module",
6
6
  "scripts": {