@every-app/sdk 0.2.0 → 0.3.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +608 -2
- package/dist/cloudflare/index.d.ts +22 -0
- package/dist/cloudflare/index.d.ts.map +1 -0
- package/dist/cloudflare/index.js +21 -0
- package/dist/cloudflare/sentinel.d.ts +69 -0
- package/dist/cloudflare/sentinel.d.ts.map +1 -0
- package/dist/cloudflare/sentinel.js +50 -0
- package/dist/cloudflare/worker.d.ts +511 -0
- package/dist/cloudflare/worker.d.ts.map +1 -0
- package/dist/cloudflare/worker.js +738 -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 +24 -0
- package/dist/dev/keypair.d.ts.map +1 -0
- package/dist/dev/keypair.js +60 -0
- package/dist/internal/aiProviders.d.ts +67 -0
- package/dist/internal/aiProviders.d.ts.map +1 -0
- package/dist/internal/aiProviders.js +220 -0
- package/dist/internal/appSettings.d.ts +237 -0
- package/dist/internal/appSettings.d.ts.map +1 -0
- package/dist/internal/appSettings.js +374 -0
- package/dist/internal/capabilities.d.ts +1344 -0
- package/dist/internal/capabilities.d.ts.map +1 -0
- package/dist/internal/capabilities.js +1521 -0
- package/dist/internal/devProviders.d.ts +49 -0
- package/dist/internal/devProviders.d.ts.map +1 -0
- package/dist/internal/devProviders.js +62 -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 +182 -0
- package/dist/internal/events.d.ts.map +1 -0
- package/dist/internal/events.js +324 -0
- package/dist/internal/gatewaySettings.d.ts +82 -0
- package/dist/internal/gatewaySettings.d.ts.map +1 -0
- package/dist/internal/gatewaySettings.js +209 -0
- package/dist/internal/identity.d.ts +18 -3
- package/dist/internal/identity.d.ts.map +1 -1
- package/dist/internal/identity.js +53 -14
- package/dist/internal/index.d.ts +17 -1
- package/dist/internal/index.d.ts.map +1 -1
- package/dist/internal/index.js +17 -1
- package/dist/internal/members.d.ts +35 -0
- package/dist/internal/members.d.ts.map +1 -0
- package/dist/internal/members.js +7 -0
- package/dist/internal/oauthClient.d.ts +63 -0
- package/dist/internal/oauthClient.d.ts.map +1 -0
- package/dist/internal/oauthClient.js +194 -0
- package/dist/internal/oauthScopes.d.ts +117 -0
- package/dist/internal/oauthScopes.d.ts.map +1 -0
- package/dist/internal/oauthScopes.js +416 -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 +86 -2
- package/dist/internal/protocol.d.ts.map +1 -1
- package/dist/internal/protocol.js +112 -1
- 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 +147 -0
- package/dist/internal/providerRegistry.d.ts.map +1 -0
- package/dist/internal/providerRegistry.js +262 -0
- package/dist/internal/providerSpec.d.ts +55 -0
- package/dist/internal/providerSpec.d.ts.map +1 -0
- package/dist/internal/providerSpec.js +746 -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/tools.d.ts +115 -0
- package/dist/internal/tools.d.ts.map +1 -0
- package/dist/internal/tools.js +80 -0
- package/dist/server/attribution.d.ts +39 -0
- package/dist/server/attribution.d.ts.map +1 -0
- package/dist/server/attribution.js +67 -0
- package/dist/server/authorizeUrl.d.ts +43 -0
- package/dist/server/authorizeUrl.d.ts.map +1 -0
- package/dist/server/authorizeUrl.js +110 -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/everyApp.d.ts +38 -12
- package/dist/server/everyApp.d.ts.map +1 -1
- package/dist/server/everyApp.js +92 -28
- package/dist/server/gatewayFetch.d.ts +24 -8
- package/dist/server/gatewayFetch.d.ts.map +1 -1
- package/dist/server/gatewayFetch.js +81 -36
- package/dist/server/index.d.ts +10 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +8 -1
- package/dist/server/integrationFetch.d.ts +131 -0
- package/dist/server/integrationFetch.d.ts.map +1 -0
- package/dist/server/integrationFetch.js +526 -0
- package/dist/server/listMembers.d.ts +32 -0
- package/dist/server/listMembers.d.ts.map +1 -0
- package/dist/server/listMembers.js +74 -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/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 +231 -0
- package/package.json +30 -17
- 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,1344 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The built-in provider catalog: everything the gateway holds a credential
|
|
3
|
+
* for on apps' behalf (docs/capabilities.md,
|
|
4
|
+
* docs/design/2026-10-provider-registry.md), of four kinds, each an entry
|
|
5
|
+
* of data and nothing else, so a provider the catalog doesn't have can be
|
|
6
|
+
* registered on one gateway as a row of the same shape (./providerSpec.ts,
|
|
7
|
+
* ./providerRegistry.ts):
|
|
8
|
+
*
|
|
9
|
+
* - `api_key`: a provider whose key the gateway holds. The operator sets
|
|
10
|
+
* the key once on the gateway (`everyapp secret set <secret>`), an app lists the provider in its manifest's `capabilities`,
|
|
11
|
+
* and the app calls the provider through the AppGateway binding
|
|
12
|
+
* (`integrationFetch()`), so no app ever holds the key. `auth` says
|
|
13
|
+
* where the key goes on the request ({@link ApiKeyAuth}).
|
|
14
|
+
* - `ai`: an AI provider, reached under `providers` in the manifest and
|
|
15
|
+
* `/api/ai/<id>` on the binding (`createGatewayFetch()`), with the AI
|
|
16
|
+
* proxy's rules: inference routes only, the model allowlist, the usage
|
|
17
|
+
* tap. Never a capability: its key would reach the account's credits
|
|
18
|
+
* and keys on the same host.
|
|
19
|
+
* - `oauth_client`: a provider's OAuth client (a social network's), held
|
|
20
|
+
* the same way. The gateway completes the token endpoint calls only,
|
|
21
|
+
* putting the client on them; the app builds the authorize URL from the
|
|
22
|
+
* public client id (`integrationStatus()`), keeps the user tokens and
|
|
23
|
+
* calls the provider's API with them itself. A client shared by apps
|
|
24
|
+
* with different needs carries a `scopePolicy`: named scope sets an app
|
|
25
|
+
* lists in its manifest entry's `scopes`, which ./oauthScopes.ts turns
|
|
26
|
+
* into what the app may ask the provider for and what a token it is
|
|
27
|
+
* handed may carry.
|
|
28
|
+
* - `service`: something the gateway does itself, with no upstream host
|
|
29
|
+
* an app names (sending email, listing the organization's members). An
|
|
30
|
+
* app lists it the same way and calls its routes,
|
|
31
|
+
* `/api/integrations/<id>/<route>`, through the SDK's own helper
|
|
32
|
+
* (`sendEmail()`, `listMembers()`).
|
|
33
|
+
*
|
|
34
|
+
* The gateway enforces these definitions, the manifest validator checks
|
|
35
|
+
* `capabilities` against them, and the SDK reads them for its local-dev
|
|
36
|
+
* fallback, which calls the provider directly with a developer's own key.
|
|
37
|
+
* All three import them from here so they cannot drift.
|
|
38
|
+
*/
|
|
39
|
+
/** What an app may ask to do with a capability. */
|
|
40
|
+
export type CapabilityAccess = "read" | "write";
|
|
41
|
+
/**
|
|
42
|
+
* Where an API-key provider's key goes on a request, as data: the same
|
|
43
|
+
* four kinds a remote MCP app's credential takes. `secret` is always the
|
|
44
|
+
* name of a Gateway setting (in local dev, the `.dev.vars` name), never a
|
|
45
|
+
* value. {@link authorizationFor} turns one into headers or a query
|
|
46
|
+
* parameter from the settings.
|
|
47
|
+
*/
|
|
48
|
+
export type ApiKeyAuth =
|
|
49
|
+
/** `Authorization: Bearer <key>`; `scheme` for a provider that spells it `Token` or `Api-Key`. */
|
|
50
|
+
{
|
|
51
|
+
kind: "bearer";
|
|
52
|
+
secret: string;
|
|
53
|
+
scheme?: string;
|
|
54
|
+
}
|
|
55
|
+
/** `<header>: <prefix><key>` (`x-api-key: <key>`, `Authorization: Klaviyo-API-Key <key>`). */
|
|
56
|
+
| {
|
|
57
|
+
kind: "header";
|
|
58
|
+
secret: string;
|
|
59
|
+
header: string;
|
|
60
|
+
prefix?: string;
|
|
61
|
+
}
|
|
62
|
+
/** `?<param>=<key>` on the query string. */
|
|
63
|
+
| {
|
|
64
|
+
kind: "query";
|
|
65
|
+
secret: string;
|
|
66
|
+
param: string;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* `Authorization: Basic base64(user:password)`, the placement said
|
|
70
|
+
* outright, never guessed from the value: the secret is the password
|
|
71
|
+
* beside `user` (a literal, Mailgun's `api`; or `{ secret }`, a second
|
|
72
|
+
* Gateway setting, Twilio's SID), the username with an empty password
|
|
73
|
+
* (Segment, Mixpanel, Crisp), or the whole `login:password` pair, which
|
|
74
|
+
* may already be base64-encoded (DataForSEO's rule: a base64 string
|
|
75
|
+
* never holds a colon).
|
|
76
|
+
*/
|
|
77
|
+
| {
|
|
78
|
+
kind: "basic";
|
|
79
|
+
secret: string;
|
|
80
|
+
as: "password";
|
|
81
|
+
user: string | {
|
|
82
|
+
secret: string;
|
|
83
|
+
};
|
|
84
|
+
} | {
|
|
85
|
+
kind: "basic";
|
|
86
|
+
secret: string;
|
|
87
|
+
as: "username";
|
|
88
|
+
} | {
|
|
89
|
+
kind: "basic";
|
|
90
|
+
secret: string;
|
|
91
|
+
as: "pair";
|
|
92
|
+
};
|
|
93
|
+
/** What a provider says about one of its Gateway settings, for whoever sets it. */
|
|
94
|
+
export interface ProviderSecretDetail {
|
|
95
|
+
name: string;
|
|
96
|
+
/** What kind of key, in one sentence: "A restricted key with read access to Customers is enough." */
|
|
97
|
+
hint?: string;
|
|
98
|
+
}
|
|
99
|
+
/** What a call costs, for the usage counters and the setup text. */
|
|
100
|
+
export interface ProviderCost {
|
|
101
|
+
unit: "call" | "result" | "token";
|
|
102
|
+
usd?: number;
|
|
103
|
+
note?: string;
|
|
104
|
+
/**
|
|
105
|
+
* A top-level field of the provider's JSON answer that reports the
|
|
106
|
+
* call's cost in US dollars (DataForSEO's `cost`); read off the head of
|
|
107
|
+
* every answer and added to the usage counters. Absent: nothing is read.
|
|
108
|
+
*/
|
|
109
|
+
responseField?: string;
|
|
110
|
+
}
|
|
111
|
+
/** The provider's rate limits, as hints beside the counters. */
|
|
112
|
+
export interface ProviderRate {
|
|
113
|
+
perSecond?: number;
|
|
114
|
+
perMinute?: number;
|
|
115
|
+
perDay?: number;
|
|
116
|
+
note?: string;
|
|
117
|
+
}
|
|
118
|
+
/** One request that costs nothing, for a setup guide's Verify step. */
|
|
119
|
+
export interface SmokeRequest {
|
|
120
|
+
method: "GET" | "HEAD" | "POST";
|
|
121
|
+
/** One of the provider's hosts; the first when absent. */
|
|
122
|
+
host?: string;
|
|
123
|
+
path: string;
|
|
124
|
+
/** The statuses that mean the key works. */
|
|
125
|
+
expect: readonly number[];
|
|
126
|
+
free: boolean;
|
|
127
|
+
note?: string;
|
|
128
|
+
}
|
|
129
|
+
/** Whether somebody checked the entry against the provider's docs, and how. */
|
|
130
|
+
export type ProviderVerification = {
|
|
131
|
+
on: string;
|
|
132
|
+
how: "docs" | "live";
|
|
133
|
+
} | false;
|
|
134
|
+
/** What every provider may say about itself beyond what the gateway enforces. */
|
|
135
|
+
export interface ProviderDetails {
|
|
136
|
+
/** What it is for, in one line, for lists and agents. */
|
|
137
|
+
description?: string;
|
|
138
|
+
/** The API reference, when it isn't the `docs` page. */
|
|
139
|
+
api?: string;
|
|
140
|
+
/**
|
|
141
|
+
* The setup sentence the "Needs setup" dialog and `everyapp status` show
|
|
142
|
+
* when there is no guide, or beside one: what the key is and where it
|
|
143
|
+
* comes from, 1 to 3 sentences.
|
|
144
|
+
*/
|
|
145
|
+
hint?: string;
|
|
146
|
+
/** Detail per Gateway setting `auth` names. */
|
|
147
|
+
secrets?: readonly ProviderSecretDetail[];
|
|
148
|
+
/** What to say to an agent to try it, after "Use <name> to". */
|
|
149
|
+
example?: string;
|
|
150
|
+
cost?: ProviderCost;
|
|
151
|
+
rate?: ProviderRate;
|
|
152
|
+
verified?: ProviderVerification;
|
|
153
|
+
tags?: readonly string[];
|
|
154
|
+
}
|
|
155
|
+
export interface ApiKeyCapability extends ProviderDetails {
|
|
156
|
+
mode: "api_key";
|
|
157
|
+
/** The provider's name in errors and logs. */
|
|
158
|
+
label: string;
|
|
159
|
+
/** Where the key goes, and which Gateway setting holds it. */
|
|
160
|
+
auth: ApiKeyAuth;
|
|
161
|
+
/** Where an operator gets the key: the provider's API access page. */
|
|
162
|
+
docs: string;
|
|
163
|
+
/** The everyapp skill's setup guide for it, relative to the skill (`setup/dataforseo.md`); a row has none. */
|
|
164
|
+
setup?: string;
|
|
165
|
+
/** The only hosts the key is ever sent to, always over https; may be empty when `hostSetting` names the host. */
|
|
166
|
+
hosts: readonly string[];
|
|
167
|
+
/**
|
|
168
|
+
* A Gateway setting naming the provider's host, for a provider whose host
|
|
169
|
+
* is the operator's (Shopify's `<shop>.myshopify.com`): a bare host or an
|
|
170
|
+
* https origin with no path, held to the host rules when read
|
|
171
|
+
* ({@link apiKeyHosts}). Named after the provider like its key.
|
|
172
|
+
*/
|
|
173
|
+
hostSetting?: string;
|
|
174
|
+
/**
|
|
175
|
+
* Whose data the key reaches: `per-call` (search, scrape, inference:
|
|
176
|
+
* each call is its own) or `account` (every list is the whole account).
|
|
177
|
+
* A hosted gateway, where one key would be every tenant's, serves
|
|
178
|
+
* `account` providers to nobody until it holds per-organization keys.
|
|
179
|
+
*/
|
|
180
|
+
data?: "per-call" | "account";
|
|
181
|
+
/** The access levels the provider offers; the manifest may ask for these only. */
|
|
182
|
+
access: readonly CapabilityAccess[];
|
|
183
|
+
/** Methods an app asking for `access: "read"` may use. */
|
|
184
|
+
readMethods: readonly string[];
|
|
185
|
+
/** Methods an app asking for `access: "write"` may use besides, when the provider offers write; {@link DEFAULT_WRITE_METHODS} when absent. */
|
|
186
|
+
writeMethods?: readonly string[];
|
|
187
|
+
/**
|
|
188
|
+
* Paths no app may reach, each as its run of path segments, refused
|
|
189
|
+
* wherever those segments appear together in the upstream path however
|
|
190
|
+
* it is spelled (see {@link isAccountWidePath}). One key serves every app
|
|
191
|
+
* in every organization, so endpoints that list or describe the whole
|
|
192
|
+
* provider account would show one app another's work.
|
|
193
|
+
*/
|
|
194
|
+
accountWidePaths: readonly (readonly string[])[];
|
|
195
|
+
smoke?: SmokeRequest;
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* An AI provider (OpenAI, OpenRouter, Workers AI): the AI proxy's table as
|
|
199
|
+
* a catalog entry. The app's path is joined onto `origin` and `basePath`
|
|
200
|
+
* (with `{SETTING}` placeholders filled from the Gateway's settings, each
|
|
201
|
+
* URL-encoded) and must be one of `inferenceRoutes` (a POST), unless both
|
|
202
|
+
* the operator (`AI_PROXY_EXTRA_ROUTES`) and the app's manifest (`ai.routes`)
|
|
203
|
+
* allow more (`extraRoutes`). `unstoredRoutes` get `store: false`.
|
|
204
|
+
* `normalize` names the one response rewrite the gateway has.
|
|
205
|
+
*/
|
|
206
|
+
export interface AiProviderCapability extends ProviderDetails {
|
|
207
|
+
mode: "ai";
|
|
208
|
+
label: string;
|
|
209
|
+
/** Where the key goes: bearer for the three today; Anthropic's `x-api-key` header is a `header` kind. */
|
|
210
|
+
auth: ApiKeyAuth;
|
|
211
|
+
docs: string;
|
|
212
|
+
setup?: string;
|
|
213
|
+
/** `https://api.openai.com`. */
|
|
214
|
+
origin: string;
|
|
215
|
+
/** Gateway settings the URL needs besides the key (`CLOUDFLARE_ACCOUNT_ID`). */
|
|
216
|
+
alsoNeeds?: readonly string[];
|
|
217
|
+
/** Joined onto the origin before every path: `/client/v4/accounts/{CLOUDFLARE_ACCOUNT_ID}/ai`. */
|
|
218
|
+
basePath?: string;
|
|
219
|
+
inferenceRoutes: readonly string[];
|
|
220
|
+
unstoredRoutes?: readonly string[];
|
|
221
|
+
extraRoutes?: boolean;
|
|
222
|
+
normalize?: "workers-ai";
|
|
223
|
+
}
|
|
224
|
+
/** What `access: "write"` adds to a provider's read methods when its entry doesn't say. */
|
|
225
|
+
export declare const DEFAULT_WRITE_METHODS: readonly string[];
|
|
226
|
+
/**
|
|
227
|
+
* A capability the gateway performs itself, with no upstream host:
|
|
228
|
+
* reached at `/api/integrations/<id>/<route>`.
|
|
229
|
+
*/
|
|
230
|
+
export interface GatewayServiceCapability {
|
|
231
|
+
mode: "service";
|
|
232
|
+
/** The capability's name in errors and logs. */
|
|
233
|
+
label: string;
|
|
234
|
+
/** The access levels it offers; the manifest may ask for these only. */
|
|
235
|
+
access: readonly CapabilityAccess[];
|
|
236
|
+
/** Routes under `/api/integrations/<id>/`, each with the methods it takes. */
|
|
237
|
+
routes: Readonly<Record<string, readonly string[]>>;
|
|
238
|
+
/** The gateway settings that make it ready (status, the dev fallback). */
|
|
239
|
+
settings: readonly string[];
|
|
240
|
+
/** Settings it reads when set (another transport), ready or not. */
|
|
241
|
+
optionalSettings: readonly string[];
|
|
242
|
+
/** The everyapp skill's setup guide, when there is anything to set up. */
|
|
243
|
+
setup?: string;
|
|
244
|
+
}
|
|
245
|
+
/** Where the gateway puts an OAuth client on a token request. */
|
|
246
|
+
export type OAuthClientInjection = "form" | "basic" | "query" | "json";
|
|
247
|
+
/** A token endpoint an `oauth_client` capability completes, with its rule. */
|
|
248
|
+
export interface OAuthTokenEndpoint {
|
|
249
|
+
/**
|
|
250
|
+
* The endpoint's host, always over https. Absent: the host the
|
|
251
|
+
* capability's `hostSetting` names (an instance the operator chose).
|
|
252
|
+
*/
|
|
253
|
+
host?: string;
|
|
254
|
+
/** The exact pathname, or a RegExp for versioned ones (Meta's `/v25.0/oauth/access_token`). */
|
|
255
|
+
path: string | RegExp;
|
|
256
|
+
methods: readonly ("GET" | "POST")[];
|
|
257
|
+
/**
|
|
258
|
+
* Where the client goes: the form body, HTTP Basic, the query string, or
|
|
259
|
+
* the JSON body (injectClientCredentials() in ./oauthClient.ts).
|
|
260
|
+
*/
|
|
261
|
+
inject: OAuthClientInjection;
|
|
262
|
+
/** The fields' names when not `client_id` / `client_secret` (TikTok's `client_key`). */
|
|
263
|
+
params?: {
|
|
264
|
+
clientId?: string;
|
|
265
|
+
clientSecret?: string;
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* One host's allowlist a scope set unlocks. Matched against the raw
|
|
270
|
+
* pathname, case preserved, by `scopeRouteAllows()` in ./oauthScopes.ts:
|
|
271
|
+
* the proxy boundary once the gateway holds tokens, tested data until then.
|
|
272
|
+
*/
|
|
273
|
+
export interface OAuthScopeRoute {
|
|
274
|
+
/** A bare https host, one of the capability's `api` hosts. */
|
|
275
|
+
host: string;
|
|
276
|
+
/**
|
|
277
|
+
* Raw-path entries: exact, or a prefix when the entry ends in `/`. GET
|
|
278
|
+
* and HEAD go through when one matches.
|
|
279
|
+
*/
|
|
280
|
+
paths: readonly string[];
|
|
281
|
+
/**
|
|
282
|
+
* The read-shaped POSTs a read set allows (queries, watches): anchored,
|
|
283
|
+
* flagless RegExps over the raw pathname. Every other POST is refused.
|
|
284
|
+
*/
|
|
285
|
+
posts?: readonly RegExp[];
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* A named bundle an app lists under `scopes`: what it asks the provider for
|
|
289
|
+
* and what that unlocks.
|
|
290
|
+
*/
|
|
291
|
+
export interface OAuthScopeSet {
|
|
292
|
+
/** What Admin → Apps and a consent page call it: "Gmail (read-only)". */
|
|
293
|
+
label: string;
|
|
294
|
+
/**
|
|
295
|
+
* A read set unlocks GET, HEAD and its `posts` only. No write set exists
|
|
296
|
+
* on the shared clients yet; adding one is a reviewed registry change.
|
|
297
|
+
*/
|
|
298
|
+
access: CapabilityAccess;
|
|
299
|
+
/** The provider's scope strings, requested verbatim (Slack: bot scopes). */
|
|
300
|
+
scopes: readonly string[];
|
|
301
|
+
/** Slack's `user_scope` strings, issued to the installing person's own token; absent elsewhere. */
|
|
302
|
+
userScopes?: readonly string[];
|
|
303
|
+
routes: readonly OAuthScopeRoute[];
|
|
304
|
+
}
|
|
305
|
+
/** How a provider spells granted scopes in its token response; each has a parser in ./oauthScopes.ts. */
|
|
306
|
+
export type OAuthScopeDialect = "google" | "microsoft" | "slack";
|
|
307
|
+
/**
|
|
308
|
+
* Everything the gateway needs to hold an app to its scope sets at the
|
|
309
|
+
* token endpoint. Present means an app's entry must list `scopes` and the
|
|
310
|
+
* gateway refuses tokens outside them. Data only: the dialect selects the
|
|
311
|
+
* parser, so the registry stays a table.
|
|
312
|
+
*/
|
|
313
|
+
export interface OAuthScopePolicy {
|
|
314
|
+
sets: Readonly<Record<string, OAuthScopeSet>>;
|
|
315
|
+
/**
|
|
316
|
+
* Scopes a token may carry beyond the declared sets without refusal:
|
|
317
|
+
* identity and refresh scopes, in every spelling the provider uses.
|
|
318
|
+
* Never a data scope.
|
|
319
|
+
*/
|
|
320
|
+
tolerated: readonly string[];
|
|
321
|
+
/**
|
|
322
|
+
* Scopes every declaring app asks for whatever its sets, on the authorize
|
|
323
|
+
* URL and Microsoft's token leg (`offline_access`). Always tolerated.
|
|
324
|
+
*/
|
|
325
|
+
alwaysRequested: readonly string[];
|
|
326
|
+
dialect: OAuthScopeDialect;
|
|
327
|
+
/**
|
|
328
|
+
* The `tokenGrantType()` values the gateway completes through this
|
|
329
|
+
* client. `null` is a code exchange that carries no `grant_type` (Slack's
|
|
330
|
+
* oauth.v2.access).
|
|
331
|
+
*/
|
|
332
|
+
grantTypes: readonly (string | null)[];
|
|
333
|
+
/**
|
|
334
|
+
* What becomes of the token request's `scope` once it passes the check:
|
|
335
|
+
* `replace` it with the app's requested list (Microsoft's token-leg
|
|
336
|
+
* extension, which keeps a token to one resource), `drop` it (Google
|
|
337
|
+
* documents no `scope` on either token leg), or `keep` it (Slack).
|
|
338
|
+
*/
|
|
339
|
+
requestScope: "replace" | "drop" | "keep";
|
|
340
|
+
/**
|
|
341
|
+
* Decoded path segments no set unlocks on any host, compared
|
|
342
|
+
* case-insensitively: batch tunnels that carry other requests inside, and
|
|
343
|
+
* resources that reveal secrets under a read scope.
|
|
344
|
+
*/
|
|
345
|
+
deniedSegments: readonly string[];
|
|
346
|
+
}
|
|
347
|
+
/**
|
|
348
|
+
* A provider's OAuth client the gateway holds. The gateway completes its
|
|
349
|
+
* token endpoints only (`token`), putting the client on each request; the
|
|
350
|
+
* app builds the authorize URL from the public client id and calls the
|
|
351
|
+
* provider's API with the user tokens it keeps.
|
|
352
|
+
*/
|
|
353
|
+
export interface OAuthClientCapability {
|
|
354
|
+
mode: "oauth_client";
|
|
355
|
+
/** The provider's name in errors and logs. */
|
|
356
|
+
label: string;
|
|
357
|
+
/** Gateway secret names. No `clientSecret`: a public client, the id alone. */
|
|
358
|
+
secrets: {
|
|
359
|
+
clientId: string;
|
|
360
|
+
clientSecret?: string;
|
|
361
|
+
};
|
|
362
|
+
/** The only calls the gateway completes; anything else is refused. */
|
|
363
|
+
token: readonly OAuthTokenEndpoint[];
|
|
364
|
+
/**
|
|
365
|
+
* A gateway setting naming the provider's origin, for a provider with no
|
|
366
|
+
* fixed one (Mastodon's instance): the host of `token` entries without
|
|
367
|
+
* their own, and of the authorize URL.
|
|
368
|
+
*/
|
|
369
|
+
hostSetting?: string;
|
|
370
|
+
/** The origin when `hostSetting` is unset. */
|
|
371
|
+
defaultOrigin?: string;
|
|
372
|
+
/** Obtaining and refreshing user tokens with the operator's client writes. */
|
|
373
|
+
access: readonly ["write"];
|
|
374
|
+
/** Where the operator registers the client. */
|
|
375
|
+
console: string;
|
|
376
|
+
/** The everyapp skill's setup guide for the client, when one exists. */
|
|
377
|
+
setup?: string;
|
|
378
|
+
/**
|
|
379
|
+
* The authorize endpoint the app sends people to (a path on the
|
|
380
|
+
* `hostSetting` origin when the provider has none fixed) and the scopes
|
|
381
|
+
* the client must be allowed: the operator's checklist and the docs. With
|
|
382
|
+
* a `scopePolicy`, the union of its sets' scopes and `alwaysRequested`.
|
|
383
|
+
*/
|
|
384
|
+
authorize: {
|
|
385
|
+
url: string;
|
|
386
|
+
scopes: readonly string[];
|
|
387
|
+
};
|
|
388
|
+
/**
|
|
389
|
+
* Named scope sets an app lists in its manifest entry's `scopes`, for a
|
|
390
|
+
* client several apps share with different needs. Absent: the whole
|
|
391
|
+
* client is the grant, as for Postiz's social networks.
|
|
392
|
+
*/
|
|
393
|
+
scopePolicy?: OAuthScopePolicy;
|
|
394
|
+
/** Hosts the app calls afterwards with the user's token (docs only); a scope policy's routes are on them. */
|
|
395
|
+
api: readonly string[];
|
|
396
|
+
/**
|
|
397
|
+
* The redirect paths the operator registers, on the app's host
|
|
398
|
+
* (`https://<app>.<APP_BASE_DOMAIN><path>`): Postiz's callback pages, the
|
|
399
|
+
* first app to use these clients.
|
|
400
|
+
*/
|
|
401
|
+
redirectPaths: readonly string[];
|
|
402
|
+
}
|
|
403
|
+
export type Capability = ApiKeyCapability | AiProviderCapability | OAuthClientCapability | GatewayServiceCapability;
|
|
404
|
+
export declare const CAPABILITIES: {
|
|
405
|
+
readonly openai: {
|
|
406
|
+
readonly mode: "ai";
|
|
407
|
+
readonly label: "OpenAI";
|
|
408
|
+
readonly description: "OpenAI's models: responses, chat, embeddings, audio, images.";
|
|
409
|
+
readonly auth: {
|
|
410
|
+
readonly kind: "bearer";
|
|
411
|
+
readonly secret: "OPENAI_API_KEY";
|
|
412
|
+
};
|
|
413
|
+
readonly docs: "https://platform.openai.com/api-keys";
|
|
414
|
+
readonly api: "https://platform.openai.com/docs/api-reference";
|
|
415
|
+
readonly setup: "setup/openai.md";
|
|
416
|
+
readonly origin: "https://api.openai.com";
|
|
417
|
+
readonly inferenceRoutes: readonly ["/v1/responses", "/v1/chat/completions", "/v1/embeddings", "/v1/audio/speech", "/v1/audio/transcriptions", "/v1/audio/translations", "/v1/images/generations", "/v1/images/edits", "/v1/images/variations"];
|
|
418
|
+
readonly unstoredRoutes: readonly ["/v1/responses", "/v1/chat/completions"];
|
|
419
|
+
readonly extraRoutes: true;
|
|
420
|
+
readonly hint: "A secret key from the API keys page; the Gateway puts it on every call as a bearer token.";
|
|
421
|
+
readonly verified: {
|
|
422
|
+
readonly on: "2026-10-25";
|
|
423
|
+
readonly how: "live";
|
|
424
|
+
};
|
|
425
|
+
};
|
|
426
|
+
readonly openrouter: {
|
|
427
|
+
readonly mode: "ai";
|
|
428
|
+
readonly label: "OpenRouter";
|
|
429
|
+
readonly description: "One key for many models, through OpenAI's API shape.";
|
|
430
|
+
readonly auth: {
|
|
431
|
+
readonly kind: "bearer";
|
|
432
|
+
readonly secret: "OPENROUTER_API_KEY";
|
|
433
|
+
};
|
|
434
|
+
readonly docs: "https://openrouter.ai/settings/keys";
|
|
435
|
+
readonly api: "https://openrouter.ai/docs";
|
|
436
|
+
readonly setup: "setup/openrouter.md";
|
|
437
|
+
readonly origin: "https://openrouter.ai";
|
|
438
|
+
readonly inferenceRoutes: readonly ["/api/v1/chat/completions", "/api/v1/completions", "/api/v1/responses", "/api/v1/embeddings"];
|
|
439
|
+
readonly hint: "An API key from OpenRouter's keys page; the Gateway puts it on every call as a bearer token.";
|
|
440
|
+
readonly verified: {
|
|
441
|
+
readonly on: "2026-10-25";
|
|
442
|
+
readonly how: "live";
|
|
443
|
+
};
|
|
444
|
+
};
|
|
445
|
+
readonly "workers-ai": {
|
|
446
|
+
readonly mode: "ai";
|
|
447
|
+
readonly label: "Workers AI";
|
|
448
|
+
readonly description: "Cloudflare's models, in the Gateway's own account.";
|
|
449
|
+
readonly auth: {
|
|
450
|
+
readonly kind: "bearer";
|
|
451
|
+
readonly secret: "WORKERS_AI_API_TOKEN";
|
|
452
|
+
};
|
|
453
|
+
readonly docs: "https://dash.cloudflare.com/profile/api-tokens";
|
|
454
|
+
readonly api: "https://developers.cloudflare.com/workers-ai/";
|
|
455
|
+
readonly setup: "setup/workers-ai.md";
|
|
456
|
+
readonly origin: "https://api.cloudflare.com";
|
|
457
|
+
readonly alsoNeeds: readonly ["CLOUDFLARE_ACCOUNT_ID"];
|
|
458
|
+
readonly basePath: "/client/v4/accounts/{CLOUDFLARE_ACCOUNT_ID}/ai";
|
|
459
|
+
readonly inferenceRoutes: readonly ["/v1/chat/completions", "/v1/embeddings", "/v1/responses"];
|
|
460
|
+
readonly normalize: "workers-ai";
|
|
461
|
+
readonly hint: "A Cloudflare API token with Workers AI Read (the Workers AI page's prefilled token); the account is the Gateway's own.";
|
|
462
|
+
readonly verified: {
|
|
463
|
+
readonly on: "2026-10-25";
|
|
464
|
+
readonly how: "live";
|
|
465
|
+
};
|
|
466
|
+
};
|
|
467
|
+
readonly dataforseo: {
|
|
468
|
+
readonly mode: "api_key";
|
|
469
|
+
readonly label: "DataForSEO";
|
|
470
|
+
readonly description: "SEO data: keyword metrics, live search results, domain rankings, backlinks.";
|
|
471
|
+
readonly auth: {
|
|
472
|
+
readonly kind: "basic";
|
|
473
|
+
readonly secret: "DATAFORSEO_API_KEY";
|
|
474
|
+
readonly as: "pair";
|
|
475
|
+
};
|
|
476
|
+
readonly docs: "https://app.dataforseo.com/api-access";
|
|
477
|
+
readonly api: "https://docs.dataforseo.com/v3/";
|
|
478
|
+
readonly setup: "setup/dataforseo.md";
|
|
479
|
+
readonly hosts: readonly ["api.dataforseo.com", "sandbox.dataforseo.com"];
|
|
480
|
+
readonly access: readonly ["read"];
|
|
481
|
+
readonly readMethods: readonly ["GET", "POST"];
|
|
482
|
+
readonly accountWidePaths: readonly [readonly ["tasks_ready"], readonly ["tasks_fixed"], readonly ["id_list"], readonly ["errors"], readonly ["appendix", "user_data"], readonly ["appendix", "webhook_resend"]];
|
|
483
|
+
readonly hint: "The API login and password from API Access, as login:password (or that pair base64-encoded); the Gateway sends them as HTTP Basic.";
|
|
484
|
+
readonly secrets: readonly [{
|
|
485
|
+
readonly name: "DATAFORSEO_API_KEY";
|
|
486
|
+
readonly hint: "login:password, or its base64; never the dashboard sign-in password.";
|
|
487
|
+
}];
|
|
488
|
+
readonly cost: {
|
|
489
|
+
readonly unit: "call";
|
|
490
|
+
readonly responseField: "cost";
|
|
491
|
+
readonly note: "A Google SERP $0.002 per 10 results; a Labs task $0.012 plus $0.00012 per item.";
|
|
492
|
+
};
|
|
493
|
+
readonly smoke: {
|
|
494
|
+
readonly method: "GET";
|
|
495
|
+
readonly path: "/v3/appendix/user_data";
|
|
496
|
+
readonly expect: readonly [200];
|
|
497
|
+
readonly free: true;
|
|
498
|
+
readonly note: "Account-wide, so the Gateway refuses it for apps; run it from the person's terminal.";
|
|
499
|
+
};
|
|
500
|
+
readonly example: "find keyword ideas for a page about running shoes";
|
|
501
|
+
readonly verified: {
|
|
502
|
+
readonly on: "2026-10-25";
|
|
503
|
+
readonly how: "live";
|
|
504
|
+
};
|
|
505
|
+
};
|
|
506
|
+
readonly context: {
|
|
507
|
+
readonly mode: "api_key";
|
|
508
|
+
readonly label: "Context.dev";
|
|
509
|
+
readonly description: "Scrapes and renders web pages, JavaScript included.";
|
|
510
|
+
readonly auth: {
|
|
511
|
+
readonly kind: "bearer";
|
|
512
|
+
readonly secret: "CONTEXT_API_KEY";
|
|
513
|
+
};
|
|
514
|
+
readonly docs: "https://context.dev/";
|
|
515
|
+
readonly setup: "setup/context.md";
|
|
516
|
+
readonly hosts: readonly ["api.context.dev"];
|
|
517
|
+
readonly access: readonly ["read"];
|
|
518
|
+
readonly readMethods: readonly ["GET", "POST"];
|
|
519
|
+
readonly accountWidePaths: readonly [];
|
|
520
|
+
readonly hint: "An API key from the Context.dev dashboard; the Gateway puts it on every call as a bearer token.";
|
|
521
|
+
readonly verified: {
|
|
522
|
+
readonly on: "2026-10-25";
|
|
523
|
+
readonly how: "live";
|
|
524
|
+
};
|
|
525
|
+
};
|
|
526
|
+
readonly email: {
|
|
527
|
+
readonly mode: "service";
|
|
528
|
+
readonly label: "Email";
|
|
529
|
+
readonly access: readonly ["write"];
|
|
530
|
+
readonly routes: {
|
|
531
|
+
readonly send: readonly ["POST"];
|
|
532
|
+
};
|
|
533
|
+
readonly settings: readonly ["EMAIL_FROM", "EMAIL_FROM_NAME"];
|
|
534
|
+
readonly optionalSettings: readonly ["EMAIL_REST_API_TOKEN", "CLOUDFLARE_ACCOUNT_ID", "RESEND_API_KEY", "EMAIL_PROVIDER"];
|
|
535
|
+
readonly setup: "setup/email.md";
|
|
536
|
+
};
|
|
537
|
+
readonly members: {
|
|
538
|
+
readonly mode: "service";
|
|
539
|
+
readonly label: "Members";
|
|
540
|
+
readonly access: readonly ["read"];
|
|
541
|
+
readonly routes: {
|
|
542
|
+
readonly list: readonly ["GET"];
|
|
543
|
+
};
|
|
544
|
+
readonly settings: readonly [];
|
|
545
|
+
readonly optionalSettings: readonly [];
|
|
546
|
+
};
|
|
547
|
+
readonly linkedin: {
|
|
548
|
+
readonly mode: "oauth_client";
|
|
549
|
+
readonly label: "LinkedIn";
|
|
550
|
+
readonly secrets: {
|
|
551
|
+
readonly clientId: "LINKEDIN_CLIENT_ID";
|
|
552
|
+
readonly clientSecret: "LINKEDIN_CLIENT_SECRET";
|
|
553
|
+
};
|
|
554
|
+
readonly token: readonly [{
|
|
555
|
+
readonly host: "www.linkedin.com";
|
|
556
|
+
readonly path: "/oauth/v2/accessToken";
|
|
557
|
+
readonly methods: readonly ["POST"];
|
|
558
|
+
readonly inject: "form";
|
|
559
|
+
}];
|
|
560
|
+
readonly access: readonly ["write"];
|
|
561
|
+
readonly console: "https://www.linkedin.com/developers/apps";
|
|
562
|
+
readonly authorize: {
|
|
563
|
+
readonly url: "https://www.linkedin.com/oauth/v2/authorization";
|
|
564
|
+
readonly scopes: readonly ["openid", "profile", "w_member_social", "r_basicprofile", "rw_organization_admin", "w_organization_social", "r_organization_social"];
|
|
565
|
+
};
|
|
566
|
+
readonly api: readonly ["api.linkedin.com"];
|
|
567
|
+
readonly redirectPaths: readonly ["/integrations/social/linkedin", "/integrations/social/linkedin-page"];
|
|
568
|
+
};
|
|
569
|
+
readonly facebook: {
|
|
570
|
+
readonly mode: "oauth_client";
|
|
571
|
+
readonly label: "Facebook";
|
|
572
|
+
readonly secrets: {
|
|
573
|
+
readonly clientId: "FACEBOOK_APP_ID";
|
|
574
|
+
readonly clientSecret: "FACEBOOK_APP_SECRET";
|
|
575
|
+
};
|
|
576
|
+
readonly token: readonly [{
|
|
577
|
+
readonly host: "graph.facebook.com";
|
|
578
|
+
readonly path: RegExp;
|
|
579
|
+
readonly methods: readonly ["GET", "POST"];
|
|
580
|
+
readonly inject: "query";
|
|
581
|
+
}];
|
|
582
|
+
readonly access: readonly ["write"];
|
|
583
|
+
readonly console: "https://developers.facebook.com/apps";
|
|
584
|
+
readonly authorize: {
|
|
585
|
+
readonly url: "https://www.facebook.com/v25.0/dialog/oauth";
|
|
586
|
+
readonly scopes: readonly ["pages_show_list", "business_management", "pages_manage_posts", "pages_manage_engagement", "pages_read_engagement", "read_insights", "instagram_basic", "instagram_content_publish", "instagram_manage_comments", "instagram_manage_insights"];
|
|
587
|
+
};
|
|
588
|
+
readonly api: readonly ["graph.facebook.com", "graph.instagram.com"];
|
|
589
|
+
readonly redirectPaths: readonly ["/integrations/social/facebook", "/integrations/social/instagram"];
|
|
590
|
+
};
|
|
591
|
+
readonly instagram: {
|
|
592
|
+
readonly mode: "oauth_client";
|
|
593
|
+
readonly label: "Instagram";
|
|
594
|
+
readonly secrets: {
|
|
595
|
+
readonly clientId: "INSTAGRAM_APP_ID";
|
|
596
|
+
readonly clientSecret: "INSTAGRAM_APP_SECRET";
|
|
597
|
+
};
|
|
598
|
+
readonly token: readonly [{
|
|
599
|
+
readonly host: "api.instagram.com";
|
|
600
|
+
readonly path: "/oauth/access_token";
|
|
601
|
+
readonly methods: readonly ["POST"];
|
|
602
|
+
readonly inject: "form";
|
|
603
|
+
}, {
|
|
604
|
+
readonly host: "graph.instagram.com";
|
|
605
|
+
readonly path: "/access_token";
|
|
606
|
+
readonly methods: readonly ["GET"];
|
|
607
|
+
readonly inject: "query";
|
|
608
|
+
}];
|
|
609
|
+
readonly access: readonly ["write"];
|
|
610
|
+
readonly console: "https://developers.facebook.com/apps";
|
|
611
|
+
readonly authorize: {
|
|
612
|
+
readonly url: "https://www.instagram.com/oauth/authorize";
|
|
613
|
+
readonly scopes: readonly ["instagram_business_basic", "instagram_business_content_publish", "instagram_business_manage_comments", "instagram_business_manage_insights"];
|
|
614
|
+
};
|
|
615
|
+
readonly api: readonly ["graph.instagram.com"];
|
|
616
|
+
readonly redirectPaths: readonly ["/integrations/social/instagram-standalone"];
|
|
617
|
+
};
|
|
618
|
+
readonly threads: {
|
|
619
|
+
readonly mode: "oauth_client";
|
|
620
|
+
readonly label: "Threads";
|
|
621
|
+
readonly secrets: {
|
|
622
|
+
readonly clientId: "THREADS_APP_ID";
|
|
623
|
+
readonly clientSecret: "THREADS_APP_SECRET";
|
|
624
|
+
};
|
|
625
|
+
readonly token: readonly [{
|
|
626
|
+
readonly host: "graph.threads.net";
|
|
627
|
+
readonly path: "/oauth/access_token";
|
|
628
|
+
readonly methods: readonly ["GET", "POST"];
|
|
629
|
+
readonly inject: "query";
|
|
630
|
+
}, {
|
|
631
|
+
readonly host: "graph.threads.net";
|
|
632
|
+
readonly path: "/access_token";
|
|
633
|
+
readonly methods: readonly ["GET"];
|
|
634
|
+
readonly inject: "query";
|
|
635
|
+
}];
|
|
636
|
+
readonly access: readonly ["write"];
|
|
637
|
+
readonly console: "https://developers.facebook.com/apps";
|
|
638
|
+
readonly authorize: {
|
|
639
|
+
readonly url: "https://threads.net/oauth/authorize";
|
|
640
|
+
readonly scopes: readonly ["threads_basic", "threads_content_publish", "threads_manage_replies", "threads_manage_insights"];
|
|
641
|
+
};
|
|
642
|
+
readonly api: readonly ["graph.threads.net"];
|
|
643
|
+
readonly redirectPaths: readonly ["/integrations/social/threads"];
|
|
644
|
+
};
|
|
645
|
+
readonly youtube: {
|
|
646
|
+
readonly mode: "oauth_client";
|
|
647
|
+
readonly label: "YouTube";
|
|
648
|
+
readonly secrets: {
|
|
649
|
+
readonly clientId: "YOUTUBE_CLIENT_ID";
|
|
650
|
+
readonly clientSecret: "YOUTUBE_CLIENT_SECRET";
|
|
651
|
+
};
|
|
652
|
+
readonly token: readonly [{
|
|
653
|
+
readonly host: "oauth2.googleapis.com";
|
|
654
|
+
readonly path: "/token";
|
|
655
|
+
readonly methods: readonly ["POST"];
|
|
656
|
+
readonly inject: "form";
|
|
657
|
+
}];
|
|
658
|
+
readonly access: readonly ["write"];
|
|
659
|
+
readonly console: "https://console.cloud.google.com/apis/credentials";
|
|
660
|
+
readonly setup: "setup/google.md";
|
|
661
|
+
readonly authorize: {
|
|
662
|
+
readonly url: "https://accounts.google.com/o/oauth2/v2/auth";
|
|
663
|
+
readonly scopes: readonly ["https://www.googleapis.com/auth/userinfo.profile", "https://www.googleapis.com/auth/userinfo.email", "https://www.googleapis.com/auth/youtube", "https://www.googleapis.com/auth/youtube.force-ssl", "https://www.googleapis.com/auth/youtube.readonly", "https://www.googleapis.com/auth/youtube.upload", "https://www.googleapis.com/auth/youtubepartner", "https://www.googleapis.com/auth/yt-analytics.readonly", "https://www.googleapis.com/auth/business.manage"];
|
|
664
|
+
};
|
|
665
|
+
readonly api: readonly ["www.googleapis.com", "youtubeanalytics.googleapis.com", "mybusinessaccountmanagement.googleapis.com", "mybusinessbusinessinformation.googleapis.com", "mybusiness.googleapis.com", "businessprofileperformance.googleapis.com"];
|
|
666
|
+
readonly redirectPaths: readonly ["/integrations/social/youtube", "/integrations/social/gmb"];
|
|
667
|
+
};
|
|
668
|
+
readonly tiktok: {
|
|
669
|
+
readonly mode: "oauth_client";
|
|
670
|
+
readonly label: "TikTok";
|
|
671
|
+
readonly secrets: {
|
|
672
|
+
readonly clientId: "TIKTOK_CLIENT_ID";
|
|
673
|
+
readonly clientSecret: "TIKTOK_CLIENT_SECRET";
|
|
674
|
+
};
|
|
675
|
+
readonly token: readonly [{
|
|
676
|
+
readonly host: "open.tiktokapis.com";
|
|
677
|
+
readonly path: "/v2/oauth/token/";
|
|
678
|
+
readonly methods: readonly ["POST"];
|
|
679
|
+
readonly inject: "form";
|
|
680
|
+
readonly params: {
|
|
681
|
+
readonly clientId: "client_key";
|
|
682
|
+
};
|
|
683
|
+
}];
|
|
684
|
+
readonly access: readonly ["write"];
|
|
685
|
+
readonly console: "https://developers.tiktok.com/apps";
|
|
686
|
+
readonly authorize: {
|
|
687
|
+
readonly url: "https://www.tiktok.com/v2/auth/authorize/";
|
|
688
|
+
readonly scopes: readonly ["video.list", "user.info.basic", "video.publish", "video.upload", "user.info.profile", "user.info.stats"];
|
|
689
|
+
};
|
|
690
|
+
readonly api: readonly ["open.tiktokapis.com"];
|
|
691
|
+
readonly redirectPaths: readonly ["/integrations/social/tiktok"];
|
|
692
|
+
};
|
|
693
|
+
readonly "tiktok-business": {
|
|
694
|
+
readonly mode: "oauth_client";
|
|
695
|
+
readonly label: "TikTok Business";
|
|
696
|
+
readonly secrets: {
|
|
697
|
+
readonly clientId: "TIKTOK_BUSINESS_CLIENT_ID";
|
|
698
|
+
readonly clientSecret: "TIKTOK_BUSINESS_CLIENT_SECRET";
|
|
699
|
+
};
|
|
700
|
+
readonly token: readonly [{
|
|
701
|
+
readonly host: "business-api.tiktok.com";
|
|
702
|
+
readonly path: "/open_api/v1.3/tt_user/oauth2/token/";
|
|
703
|
+
readonly methods: readonly ["POST"];
|
|
704
|
+
readonly inject: "json";
|
|
705
|
+
}, {
|
|
706
|
+
readonly host: "business-api.tiktok.com";
|
|
707
|
+
readonly path: "/open_api/v1.3/tt_user/oauth2/refresh_token/";
|
|
708
|
+
readonly methods: readonly ["POST"];
|
|
709
|
+
readonly inject: "json";
|
|
710
|
+
}];
|
|
711
|
+
readonly access: readonly ["write"];
|
|
712
|
+
readonly console: "https://business-api.tiktok.com/portal/apps";
|
|
713
|
+
readonly authorize: {
|
|
714
|
+
readonly url: "https://www.tiktok.com/v2/auth/authorize/";
|
|
715
|
+
readonly scopes: readonly ["user.info.basic", "user.info.username", "user.info.stats", "video.list", "video.upload", "video.publish"];
|
|
716
|
+
};
|
|
717
|
+
readonly api: readonly ["business-api.tiktok.com"];
|
|
718
|
+
readonly redirectPaths: readonly ["/integrations/social/tiktok-business/"];
|
|
719
|
+
};
|
|
720
|
+
readonly reddit: {
|
|
721
|
+
readonly mode: "oauth_client";
|
|
722
|
+
readonly label: "Reddit";
|
|
723
|
+
readonly secrets: {
|
|
724
|
+
readonly clientId: "REDDIT_CLIENT_ID";
|
|
725
|
+
readonly clientSecret: "REDDIT_CLIENT_SECRET";
|
|
726
|
+
};
|
|
727
|
+
readonly token: readonly [{
|
|
728
|
+
readonly host: "www.reddit.com";
|
|
729
|
+
readonly path: "/api/v1/access_token";
|
|
730
|
+
readonly methods: readonly ["POST"];
|
|
731
|
+
readonly inject: "basic";
|
|
732
|
+
}];
|
|
733
|
+
readonly access: readonly ["write"];
|
|
734
|
+
readonly console: "https://www.reddit.com/prefs/apps";
|
|
735
|
+
readonly authorize: {
|
|
736
|
+
readonly url: "https://www.reddit.com/api/v1/authorize";
|
|
737
|
+
readonly scopes: readonly ["read", "identity", "submit", "flair"];
|
|
738
|
+
};
|
|
739
|
+
readonly api: readonly ["oauth.reddit.com"];
|
|
740
|
+
readonly redirectPaths: readonly ["/integrations/social/reddit"];
|
|
741
|
+
};
|
|
742
|
+
readonly pinterest: {
|
|
743
|
+
readonly mode: "oauth_client";
|
|
744
|
+
readonly label: "Pinterest";
|
|
745
|
+
readonly secrets: {
|
|
746
|
+
readonly clientId: "PINTEREST_CLIENT_ID";
|
|
747
|
+
readonly clientSecret: "PINTEREST_CLIENT_SECRET";
|
|
748
|
+
};
|
|
749
|
+
readonly token: readonly [{
|
|
750
|
+
readonly host: "api.pinterest.com";
|
|
751
|
+
readonly path: "/v5/oauth/token";
|
|
752
|
+
readonly methods: readonly ["POST"];
|
|
753
|
+
readonly inject: "basic";
|
|
754
|
+
}];
|
|
755
|
+
readonly access: readonly ["write"];
|
|
756
|
+
readonly console: "https://developers.pinterest.com/apps/";
|
|
757
|
+
readonly authorize: {
|
|
758
|
+
readonly url: "https://www.pinterest.com/oauth/";
|
|
759
|
+
readonly scopes: readonly ["boards:read", "boards:write", "pins:read", "pins:write", "user_accounts:read"];
|
|
760
|
+
};
|
|
761
|
+
readonly api: readonly ["api.pinterest.com"];
|
|
762
|
+
readonly redirectPaths: readonly ["/integrations/social/pinterest"];
|
|
763
|
+
};
|
|
764
|
+
readonly discord: {
|
|
765
|
+
readonly mode: "oauth_client";
|
|
766
|
+
readonly label: "Discord";
|
|
767
|
+
readonly secrets: {
|
|
768
|
+
readonly clientId: "DISCORD_CLIENT_ID";
|
|
769
|
+
readonly clientSecret: "DISCORD_CLIENT_SECRET";
|
|
770
|
+
};
|
|
771
|
+
readonly token: readonly [{
|
|
772
|
+
readonly host: "discord.com";
|
|
773
|
+
readonly path: "/api/oauth2/token";
|
|
774
|
+
readonly methods: readonly ["POST"];
|
|
775
|
+
readonly inject: "basic";
|
|
776
|
+
}];
|
|
777
|
+
readonly access: readonly ["write"];
|
|
778
|
+
readonly console: "https://discord.com/developers/applications";
|
|
779
|
+
readonly authorize: {
|
|
780
|
+
readonly url: "https://discord.com/oauth2/authorize";
|
|
781
|
+
readonly scopes: readonly ["bot", "identify", "guilds"];
|
|
782
|
+
};
|
|
783
|
+
readonly api: readonly ["discord.com"];
|
|
784
|
+
readonly redirectPaths: readonly ["/integrations/social/discord"];
|
|
785
|
+
};
|
|
786
|
+
readonly slack: {
|
|
787
|
+
readonly mode: "oauth_client";
|
|
788
|
+
readonly label: "Slack";
|
|
789
|
+
readonly secrets: {
|
|
790
|
+
readonly clientId: "SLACK_CLIENT_ID";
|
|
791
|
+
readonly clientSecret: "SLACK_CLIENT_SECRET";
|
|
792
|
+
};
|
|
793
|
+
readonly token: readonly [{
|
|
794
|
+
readonly host: "slack.com";
|
|
795
|
+
readonly path: "/api/oauth.v2.access";
|
|
796
|
+
readonly methods: readonly ["POST"];
|
|
797
|
+
readonly inject: "form";
|
|
798
|
+
}];
|
|
799
|
+
readonly access: readonly ["write"];
|
|
800
|
+
readonly console: "https://api.slack.com/apps";
|
|
801
|
+
readonly setup: "setup/slack.md";
|
|
802
|
+
readonly authorize: {
|
|
803
|
+
readonly url: "https://slack.com/oauth/v2/authorize";
|
|
804
|
+
readonly scopes: readonly ["channels:read", "groups:read", "users:read", "users:read.email", "chat:write", "chat:write.public", "chat:write.customize", "channels:join", "channels:manage", "groups:write", "channels:write.invites", "groups:write.invites", "im:write", "files:write", "channels:write"];
|
|
805
|
+
};
|
|
806
|
+
readonly scopePolicy: {
|
|
807
|
+
readonly dialect: "slack";
|
|
808
|
+
readonly grantTypes: readonly [null, "refresh_token"];
|
|
809
|
+
readonly requestScope: "keep";
|
|
810
|
+
readonly alwaysRequested: readonly [];
|
|
811
|
+
readonly tolerated: readonly [];
|
|
812
|
+
readonly deniedSegments: readonly [];
|
|
813
|
+
readonly sets: {
|
|
814
|
+
readonly "channels.read": {
|
|
815
|
+
readonly label: "Channels (read-only)";
|
|
816
|
+
readonly access: "read";
|
|
817
|
+
readonly scopes: readonly ["channels:read", "groups:read"];
|
|
818
|
+
readonly routes: readonly [{
|
|
819
|
+
readonly host: "slack.com";
|
|
820
|
+
readonly paths: readonly ["/api/conversations.list", "/api/conversations.info", "/api/conversations.members", "/api/users.conversations"];
|
|
821
|
+
readonly posts: readonly [RegExp, RegExp];
|
|
822
|
+
}];
|
|
823
|
+
};
|
|
824
|
+
readonly "users.read": {
|
|
825
|
+
readonly label: "Members (read-only)";
|
|
826
|
+
readonly access: "read";
|
|
827
|
+
readonly scopes: readonly ["users:read"];
|
|
828
|
+
readonly routes: readonly [{
|
|
829
|
+
readonly host: "slack.com";
|
|
830
|
+
readonly paths: readonly ["/api/users.list", "/api/users.info", "/api/users.getPresence", "/api/bots.info"];
|
|
831
|
+
readonly posts: readonly [RegExp, RegExp];
|
|
832
|
+
}];
|
|
833
|
+
};
|
|
834
|
+
readonly "users.email": {
|
|
835
|
+
readonly label: "Members' email addresses (read-only)";
|
|
836
|
+
readonly access: "read";
|
|
837
|
+
readonly scopes: readonly ["users:read.email"];
|
|
838
|
+
readonly routes: readonly [{
|
|
839
|
+
readonly host: "slack.com";
|
|
840
|
+
readonly paths: readonly ["/api/users.lookupByEmail"];
|
|
841
|
+
readonly posts: readonly [RegExp];
|
|
842
|
+
}];
|
|
843
|
+
};
|
|
844
|
+
readonly "messages.write": {
|
|
845
|
+
readonly label: "Messages (post as the app)";
|
|
846
|
+
readonly access: "write";
|
|
847
|
+
readonly scopes: readonly ["chat:write", "chat:write.public", "chat:write.customize"];
|
|
848
|
+
readonly routes: readonly [{
|
|
849
|
+
readonly host: "slack.com";
|
|
850
|
+
readonly paths: readonly ["/api/chat.scheduledMessages.list"];
|
|
851
|
+
readonly posts: readonly [RegExp];
|
|
852
|
+
}];
|
|
853
|
+
};
|
|
854
|
+
readonly "channels.join": {
|
|
855
|
+
readonly label: "Channels (join public ones)";
|
|
856
|
+
readonly access: "write";
|
|
857
|
+
readonly scopes: readonly ["channels:join"];
|
|
858
|
+
readonly routes: readonly [{
|
|
859
|
+
readonly host: "slack.com";
|
|
860
|
+
readonly paths: readonly [];
|
|
861
|
+
readonly posts: readonly [RegExp];
|
|
862
|
+
}];
|
|
863
|
+
};
|
|
864
|
+
readonly "channels.manage": {
|
|
865
|
+
readonly label: "Channels (create, manage and invite to; open DMs)";
|
|
866
|
+
readonly access: "write";
|
|
867
|
+
readonly scopes: readonly ["channels:manage", "groups:write", "channels:write.invites", "groups:write.invites", "im:write"];
|
|
868
|
+
readonly routes: readonly [{
|
|
869
|
+
readonly host: "slack.com";
|
|
870
|
+
readonly paths: readonly [];
|
|
871
|
+
readonly posts: readonly [RegExp];
|
|
872
|
+
}];
|
|
873
|
+
};
|
|
874
|
+
readonly "files.write": {
|
|
875
|
+
readonly label: "Files (upload)";
|
|
876
|
+
readonly access: "write";
|
|
877
|
+
readonly scopes: readonly ["files:write"];
|
|
878
|
+
readonly routes: readonly [{
|
|
879
|
+
readonly host: "slack.com";
|
|
880
|
+
readonly paths: readonly [];
|
|
881
|
+
readonly posts: readonly [RegExp];
|
|
882
|
+
}];
|
|
883
|
+
};
|
|
884
|
+
readonly "user-channels.manage": {
|
|
885
|
+
readonly label: "Channels (as the installing person: read, manage, invite to)";
|
|
886
|
+
readonly access: "write";
|
|
887
|
+
readonly scopes: readonly [];
|
|
888
|
+
readonly userScopes: readonly ["channels:read", "channels:write", "groups:read", "groups:write"];
|
|
889
|
+
readonly routes: readonly [{
|
|
890
|
+
readonly host: "slack.com";
|
|
891
|
+
readonly paths: readonly ["/api/conversations.list", "/api/conversations.info", "/api/conversations.members", "/api/users.conversations"];
|
|
892
|
+
readonly posts: readonly [RegExp, RegExp];
|
|
893
|
+
}];
|
|
894
|
+
};
|
|
895
|
+
};
|
|
896
|
+
};
|
|
897
|
+
readonly api: readonly ["slack.com"];
|
|
898
|
+
readonly redirectPaths: readonly ["/integrations/social/slack", "/integrations/slack/callback"];
|
|
899
|
+
};
|
|
900
|
+
readonly mastodon: {
|
|
901
|
+
readonly mode: "oauth_client";
|
|
902
|
+
readonly label: "Mastodon";
|
|
903
|
+
readonly secrets: {
|
|
904
|
+
readonly clientId: "MASTODON_CLIENT_ID";
|
|
905
|
+
readonly clientSecret: "MASTODON_CLIENT_SECRET";
|
|
906
|
+
};
|
|
907
|
+
readonly token: readonly [{
|
|
908
|
+
readonly path: "/oauth/token";
|
|
909
|
+
readonly methods: readonly ["POST"];
|
|
910
|
+
readonly inject: "form";
|
|
911
|
+
}];
|
|
912
|
+
readonly hostSetting: "MASTODON_URL";
|
|
913
|
+
readonly defaultOrigin: "https://mastodon.social";
|
|
914
|
+
readonly access: readonly ["write"];
|
|
915
|
+
readonly console: "/settings/applications";
|
|
916
|
+
readonly authorize: {
|
|
917
|
+
readonly url: "/oauth/authorize";
|
|
918
|
+
readonly scopes: readonly ["write:statuses", "profile", "write:media"];
|
|
919
|
+
};
|
|
920
|
+
readonly api: readonly [];
|
|
921
|
+
readonly redirectPaths: readonly ["/integrations/social/mastodon"];
|
|
922
|
+
};
|
|
923
|
+
readonly kick: {
|
|
924
|
+
readonly mode: "oauth_client";
|
|
925
|
+
readonly label: "Kick";
|
|
926
|
+
readonly secrets: {
|
|
927
|
+
readonly clientId: "KICK_CLIENT_ID";
|
|
928
|
+
readonly clientSecret: "KICK_CLIENT_SECRET";
|
|
929
|
+
};
|
|
930
|
+
readonly token: readonly [{
|
|
931
|
+
readonly host: "id.kick.com";
|
|
932
|
+
readonly path: "/oauth/token";
|
|
933
|
+
readonly methods: readonly ["POST"];
|
|
934
|
+
readonly inject: "form";
|
|
935
|
+
}];
|
|
936
|
+
readonly access: readonly ["write"];
|
|
937
|
+
readonly console: "https://kick.com/settings/developer";
|
|
938
|
+
readonly authorize: {
|
|
939
|
+
readonly url: "https://id.kick.com/oauth/authorize";
|
|
940
|
+
readonly scopes: readonly ["chat:write", "user:read", "channel:read"];
|
|
941
|
+
};
|
|
942
|
+
readonly api: readonly ["api.kick.com"];
|
|
943
|
+
readonly redirectPaths: readonly ["/integrations/social/kick"];
|
|
944
|
+
};
|
|
945
|
+
readonly twitch: {
|
|
946
|
+
readonly mode: "oauth_client";
|
|
947
|
+
readonly label: "Twitch";
|
|
948
|
+
readonly secrets: {
|
|
949
|
+
readonly clientId: "TWITCH_CLIENT_ID";
|
|
950
|
+
readonly clientSecret: "TWITCH_CLIENT_SECRET";
|
|
951
|
+
};
|
|
952
|
+
readonly token: readonly [{
|
|
953
|
+
readonly host: "id.twitch.tv";
|
|
954
|
+
readonly path: "/oauth2/token";
|
|
955
|
+
readonly methods: readonly ["POST"];
|
|
956
|
+
readonly inject: "form";
|
|
957
|
+
}];
|
|
958
|
+
readonly access: readonly ["write"];
|
|
959
|
+
readonly console: "https://dev.twitch.tv/console/apps";
|
|
960
|
+
readonly authorize: {
|
|
961
|
+
readonly url: "https://id.twitch.tv/oauth2/authorize";
|
|
962
|
+
readonly scopes: readonly ["user:write:chat", "user:read:chat", "moderator:manage:announcements"];
|
|
963
|
+
};
|
|
964
|
+
readonly api: readonly ["api.twitch.tv"];
|
|
965
|
+
readonly redirectPaths: readonly ["/integrations/social/twitch"];
|
|
966
|
+
};
|
|
967
|
+
readonly tumblr: {
|
|
968
|
+
readonly mode: "oauth_client";
|
|
969
|
+
readonly label: "Tumblr";
|
|
970
|
+
readonly secrets: {
|
|
971
|
+
readonly clientId: "TUMBLR_CLIENT_ID";
|
|
972
|
+
readonly clientSecret: "TUMBLR_CLIENT_SECRET";
|
|
973
|
+
};
|
|
974
|
+
readonly token: readonly [{
|
|
975
|
+
readonly host: "api.tumblr.com";
|
|
976
|
+
readonly path: "/v2/oauth2/token";
|
|
977
|
+
readonly methods: readonly ["POST"];
|
|
978
|
+
readonly inject: "form";
|
|
979
|
+
}];
|
|
980
|
+
readonly access: readonly ["write"];
|
|
981
|
+
readonly console: "https://www.tumblr.com/oauth/apps";
|
|
982
|
+
readonly authorize: {
|
|
983
|
+
readonly url: "https://www.tumblr.com/oauth2/authorize";
|
|
984
|
+
readonly scopes: readonly ["write", "offline_access"];
|
|
985
|
+
};
|
|
986
|
+
readonly api: readonly ["api.tumblr.com"];
|
|
987
|
+
readonly redirectPaths: readonly ["/integrations/social/tumblr"];
|
|
988
|
+
};
|
|
989
|
+
readonly dribbble: {
|
|
990
|
+
readonly mode: "oauth_client";
|
|
991
|
+
readonly label: "Dribbble";
|
|
992
|
+
readonly secrets: {
|
|
993
|
+
readonly clientId: "DRIBBBLE_CLIENT_ID";
|
|
994
|
+
readonly clientSecret: "DRIBBBLE_CLIENT_SECRET";
|
|
995
|
+
};
|
|
996
|
+
readonly token: readonly [{
|
|
997
|
+
readonly host: "dribbble.com";
|
|
998
|
+
readonly path: "/oauth/token";
|
|
999
|
+
readonly methods: readonly ["POST"];
|
|
1000
|
+
readonly inject: "query";
|
|
1001
|
+
}];
|
|
1002
|
+
readonly access: readonly ["write"];
|
|
1003
|
+
readonly console: "https://dribbble.com/account/applications";
|
|
1004
|
+
readonly authorize: {
|
|
1005
|
+
readonly url: "https://dribbble.com/oauth/authorize";
|
|
1006
|
+
readonly scopes: readonly ["public", "upload"];
|
|
1007
|
+
};
|
|
1008
|
+
readonly api: readonly ["api.dribbble.com"];
|
|
1009
|
+
readonly redirectPaths: readonly ["/integrations/social/dribbble"];
|
|
1010
|
+
};
|
|
1011
|
+
readonly "google-workspace": {
|
|
1012
|
+
readonly mode: "oauth_client";
|
|
1013
|
+
readonly label: "Google (Gmail, Calendar, Search Console and Analytics)";
|
|
1014
|
+
readonly secrets: {
|
|
1015
|
+
readonly clientId: "GOOGLE_WORKSPACE_CLIENT_ID";
|
|
1016
|
+
readonly clientSecret: "GOOGLE_WORKSPACE_CLIENT_SECRET";
|
|
1017
|
+
};
|
|
1018
|
+
readonly token: readonly [{
|
|
1019
|
+
readonly host: "oauth2.googleapis.com";
|
|
1020
|
+
readonly path: "/token";
|
|
1021
|
+
readonly methods: readonly ["POST"];
|
|
1022
|
+
readonly inject: "form";
|
|
1023
|
+
}];
|
|
1024
|
+
readonly access: readonly ["write"];
|
|
1025
|
+
readonly console: "https://console.cloud.google.com/apis/credentials";
|
|
1026
|
+
readonly setup: "setup/google.md";
|
|
1027
|
+
readonly authorize: {
|
|
1028
|
+
readonly url: "https://accounts.google.com/o/oauth2/v2/auth";
|
|
1029
|
+
readonly scopes: readonly ["openid", "email", "profile", "https://www.googleapis.com/auth/gmail.readonly", "https://www.googleapis.com/auth/calendar.readonly", "https://www.googleapis.com/auth/webmasters.readonly", "https://www.googleapis.com/auth/analytics.readonly"];
|
|
1030
|
+
};
|
|
1031
|
+
readonly scopePolicy: {
|
|
1032
|
+
readonly dialect: "google";
|
|
1033
|
+
readonly grantTypes: readonly ["authorization_code", "refresh_token"];
|
|
1034
|
+
readonly requestScope: "drop";
|
|
1035
|
+
readonly alwaysRequested: readonly [];
|
|
1036
|
+
readonly tolerated: readonly ["openid", "email", "profile", "https://www.googleapis.com/auth/userinfo.email", "https://www.googleapis.com/auth/userinfo.profile"];
|
|
1037
|
+
readonly deniedSegments: readonly ["batch", "measurementProtocolSecrets"];
|
|
1038
|
+
readonly sets: {
|
|
1039
|
+
readonly identity: {
|
|
1040
|
+
readonly label: "Google account (who you are)";
|
|
1041
|
+
readonly access: "read";
|
|
1042
|
+
readonly scopes: readonly ["openid", "email", "profile"];
|
|
1043
|
+
readonly routes: readonly [{
|
|
1044
|
+
readonly host: "openidconnect.googleapis.com";
|
|
1045
|
+
readonly paths: readonly ["/v1/userinfo"];
|
|
1046
|
+
}, {
|
|
1047
|
+
readonly host: "www.googleapis.com";
|
|
1048
|
+
readonly paths: readonly ["/oauth2/v2/userinfo", "/oauth2/v3/userinfo", "/userinfo/v2/me"];
|
|
1049
|
+
}];
|
|
1050
|
+
};
|
|
1051
|
+
readonly "gmail.read": {
|
|
1052
|
+
readonly label: "Gmail (read-only)";
|
|
1053
|
+
readonly access: "read";
|
|
1054
|
+
readonly scopes: readonly ["https://www.googleapis.com/auth/gmail.readonly"];
|
|
1055
|
+
readonly routes: readonly [{
|
|
1056
|
+
readonly host: "gmail.googleapis.com";
|
|
1057
|
+
readonly paths: readonly ["/gmail/v1/users/"];
|
|
1058
|
+
readonly posts: readonly [RegExp];
|
|
1059
|
+
}];
|
|
1060
|
+
};
|
|
1061
|
+
readonly "calendar.read": {
|
|
1062
|
+
readonly label: "Google Calendar (read-only)";
|
|
1063
|
+
readonly access: "read";
|
|
1064
|
+
readonly scopes: readonly ["https://www.googleapis.com/auth/calendar.readonly"];
|
|
1065
|
+
readonly routes: readonly [{
|
|
1066
|
+
readonly host: "www.googleapis.com";
|
|
1067
|
+
readonly paths: readonly ["/calendar/v3/"];
|
|
1068
|
+
readonly posts: readonly [RegExp, RegExp, RegExp, RegExp];
|
|
1069
|
+
}];
|
|
1070
|
+
};
|
|
1071
|
+
readonly "search-console.read": {
|
|
1072
|
+
readonly label: "Search Console (read-only)";
|
|
1073
|
+
readonly access: "read";
|
|
1074
|
+
readonly scopes: readonly ["https://www.googleapis.com/auth/webmasters.readonly"];
|
|
1075
|
+
readonly routes: readonly [{
|
|
1076
|
+
readonly host: "www.googleapis.com";
|
|
1077
|
+
readonly paths: readonly ["/webmasters/v3/"];
|
|
1078
|
+
readonly posts: readonly [RegExp];
|
|
1079
|
+
}, {
|
|
1080
|
+
readonly host: "searchconsole.googleapis.com";
|
|
1081
|
+
readonly paths: readonly ["/webmasters/v3/"];
|
|
1082
|
+
readonly posts: readonly [RegExp, RegExp];
|
|
1083
|
+
}];
|
|
1084
|
+
};
|
|
1085
|
+
readonly "analytics.read": {
|
|
1086
|
+
readonly label: "Google Analytics (read-only)";
|
|
1087
|
+
readonly access: "read";
|
|
1088
|
+
readonly scopes: readonly ["https://www.googleapis.com/auth/analytics.readonly"];
|
|
1089
|
+
readonly routes: readonly [{
|
|
1090
|
+
readonly host: "analyticsdata.googleapis.com";
|
|
1091
|
+
readonly paths: readonly ["/v1beta/properties/"];
|
|
1092
|
+
readonly posts: readonly [RegExp];
|
|
1093
|
+
}, {
|
|
1094
|
+
readonly host: "analyticsadmin.googleapis.com";
|
|
1095
|
+
readonly paths: readonly ["/v1beta/accountSummaries", "/v1beta/accounts", "/v1beta/accounts/", "/v1beta/properties", "/v1beta/properties/", "/v1alpha/properties/"];
|
|
1096
|
+
}];
|
|
1097
|
+
};
|
|
1098
|
+
};
|
|
1099
|
+
};
|
|
1100
|
+
readonly api: readonly ["gmail.googleapis.com", "www.googleapis.com", "searchconsole.googleapis.com", "analyticsdata.googleapis.com", "analyticsadmin.googleapis.com", "openidconnect.googleapis.com"];
|
|
1101
|
+
readonly redirectPaths: readonly ["/integrations/google/callback"];
|
|
1102
|
+
};
|
|
1103
|
+
readonly "microsoft-365": {
|
|
1104
|
+
readonly mode: "oauth_client";
|
|
1105
|
+
readonly label: "Microsoft 365 (Outlook mail and calendar)";
|
|
1106
|
+
readonly secrets: {
|
|
1107
|
+
readonly clientId: "MICROSOFT_365_CLIENT_ID";
|
|
1108
|
+
readonly clientSecret: "MICROSOFT_365_CLIENT_SECRET";
|
|
1109
|
+
};
|
|
1110
|
+
readonly token: readonly [{
|
|
1111
|
+
readonly host: "login.microsoftonline.com";
|
|
1112
|
+
readonly path: "/common/oauth2/v2.0/token";
|
|
1113
|
+
readonly methods: readonly ["POST"];
|
|
1114
|
+
readonly inject: "form";
|
|
1115
|
+
}];
|
|
1116
|
+
readonly access: readonly ["write"];
|
|
1117
|
+
readonly console: "https://entra.microsoft.com/#view/Microsoft_AAD_RegisteredApps/ApplicationsListBlade";
|
|
1118
|
+
readonly setup: "setup/microsoft-365.md";
|
|
1119
|
+
readonly authorize: {
|
|
1120
|
+
readonly url: "https://login.microsoftonline.com/common/oauth2/v2.0/authorize";
|
|
1121
|
+
readonly scopes: readonly ["offline_access", "User.Read", "Mail.Read", "Calendars.Read"];
|
|
1122
|
+
};
|
|
1123
|
+
readonly scopePolicy: {
|
|
1124
|
+
readonly dialect: "microsoft";
|
|
1125
|
+
readonly grantTypes: readonly ["authorization_code", "refresh_token"];
|
|
1126
|
+
readonly requestScope: "replace";
|
|
1127
|
+
readonly alwaysRequested: readonly ["offline_access"];
|
|
1128
|
+
readonly tolerated: readonly ["openid", "profile", "email", "offline_access", "User.Read"];
|
|
1129
|
+
readonly deniedSegments: readonly ["$batch", "beta"];
|
|
1130
|
+
readonly sets: {
|
|
1131
|
+
readonly identity: {
|
|
1132
|
+
readonly label: "Microsoft account (who you are)";
|
|
1133
|
+
readonly access: "read";
|
|
1134
|
+
readonly scopes: readonly ["User.Read"];
|
|
1135
|
+
readonly routes: readonly [{
|
|
1136
|
+
readonly host: "graph.microsoft.com";
|
|
1137
|
+
readonly paths: readonly ["/v1.0/me", "/oidc/userinfo"];
|
|
1138
|
+
}];
|
|
1139
|
+
};
|
|
1140
|
+
readonly "mail.read": {
|
|
1141
|
+
readonly label: "Outlook mail (read-only)";
|
|
1142
|
+
readonly access: "read";
|
|
1143
|
+
readonly scopes: readonly ["Mail.Read"];
|
|
1144
|
+
readonly routes: readonly [{
|
|
1145
|
+
readonly host: "graph.microsoft.com";
|
|
1146
|
+
readonly paths: readonly ["/v1.0/me/messages", "/v1.0/me/messages/", "/v1.0/me/mailFolders", "/v1.0/me/mailFolders/"];
|
|
1147
|
+
}];
|
|
1148
|
+
};
|
|
1149
|
+
readonly "calendar.read": {
|
|
1150
|
+
readonly label: "Outlook calendar (read-only)";
|
|
1151
|
+
readonly access: "read";
|
|
1152
|
+
readonly scopes: readonly ["Calendars.Read"];
|
|
1153
|
+
readonly routes: readonly [{
|
|
1154
|
+
readonly host: "graph.microsoft.com";
|
|
1155
|
+
readonly paths: readonly ["/v1.0/me/calendar", "/v1.0/me/calendar/", "/v1.0/me/calendars", "/v1.0/me/calendars/", "/v1.0/me/events", "/v1.0/me/events/", "/v1.0/me/calendarView", "/v1.0/me/calendarView/"];
|
|
1156
|
+
readonly posts: readonly [RegExp];
|
|
1157
|
+
}];
|
|
1158
|
+
};
|
|
1159
|
+
};
|
|
1160
|
+
};
|
|
1161
|
+
readonly api: readonly ["graph.microsoft.com"];
|
|
1162
|
+
readonly redirectPaths: readonly ["/integrations/microsoft/callback"];
|
|
1163
|
+
};
|
|
1164
|
+
};
|
|
1165
|
+
export type CapabilityId = keyof typeof CAPABILITIES;
|
|
1166
|
+
type CapabilityIdOf<Mode extends Capability["mode"]> = {
|
|
1167
|
+
[K in CapabilityId]: (typeof CAPABILITIES)[K]["mode"] extends Mode ? K : never;
|
|
1168
|
+
}[CapabilityId];
|
|
1169
|
+
/** Capabilities an app calls with `integrationFetch()`: providers whose key the gateway holds. */
|
|
1170
|
+
export type ApiKeyCapabilityId = CapabilityIdOf<"api_key">;
|
|
1171
|
+
/** The AI providers an app lists under `providers` and calls with `createGatewayFetch()`. */
|
|
1172
|
+
export type AiProviderId = CapabilityIdOf<"ai">;
|
|
1173
|
+
/** Capabilities the gateway performs itself, each with its SDK helper. */
|
|
1174
|
+
export type ServiceCapabilityId = CapabilityIdOf<"service">;
|
|
1175
|
+
/** OAuth clients whose token endpoints apps reach with `integrationFetch()`. */
|
|
1176
|
+
export type OAuthClientCapabilityId = CapabilityIdOf<"oauth_client">;
|
|
1177
|
+
/**
|
|
1178
|
+
* The scope set names an OAuth client offers; `never` for a client without
|
|
1179
|
+
* a scope policy. Distributes over a union of ids, so a generic over two
|
|
1180
|
+
* clients gets every name either offers rather than the names they share.
|
|
1181
|
+
*/
|
|
1182
|
+
export type OAuthScopeSetName<Id extends OAuthClientCapabilityId> = Id extends unknown ? (typeof CAPABILITIES)[Id] extends {
|
|
1183
|
+
scopePolicy: {
|
|
1184
|
+
sets: infer S;
|
|
1185
|
+
};
|
|
1186
|
+
} ? keyof S & string : never : never;
|
|
1187
|
+
/** The Gateway settings an `auth` block names: the key, and a Basic username held as a setting. */
|
|
1188
|
+
type AuthSettingsOf<A> = (A extends {
|
|
1189
|
+
secret: infer S extends string;
|
|
1190
|
+
} ? S : never) | (A extends {
|
|
1191
|
+
username: {
|
|
1192
|
+
secret: infer U extends string;
|
|
1193
|
+
};
|
|
1194
|
+
} ? U : never);
|
|
1195
|
+
type SettingsOf<C> = C extends {
|
|
1196
|
+
settings: readonly (infer S extends string)[];
|
|
1197
|
+
optionalSettings: readonly (infer O extends string)[];
|
|
1198
|
+
} ? S | O : C extends {
|
|
1199
|
+
secrets: infer S;
|
|
1200
|
+
token: unknown;
|
|
1201
|
+
} ? (S[keyof S] & string) | (C extends {
|
|
1202
|
+
hostSetting: infer H extends string;
|
|
1203
|
+
} ? H : never) : C extends {
|
|
1204
|
+
auth: infer A;
|
|
1205
|
+
} ? AuthSettingsOf<A> | (C extends {
|
|
1206
|
+
alsoNeeds: readonly (infer N extends string)[];
|
|
1207
|
+
} ? N : never) : never;
|
|
1208
|
+
/** The gateway settings capabilities read: keys, clients, senders, transports. */
|
|
1209
|
+
export type CapabilitySecret = SettingsOf<(typeof CAPABILITIES)[CapabilityId]>;
|
|
1210
|
+
/** The Gateway settings an API-key or AI provider's `auth` names: the key first, then a Basic username held as a setting. */
|
|
1211
|
+
export declare function authSettingNames(auth: ApiKeyAuth): string[];
|
|
1212
|
+
/** Every gateway setting `capability` reads, the ones it needs first. */
|
|
1213
|
+
export declare function capabilitySettings(capability: Capability): readonly string[];
|
|
1214
|
+
export declare const CAPABILITY_IDS: CapabilityId[];
|
|
1215
|
+
export declare function isCapabilityId(value: unknown): value is CapabilityId;
|
|
1216
|
+
/**
|
|
1217
|
+
* Where a provider id is looked up: the built-in catalog alone
|
|
1218
|
+
* ({@link CATALOG}), or the catalog and one gateway's registered rows
|
|
1219
|
+
* (`providerRegistry()` in ./providerRegistry.ts). Everything that brokers,
|
|
1220
|
+
* validates or describes a provider takes one, so a registered row is a
|
|
1221
|
+
* provider wherever a catalog entry is.
|
|
1222
|
+
*/
|
|
1223
|
+
export interface CapabilityLookup {
|
|
1224
|
+
get(id: string): Capability | undefined;
|
|
1225
|
+
/** Every id, in order: the catalog's, then a gateway's rows. */
|
|
1226
|
+
ids(): readonly string[];
|
|
1227
|
+
/**
|
|
1228
|
+
* Whether `id`'s settings may be read now: a registered row's only while
|
|
1229
|
+
* its key was set for the hosts and auth it has (the registry's rule);
|
|
1230
|
+
* absent, as for the catalog alone, every entry's may.
|
|
1231
|
+
*/
|
|
1232
|
+
bound?(id: string): boolean;
|
|
1233
|
+
}
|
|
1234
|
+
/** The built-in catalog as a lookup: what every surface reads without a gateway's rows. */
|
|
1235
|
+
export declare const CATALOG: CapabilityLookup;
|
|
1236
|
+
/** The ids an app may list under `capabilities`: every provider but the AI ones, which go under `providers`. */
|
|
1237
|
+
export declare function capabilityIdsOf(lookup: CapabilityLookup): string[];
|
|
1238
|
+
/**
|
|
1239
|
+
* The settings `capability` needs on a request, read from the Gateway's
|
|
1240
|
+
* settings (or `.dev.vars`): the headers to set and the query parameters
|
|
1241
|
+
* to add, or null while any setting its `auth` names is unset or blank.
|
|
1242
|
+
* Values are trimmed. A Basic key without a username is `login:password`
|
|
1243
|
+
* to encode, or taken as already encoded when it holds no colon.
|
|
1244
|
+
*/
|
|
1245
|
+
export declare function authorizationFor(capability: ApiKeyCapability | AiProviderCapability, settings: CapabilitySettings): Authorization | null;
|
|
1246
|
+
/** What {@link authorizationFor} puts on a request. */
|
|
1247
|
+
export interface Authorization {
|
|
1248
|
+
headers: Record<string, string>;
|
|
1249
|
+
query: Record<string, string>;
|
|
1250
|
+
}
|
|
1251
|
+
/** {@link authorizationFor} for an `auth` block alone (the SDK's AI fallback holds the block, not the entry). */
|
|
1252
|
+
export declare function authorizationOf(auth: ApiKeyAuth, settings: CapabilitySettings): Authorization | null;
|
|
1253
|
+
/**
|
|
1254
|
+
* The host a provider's `hostSetting` names, from its value: a bare host
|
|
1255
|
+
* or an https origin with nothing else (no path, port, query, userinfo),
|
|
1256
|
+
* lowercased; null when unset or not of that shape. The host rules a row
|
|
1257
|
+
* must pass apply to it when the registry reads the row.
|
|
1258
|
+
*/
|
|
1259
|
+
export declare function hostSettingValue(value: unknown): string | null;
|
|
1260
|
+
/**
|
|
1261
|
+
* The hosts an API-key provider's key may be sent to: the entry's own,
|
|
1262
|
+
* and the one its `hostSetting` names when that is set and well-formed.
|
|
1263
|
+
*/
|
|
1264
|
+
export declare function apiKeyHosts(capability: ApiKeyCapability, settings?: CapabilitySettings): string[];
|
|
1265
|
+
/** Where AppGateway serves capability calls. */
|
|
1266
|
+
export declare const INTEGRATION_PROXY_PREFIX = "/api/integrations";
|
|
1267
|
+
/**
|
|
1268
|
+
* The AppGateway path for a call to `upstream`:
|
|
1269
|
+
* `/api/integrations/<id>/<host><path>?<query>`. The host is in the path so
|
|
1270
|
+
* a provider with several API hosts needs no other channel.
|
|
1271
|
+
*/
|
|
1272
|
+
export declare function integrationProxyPath(id: ApiKeyCapabilityId | OAuthClientCapabilityId | (string & {}), upstream: URL): string;
|
|
1273
|
+
/** The AppGateway path of a service capability's route: `/api/integrations/<id>/<route>`. */
|
|
1274
|
+
export declare function serviceRoutePath(id: ServiceCapabilityId, route: string): string;
|
|
1275
|
+
/** What an AppGateway capability path names. */
|
|
1276
|
+
export type IntegrationProxyRoute =
|
|
1277
|
+
/** A call the gateway forwards to the provider's `upstream` with its key. */
|
|
1278
|
+
{
|
|
1279
|
+
kind: "api_key";
|
|
1280
|
+
id: string;
|
|
1281
|
+
capability: ApiKeyCapability;
|
|
1282
|
+
upstream: URL;
|
|
1283
|
+
}
|
|
1284
|
+
/** A call to one of an OAuth client's token endpoints, with its rule. */
|
|
1285
|
+
| {
|
|
1286
|
+
kind: "oauth_client";
|
|
1287
|
+
id: string;
|
|
1288
|
+
capability: OAuthClientCapability;
|
|
1289
|
+
upstream: URL;
|
|
1290
|
+
endpoint: OAuthTokenEndpoint;
|
|
1291
|
+
}
|
|
1292
|
+
/** A call to one of the routes a service capability declares. */
|
|
1293
|
+
| {
|
|
1294
|
+
kind: "service";
|
|
1295
|
+
id: ServiceCapabilityId;
|
|
1296
|
+
capability: GatewayServiceCapability;
|
|
1297
|
+
route: string;
|
|
1298
|
+
};
|
|
1299
|
+
/** Gateway settings by name: the gateway's env, or `.dev.vars` in dev. */
|
|
1300
|
+
export type CapabilitySettings = Readonly<Record<string, unknown>>;
|
|
1301
|
+
/**
|
|
1302
|
+
* The capability call an AppGateway path names, or null when the path names
|
|
1303
|
+
* an unknown capability (or an AI provider, which has its own route), a
|
|
1304
|
+
* host outside the provider's, a path that could leave that host, a path
|
|
1305
|
+
* that isn't one of an OAuth client's token endpoints, or a route a service
|
|
1306
|
+
* capability doesn't declare. `settings` resolves an OAuth client's
|
|
1307
|
+
* `hostSetting` (Mastodon's instance); `lookup` is where the id is found,
|
|
1308
|
+
* the catalog alone by default.
|
|
1309
|
+
*/
|
|
1310
|
+
export declare function parseIntegrationProxyPath(pathname: string, search: string, settings?: CapabilitySettings, lookup?: CapabilityLookup): IntegrationProxyRoute | null;
|
|
1311
|
+
/**
|
|
1312
|
+
* The origin an OAuth client's `hostSetting` names (its default when the
|
|
1313
|
+
* setting is unset), or null for a client with a fixed host or a setting
|
|
1314
|
+
* that isn't an https origin. A bare host is taken as https.
|
|
1315
|
+
*/
|
|
1316
|
+
export declare function oauthClientOrigin(capability: OAuthClientCapability, settings: CapabilitySettings | undefined): string | null;
|
|
1317
|
+
/**
|
|
1318
|
+
* The token endpoint `upstream` is, by its exact host and path (a RegExp
|
|
1319
|
+
* for a versioned one), or null. Its method is the caller's to check.
|
|
1320
|
+
*/
|
|
1321
|
+
export declare function tokenEndpointFor(capability: OAuthClientCapability, upstream: URL, settings: CapabilitySettings | undefined): OAuthTokenEndpoint | null;
|
|
1322
|
+
/** An OAuth client's token endpoints, as `POST https://host/path` lines for messages. */
|
|
1323
|
+
export declare function describeTokenEndpoints(capability: OAuthClientCapability): string;
|
|
1324
|
+
/** A token endpoint's path as people read it: a versioned one as `/v<version>/oauth/access_token`. */
|
|
1325
|
+
export declare function tokenPathText(path: string | RegExp): string;
|
|
1326
|
+
/**
|
|
1327
|
+
* The command that gives the gateway `capability`'s client:
|
|
1328
|
+
* `pnpm everyapp secret set <ID> <SECRET> [<HOST SETTING>]`.
|
|
1329
|
+
*/
|
|
1330
|
+
export declare function oauthClientSecretSetCommand(capability: OAuthClientCapability): string;
|
|
1331
|
+
/**
|
|
1332
|
+
* Whether `pathname` reaches one of the capability's account-wide paths,
|
|
1333
|
+
* however it is spelled: percent-encoded (twice, even), in another case,
|
|
1334
|
+
* with a suffix on a segment, with doubled or backslash separators, or with
|
|
1335
|
+
* a trailing segment. A path that doesn't decode, or that holds control
|
|
1336
|
+
* characters or whitespace once decoded, counts as one; so does anything
|
|
1337
|
+
* outside ASCII for a provider that has account-wide paths, since how it
|
|
1338
|
+
* folds case is its own business.
|
|
1339
|
+
*/
|
|
1340
|
+
export declare function isAccountWidePath(capability: ApiKeyCapability, pathname: string): boolean;
|
|
1341
|
+
/** The base64 of `text`'s UTF-8 bytes (`btoa` takes Latin-1 only). */
|
|
1342
|
+
export declare function base64Utf8(text: string): string;
|
|
1343
|
+
export {};
|
|
1344
|
+
//# sourceMappingURL=capabilities.d.ts.map
|