@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,416 @@
1
+ /**
2
+ * The scope set names a manifest entry declares, or null when the entry
3
+ * voids its grant: `scopes` missing, not an array, empty, a non-string
4
+ * element, a name listed twice, or any name the policy doesn't offer. An
5
+ * unknown name voids the whole grant rather than narrowing it silently, so
6
+ * a newer CLI's set name reaching an older gateway is refused outright and
7
+ * a message can say so.
8
+ */
9
+ export function declaredScopeSets(policy, entry) {
10
+ const declared = entry?.scopes;
11
+ if (!Array.isArray(declared) || declared.length === 0)
12
+ return null;
13
+ const names = [];
14
+ for (const name of declared) {
15
+ if (typeof name !== "string" ||
16
+ !Object.hasOwn(policy.sets, name) ||
17
+ names.includes(name)) {
18
+ return null;
19
+ }
20
+ names.push(name);
21
+ }
22
+ return names;
23
+ }
24
+ /**
25
+ * What an app with `sets` asks the provider for: the sets' scopes in
26
+ * registry order, deduplicated, then `alwaysRequested`. The status hands
27
+ * these out and the authorize URL (Microsoft: the token leg too) carries
28
+ * them verbatim.
29
+ */
30
+ export function requestedScopes(policy, sets) {
31
+ const scopes = [];
32
+ const userScopes = [];
33
+ for (const [, set] of declaredSets(policy, sets)) {
34
+ pushNew(scopes, set.scopes);
35
+ pushNew(userScopes, set.userScopes ?? []);
36
+ }
37
+ pushNew(scopes, policy.alwaysRequested);
38
+ return { scopes, userScopes };
39
+ }
40
+ /**
41
+ * What a token an app with `sets` is handed may carry: the requested
42
+ * scopes and the tolerated ones, in the dialect's canonical spelling so a
43
+ * granted list canonicalised the same way compares exactly.
44
+ */
45
+ export function allowedScopes(policy, sets) {
46
+ const requested = requestedScopes(policy, sets);
47
+ return {
48
+ scopes: canonical(policy.dialect, [
49
+ ...requested.scopes,
50
+ ...policy.tolerated,
51
+ ]),
52
+ userScopes: canonical(policy.dialect, requested.userScopes),
53
+ };
54
+ }
55
+ /**
56
+ * Whether a token response body carries a token: an access, refresh or ID
57
+ * token, or Slack's user token under `authed_user`. A 2xx without one
58
+ * (Slack's `ok: false`) is an error the app must see, not a grant.
59
+ */
60
+ export function carriesToken(json) {
61
+ const body = record(json);
62
+ if (!body)
63
+ return false;
64
+ return (typeof body["access_token"] === "string" ||
65
+ typeof body["refresh_token"] === "string" ||
66
+ typeof body["id_token"] === "string" ||
67
+ typeof record(body["authed_user"])?.["access_token"] === "string");
68
+ }
69
+ /**
70
+ * The scopes a token response says it granted, canonicalised per dialect,
71
+ * or null when the answer names none for a token it carries, which fails
72
+ * closed: every documented success response of the three providers names
73
+ * them (map-providers: Google and Microsoft `scope`, Slack `scope` and
74
+ * `authed_user.scope`), so a missing field is an answer the gateway can't
75
+ * hold to anything.
76
+ */
77
+ export function grantedScopes(policy, json) {
78
+ const body = record(json);
79
+ if (!body)
80
+ return null;
81
+ switch (policy.dialect) {
82
+ case "google": {
83
+ // Space-delimited, case-sensitive strings (Google's own words).
84
+ const scopes = splitScopes("google", body["scope"]);
85
+ return scopes ? { scopes } : null;
86
+ }
87
+ case "microsoft": {
88
+ // Documented URL-encoded with the Graph prefix
89
+ // (`https%3A%2F%2Fgraph.microsoft.com%2Fmail.read`), seen as short
90
+ // names in either case; `offline_access` is never echoed, and dropped
91
+ // if it ever is.
92
+ if (typeof body["scope"] !== "string")
93
+ return null;
94
+ let decoded;
95
+ try {
96
+ decoded = decodeURIComponent(body["scope"]);
97
+ }
98
+ catch {
99
+ return null;
100
+ }
101
+ const scopes = splitScopes("microsoft", decoded)?.filter((scope) => scope !== "offline_access");
102
+ return scopes && scopes.length > 0 ? { scopes } : null;
103
+ }
104
+ case "slack":
105
+ return slackGrantedScopes(body);
106
+ }
107
+ }
108
+ /**
109
+ * Slack answers with up to two tokens, each with its own scopes: the bot
110
+ * token at the top level and the installing person's under `authed_user`.
111
+ * Which kind the top-level one is comes from `token_type`, because a
112
+ * token-rotation refresh of a user token comes back at the top level with
113
+ * `token_type: "user"`; `authed_user` is a user token unless it says so.
114
+ */
115
+ function slackGrantedScopes(body) {
116
+ const granted = {};
117
+ const take = (token, kind) => {
118
+ if (kind !== "bot" && kind !== "user")
119
+ return false;
120
+ const scopes = splitScopes("slack", token["scope"]);
121
+ if (!scopes)
122
+ return false;
123
+ const key = kind === "bot" ? "scopes" : "userScopes";
124
+ granted[key] = pushNew(granted[key] ?? [], scopes);
125
+ return true;
126
+ };
127
+ if (typeof body["access_token"] === "string") {
128
+ if (!take(body, body["token_type"]))
129
+ return null;
130
+ }
131
+ const authedUser = record(body["authed_user"]);
132
+ if (authedUser && typeof authedUser["access_token"] === "string") {
133
+ if (!take(authedUser, authedUser["token_type"] ?? "user"))
134
+ return null;
135
+ }
136
+ return granted.scopes || granted.userScopes ? granted : null;
137
+ }
138
+ /**
139
+ * What `granted` carries beyond `allowed`, per token kind, for a refusal's
140
+ * message and log line: the user token's extras as `user:<scope>`. Both
141
+ * lists are in the dialect's canonical spelling already.
142
+ */
143
+ export function scopeExcess(granted, allowed) {
144
+ const extra = (scopes, within) => (scopes ?? []).filter((scope) => !within.includes(scope));
145
+ return [
146
+ ...extra(granted.scopes, allowed.scopes),
147
+ ...extra(granted.userScopes, allowed.userScopes).map((scope) => `user:${scope}`),
148
+ ];
149
+ }
150
+ /**
151
+ * The scopes a token request itself asks for (`scope`, and Slack's
152
+ * `user_scope`, in any case) in its form or JSON body, canonicalised per
153
+ * dialect for comparison with `allowedScopes()`, or null when the body
154
+ * names none. The query string is never read: the gateway refuses a
155
+ * request that puts these there, so only one place decides.
156
+ */
157
+ export function requestedTokenScopes(policy, request) {
158
+ const fields = bodyFields(request);
159
+ if (!fields)
160
+ return null;
161
+ const requested = {};
162
+ const scopes = splitScopes(policy.dialect, fields["scope"]);
163
+ if (scopes)
164
+ requested.scopes = scopes;
165
+ const userScopes = splitScopes(policy.dialect, fields["user_scope"]);
166
+ if (userScopes)
167
+ requested.userScopes = userScopes;
168
+ return requested.scopes || requested.userScopes ? requested : null;
169
+ }
170
+ /**
171
+ * `request` with its `scope`, in any case, as the policy's `requestScope`
172
+ * says: replaced by the requested list of the app's `sets`, dropped, or
173
+ * kept as sent. A separate step after `injectClientCredentials()`, whose
174
+ * re-serialised form or JSON body this edits the same way; any other body
175
+ * is left alone.
176
+ */
177
+ export function rewriteTokenRequestScope(policy, sets, request) {
178
+ if (policy.requestScope === "keep" || !request.body)
179
+ return request;
180
+ const replacement = policy.requestScope === "replace"
181
+ ? requestedScopes(policy, sets).scopes.join(" ")
182
+ : null;
183
+ const type = mediaType(request.headers.get("content-type"));
184
+ // Every spelling goes, as `injectClientCredentials()` strips the client:
185
+ // Entra reads a form's names in any case, so a `Scope` left beside the
186
+ // gateway's `scope` is refused upstream as a duplicate, or read instead.
187
+ const isScope = (name) => name.toLowerCase() === "scope";
188
+ let body = request.body;
189
+ if (type === FORM) {
190
+ const params = new URLSearchParams(body);
191
+ for (const name of new Set([...params.keys()].filter(isScope))) {
192
+ params.delete(name);
193
+ }
194
+ if (replacement !== null)
195
+ params.set("scope", replacement);
196
+ body = params.toString();
197
+ }
198
+ else if (type === JSON_TYPE) {
199
+ const parsed = jsonObject(body);
200
+ if (!parsed)
201
+ return request;
202
+ for (const name of Object.keys(parsed)) {
203
+ if (isScope(name))
204
+ delete parsed[name];
205
+ }
206
+ if (replacement !== null)
207
+ parsed["scope"] = replacement;
208
+ body = JSON.stringify(parsed);
209
+ }
210
+ else {
211
+ return request;
212
+ }
213
+ return { url: request.url, headers: request.headers, body };
214
+ }
215
+ /**
216
+ * The declared set that unlocks `method upstream`, or null. Not wired to
217
+ * any live path yet: it becomes the proxy's boundary once the gateway
218
+ * holds tokens, and the outbound Worker's for dispatched apps before that.
219
+ *
220
+ * In order: https only; the host must be on one of the declared sets'
221
+ * routes; the raw pathname is refused when it holds `\`, `//` or `%00`;
222
+ * each raw segment, and each percent-decoding of it while a `%` remains
223
+ * (a provider's layers may each decode once), is refused when it won't
224
+ * decode, holds a control or format character or a backslash, is one of
225
+ * the policy's denied segments in any case, or splits on `/` into a dot
226
+ * segment: `.` or `..`, with or without a `;` parameter (`..;x`), which
227
+ * Google's front end resolves like the bare one. The denied comparison is
228
+ * of the whole segment, because an encoded slash is part of one id to the
229
+ * provider, never a separator: a Search Console site URL whose own path
230
+ * holds `batch` stays matchable, and `2%2FmeasurementProtocolSecrets` is
231
+ * a data stream id that doesn't exist, not the secrets. Then the raw
232
+ * pathname, case preserved, is matched: GET and HEAD need a `paths` entry
233
+ * (exact, or a prefix when it ends in `/`), POST needs a `posts` pattern,
234
+ * and no other method goes through. Matching the raw path is what lets
235
+ * Search Console's `sites/https%3A%2F%2Fexample.com%2F/searchAnalytics/query`
236
+ * match `[^/]+` while `..`, batch tunnels and secrets stay refused however
237
+ * encoded. `X-HTTP-Method-Override`, `access_token` and `token` parameters
238
+ * are the proxy's to strip before it asks; nothing here reads them. The
239
+ * proxy fetches with `redirect: "manual"`: Google answers a dot segment it
240
+ * resolves with a 302 to the resolved path, and following one would carry
241
+ * the token to a path this never matched.
242
+ */
243
+ export function scopeRouteAllows(policy, sets, method, upstream) {
244
+ if (upstream.protocol !== "https:")
245
+ return null;
246
+ const onHost = declaredSets(policy, sets).flatMap(([name, set]) => set.routes
247
+ .filter((route) => route.host === upstream.host)
248
+ .map((route) => [name, route]));
249
+ if (onHost.length === 0)
250
+ return null;
251
+ const pathname = upstream.pathname;
252
+ if (!safeSegments(policy, pathname))
253
+ return null;
254
+ const verb = method.toUpperCase();
255
+ for (const [name, route] of onHost) {
256
+ if (verb === "GET" || verb === "HEAD") {
257
+ const covered = route.paths.some((entry) => entry.endsWith("/") ? pathname.startsWith(entry) : pathname === entry);
258
+ if (covered)
259
+ return name;
260
+ }
261
+ else if (verb === "POST") {
262
+ if (route.posts?.some((pattern) => pattern.test(pathname)))
263
+ return name;
264
+ }
265
+ }
266
+ return null;
267
+ }
268
+ /** Control and format characters: in no provider's path once decoded. */
269
+ const UNPRINTABLE = /[\p{Cc}\p{Cf}]/u;
270
+ /** A dot segment, bare or with a path parameter (`..;x`): Google's front end resolves both. */
271
+ const DOT_SEGMENT = /^\.{1,2}(;|$)/;
272
+ /**
273
+ * Whether every segment of the raw `pathname` passes the checks above in
274
+ * each form a provider's layers could see it: raw, then decoded again
275
+ * while a `%` remains.
276
+ */
277
+ function safeSegments(policy, pathname) {
278
+ if (pathname.includes("\\") ||
279
+ pathname.includes("//") ||
280
+ pathname.includes("%00")) {
281
+ return false;
282
+ }
283
+ const denied = policy.deniedSegments.map((segment) => segment.toLowerCase());
284
+ for (const raw of pathname.split("/")) {
285
+ let text = raw;
286
+ for (;;) {
287
+ if (!safeSegment(text, denied))
288
+ return false;
289
+ if (!text.includes("%"))
290
+ break;
291
+ // A `%` left after a decode is a byte the provider may decode again
292
+ // (double encoding), so that form is checked too; one that isn't an
293
+ // escape (`%2525` ends in a bare `%`) won't decode and refuses, as a
294
+ // malformed escape in the raw path does.
295
+ try {
296
+ text = decodeURIComponent(text);
297
+ }
298
+ catch {
299
+ return false;
300
+ }
301
+ }
302
+ }
303
+ return true;
304
+ }
305
+ /**
306
+ * Whether one form of a segment is safe: no control or format character,
307
+ * no backslash (in no provider's grammar), not a denied segment in any
308
+ * case, and no dot segment among its `/`-split parts (a traversal the
309
+ * provider might resolve). The denied comparison is of the whole: an
310
+ * encoded slash is part of one id to the provider, never a separator, so
311
+ * a Search Console site URL whose own path holds `batch` stays matchable.
312
+ */
313
+ function safeSegment(text, denied) {
314
+ if (UNPRINTABLE.test(text) || text.includes("\\"))
315
+ return false;
316
+ if (denied.includes(text.toLowerCase()))
317
+ return false;
318
+ return !text.split("/").some((part) => DOT_SEGMENT.test(part));
319
+ }
320
+ /** The policy's sets in registry order, keeping those `names` declares. */
321
+ function declaredSets(policy, names) {
322
+ return Object.entries(policy.sets).filter(([name]) => names.includes(name));
323
+ }
324
+ const GOOGLE_ALIASES = new Map([
325
+ ["email", "https://www.googleapis.com/auth/userinfo.email"],
326
+ ["profile", "https://www.googleapis.com/auth/userinfo.profile"],
327
+ ]);
328
+ const GRAPH_PREFIX = /^https:\/\/graph\.microsoft\.com\//i;
329
+ /** `scopes` in the dialect's one spelling, deduplicated, order kept. */
330
+ function canonical(dialect, scopes) {
331
+ return pushNew([], scopes.map((scope) => {
332
+ switch (dialect) {
333
+ case "google":
334
+ return GOOGLE_ALIASES.get(scope) ?? scope;
335
+ case "microsoft":
336
+ return scope.replace(GRAPH_PREFIX, "").toLowerCase();
337
+ case "slack":
338
+ return scope;
339
+ }
340
+ }));
341
+ }
342
+ /**
343
+ * A provider's scope field split into scopes, canonicalised, or null when
344
+ * it isn't a string or names nothing. Google and Microsoft separate with
345
+ * spaces; Slack with commas (spaces too, in its legacy form).
346
+ */
347
+ function splitScopes(dialect, value) {
348
+ if (typeof value !== "string")
349
+ return null;
350
+ const separator = dialect === "slack" ? /[,\s]+/ : /\s+/;
351
+ const scopes = canonical(dialect, value.split(separator).filter(Boolean));
352
+ return scopes.length > 0 ? scopes : null;
353
+ }
354
+ /** `into` with each of `more` it doesn't have yet, in order. */
355
+ function pushNew(into, more) {
356
+ for (const item of more)
357
+ if (!into.includes(item))
358
+ into.push(item);
359
+ return into;
360
+ }
361
+ const FORM = "application/x-www-form-urlencoded";
362
+ const JSON_TYPE = "application/json";
363
+ /** A token request's body fields, form or JSON, by lowercased name; null for any other body. */
364
+ function bodyFields(request) {
365
+ if (!request.body)
366
+ return null;
367
+ const type = mediaType(request.headers.get("content-type"));
368
+ if (type === FORM)
369
+ return foldFields(new URLSearchParams(request.body));
370
+ if (type === JSON_TYPE) {
371
+ const parsed = jsonObject(request.body);
372
+ return parsed && foldFields(Object.entries(parsed));
373
+ }
374
+ return null;
375
+ }
376
+ /**
377
+ * `pairs` by lowercased name, as Entra reads a form's names in any case. A
378
+ * name's values are one space-joined list, so a field sent twice, or as
379
+ * `scope` and `Scope`, hides nothing in the second copy; a value that
380
+ * isn't a string leaves its field not a string, which reads as naming
381
+ * none.
382
+ */
383
+ function foldFields(pairs) {
384
+ const fields = new Map();
385
+ for (const [name, value] of pairs) {
386
+ const key = name.toLowerCase();
387
+ const before = fields.get(key);
388
+ fields.set(key, !fields.has(key)
389
+ ? value
390
+ : typeof before === "string" && typeof value === "string"
391
+ ? `${before} ${value}`
392
+ : [before, value]);
393
+ }
394
+ return Object.fromEntries(fields);
395
+ }
396
+ /** A Content-Type's media type, lowercased and without parameters. */
397
+ function mediaType(contentType) {
398
+ return (contentType ?? "").split(";")[0].trim().toLowerCase();
399
+ }
400
+ /**
401
+ * `text` as a JSON object, or null for anything else (an array, a scalar,
402
+ * not JSON). Shared with the gateway's read of a provider's token answer.
403
+ */
404
+ export function jsonObject(text) {
405
+ try {
406
+ return record(JSON.parse(text));
407
+ }
408
+ catch {
409
+ return null;
410
+ }
411
+ }
412
+ function record(value) {
413
+ return value && typeof value === "object" && !Array.isArray(value)
414
+ ? value
415
+ : null;
416
+ }
@@ -0,0 +1,18 @@
1
+ /**
2
+ * The rule for a workspace's name: what the Gateway's setup claim gives
3
+ * the first organization, what a personal organization is called, and
4
+ * what a rename takes (Manage workspace → Rename, `everyapp workspace
5
+ * rename`). The Gateway and the CLI share it so a name the CLI writes is
6
+ * one the Gateway would have accepted. A name is user input that reaches
7
+ * other people: the invitation emails it sends, and every member's
8
+ * organization switcher.
9
+ */
10
+ export declare const MAX_ORGANIZATION_NAME_LENGTH = 64;
11
+ /**
12
+ * The name, trimmed and with its runs of whitespace made single spaces, or
13
+ * null when it is empty, longer than 64 characters, or has a control or
14
+ * invisible formatting character (line breaks, bidirectional overrides,
15
+ * zero-width characters) anywhere in it.
16
+ */
17
+ export declare function validOrganizationName(raw: string): string | null;
18
+ //# sourceMappingURL=organizationName.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"organizationName.d.ts","sourceRoot":"","sources":["../../src/internal/organizationName.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,eAAO,MAAM,4BAA4B,KAAK,CAAC;AAE/C;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAKhE"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * The rule for a workspace's name: what the Gateway's setup claim gives
3
+ * the first organization, what a personal organization is called, and
4
+ * what a rename takes (Manage workspace → Rename, `everyapp workspace
5
+ * rename`). The Gateway and the CLI share it so a name the CLI writes is
6
+ * one the Gateway would have accepted. A name is user input that reaches
7
+ * other people: the invitation emails it sends, and every member's
8
+ * organization switcher.
9
+ */
10
+ export const MAX_ORGANIZATION_NAME_LENGTH = 64;
11
+ /**
12
+ * The name, trimmed and with its runs of whitespace made single spaces, or
13
+ * null when it is empty, longer than 64 characters, or has a control or
14
+ * invisible formatting character (line breaks, bidirectional overrides,
15
+ * zero-width characters) anywhere in it.
16
+ */
17
+ export function validOrganizationName(raw) {
18
+ if (/[\p{Cc}\p{Cf}\u2028\u2029]/u.test(raw))
19
+ return null;
20
+ const name = raw.trim().replace(/\s+/g, " ");
21
+ if (!name || [...name].length > MAX_ORGANIZATION_NAME_LENGTH)
22
+ return null;
23
+ return name;
24
+ }
@@ -0,0 +1,195 @@
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 { type JWTPayload } from "jose";
9
+ import type { ToolCallClaim } from "./tools.js";
10
+ export declare const IDENTITY_ALG = "RS256";
11
+ export declare const IDENTITY_KEY_ID = "everyapp-identity";
12
+ export declare const IDENTITY_DEV_KEY_ID = "everyapp-identity-dev";
13
+ /**
14
+ * The only issuer a dev-kid token may name. The same value as
15
+ * `@every-app/sdk/dev`'s, kept apart so the Worker never loads the module
16
+ * `cloudflare.config.ts` does (a test pins the two together).
17
+ */
18
+ export declare const DEV_ISSUER = "https://gateway.dev.localhost";
19
+ export declare const IDENTITY_HEADER = "x-everyapp-identity";
20
+ export declare const PUBLIC_HEADER = "x-everyapp-public";
21
+ /**
22
+ * Carries the gateway's system token on its own calls to an app (the tools
23
+ * catalog fetch). Never an identity: no user, and it only opens the endpoint
24
+ * named by its `purpose` claim.
25
+ */
26
+ export declare const SYSTEM_HEADER = "x-everyapp-system";
27
+ /**
28
+ * On a refusal the AppGateway binding makes itself (the app's manifest lacks
29
+ * the capability, the gateway holds no key), as opposed to the provider's
30
+ * own answer passed through: the refusal's code, also in the JSON body.
31
+ */
32
+ export declare const GATEWAY_ERROR_HEADER = "x-everyapp-error";
33
+ /**
34
+ * On a shared app's call to the AppGateway binding for work no request
35
+ * started (a cron, a Workflow step): the organization the work is for. The
36
+ * gateway believes it only from a shared app's Worker, and only for an
37
+ * active organization with a live member; an organization's own app may
38
+ * only name its own. The perimeter strips it, with every `x-everyapp-*`,
39
+ * from what browsers send.
40
+ */
41
+ export declare const ORG_HEADER = "x-everyapp-org";
42
+ /** 120-second lifetime — caps revocation staleness while surviving clock skew. */
43
+ export declare const IDENTITY_TTL_SECONDS = 120;
44
+ /** System tokens are minted per call and live at most a minute. */
45
+ export declare const SYSTEM_TOKEN_TTL_SECONDS = 60;
46
+ /** Env var carrying the app's manifest id. */
47
+ export declare const APP_ID_ENV = "EVERYAPP_APP_ID";
48
+ /**
49
+ * Env var carrying the expected identity audience: the app's Worker name,
50
+ * which the gateway stamps as `aud` on every token it mints for the app. Two
51
+ * Workers of one app id (two organizations' copies) never accept each
52
+ * other's tokens.
53
+ */
54
+ export declare const AUDIENCE_ENV = "EVERYAPP_AUDIENCE";
55
+ /** Default env var carrying a JSON array of SPKI PEM public keys. */
56
+ export declare const PUBLIC_KEYS_ENV = "EVERYAPP_IDENTITY_PUBLIC_KEYS";
57
+ /** Env var carrying the expected gateway issuer for user identity verification. */
58
+ export declare const ISSUER_ENV = "EVERYAPP_IDENTITY_ISSUER";
59
+ /**
60
+ * Env var set to `1` on a shared app's Workers (one Worker for every
61
+ * organization): a gateway call from them must say whom it is for.
62
+ */
63
+ export declare const SHARED_ENV = "EVERYAPP_SHARED";
64
+ /** When set to `1` or `true` in the worker env, the dev identity kid is accepted. */
65
+ export declare const DEV_ENV = "EVERYAPP_DEV";
66
+ /** `sub` claim the gateway mints public-route markers with. */
67
+ export declare const PUBLIC_MARKER_SUB = "public";
68
+ /** `sub` claim of gateway system tokens. */
69
+ export declare const SYSTEM_TOKEN_SUB = "system";
70
+ export type IdentityChannel = "web" | "api" | "mcp" | "agent";
71
+ export type IdentityTokenType = "user" | "public" | "system";
72
+ /** What a system token may open. One purpose per token. */
73
+ export type SystemTokenPurpose = "tools.list";
74
+ /** The actor on whose behalf the request is made (user, MCP client, agent). */
75
+ export interface IdentityActor {
76
+ sub: string;
77
+ }
78
+ export interface IdentitySubject {
79
+ sub: string;
80
+ email: string;
81
+ orgId: string;
82
+ orgRole: string;
83
+ }
84
+ export interface EveryAppUser {
85
+ /** User id (the `sub` claim). */
86
+ id: string;
87
+ email: string;
88
+ orgId: string;
89
+ orgRole: string;
90
+ channel: IdentityChannel;
91
+ /** The acting principal (user, or `mcp:<client>` / agent). */
92
+ actor: IdentityActor;
93
+ scopes: string[];
94
+ jti: string;
95
+ /**
96
+ * Set only on an MCP tool call (`channel: "mcp"`): the one call this
97
+ * identity was minted for.
98
+ */
99
+ toolCall?: ToolCallClaim;
100
+ }
101
+ export interface IdentityClaims extends JWTPayload {
102
+ typ: "user";
103
+ email: string;
104
+ org_id: string;
105
+ org_role: string;
106
+ chan: IdentityChannel;
107
+ act: IdentityActor;
108
+ scopes: string[];
109
+ jti: string;
110
+ /** Tool-call binding; only the gateway's ToolBus mints it. */
111
+ tc?: ToolCallClaim;
112
+ }
113
+ export interface SystemClaims extends JWTPayload {
114
+ typ: "system";
115
+ purpose: SystemTokenPurpose;
116
+ jti: string;
117
+ }
118
+ export interface PublicMarkerClaims extends JWTPayload {
119
+ typ: "public";
120
+ pub: true;
121
+ jti: string;
122
+ }
123
+ export declare class ProtocolClaimsError extends Error {
124
+ constructor(message: string);
125
+ }
126
+ export declare function identitySubjectToClaims(subject: IdentitySubject, opts: {
127
+ channel?: IdentityChannel;
128
+ actor?: IdentityActor;
129
+ scopes?: string[];
130
+ toolCall?: ToolCallClaim;
131
+ jti: string;
132
+ }): IdentityClaims;
133
+ export declare function identityClaimsToEveryAppUser(payload: JWTPayload): EveryAppUser;
134
+ export declare function publicMarkerClaims(jti: string): PublicMarkerClaims;
135
+ export declare function assertPublicMarkerClaims(payload: JWTPayload): void;
136
+ /**
137
+ * A system token opens exactly one endpoint and lives at most
138
+ * {@link SYSTEM_TOKEN_TTL_SECONDS}: a leaked one is short-lived and useless
139
+ * anywhere else.
140
+ */
141
+ export declare function assertSystemClaims(payload: JWTPayload, purpose: SystemTokenPurpose): SystemClaims;
142
+ export interface MintIdentityOptions {
143
+ subject: IdentitySubject;
144
+ /** The app id this token is scoped to — becomes the `aud` claim. */
145
+ audience: string;
146
+ issuer: string;
147
+ channel?: IdentityChannel;
148
+ actor?: IdentityActor;
149
+ scopes?: string[];
150
+ /** Bind the token to one MCP tool call (`tc` claim). ToolBus only. */
151
+ toolCall?: ToolCallClaim;
152
+ ttlSeconds?: number;
153
+ now?: number;
154
+ /** Header kid. Defaults to the production kid; dev mints with the dev kid. */
155
+ keyId?: string;
156
+ }
157
+ /**
158
+ * Mint an identity JWT. Returns the compact JWS string to inject as
159
+ * `x-everyapp-identity`.
160
+ */
161
+ export declare function mintIdentityJwt(privateKeyPem: string, opts: MintIdentityOptions): Promise<string>;
162
+ export interface MintPublicMarkerOptions {
163
+ /** The app id this marker is scoped to — becomes the `aud` claim. */
164
+ audience: string;
165
+ issuer: string;
166
+ ttlSeconds?: number;
167
+ now?: number;
168
+ /** Header kid. Defaults to the production kid; dev mints with the dev kid. */
169
+ keyId?: string;
170
+ }
171
+ /**
172
+ * Mint the public-route marker for `x-everyapp-public`. A bare header value
173
+ * is never a trust source, so the marker is a signed, short-lived, app-scoped
174
+ * JWT with `pub: true` and `typ: "public"` that the SDK verifies exactly like
175
+ * an identity token.
176
+ */
177
+ export declare function mintPublicMarkerJwt(privateKeyPem: string, opts: MintPublicMarkerOptions): Promise<string>;
178
+ export interface MintSystemTokenOptions {
179
+ /** The app id the token is for — becomes the `aud` claim. */
180
+ audience: string;
181
+ issuer: string;
182
+ purpose: SystemTokenPurpose;
183
+ /** At most {@link SYSTEM_TOKEN_TTL_SECONDS}. */
184
+ ttlSeconds?: number;
185
+ now?: number;
186
+ /** Header kid. Defaults to the production kid; dev mints with the dev kid. */
187
+ keyId?: string;
188
+ }
189
+ /**
190
+ * Mint the gateway's system token for `x-everyapp-system`: no user, one
191
+ * purpose, one app, one minute. The SDK only accepts it on the endpoint its
192
+ * purpose names, and never as an identity.
193
+ */
194
+ export declare function mintSystemJwt(privateKeyPem: string, opts: MintSystemTokenOptions): Promise<string>;
195
+ //# sourceMappingURL=protocol.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../../src/internal/protocol.ts"],"names":[],"mappings":"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"}