@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
@@ -39,6 +39,17 @@ export declare const GATEWAY_ERROR_HEADER = "x-everyapp-error";
39
39
  * from what browsers send.
40
40
  */
41
41
  export declare const ORG_HEADER = "x-everyapp-org";
42
+ /**
43
+ * Which connection an app's call to an OAuth provider uses: the person's
44
+ * (`user`, the default when a person is behind the call) or the
45
+ * organization's (`organization`, the default for background work),
46
+ * docs/design/2026-10-oauth-providers.md section 7. Set by
47
+ * `integrationFetch({ account })`; the gateway reads it on the held-token
48
+ * branch and ignores it elsewhere.
49
+ */
50
+ export declare const ACCOUNT_HEADER = "x-everyapp-account";
51
+ /** The values {@link ACCOUNT_HEADER} may carry. */
52
+ export type ConnectionAccount = "user" | "organization";
42
53
  /** 120-second lifetime — caps revocation staleness while surviving clock skew. */
43
54
  export declare const IDENTITY_TTL_SECONDS = 120;
44
55
  /** System tokens are minted per call and live at most a minute. */
@@ -63,10 +74,36 @@ export declare const ISSUER_ENV = "EVERYAPP_IDENTITY_ISSUER";
63
74
  export declare const SHARED_ENV = "EVERYAPP_SHARED";
64
75
  /** When set to `1` or `true` in the worker env, the dev identity kid is accepted. */
65
76
  export declare const DEV_ENV = "EVERYAPP_DEV";
77
+ /**
78
+ * The organization an app's Worker is pinned to (a secret the deploy sends;
79
+ * in development the stub gateway's organization). `everyApp()` refuses an
80
+ * identity for any other organization; absent on a shared app's Workers.
81
+ */
82
+ export declare const ORG_ID_ENV = "EVERY_APP_ORG_ID";
83
+ /**
84
+ * The organization the dev gateway's seeded user belongs to. The same value
85
+ * as `@every-app/sdk/dev`'s, kept apart like {@link DEV_ISSUER} (the same
86
+ * test pins the two together).
87
+ */
88
+ export declare const DEV_ORG_ID = "dev-org";
66
89
  /** `sub` claim the gateway mints public-route markers with. */
67
90
  export declare const PUBLIC_MARKER_SUB = "public";
68
91
  /** `sub` claim of gateway system tokens. */
69
92
  export declare const SYSTEM_TOKEN_SUB = "system";
93
+ /**
94
+ * Linked dev (`everyapp dev --gateway`, docs/design/linked-dev.md): the
95
+ * dev Worker's env names the gateway-lite's loopback forwarder and the
96
+ * run's nonce, and the SDK builds a `{ fetch }` in place of the missing
97
+ * `EVERY_APP_GATEWAY` binding from them. Set by `everyAppWorker()` in a
98
+ * development build from the process environment `everyapp dev` starts
99
+ * the app with; never deployed.
100
+ */
101
+ export declare const LINKED_DEV_URL_ENV = "EVERYAPP_LINKED_DEV_URL";
102
+ export declare const LINKED_DEV_NONCE_ENV = "EVERYAPP_LINKED_DEV_NONCE";
103
+ /** The header the forwarder requires, with the run's nonce: no simple cross-origin request can send it. */
104
+ export declare const LINKED_DEV_HEADER = "x-everyapp-linked-dev";
105
+ /** Where the gateway-lite serves the forwarder, under the app's own host. */
106
+ export declare const LINKED_DEV_FORWARD_PATH = "/__everyapp/gateway";
70
107
  export type IdentityChannel = "web" | "api" | "mcp" | "agent";
71
108
  export type IdentityTokenType = "user" | "public" | "system";
72
109
  /** What a system token may open. One purpose per token. */
@@ -80,13 +117,37 @@ export interface IdentitySubject {
80
117
  email: string;
81
118
  orgId: string;
82
119
  orgRole: string;
120
+ /**
121
+ * The organization's name as its owners set it (`org_name`), so an app
122
+ * can show "Acme" rather than an id. Left out when the minter has none.
123
+ */
124
+ orgName?: string;
83
125
  }
