@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.
- package/LICENSE +21 -0
- package/README.md +1 -1
- package/dist/cloudflare/catalogSettings.generated.d.ts +81 -0
- package/dist/cloudflare/catalogSettings.generated.d.ts.map +1 -0
- package/dist/cloudflare/catalogSettings.generated.js +174 -0
- package/dist/cloudflare/index.d.ts +3 -2
- package/dist/cloudflare/index.d.ts.map +1 -1
- package/dist/cloudflare/index.js +4 -1
- package/dist/cloudflare/sentinel.d.ts +60 -2
- package/dist/cloudflare/sentinel.d.ts.map +1 -1
- package/dist/cloudflare/sentinel.js +37 -2
- package/dist/cloudflare/worker.d.ts +357 -63
- package/dist/cloudflare/worker.d.ts.map +1 -1
- package/dist/cloudflare/worker.js +363 -104
- package/dist/dev/index.d.ts +1 -1
- package/dist/dev/index.d.ts.map +1 -1
- package/dist/dev/index.js +1 -1
- package/dist/dev/keypair.d.ts +2 -0
- package/dist/dev/keypair.d.ts.map +1 -1
- package/dist/dev/keypair.js +2 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/internal/aiDefault.d.ts +204 -0
- package/dist/internal/aiDefault.d.ts.map +1 -0
- package/dist/internal/aiDefault.js +334 -0
- package/dist/internal/aiProviders.d.ts +7 -2
- package/dist/internal/aiProviders.d.ts.map +1 -1
- package/dist/internal/aiProviders.js +17 -4
- package/dist/internal/appSettings.d.ts +82 -4
- package/dist/internal/appSettings.d.ts.map +1 -1
- package/dist/internal/appSettings.js +204 -29
- package/dist/internal/audit.d.ts +108 -0
- package/dist/internal/audit.d.ts.map +1 -0
- package/dist/internal/audit.js +235 -0
- package/dist/internal/capabilities.d.ts +2268 -438
- package/dist/internal/capabilities.d.ts.map +1 -1
- package/dist/internal/capabilities.js +128 -539
- package/dist/internal/catalog/commerce.d.ts +394 -0
- package/dist/internal/catalog/commerce.d.ts.map +1 -0
- package/dist/internal/catalog/commerce.js +477 -0
- package/dist/internal/catalog/comms.d.ts +375 -0
- package/dist/internal/catalog/comms.d.ts.map +1 -0
- package/dist/internal/catalog/comms.js +520 -0
- package/dist/internal/catalog/index.d.ts +1973 -0
- package/dist/internal/catalog/index.d.ts.map +1 -0
- package/dist/internal/catalog/index.js +19 -0
- package/dist/internal/catalog/inference.d.ts +393 -0
- package/dist/internal/catalog/inference.d.ts.map +1 -0
- package/dist/internal/catalog/inference.js +460 -0
- package/dist/internal/catalog/infra.d.ts +423 -0
- package/dist/internal/catalog/infra.d.ts.map +1 -0
- package/dist/internal/catalog/infra.js +543 -0
- package/dist/internal/catalog/search.d.ts +400 -0
- package/dist/internal/catalog/search.d.ts.map +1 -0
- package/dist/internal/catalog/search.js +463 -0
- package/dist/internal/devProviders.d.ts +2 -2
- package/dist/internal/devProviders.d.ts.map +1 -1
- package/dist/internal/devProviders.js +19 -1
- package/dist/internal/events.d.ts +13 -2
- package/dist/internal/events.d.ts.map +1 -1
- package/dist/internal/events.js +47 -4
- package/dist/internal/gatewaySettings.d.ts +3 -2
- package/dist/internal/gatewaySettings.d.ts.map +1 -1
- package/dist/internal/gatewaySettings.js +12 -6
- package/dist/internal/identity.d.ts +41 -4
- package/dist/internal/identity.d.ts.map +1 -1
- package/dist/internal/identity.js +48 -10
- package/dist/internal/index.d.ts +6 -1
- package/dist/internal/index.d.ts.map +1 -1
- package/dist/internal/index.js +6 -1
- package/dist/internal/members.d.ts +3 -2
- package/dist/internal/members.d.ts.map +1 -1
- package/dist/internal/oauthClient.d.ts +10 -12
- package/dist/internal/oauthClient.d.ts.map +1 -1
- package/dist/internal/oauthClient.js +20 -81
- package/dist/internal/oauthPresets.d.ts +33 -0
- package/dist/internal/oauthPresets.d.ts.map +1 -0
- package/dist/internal/oauthPresets.js +1064 -0
- package/dist/internal/oauthScopes.d.ts +56 -1
- package/dist/internal/oauthScopes.d.ts.map +1 -1
- package/dist/internal/oauthScopes.js +98 -4
- package/dist/internal/oauthSpec.d.ts +102 -0
- package/dist/internal/oauthSpec.d.ts.map +1 -0
- package/dist/internal/oauthSpec.js +789 -0
- package/dist/internal/protocol.d.ts +64 -1
- package/dist/internal/protocol.d.ts.map +1 -1
- package/dist/internal/protocol.js +51 -1
- package/dist/internal/providerRegistry.d.ts +77 -6
- package/dist/internal/providerRegistry.d.ts.map +1 -1
- package/dist/internal/providerRegistry.js +178 -8
- package/dist/internal/providerSpec.d.ts +18 -7
- package/dist/internal/providerSpec.d.ts.map +1 -1
- package/dist/internal/providerSpec.js +442 -34
- package/dist/internal/signInProviders.d.ts +104 -0
- package/dist/internal/signInProviders.d.ts.map +1 -0
- package/dist/internal/signInProviders.js +245 -0
- package/dist/manifest.d.ts +238 -0
- package/dist/manifest.d.ts.map +1 -0
- package/dist/manifest.js +30 -0
- package/dist/server/ai.d.ts +111 -0
- package/dist/server/ai.d.ts.map +1 -0
- package/dist/server/ai.js +145 -0
- package/dist/server/aiBinding.d.ts +68 -0
- package/dist/server/aiBinding.d.ts.map +1 -0
- package/dist/server/aiBinding.js +294 -0
- package/dist/server/attribution.d.ts +9 -5
- package/dist/server/attribution.d.ts.map +1 -1
- package/dist/server/attribution.js +12 -4
- package/dist/server/authorizeUrl.d.ts +1 -1
- package/dist/server/authorizeUrl.d.ts.map +1 -1
- package/dist/server/authorizeUrl.js +2 -6
- package/dist/server/connectUrl.d.ts +21 -0
- package/dist/server/connectUrl.d.ts.map +1 -0
- package/dist/server/connectUrl.js +37 -0
- package/dist/server/context.d.ts +68 -0
- package/dist/server/context.d.ts.map +1 -0
- package/dist/server/context.js +117 -0
- package/dist/server/emailBinding.d.ts +72 -0
- package/dist/server/emailBinding.d.ts.map +1 -0
- package/dist/server/emailBinding.js +124 -0
- package/dist/server/emit.d.ts +1 -1
- package/dist/server/emit.d.ts.map +1 -1
- package/dist/server/emit.js +7 -7
- package/dist/server/env.d.ts +44 -0
- package/dist/server/env.d.ts.map +1 -0
- package/dist/server/env.js +1 -0
- package/dist/server/everyApp.d.ts +27 -7
- package/dist/server/everyApp.d.ts.map +1 -1
- package/dist/server/everyApp.js +106 -5
- package/dist/server/fromMcpTools.d.ts +89 -0
- package/dist/server/fromMcpTools.d.ts.map +1 -0
- package/dist/server/fromMcpTools.js +192 -0
- package/dist/server/gatewayFetch.d.ts +42 -18
- package/dist/server/gatewayFetch.d.ts.map +1 -1
- package/dist/server/gatewayFetch.js +138 -19
- package/dist/server/gatewayUrl.d.ts +13 -0
- package/dist/server/gatewayUrl.d.ts.map +1 -0
- package/dist/server/gatewayUrl.js +34 -0
- package/dist/server/index.d.ts +15 -4
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +12 -2
- package/dist/server/integrationFetch.d.ts +70 -39
- package/dist/server/integrationFetch.d.ts.map +1 -1
- package/dist/server/integrationFetch.js +244 -82
- package/dist/server/listMembers.d.ts +1 -1
- package/dist/server/listMembers.d.ts.map +1 -1
- package/dist/server/listMembers.js +8 -11
- package/dist/server/refusal.d.ts +55 -0
- package/dist/server/refusal.d.ts.map +1 -0
- package/dist/server/refusal.js +193 -0
- package/dist/server/sendEmail.d.ts +1 -1
- package/dist/server/sendEmail.d.ts.map +1 -1
- package/dist/server/sendEmail.js +7 -7
- package/dist/server/toolsEndpoint.d.ts.map +1 -1
- package/dist/server/toolsEndpoint.js +11 -5
- package/dist/tanstack-start/index.d.ts +9 -0
- package/dist/tanstack-start/index.d.ts.map +1 -0
- package/dist/tanstack-start/index.js +29 -0
- package/dist/testing/index.d.ts +93 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +156 -0
- 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:
|
|
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":"AAAA;;;;;;GAMG;AACH,OAAO,EAAwB,KAAK,UAAU,EAAE,MAAM,MAAM,CAAC;AAC7D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD,eAAO,MAAM,YAAY,UAAU,CAAC;AACpC,eAAO,MAAM,eAAe,sBAAsB,CAAC;AACnD,eAAO,MAAM,mBAAmB,0BAA0B,CAAC;AAC3D;;;;GAIG;AACH,eAAO,MAAM,UAAU,kCAAkC,CAAC;AAC1D,eAAO,MAAM,eAAe,wBAAwB,CAAC;AACrD,eAAO,MAAM,aAAa,sBAAsB,CAAC;AACjD;;;;GAIG;AACH,eAAO,MAAM,aAAa,sBAAsB,CAAC;AACjD;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,qBAAqB,CAAC;AACvD;;;;;;;GAOG;AACH,eAAO,MAAM,UAAU,mBAAmB,CAAC;AAC3C,kFAAkF;AAClF,eAAO,MAAM,oBAAoB,MAAM,CAAC;AACxC,mEAAmE;AACnE,eAAO,MAAM,wBAAwB,KAAK,CAAC;AAC3C,8CAA8C;AAC9C,eAAO,MAAM,UAAU,oBAAoB,CAAC;AAC5C;;;;;GAKG;AACH,eAAO,MAAM,YAAY,sBAAsB,CAAC;AAChD,qEAAqE;AACrE,eAAO,MAAM,eAAe,kCAAkC,CAAC;AAC/D,mFAAmF;AACnF,eAAO,MAAM,UAAU,6BAA6B,CAAC;AACrD;;;GAGG;AACH,eAAO,MAAM,UAAU,oBAAoB,CAAC;AAC5C,qFAAqF;AACrF,eAAO,MAAM,OAAO,iBAAiB,CAAC;AACtC,+DAA+D;AAC/D,eAAO,MAAM,iBAAiB,WAAW,CAAC;AAC1C,4CAA4C;AAC5C,eAAO,MAAM,gBAAgB,WAAW,CAAC;AAEzC,MAAM,MAAM,eAAe,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG,OAAO,CAAC;AAC9D,MAAM,MAAM,iBAAiB,GAAG,MAAM,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAC7D,2DAA2D;AAC3D,MAAM,MAAM,kBAAkB,GAAG,YAAY,CAAC;AAE9C,+EAA+E;AAC/E,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;
|
|
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
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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":"AAAA
|
|
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
|
-
|
|
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
|
|
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. */
|