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

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 (163) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1 -1
  3. package/dist/cloudflare/catalogSettings.generated.d.ts +81 -0
  4. package/dist/cloudflare/catalogSettings.generated.d.ts.map +1 -0
  5. package/dist/cloudflare/catalogSettings.generated.js +174 -0
  6. package/dist/cloudflare/index.d.ts +3 -2
  7. package/dist/cloudflare/index.d.ts.map +1 -1
  8. package/dist/cloudflare/index.js +4 -1
  9. package/dist/cloudflare/sentinel.d.ts +60 -2
  10. package/dist/cloudflare/sentinel.d.ts.map +1 -1
  11. package/dist/cloudflare/sentinel.js +37 -2
  12. package/dist/cloudflare/worker.d.ts +357 -63
  13. package/dist/cloudflare/worker.d.ts.map +1 -1
  14. package/dist/cloudflare/worker.js +363 -104
  15. package/dist/dev/index.d.ts +1 -1
  16. package/dist/dev/index.d.ts.map +1 -1
  17. package/dist/dev/index.js +1 -1
  18. package/dist/dev/keypair.d.ts +2 -0
  19. package/dist/dev/keypair.d.ts.map +1 -1
  20. package/dist/dev/keypair.js +2 -0
  21. package/dist/index.d.ts +6 -0
  22. package/dist/index.d.ts.map +1 -0
  23. package/dist/index.js +5 -0
  24. package/dist/internal/aiDefault.d.ts +204 -0
  25. package/dist/internal/aiDefault.d.ts.map +1 -0
  26. package/dist/internal/aiDefault.js +334 -0
  27. package/dist/internal/aiProviders.d.ts +7 -2
  28. package/dist/internal/aiProviders.d.ts.map +1 -1
  29. package/dist/internal/aiProviders.js +17 -4
  30. package/dist/internal/appSettings.d.ts +82 -4
  31. package/dist/internal/appSettings.d.ts.map +1 -1
  32. package/dist/internal/appSettings.js +204 -29
  33. package/dist/internal/audit.d.ts +108 -0
  34. package/dist/internal/audit.d.ts.map +1 -0
  35. package/dist/internal/audit.js +235 -0
  36. package/dist/internal/capabilities.d.ts +2268 -438
  37. package/dist/internal/capabilities.d.ts.map +1 -1
  38. package/dist/internal/capabilities.js +128 -539
  39. package/dist/internal/catalog/commerce.d.ts +394 -0
  40. package/dist/internal/catalog/commerce.d.ts.map +1 -0
  41. package/dist/internal/catalog/commerce.js +477 -0
  42. package/dist/internal/catalog/comms.d.ts +375 -0
  43. package/dist/internal/catalog/comms.d.ts.map +1 -0
  44. package/dist/internal/catalog/comms.js +520 -0
  45. package/dist/internal/catalog/index.d.ts +1973 -0
  46. package/dist/internal/catalog/index.d.ts.map +1 -0
  47. package/dist/internal/catalog/index.js +19 -0
  48. package/dist/internal/catalog/inference.d.ts +393 -0
  49. package/dist/internal/catalog/inference.d.ts.map +1 -0
  50. package/dist/internal/catalog/inference.js +460 -0
  51. package/dist/internal/catalog/infra.d.ts +423 -0
  52. package/dist/internal/catalog/infra.d.ts.map +1 -0
  53. package/dist/internal/catalog/infra.js +543 -0
  54. package/dist/internal/catalog/search.d.ts +400 -0
  55. package/dist/internal/catalog/search.d.ts.map +1 -0
  56. package/dist/internal/catalog/search.js +463 -0
  57. package/dist/internal/devProviders.d.ts +2 -2
  58. package/dist/internal/devProviders.d.ts.map +1 -1
  59. package/dist/internal/devProviders.js +19 -1
  60. package/dist/internal/events.d.ts +13 -2
  61. package/dist/internal/events.d.ts.map +1 -1
  62. package/dist/internal/events.js +47 -4
  63. package/dist/internal/gatewaySettings.d.ts +3 -2
  64. package/dist/internal/gatewaySettings.d.ts.map +1 -1
  65. package/dist/internal/gatewaySettings.js +12 -6
  66. package/dist/internal/identity.d.ts +41 -4
  67. package/dist/internal/identity.d.ts.map +1 -1
  68. package/dist/internal/identity.js +48 -10
  69. package/dist/internal/index.d.ts +6 -1
  70. package/dist/internal/index.d.ts.map +1 -1
  71. package/dist/internal/index.js +6 -1
  72. package/dist/internal/members.d.ts +3 -2
  73. package/dist/internal/members.d.ts.map +1 -1
  74. package/dist/internal/oauthClient.d.ts +10 -12
  75. package/dist/internal/oauthClient.d.ts.map +1 -1
  76. package/dist/internal/oauthClient.js +20 -81
  77. package/dist/internal/oauthPresets.d.ts +33 -0
  78. package/dist/internal/oauthPresets.d.ts.map +1 -0
  79. package/dist/internal/oauthPresets.js +1064 -0
  80. package/dist/internal/oauthScopes.d.ts +56 -1
  81. package/dist/internal/oauthScopes.d.ts.map +1 -1
  82. package/dist/internal/oauthScopes.js +98 -4
  83. package/dist/internal/oauthSpec.d.ts +102 -0
  84. package/dist/internal/oauthSpec.d.ts.map +1 -0
  85. package/dist/internal/oauthSpec.js +789 -0
  86. package/dist/internal/protocol.d.ts +64 -1
  87. package/dist/internal/protocol.d.ts.map +1 -1
  88. package/dist/internal/protocol.js +51 -1
  89. package/dist/internal/providerRegistry.d.ts +77 -6
  90. package/dist/internal/providerRegistry.d.ts.map +1 -1
  91. package/dist/internal/providerRegistry.js +178 -8
  92. package/dist/internal/providerSpec.d.ts +18 -7
  93. package/dist/internal/providerSpec.d.ts.map +1 -1
  94. package/dist/internal/providerSpec.js +442 -34
  95. package/dist/internal/signInProviders.d.ts +104 -0
  96. package/dist/internal/signInProviders.d.ts.map +1 -0
  97. package/dist/internal/signInProviders.js +245 -0
  98. package/dist/manifest.d.ts +238 -0
  99. package/dist/manifest.d.ts.map +1 -0
  100. package/dist/manifest.js +30 -0
  101. package/dist/server/ai.d.ts +111 -0
  102. package/dist/server/ai.d.ts.map +1 -0
  103. package/dist/server/ai.js +145 -0
  104. package/dist/server/aiBinding.d.ts +68 -0
  105. package/dist/server/aiBinding.d.ts.map +1 -0
  106. package/dist/server/aiBinding.js +294 -0
  107. package/dist/server/attribution.d.ts +9 -5
  108. package/dist/server/attribution.d.ts.map +1 -1
  109. package/dist/server/attribution.js +12 -4
  110. package/dist/server/authorizeUrl.d.ts +1 -1
  111. package/dist/server/authorizeUrl.d.ts.map +1 -1
  112. package/dist/server/authorizeUrl.js +2 -6
  113. package/dist/server/connectUrl.d.ts +21 -0
  114. package/dist/server/connectUrl.d.ts.map +1 -0
  115. package/dist/server/connectUrl.js +37 -0
  116. package/dist/server/context.d.ts +68 -0
  117. package/dist/server/context.d.ts.map +1 -0
  118. package/dist/server/context.js +117 -0
  119. package/dist/server/emailBinding.d.ts +72 -0
  120. package/dist/server/emailBinding.d.ts.map +1 -0
  121. package/dist/server/emailBinding.js +124 -0
  122. package/dist/server/emit.d.ts +1 -1
  123. package/dist/server/emit.d.ts.map +1 -1
  124. package/dist/server/emit.js +7 -7
  125. package/dist/server/env.d.ts +44 -0
  126. package/dist/server/env.d.ts.map +1 -0
  127. package/dist/server/env.js +1 -0
  128. package/dist/server/everyApp.d.ts +27 -7
  129. package/dist/server/everyApp.d.ts.map +1 -1
  130. package/dist/server/everyApp.js +106 -5
  131. package/dist/server/fromMcpTools.d.ts +89 -0
  132. package/dist/server/fromMcpTools.d.ts.map +1 -0
  133. package/dist/server/fromMcpTools.js +192 -0
  134. package/dist/server/gatewayFetch.d.ts +42 -18
  135. package/dist/server/gatewayFetch.d.ts.map +1 -1
  136. package/dist/server/gatewayFetch.js +138 -19
  137. package/dist/server/gatewayUrl.d.ts +13 -0
  138. package/dist/server/gatewayUrl.d.ts.map +1 -0
  139. package/dist/server/gatewayUrl.js +34 -0
  140. package/dist/server/index.d.ts +15 -4
  141. package/dist/server/index.d.ts.map +1 -1
  142. package/dist/server/index.js +12 -2
  143. package/dist/server/integrationFetch.d.ts +70 -39
  144. package/dist/server/integrationFetch.d.ts.map +1 -1
  145. package/dist/server/integrationFetch.js +244 -82
  146. package/dist/server/listMembers.d.ts +1 -1
  147. package/dist/server/listMembers.d.ts.map +1 -1
  148. package/dist/server/listMembers.js +8 -11
  149. package/dist/server/refusal.d.ts +55 -0
  150. package/dist/server/refusal.d.ts.map +1 -0
  151. package/dist/server/refusal.js +193 -0
  152. package/dist/server/sendEmail.d.ts +1 -1
  153. package/dist/server/sendEmail.d.ts.map +1 -1
  154. package/dist/server/sendEmail.js +7 -7
  155. package/dist/server/toolsEndpoint.d.ts.map +1 -1
  156. package/dist/server/toolsEndpoint.js +11 -5
  157. package/dist/tanstack-start/index.d.ts +9 -0
  158. package/dist/tanstack-start/index.d.ts.map +1 -0
  159. package/dist/tanstack-start/index.js +29 -0
  160. package/dist/testing/index.d.ts +93 -0
  161. package/dist/testing/index.d.ts.map +1 -0
  162. package/dist/testing/index.js +156 -0
  163. package/package.json +35 -14