126
+ /**
127
+ * A member's role in the organization, as the identity token carries it.
128
+ * Owners and admins manage; anything the Gateway might mint that an app
129
+ * doesn't know is read as `member`.
130
+ */
131
+ export type OrgRole = "owner" | "admin" | "member";
132
+ /** `role` as an {@link OrgRole}: `owner` and `admin` as they are, anything else `member`. */
133
+ export declare function toOrgRole(role: unknown): OrgRole;
134
+ /** Whether `user` manages the organization: an owner or an admin. */
135
+ export declare function isAdmin(user: {
136
+ orgRole: OrgRole | string;
137
+ }): boolean;
84
138
  export interface EveryAppUser {
85
139
  /** User id (the `sub` claim). */
86
140
  id: string;
87
141
  email: string;
88
142
  orgId: string;
89
- orgRole: string;
143
+ orgRole: OrgRole;
144
+ /**
145
+ * The organization's display name (the `org_name` claim), as its owners
146
+ * set it: trimmed, at most 64 characters, no control characters. Show
147
+ * it; never key data by it (names change, `orgId` doesn't). Undefined
148
+ * when the token carries none.
149
+ */
150
+ orgName?: string;
90
151
  channel: IdentityChannel;
91
152
  /** The acting principal (user, or `mcp:<client>` / agent). */
92
153
  actor: IdentityActor;
@@ -103,6 +164,8 @@ export interface IdentityClaims extends JWTPayload {
103
164
  email: string;
104
165
  org_id: string;
105
166
  org_role: string;
167
+ /** The organization's display name; absent when the minter had none. */
168
+ org_name?: string;
106
169
  chan: IdentityChannel;
107
170
  act: IdentityActor;
108
171
  scopes: string[];
@@ -1 +1 @@
1
- {"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../../src/internal/protocol.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../../src/internal/protocol.ts"],"names":[],"mappings":"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"}
@@ -38,6 +38,15 @@ export const GATEWAY_ERROR_HEADER = "x-everyapp-error";
38
38
  * from what browsers send.
39
39
  */
40
40
  export const ORG_HEADER = "x-everyapp-org";
41
+ /**
42
+ * Which connection an app's call to an OAuth provider uses: the person's
43
+ * (`user`, the default when a person is behind the call) or the
44
+ * organization's (`organization`, the default for background work),
45
+ * docs/design/2026-10-oauth-providers.md section 7. Set by
46
+ * `integrationFetch({ account })`; the gateway reads it on the held-token
47
+ * branch and ignores it elsewhere.
48
+ */
49
+ export const ACCOUNT_HEADER = "x-everyapp-account";
41
50
  /** 120-second lifetime — caps revocation staleness while surviving clock skew. */
42
51
  export const IDENTITY_TTL_SECONDS = 120;
43
52
  /** System tokens are minted per call and live at most a minute. */
@@ -62,10 +71,44 @@ export const ISSUER_ENV = "EVERYAPP_IDENTITY_ISSUER";
62
71
  export const SHARED_ENV = "EVERYAPP_SHARED";
63
72
  /** When set to `1` or `true` in the worker env, the dev identity kid is accepted. */
64
73
  export const DEV_ENV = "EVERYAPP_DEV";
74
+ /**
75
+ * The organization an app's Worker is pinned to (a secret the deploy sends;
76
+ * in development the stub gateway's organization). `everyApp()` refuses an
77
+ * identity for any other organization; absent on a shared app's Workers.
78
+ */
79
+ export const ORG_ID_ENV = "EVERY_APP_ORG_ID";
80
+ /**
81
+ * The organization the dev gateway's seeded user belongs to. The same value
82
+ * as `@every-app/sdk/dev`'s, kept apart like {@link DEV_ISSUER} (the same
83
+ * test pins the two together).
84
+ */
85
+ export const DEV_ORG_ID = "dev-org";
65
86
  /** `sub` claim the gateway mints public-route markers with. */
66
87
  export const PUBLIC_MARKER_SUB = "public";
67
88
  /** `sub` claim of gateway system tokens. */
68
89
  export const SYSTEM_TOKEN_SUB = "system";
90
+ /**
91
+ * Linked dev (`everyapp dev --gateway`, docs/design/linked-dev.md): the
92
+ * dev Worker's env names the gateway-lite's loopback forwarder and the
93
+ * run's nonce, and the SDK builds a `{ fetch }` in place of the missing
94
+ * `EVERY_APP_GATEWAY` binding from them. Set by `everyAppWorker()` in a
95
+ * development build from the process environment `everyapp dev` starts
96
+ * the app with; never deployed.
97
+ */
98
+ export const LINKED_DEV_URL_ENV = "EVERYAPP_LINKED_DEV_URL";
99
+ export const LINKED_DEV_NONCE_ENV = "EVERYAPP_LINKED_DEV_NONCE";
100
+ /** The header the forwarder requires, with the run's nonce: no simple cross-origin request can send it. */
101
+ export const LINKED_DEV_HEADER = "x-everyapp-linked-dev";
102
+ /** Where the gateway-lite serves the forwarder, under the app's own host. */
103
+ export const LINKED_DEV_FORWARD_PATH = "/__everyapp/gateway";
104
+ /** `role` as an {@link OrgRole}: `owner` and `admin` as they are, anything else `member`. */
105
+ export function toOrgRole(role) {
106
+ return role === "owner" || role === "admin" ? role : "member";
107
+ }
108
+ /** Whether `user` manages the organization: an owner or an admin. */
109
+ export function isAdmin(user) {
110
+ return user.orgRole === "owner" || user.orgRole === "admin";
111
+ }
69
112
  export class ProtocolClaimsError extends Error {
70
113
  constructor(message) {
71
114
  super(message);
@@ -78,6 +121,7 @@ export function identitySubjectToClaims(subject, opts) {
78
121
  email: subject.email,
79
122
  org_id: subject.orgId,
80
123
  org_role: subject.orgRole,
124
+ ...(subject.orgName ? { org_name: subject.orgName } : {}),
81
125
  chan: opts.channel ?? "web",
82
126
  act: opts.actor ?? { sub: subject.sub },
83
127
  scopes: opts.scopes ?? ["*"],
@@ -112,6 +156,11 @@ export function identityClaimsToEveryAppUser(payload) {
112
156
  if (!sub || !email || !orgId || !orgRole) {
113
157
  throw new ProtocolClaimsError("identity token missing required claims");
114
158
  }
159
+ // Display only, so a token without it (or with a malformed one) is still
160
+ // an identity: the app falls back to no name.
161
+ const orgName = typeof payload.org_name === "string" && payload.org_name
162
+ ? payload.org_name
163
+ : undefined;
115
164
  const chan = payload.chan ?? "web";
116
165
  const act = payload.act ?? { sub };
117
166
  const scopes = Array.isArray(payload.scopes)
@@ -122,7 +171,8 @@ export function identityClaimsToEveryAppUser(payload) {
122
171
  id: sub,
123
172
  email,
124
173
  orgId,
125
- orgRole,
174
+ orgRole: toOrgRole(orgRole),
175
+ ...(orgName ? { orgName } : {}),
126
176
  channel: chan,
127
177
  actor: { sub: act.sub ?? sub },
128
178
  scopes,
@@ -19,8 +19,20 @@
19
19
  * an IP literal, localhost, or a `.local`, `.internal` or `.arpa` name)
20
20
  * and not one the gateway serves itself (`refuseHost`, which knows the
21
21
  * gateway's own host and `APP_BASE_DOMAIN`).
22
+ *
23
+ * A second kind of row, a scope-set overlay (`provider_scope_sets`,
24
+ * `everyapp provider scope-set add`), adds a named scope set to a
25
+ * built-in OAuth client that has scope sets (Google, Microsoft, Slack):
26
+ * its scopes, and the routes on the client's own API hosts it unlocks,
27
+ * checked by the rules a built-in set is checked by
28
+ * (`providers.scope-set-overlay-within-client`). An overlay never replaces
29
+ * one of the client's own sets, never names a host outside the client's
30
+ * `api`, and never applies to a registered row (an operator replaces the
31
+ * row's spec instead). Apps list an overlay set under `scopes` as they
32
+ * list a built-in one.
22
33
  */
23
- import { type ApiKeyCapability, type Capability, type CapabilityLookup } from "./capabilities.js";
34
+ import { type Capability, type CapabilityLookup, type OAuthClientCapability, type OAuthScopeSet } from "./capabilities.js";
35
+ import { type RegistrableCapability } from "./providerSpec.js";
24
36
  /** A `providers` row as the gateway or the CLI read it. */
25
37
  export interface ProviderRow {
26
38
  id: string;
@@ -38,17 +50,48 @@ export interface ProviderRow {
38
50
  /** When, in epoch milliseconds. */
39
51
  addedAt?: number | null;
40
52
  }
53
+ /** A `provider_scope_sets` row as the gateway or the CLI read it. */
54
+ export interface ScopeSetRow {
55
+ /** The built-in OAuth client the set belongs to (`google-workspace`). */
56
+ providerId: string;
57
+ /** The set's name, what an app lists under `scopes` (`gmail.send`). */
58
+ name: string;
59
+ /** The set's spec, as JSON text or already parsed (`parseScopeSetOverlay`'s shape). */
60
+ spec: unknown;
61
+ addedBy?: string | null;
62
+ addedAt?: number | null;
63
+ }
64
+ /** One overlay the registry serves, as `provider show` reports it. */
65
+ export interface RegisteredScopeSet {
66
+ providerId: string;
67
+ name: string;
68
+ set: OAuthScopeSet;
69
+ addedBy: string | null;
70
+ addedAt: number | null;
71
+ }
72
+ export type ScopeSetRefusalCode = "SCOPE_SET_INVALID" | "SCOPE_SET_PROVIDER_UNKNOWN" | "SCOPE_SET_BUILTIN";
73
+ /** Why an overlay row is not a scope set on this gateway. */
74
+ export interface ScopeSetRefusal {
75
+ providerId: string;
76
+ name: string;
77
+ code: ScopeSetRefusalCode;
78
+ message: string;
79
+ }
41
80
  /**
42
81
  * The part of a row a key is set for: its hosts, its host setting and its
43
82
  * auth, as one canonical string (sorted keys, sorted hosts), so that
44
83
  * 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.
84
+ * is no longer read until the operator sets it again. For an OAuth
85
+ * provider the client is bound to its authorize, token and revoke URLs,
86
+ * its API hosts, where the client goes on the token request and its
87
+ * client setting names (`oauth.client-bound-to-endpoints`): an admin who
88
+ * re-points `tokenUrl` has to paste the secret again.
46
89
  */
47
- export declare function providerBindingKey(capability: ApiKeyCapability): string;
90
+ export declare function providerBindingKey(capability: RegistrableCapability): string;
48
91
  /** One registered row as `provider list` and `provider show` report it. */
49
92
  export interface RegisteredProvider {
50
93
  id: string;
51
- capability: ApiKeyCapability;
94
+ capability: RegistrableCapability;
52
95
  /** Whether the row's key was set for the hosts and auth it has now. */
53
96
  bound: boolean;
54
97
  addedBy: string | null;
@@ -80,6 +123,12 @@ export interface ProviderRegistry extends CapabilityLookup {
80
123
  rows(): readonly RegisteredProvider[];
81
124
  /** The rows this registry left out, each with why. */
82
125
  readonly rejected: readonly RowRefusal[];
126
+ /** The scope-set overlays this registry applied to built-in clients, in row order. */
127
+ scopeSets(): readonly RegisteredScopeSet[];
128
+ /** Where a client's scope set comes from: its catalog entry, an overlay row, or nowhere. */
129
+ scopeSetSource(providerId: string, name: string): "catalog" | "row" | undefined;
130
+ /** The overlay rows this registry left out, each with why. */
131
+ readonly rejectedScopeSets: readonly ScopeSetRefusal[];
83
132
  }
84
133
  export interface ProviderRegistryOptions {
85
134
  /**
@@ -88,6 +137,8 @@ export interface ProviderRegistryOptions {
88
137
  * the rest (IP literals, localhost, `.internal`).
89
138
  */
90
139
  refuseHost?: (host: string) => string | null;
140
+ /** The scope-set overlays (`provider_scope_sets`), applied to the catalog's OAuth clients. */
141
+ scopeSets?: readonly ScopeSetRow[];
91
142
  }
92
143
  /** The prefix a provider's own Gateway settings carry: `stripe` → `STRIPE_`, `tiktok-business` → `TIKTOK_BUSINESS_`. */
93
144
  export declare function providerSettingPrefix(id: string): string;
@@ -121,22 +172,42 @@ export declare function rowSecretProblem(id: string, name: string, taken: (name:
121
172
  * CLI runs it before writing D1, the MCP tool before writing, and the
122
173
  * gateway again on every read.
123
174
  */
124
- export declare function checkProviderRow(id: string, capability: ApiKeyCapability, context: {
175
+ export declare function checkProviderRow(id: string, capability: RegistrableCapability, context: {
125
176
  /** Settings the other rows hold. */
126
177
  rowSettings: ReadonlySet<string>;
127
178
  refuseHost?: (host: string) => string | null;
128
179
  }): RowRefusal | null;
180
+ /**
181
+ * Every host a row sends a secret to: an API-key provider's `hosts`; an
182
+ * OAuth provider's API hosts (the token), and its authorize, token and
183
+ * revoke hosts (the client). Each passes the row host rules.
184
+ */
185
+ export declare function registrableHosts(capability: RegistrableCapability): string[];
129
186
  /** A row's spec parsed and checked: the capability, or the refusal. */
130
187
  export declare function resolveProviderRow(row: ProviderRow, context: {
131
188
  rowSettings: ReadonlySet<string>;
132
189
  refuseHost?: (host: string) => string | null;
133
190
  }): {
134
191
  ok: true;
135
- capability: ApiKeyCapability;
192
+ capability: RegistrableCapability;
136
193
  } | {
137
194
  ok: false;
138
195
  refusal: RowRefusal;
139
196
  };
197
+ /**
198
+ * The built-in OAuth client an overlay may extend: a catalog entry of mode
199
+ * `oauth_client` with a scope policy. Null for anything else (an API-key
200
+ * entry, a client without sets, a registered row, an unknown id).
201
+ */
202
+ export declare function overlayableClient(providerId: string): OAuthClientCapability | null;
203
+ /** An overlay row's spec parsed and checked against its client: the set, or the refusal. */
204
+ export declare function resolveScopeSetRow(row: ScopeSetRow): {
205
+ ok: true;
206
+ set: OAuthScopeSet;
207
+ } | {
208
+ ok: false;
209
+ refusal: ScopeSetRefusal;
210
+ };
140
211
  /**
141
212
  * The catalog and `rows` as one registry. Rows are taken in order; a row
142
213
  * whose settings another earlier row holds is the one refused.
@@ -1 +1 @@
1
- {"version":3,"file":"providerRegistry.d.ts","sourceRoot":"","sources":["../../src/internal/providerRegistry.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"providerRegistry.d.ts","sourceRoot":"","sources":["../../src/internal/providerRegistry.ts"],"names":[],"mappings":"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"}
@@ -19,18 +19,64 @@
19
19
  * an IP literal, localhost, or a `.local`, `.internal` or `.arpa` name)
20
20
  * and not one the gateway serves itself (`refuseHost`, which knows the
21
21
  * gateway's own host and `APP_BASE_DOMAIN`).
22
+ *
23
+ * A second kind of row, a scope-set overlay (`provider_scope_sets`,
24
+ * `everyapp provider scope-set add`), adds a named scope set to a
25
+ * built-in OAuth client that has scope sets (Google, Microsoft, Slack):
26
+ * its scopes, and the routes on the client's own API hosts it unlocks,
27
+ * checked by the rules a built-in set is checked by
28
+ * (`providers.scope-set-overlay-within-client`). An overlay never replaces
29
+ * one of the client's own sets, never names a host outside the client's
30
+ * `api`, and never applies to a registered row (an operator replaces the
31
+ * row's spec instead). Apps list an overlay set under `scopes` as they
32
+ * list a built-in one.
22
33
  */
23
34
  import { CAPABILITIES, CAPABILITY_IDS, capabilitySettings, } from "./capabilities.js";
24
35
  import { isDevOnlyGatewaySetting, isInstallOwnedGatewaySetting, isReservedAppSecretName, isSettableGatewaySetting, } from "./gatewaySettings.js";
36
+ import { parseScopeSetOverlay, withScopeSets } from "./oauthSpec.js";
37
+ import { isSignInSettingName } from "./signInProviders.js";
25
38
  import { describeSpecProblems, parseProviderSpec, PROVIDER_ID, } from "./providerSpec.js";
26
39
  /**
27
40
  * The part of a row a key is set for: its hosts, its host setting and its
28
41
  * auth, as one canonical string (sorted keys, sorted hosts), so that
29
42
  * replacing a row's hosts or auth changes the key and the value it held
30
- * is no longer read until the operator sets it again.
43
+ * is no longer read until the operator sets it again. For an OAuth
44
+ * provider the client is bound to its authorize, token and revoke URLs,
45
+ * its API hosts, where the client goes on the token request and its
46
+ * client setting names (`oauth.client-bound-to-endpoints`): an admin who
47
+ * re-points `tokenUrl` has to paste the secret again.
31
48
  */
32
49
  export function providerBindingKey(capability) {
33
- const auth = Object.fromEntries(Object.entries(capability.auth)
50
+ if (capability.mode === "ai") {
51
+ // An `ai` row's key is bound to where the proxy sends it: its base URL and the key's placement.
52
+ return JSON.stringify({
53
+ kind: "ai",
54
+ auth: sortedAuth(capability.auth),
55
+ origin: capability.origin,
56
+ basePath: capability.basePath ?? null,
57
+ });
58
+ }
59
+ if (capability.mode === "oauth_client") {
60
+ return JSON.stringify({
61
+ kind: "oauth2-user",
62
+ authorizeUrl: capability.authorize.url,
63
+ tokenUrl: capability.flow?.tokenUrl ?? null,
64
+ revokeUrl: capability.flow?.revokeUrl ?? null,
65
+ inject: capability.token[0]?.inject ?? "form",
66
+ clientId: capability.secrets.clientId,
67
+ clientSecret: capability.secrets.clientSecret ?? null,
68
+ hosts: [...capability.api].sort(),
69
+ });
70
+ }
71
+ return JSON.stringify({
72
+ auth: sortedAuth(capability.auth),
73
+ hostSetting: capability.hostSetting ?? null,
74
+ hosts: [...capability.hosts].sort(),
75
+ });
76
+ }
77
+ /** An auth block with its keys sorted, one level down too, for a canonical key. */
78
+ function sortedAuth(auth) {
79
+ return Object.fromEntries(Object.entries(auth)
34
80
  .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))
35
81
  .map(([field, value]) => [
36
82
  field,
@@ -38,11 +84,6 @@ export function providerBindingKey(capability) {
38
84
  ? Object.fromEntries(Object.entries(value).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0))
39
85
  : value,
40
86
  ]));
41
- return JSON.stringify({
42
- auth,
43
- hostSetting: capability.hostSetting ?? null,
44
- hosts: [...capability.hosts].sort(),
45
- });
46
87
  }
47
88
  /** The reserved app id no provider may take. */
48
89
  const RESERVED_IDS = new Set(["everyapp"]);
@@ -116,6 +157,9 @@ export function rowSecretProblem(id, name, taken) {
116
157
  if (isReservedAppSecretName(name)) {
117
158
  return `${name} is a name everyapp sets itself`;
118
159
  }
160
+ if (isSignInSettingName(name)) {
161
+ return `${name} is a sign-in provider's setting name (every <ID>_SIGNIN_<FIELD> name is the Gateway's, set with \`everyapp signin add\`)`;
162
+ }
119
163
  if (isSettableGatewaySetting(name)) {
120
164
  return `${name} is a Gateway setting another provider or the Gateway reads`;
121
165
  }
@@ -143,7 +187,7 @@ export function checkProviderRow(id, capability, context) {
143
187
  return { id, code: "PROVIDER_SECRET_TAKEN", message: problem };
144
188
  }
145
189
  }
146
- for (const host of capability.hosts) {
190
+ for (const host of registrableHosts(capability)) {
147
191
  const problem = publicHostProblem(host) ?? context.refuseHost?.(host);
148
192
  if (problem) {
149
193
  return { id, code: "PROVIDER_HOST_REFUSED", message: problem };
@@ -151,6 +195,37 @@ export function checkProviderRow(id, capability, context) {
151
195
  }
152
196
  return null;
153
197
  }
198
+ /**
199
+ * Every host a row sends a secret to: an API-key provider's `hosts`; an
200
+ * OAuth provider's API hosts (the token), and its authorize, token and
201
+ * revoke hosts (the client). Each passes the row host rules.
202
+ */
203
+ export function registrableHosts(capability) {
204
+ if (capability.mode === "api_key")
205
+ return [...capability.hosts];
206
+ if (capability.mode === "ai")
207
+ return [new URL(capability.origin).hostname.toLowerCase()];
208
+ const hosts = [...capability.api];
209
+ const urls = [
210
+ capability.authorize.url,
211
+ capability.flow?.tokenUrl,
212
+ capability.flow?.revokeUrl,
213
+ capability.flow?.identity?.url,
214
+ ];
215
+ for (const url of urls) {
216
+ if (!url)
217
+ continue;
218
+ try {
219
+ const host = new URL(url).hostname.toLowerCase();
220
+ if (!hosts.includes(host))
221
+ hosts.push(host);
222
+ }
223
+ catch {
224
+ // The parser refused it already.
225
+ }
226
+ }
227
+ return hosts;
228
+ }
154
229
  /** A row's spec parsed and checked: the capability, or the refusal. */
155
230
  export function resolveProviderRow(row, context) {
156
231
  let spec = row.spec;
@@ -195,12 +270,92 @@ export function resolveProviderRow(row, context) {
195
270
  ? { ok: false, refusal }
196
271
  : { ok: true, capability: parsed.capability };
197
272
  }
273
+ /**
274
+ * The built-in OAuth client an overlay may extend: a catalog entry of mode
275
+ * `oauth_client` with a scope policy. Null for anything else (an API-key
276
+ * entry, a client without sets, a registered row, an unknown id).
277
+ */
278
+ export function overlayableClient(providerId) {
279
+ if (!CAPABILITY_IDS.includes(providerId))
280
+ return null;
281
+ const capability = CAPABILITIES[providerId];
282
+ return capability.mode === "oauth_client" && capability.scopePolicy
283
+ ? capability
284
+ : null;
285
+ }
286
+ /** An overlay row's spec parsed and checked against its client: the set, or the refusal. */
287
+ export function resolveScopeSetRow(row) {
288
+ const refuse = (code, message) => ({
289
+ ok: false,
290
+ refusal: { providerId: row.providerId, name: row.name, code, message },
291
+ });
292
+ const client = overlayableClient(row.providerId);
293
+ if (!client) {
294
+ return refuse("SCOPE_SET_PROVIDER_UNKNOWN", `${row.providerId} isn't a built-in OAuth client with scope sets (google-workspace, microsoft-365, slack); a registered provider's sets are in its spec`);
295
+ }
296
+ if (Object.hasOwn(client.scopePolicy.sets, row.name)) {
297
+ return refuse("SCOPE_SET_BUILTIN", `${row.name} is one of ${row.providerId}'s own sets; an overlay adds a set, never replaces one`);
298
+ }
299
+ let spec = row.spec;
300
+ if (typeof spec === "string") {
301
+ try {
302
+ spec = JSON.parse(spec);
303
+ }
304
+ catch {
305
+ return refuse("SCOPE_SET_INVALID", "the stored spec isn't JSON");
306
+ }
307
+ }
308
+ const parsed = parseScopeSetOverlay(typeof spec === "object" && spec !== null && !Array.isArray(spec)
309
+ ? { ...spec, name: row.name }
310
+ : spec, { id: row.providerId, capability: client });
311
+ if (!parsed.ok) {
312
+ return refuse("SCOPE_SET_INVALID", describeSpecProblems(parsed.problems));
313
+ }
314
+ return { ok: true, set: parsed.set };
315
+ }
198
316
  /**
199
317
  * The catalog and `rows` as one registry. Rows are taken in order; a row
200
318
  * whose settings another earlier row holds is the one refused.
201
319
  */
202
320
  export function providerRegistry(rows = [], options = {}) {
203
321
  const catalog = new Map(CAPABILITY_IDS.map((id) => [id, CAPABILITIES[id]]));
322
+ // Scope-set overlays on the catalog's OAuth clients, before any row is
323
+ // looked at: a row never shadows the catalog, with or without overlays.
324
+ const overlays = [];
325
+ const rejectedScopeSets = [];
326
+ const overlaySets = new Map();
327
+ for (const row of options.scopeSets ?? []) {
328
+ if (overlays.some((each) => each.providerId === row.providerId && each.name === row.name)) {
329
+ rejectedScopeSets.push({
330
+ providerId: row.providerId,
331
+ name: row.name,
332
+ code: "SCOPE_SET_INVALID",
333
+ message: "listed twice",
334
+ });
335
+ continue;
336
+ }
337
+ const resolved = resolveScopeSetRow(row);
338
+ if (!resolved.ok) {
339
+ rejectedScopeSets.push(resolved.refusal);
340
+ continue;
341
+ }
342
+ overlays.push({
343
+ providerId: row.providerId,
344
+ name: row.name,
345
+ set: resolved.set,
346
+ addedBy: row.addedBy ?? null,
347
+ addedAt: row.addedAt ?? null,
348
+ });
349
+ const sets = overlaySets.get(row.providerId) ?? {};
350
+ sets[row.name] = resolved.set;
351
+ overlaySets.set(row.providerId, sets);
352
+ }
353
+ for (const [id, sets] of overlaySets) {
354
+ const client = catalog.get(id);
355
+ if (client?.mode === "oauth_client") {
356
+ catalog.set(id, withScopeSets(client, sets));
357
+ }
358
+ }
204
359
  const accepted = new Map();
205
360
  const rejected = [];
206
361
  const rowSettings = new Set();
@@ -256,6 +411,21 @@ export function providerRegistry(rows = [], options = {}) {
256
411
  },
257
412
  rows: () => [...accepted.values()],
258
413
  rejected,
414
+ scopeSets: () => [...overlays],
415
+ scopeSetSource: (providerId, name) => {
416
+ if (overlays.some((each) => each.providerId === providerId && each.name === name)) {
417
+ return "row";
418
+ }
419
+ const capability = CAPABILITY_IDS.includes(providerId)
420
+ ? CAPABILITIES[providerId]
421
+ : undefined;
422
+ return capability?.mode === "oauth_client" &&
423
+ capability.scopePolicy &&
424
+ Object.hasOwn(capability.scopePolicy.sets, name)
425
+ ? "catalog"
426
+ : undefined;
427
+ },
428
+ rejectedScopeSets,
259
429
  };
260
430
  }
261
431
  /** The catalog alone, as a registry: what every surface reads without a gateway's rows. */