@every-app/sdk 0.3.0-rc.4 → 0.3.0-rc.6

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 (98) hide show
  1. package/LICENSE +21 -0
  2. package/dist/cloudflare/catalogSettings.generated.d.ts +80 -0
  3. package/dist/cloudflare/catalogSettings.generated.d.ts.map +1 -0
  4. package/dist/cloudflare/catalogSettings.generated.js +172 -0
  5. package/dist/cloudflare/index.d.ts +1 -0
  6. package/dist/cloudflare/index.d.ts.map +1 -1
  7. package/dist/cloudflare/index.js +3 -0
  8. package/dist/cloudflare/worker.d.ts +29 -98
  9. package/dist/cloudflare/worker.d.ts.map +1 -1
  10. package/dist/cloudflare/worker.js +45 -132
  11. package/dist/index.d.ts +6 -0
  12. package/dist/index.d.ts.map +1 -0
  13. package/dist/index.js +5 -0
  14. package/dist/internal/aiDefault.d.ts +70 -7
  15. package/dist/internal/aiDefault.d.ts.map +1 -1
  16. package/dist/internal/aiDefault.js +145 -15
  17. package/dist/internal/aiProviders.d.ts +3 -1
  18. package/dist/internal/aiProviders.d.ts.map +1 -1
  19. package/dist/internal/aiProviders.js +12 -3
  20. package/dist/internal/appSettings.d.ts +65 -5
  21. package/dist/internal/appSettings.d.ts.map +1 -1
  22. package/dist/internal/appSettings.js +141 -23
  23. package/dist/internal/capabilities.d.ts +52 -433
  24. package/dist/internal/capabilities.d.ts.map +1 -1
  25. package/dist/internal/capabilities.js +25 -558
  26. package/dist/internal/catalog/index.d.ts +6 -6
  27. package/dist/internal/catalog/inference.d.ts +6 -6
  28. package/dist/internal/catalog/inference.d.ts.map +1 -1
  29. package/dist/internal/catalog/inference.js +9 -6
  30. package/dist/internal/events.d.ts.map +1 -1
  31. package/dist/internal/events.js +1 -0
  32. package/dist/internal/gatewaySettings.d.ts +1 -1
  33. package/dist/internal/gatewaySettings.d.ts.map +1 -1
  34. package/dist/internal/gatewaySettings.js +1 -3
  35. package/dist/internal/identity.d.ts +12 -1
  36. package/dist/internal/identity.d.ts.map +1 -1
  37. package/dist/internal/identity.js +11 -1
  38. package/dist/internal/oauthClient.d.ts +10 -12
  39. package/dist/internal/oauthClient.d.ts.map +1 -1
  40. package/dist/internal/oauthClient.js +20 -81
  41. package/dist/internal/oauthPresets.d.ts +7 -3
  42. package/dist/internal/oauthPresets.d.ts.map +1 -1
  43. package/dist/internal/oauthPresets.js +533 -3
  44. package/dist/internal/oauthSpec.d.ts +44 -1
  45. package/dist/internal/oauthSpec.d.ts.map +1 -1
  46. package/dist/internal/oauthSpec.js +147 -34
  47. package/dist/internal/protocol.d.ts +14 -0
  48. package/dist/internal/protocol.d.ts.map +1 -1
  49. package/dist/internal/protocol.js +7 -0
  50. package/dist/internal/providerRegistry.d.ts +61 -1
  51. package/dist/internal/providerRegistry.d.ts.map +1 -1
  52. package/dist/internal/providerRegistry.js +127 -6
  53. package/dist/internal/providerSpec.d.ts +14 -7
  54. package/dist/internal/providerSpec.d.ts.map +1 -1
  55. package/dist/internal/providerSpec.js +306 -7
  56. package/dist/manifest.d.ts +226 -0
  57. package/dist/manifest.d.ts.map +1 -0
  58. package/dist/manifest.js +30 -0
  59. package/dist/server/ai.d.ts +66 -0
  60. package/dist/server/ai.d.ts.map +1 -1
  61. package/dist/server/ai.js +113 -8
  62. package/dist/server/aiBinding.d.ts +68 -0
  63. package/dist/server/aiBinding.d.ts.map +1 -0
  64. package/dist/server/aiBinding.js +294 -0
  65. package/dist/server/authorizeUrl.d.ts +1 -1
  66. package/dist/server/authorizeUrl.d.ts.map +1 -1
  67. package/dist/server/authorizeUrl.js +2 -6
  68. package/dist/server/emailBinding.d.ts +72 -0
  69. package/dist/server/emailBinding.d.ts.map +1 -0
  70. package/dist/server/emailBinding.js +124 -0
  71. package/dist/server/emit.js +1 -1
  72. package/dist/server/env.d.ts +41 -0
  73. package/dist/server/env.d.ts.map +1 -0
  74. package/dist/server/env.js +1 -0
  75. package/dist/server/gatewayFetch.d.ts +17 -13
  76. package/dist/server/gatewayFetch.d.ts.map +1 -1
  77. package/dist/server/gatewayFetch.js +24 -14
  78. package/dist/server/gatewayUrl.d.ts +13 -0
  79. package/dist/server/gatewayUrl.d.ts.map +1 -0
  80. package/dist/server/gatewayUrl.js +34 -0
  81. package/dist/server/index.d.ts +10 -3
  82. package/dist/server/index.d.ts.map +1 -1
  83. package/dist/server/index.js +8 -2
  84. package/dist/server/integrationFetch.d.ts +16 -32
  85. package/dist/server/integrationFetch.d.ts.map +1 -1
  86. package/dist/server/integrationFetch.js +47 -65
  87. package/dist/server/listMembers.js +1 -1
  88. package/dist/server/refusal.d.ts +55 -0
  89. package/dist/server/refusal.d.ts.map +1 -0
  90. package/dist/server/refusal.js +193 -0
  91. package/dist/server/sendEmail.js +1 -1
  92. package/dist/tanstack-start/index.d.ts +9 -0
  93. package/dist/tanstack-start/index.d.ts.map +1 -0
  94. package/dist/tanstack-start/index.js +29 -0
  95. package/dist/testing/index.d.ts +93 -0
  96. package/dist/testing/index.d.ts.map +1 -0
  97. package/dist/testing/index.js +156 -0
  98. package/package.json +34 -12
