a2a-exposed 0.5.0 → 0.6.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.
Files changed (44) hide show
  1. package/README.md +3 -4
  2. package/lib/a2a.mjs +6 -2
  3. package/lib/commands.mjs +24 -15
  4. package/lib/deploy.mjs +20 -17
  5. package/lib/main.mjs +24 -9
  6. package/lib/pair.mjs +47 -3
  7. package/lib/status.mjs +4 -4
  8. package/lib/tunnel.mjs +11 -11
  9. package/lib/update.mjs +1 -1
  10. package/package.json +1 -1
  11. package/worker/cloudflare.config.ts +50 -7
  12. package/worker/deploy.env.example +28 -1
  13. package/worker/migrations/0008_oidc_txns.sql +12 -0
  14. package/worker/package.json +6 -2
  15. package/worker/src/approval-oidc.ts +247 -0
  16. package/worker/src/backup.ts +186 -0
  17. package/worker/src/directory.ts +120 -0
  18. package/worker/src/export.ts +156 -0
  19. package/worker/src/hosted.ts +403 -0
  20. package/worker/src/index.ts +737 -584
  21. package/worker/src/mcp.ts +30 -12
  22. package/worker/src/migrations.ts +22 -0
  23. package/worker/src/pairing.ts +17 -4
  24. package/worker/src/sql-raw.d.ts +5 -0
  25. package/worker/src/storage.ts +100 -0
  26. package/worker/src/tenancy.ts +450 -0
  27. package/worker/src/wake.ts +3 -2
  28. package/worker/test/alarms.test.ts +231 -0
  29. package/worker/test/approval-oidc.test.ts +331 -0
  30. package/worker/test/bridge-thread.mjs +40 -0
  31. package/worker/test/d1.ts +146 -2
  32. package/worker/test/directory.test.ts +90 -0
  33. package/worker/test/export.test.ts +544 -0
  34. package/worker/test/facade.test.ts +1 -1
  35. package/worker/test/harness-worker.ts +80 -0
  36. package/worker/test/hosted.test.ts +221 -0
  37. package/worker/test/migrations.test.ts +5 -5
  38. package/worker/test/pairing.test.ts +5 -4
  39. package/worker/test/register-hooks.mjs +4 -0
  40. package/worker/test/sql-raw-hook.mjs +22 -0
  41. package/worker/test/storage.test.ts +74 -0
  42. package/worker/test/tenancy.test.ts +217 -0
  43. package/worker/test/wake-retry.test.ts +24 -1
  44. package/worker/test/wake.test.ts +3 -0
@@ -2,8 +2,9 @@
2
2
  // re-sent after Retry-After, at most 3 times. Run: npm test
3
3
  import { test } from "node:test";
4
4
  import assert from "node:assert/strict";
5
- import worker from "../src/index.ts";
5
+ import worker, { nextCronAt } from "../src/index.ts";
6
6
  import { d1 } from "./d1.ts";
7
+ import { resolveTenant } from "../src/tenancy.ts";
7
8
 
8
9
  const BASE = "https://agent.example.com";
9
10
  const realNow = Date.now;
@@ -49,3 +50,25 @@ test("429 with Retry-After: the wake is re-sent after the wait, merged with newe
49
50
  assert.equal(sent.length, 5);
50
51
  assert.equal(row().pending_json, null);
51
52
  });
53
+
54
+ test("a 429 is due at Retry-After when the debounce is longer", async (t) => {
55
+ const env: any = { DB: d1(new URL("../migrations/", import.meta.url)), PUBLIC_URL: BASE, OWNER_TOKEN: "owner-secret", WAKE_PRESET: "generic",
56
+ WAKE_WEBHOOK_URL: "https://example.com/hook", WAKE_WEBHOOK_KEY: "k", WAKE_DEBOUNCE_SECONDS: "120" };
57
+ const sent: any[] = [];
58
+ const orig = globalThis.fetch;
59
+ globalThis.fetch = (async () => { sent.push(1); return new Response("{}", { status: 429, headers: { "retry-after": "30" } }); }) as any;
60
+ t.after(() => { globalThis.fetch = orig; });
61
+ const pending: Promise<unknown>[] = [];
62
+ const ectx = { waitUntil: (p: Promise<unknown>) => pending.push(p), passThroughOnException() {} };
63
+ const call = async (method: string, path: string, json?: any, auth = "Bearer owner-secret") => {
64
+ const res = await worker.fetch(new Request(BASE + path, { method, headers: { "content-type": "application/json", authorization: auth }, body: json ? JSON.stringify(json) : undefined }) as any, env, ectx as any);
65
+ await Promise.race([Promise.allSettled(pending), new Promise((r) => setTimeout(r, 200))]);
66
+ return res.json().catch(() => null);
67
+ };
68
+ const tok = (await call("POST", "/owner/peers", { label: "barry" })).token;
69
+ const before = Date.now();
70
+ await call("POST", "/", { jsonrpc: "2.0", id: 1, method: "message/send", params: { message: { kind: "message", role: "user", messageId: "m1", contextId: "ctx-long", parts: [{ kind: "text", text: "one" }] } } }, `Bearer ${tok}`);
71
+ assert.equal(sent.length, 1);
72
+ const at = await nextCronAt(resolveTenant(env), Date.now());
73
+ assert.ok(at != null && at >= before + 25_000 && at <= before + 35_000, `alarm ${at} is Retry-After, not the 120s debounce`);
74
+ });
@@ -35,6 +35,9 @@ test("claude-code: anthropic-version + text body", async () => {
35
35
  assert.match(b.text, /a2a-exposed connector \(MCP tools/, "the connector comes first");
36
36
  assert.ok(b.text.indexOf("connector") < b.text.indexOf("A2A_OWNER_TOKEN"), "the CLI is the fallback");
37
37
  assert.match(b.text, /never ask for the token in chat/);
38
+ assert.match(b.text, /npx -y a2a-exposed@latest inbox/, "the default hint runs the CLI through npx");
39
+ assert.match(b.text, /run as `npx -y a2a-exposed@latest`, no global install/);
40
+ assert.ok(!/npm i(nstall)? -g/.test(b.text), "never asks for a global install");
38
41
  assert.ok(!b.text.includes("Bearer rt") && !b.text.includes(" rt "), "no secret in the text");
39
42
  });
40
43