@every-app/sdk 0.1.14 → 0.3.0-rc.1

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 (167) hide show
  1. package/README.md +608 -2
  2. package/dist/cloudflare/index.d.ts +21 -1
  3. package/dist/cloudflare/index.d.ts.map +1 -1
  4. package/dist/cloudflare/index.js +21 -1
  5. package/dist/cloudflare/sentinel.d.ts +69 -0
  6. package/dist/cloudflare/sentinel.d.ts.map +1 -0
  7. package/dist/cloudflare/sentinel.js +50 -0
  8. package/dist/cloudflare/worker.d.ts +511 -0
  9. package/dist/cloudflare/worker.d.ts.map +1 -0
  10. package/dist/cloudflare/worker.js +738 -0
  11. package/dist/dev/index.d.ts +8 -0
  12. package/dist/dev/index.d.ts.map +1 -0
  13. package/dist/dev/index.js +7 -0
  14. package/dist/dev/keypair.d.ts +24 -0
  15. package/dist/dev/keypair.d.ts.map +1 -0
  16. package/dist/dev/keypair.js +60 -0
  17. package/dist/internal/aiProviders.d.ts +67 -0
  18. package/dist/internal/aiProviders.d.ts.map +1 -0
  19. package/dist/internal/aiProviders.js +220 -0
  20. package/dist/internal/appSettings.d.ts +237 -0
  21. package/dist/internal/appSettings.d.ts.map +1 -0
  22. package/dist/internal/appSettings.js +374 -0
  23. package/dist/internal/capabilities.d.ts +1344 -0
  24. package/dist/internal/capabilities.d.ts.map +1 -0
  25. package/dist/internal/capabilities.js +1521 -0
  26. package/dist/internal/devProviders.d.ts +49 -0
  27. package/dist/internal/devProviders.d.ts.map +1 -0
  28. package/dist/internal/devProviders.js +62 -0
  29. package/dist/internal/email.d.ts +280 -0
  30. package/dist/internal/email.d.ts.map +1 -0
  31. package/dist/internal/email.js +613 -0
  32. package/dist/internal/events.d.ts +182 -0
  33. package/dist/internal/events.d.ts.map +1 -0
  34. package/dist/internal/events.js +324 -0
  35. package/dist/internal/gatewaySettings.d.ts +82 -0
  36. package/dist/internal/gatewaySettings.d.ts.map +1 -0
  37. package/dist/internal/gatewaySettings.js +209 -0
  38. package/dist/internal/identity.d.ts +88 -0
  39. package/dist/internal/identity.d.ts.map +1 -0
  40. package/dist/internal/identity.js +231 -0
  41. package/dist/internal/index.d.ts +19 -0
  42. package/dist/internal/index.d.ts.map +1 -0
  43. package/dist/internal/index.js +18 -0
  44. package/dist/internal/members.d.ts +35 -0
  45. package/dist/internal/members.d.ts.map +1 -0
  46. package/dist/internal/members.js +7 -0
  47. package/dist/internal/oauthClient.d.ts +63 -0
  48. package/dist/internal/oauthClient.d.ts.map +1 -0
  49. package/dist/internal/oauthClient.js +194 -0
  50. package/dist/internal/oauthScopes.d.ts +117 -0
  51. package/dist/internal/oauthScopes.d.ts.map +1 -0
  52. package/dist/internal/oauthScopes.js +416 -0
  53. package/dist/internal/organizationName.d.ts +18 -0
  54. package/dist/internal/organizationName.d.ts.map +1 -0
  55. package/dist/internal/organizationName.js +24 -0
  56. package/dist/internal/protocol.d.ts +195 -0
  57. package/dist/internal/protocol.d.ts.map +1 -0
  58. package/dist/internal/protocol.js +250 -0
  59. package/dist/internal/providerApps.d.ts +75 -0
  60. package/dist/internal/providerApps.d.ts.map +1 -0
  61. package/dist/internal/providerApps.js +59 -0
  62. package/dist/internal/providerRegistry.d.ts +147 -0
  63. package/dist/internal/providerRegistry.d.ts.map +1 -0
  64. package/dist/internal/providerRegistry.js +262 -0
  65. package/dist/internal/providerSpec.d.ts +55 -0
  66. package/dist/internal/providerSpec.d.ts.map +1 -0
  67. package/dist/internal/providerSpec.js +746 -0
  68. package/dist/internal/remoteMcp.d.ts +188 -0
  69. package/dist/internal/remoteMcp.d.ts.map +1 -0
  70. package/dist/internal/remoteMcp.js +543 -0
  71. package/dist/internal/tools.d.ts +115 -0
  72. package/dist/internal/tools.d.ts.map +1 -0
  73. package/dist/internal/tools.js +80 -0
  74. package/dist/server/attribution.d.ts +39 -0
  75. package/dist/server/attribution.d.ts.map +1 -0
  76. package/dist/server/attribution.js +67 -0
  77. package/dist/server/authorizeUrl.d.ts +43 -0
  78. package/dist/server/authorizeUrl.d.ts.map +1 -0
  79. package/dist/server/authorizeUrl.js +110 -0
  80. package/dist/server/emit.d.ts +63 -0
  81. package/dist/server/emit.d.ts.map +1 -0
  82. package/dist/server/emit.js +101 -0
  83. package/dist/server/everyApp.d.ts +81 -0
  84. package/dist/server/everyApp.d.ts.map +1 -0
  85. package/dist/server/everyApp.js +185 -0
  86. package/dist/server/gatewayFetch.d.ts +37 -0
  87. package/dist/server/gatewayFetch.d.ts.map +1 -0
  88. package/dist/server/gatewayFetch.js +115 -0
  89. package/dist/server/index.d.ts +18 -0
  90. package/dist/server/index.d.ts.map +1 -0
  91. package/dist/server/index.js +15 -0
  92. package/dist/server/integrationFetch.d.ts +131 -0
  93. package/dist/server/integrationFetch.d.ts.map +1 -0
  94. package/dist/server/integrationFetch.js +526 -0
  95. package/dist/server/listMembers.d.ts +32 -0
  96. package/dist/server/listMembers.d.ts.map +1 -0
  97. package/dist/server/listMembers.js +74 -0
  98. package/dist/server/nodeServer.d.ts +48 -0
  99. package/dist/server/nodeServer.d.ts.map +1 -0
  100. package/dist/server/nodeServer.js +45 -0
  101. package/dist/server/sendEmail.d.ts +39 -0
  102. package/dist/server/sendEmail.d.ts.map +1 -0
  103. package/dist/server/sendEmail.js +114 -0
  104. package/dist/server/tools.d.ts +184 -0
  105. package/dist/server/tools.d.ts.map +1 -0
  106. package/dist/server/tools.js +347 -0
  107. package/dist/server/toolsEndpoint.d.ts +32 -0
  108. package/dist/server/toolsEndpoint.d.ts.map +1 -0
  109. package/dist/server/toolsEndpoint.js +231 -0
  110. package/package.json +21 -31
  111. package/dist/cloudflare/getLocalD1Url.d.ts +0 -2
  112. package/dist/cloudflare/getLocalD1Url.d.ts.map +0 -1
  113. package/dist/cloudflare/getLocalD1Url.js +0 -40
  114. package/dist/cloudflare/lazyInit.d.ts +0 -22
  115. package/dist/cloudflare/lazyInit.d.ts.map +0 -1
  116. package/dist/cloudflare/lazyInit.js +0 -65
  117. package/dist/cloudflare/server/gateway.d.ts +0 -29
  118. package/dist/cloudflare/server/gateway.d.ts.map +0 -1
  119. package/dist/cloudflare/server/gateway.js +0 -69
  120. package/dist/cloudflare/server/index.d.ts +0 -3
  121. package/dist/cloudflare/server/index.d.ts.map +0 -1
  122. package/dist/cloudflare/server/index.js +0 -2
  123. package/dist/core/authenticatedFetch.d.ts +0 -9
  124. package/dist/core/authenticatedFetch.d.ts.map +0 -1
  125. package/dist/core/authenticatedFetch.js +0 -31
  126. package/dist/core/index.d.ts +0 -4
  127. package/dist/core/index.d.ts.map +0 -1
  128. package/dist/core/index.js +0 -2
  129. package/dist/core/sessionManager.d.ts +0 -58
  130. package/dist/core/sessionManager.d.ts.map +0 -1
  131. package/dist/core/sessionManager.js +0 -357
  132. package/dist/shared/bypassGatewayLocalOnly.d.ts +0 -15
  133. package/dist/shared/bypassGatewayLocalOnly.d.ts.map +0 -1
  134. package/dist/shared/bypassGatewayLocalOnly.js +0 -45
  135. package/dist/shared/parseMessagePayload.d.ts +0 -3
  136. package/dist/shared/parseMessagePayload.d.ts.map +0 -1
  137. package/dist/shared/parseMessagePayload.js +0 -18
  138. package/dist/tanstack/EmbeddedAppProvider.d.ts +0 -30
  139. package/dist/tanstack/EmbeddedAppProvider.d.ts.map +0 -1
  140. package/dist/tanstack/EmbeddedAppProvider.js +0 -57
  141. package/dist/tanstack/GatewayRequiredError.d.ts +0 -20
  142. package/dist/tanstack/GatewayRequiredError.d.ts.map +0 -1
  143. package/dist/tanstack/GatewayRequiredError.js +0 -91
  144. package/dist/tanstack/_internal/useEveryAppSession.d.ts +0 -18
  145. package/dist/tanstack/_internal/useEveryAppSession.d.ts.map +0 -1
  146. package/dist/tanstack/_internal/useEveryAppSession.js +0 -47
  147. package/dist/tanstack/index.d.ts +0 -4
  148. package/dist/tanstack/index.d.ts.map +0 -1
  149. package/dist/tanstack/index.js +0 -3
  150. package/dist/tanstack/server/authConfig.d.ts +0 -3
  151. package/dist/tanstack/server/authConfig.d.ts.map +0 -1
  152. package/dist/tanstack/server/authConfig.js +0 -13
  153. package/dist/tanstack/server/authenticateRequest.d.ts +0 -31
  154. package/dist/tanstack/server/authenticateRequest.d.ts.map +0 -1
  155. package/dist/tanstack/server/authenticateRequest.js +0 -154
  156. package/dist/tanstack/server/index.d.ts +0 -4
  157. package/dist/tanstack/server/index.d.ts.map +0 -1
  158. package/dist/tanstack/server/index.js +0 -2
  159. package/dist/tanstack/server/types.d.ts +0 -5
  160. package/dist/tanstack/server/types.d.ts.map +0 -1
  161. package/dist/tanstack/server/types.js +0 -1
  162. package/dist/tanstack/useEveryAppRouter.d.ts +0 -7
  163. package/dist/tanstack/useEveryAppRouter.d.ts.map +0 -1
  164. package/dist/tanstack/useEveryAppRouter.js +0 -66
  165. package/dist/tanstack/useSessionTokenClientMiddleware.d.ts +0 -2
  166. package/dist/tanstack/useSessionTokenClientMiddleware.d.ts.map +0 -1
  167. package/dist/tanstack/useSessionTokenClientMiddleware.js +0 -29
