@every-app/sdk 0.2.0 → 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 +609 -3
- 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 +23 -0
- package/dist/cloudflare/index.d.ts.map +1 -0
- package/dist/cloudflare/index.js +24 -0
- package/dist/cloudflare/sentinel.d.ts +127 -0
- package/dist/cloudflare/sentinel.d.ts.map +1 -0
- package/dist/cloudflare/sentinel.js +85 -0
- package/dist/cloudflare/worker.d.ts +805 -0
- package/dist/cloudflare/worker.d.ts.map +1 -0
- package/dist/cloudflare/worker.js +997 -0
- package/dist/dev/index.d.ts +8 -0
- package/dist/dev/index.d.ts.map +1 -0
- package/dist/dev/index.js +7 -0
- package/dist/dev/keypair.d.ts +26 -0
- package/dist/dev/keypair.d.ts.map +1 -0
- package/dist/dev/keypair.js +62 -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 +72 -0
- package/dist/internal/aiProviders.d.ts.map +1 -0
- package/dist/internal/aiProviders.js +233 -0
- package/dist/internal/appSettings.d.ts +315 -0
- package/dist/internal/appSettings.d.ts.map +1 -0
- package/dist/internal/appSettings.js +549 -0
- 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 +3174 -0
- package/dist/internal/capabilities.d.ts.map +1 -0
- package/dist/internal/capabilities.js +1110 -0
- 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 +49 -0
- package/dist/internal/devProviders.d.ts.map +1 -0
- package/dist/internal/devProviders.js +80 -0
- package/dist/internal/email.d.ts +280 -0
- package/dist/internal/email.d.ts.map +1 -0
- package/dist/internal/email.js +613 -0
- package/dist/internal/events.d.ts +193 -0
- package/dist/internal/events.d.ts.map +1 -0
- package/dist/internal/events.js +367 -0
- package/dist/internal/gatewaySettings.d.ts +83 -0
- package/dist/internal/gatewaySettings.d.ts.map +1 -0
- package/dist/internal/gatewaySettings.js +215 -0
- package/dist/internal/identity.d.ts +57 -5
- package/dist/internal/identity.d.ts.map +1 -1
- package/dist/internal/identity.js +99 -22
- package/dist/internal/index.d.ts +22 -1
- package/dist/internal/index.d.ts.map +1 -1
- package/dist/internal/index.js +22 -1
- package/dist/internal/members.d.ts +36 -0
- package/dist/internal/members.d.ts.map +1 -0
- package/dist/internal/members.js +7 -0
- package/dist/internal/oauthClient.d.ts +61 -0
- package/dist/internal/oauthClient.d.ts.map +1 -0
- package/dist/internal/oauthClient.js +133 -0
- 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 +172 -0
- package/dist/internal/oauthScopes.d.ts.map +1 -0
- package/dist/internal/oauthScopes.js +510 -0
- 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/organizationName.d.ts +18 -0
- package/dist/internal/organizationName.d.ts.map +1 -0
- package/dist/internal/organizationName.js +24 -0
- package/dist/internal/protocol.d.ts +150 -3
- package/dist/internal/protocol.d.ts.map +1 -1
- package/dist/internal/protocol.js +163 -2
- package/dist/internal/providerApps.d.ts +75 -0
- package/dist/internal/providerApps.d.ts.map +1 -0
- package/dist/internal/providerApps.js +59 -0
- package/dist/internal/providerRegistry.d.ts +218 -0
- package/dist/internal/providerRegistry.d.ts.map +1 -0
- package/dist/internal/providerRegistry.js +432 -0
- package/dist/internal/providerSpec.d.ts +66 -0
- package/dist/internal/providerSpec.d.ts.map +1 -0
- package/dist/internal/providerSpec.js +1154 -0
- package/dist/internal/remoteMcp.d.ts +188 -0
- package/dist/internal/remoteMcp.d.ts.map +1 -0
- package/dist/internal/remoteMcp.js +543 -0
- 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/internal/tools.d.ts +115 -0
- package/dist/internal/tools.d.ts.map +1 -0
- package/dist/internal/tools.js +80 -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 +43 -0
- package/dist/server/attribution.d.ts.map +1 -0
- package/dist/server/attribution.js +75 -0
- package/dist/server/authorizeUrl.d.ts +43 -0
- package/dist/server/authorizeUrl.d.ts.map +1 -0
- package/dist/server/authorizeUrl.js +106 -0
- 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 +63 -0
- package/dist/server/emit.d.ts.map +1 -0
- package/dist/server/emit.js +101 -0
- 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 +65 -19
- package/dist/server/everyApp.d.ts.map +1 -1
- package/dist/server/everyApp.js +195 -30
- 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 +54 -14
- package/dist/server/gatewayFetch.d.ts.map +1 -1
- package/dist/server/gatewayFetch.js +201 -37
- 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 +23 -3
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +19 -2
- package/dist/server/integrationFetch.d.ts +162 -0
- package/dist/server/integrationFetch.d.ts.map +1 -0
- package/dist/server/integrationFetch.js +688 -0
- package/dist/server/listMembers.d.ts +32 -0
- package/dist/server/listMembers.d.ts.map +1 -0
- package/dist/server/listMembers.js +71 -0
- package/dist/server/nodeServer.d.ts +48 -0
- package/dist/server/nodeServer.d.ts.map +1 -0
- package/dist/server/nodeServer.js +45 -0
- 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 +39 -0
- package/dist/server/sendEmail.d.ts.map +1 -0
- package/dist/server/sendEmail.js +114 -0
- package/dist/server/tools.d.ts +184 -0
- package/dist/server/tools.d.ts.map +1 -0
- package/dist/server/tools.js +347 -0
- package/dist/server/toolsEndpoint.d.ts +32 -0
- package/dist/server/toolsEndpoint.d.ts.map +1 -0
- package/dist/server/toolsEndpoint.js +237 -0
- 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 +42 -8
- package/dist/server/mcp.d.ts +0 -66
- package/dist/server/mcp.d.ts.map +0 -1
- package/dist/server/mcp.js +0 -147
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Gateway's settings and the app's own secrets, by name: the Gateway
|
|
3
|
+
* settings an operator changes with `everyapp secret set <NAME>` (plain
|
|
4
|
+
* secrets on the Gateway Worker, read on its next request), the ones the
|
|
5
|
+
* install writes once, and the names an app's own secret can never take.
|
|
6
|
+
* What an app's manifest needs of them is appSettings.ts. One registry serves
|
|
7
|
+
* the CLI (a Gateway name goes to the Gateway, any other to the app in the
|
|
8
|
+
* current directory), the manifest validator (an app's `secrets` may not
|
|
9
|
+
* take a Gateway name, since the app reaches those through `providers` and
|
|
10
|
+
* `capabilities`) and the Gateway's dev config, which a test keeps
|
|
11
|
+
* declaring every settable one.
|
|
12
|
+
*/
|
|
13
|
+
import { CAPABILITIES, CAPABILITY_IDS, capabilitySettings, } from "./capabilities.js";
|
|
14
|
+
import { PLAIN_SIGN_IN_SETTINGS, SIGN_IN_GATEWAY_SETTINGS, } from "./signInProviders.js";
|
|
15
|
+
/**
|
|
16
|
+
* The Gateway's own settings: the install writes them once (`everyapp
|
|
17
|
+
* setup`), or an operator by hand (THIRD_PARTY_DEPLOYS), and `everyapp
|
|
18
|
+
* secret set` never changes them. An app's own Worker may still have a
|
|
19
|
+
* secret of the same name (OpenSEO's BETTER_AUTH_SECRET): the two never meet.
|
|
20
|
+
*/
|
|
21
|
+
export const INSTALL_OWNED_GATEWAY_SETTINGS = [
|
|
22
|
+
"GATEWAY_URL",
|
|
23
|
+
"APP_BASE_DOMAIN",
|
|
24
|
+
"BETTER_AUTH_SECRET",
|
|
25
|
+
"JWT_PRIVATE_KEY",
|
|
26
|
+
"JWT_PUBLIC_KEY",
|
|
27
|
+
"GATEWAY_DEPLOYMENT_MODE",
|
|
28
|
+
"CLOUDFLARE_ACCOUNT_ID",
|
|
29
|
+
"THIRD_PARTY_DEPLOYS",
|
|
30
|
+
];
|
|
31
|
+
const INSTALL_OWNED = new Set(INSTALL_OWNED_GATEWAY_SETTINGS);
|
|
32
|
+
export function isInstallOwnedGatewaySetting(name) {
|
|
33
|
+
return INSTALL_OWNED.has(name);
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* The settings the catalog's providers read (the AI providers' keys, the
|
|
37
|
+
* API-key providers' keys and hosts, the OAuth clients), in catalog order, the install's own left out: what `everyapp
|
|
38
|
+
* secret set` accepts because a provider reads it. A gateway's registered
|
|
39
|
+
* rows add theirs at run time (providerRegistry.settingNames()).
|
|
40
|
+
*/
|
|
41
|
+
const PROVIDER_GATEWAY_SETTINGS = [
|
|
42
|
+
...new Set(CAPABILITY_IDS.flatMap((id) => {
|
|
43
|
+
const capability = CAPABILITIES[id];
|
|
44
|
+
return capability.mode === "service"
|
|
45
|
+
? []
|
|
46
|
+
: capabilitySettings(capability);
|
|
47
|
+
})),
|
|
48
|
+
].filter((name) => !INSTALL_OWNED.has(name));
|
|
49
|
+
/** The Gateway's own optional settings `everyapp secret set` changes: nothing a provider reads. */
|
|
50
|
+
export const GATEWAY_OWN_SETTINGS = [
|
|
51
|
+
"AI_PROXY_EXTRA_ROUTES",
|
|
52
|
+
// Email's providers: Cloudflare's REST token, Resend's key, the choice.
|
|
53
|
+
"EMAIL_REST_API_TOKEN",
|
|
54
|
+
"RESEND_API_KEY",
|
|
55
|
+
"EMAIL_PROVIDER",
|
|
56
|
+
"EMAIL_FROM",
|
|
57
|
+
"EMAIL_FROM_NAME",
|
|
58
|
+
"MCP_OAUTH_ENABLED",
|
|
59
|
+
"MCP_DCR_ENABLED",
|
|
60
|
+
"MCP_ALLOWED_ORIGINS",
|
|
61
|
+
"MCP_AUDIT_RETENTION_DAYS",
|
|
62
|
+
"CLOUDFLARE_ACCESS_OIDC_ISSUER",
|
|
63
|
+
"CLOUDFLARE_ACCESS_OIDC_CLIENT_ID",
|
|
64
|
+
"CLOUDFLARE_ACCESS_OIDC_CLIENT_SECRET",
|
|
65
|
+
"CLOUDFLARE_ACCESS_OIDC_LABEL",
|
|
66
|
+
"CLOUDFLARE_ACCESS_TEAM_DOMAIN",
|
|
67
|
+
"CLOUDFLARE_ACCESS_AUD",
|
|
68
|
+
"CLOUDFLARE_ACCESS_APPS_AUD",
|
|
69
|
+
"CLOUDFLARE_ACCESS_AUTO_JOIN_DOMAINS",
|
|
70
|
+
"CLOUDFLARE_ACCESS_OUTER_RING_AUTO_JOIN",
|
|
71
|
+
"EMAIL_PASSWORD_SIGN_IN",
|
|
72
|
+
// "false" keeps the hosted gateway's sign-up invite-only.
|
|
73
|
+
"HOSTED_OPEN_SIGNUP",
|
|
74
|
+
// Release deployers and the hosted third-party domain. The hosted launch
|
|
75
|
+
// gate, THIRD_PARTY_DEPLOYS, is never set from here: it is opened by
|
|
76
|
+
// hand once the launch checks pass (docs/runbooks/hosted-install.md).
|
|
77
|
+
"CF_DEPLOY_TOKEN",
|
|
78
|
+
// Self-hosted Gateway app installs: off unless exactly "on" (everyapp deploy-token add).
|
|
79
|
+
"BROWSER_APP_INSTALLS",
|
|
80
|
+
"DISPATCH_NAMESPACE",
|
|
81
|
+
"THIRD_PARTY_DOMAIN",
|
|
82
|
+
// "true" lets event webhooks target http: and private hosts (self-host only).
|
|
83
|
+
"EVENTS_ALLOW_PRIVATE_TARGETS",
|
|
84
|
+
];
|
|
85
|
+
/**
|
|
86
|
+
* The Gateway's optional settings `everyapp secret set` changes: every
|
|
87
|
+
* setting a catalog provider reads, the Gateway's own, then the sign-in
|
|
88
|
+
* providers' (`<ID>_SIGNIN_<FIELD>`, ./signInProviders.ts).
|
|
89
|
+
*/
|
|
90
|
+
export const SETTABLE_GATEWAY_SETTINGS = [
|
|
91
|
+
...PROVIDER_GATEWAY_SETTINGS,
|
|
92
|
+
...GATEWAY_OWN_SETTINGS,
|
|
93
|
+
...SIGN_IN_GATEWAY_SETTINGS,
|
|
94
|
+
];
|
|
95
|
+
const SETTABLE = new Set(SETTABLE_GATEWAY_SETTINGS);
|
|
96
|
+
/**
|
|
97
|
+
* The credential names of remote MCP apps (`everyapp mcp add <url>`,
|
|
98
|
+
* ./remoteMcp.ts): `<ID>_MCP_TOKEN` by default, any name ending in
|
|
99
|
+
* `_MCP_TOKEN` by choice. A family rather than a list, so the names a
|
|
100
|
+
* registry row declares at run time route to the Gateway like the fixed
|
|
101
|
+
* names (`everyapp secret set` reads no registry to decide), an app's own
|
|
102
|
+
* secret can never take one (the manifest validator refuses the family),
|
|
103
|
+
* and a remote server can never be given a fixed provider key.
|
|
104
|
+
*/
|
|
105
|
+
export const REMOTE_MCP_SECRET_PATTERN = /^[A-Z][A-Z0-9_]*_MCP_TOKEN$/;
|
|
106
|
+
/** Whether `name` is a remote MCP app's credential name (`TREG_MCP_TOKEN`). */
|
|
107
|
+
export function isRemoteMcpSecretName(name) {
|
|
108
|
+
return REMOTE_MCP_SECRET_PATTERN.test(name);
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Whether `everyapp secret set <name>` changes the Gateway: one of the
|
|
112
|
+
* fixed settings, or a remote MCP app's credential name.
|
|
113
|
+
*/
|
|
114
|
+
export function isSettableGatewaySetting(name) {
|
|
115
|
+
return SETTABLE.has(name) || isRemoteMcpSecretName(name);
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Settable Gateway settings whose value is a plain word, address, list
|
|
119
|
+
* or switch rather than a credential: a sender, a provider choice, a
|
|
120
|
+
* URL, an audience, a flag. `everyapp secret set` may show these as they
|
|
121
|
+
* are typed and check their shape; anything else is a credential and
|
|
122
|
+
* stays hidden.
|
|
123
|
+
*/
|
|
124
|
+
export const PLAIN_GATEWAY_SETTINGS = [
|
|
125
|
+
"EMAIL_FROM",
|
|
126
|
+
"EMAIL_FROM_NAME",
|
|
127
|
+
"EMAIL_PROVIDER",
|
|
128
|
+
"EMAIL_PASSWORD_SIGN_IN",
|
|
129
|
+
"AI_PROXY_EXTRA_ROUTES",
|
|
130
|
+
"MCP_OAUTH_ENABLED",
|
|
131
|
+
"MCP_DCR_ENABLED",
|
|
132
|
+
"MCP_ALLOWED_ORIGINS",
|
|
133
|
+
"MCP_AUDIT_RETENTION_DAYS",
|
|
134
|
+
"CLOUDFLARE_ACCESS_OIDC_ISSUER",
|
|
135
|
+
"CLOUDFLARE_ACCESS_OIDC_CLIENT_ID",
|
|
136
|
+
"CLOUDFLARE_ACCESS_OIDC_LABEL",
|
|
137
|
+
"CLOUDFLARE_ACCESS_TEAM_DOMAIN",
|
|
138
|
+
"CLOUDFLARE_ACCESS_AUD",
|
|
139
|
+
"CLOUDFLARE_ACCESS_APPS_AUD",
|
|
140
|
+
"CLOUDFLARE_ACCESS_AUTO_JOIN_DOMAINS",
|
|
141
|
+
"CLOUDFLARE_ACCESS_OUTER_RING_AUTO_JOIN",
|
|
142
|
+
"HOSTED_OPEN_SIGNUP",
|
|
143
|
+
"BROWSER_APP_INSTALLS",
|
|
144
|
+
"DISPATCH_NAMESPACE",
|
|
145
|
+
"THIRD_PARTY_DOMAIN",
|
|
146
|
+
"EVENTS_ALLOW_PRIVATE_TARGETS",
|
|
147
|
+
];
|
|
148
|
+
const PLAIN = new Set([
|
|
149
|
+
...PLAIN_GATEWAY_SETTINGS,
|
|
150
|
+
// The sign-in providers' ids, issuer, label and tenant; their client
|
|
151
|
+
// secrets are credentials.
|
|
152
|
+
...PLAIN_SIGN_IN_SETTINGS,
|
|
153
|
+
]);
|
|
154
|
+
/** Whether a settable Gateway setting's value is a plain value, not a credential. */
|
|
155
|
+
export function isPlainGatewaySetting(name) {
|
|
156
|
+
return PLAIN.has(name);
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Settable Gateway settings only the hosted gateway reads: a self-hosted
|
|
160
|
+
* install never needs them, so `secret list` leaves them out there.
|
|
161
|
+
*/
|
|
162
|
+
export const HOSTED_ONLY_GATEWAY_SETTINGS = [
|
|
163
|
+
"HOSTED_OPEN_SIGNUP",
|
|
164
|
+
"DISPATCH_NAMESPACE",
|
|
165
|
+
"THIRD_PARTY_DOMAIN",
|
|
166
|
+
];
|
|
167
|
+
const HOSTED_ONLY = new Set(HOSTED_ONLY_GATEWAY_SETTINGS);
|
|
168
|
+
export function isHostedOnlyGatewaySetting(name) {
|
|
169
|
+
return HOSTED_ONLY.has(name);
|
|
170
|
+
}
|
|
171
|
+
/** Gateway settings for local testing only, set in the gateway's `.dev.vars`, never deployed. */
|
|
172
|
+
export const DEV_ONLY_GATEWAY_SETTINGS = [
|
|
173
|
+
"MCP_ACCESS_TOKEN_TTL",
|
|
174
|
+
// "true" sends the DataForSEO provider app's calls to the free sandbox.
|
|
175
|
+
"DATAFORSEO_SANDBOX",
|
|
176
|
+
];
|
|
177
|
+
export function isDevOnlyGatewaySetting(name) {
|
|
178
|
+
return DEV_ONLY_GATEWAY_SETTINGS.includes(name);
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Names an app's own secret can't take: the deploy sets GATEWAY_URL on
|
|
182
|
+
* every Worker and builds in the identity settings, the gateway binding
|
|
183
|
+
* and the platform's own namespaces. Checked without regard to case. The
|
|
184
|
+
* SDK's `everyAppWorker()` keeps the same rule as a regex (its config
|
|
185
|
+
* module can't import this one); a test keeps them in step.
|
|
186
|
+
*/
|
|
187
|
+
const RESERVED_APP_SECRET_NAMES = new Set([
|
|
188
|
+
"GATEWAY_URL",
|
|
189
|
+
"CF_VERSION_METADATA",
|
|
190
|
+
]);
|
|
191
|
+
const RESERVED_APP_SECRET_PREFIXES = [
|
|
192
|
+
"EVERYAPP_",
|
|
193
|
+
"EVERY_APP_",
|
|
194
|
+
"APP__",
|
|
195
|
+
];
|
|
196
|
+
/** What the reserved names are, for messages. */
|
|
197
|
+
export const RESERVED_APP_SECRET_NAMES_TEXT = "GATEWAY_URL, CF_VERSION_METADATA and the EVERYAPP_*, EVERY_APP_* and APP__* names";
|
|
198
|
+
export function isReservedAppSecretName(name) {
|
|
199
|
+
const upper = name.toUpperCase();
|
|
200
|
+
return (RESERVED_APP_SECRET_NAMES.has(upper) ||
|
|
201
|
+
RESERVED_APP_SECRET_PREFIXES.some((prefix) => upper.startsWith(prefix)));
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* The AI provider or capability a Gateway setting belongs to: what to list
|
|
205
|
+
* in a manifest instead of holding the key as the app's own.
|
|
206
|
+
*/
|
|
207
|
+
export function gatewaySettingOwner(name) {
|
|
208
|
+
for (const id of CAPABILITY_IDS) {
|
|
209
|
+
const capability = CAPABILITIES[id];
|
|
210
|
+
if (capabilitySettings(capability).includes(name)) {
|
|
211
|
+
return { kind: capability.mode === "ai" ? "provider" : "capability", id };
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
return null;
|
|
215
|
+
}
|
|
@@ -1,12 +1,23 @@
|
|
|
1
|
-
import { APP_ID_ENV, DEV_ENV, IDENTITY_ALG, IDENTITY_DEV_KEY_ID, IDENTITY_HEADER, IDENTITY_KEY_ID, ISSUER_ENV, PUBLIC_HEADER, PUBLIC_KEYS_ENV, PUBLIC_MARKER_SUB, type EveryAppUser, type IdentityChannel } from "./protocol.js";
|
|
2
|
-
export { APP_ID_ENV, DEV_ENV, IDENTITY_ALG, IDENTITY_DEV_KEY_ID, IDENTITY_HEADER, IDENTITY_KEY_ID, ISSUER_ENV, PUBLIC_HEADER, PUBLIC_KEYS_ENV, PUBLIC_MARKER_SUB, type EveryAppUser, type IdentityChannel, };
|
|
1
|
+
import { APP_ID_ENV, DEV_ENV, DEV_ISSUER, IDENTITY_ALG, IDENTITY_DEV_KEY_ID, IDENTITY_HEADER, IDENTITY_KEY_ID, ISSUER_ENV, ORG_ID_ENV, PUBLIC_HEADER, PUBLIC_KEYS_ENV, PUBLIC_MARKER_SUB, type EveryAppUser, type IdentityChannel, type SystemClaims, type SystemTokenPurpose } from "./protocol.js";
|
|
2
|
+
export { APP_ID_ENV, DEV_ENV, DEV_ISSUER, IDENTITY_ALG, IDENTITY_DEV_KEY_ID, IDENTITY_HEADER, IDENTITY_KEY_ID, ISSUER_ENV, ORG_ID_ENV, PUBLIC_HEADER, PUBLIC_KEYS_ENV, PUBLIC_MARKER_SUB, type EveryAppUser, type IdentityChannel, };
|
|
3
3
|
export declare class IdentityError extends Error {
|
|
4
4
|
readonly status = 401;
|
|
5
5
|
constructor(message: string);
|
|
6
6
|
}
|
|
7
7
|
export declare class ConfigurationError extends Error {
|
|
8
8
|
readonly status = 500;
|
|
9
|
-
|
|
9
|
+
/**
|
|
10
|
+
* The Gateway refusal code the same gap gets once deployed
|
|
11
|
+
* (`ai_provider_not_configured`, `ai_default_not_configured`), when the
|
|
12
|
+
* error is "not set up" rather than a mistake in the code.
|
|
13
|
+
*/
|
|
14
|
+
readonly code: string | undefined;
|
|
15
|
+
/** The settings that would close the gap (`.dev.vars` names in local dev). */
|
|
16
|
+
readonly settings: readonly string[];
|
|
17
|
+
constructor(message: string, setup?: {
|
|
18
|
+
code: string;
|
|
19
|
+
settings?: readonly string[];
|
|
20
|
+
});
|
|
10
21
|
}
|
|
11
22
|
/**
|
|
12
23
|
* Parse the public key set from an env var value. Accepts a JSON array of PEM
|
|
@@ -23,7 +34,7 @@ export interface VerifyOptions {
|
|
|
23
34
|
/**
|
|
24
35
|
* Accept the dev identity kid ({@link IDENTITY_DEV_KEY_ID}). Set ONLY in
|
|
25
36
|
* local dev (driven by the {@link DEV_ENV} worker env var). Never true in
|
|
26
|
-
* production.
|
|
37
|
+
* production. Requires `issuer` to be {@link DEV_ISSUER}.
|
|
27
38
|
*/
|
|
28
39
|
allowDevIdentities?: boolean;
|
|
29
40
|
/** Override for tests. */
|
|
@@ -35,6 +46,33 @@ export interface VerifyOptions {
|
|
|
35
46
|
* claims).
|
|
36
47
|
*/
|
|
37
48
|
export declare function verifyIdentityJwt(token: string, options: VerifyOptions): Promise<EveryAppUser>;
|
|
49
|
+
/** A verified identity, with when it stops being one. */
|
|
50
|
+
export interface VerifiedIdentity {
|
|
51
|
+
user: EveryAppUser;
|
|
52
|
+
/** The token's `exp`, in epoch milliseconds. */
|
|
53
|
+
expiresAt: number;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* {@link verifyIdentityJwt}, keeping the token's expiry: the SDK's request
|
|
57
|
+
* context stops forwarding an identity shortly before it, and goes on as
|
|
58
|
+
* the organization's background work.
|
|
59
|
+
*/
|
|
60
|
+
export declare function verifyIdentity(token: string, options: VerifyOptions): Promise<VerifiedIdentity>;
|
|
61
|
+
/**
|
|
62
|
+
* The organization pin: a deployed Worker serves one organization
|
|
63
|
+
* (`EVERY_APP_ORG_ID`), and an identity for any other is refused, whatever
|
|
64
|
+
* its audience says. Throws {@link IdentityError} on a mismatch; a Worker
|
|
65
|
+
* with no pin (a shared app's) accepts every organization.
|
|
66
|
+
*/
|
|
67
|
+
export declare function assertOrganizationPin(user: EveryAppUser, organizationId: string | undefined): void;
|
|
68
|
+
/**
|
|
69
|
+
* Verify the gateway's system token (the value of `x-everyapp-system`)
|
|
70
|
+
* fail-closed, for exactly one purpose. A user identity or public marker is
|
|
71
|
+
* never a system token, and a system token is never an identity.
|
|
72
|
+
*/
|
|
73
|
+
export declare function verifySystemJwt(token: string, options: VerifyOptions & {
|
|
74
|
+
purpose: SystemTokenPurpose;
|
|
75
|
+
}): Promise<SystemClaims>;
|
|
38
76
|
/**
|
|
39
77
|
* Verify a public-route marker (the value of `x-everyapp-public`). The marker
|
|
40
78
|
* is a gateway-signed, app-scoped JWT with `pub: true` and `typ: "public"` —
|
|
@@ -48,9 +86,16 @@ export interface IdentityResult {
|
|
|
48
86
|
user: EveryAppUser | null;
|
|
49
87
|
/** True when the gateway marked this request as a public route. */
|
|
50
88
|
isPublic: boolean;
|
|
89
|
+
/** When the identity expires (epoch ms); null on a public route. */
|
|
90
|
+
expiresAt: number | null;
|
|
51
91
|
}
|
|
52
92
|
export interface RequestIdentityOptions {
|
|
53
93
|
audience: string;
|
|
94
|
+
/**
|
|
95
|
+
* The organization this Worker is pinned to ({@link ORG_ID_ENV}): an
|
|
96
|
+
* identity for another is refused. Undefined accepts every organization.
|
|
97
|
+
*/
|
|
98
|
+
organizationId?: string;
|
|
54
99
|
/** Provide keys directly, or let {@link getIdentityFromRequest} read env. */
|
|
55
100
|
publicKeys?: string[];
|
|
56
101
|
/** Env bag to read {@link PUBLIC_KEYS_ENV} / {@link DEV_ENV} from. */
|
|
@@ -61,6 +106,13 @@ export interface RequestIdentityOptions {
|
|
|
61
106
|
allowDevIdentities?: boolean;
|
|
62
107
|
now?: number;
|
|
63
108
|
}
|
|
109
|
+
/**
|
|
110
|
+
* The verification options for a request: keys from options or env, the
|
|
111
|
+
* expected issuer, and the dev-kid opt-in. Throws {@link ConfigurationError}
|
|
112
|
+
* when no key set is configured, or when the dev opt-in meets an issuer other
|
|
113
|
+
* than {@link DEV_ISSUER}.
|
|
114
|
+
*/
|
|
115
|
+
export declare function resolveVerifyOptions(options: RequestIdentityOptions): VerifyOptions;
|
|
64
116
|
/**
|
|
65
117
|
* Resolve identity for an incoming proxied request. Public routes carry a
|
|
66
118
|
* gateway-SIGNED marker in `x-everyapp-public` and resolve to
|
|
@@ -69,5 +121,5 @@ export interface RequestIdentityOptions {
|
|
|
69
121
|
* problem — including a bare/forged public header — so a re-exposed worker
|
|
70
122
|
* fails closed.
|
|
71
123
|
*/
|
|
72
|
-
export declare function getIdentityFromRequest(request: Request, options: RequestIdentityOptions): Promise<IdentityResult>;
|
|
124
|
+
export declare function getIdentityFromRequest(request: Request | Headers, options: RequestIdentityOptions): Promise<IdentityResult>;
|
|
73
125
|
//# sourceMappingURL=identity.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"identity.d.ts","sourceRoot":"","sources":["../../src/internal/identity.ts"],"names":[],"mappings":"AAgBA,OAAO,EACL,UAAU,EACV,OAAO,EACP,YAAY,EACZ,mBAAmB,EACnB,eAAe,EACf,eAAe,EACf,UAAU,EACV,aAAa,EACb,eAAe,EACf,iBAAiB,
|
|
1
|
+
{"version":3,"file":"identity.d.ts","sourceRoot":"","sources":["../../src/internal/identity.ts"],"names":[],"mappings":"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"}
|
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
* survives verification produces a user.
|
|
10
10
|
*/
|
|
11
11
|
import { importSPKI, jwtVerify, decodeProtectedHeader, } from "jose";
|
|
12
|
-
import { APP_ID_ENV, DEV_ENV, IDENTITY_ALG, IDENTITY_DEV_KEY_ID, IDENTITY_HEADER, IDENTITY_KEY_ID, ISSUER_ENV, PUBLIC_HEADER, PUBLIC_KEYS_ENV, PUBLIC_MARKER_SUB, assertPublicMarkerClaims, identityClaimsToEveryAppUser, ProtocolClaimsError, } from "./protocol.js";
|
|
13
|
-
export { APP_ID_ENV, DEV_ENV, IDENTITY_ALG, IDENTITY_DEV_KEY_ID, IDENTITY_HEADER, IDENTITY_KEY_ID, ISSUER_ENV, PUBLIC_HEADER, PUBLIC_KEYS_ENV, PUBLIC_MARKER_SUB, };
|
|
12
|
+
import { APP_ID_ENV, DEV_ENV, DEV_ISSUER, IDENTITY_ALG, IDENTITY_DEV_KEY_ID, IDENTITY_HEADER, IDENTITY_KEY_ID, ISSUER_ENV, ORG_ID_ENV, PUBLIC_HEADER, PUBLIC_KEYS_ENV, PUBLIC_MARKER_SUB, assertPublicMarkerClaims, assertSystemClaims, identityClaimsToEveryAppUser, ProtocolClaimsError, } from "./protocol.js";
|
|
13
|
+
export { APP_ID_ENV, DEV_ENV, DEV_ISSUER, IDENTITY_ALG, IDENTITY_DEV_KEY_ID, IDENTITY_HEADER, IDENTITY_KEY_ID, ISSUER_ENV, ORG_ID_ENV, PUBLIC_HEADER, PUBLIC_KEYS_ENV, PUBLIC_MARKER_SUB, };
|
|
14
14
|
export class IdentityError extends Error {
|
|
15
15
|
status = 401;
|
|
16
16
|
constructor(message) {
|
|
@@ -20,9 +20,19 @@ export class IdentityError extends Error {
|
|
|
20
20
|
}
|
|
21
21
|
export class ConfigurationError extends Error {
|
|
22
22
|
status = 500;
|
|
23
|
-
|
|
23
|
+
/**
|
|
24
|
+
* The Gateway refusal code the same gap gets once deployed
|
|
25
|
+
* (`ai_provider_not_configured`, `ai_default_not_configured`), when the
|
|
26
|
+
* error is "not set up" rather than a mistake in the code.
|
|
27
|
+
*/
|
|
28
|
+
code;
|
|
29
|
+
/** The settings that would close the gap (`.dev.vars` names in local dev). */
|
|
30
|
+
settings;
|
|
31
|
+
constructor(message, setup) {
|
|
24
32
|
super(message);
|
|
25
33
|
this.name = "ConfigurationError";
|
|
34
|
+
this.code = setup?.code;
|
|
35
|
+
this.settings = setup?.settings ?? [];
|
|
26
36
|
}
|
|
27
37
|
}
|
|
28
38
|
/**
|
|
@@ -65,15 +75,63 @@ function importKey(pem) {
|
|
|
65
75
|
}
|
|
66
76
|
return cached;
|
|
67
77
|
}
|
|
78
|
+
/**
|
|
79
|
+
* The dev keypair is public (`@every-app/sdk/dev`), so the dev opt-in holds
|
|
80
|
+
* only for the dev issuer: a dev-kid token that names a real gateway as its
|
|
81
|
+
* issuer never verifies, whatever the env says.
|
|
82
|
+
*/
|
|
83
|
+
function assertDevIssuer(options) {
|
|
84
|
+
if (options.allowDevIdentities && options.issuer !== DEV_ISSUER) {
|
|
85
|
+
throw new ConfigurationError(`Dev identities are accepted only from the dev issuer ${DEV_ISSUER}, not ${options.issuer ? `"${options.issuer}"` : "an unset issuer"}. ${DEV_ENV} is for \`everyapp dev\` alone.`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
68
88
|
/**
|
|
69
89
|
* Verify an identity JWT fail-closed. Throws {@link IdentityError} on any
|
|
70
90
|
* problem (bad alg/kid, `none`, wrong key, expired, wrong audience, missing
|
|
71
91
|
* claims).
|
|
72
92
|
*/
|
|
73
93
|
export async function verifyIdentityJwt(token, options) {
|
|
94
|
+
return (await verifyIdentity(token, options)).user;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* {@link verifyIdentityJwt}, keeping the token's expiry: the SDK's request
|
|
98
|
+
* context stops forwarding an identity shortly before it, and goes on as
|
|
99
|
+
* the organization's background work.
|
|
100
|
+
*/
|
|
101
|
+
export async function verifyIdentity(token, options) {
|
|
74
102
|
const payload = await verifyPinnedJwt(token, options, "user");
|
|
75
103
|
try {
|
|
76
|
-
|
|
104
|
+
const user = identityClaimsToEveryAppUser(payload);
|
|
105
|
+
// `exp` is a required claim (verifyPinnedJwt); jose checked it.
|
|
106
|
+
return { user, expiresAt: payload.exp * 1000 };
|
|
107
|
+
}
|
|
108
|
+
catch (error) {
|
|
109
|
+
if (error instanceof ProtocolClaimsError) {
|
|
110
|
+
throw new IdentityError(error.message);
|
|
111
|
+
}
|
|
112
|
+
throw error;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* The organization pin: a deployed Worker serves one organization
|
|
117
|
+
* (`EVERY_APP_ORG_ID`), and an identity for any other is refused, whatever
|
|
118
|
+
* its audience says. Throws {@link IdentityError} on a mismatch; a Worker
|
|
119
|
+
* with no pin (a shared app's) accepts every organization.
|
|
120
|
+
*/
|
|
121
|
+
export function assertOrganizationPin(user, organizationId) {
|
|
122
|
+
if (organizationId && user.orgId !== organizationId) {
|
|
123
|
+
throw new IdentityError(`identity is for organization "${user.orgId}", and this Worker serves organization "${organizationId}" (${ORG_ID_ENV})`);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Verify the gateway's system token (the value of `x-everyapp-system`)
|
|
128
|
+
* fail-closed, for exactly one purpose. A user identity or public marker is
|
|
129
|
+
* never a system token, and a system token is never an identity.
|
|
130
|
+
*/
|
|
131
|
+
export async function verifySystemJwt(token, options) {
|
|
132
|
+
const payload = await verifyPinnedJwt(token, options, "system");
|
|
133
|
+
try {
|
|
134
|
+
return assertSystemClaims(payload, options.purpose);
|
|
77
135
|
}
|
|
78
136
|
catch (error) {
|
|
79
137
|
if (error instanceof ProtocolClaimsError) {
|
|
@@ -87,6 +145,7 @@ export async function verifyIdentityJwt(token, options) {
|
|
|
87
145
|
* `aud` checked, multi-key (current + next). Returns the verified payload.
|
|
88
146
|
*/
|
|
89
147
|
async function verifyPinnedJwt(token, options, expectedTyp) {
|
|
148
|
+
assertDevIssuer(options);
|
|
90
149
|
if (!token)
|
|
91
150
|
throw new IdentityError("no identity token");
|
|
92
151
|
// Pin the header BEFORE attempting any signature work. This is what defeats
|
|
@@ -108,13 +167,13 @@ async function verifyPinnedJwt(token, options, expectedTyp) {
|
|
|
108
167
|
if (!header.kid || !allowedKids.includes(header.kid)) {
|
|
109
168
|
throw new IdentityError(`unexpected kid "${header.kid}"`);
|
|
110
169
|
}
|
|
111
|
-
if (expectedTyp
|
|
112
|
-
throw new IdentityError(`${ISSUER_ENV} not configured — deploy with the
|
|
170
|
+
if (expectedTyp !== "public" && !options.issuer) {
|
|
171
|
+
throw new IdentityError(`${ISSUER_ENV} not configured — deploy with the EveryApp CLI or provide an explicit issuer.`);
|
|
113
172
|
}
|
|
114
173
|
const verifyOpts = {
|
|
115
174
|
algorithms: [IDENTITY_ALG],
|
|
116
175
|
audience: options.audience,
|
|
117
|
-
requiredClaims: ["exp"],
|
|
176
|
+
requiredClaims: expectedTyp === "system" ? ["exp", "iat"] : ["exp"],
|
|
118
177
|
...(options.issuer ? { issuer: options.issuer } : {}),
|
|
119
178
|
...(options.now ? { currentDate: new Date(options.now) } : {}),
|
|
120
179
|
};
|
|
@@ -154,23 +213,21 @@ export async function verifyPublicMarkerJwt(token, options) {
|
|
|
154
213
|
}
|
|
155
214
|
}
|
|
156
215
|
/**
|
|
157
|
-
*
|
|
158
|
-
*
|
|
159
|
-
*
|
|
160
|
-
*
|
|
161
|
-
* problem — including a bare/forged public header — so a re-exposed worker
|
|
162
|
-
* fails closed.
|
|
216
|
+
* The verification options for a request: keys from options or env, the
|
|
217
|
+
* expected issuer, and the dev-kid opt-in. Throws {@link ConfigurationError}
|
|
218
|
+
* when no key set is configured, or when the dev opt-in meets an issuer other
|
|
219
|
+
* than {@link DEV_ISSUER}.
|
|
163
220
|
*/
|
|
164
|
-
export
|
|
221
|
+
export function resolveVerifyOptions(options) {
|
|
165
222
|
const publicKeys = options.publicKeys ??
|
|
166
223
|
parsePublicKeys(options.env?.[options.keysEnvVar ?? PUBLIC_KEYS_ENV] ?? null);
|
|
167
|
-
// Dev identities are accepted only when the worker env opts in
|
|
168
|
-
// sets EVERYAPP_DEV in
|
|
224
|
+
// Dev identities are accepted only when the worker env opts in
|
|
225
|
+
// (everyAppWorker() sets EVERYAPP_DEV in development). A deploy never does.
|
|
169
226
|
const devEnv = options.env?.[DEV_ENV];
|
|
170
227
|
const allowDevIdentities = options.allowDevIdentities ??
|
|
171
228
|
(typeof devEnv === "string" &&
|
|
172
229
|
(devEnv === "1" || devEnv.toLowerCase() === "true"));
|
|
173
|
-
const
|
|
230
|
+
const resolved = {
|
|
174
231
|
publicKeys,
|
|
175
232
|
audience: options.audience,
|
|
176
233
|
issuer: options.issuer ??
|
|
@@ -178,15 +235,35 @@ export async function getIdentityFromRequest(request, options) {
|
|
|
178
235
|
allowDevIdentities,
|
|
179
236
|
now: options.now,
|
|
180
237
|
};
|
|
181
|
-
|
|
238
|
+
assertDevIssuer(resolved);
|
|
239
|
+
return resolved;
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Resolve identity for an incoming proxied request. Public routes carry a
|
|
243
|
+
* gateway-SIGNED marker in `x-everyapp-public` and resolve to
|
|
244
|
+
* `{ user: null, isPublic: true }` only after the marker verifies. Everything
|
|
245
|
+
* else requires a valid identity JWT. Throws {@link IdentityError} on any
|
|
246
|
+
* problem — including a bare/forged public header — so a re-exposed worker
|
|
247
|
+
* fails closed.
|
|
248
|
+
*/
|
|
249
|
+
export async function getIdentityFromRequest(request, options) {
|
|
250
|
+
const verifyOptions = resolveVerifyOptions(options);
|
|
251
|
+
const headers = isRequestLike(request) ? request.headers : request;
|
|
252
|
+
const publicMarker = headers.get(PUBLIC_HEADER);
|
|
182
253
|
if (publicMarker) {
|
|
183
254
|
await verifyPublicMarkerJwt(publicMarker, verifyOptions);
|
|
184
|
-
return { user: null, isPublic: true };
|
|
255
|
+
return { user: null, isPublic: true, expiresAt: null };
|
|
185
256
|
}
|
|
186
|
-
const token =
|
|
257
|
+
const token = headers.get(IDENTITY_HEADER);
|
|
187
258
|
if (!token) {
|
|
188
259
|
throw new IdentityError("request reached the app without an identity token (not proxied through the gateway?)");
|
|
189
260
|
}
|
|
190
|
-
const user = await
|
|
191
|
-
|
|
261
|
+
const { user, expiresAt } = await verifyIdentity(token, verifyOptions);
|
|
262
|
+
assertOrganizationPin(user, options.organizationId);
|
|
263
|
+
return { user, isPublic: false, expiresAt };
|
|
264
|
+
}
|
|
265
|
+
// Duck-typed: a Request from another realm (a test runner, a polyfill) still
|
|
266
|
+
// carries its headers the same way.
|
|
267
|
+
function isRequestLike(value) {
|
|
268
|
+
return "headers" in value && typeof value.headers?.get === "function";
|
|
192
269
|
}
|
package/dist/internal/index.d.ts
CHANGED
|
@@ -1,3 +1,24 @@
|
|
|
1
1
|
export * from "./protocol.js";
|
|
2
|
-
export
|
|
2
|
+
export * from "./tools.js";
|
|
3
|
+
export * from "./capabilities.js";
|
|
4
|
+
export * from "./aiProviders.js";
|
|
5
|
+
export * from "./aiDefault.js";
|
|
6
|
+
export * from "./gatewaySettings.js";
|
|
7
|
+
export * from "./appSettings.js";
|
|
8
|
+
export * from "./email.js";
|
|
9
|
+
export * from "./members.js";
|
|
10
|
+
export * from "./organizationName.js";
|
|
11
|
+
export * from "./oauthClient.js";
|
|
12
|
+
export * from "./oauthScopes.js";
|
|
13
|
+
export * from "./oauthSpec.js";
|
|
14
|
+
export * from "./oauthPresets.js";
|
|
15
|
+
export * from "./providerApps.js";
|
|
16
|
+
export * from "./events.js";
|
|
17
|
+
export * from "./audit.js";
|
|
18
|
+
export * from "./providerSpec.js";
|
|
19
|
+
export * from "./providerRegistry.js";
|
|
20
|
+
export * from "./remoteMcp.js";
|
|
21
|
+
export * from "./signInProviders.js";
|
|
22
|
+
export * from "./devProviders.js";
|
|
23
|
+
export { ConfigurationError, IdentityError, assertOrganizationPin, getIdentityFromRequest, parsePublicKeys, resolveVerifyOptions, verifyIdentity, verifyIdentityJwt, verifyPublicMarkerJwt, verifySystemJwt, type IdentityResult, type RequestIdentityOptions, type VerifiedIdentity, type VerifyOptions, } from "./identity.js";
|
|
3
24
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/internal/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,OAAO,EACL,kBAAkB,EAClB,aAAa,EACb,sBAAsB,EACtB,eAAe,EACf,iBAAiB,EACjB,qBAAqB,EACrB,KAAK,cAAc,EACnB,KAAK,sBAAsB,EAC3B,KAAK,aAAa,GACnB,MAAM,eAAe,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/internal/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,YAAY,CAAC;AAC3B,cAAc,mBAAmB,CAAC;AAClC,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,sBAAsB,CAAC;AACrC,cAAc,kBAAkB,CAAC;AACjC,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,uBAAuB,CAAC;AACtC,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,mBAAmB,CAAC;AAClC,cAAc,uBAAuB,CAAC;AACtC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,sBAAsB,CAAC;AACrC,cAAc,mBAAmB,CAAC;AAClC,OAAO,EACL,kBAAkB,EAClB,aAAa,EACb,qBAAqB,EACrB,sBAAsB,EACtB,eAAe,EACf,oBAAoB,EACpB,cAAc,EACd,iBAAiB,EACjB,qBAAqB,EACrB,eAAe,EACf,KAAK,cAAc,EACnB,KAAK,sBAAsB,EAC3B,KAAK,gBAAgB,EACrB,KAAK,aAAa,GACnB,MAAM,eAAe,CAAC"}
|
package/dist/internal/index.js
CHANGED
|
@@ -1,2 +1,23 @@
|
|
|
1
1
|
export * from "./protocol.js";
|
|
2
|
-
export
|
|
2
|
+
export * from "./tools.js";
|
|
3
|
+
export * from "./capabilities.js";
|
|
4
|
+
export * from "./aiProviders.js";
|
|
5
|
+
export * from "./aiDefault.js";
|
|
6
|
+
export * from "./gatewaySettings.js";
|
|
7
|
+
export * from "./appSettings.js";
|
|
8
|
+
export * from "./email.js";
|
|
9
|
+
export * from "./members.js";
|
|
10
|
+
export * from "./organizationName.js";
|
|
11
|
+
export * from "./oauthClient.js";
|
|
12
|
+
export * from "./oauthScopes.js";
|
|
13
|
+
export * from "./oauthSpec.js";
|
|
14
|
+
export * from "./oauthPresets.js";
|
|
15
|
+
export * from "./providerApps.js";
|
|
16
|
+
export * from "./events.js";
|
|
17
|
+
export * from "./audit.js";
|
|
18
|
+
export * from "./providerSpec.js";
|
|
19
|
+
export * from "./providerRegistry.js";
|
|
20
|
+
export * from "./remoteMcp.js";
|
|
21
|
+
export * from "./signInProviders.js";
|
|
22
|
+
export * from "./devProviders.js";
|
|
23
|
+
export { ConfigurationError, IdentityError, assertOrganizationPin, getIdentityFromRequest, parsePublicKeys, resolveVerifyOptions, verifyIdentity, verifyIdentityJwt, verifyPublicMarkerJwt, verifySystemJwt, } from "./identity.js";
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `members` capability's wire contract (docs/capabilities.md "Gateway
|
|
3
|
+
* services"): what `GET /api/integrations/members/list` answers. The
|
|
4
|
+
* gateway builds it, the SDK's `listMembers()` returns it, and its local-dev
|
|
5
|
+
* fallback answers in the same shape. Types only.
|
|
6
|
+
*/
|
|
7
|
+
import type { OrgRole } from "./protocol.js";
|
|
8
|
+
/** A member's role in the organization: the identity token's {@link OrgRole}. */
|
|
9
|
+
export type OrganizationMemberRole = OrgRole;
|
|
10
|
+
/**
|
|
11
|
+
* One member of the organization who can open the app: not deactivated,
|
|
12
|
+
* and, for an organization's own app, granted it.
|
|
13
|
+
*/
|
|
14
|
+
export interface OrganizationMember {
|
|
15
|
+
/** The user id, the identity's `sub` (`getEveryAppUser().id`). */
|
|
16
|
+
id: string;
|
|
17
|
+
email: string;
|
|
18
|
+
/** The display name; empty when the person set none. */
|
|
19
|
+
name: string;
|
|
20
|
+
role: OrganizationMemberRole;
|
|
21
|
+
}
|
|
22
|
+
/** What a list answers. */
|
|
23
|
+
export interface ListMembersResult {
|
|
24
|
+
members: OrganizationMember[];
|
|
25
|
+
}
|
|
26
|
+
/** `GET /api/integrations/members`: whether the app may list members. */
|
|
27
|
+
export interface MembersCapabilityStatus {
|
|
28
|
+
capability: "members";
|
|
29
|
+
/** The app's manifest lists `members`. */
|
|
30
|
+
requested: boolean;
|
|
31
|
+
/** Always true: the gateway needs no setting to list its own members. */
|
|
32
|
+
configured: true;
|
|
33
|
+
/** Lists would go through. */
|
|
34
|
+
ready: boolean;
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=members.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"members.d.ts","sourceRoot":"","sources":["../../src/internal/members.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAE7C,iFAAiF;AACjF,MAAM,MAAM,sBAAsB,GAAG,OAAO,CAAC;AAE7C;;;GAGG;AACH,MAAM,WAAW,kBAAkB;IACjC,kEAAkE;IAClE,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,wDAAwD;IACxD,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,sBAAsB,CAAC;CAC9B;AAED,2BAA2B;AAC3B,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,kBAAkB,EAAE,CAAC;CAC/B;AAED,yEAAyE;AACzE,MAAM,WAAW,uBAAuB;IACtC,UAAU,EAAE,SAAS,CAAC;IACtB,0CAA0C;IAC1C,SAAS,EAAE,OAAO,CAAC;IACnB,yEAAyE;IACzE,UAAU,EAAE,IAAI,CAAC;IACjB,8BAA8B;IAC9B,KAAK,EAAE,OAAO,CAAC;CAChB"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `members` capability's wire contract (docs/capabilities.md "Gateway
|
|
3
|
+
* services"): what `GET /api/integrations/members/list` answers. The
|
|
4
|
+
* gateway builds it, the SDK's `listMembers()` returns it, and its local-dev
|
|
5
|
+
* fallback answers in the same shape. Types only.
|
|
6
|
+
*/
|
|
7
|
+
export {};
|