@@ -0,0 +1,156 @@
1
+ /**
2
+ * @every-app/sdk/testing — an app's tests, without a Gateway: a signed-in
3
+ * person for a request, and the tools called the way the Gateway calls them.
4
+ *
5
+ * import { callTool, testContext, testEnv, testRequest } from "@every-app/sdk/testing";
6
+ *
7
+ * const worker = everyApp(handler, { tools });
8
+ * const response = await worker.fetch(
9
+ * await testRequest("https://todo.test/api/todos", { user: { id: "ana" } }),
10
+ * testEnv(),
11
+ * testContext(),
12
+ * );
13
+ * const result = await callTool(worker, "list_todos", {}, { user: { id: "ana" } });
14
+ *
15
+ * Identities are signed with the well-known dev keypair, which `everyApp()`
16
+ * trusts only with `EVERYAPP_DEV` set, as {@link testEnv} sets it: never in a
17
+ * deployed Worker. For tests only; a Worker never imports this module.
18
+ */
19
+ import { DEV_ISSUER, DEV_PRIVATE_KEY_PEM, DEV_PUBLIC_KEY_PEM, } from "../dev/keypair.js";
20
+ import { APP_ID_ENV, AUDIENCE_ENV, IDENTITY_DEV_KEY_ID, IDENTITY_HEADER, MCP_DESTRUCTIVE_SCOPE, MCP_READ_SCOPE, MCP_WRITE_SCOPE, SYSTEM_HEADER, TOOLS_CALL_PATH, TOOLS_LIST_PATH, mintIdentityJwt, mintSystemJwt, } from "../internal/index.js";
21
+ import { everyApp } from "../server/everyApp.js";
22
+ export { IDENTITY_HEADER };
23
+ /** The person a test signs in by default: the owner of `org_test`. */
24
+ export const TEST_USER = Object.freeze({
25
+ id: "user_test",
26
+ email: "test@example.com",
27
+ orgId: "org_test",
28
+ orgRole: "owner",
29
+ });
30
+ /** The app id {@link testEnv} uses when none is given. */
31
+ export const TEST_APP_ID = "test-app";
32
+ /**
33
+ * The Worker env `everyApp()` needs to trust test identities: the app id,
34
+ * the dev issuer and key, `EVERYAPP_DEV`, and a `GATEWAY_URL`. `overrides`
35
+ * adds the app's own bindings (a fake `DB`, a secret) or replaces any of
36
+ * these.
37
+ */
38
+ export function testEnv(overrides = {}) {
39
+ const { appId = TEST_APP_ID, ...rest } = overrides;
40
+ return {
41
+ EVERYAPP_APP_ID: appId,
42
+ EVERYAPP_DEV: "1",
43
+ EVERYAPP_IDENTITY_ISSUER: DEV_ISSUER,
44
+ EVERYAPP_IDENTITY_PUBLIC_KEYS: JSON.stringify([DEV_PUBLIC_KEY_PEM]),
45
+ GATEWAY_URL: "https://gateway.test",
46
+ ...rest,
47
+ };
48
+ }
49
+ /**
50
+ * An `ExecutionContext` for calling a Worker's `fetch` in a test:
51
+ * `waitUntil` keeps each promise in `waited`, so a test can await them.
52
+ */
53
+ export function testContext() {
54
+ const waited = [];
55
+ return {
56
+ waited,
57
+ waitUntil: (promise) => void waited.push(promise),
58
+ passThroughOnException: () => { },
59
+ props: {},
60
+ };
61
+ }
62
+ /** An identity token for `user`, as the Gateway sends in the identity header. */
63
+ export async function mintTestIdentity(options = {}) {
64
+ const user = { ...TEST_USER, ...options.user };
65
+ return mintIdentityJwt(DEV_PRIVATE_KEY_PEM, {
66
+ subject: {
67
+ sub: user.id,
68
+ email: user.email,
69
+ orgId: user.orgId,
70
+ orgRole: user.orgRole,
71
+ },
72
+ audience: options.appId ?? TEST_APP_ID,
73
+ issuer: DEV_ISSUER,
74
+ keyId: IDENTITY_DEV_KEY_ID,
75
+ channel: options.channel,
76
+ scopes: options.scopes,
77
+ toolCall: options.toolCall,
78
+ });
79
+ }
80
+ /**
81
+ * A request as the Gateway forwards it: `user` signed in (the default
82
+ * person when left out), or nobody with `user: null`, as on a public route.
83
+ */
84
+ export async function testRequest(input, init = {}) {
85
+ const { user, appId, scopes, channel, ...requestInit } = init;
86
+ const headers = new Headers(requestInit.headers);
87
+ if (user !== null) {
88
+ headers.set(IDENTITY_HEADER, await mintTestIdentity({ user, appId, scopes, channel }));
89
+ }
90
+ return new Request(input, { ...requestInit, headers });
91
+ }
92
+ /**
93
+ * Call one tool as the Gateway does for an AI client: a `chan: "mcp"`
94
+ * identity minted for this call, through the app's tools endpoint, so the
95
+ * SDK checks the scope, validates input and output and maps errors as it
96
+ * does deployed. `app` is the Worker `everyApp()` returned, or the
97
+ * `defineTools()` set alone. The answer is `{ result }`, or `{ error }`
98
+ * when the SDK refused the call.
99
+ */
100
+ export async function callTool(app, name, args = {}, options = {}) {
101
+ const env = options.env ?? testEnv();
102
+ const callId = crypto.randomUUID();
103
+ const identity = await mintTestIdentity({
104
+ user: options.user,
105
+ appId: audienceOf(env),
106
+ channel: "mcp",
107
+ scopes: options.scopes ?? [
108
+ MCP_READ_SCOPE,
109
+ MCP_WRITE_SCOPE,
110
+ MCP_DESTRUCTIVE_SCOPE,
111
+ ],
112
+ toolCall: { id: callId, name },
113
+ });
114
+ const response = await workerOf(app).fetch(new Request(`https://app.test${TOOLS_CALL_PATH}`, {
115
+ method: "POST",
116
+ headers: { [IDENTITY_HEADER]: identity },
117
+ body: JSON.stringify({ v: 1, name, arguments: args, callId }),
118
+ }), env, options.ctx ?? testContext());
119
+ return (await response.json());
120
+ }
121
+ /** The tool catalog, read as the Gateway reads it when the app deploys. */
122
+ export async function listTools(app, options = {}) {
123
+ const env = options.env ?? testEnv();
124
+ const token = await mintSystemJwt(DEV_PRIVATE_KEY_PEM, {
125
+ audience: audienceOf(env),
126
+ issuer: DEV_ISSUER,
127
+ purpose: "tools.list",
128
+ keyId: IDENTITY_DEV_KEY_ID,
129
+ });
130
+ const response = await workerOf(app).fetch(new Request(`https://app.test${TOOLS_LIST_PATH}`, {
131
+ method: "POST",
132
+ headers: { [SYSTEM_HEADER]: token },
133
+ body: JSON.stringify({ v: 1 }),
134
+ }), env, options.ctx ?? testContext());
135
+ if (!response.ok) {
136
+ throw new Error(`the tools list answered ${response.status}: ${await response.text()}`);
137
+ }
138
+ return (await response.json());
139
+ }
140
+ /** Who the app's identities are minted for: the deployed audience, else the app id. */
141
+ function audienceOf(env) {
142
+ const values = env;
143
+ for (const key of [AUDIENCE_ENV, APP_ID_ENV]) {
144
+ const value = values[key];
145
+ if (typeof value === "string" && value)
146
+ return value;
147
+ }
148
+ return TEST_APP_ID;
149
+ }
150
+ function workerOf(app) {
151
+ if ("fetch" in app)
152
+ return app;
153
+ return everyApp(() => new Response("Not found", { status: 404 }), {
154
+ tools: app,
155
+ });
156
+ }
package/package.json CHANGED
@@ -1,9 +1,13 @@
1
1
  {
2
2
  "name": "@every-app/sdk",
3
- "version": "0.3.0-rc.4",
3
+ "version": "0.3.0-rc.6",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "exports": {
7
+ ".": {
8
+ "types": "./dist/index.d.ts",
9
+ "default": "./dist/index.js"
10
+ },
7
11
  "./server": {
8
12
  "types": "./dist/server/index.d.ts",
9
13
  "default": "./dist/server/index.js"
@@ -24,27 +28,29 @@
24
28
  "types": "./dist/dev/index.d.ts",
25
29
  "default": "./dist/dev/index.js"
26
30
  },
31
+ "./tanstack-start": {
32
+ "types": "./dist/tanstack-start/index.d.ts",
33
+ "default": "./dist/tanstack-start/index.js"
34
+ },
35
+ "./testing": {
36
+ "types": "./dist/testing/index.d.ts",
37
+ "default": "./dist/testing/index.js"
38
+ },
27
39
  "./package.json": "./package.json"
28
40
  },
29
41
  "files": [
30
42
  "dist",
31
43
  "README.md"
32
44
  ],
33
- "scripts": {
34
- "prebuild": "node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\"",
35
- "build": "tsc -p tsconfig.build.json",
36
- "types:check": "tsc --noEmit",
37
- "format:check": "prettier --check .",
38
- "format:write": "prettier . --write",
39
- "test": "vitest run --silent",
40
- "test:watch": "vitest",
41
- "check:esm-relative-imports": "node ./scripts/check-esm-relative-imports.mjs"
42
- },
43
45
  "dependencies": {
44
46
  "jose": "^6.2.5"
45
47
  },
48
+ "peerDependencies": {
49
+ "@tanstack/react-start": "^1.168.61"
50
+ },
46
51
  "devDependencies": {
47
52
  "@cloudflare/workers-types": "^4.20251014.0",
53
+ "@tanstack/react-start": "1.168.61",
48
54
  "@types/node": "^22.18.13",
49
55
  "prettier": "^3.6.2",
50
56
  "typescript": "^5.9.3",
@@ -52,5 +58,21 @@
52
58
  "vite-tsconfig-paths": "^5.1.4",
53
59
  "vitest": "^3.2.6",
54
60
  "zod": "^4.2.0"
61
+ },
62
+ "peerDependenciesMeta": {
63
+ "@tanstack/react-start": {
64
+ "optional": true
65
+ }
66
+ },
67
+ "scripts": {
68
+ "prebuild": "node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\"",
69
+ "build": "tsc -p tsconfig.build.json",
70
+ "types:check": "tsc --noEmit",
71
+ "format:check": "prettier --check .",
72
+ "format:write": "prettier . --write",
73
+ "test": "vitest run --silent",
74
+ "test:watch": "vitest",
75
+ "check:esm-relative-imports": "node ./scripts/check-esm-relative-imports.mjs",
76
+ "catalog:update": "UPDATE_CATALOG=1 vitest run src/cloudflare/catalogSettings.test.ts --silent"
55
77
  }
56
- }
78
+ }