@every-app/sdk 0.3.0-rc.5 → 0.3.0-rc.7
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/dist/cloudflare/catalogSettings.generated.d.ts +1 -16
- package/dist/cloudflare/catalogSettings.generated.d.ts.map +1 -1
- package/dist/cloudflare/catalogSettings.generated.js +0 -49
- package/dist/cloudflare/worker.d.ts +14 -0
- package/dist/cloudflare/worker.d.ts.map +1 -1
- package/dist/cloudflare/worker.js +19 -6
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/internal/aiDefault.d.ts +70 -7
- package/dist/internal/aiDefault.d.ts.map +1 -1
- package/dist/internal/aiDefault.js +145 -15
- package/dist/internal/aiProviders.d.ts +3 -1
- package/dist/internal/aiProviders.d.ts.map +1 -1
- package/dist/internal/aiProviders.js +12 -3
- package/dist/internal/appSettings.d.ts +65 -5
- package/dist/internal/appSettings.d.ts.map +1 -1
- package/dist/internal/appSettings.js +141 -23
- package/dist/internal/capabilities.d.ts +52 -433
- package/dist/internal/capabilities.d.ts.map +1 -1
- package/dist/internal/capabilities.js +25 -558
- package/dist/internal/catalog/index.d.ts +6 -6
- package/dist/internal/catalog/inference.d.ts +6 -6
- package/dist/internal/catalog/inference.d.ts.map +1 -1
- package/dist/internal/catalog/inference.js +9 -6
- package/dist/internal/events.d.ts.map +1 -1
- package/dist/internal/events.js +1 -0
- package/dist/internal/gatewaySettings.d.ts +0 -6
- package/dist/internal/gatewaySettings.d.ts.map +1 -1
- package/dist/internal/gatewaySettings.js +1 -14
- package/dist/internal/identity.d.ts +12 -1
- package/dist/internal/identity.d.ts.map +1 -1
- package/dist/internal/identity.js +11 -1
- package/dist/internal/oauthClient.d.ts +10 -12
- package/dist/internal/oauthClient.d.ts.map +1 -1
- package/dist/internal/oauthClient.js +20 -81
- package/dist/internal/oauthPresets.d.ts +7 -3
- package/dist/internal/oauthPresets.d.ts.map +1 -1
- package/dist/internal/oauthPresets.js +533 -3
- package/dist/internal/oauthSpec.d.ts +44 -1
- package/dist/internal/oauthSpec.d.ts.map +1 -1
- package/dist/internal/oauthSpec.js +147 -34
- package/dist/internal/protocol.d.ts +14 -0
- package/dist/internal/protocol.d.ts.map +1 -1
- package/dist/internal/protocol.js +7 -0
- package/dist/internal/providerRegistry.d.ts +61 -1
- package/dist/internal/providerRegistry.d.ts.map +1 -1
- package/dist/internal/providerRegistry.js +127 -6
- package/dist/internal/providerSpec.d.ts +14 -7
- package/dist/internal/providerSpec.d.ts.map +1 -1
- package/dist/internal/providerSpec.js +306 -7
- package/dist/manifest.d.ts +25 -4
- package/dist/manifest.d.ts.map +1 -1
- package/dist/server/ai.d.ts +45 -0
- package/dist/server/ai.d.ts.map +1 -1
- package/dist/server/ai.js +77 -1
- package/dist/server/aiBinding.d.ts.map +1 -1
- package/dist/server/aiBinding.js +3 -3
- package/dist/server/authorizeUrl.d.ts +1 -1
- package/dist/server/authorizeUrl.d.ts.map +1 -1
- package/dist/server/authorizeUrl.js +2 -6
- package/dist/server/emailBinding.js +1 -1
- package/dist/server/emit.js +1 -1
- package/dist/server/gatewayFetch.d.ts.map +1 -1
- package/dist/server/gatewayFetch.js +20 -7
- package/dist/server/index.d.ts +3 -2
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +3 -2
- package/dist/server/integrationFetch.d.ts +4 -31
- package/dist/server/integrationFetch.d.ts.map +1 -1
- package/dist/server/integrationFetch.js +44 -42
- package/dist/server/listMembers.js +1 -1
- 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.js +1 -1
- package/package.json +1 -1
|
@@ -16,11 +16,14 @@
|
|
|
16
16
|
* proxy's rules: inference routes only, the model allowlist, the usage
|
|
17
17
|
* tap. Never a capability: its key would reach the account's credits
|
|
18
18
|
* and keys on the same host.
|
|
19
|
-
* - `oauth_client`: a provider's OAuth client (
|
|
20
|
-
* the same way. The gateway completes the token endpoint
|
|
21
|
-
* putting the client on them; the app builds the authorize
|
|
22
|
-
* public client id (`integrationStatus()`),
|
|
23
|
-
*
|
|
19
|
+
* - `oauth_client`: a provider's OAuth client (Google's, Microsoft's,
|
|
20
|
+
* Slack's), held the same way. The gateway completes the token endpoint
|
|
21
|
+
* calls only, putting the client on them; the app builds the authorize
|
|
22
|
+
* URL from the public client id (`integrationStatus()`), sends people
|
|
23
|
+
* back to a callback its manifest entry lists (`redirectPaths`), keeps
|
|
24
|
+
* the user tokens and calls the provider's API with them itself. Other
|
|
25
|
+
* providers' clients (GitHub, the social networks) are presets
|
|
26
|
+
* (./oauthPresets.ts): rows only once an operator adds one. A client shared by apps
|
|
24
27
|
* with different needs carries a `scopePolicy`: named scope sets an app
|
|
25
28
|
* lists in its manifest entry's `scopes`, which ./oauthScopes.ts turns
|
|
26
29
|
* into what the app may ask the provider for and what a token it is
|
|
@@ -72,8 +75,8 @@ export const CAPABILITIES = {
|
|
|
72
75
|
extraRoutes: true,
|
|
73
76
|
// Tool calling on chat completions needs `reasoning_effort: "none"`
|
|
74
77
|
// on the GPT-6 family (the responses route takes tools as it is).
|
|
75
|
-
chat: { path: "/v1/chat/completions",
|
|
76
|
-
embeddings: { path: "/v1/embeddings",
|
|
78
|
+
chat: { path: "/v1/chat/completions", seedModel: "gpt-6-luna" },
|
|
79
|
+
embeddings: { path: "/v1/embeddings", seedModel: "text-embedding-3-small" },
|
|
77
80
|
// AI Gateway's OpenAI endpoint takes the path without `/v1`.
|
|
78
81
|
aig: { slug: "openai", trim: "/v1" },
|
|
79
82
|
hint: "A secret key from the API keys page; the Gateway puts it on every call as a bearer token.",
|
|
@@ -98,11 +101,11 @@ export const CAPABILITIES = {
|
|
|
98
101
|
],
|
|
99
102
|
chat: {
|
|
100
103
|
path: "/api/v1/chat/completions",
|
|
101
|
-
|
|
104
|
+
seedModel: "anthropic/claude-haiku-5.5",
|
|
102
105
|
},
|
|
103
106
|
embeddings: {
|
|
104
107
|
path: "/api/v1/embeddings",
|
|
105
|
-
|
|
108
|
+
seedModel: "openai/text-embedding-3-small",
|
|
106
109
|
},
|
|
107
110
|
// AI Gateway's OpenRouter endpoint takes the path without `/api`.
|
|
108
111
|
aig: { slug: "openrouter", trim: "/api" },
|
|
@@ -140,9 +143,9 @@ export const CAPABILITIES = {
|
|
|
140
143
|
normalize: "workers-ai",
|
|
141
144
|
chat: {
|
|
142
145
|
path: "/v1/chat/completions",
|
|
143
|
-
|
|
146
|
+
seedModel: "@cf/meta/llama-4-scout-17b-16e-instruct",
|
|
144
147
|
},
|
|
145
|
-
embeddings: { path: "/v1/embeddings",
|
|
148
|
+
embeddings: { path: "/v1/embeddings", seedModel: "@cf/baai/bge-m3" },
|
|
146
149
|
// Workers AI's REST API is AI Gateway's own host: the URL stays and
|
|
147
150
|
// `cf-aig-gateway-id` names the gateway.
|
|
148
151
|
aig: { slug: "workers-ai", header: true },
|
|
@@ -293,359 +296,6 @@ export const CAPABILITIES = {
|
|
|
293
296
|
settings: [],
|
|
294
297
|
optionalSettings: [],
|
|
295
298
|
},
|
|
296
|
-
// Social networks' OAuth clients (docs/capabilities.md "OAuth clients"):
|
|
297
|
-
// the gateway completes their token endpoints only. Postiz connects its
|
|
298
|
-
// channels with them; one client serves every organization on the gateway.
|
|
299
|
-
linkedin: {
|
|
300
|
-
mode: "oauth_client",
|
|
301
|
-
label: "LinkedIn",
|
|
302
|
-
secrets: {
|
|
303
|
-
clientId: "LINKEDIN_CLIENT_ID",
|
|
304
|
-
clientSecret: "LINKEDIN_CLIENT_SECRET",
|
|
305
|
-
},
|
|
306
|
-
token: [
|
|
307
|
-
{
|
|
308
|
-
host: "www.linkedin.com",
|
|
309
|
-
path: "/oauth/v2/accessToken",
|
|
310
|
-
methods: ["POST"],
|
|
311
|
-
inject: "form",
|
|
312
|
-
},
|
|
313
|
-
],
|
|
314
|
-
access: ["write"],
|
|
315
|
-
console: "https://www.linkedin.com/developers/apps",
|
|
316
|
-
authorize: {
|
|
317
|
-
url: "https://www.linkedin.com/oauth/v2/authorization",
|
|
318
|
-
scopes: [
|
|
319
|
-
"openid",
|
|
320
|
-
"profile",
|
|
321
|
-
"w_member_social",
|
|
322
|
-
"r_basicprofile",
|
|
323
|
-
"rw_organization_admin",
|
|
324
|
-
"w_organization_social",
|
|
325
|
-
"r_organization_social",
|
|
326
|
-
],
|
|
327
|
-
},
|
|
328
|
-
api: ["api.linkedin.com"],
|
|
329
|
-
// Profiles and pages: both callbacks complete on the one client.
|
|
330
|
-
redirectPaths: [
|
|
331
|
-
"/integrations/social/linkedin",
|
|
332
|
-
"/integrations/social/linkedin-page",
|
|
333
|
-
],
|
|
334
|
-
},
|
|
335
|
-
facebook: {
|
|
336
|
-
mode: "oauth_client",
|
|
337
|
-
label: "Facebook",
|
|
338
|
-
secrets: {
|
|
339
|
-
clientId: "FACEBOOK_APP_ID",
|
|
340
|
-
clientSecret: "FACEBOOK_APP_SECRET",
|
|
341
|
-
},
|
|
342
|
-
token: [
|
|
343
|
-
{
|
|
344
|
-
// The code exchange and the long-lived token exchange, both on a
|
|
345
|
-
// versioned path (/v25.0/oauth/access_token).
|
|
346
|
-
host: "graph.facebook.com",
|
|
347
|
-
path: /^\/v\d+\.\d+\/oauth\/access_token$/,
|
|
348
|
-
methods: ["GET", "POST"],
|
|
349
|
-
inject: "query",
|
|
350
|
-
},
|
|
351
|
-
],
|
|
352
|
-
access: ["write"],
|
|
353
|
-
console: "https://developers.facebook.com/apps",
|
|
354
|
-
authorize: {
|
|
355
|
-
url: "https://www.facebook.com/v25.0/dialog/oauth",
|
|
356
|
-
// Facebook pages, and Instagram business accounts through them.
|
|
357
|
-
scopes: [
|
|
358
|
-
"pages_show_list",
|
|
359
|
-
"business_management",
|
|
360
|
-
"pages_manage_posts",
|
|
361
|
-
"pages_manage_engagement",
|
|
362
|
-
"pages_read_engagement",
|
|
363
|
-
"read_insights",
|
|
364
|
-
"instagram_basic",
|
|
365
|
-
"instagram_content_publish",
|
|
366
|
-
"instagram_manage_comments",
|
|
367
|
-
"instagram_manage_insights",
|
|
368
|
-
],
|
|
369
|
-
},
|
|
370
|
-
api: ["graph.facebook.com", "graph.instagram.com"],
|
|
371
|
-
redirectPaths: [
|
|
372
|
-
"/integrations/social/facebook",
|
|
373
|
-
"/integrations/social/instagram",
|
|
374
|
-
],
|
|
375
|
-
},
|
|
376
|
-
instagram: {
|
|
377
|
-
mode: "oauth_client",
|
|
378
|
-
label: "Instagram",
|
|
379
|
-
secrets: {
|
|
380
|
-
clientId: "INSTAGRAM_APP_ID",
|
|
381
|
-
clientSecret: "INSTAGRAM_APP_SECRET",
|
|
382
|
-
},
|
|
383
|
-
token: [
|
|
384
|
-
// The code exchange, then the long-lived token exchange.
|
|
385
|
-
{
|
|
386
|
-
host: "api.instagram.com",
|
|
387
|
-
path: "/oauth/access_token",
|
|
388
|
-
methods: ["POST"],
|
|
389
|
-
inject: "form",
|
|
390
|
-
},
|
|
391
|
-
{
|
|
392
|
-
host: "graph.instagram.com",
|
|
393
|
-
path: "/access_token",
|
|
394
|
-
methods: ["GET"],
|
|
395
|
-
inject: "query",
|
|
396
|
-
},
|
|
397
|
-
],
|
|
398
|
-
access: ["write"],
|
|
399
|
-
console: "https://developers.facebook.com/apps",
|
|
400
|
-
authorize: {
|
|
401
|
-
url: "https://www.instagram.com/oauth/authorize",
|
|
402
|
-
scopes: [
|
|
403
|
-
"instagram_business_basic",
|
|
404
|
-
"instagram_business_content_publish",
|
|
405
|
-
"instagram_business_manage_comments",
|
|
406
|
-
"instagram_business_manage_insights",
|
|
407
|
-
],
|
|
408
|
-
},
|
|
409
|
-
api: ["graph.instagram.com"],
|
|
410
|
-
redirectPaths: ["/integrations/social/instagram-standalone"],
|
|
411
|
-
},
|
|
412
|
-
threads: {
|
|
413
|
-
mode: "oauth_client",
|
|
414
|
-
label: "Threads",
|
|
415
|
-
secrets: { clientId: "THREADS_APP_ID", clientSecret: "THREADS_APP_SECRET" },
|
|
416
|
-
token: [
|
|
417
|
-
// The code exchange, then the long-lived token exchange.
|
|
418
|
-
{
|
|
419
|
-
host: "graph.threads.net",
|
|
420
|
-
path: "/oauth/access_token",
|
|
421
|
-
methods: ["GET", "POST"],
|
|
422
|
-
inject: "query",
|
|
423
|
-
},
|
|
424
|
-
{
|
|
425
|
-
host: "graph.threads.net",
|
|
426
|
-
path: "/access_token",
|
|
427
|
-
methods: ["GET"],
|
|
428
|
-
inject: "query",
|
|
429
|
-
},
|
|
430
|
-
],
|
|
431
|
-
access: ["write"],
|
|
432
|
-
console: "https://developers.facebook.com/apps",
|
|
433
|
-
authorize: {
|
|
434
|
-
url: "https://threads.net/oauth/authorize",
|
|
435
|
-
scopes: [
|
|
436
|
-
"threads_basic",
|
|
437
|
-
"threads_content_publish",
|
|
438
|
-
"threads_manage_replies",
|
|
439
|
-
"threads_manage_insights",
|
|
440
|
-
],
|
|
441
|
-
},
|
|
442
|
-
api: ["graph.threads.net"],
|
|
443
|
-
redirectPaths: ["/integrations/social/threads"],
|
|
444
|
-
},
|
|
445
|
-
youtube: {
|
|
446
|
-
mode: "oauth_client",
|
|
447
|
-
label: "YouTube",
|
|
448
|
-
secrets: {
|
|
449
|
-
clientId: "YOUTUBE_CLIENT_ID",
|
|
450
|
-
clientSecret: "YOUTUBE_CLIENT_SECRET",
|
|
451
|
-
},
|
|
452
|
-
token: [
|
|
453
|
-
{
|
|
454
|
-
host: "oauth2.googleapis.com",
|
|
455
|
-
path: "/token",
|
|
456
|
-
methods: ["POST"],
|
|
457
|
-
inject: "form",
|
|
458
|
-
},
|
|
459
|
-
],
|
|
460
|
-
access: ["write"],
|
|
461
|
-
console: "https://console.cloud.google.com/apis/credentials",
|
|
462
|
-
setup: "setup/google.md",
|
|
463
|
-
authorize: {
|
|
464
|
-
url: "https://accounts.google.com/o/oauth2/v2/auth",
|
|
465
|
-
// YouTube channels, and Google Business Profiles on the same client.
|
|
466
|
-
scopes: [
|
|
467
|
-
"https://www.googleapis.com/auth/userinfo.profile",
|
|
468
|
-
"https://www.googleapis.com/auth/userinfo.email",
|
|
469
|
-
"https://www.googleapis.com/auth/youtube",
|
|
470
|
-
"https://www.googleapis.com/auth/youtube.force-ssl",
|
|
471
|
-
"https://www.googleapis.com/auth/youtube.readonly",
|
|
472
|
-
"https://www.googleapis.com/auth/youtube.upload",
|
|
473
|
-
"https://www.googleapis.com/auth/youtubepartner",
|
|
474
|
-
"https://www.googleapis.com/auth/yt-analytics.readonly",
|
|
475
|
-
"https://www.googleapis.com/auth/business.manage",
|
|
476
|
-
],
|
|
477
|
-
},
|
|
478
|
-
api: [
|
|
479
|
-
"www.googleapis.com",
|
|
480
|
-
"youtubeanalytics.googleapis.com",
|
|
481
|
-
"mybusinessaccountmanagement.googleapis.com",
|
|
482
|
-
"mybusinessbusinessinformation.googleapis.com",
|
|
483
|
-
"mybusiness.googleapis.com",
|
|
484
|
-
"businessprofileperformance.googleapis.com",
|
|
485
|
-
],
|
|
486
|
-
redirectPaths: ["/integrations/social/youtube", "/integrations/social/gmb"],
|
|
487
|
-
},
|
|
488
|
-
tiktok: {
|
|
489
|
-
mode: "oauth_client",
|
|
490
|
-
label: "TikTok",
|
|
491
|
-
secrets: {
|
|
492
|
-
clientId: "TIKTOK_CLIENT_ID",
|
|
493
|
-
clientSecret: "TIKTOK_CLIENT_SECRET",
|
|
494
|
-
},
|
|
495
|
-
token: [
|
|
496
|
-
{
|
|
497
|
-
host: "open.tiktokapis.com",
|
|
498
|
-
path: "/v2/oauth/token/",
|
|
499
|
-
methods: ["POST"],
|
|
500
|
-
inject: "form",
|
|
501
|
-
// TikTok calls the client id its client key.
|
|
502
|
-
params: { clientId: "client_key" },
|
|
503
|
-
},
|
|
504
|
-
],
|
|
505
|
-
access: ["write"],
|
|
506
|
-
console: "https://developers.tiktok.com/apps",
|
|
507
|
-
authorize: {
|
|
508
|
-
url: "https://www.tiktok.com/v2/auth/authorize/",
|
|
509
|
-
scopes: [
|
|
510
|
-
"video.list",
|
|
511
|
-
"user.info.basic",
|
|
512
|
-
"video.publish",
|
|
513
|
-
"video.upload",
|
|
514
|
-
"user.info.profile",
|
|
515
|
-
"user.info.stats",
|
|
516
|
-
],
|
|
517
|
-
},
|
|
518
|
-
api: ["open.tiktokapis.com"],
|
|
519
|
-
redirectPaths: ["/integrations/social/tiktok"],
|
|
520
|
-
},
|
|
521
|
-
"tiktok-business": {
|
|
522
|
-
mode: "oauth_client",
|
|
523
|
-
label: "TikTok Business",
|
|
524
|
-
secrets: {
|
|
525
|
-
clientId: "TIKTOK_BUSINESS_CLIENT_ID",
|
|
526
|
-
clientSecret: "TIKTOK_BUSINESS_CLIENT_SECRET",
|
|
527
|
-
},
|
|
528
|
-
token: [
|
|
529
|
-
{
|
|
530
|
-
host: "business-api.tiktok.com",
|
|
531
|
-
path: "/open_api/v1.3/tt_user/oauth2/token/",
|
|
532
|
-
methods: ["POST"],
|
|
533
|
-
inject: "json",
|
|
534
|
-
},
|
|
535
|
-
{
|
|
536
|
-
host: "business-api.tiktok.com",
|
|
537
|
-
path: "/open_api/v1.3/tt_user/oauth2/refresh_token/",
|
|
538
|
-
methods: ["POST"],
|
|
539
|
-
inject: "json",
|
|
540
|
-
},
|
|
541
|
-
],
|
|
542
|
-
access: ["write"],
|
|
543
|
-
console: "https://business-api.tiktok.com/portal/apps",
|
|
544
|
-
authorize: {
|
|
545
|
-
url: "https://www.tiktok.com/v2/auth/authorize/",
|
|
546
|
-
scopes: [
|
|
547
|
-
"user.info.basic",
|
|
548
|
-
"user.info.username",
|
|
549
|
-
"user.info.stats",
|
|
550
|
-
"video.list",
|
|
551
|
-
"video.upload",
|
|
552
|
-
"video.publish",
|
|
553
|
-
],
|
|
554
|
-
},
|
|
555
|
-
api: ["business-api.tiktok.com"],
|
|
556
|
-
// TikTok Business wants the trailing slash.
|
|
557
|
-
redirectPaths: ["/integrations/social/tiktok-business/"],
|
|
558
|
-
},
|
|
559
|
-
reddit: {
|
|
560
|
-
mode: "oauth_client",
|
|
561
|
-
label: "Reddit",
|
|
562
|
-
secrets: {
|
|
563
|
-
clientId: "REDDIT_CLIENT_ID",
|
|
564
|
-
clientSecret: "REDDIT_CLIENT_SECRET",
|
|
565
|
-
},
|
|
566
|
-
token: [
|
|
567
|
-
{
|
|
568
|
-
host: "www.reddit.com",
|
|
569
|
-
path: "/api/v1/access_token",
|
|
570
|
-
methods: ["POST"],
|
|
571
|
-
inject: "basic",
|
|
572
|
-
},
|
|
573
|
-
],
|
|
574
|
-
access: ["write"],
|
|
575
|
-
console: "https://www.reddit.com/prefs/apps",
|
|
576
|
-
authorize: {
|
|
577
|
-
url: "https://www.reddit.com/api/v1/authorize",
|
|
578
|
-
scopes: ["read", "identity", "submit", "flair"],
|
|
579
|
-
},
|
|
580
|
-
api: ["oauth.reddit.com"],
|
|
581
|
-
redirectPaths: ["/integrations/social/reddit"],
|
|
582
|
-
},
|
|
583
|
-
pinterest: {
|
|
584
|
-
mode: "oauth_client",
|
|
585
|
-
label: "Pinterest",
|
|
586
|
-
secrets: {
|
|
587
|
-
clientId: "PINTEREST_CLIENT_ID",
|
|
588
|
-
clientSecret: "PINTEREST_CLIENT_SECRET",
|
|
589
|
-
},
|
|
590
|
-
token: [
|
|
591
|
-
{
|
|
592
|
-
host: "api.pinterest.com",
|
|
593
|
-
path: "/v5/oauth/token",
|
|
594
|
-
methods: ["POST"],
|
|
595
|
-
inject: "basic",
|
|
596
|
-
},
|
|
597
|
-
],
|
|
598
|
-
access: ["write"],
|
|
599
|
-
console: "https://developers.pinterest.com/apps/",
|
|
600
|
-
authorize: {
|
|
601
|
-
url: "https://www.pinterest.com/oauth/",
|
|
602
|
-
scopes: [
|
|
603
|
-
"boards:read",
|
|
604
|
-
"boards:write",
|
|
605
|
-
"pins:read",
|
|
606
|
-
"pins:write",
|
|
607
|
-
"user_accounts:read",
|
|
608
|
-
],
|
|
609
|
-
},
|
|
610
|
-
api: ["api.pinterest.com"],
|
|
611
|
-
redirectPaths: ["/integrations/social/pinterest"],
|
|
612
|
-
},
|
|
613
|
-
discord: {
|
|
614
|
-
mode: "oauth_client",
|
|
615
|
-
label: "Discord",
|
|
616
|
-
secrets: {
|
|
617
|
-
clientId: "DISCORD_CLIENT_ID",
|
|
618
|
-
clientSecret: "DISCORD_CLIENT_SECRET",
|
|
619
|
-
},
|
|
620
|
-
token: [
|
|
621
|
-
{
|
|
622
|
-
host: "discord.com",
|
|
623
|
-
path: "/api/oauth2/token",
|
|
624
|
-
methods: ["POST"],
|
|
625
|
-
inject: "basic",
|
|
626
|
-
},
|
|
627
|
-
],
|
|
628
|
-
access: ["write"],
|
|
629
|
-
console: "https://discord.com/developers/applications",
|
|
630
|
-
// The server install; posting uses the bot's token, an app secret.
|
|
631
|
-
authorize: {
|
|
632
|
-
url: "https://discord.com/oauth2/authorize",
|
|
633
|
-
scopes: ["bot", "identify", "guilds"],
|
|
634
|
-
},
|
|
635
|
-
api: ["discord.com"],
|
|
636
|
-
redirectPaths: ["/integrations/social/discord"],
|
|
637
|
-
flow: {
|
|
638
|
-
tokenUrl: "https://discord.com/api/oauth2/token",
|
|
639
|
-
revokeUrl: "https://discord.com/api/oauth2/token/revoke",
|
|
640
|
-
pkce: true,
|
|
641
|
-
scopeDialect: "space",
|
|
642
|
-
identity: {
|
|
643
|
-
url: "https://discord.com/api/users/@me",
|
|
644
|
-
label: "username",
|
|
645
|
-
id: "id",
|
|
646
|
-
},
|
|
647
|
-
},
|
|
648
|
-
},
|
|
649
299
|
slack: {
|
|
650
300
|
mode: "oauth_client",
|
|
651
301
|
label: "Slack",
|
|
@@ -855,10 +505,6 @@ export const CAPABILITIES = {
|
|
|
855
505
|
},
|
|
856
506
|
},
|
|
857
507
|
api: ["slack.com"],
|
|
858
|
-
redirectPaths: [
|
|
859
|
-
"/integrations/social/slack",
|
|
860
|
-
"/integrations/slack/callback",
|
|
861
|
-
],
|
|
862
508
|
// Slack refuses `code_challenge`; `auth.test` names the workspace and
|
|
863
509
|
// the installing person.
|
|
864
510
|
flow: {
|
|
@@ -873,131 +519,12 @@ export const CAPABILITIES = {
|
|
|
873
519
|
},
|
|
874
520
|
},
|
|
875
521
|
},
|
|
876
|
-
mastodon: {
|
|
877
|
-
mode: "oauth_client",
|
|
878
|
-
label: "Mastodon",
|
|
879
|
-
secrets: {
|
|
880
|
-
clientId: "MASTODON_CLIENT_ID",
|
|
881
|
-
clientSecret: "MASTODON_CLIENT_SECRET",
|
|
882
|
-
},
|
|
883
|
-
// On the instance the operator registered the client on.
|
|
884
|
-
token: [{ path: "/oauth/token", methods: ["POST"], inject: "form" }],
|
|
885
|
-
hostSetting: "MASTODON_URL",
|
|
886
|
-
defaultOrigin: "https://mastodon.social",
|
|
887
|
-
access: ["write"],
|
|
888
|
-
console: "/settings/applications",
|
|
889
|
-
authorize: {
|
|
890
|
-
url: "/oauth/authorize",
|
|
891
|
-
scopes: ["write:statuses", "profile", "write:media"],
|
|
892
|
-
},
|
|
893
|
-
api: [],
|
|
894
|
-
redirectPaths: ["/integrations/social/mastodon"],
|
|
895
|
-
},
|
|
896
|
-
kick: {
|
|
897
|
-
mode: "oauth_client",
|
|
898
|
-
label: "Kick",
|
|
899
|
-
secrets: { clientId: "KICK_CLIENT_ID", clientSecret: "KICK_CLIENT_SECRET" },
|
|
900
|
-
token: [
|
|
901
|
-
{
|
|
902
|
-
host: "id.kick.com",
|
|
903
|
-
path: "/oauth/token",
|
|
904
|
-
methods: ["POST"],
|
|
905
|
-
inject: "form",
|
|
906
|
-
},
|
|
907
|
-
],
|
|
908
|
-
access: ["write"],
|
|
909
|
-
console: "https://kick.com/settings/developer",
|
|
910
|
-
authorize: {
|
|
911
|
-
url: "https://id.kick.com/oauth/authorize",
|
|
912
|
-
scopes: ["chat:write", "user:read", "channel:read"],
|
|
913
|
-
},
|
|
914
|
-
api: ["api.kick.com"],
|
|
915
|
-
redirectPaths: ["/integrations/social/kick"],
|
|
916
|
-
},
|
|
917
|
-
twitch: {
|
|
918
|
-
mode: "oauth_client",
|
|
919
|
-
label: "Twitch",
|
|
920
|
-
secrets: {
|
|
921
|
-
clientId: "TWITCH_CLIENT_ID",
|
|
922
|
-
clientSecret: "TWITCH_CLIENT_SECRET",
|
|
923
|
-
},
|
|
924
|
-
token: [
|
|
925
|
-
{
|
|
926
|
-
host: "id.twitch.tv",
|
|
927
|
-
path: "/oauth2/token",
|
|
928
|
-
methods: ["POST"],
|
|
929
|
-
inject: "form",
|
|
930
|
-
},
|
|
931
|
-
],
|
|
932
|
-
access: ["write"],
|
|
933
|
-
console: "https://dev.twitch.tv/console/apps",
|
|
934
|
-
authorize: {
|
|
935
|
-
url: "https://id.twitch.tv/oauth2/authorize",
|
|
936
|
-
scopes: [
|
|
937
|
-
"user:write:chat",
|
|
938
|
-
"user:read:chat",
|
|
939
|
-
"moderator:manage:announcements",
|
|
940
|
-
],
|
|
941
|
-
},
|
|
942
|
-
// Helix also wants the public client id, as Client-Id, on every call.
|
|
943
|
-
api: ["api.twitch.tv"],
|
|
944
|
-
redirectPaths: ["/integrations/social/twitch"],
|
|
945
|
-
},
|
|
946
|
-
tumblr: {
|
|
947
|
-
mode: "oauth_client",
|
|
948
|
-
label: "Tumblr",
|
|
949
|
-
secrets: {
|
|
950
|
-
clientId: "TUMBLR_CLIENT_ID",
|
|
951
|
-
clientSecret: "TUMBLR_CLIENT_SECRET",
|
|
952
|
-
},
|
|
953
|
-
token: [
|
|
954
|
-
{
|
|
955
|
-
host: "api.tumblr.com",
|
|
956
|
-
path: "/v2/oauth2/token",
|
|
957
|
-
methods: ["POST"],
|
|
958
|
-
inject: "form",
|
|
959
|
-
},
|
|
960
|
-
],
|
|
961
|
-
access: ["write"],
|
|
962
|
-
console: "https://www.tumblr.com/oauth/apps",
|
|
963
|
-
authorize: {
|
|
964
|
-
url: "https://www.tumblr.com/oauth2/authorize",
|
|
965
|
-
scopes: ["write", "offline_access"],
|
|
966
|
-
},
|
|
967
|
-
api: ["api.tumblr.com"],
|
|
968
|
-
redirectPaths: ["/integrations/social/tumblr"],
|
|
969
|
-
},
|
|
970
|
-
dribbble: {
|
|
971
|
-
mode: "oauth_client",
|
|
972
|
-
label: "Dribbble",
|
|
973
|
-
secrets: {
|
|
974
|
-
clientId: "DRIBBBLE_CLIENT_ID",
|
|
975
|
-
clientSecret: "DRIBBBLE_CLIENT_SECRET",
|
|
976
|
-
},
|
|
977
|
-
token: [
|
|
978
|
-
{
|
|
979
|
-
// A POST that takes the client in its query string.
|
|
980
|
-
host: "dribbble.com",
|
|
981
|
-
path: "/oauth/token",
|
|
982
|
-
methods: ["POST"],
|
|
983
|
-
inject: "query",
|
|
984
|
-
},
|
|
985
|
-
],
|
|
986
|
-
access: ["write"],
|
|
987
|
-
console: "https://dribbble.com/account/applications",
|
|
988
|
-
authorize: {
|
|
989
|
-
url: "https://dribbble.com/oauth/authorize",
|
|
990
|
-
scopes: ["public", "upload"],
|
|
991
|
-
},
|
|
992
|
-
api: ["api.dribbble.com"],
|
|
993
|
-
redirectPaths: ["/integrations/social/dribbble"],
|
|
994
|
-
},
|
|
995
522
|
// Clients several apps share with different needs, so each app lists the
|
|
996
523
|
// scope sets it uses: Open CRM reads a member's own mailbox and calendar
|
|
997
524
|
// (`gmail.read`, `calendar.read`; `identity`, `mail.read`), OpenSEO reads
|
|
998
525
|
// a site's Search Console and Analytics (`identity`, `search-console.read`,
|
|
999
526
|
// `analytics.read`). Every set is read-only. Google's is one Cloud project
|
|
1000
|
-
// apart from YouTube's; Gmail's read scope is restricted and needs
|
|
527
|
+
// apart from the YouTube preset's; Gmail's read scope is restricted and needs
|
|
1001
528
|
// Google's verification, and whether Search Console and Analytics share
|
|
1002
529
|
// that consent screen with it is the operator's choice when verifying.
|
|
1003
530
|
"google-workspace": {
|
|
@@ -1161,7 +688,6 @@ export const CAPABILITIES = {
|
|
|
1161
688
|
"analyticsadmin.googleapis.com",
|
|
1162
689
|
"openidconnect.googleapis.com",
|
|
1163
690
|
],
|
|
1164
|
-
redirectPaths: ["/integrations/google/callback"],
|
|
1165
691
|
// The Gateway-owned flow: a refresh token needs `access_type=offline`,
|
|
1166
692
|
// and `prompt=consent` makes Google issue one on every connect. No
|
|
1167
693
|
// revoke: Google's `/revoke` is per person per client and would also
|
|
@@ -1271,7 +797,6 @@ export const CAPABILITIES = {
|
|
|
1271
797
|
},
|
|
1272
798
|
},
|
|
1273
799
|
api: ["graph.microsoft.com"],
|
|
1274
|
-
redirectPaths: ["/integrations/microsoft/callback"],
|
|
1275
800
|
flow: {
|
|
1276
801
|
tokenUrl: "https://login.microsoftonline.com/common/oauth2/v2.0/token",
|
|
1277
802
|
pkce: true,
|
|
@@ -1315,7 +840,6 @@ export function capabilitySettings(capability) {
|
|
|
1315
840
|
...(capability.secrets.clientSecret
|
|
1316
841
|
? [capability.secrets.clientSecret]
|
|
1317
842
|
: []),
|
|
1318
|
-
...(capability.hostSetting ? [capability.hostSetting] : []),
|
|
1319
843
|
];
|
|
1320
844
|
}
|
|
1321
845
|
}
|
|
@@ -1437,8 +961,8 @@ export function serviceRoutePath(id, route) {
|
|
|
1437
961
|
* an unknown capability (or an AI provider, which has its own route), a
|
|
1438
962
|
* host outside the provider's, a path that could leave that host, a path
|
|
1439
963
|
* that isn't one of an OAuth client's token endpoints, or a route a service
|
|
1440
|
-
* capability doesn't declare. `settings` resolves an
|
|
1441
|
-
* `hostSetting` (
|
|
964
|
+
* capability doesn't declare. `settings` resolves an API-key provider's
|
|
965
|
+
* `hostSetting` (a Shopify store's host); `lookup` is where the id is found,
|
|
1442
966
|
* the catalog alone by default.
|
|
1443
967
|
*/
|
|
1444
968
|
export function parseIntegrationProxyPath(pathname, search, settings, lookup = CATALOG) {
|
|
@@ -1462,10 +986,10 @@ export function parseIntegrationProxyPath(pathname, search, settings, lookup = C
|
|
|
1462
986
|
};
|
|
1463
987
|
}
|
|
1464
988
|
if (capability.mode === "oauth_client") {
|
|
1465
|
-
const upstream =
|
|
989
|
+
const upstream = capability.token.some((rule) => rule.host === host)
|
|
1466
990
|
? httpsUpstream(host, path ?? "/", search)
|
|
1467
991
|
: null;
|
|
1468
|
-
const endpoint = upstream && tokenEndpointFor(capability, upstream
|
|
992
|
+
const endpoint = upstream && tokenEndpointFor(capability, upstream);
|
|
1469
993
|
if (!upstream || !endpoint)
|
|
1470
994
|
return null;
|
|
1471
995
|
return { kind: "oauth_client", id, capability, upstream, endpoint };
|
|
@@ -1490,80 +1014,23 @@ function httpsUpstream(host, path, search) {
|
|
|
1490
1014
|
return upstream;
|
|
1491
1015
|
}
|
|
1492
1016
|
/**
|
|
1493
|
-
* The
|
|
1494
|
-
*
|
|
1495
|
-
* that isn't an https origin. A bare host is taken as https.
|
|
1496
|
-
*/
|
|
1497
|
-
export function oauthClientOrigin(capability, settings) {
|
|
1498
|
-
if (!capability.hostSetting)
|
|
1499
|
-
return null;
|
|
1500
|
-
const set = settings?.[capability.hostSetting];
|
|
1501
|
-
const value = typeof set === "string" && set.trim()
|
|
1502
|
-
? set.trim()
|
|
1503
|
-
: capability.defaultOrigin;
|
|
1504
|
-
if (!value)
|
|
1505
|
-
return null;
|
|
1506
|
-
let url;
|
|
1507
|
-
try {
|
|
1508
|
-
url = new URL(/^[a-z][a-z0-9+.-]*:\/\//i.test(value) ? value : `https://${value}`);
|
|
1509
|
-
}
|
|
1510
|
-
catch {
|
|
1511
|
-
return null;
|
|
1512
|
-
}
|
|
1513
|
-
// An origin and nothing else: the paths are the provider's own.
|
|
1514
|
-
const bare = url.pathname === "/" &&
|
|
1515
|
-
!url.search &&
|
|
1516
|
-
!url.hash &&
|
|
1517
|
-
!url.username &&
|
|
1518
|
-
!url.password;
|
|
1519
|
-
return url.protocol === "https:" && bare ? url.origin : null;
|
|
1520
|
-
}
|
|
1521
|
-
/** The host an OAuth client's `hostSetting` names, or null. */
|
|
1522
|
-
function settingHost(capability, settings) {
|
|
1523
|
-
const origin = oauthClientOrigin(capability, settings);
|
|
1524
|
-
return origin ? new URL(origin).host : null;
|
|
1525
|
-
}
|
|
1526
|
-
/** The hosts an OAuth client's token endpoints are on. */
|
|
1527
|
-
function oauthClientHosts(capability, settings) {
|
|
1528
|
-
const fromSetting = settingHost(capability, settings);
|
|
1529
|
-
return [
|
|
1530
|
-
...new Set(capability.token.flatMap(({ host }) => {
|
|
1531
|
-
const resolved = host ?? fromSetting;
|
|
1532
|
-
return resolved ? [resolved] : [];
|
|
1533
|
-
})),
|
|
1534
|
-
];
|
|
1535
|
-
}
|
|
1536
|
-
/**
|
|
1537
|
-
* The token endpoint `upstream` is, by its exact host and path (a RegExp
|
|
1538
|
-
* for a versioned one), or null. Its method is the caller's to check.
|
|
1017
|
+
* The token endpoint `upstream` is, by its exact host and path, or null.
|
|
1018
|
+
* Its method is the caller's to check.
|
|
1539
1019
|
*/
|
|
1540
|
-
export function tokenEndpointFor(capability, upstream
|
|
1020
|
+
export function tokenEndpointFor(capability, upstream) {
|
|
1541
1021
|
if (upstream.protocol !== "https:")
|
|
1542
1022
|
return null;
|
|
1543
|
-
|
|
1544
|
-
return (capability.token.find(({ host, path }) => (host ?? fromSetting) === upstream.host &&
|
|
1545
|
-
(typeof path === "string"
|
|
1546
|
-
? path === upstream.pathname
|
|
1547
|
-
: path.test(upstream.pathname))) ?? null);
|
|
1023
|
+
return (capability.token.find(({ host, path }) => host === upstream.host && path === upstream.pathname) ?? null);
|
|
1548
1024
|
}
|
|
1549
1025
|
/** An OAuth client's token endpoints, as `POST https://host/path` lines for messages. */
|
|
1550
1026
|
export function describeTokenEndpoints(capability) {
|
|
1551
1027
|
return capability.token
|
|
1552
|
-
.map(({ host, path, methods }) => `${methods.join("/")} https://${host
|
|
1028
|
+
.map(({ host, path, methods }) => `${methods.join("/")} https://${host}${path}`)
|
|
1553
1029
|
.join(", ");
|
|
1554
1030
|
}
|
|
1555
|
-
/** A token endpoint's path as people read it: a versioned one as `/v<version>/oauth/access_token`. */
|
|
1556
|
-
export function tokenPathText(path) {
|
|
1557
|
-
if (typeof path === "string")
|
|
1558
|
-
return path;
|
|
1559
|
-
return path.source
|
|
1560
|
-
.replace(/^\^|\$$/g, "")
|
|
1561
|
-
.replace(/v\\d\+\\\.\\d\+/g, "v<version>")
|
|
1562
|
-
.replace(/\\(.)/g, "$1");
|
|
1563
|
-
}
|
|
1564
1031
|
/**
|
|
1565
1032
|
* The command that gives the gateway `capability`'s client:
|
|
1566
|
-
* `pnpm everyapp secret set <ID> <SECRET
|
|
1033
|
+
* `pnpm everyapp secret set <ID> <SECRET>`.
|
|
1567
1034
|
*/
|
|
1568
1035
|
export function oauthClientSecretSetCommand(capability) {
|
|
1569
1036
|
return `pnpm everyapp secret set ${capabilitySettings(capability).join(" ")}`;
|