@@ -7,7 +7,7 @@
7
7
  * check, the SDK's local-dev twin of it and, later, the proxy and the
8
8
  * outbound Worker. Nothing here reads a secret or a token value.
9
9
  */
10
- import type { OAuthScopePolicy } from "./capabilities.js";
10
+ import type { OAuthScopeDialect, OAuthScopePolicy } from "./capabilities.js";
11
11
  import type { TokenRequest } from "./oauthClient.js";
12
12
  /** Scopes by the token they belong to: the bot or only token, and Slack's user token. */
13
13
  export interface ScopeList {
@@ -58,6 +58,54 @@ export declare function carriesToken(json: unknown): boolean;
58
58
  * hold to anything.
59
59
  */
60
60
  export declare function grantedScopes(policy: OAuthScopePolicy, json: unknown): GrantedScopes | null;
61
+ /**
62
+ * What a token response granted, for the Gateway-owned flow: as
63
+ * {@link grantedScopes}, except that a `space` or `comma` provider that
64
+ * names no `scope` at all is taken at its word (RFC 6749 §5.1: the field
65
+ * is optional when the grant matches the request), so `requested` stands.
66
+ * The three parsed dialects keep failing closed.
67
+ */
68
+ export declare function grantedScopesOrRequested(policy: OAuthScopePolicy, json: unknown, requested: ScopeList): GrantedScopes | null;
69
+ /** Why the proxy refuses a held-token call, with what would let it through. */
70
+ export type HeldTokenRefusal = {
71
+ ok: false;
72
+ code: "integration_not_connected";
73
+ /** The declared sets the connection was not granted. */
74
+ missingSets: string[];
75
+ } | {
76
+ ok: false;
77
+ code: "integration_scope_not_allowed" | "integration_method_not_allowed";
78
+ message: string;
79
+ };
80
+ /**
81
+ * Whether an app's call with a held token goes through, and under which
82
+ * set (docs/design/2026-10-oauth-providers.md section 7). In order: every
83
+ * set the app declares must be among the connection's (else the person
84
+ * connects again: `integration_not_connected` with the missing sets); the
85
+ * host must be one of the provider's `api` hosts; the path passes the
86
+ * segment rules (`scopeRouteAllows`'s: no batch tunnels, no dot segments,
87
+ * no denied segments); then a declared set with routes must cover the
88
+ * call, or a declared set without routes covers its hosts by access: a
89
+ * read set unlocks `readMethods` (GET and HEAD by default), a write set
90
+ * every method the provider offers. `writes` says whether the method is
91
+ * one the grant allows beyond reads, decided by the caller as for an
92
+ * API-key provider.
93
+ */
94
+ export declare function heldTokenCallAllowed({ policy, declaredSets, connectionSets, hosts, method, upstream, readMethods, writes, }: {
95
+ policy: OAuthScopePolicy;
96
+ declaredSets: readonly string[];
97
+ connectionSets: readonly string[];
98
+ /** The provider's `api` hosts. */
99
+ hosts: readonly string[];
100
+ method: string;
101
+ upstream: URL;
102
+ readMethods?: readonly string[];
103
+ /** Whether `method` is a write the app's grant allows. */
104
+ writes: boolean;
105
+ }): {
106
+ ok: true;
107
+ set: string;
108
+ } | HeldTokenRefusal;
61
109
  /**
62
110
  * What `granted` carries beyond `allowed`, per token kind, for a refusal's
63
111
  * message and log line: the user token's extras as `user:<scope>`. Both
@@ -109,6 +157,13 @@ export declare function rewriteTokenRequestScope(policy: OAuthScopePolicy, sets:
109
157
  * the token to a path this never matched.
110
158
  */
111
159
  export declare function scopeRouteAllows(policy: OAuthScopePolicy, sets: readonly string[], method: string, upstream: URL): string | null;
160
+ /** `scopes` in the dialect's one spelling, deduplicated, order kept. */
161
+ /**
162
+ * `scopes` in the dialect's canonical spelling (Google's long names,
163
+ * Microsoft's bare lower-case names), for comparing a set's scopes with
164
+ * what a token response says it granted.
165
+ */
166
+ export declare function canonicalScopes(dialect: OAuthScopeDialect, scopes: readonly string[]): string[];
112
167
  /**
113
168
  * `text` as a JSON object, or null for anything else (an array, a scalar,
114
169
  * not JSON). Shared with the gateway's read of a provider's token answer.
@@ -1 +1 @@
1
- {"version":3,"file":"oauthScopes.d.ts","sourceRoot":"","sources":["../../src/internal/oauthScopes.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAEV,gBAAgB,EAEjB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAErD,yFAAyF;AACzF,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,4FAA4F;AAC5F,MAAM,WAAW,aAAa;IAC5B,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;CACvB;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,gBAAgB,EACxB,KAAK,EAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,SAAS,GACtC,MAAM,EAAE,GAAG,IAAI,CAejB;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,gBAAgB,EACxB,IAAI,EAAE,SAAS,MAAM,EAAE,GACtB,SAAS,CASX;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE,gBAAgB,EACxB,IAAI,EAAE,SAAS,MAAM,EAAE,GACtB,SAAS,CASX;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CASnD;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE,gBAAgB,EACxB,IAAI,EAAE,OAAO,GACZ,aAAa,GAAG,IAAI,CA6BtB;AA+BD;;;;GAIG;AACH,wBAAgB,WAAW,CACzB,OAAO,EAAE,aAAa,EACtB,OAAO,EAAE,SAAS,GACjB,MAAM,EAAE,CASV;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,gBAAgB,EACxB,OAAO,EAAE,YAAY,GACpB,aAAa,GAAG,IAAI,CAStB;AAED;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,gBAAgB,EACxB,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,OAAO,EAAE,YAAY,GACpB,YAAY,CA+Bd;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,gBAAgB,EACxB,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,GAAG,GACZ,MAAM,GAAG,IAAI,CAsBf;AAwJD;;;GAGG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAMvE"}
1
+ {"version":3,"file":"oauthScopes.d.ts","sourceRoot":"","sources":["../../src/internal/oauthScopes.ts"],"names":[],"mappings":"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"}
@@ -30,7 +30,7 @@ export function declaredScopeSets(policy, entry) {
30
30
  export function requestedScopes(policy, sets) {
31
31
  const scopes = [];
32
32
  const userScopes = [];
33
- for (const [, set] of declaredSets(policy, sets)) {
33
+ for (const [, set] of setsOf(policy, sets)) {
34
34
  pushNew(scopes, set.scopes);
35
35
  pushNew(userScopes, set.userScopes ?? []);
36
36
  }
@@ -103,7 +103,91 @@ export function grantedScopes(policy, json) {
103
103
  }
104
104
  case "slack":
105
105
  return slackGrantedScopes(body);
106
+ case "space":
107
+ case "comma": {
108
+ const scopes = splitScopes(policy.dialect, body["scope"]);
109
+ return scopes ? { scopes } : null;
110
+ }
111
+ }
112
+ }
113
+ /**
114
+ * What a token response granted, for the Gateway-owned flow: as
115
+ * {@link grantedScopes}, except that a `space` or `comma` provider that
116
+ * names no `scope` at all is taken at its word (RFC 6749 §5.1: the field
117
+ * is optional when the grant matches the request), so `requested` stands.
118
+ * The three parsed dialects keep failing closed.
119
+ */
120
+ export function grantedScopesOrRequested(policy, json, requested) {
121
+ const granted = grantedScopes(policy, json);
122
+ if (granted)
123
+ return granted;
124
+ const body = record(json);
125
+ if (body &&
126
+ body["scope"] === undefined &&
127
+ (policy.dialect === "space" || policy.dialect === "comma")) {
128
+ return { scopes: canonical(policy.dialect, requested.scopes) };
106
129
  }
130
+ return null;
131
+ }
132
+ /**
133
+ * Whether an app's call with a held token goes through, and under which
134
+ * set (docs/design/2026-10-oauth-providers.md section 7). In order: every
135
+ * set the app declares must be among the connection's (else the person
136
+ * connects again: `integration_not_connected` with the missing sets); the
137
+ * host must be one of the provider's `api` hosts; the path passes the
138
+ * segment rules (`scopeRouteAllows`'s: no batch tunnels, no dot segments,
139
+ * no denied segments); then a declared set with routes must cover the
140
+ * call, or a declared set without routes covers its hosts by access: a
141
+ * read set unlocks `readMethods` (GET and HEAD by default), a write set
142
+ * every method the provider offers. `writes` says whether the method is
143
+ * one the grant allows beyond reads, decided by the caller as for an
144
+ * API-key provider.
145
+ */
146
+ export function heldTokenCallAllowed({ policy, declaredSets, connectionSets, hosts, method, upstream, readMethods = ["GET", "HEAD"], writes, }) {
147
+ const missingSets = declaredSets.filter((name) => !connectionSets.includes(name));
148
+ if (missingSets.length > 0) {
149
+ return { ok: false, code: "integration_not_connected", missingSets };
150
+ }
151
+ if (upstream.protocol !== "https:" || !hosts.includes(upstream.host)) {
152
+ return {
153
+ ok: false,
154
+ code: "integration_scope_not_allowed",
155
+ message: `${upstream.host} is not a host this provider's token reaches (${hosts.join(", ")}).`,
156
+ };
157
+ }
158
+ if (!safeSegments(policy, upstream.pathname)) {
159
+ return {
160
+ ok: false,
161
+ code: "integration_scope_not_allowed",
162
+ message: `${upstream.pathname} is a path no scope set unlocks.`,
163
+ };
164
+ }
165
+ const verb = method.toUpperCase();
166
+ const reads = readMethods.includes(verb);
167
+ // A set's routes decide first: a read-shaped POST a read set lists
168
+ // under `posts` (a search, a query) is a read whatever the grant.
169
+ const routed = scopeRouteAllows(policy, declaredSets, verb, upstream);
170
+ if (routed)
171
+ return { ok: true, set: routed };
172
+ if (!reads && !writes) {
173
+ return {
174
+ ok: false,
175
+ code: "integration_method_not_allowed",
176
+ message: `${verb} ${upstream.pathname}: calls may use ${readMethods.join(" or ")} with access: "read"; ${verb} needs access: "write" in the app's capabilities entry, on a provider that offers it, or a scope set whose routes list it.`,
177
+ };
178
+ }
179
+ for (const [name, set] of setsOf(policy, declaredSets)) {
180
+ if (set.routes.length > 0)
181
+ continue;
182
+ if (reads || (writes && set.access === "write")) {
183
+ return { ok: true, set: name };
184
+ }
185
+ }
186
+ return {
187
+ ok: false,
188
+ code: "integration_scope_not_allowed",
189
+ message: `${verb} ${upstream.pathname} is outside the scope sets this app declares (${declaredSets.join(", ")}).`,
190
+ };
107
191
  }
108
192
  /**
109
193
  * Slack answers with up to two tokens, each with its own scopes: the bot
@@ -243,7 +327,7 @@ export function rewriteTokenRequestScope(policy, sets, request) {
243
327
  export function scopeRouteAllows(policy, sets, method, upstream) {
244
328
  if (upstream.protocol !== "https:")
245
329
  return null;
246
- const onHost = declaredSets(policy, sets).flatMap(([name, set]) => set.routes
330
+ const onHost = setsOf(policy, sets).flatMap(([name, set]) => set.routes
247
331
  .filter((route) => route.host === upstream.host)
248
332
  .map((route) => [name, route]));
249
333
  if (onHost.length === 0)
@@ -318,7 +402,7 @@ function safeSegment(text, denied) {
318
402
  return !text.split("/").some((part) => DOT_SEGMENT.test(part));
319
403
  }
320
404
  /** The policy's sets in registry order, keeping those `names` declares. */
321
- function declaredSets(policy, names) {
405
+ function setsOf(policy, names) {
322
406
  return Object.entries(policy.sets).filter(([name]) => names.includes(name));
323
407
  }
324
408
  const GOOGLE_ALIASES = new Map([
@@ -327,6 +411,14 @@ const GOOGLE_ALIASES = new Map([
327
411
  ]);
328
412
  const GRAPH_PREFIX = /^https:\/\/graph\.microsoft\.com\//i;
329
413
  /** `scopes` in the dialect's one spelling, deduplicated, order kept. */
414
+ /**
415
+ * `scopes` in the dialect's canonical spelling (Google's long names,
416
+ * Microsoft's bare lower-case names), for comparing a set's scopes with
417
+ * what a token response says it granted.
418
+ */
419
+ export function canonicalScopes(dialect, scopes) {
420
+ return canonical(dialect, [...scopes]);
421
+ }
330
422
  function canonical(dialect, scopes) {
331
423
  return pushNew([], scopes.map((scope) => {
332
424
  switch (dialect) {
@@ -335,6 +427,8 @@ function canonical(dialect, scopes) {
335
427
  case "microsoft":
336
428
  return scope.replace(GRAPH_PREFIX, "").toLowerCase();
337
429
  case "slack":
430
+ case "space":
431
+ case "comma":
338
432
  return scope;
339
433
  }
340
434
  }));
@@ -347,7 +441,7 @@ function canonical(dialect, scopes) {
347
441
  function splitScopes(dialect, value) {
348
442
  if (typeof value !== "string")
349
443
  return null;
350
- const separator = dialect === "slack" ? /[,\s]+/ : /\s+/;
444
+ const separator = dialect === "slack" || dialect === "comma" ? /[,\s]+/ : /\s+/;
351
445
  const scopes = canonical(dialect, value.split(separator).filter(Boolean));
352
446
  return scopes.length > 0 ? scopes : null;
353
447
  }
@@ -0,0 +1,102 @@
1
+ /**
2
+ * The `oauth2-user` half of a provider spec
3
+ * (docs/design/2026-10-oauth-providers.md section 3): a registered OAuth
4
+ * provider, or a preset (./oauthPresets.ts), as JSON, turned into the
5
+ * same {@link OAuthClientCapability} a catalog client is, with a `flow`
6
+ * the Gateway runs itself. `parseProviderSpec` (./providerSpec.ts) hands
7
+ * the common fields here once it sees `auth.kind: "oauth2-user"`; nothing
8
+ * here reads a value: a spec names Gateway settings, never holds one.
9
+ */
10
+ import { type CapabilityAccess, type OAuthClientCapability, type OAuthScopeSet } from "./capabilities.js";
11
+ export interface SpecProblem {
12
+ path: string;
13
+ message: string;
14
+ }
15
+ /** A scope set's name: `identity`, or `<area>.<access>` (`repo.read`), lowercase. */
16
+ export declare const SCOPE_SET_NAME: RegExp;
17
+ /** Segments no set unlocks on any host: batch tunnels carry whole requests inside. */
18
+ export declare const DEFAULT_DENIED_SEGMENTS: readonly string[];
19
+ /** The fields of `auth` when its kind is `oauth2-user`. */
20
+ export declare const OAUTH_AUTH_FIELDS: readonly ["kind", "authorizeUrl", "tokenUrl", "revokeUrl", "revokeMethod", "clientId", "clientSecret", "inject", "pkce", "scopeDialect", "authorizeParams", "tokenHeaders", "identity"];
21
+ /** The common fields `parseProviderSpec` parsed before handing over. */
22
+ export interface OAuthSpecCommon {
23
+ id: string;
24
+ name: string;
25
+ docs: string;
26
+ hosts: readonly string[];
27
+ description?: string;
28
+ reference?: string;
29
+ access?: readonly CapabilityAccess[];
30
+ readMethods?: readonly string[];
31
+ writeMethods?: readonly string[];
32
+ hint?: string;
33
+ example?: string;
34
+ tags?: readonly string[];
35
+ }
36
+ /**
37
+ * One scope set (`{ label, access, scopes, userScopes?, routes? }`) at
38
+ * `at`, its routes on `hosts` alone; undefined when a field is wrong,
39
+ * every problem reported. `overlay`: a set added to a built-in client
40
+ * must name a scope and say what it unlocks (a set with no routes unlocks
41
+ * nothing on the held-token path); a spec's own set may leave both empty
42
+ * (Notion's sets carry no scope string).
43
+ */
44
+ export declare function parseScopeSet(raw: unknown, at: string, hosts: readonly string[], problems: SpecProblem[], { overlay }?: {
45
+ overlay?: boolean;
46
+ }): OAuthScopeSet | undefined;
47
+ /** What `parseScopeSetOverlay` returns. */
48
+ export type ParsedScopeSetOverlay = {
49
+ ok: true;
50
+ name: string;
51
+ set: OAuthScopeSet;
52
+ } | {
53
+ ok: false;
54
+ problems: SpecProblem[];
55
+ };
56
+ /**
57
+ * A scope set an operator adds to a built-in OAuth client
58
+ * (`everyapp provider scope-set add google-workspace gmail-send.json`):
59
+ * `{ "name": "gmail.send", "label", "access", "scopes", "routes" }`, held
60
+ * to the rules a built-in set is (the set's shape, routes on the client's
61
+ * `api` hosts alone, anchored `posts`) plus two of its own: `access` is
62
+ * said outright (a write set is never implied by its scopes) and `routes`
63
+ * is required. A `provider` field, when present, must be `id`. The name
64
+ * may not be one of the client's own sets: an overlay adds, never
65
+ * replaces. Nothing here reads a value.
66
+ */
67
+ export declare function parseScopeSetOverlay(input: unknown, client: {
68
+ id: string;
69
+ capability: OAuthClientCapability;
70
+ }): ParsedScopeSetOverlay;
71
+ /**
72
+ * `capability` with `sets` added to its scope policy: the sets after the
73
+ * client's own, in the order given, and each set's scopes added to the
74
+ * authorize URL's list (what the operator's client must be allowed), as
75
+ * `parseOAuthUserSpec` builds it. A name the client already has is left
76
+ * as the client's (the registry refuses such an overlay before this).
77
+ */
78
+ export declare function withScopeSets(capability: OAuthClientCapability, sets: Readonly<Record<string, OAuthScopeSet>>): OAuthClientCapability;
79
+ /** What `parseOAuthUserSpec` returns on success, before the registry's rules. */
80
+ export interface ParsedOAuthSpec {
81
+ capability: OAuthClientCapability;
82
+ /** Every host a row's rules must accept: the API hosts and the endpoints'. */
83
+ hosts: string[];
84
+ }
85
+ /**
86
+ * Parse the OAuth half of a spec whose `auth.kind` is `oauth2-user`:
87
+ * `auth` itself, `scopeSets`, `alwaysRequested` and `tolerated`, with
88
+ * the common fields already parsed. Every problem is reported; on
89
+ * success the catalog-shaped capability with its `flow`.
90
+ */
91
+ export declare function parseOAuthUserSpec(input: Record<string, unknown>, common: OAuthSpecCommon, problems: SpecProblem[]): ParsedOAuthSpec | undefined;
92
+ /**
93
+ * The JSON spec of an OAuth capability that has a `flow` (`provider
94
+ * show`, a preset's round trip): `parseProviderSpec` of it gives the
95
+ * capability back. A catalog client without a `flow` has no spec.
96
+ */
97
+ export declare function oauthSpecOf(id: string, capability: OAuthClientCapability): Record<string, unknown> | null;
98
+ /** The methods a held-token write may use on `capability` beyond its reads. */
99
+ export declare function oauthWriteMethods(capability: OAuthClientCapability): readonly string[];
100
+ /** The methods a read grant may use on `capability` (GET and HEAD unless the spec says). */
101
+ export declare function oauthReadMethods(capability: OAuthClientCapability): readonly string[];
102
+ //# sourceMappingURL=oauthSpec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oauthSpec.d.ts","sourceRoot":"","sources":["../../src/internal/oauthSpec.ts"],"names":[],"mappings":"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"}