@@ -0,0 +1,250 @@
1
+ /**
2
+ * @every-app/sdk/internal — Every App platform protocol internals.
3
+ *
4
+ * This subpath is for the Every App platform itself (gateway, perimeter, CLI),
5
+ * not for app authors. It owns the wire constants, claim shapes, claim codecs,
6
+ * and gateway-side JWT minters shared by the platform packages.
7
+ */
8
+ import { SignJWT, importPKCS8 } from "jose";
9
+ export const IDENTITY_ALG = "RS256";
10
+ export const IDENTITY_KEY_ID = "everyapp-identity";
11
+ export const IDENTITY_DEV_KEY_ID = "everyapp-identity-dev";
12
+ /**
13
+ * The only issuer a dev-kid token may name. The same value as
14
+ * `@every-app/sdk/dev`'s, kept apart so the Worker never loads the module
15
+ * `cloudflare.config.ts` does (a test pins the two together).
16
+ */
17
+ export const DEV_ISSUER = "https://gateway.dev.localhost";
18
+ export const IDENTITY_HEADER = "x-everyapp-identity";
19
+ export const PUBLIC_HEADER = "x-everyapp-public";
20
+ /**
21
+ * Carries the gateway's system token on its own calls to an app (the tools
22
+ * catalog fetch). Never an identity: no user, and it only opens the endpoint
23
+ * named by its `purpose` claim.
24
+ */
25
+ export const SYSTEM_HEADER = "x-everyapp-system";
26
+ /**
27
+ * On a refusal the AppGateway binding makes itself (the app's manifest lacks
28
+ * the capability, the gateway holds no key), as opposed to the provider's
29
+ * own answer passed through: the refusal's code, also in the JSON body.
30
+ */
31
+ export const GATEWAY_ERROR_HEADER = "x-everyapp-error";
32
+ /**
33
+ * On a shared app's call to the AppGateway binding for work no request
34
+ * started (a cron, a Workflow step): the organization the work is for. The
35
+ * gateway believes it only from a shared app's Worker, and only for an
36
+ * active organization with a live member; an organization's own app may
37
+ * only name its own. The perimeter strips it, with every `x-everyapp-*`,
38
+ * from what browsers send.
39
+ */
40
+ export const ORG_HEADER = "x-everyapp-org";
41
+ /** 120-second lifetime — caps revocation staleness while surviving clock skew. */
42
+ export const IDENTITY_TTL_SECONDS = 120;
43
+ /** System tokens are minted per call and live at most a minute. */
44
+ export const SYSTEM_TOKEN_TTL_SECONDS = 60;
45
+ /** Env var carrying the app's manifest id. */
46
+ export const APP_ID_ENV = "EVERYAPP_APP_ID";
47
+ /**
48
+ * Env var carrying the expected identity audience: the app's Worker name,
49
+ * which the gateway stamps as `aud` on every token it mints for the app. Two
50
+ * Workers of one app id (two organizations' copies) never accept each
51
+ * other's tokens.
52
+ */
53
+ export const AUDIENCE_ENV = "EVERYAPP_AUDIENCE";
54
+ /** Default env var carrying a JSON array of SPKI PEM public keys. */
55
+ export const PUBLIC_KEYS_ENV = "EVERYAPP_IDENTITY_PUBLIC_KEYS";
56
+ /** Env var carrying the expected gateway issuer for user identity verification. */
57
+ export const ISSUER_ENV = "EVERYAPP_IDENTITY_ISSUER";
58
+ /**
59
+ * Env var set to `1` on a shared app's Workers (one Worker for every
60
+ * organization): a gateway call from them must say whom it is for.
61
+ */
62
+ export const SHARED_ENV = "EVERYAPP_SHARED";
63
+ /** When set to `1` or `true` in the worker env, the dev identity kid is accepted. */
64
+ export const DEV_ENV = "EVERYAPP_DEV";
65
+ /** `sub` claim the gateway mints public-route markers with. */
66
+ export const PUBLIC_MARKER_SUB = "public";
67
+ /** `sub` claim of gateway system tokens. */
68
+ export const SYSTEM_TOKEN_SUB = "system";
69
+ export class ProtocolClaimsError extends Error {
70
+ constructor(message) {
71
+ super(message);
72
+ this.name = "ProtocolClaimsError";
73
+ }
74
+ }
75
+ export function identitySubjectToClaims(subject, opts) {
76
+ return {
77
+ typ: "user",
78
+ email: subject.email,
79
+ org_id: subject.orgId,
80
+ org_role: subject.orgRole,
81
+ chan: opts.channel ?? "web",
82
+ act: opts.actor ?? { sub: subject.sub },
83
+ scopes: opts.scopes ?? ["*"],
84
+ jti: opts.jti,
85
+ ...(opts.toolCall
86
+ ? { tc: { id: opts.toolCall.id, name: opts.toolCall.name } }
87
+ : {}),
88
+ };
89
+ }
90
+ function parseToolCallClaim(value) {
91
+ if (value === undefined)
92
+ return undefined;
93
+ const claim = value;
94
+ if (!claim ||
95
+ typeof claim !== "object" ||
96
+ typeof claim.id !== "string" ||
97
+ typeof claim.name !== "string" ||
98
+ !claim.id ||
99
+ !claim.name) {
100
+ throw new ProtocolClaimsError("identity token has a malformed tc claim");
101
+ }
102
+ return { id: claim.id, name: claim.name };
103
+ }
104
+ export function identityClaimsToEveryAppUser(payload) {
105
+ if (payload.typ !== "user") {
106
+ throw new ProtocolClaimsError("identity token has wrong typ");
107
+ }
108
+ const sub = payload.sub;
109
+ const email = payload.email;
110
+ const orgId = payload.org_id;
111
+ const orgRole = payload.org_role;
112
+ if (!sub || !email || !orgId || !orgRole) {
113
+ throw new ProtocolClaimsError("identity token missing required claims");
114
+ }
115
+ const chan = payload.chan ?? "web";
116
+ const act = payload.act ?? { sub };
117
+ const scopes = Array.isArray(payload.scopes)
118
+ ? payload.scopes.filter((scope) => typeof scope === "string")
119
+ : ["*"];
120
+ const toolCall = parseToolCallClaim(payload.tc);
121
+ return {
122
+ id: sub,
123
+ email,
124
+ orgId,
125
+ orgRole,
126
+ channel: chan,
127
+ actor: { sub: act.sub ?? sub },
128
+ scopes,
129
+ jti: payload.jti ?? "",
130
+ ...(toolCall ? { toolCall } : {}),
131
+ };
132
+ }
133
+ export function publicMarkerClaims(jti) {
134
+ return { typ: "public", pub: true, jti };
135
+ }
136
+ export function assertPublicMarkerClaims(payload) {
137
+ if (payload.typ !== "public") {
138
+ throw new ProtocolClaimsError("public marker has wrong typ");
139
+ }
140
+ if (payload.pub !== true || payload.sub !== PUBLIC_MARKER_SUB) {
141
+ throw new ProtocolClaimsError("token is not a public-route marker");
142
+ }
143
+ }
144
+ /**
145
+ * A system token opens exactly one endpoint and lives at most
146
+ * {@link SYSTEM_TOKEN_TTL_SECONDS}: a leaked one is short-lived and useless
147
+ * anywhere else.
148
+ */
149
+ export function assertSystemClaims(payload, purpose) {
150
+ if (payload.typ !== "system" || payload.sub !== SYSTEM_TOKEN_SUB) {
151
+ throw new ProtocolClaimsError("token is not a system token");
152
+ }
153
+ if (payload.purpose !== purpose) {
154
+ throw new ProtocolClaimsError(`system token purpose "${String(payload.purpose)}" is not "${purpose}"`);
155
+ }
156
+ if (typeof payload.iat !== "number" ||
157
+ typeof payload.exp !== "number" ||
158
+ payload.exp - payload.iat > SYSTEM_TOKEN_TTL_SECONDS) {
159
+ throw new ProtocolClaimsError(`system token must expire within ${SYSTEM_TOKEN_TTL_SECONDS}s of issue`);
160
+ }
161
+ return payload;
162
+ }
163
+ let cachedPrivateKey = null;
164
+ async function loadPrivateKey(privateKeyPem) {
165
+ const pem = privateKeyPem.replace(/\\n/g, "\n");
166
+ if (cachedPrivateKey && cachedPrivateKey.pem === pem) {
167
+ return cachedPrivateKey.key;
168
+ }
169
+ const key = await importPKCS8(pem, IDENTITY_ALG);
170
+ cachedPrivateKey = { pem, key };
171
+ return key;
172
+ }
173
+ /**
174
+ * Mint an identity JWT. Returns the compact JWS string to inject as
175
+ * `x-everyapp-identity`.
176
+ */
177
+ export async function mintIdentityJwt(privateKeyPem, opts) {
178
+ const key = await loadPrivateKey(privateKeyPem);
179
+ const nowSec = Math.floor((opts.now ?? Date.now()) / 1000);
180
+ const ttl = opts.ttlSeconds ?? IDENTITY_TTL_SECONDS;
181
+ const jti = crypto.randomUUID();
182
+ return new SignJWT(identitySubjectToClaims(opts.subject, {
183
+ channel: opts.channel,
184
+ actor: opts.actor,
185
+ scopes: opts.scopes,
186
+ toolCall: opts.toolCall,
187
+ jti,
188
+ }))
189
+ .setProtectedHeader({
190
+ alg: IDENTITY_ALG,
191
+ kid: opts.keyId ?? IDENTITY_KEY_ID,
192
+ })
193
+ .setIssuer(opts.issuer)
194
+ .setSubject(opts.subject.sub)
195
+ .setAudience(opts.audience)
196
+ .setIssuedAt(nowSec)
197
+ .setExpirationTime(nowSec + ttl)
198
+ .sign(key);
199
+ }
200
+ /**
201
+ * Mint the public-route marker for `x-everyapp-public`. A bare header value
202
+ * is never a trust source, so the marker is a signed, short-lived, app-scoped
203
+ * JWT with `pub: true` and `typ: "public"` that the SDK verifies exactly like
204
+ * an identity token.
205
+ */
206
+ export async function mintPublicMarkerJwt(privateKeyPem, opts) {
207
+ const key = await loadPrivateKey(privateKeyPem);
208
+ const nowSec = Math.floor((opts.now ?? Date.now()) / 1000);
209
+ const ttl = opts.ttlSeconds ?? IDENTITY_TTL_SECONDS;
210
+ return new SignJWT(publicMarkerClaims(crypto.randomUUID()))
211
+ .setProtectedHeader({
212
+ alg: IDENTITY_ALG,
213
+ kid: opts.keyId ?? IDENTITY_KEY_ID,
214
+ })
215
+ .setIssuer(opts.issuer)
216
+ .setSubject(PUBLIC_MARKER_SUB)
217
+ .setAudience(opts.audience)
218
+ .setIssuedAt(nowSec)
219
+ .setExpirationTime(nowSec + ttl)
220
+ .sign(key);
221
+ }
222
+ /**
223
+ * Mint the gateway's system token for `x-everyapp-system`: no user, one
224
+ * purpose, one app, one minute. The SDK only accepts it on the endpoint its
225
+ * purpose names, and never as an identity.
226
+ */
227
+ export async function mintSystemJwt(privateKeyPem, opts) {
228
+ const ttl = opts.ttlSeconds ?? SYSTEM_TOKEN_TTL_SECONDS;
229
+ if (ttl <= 0 || ttl > SYSTEM_TOKEN_TTL_SECONDS) {
230
+ throw new RangeError(`system tokens live at most ${SYSTEM_TOKEN_TTL_SECONDS}s (got ${ttl})`);
231
+ }
232
+ const key = await loadPrivateKey(privateKeyPem);
233
+ const nowSec = Math.floor((opts.now ?? Date.now()) / 1000);
234
+ const claims = {
235
+ typ: "system",
236
+ purpose: opts.purpose,
237
+ jti: crypto.randomUUID(),
238
+ };
239
+ return new SignJWT(claims)
240
+ .setProtectedHeader({
241
+ alg: IDENTITY_ALG,
242
+ kid: opts.keyId ?? IDENTITY_KEY_ID,
243
+ })
244
+ .setIssuer(opts.issuer)
245
+ .setSubject(SYSTEM_TOKEN_SUB)
246
+ .setAudience(opts.audience)
247
+ .setIssuedAt(nowSec)
248
+ .setExpirationTime(nowSec + ttl)
249
+ .sign(key);
250
+ }
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Provider apps, "MCP apps" to the person: a data provider (DataForSEO
3
+ * today) offered to members as an app of the Gateway's own, with no page
4
+ * and no Worker to deploy. The operator turns it on (`everyapp mcp on
5
+ * <id>`) and sets the provider's key as a Gateway setting; the Gateway then
6
+ * serves the provider's tools on its `/mcp` under `<id>_<tool>` names, with
7
+ * the key never leaving the Gateway, every call attributed to the member
8
+ * who made it, counted and audited like an app's capability calls. The
9
+ * launcher lists it under "MCP apps" and its card opens the "Use it from
10
+ * your agent" dialog instead of a page (docs/design/2026-10-mcp-apps-ui.md).
11
+ *
12
+ * A provider app is an `apps` row of tier {@link PROVIDER_APP_TIER} with no
13
+ * hostname and no Worker name: the perimeter never routes it, and the
14
+ * Gateway reaches its tools in-process rather than over a service binding.
15
+ * Its manifest is generated here, so the settings model
16
+ * (./appSettings.ts) reads the provider's key as a required Gateway setting
17
+ * like any app's capability. The registry rules that write the row are in
18
+ * `@every-app/perimeter/registry` (providerApps.ts); the Gateway serves it
19
+ * from `apps/every-app-gateway/src/server/provider-apps/`.
20
+ */
21
+ import { type ApiKeyCapabilityId } from "./capabilities.js";
22
+ /** The `apps.tier` of a provider app: no Worker, served by the Gateway itself. */
23
+ export declare const PROVIDER_APP_TIER = "provider";
24
+ export interface ProviderAppDefinition {
25
+ /** The app id (its slug and tool-name prefix): lowercase, no underscore. */
26
+ id: string;
27
+ /** What Admin → Apps and the launcher call it. */
28
+ name: string;
29
+ /** What it is for, as the app library and `everyapp_list_apps` tell it. */
30
+ description: string;
31
+ /**
32
+ * The `api_key` capability whose Gateway setting holds the key and whose
33
+ * proxy rules (hosts, methods, account-wide paths) every tool call obeys.
34
+ */
35
+ capability: ApiKeyCapabilityId;
36
+ /** Why the app lists the capability: the manifest entry's `why`. */
37
+ why: string;
38
+ /**
39
+ * What to say to an agent to try it, after "Use <name> to": the "Use it
40
+ * from your agent" dialog's example sentence.
41
+ */
42
+ example: string;
43
+ }
44
+ export declare const PROVIDER_APPS: {
45
+ readonly dataforseo: {
46
+ readonly id: "dataforseo";
47
+ readonly name: "DataForSEO";
48
+ readonly description: "SEO data for your agent: keyword metrics and suggestions, live Google results, domain rankings, competitors and backlinks, through the Gateway's DataForSEO key.";
49
+ readonly capability: "dataforseo";
50
+ readonly why: "Serves DataForSEO's keyword, search-result, domain and backlink data to members' AI clients.";
51
+ readonly example: "find keyword ideas for a page about running shoes";
52
+ };
53
+ };
54
+ export type ProviderAppId = keyof typeof PROVIDER_APPS;
55
+ /** The provider app ids, in a stable order. */
56
+ export declare const PROVIDER_APP_IDS: ProviderAppId[];
57
+ export declare function isProviderAppId(id: string): id is ProviderAppId;
58
+ /** The Gateway setting that holds a provider app's key (`DATAFORSEO_API_KEY`). */
59
+ export declare function providerAppKeySetting(id: ProviderAppId): string;
60
+ /**
61
+ * The manifest a provider app's registry row stores: what a deployed app
62
+ * would declare to use the same capability, so Admin → Apps, the settings
63
+ * model and the integration proxy read it like any app's. Read-only
64
+ * access: every provider app only reads data.
65
+ */
66
+ export declare function providerAppManifest(id: ProviderAppId): {
67
+ id: string;
68
+ name: string;
69
+ description: string;
70
+ capabilities: Record<string, {
71
+ access: "read";
72
+ why: string;
73
+ }>;
74
+ };
75
+ //# sourceMappingURL=providerApps.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"providerApps.d.ts","sourceRoot":"","sources":["../../src/internal/providerApps.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,EAGL,KAAK,kBAAkB,EACxB,MAAM,mBAAmB,CAAC;AAE3B,kFAAkF;AAClF,eAAO,MAAM,iBAAiB,aAAa,CAAC;AAE5C,MAAM,WAAW,qBAAqB;IACpC,4EAA4E;IAC5E,EAAE,EAAE,MAAM,CAAC;IACX,kDAAkD;IAClD,IAAI,EAAE,MAAM,CAAC;IACb,2EAA2E;IAC3E,WAAW,EAAE,MAAM,CAAC;IACpB;;;OAGG;IACH,UAAU,EAAE,kBAAkB,CAAC;IAC/B,oEAAoE;IACpE,GAAG,EAAE,MAAM,CAAC;IACZ;;;OAGG;IACH,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,eAAO,MAAM,aAAa;;;;;;;;;CAUgC,CAAC;AAE3D,MAAM,MAAM,aAAa,GAAG,MAAM,OAAO,aAAa,CAAC;AAEvD,+CAA+C;AAC/C,eAAO,MAAM,gBAAgB,EAEjB,aAAa,EAAE,CAAC;AAE5B,wBAAgB,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,EAAE,IAAI,aAAa,CAE/D;AAED,kFAAkF;AAClF,wBAAgB,qBAAqB,CAAC,EAAE,EAAE,aAAa,GAAG,MAAM,CAE/D;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,EAAE,EAAE,aAAa,GAAG;IACtD,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC/D,CAUA"}
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Provider apps, "MCP apps" to the person: a data provider (DataForSEO
3
+ * today) offered to members as an app of the Gateway's own, with no page
4
+ * and no Worker to deploy. The operator turns it on (`everyapp mcp on
5
+ * <id>`) and sets the provider's key as a Gateway setting; the Gateway then
6
+ * serves the provider's tools on its `/mcp` under `<id>_<tool>` names, with
7
+ * the key never leaving the Gateway, every call attributed to the member
8
+ * who made it, counted and audited like an app's capability calls. The
9
+ * launcher lists it under "MCP apps" and its card opens the "Use it from
10
+ * your agent" dialog instead of a page (docs/design/2026-10-mcp-apps-ui.md).
11
+ *
12
+ * A provider app is an `apps` row of tier {@link PROVIDER_APP_TIER} with no
13
+ * hostname and no Worker name: the perimeter never routes it, and the
14
+ * Gateway reaches its tools in-process rather than over a service binding.
15
+ * Its manifest is generated here, so the settings model
16
+ * (./appSettings.ts) reads the provider's key as a required Gateway setting
17
+ * like any app's capability. The registry rules that write the row are in
18
+ * `@every-app/perimeter/registry` (providerApps.ts); the Gateway serves it
19
+ * from `apps/every-app-gateway/src/server/provider-apps/`.
20
+ */
21
+ import { CAPABILITIES, authSettingNames, } from "./capabilities.js";
22
+ /** The `apps.tier` of a provider app: no Worker, served by the Gateway itself. */
23
+ export const PROVIDER_APP_TIER = "provider";
24
+ export const PROVIDER_APPS = {
25
+ dataforseo: {
26
+ id: "dataforseo",
27
+ name: "DataForSEO",
28
+ description: "SEO data for your agent: keyword metrics and suggestions, live Google results, domain rankings, competitors and backlinks, through the Gateway's DataForSEO key.",
29
+ capability: "dataforseo",
30
+ why: "Serves DataForSEO's keyword, search-result, domain and backlink data to members' AI clients.",
31
+ example: "find keyword ideas for a page about running shoes",
32
+ },
33
+ };
34
+ /** The provider app ids, in a stable order. */
35
+ export const PROVIDER_APP_IDS = Object.keys(PROVIDER_APPS).sort();
36
+ export function isProviderAppId(id) {
37
+ return Object.hasOwn(PROVIDER_APPS, id);
38
+ }
39
+ /** The Gateway setting that holds a provider app's key (`DATAFORSEO_API_KEY`). */
40
+ export function providerAppKeySetting(id) {
41
+ return authSettingNames(CAPABILITIES[PROVIDER_APPS[id].capability].auth)[0];
42
+ }
43
+ /**
44
+ * The manifest a provider app's registry row stores: what a deployed app
45
+ * would declare to use the same capability, so Admin → Apps, the settings
46
+ * model and the integration proxy read it like any app's. Read-only
47
+ * access: every provider app only reads data.
48
+ */
49
+ export function providerAppManifest(id) {
50
+ const provider = PROVIDER_APPS[id];
51
+ return {
52
+ id: provider.id,
53
+ name: provider.name,
54
+ description: provider.description,
55
+ capabilities: {
56
+ [provider.capability]: { access: "read", why: provider.why },
57
+ },
58
+ };
59
+ }
@@ -0,0 +1,147 @@
1
+ /**
2
+ * The provider registry: the built-in catalog (./capabilities.ts) and the
3
+ * providers one gateway registered as rows (`everyapp provider add`,
4
+ * `everyapp_provider_add`), resolved as one lookup
5
+ * (docs/design/2026-10-provider-registry.md). The catalog comes first and
6
+ * a row can never shadow it. Every row is parsed and checked again each
7
+ * time a registry is built, so a row written by hand into D1, or one that
8
+ * stopped passing the rules when a later catalog took its name, is left
9
+ * out and named in `rejected` rather than served.
10
+ *
11
+ * The rules a row must pass (the register's `registry.*` invariants):
12
+ *
13
+ * - `registry.builtin-precedence`: not a catalog id, and never `everyapp`;
14
+ * - `registry.row-secret-is-its-own`: each Gateway setting it names starts
15
+ * with its own id (`STRIPE_` for `stripe`) and is nobody else's: no
16
+ * install-owned, dev-only or reserved name, no settable Gateway setting
17
+ * (the catalog's keys and clients included), no other row's;
18
+ * - `registry.row-hosts-public-https`: each host is a public DNS name (not
19
+ * an IP literal, localhost, or a `.local`, `.internal` or `.arpa` name)
20
+ * and not one the gateway serves itself (`refuseHost`, which knows the
21
+ * gateway's own host and `APP_BASE_DOMAIN`).
22
+ */
23
+ import { type ApiKeyCapability, type Capability, type CapabilityLookup } from "./capabilities.js";
24
+ /** A `providers` row as the gateway or the CLI read it. */
25
+ export interface ProviderRow {
26
+ id: string;
27
+ /** The spec, as JSON text or already parsed. */
28
+ spec: unknown;
29
+ /**
30
+ * What the row's key was set for: {@link providerBindingKey} of the row
31
+ * as it was when `everyapp secret set` last set one of its settings;
32
+ * null until then. The gateway reads the row's settings only while this
33
+ * equals the key of the row it has now (`providers.value-bound-to-hosts`).
34
+ */
35
+ boundTo?: string | null;
36
+ /** Who registered it (the Cloudflare login's email, or a member's), for the person setting its key. */
37
+ addedBy?: string | null;
38
+ /** When, in epoch milliseconds. */
39
+ addedAt?: number | null;
40
+ }
41
+ /**
42
+ * The part of a row a key is set for: its hosts, its host setting and its
43
+ * auth, as one canonical string (sorted keys, sorted hosts), so that
44
+ * replacing a row's hosts or auth changes the key and the value it held
45
+ * is no longer read until the operator sets it again.
46
+ */
47
+ export declare function providerBindingKey(capability: ApiKeyCapability): string;
48
+ /** One registered row as `provider list` and `provider show` report it. */
49
+ export interface RegisteredProvider {
50
+ id: string;
51
+ capability: ApiKeyCapability;
52
+ /** Whether the row's key was set for the hosts and auth it has now. */
53
+ bound: boolean;
54
+ addedBy: string | null;
55
+ addedAt: number | null;
56
+ }
57
+ export type RowRefusalCode = "PROVIDER_SPEC_INVALID" | "PROVIDER_BUILTIN" | "PROVIDER_SECRET_TAKEN" | "PROVIDER_HOST_REFUSED";
58
+ /** Why a row is not a provider on this gateway. */
59
+ export interface RowRefusal {
60
+ id: string;
61
+ code: RowRefusalCode;
62
+ message: string;
63
+ }
64
+ export interface ProviderRegistry extends CapabilityLookup {
65
+ /** Every id, the catalog's first in catalog order, then the rows' in row order. */
66
+ ids(): readonly string[];
67
+ entries(): ReadonlyArray<readonly [string, Capability]>;
68
+ sourceOf(id: string): "catalog" | "row" | undefined;
69
+ /** Every Gateway setting any provider reads, the catalog's and the rows'. */
70
+ settingNames(): ReadonlySet<string>;
71
+ /**
72
+ * Whether `id`'s settings may be read: always for a catalog entry; for a
73
+ * row, only while its key was set for the hosts and auth it has now.
74
+ * False for an id the registry doesn't have.
75
+ */
76
+ bound(id: string): boolean;
77
+ /** The settings of rows whose key isn't bound: read as unset everywhere. */
78
+ unboundSettings(): ReadonlySet<string>;
79
+ /** The registered rows this registry serves, in row order. */
80
+ rows(): readonly RegisteredProvider[];
81
+ /** The rows this registry left out, each with why. */
82
+ readonly rejected: readonly RowRefusal[];
83
+ }
84
+ export interface ProviderRegistryOptions {
85
+ /**
86
+ * A host no row may name on this gateway, with why: the gateway's own
87
+ * host and anything under its apps' base domain. The pure rules refuse
88
+ * the rest (IP literals, localhost, `.internal`).
89
+ */
90
+ refuseHost?: (host: string) => string | null;
91
+ }
92
+ /** The prefix a provider's own Gateway settings carry: `stripe` → `STRIPE_`, `tiktok-business` → `TIKTOK_BUSINESS_`. */
93
+ export declare function providerSettingPrefix(id: string): string;
94
+ /** Why `host` can't be a row's, by the pure rules alone; null when it can. */
95
+ export declare function publicHostProblem(host: string): string | null;
96
+ /** What a gateway serves itself, for {@link gatewayHostRefusal}. */
97
+ export interface GatewayHosts {
98
+ /** The gateway's own host (`apps.example.com`), or its URL. */
99
+ gatewayHost?: string | null;
100
+ /** Where its apps live (`APP_BASE_DOMAIN`): the domain and everything under it. */
101
+ appBaseDomain?: string | null;
102
+ /** A hosted gateway's third-party domain (`THIRD_PARTY_DOMAIN`), when it has one. */
103
+ thirdPartyDomain?: string | null;
104
+ }
105
+ /**
106
+ * Why a row can't send its key to `host` on this gateway: the gateway's
107
+ * own host, an app host under its base domain, or a host under its
108
+ * third-party domain. Null when none applies. The gateway applies it on
109
+ * every read (`refusedGatewayHost`, with its env) and the CLI at `provider
110
+ * add` (with the install's gateway host and base domain), in the same words.
111
+ */
112
+ export declare function gatewayHostRefusal(host: string, hosts: GatewayHosts): string | null;
113
+ /**
114
+ * Why a setting name can't be a row's: a name the Gateway, the catalog or
115
+ * another provider already reads, or one outside the row's own prefix.
116
+ * Null when the row may hold it.
117
+ */
118
+ export declare function rowSecretProblem(id: string, name: string, taken: (name: string) => boolean): string | null;
119
+ /**
120
+ * Check one parsed row against the catalog and the other rows. Pure: the
121
+ * CLI runs it before writing D1, the MCP tool before writing, and the
122
+ * gateway again on every read.
123
+ */
124
+ export declare function checkProviderRow(id: string, capability: ApiKeyCapability, context: {
125
+ /** Settings the other rows hold. */
126
+ rowSettings: ReadonlySet<string>;
127
+ refuseHost?: (host: string) => string | null;
128
+ }): RowRefusal | null;
129
+ /** A row's spec parsed and checked: the capability, or the refusal. */
130
+ export declare function resolveProviderRow(row: ProviderRow, context: {
131
+ rowSettings: ReadonlySet<string>;
132
+ refuseHost?: (host: string) => string | null;
133
+ }): {
134
+ ok: true;
135
+ capability: ApiKeyCapability;
136
+ } | {
137
+ ok: false;
138
+ refusal: RowRefusal;
139
+ };
140
+ /**
141
+ * The catalog and `rows` as one registry. Rows are taken in order; a row
142
+ * whose settings another earlier row holds is the one refused.
143
+ */
144
+ export declare function providerRegistry(rows?: readonly ProviderRow[], options?: ProviderRegistryOptions): ProviderRegistry;
145
+ /** The catalog alone, as a registry: what every surface reads without a gateway's rows. */
146
+ export declare const BUILTIN_PROVIDERS: ProviderRegistry;
147
+ //# sourceMappingURL=providerRegistry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"providerRegistry.d.ts","sourceRoot":"","sources":["../../src/internal/providerRegistry.ts"],"names":[],"mappings":"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"}