@every-app/sdk 0.3.0-rc.2 → 0.3.0-rc.3
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/index.d.ts +2 -2
- package/dist/cloudflare/index.d.ts.map +1 -1
- package/dist/cloudflare/index.js +1 -1
- package/dist/cloudflare/sentinel.d.ts +39 -1
- package/dist/cloudflare/sentinel.d.ts.map +1 -1
- package/dist/cloudflare/sentinel.js +22 -1
- package/dist/cloudflare/worker.d.ts +119 -2
- package/dist/cloudflare/worker.d.ts.map +1 -1
- package/dist/cloudflare/worker.js +90 -6
- package/dist/internal/aiDefault.d.ts +141 -0
- package/dist/internal/aiDefault.d.ts.map +1 -0
- package/dist/internal/aiDefault.js +204 -0
- package/dist/internal/aiProviders.d.ts +4 -1
- package/dist/internal/aiProviders.d.ts.map +1 -1
- package/dist/internal/aiProviders.js +5 -1
- package/dist/internal/appSettings.d.ts +20 -2
- package/dist/internal/appSettings.d.ts.map +1 -1
- package/dist/internal/appSettings.js +53 -7
- package/dist/internal/audit.d.ts +108 -0
- package/dist/internal/audit.d.ts.map +1 -0
- package/dist/internal/audit.js +235 -0
- package/dist/internal/capabilities.d.ts +275 -6
- package/dist/internal/capabilities.d.ts.map +1 -1
- package/dist/internal/capabilities.js +111 -0
- package/dist/internal/catalog/index.d.ts +38 -1
- package/dist/internal/catalog/index.d.ts.map +1 -1
- package/dist/internal/catalog/inference.d.ts +38 -1
- package/dist/internal/catalog/inference.d.ts.map +1 -1
- package/dist/internal/catalog/inference.js +33 -1
- package/dist/internal/devProviders.d.ts +2 -2
- package/dist/internal/devProviders.d.ts.map +1 -1
- package/dist/internal/devProviders.js +19 -1
- package/dist/internal/events.d.ts +13 -2
- package/dist/internal/events.d.ts.map +1 -1
- package/dist/internal/events.js +19 -3
- package/dist/internal/index.d.ts +4 -0
- package/dist/internal/index.d.ts.map +1 -1
- package/dist/internal/index.js +4 -0
- package/dist/internal/oauthPresets.d.ts +29 -0
- package/dist/internal/oauthPresets.d.ts.map +1 -0
- package/dist/internal/oauthPresets.js +534 -0
- package/dist/internal/oauthScopes.d.ts +56 -1
- package/dist/internal/oauthScopes.d.ts.map +1 -1
- package/dist/internal/oauthScopes.js +98 -4
- package/dist/internal/oauthSpec.d.ts +59 -0
- package/dist/internal/oauthSpec.d.ts.map +1 -0
- package/dist/internal/oauthSpec.js +676 -0
- package/dist/internal/protocol.d.ts +11 -0
- package/dist/internal/protocol.d.ts.map +1 -1
- package/dist/internal/protocol.js +9 -0
- package/dist/internal/providerRegistry.d.ts +17 -6
- package/dist/internal/providerRegistry.d.ts.map +1 -1
- package/dist/internal/providerRegistry.js +47 -2
- package/dist/internal/providerSpec.d.ts +11 -7
- package/dist/internal/providerSpec.d.ts.map +1 -1
- package/dist/internal/providerSpec.js +134 -37
- package/dist/internal/signInProviders.d.ts.map +1 -1
- package/dist/internal/signInProviders.js +11 -4
- package/dist/server/ai.d.ts +45 -0
- package/dist/server/ai.d.ts.map +1 -0
- package/dist/server/ai.js +40 -0
- package/dist/server/connectUrl.d.ts +21 -0
- package/dist/server/connectUrl.d.ts.map +1 -0
- package/dist/server/connectUrl.js +37 -0
- package/dist/server/gatewayFetch.d.ts.map +1 -1
- package/dist/server/gatewayFetch.js +72 -8
- package/dist/server/index.d.ts +4 -2
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +3 -1
- package/dist/server/integrationFetch.d.ts +39 -2
- package/dist/server/integrationFetch.d.ts.map +1 -1
- package/dist/server/integrationFetch.js +177 -13
- package/package.json +1 -1
|
@@ -30,7 +30,7 @@ export function declaredScopeSets(policy, entry) {
|
|
|
30
30
|
export function requestedScopes(policy, sets) {
|
|
31
31
|
const scopes = [];
|
|
32
32
|
const userScopes = [];
|
|
33
|
-
for (const [, set] of
|
|
33
|
+
for (const [, set] of setsOf(policy, sets)) {
|
|
34
34
|
pushNew(scopes, set.scopes);
|
|
35
35
|
pushNew(userScopes, set.userScopes ?? []);
|
|
36
36
|
}
|
|
@@ -103,7 +103,91 @@ export function grantedScopes(policy, json) {
|
|
|
103
103
|
}
|
|
104
104
|
case "slack":
|
|
105
105
|
return slackGrantedScopes(body);
|
|
106
|
+
case "space":
|
|
107
|
+
case "comma": {
|
|
108
|
+
const scopes = splitScopes(policy.dialect, body["scope"]);
|
|
109
|
+
return scopes ? { scopes } : null;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* What a token response granted, for the Gateway-owned flow: as
|
|
115
|
+
* {@link grantedScopes}, except that a `space` or `comma` provider that
|
|
116
|
+
* names no `scope` at all is taken at its word (RFC 6749 §5.1: the field
|
|
117
|
+
* is optional when the grant matches the request), so `requested` stands.
|
|
118
|
+
* The three parsed dialects keep failing closed.
|
|
119
|
+
*/
|
|
120
|
+
export function grantedScopesOrRequested(policy, json, requested) {
|
|
121
|
+
const granted = grantedScopes(policy, json);
|
|
122
|
+
if (granted)
|
|
123
|
+
return granted;
|
|
124
|
+
const body = record(json);
|
|
125
|
+
if (body &&
|
|
126
|
+
body["scope"] === undefined &&
|
|
127
|
+
(policy.dialect === "space" || policy.dialect === "comma")) {
|
|
128
|
+
return { scopes: canonical(policy.dialect, requested.scopes) };
|
|
106
129
|
}
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Whether an app's call with a held token goes through, and under which
|
|
134
|
+
* set (docs/design/2026-10-oauth-providers.md section 7). In order: every
|
|
135
|
+
* set the app declares must be among the connection's (else the person
|
|
136
|
+
* connects again: `integration_not_connected` with the missing sets); the
|
|
137
|
+
* host must be one of the provider's `api` hosts; the path passes the
|
|
138
|
+
* segment rules (`scopeRouteAllows`'s: no batch tunnels, no dot segments,
|
|
139
|
+
* no denied segments); then a declared set with routes must cover the
|
|
140
|
+
* call, or a declared set without routes covers its hosts by access: a
|
|
141
|
+
* read set unlocks `readMethods` (GET and HEAD by default), a write set
|
|
142
|
+
* every method the provider offers. `writes` says whether the method is
|
|
143
|
+
* one the grant allows beyond reads, decided by the caller as for an
|
|
144
|
+
* API-key provider.
|
|
145
|
+
*/
|
|
146
|
+
export function heldTokenCallAllowed({ policy, declaredSets, connectionSets, hosts, method, upstream, readMethods = ["GET", "HEAD"], writes, }) {
|
|
147
|
+
const missingSets = declaredSets.filter((name) => !connectionSets.includes(name));
|
|
148
|
+
if (missingSets.length > 0) {
|
|
149
|
+
return { ok: false, code: "integration_not_connected", missingSets };
|
|
150
|
+
}
|
|
151
|
+
if (upstream.protocol !== "https:" || !hosts.includes(upstream.host)) {
|
|
152
|
+
return {
|
|
153
|
+
ok: false,
|
|
154
|
+
code: "integration_scope_not_allowed",
|
|
155
|
+
message: `${upstream.host} is not a host this provider's token reaches (${hosts.join(", ")}).`,
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
if (!safeSegments(policy, upstream.pathname)) {
|
|
159
|
+
return {
|
|
160
|
+
ok: false,
|
|
161
|
+
code: "integration_scope_not_allowed",
|
|
162
|
+
message: `${upstream.pathname} is a path no scope set unlocks.`,
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
const verb = method.toUpperCase();
|
|
166
|
+
const reads = readMethods.includes(verb);
|
|
167
|
+
// A set's routes decide first: a read-shaped POST a read set lists
|
|
168
|
+
// under `posts` (a search, a query) is a read whatever the grant.
|
|
169
|
+
const routed = scopeRouteAllows(policy, declaredSets, verb, upstream);
|
|
170
|
+
if (routed)
|
|
171
|
+
return { ok: true, set: routed };
|
|
172
|
+
if (!reads && !writes) {
|
|
173
|
+
return {
|
|
174
|
+
ok: false,
|
|
175
|
+
code: "integration_method_not_allowed",
|
|
176
|
+
message: `${verb} ${upstream.pathname}: calls may use ${readMethods.join(" or ")} with access: "read"; ${verb} needs access: "write" in the app's capabilities entry, on a provider that offers it, or a scope set whose routes list it.`,
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
for (const [name, set] of setsOf(policy, declaredSets)) {
|
|
180
|
+
if (set.routes.length > 0)
|
|
181
|
+
continue;
|
|
182
|
+
if (reads || (writes && set.access === "write")) {
|
|
183
|
+
return { ok: true, set: name };
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
return {
|
|
187
|
+
ok: false,
|
|
188
|
+
code: "integration_scope_not_allowed",
|
|
189
|
+
message: `${verb} ${upstream.pathname} is outside the scope sets this app declares (${declaredSets.join(", ")}).`,
|
|
190
|
+
};
|
|
107
191
|
}
|
|
108
192
|
/**
|
|
109
193
|
* Slack answers with up to two tokens, each with its own scopes: the bot
|
|
@@ -243,7 +327,7 @@ export function rewriteTokenRequestScope(policy, sets, request) {
|
|
|
243
327
|
export function scopeRouteAllows(policy, sets, method, upstream) {
|
|
244
328
|
if (upstream.protocol !== "https:")
|
|
245
329
|
return null;
|
|
246
|
-
const onHost =
|
|
330
|
+
const onHost = setsOf(policy, sets).flatMap(([name, set]) => set.routes
|
|
247
331
|
.filter((route) => route.host === upstream.host)
|
|
248
332
|
.map((route) => [name, route]));
|
|
249
333
|
if (onHost.length === 0)
|
|
@@ -318,7 +402,7 @@ function safeSegment(text, denied) {
|
|
|
318
402
|
return !text.split("/").some((part) => DOT_SEGMENT.test(part));
|
|
319
403
|
}
|
|
320
404
|
/** The policy's sets in registry order, keeping those `names` declares. */
|
|
321
|
-
function
|
|
405
|
+
function setsOf(policy, names) {
|
|
322
406
|
return Object.entries(policy.sets).filter(([name]) => names.includes(name));
|
|
323
407
|
}
|
|
324
408
|
const GOOGLE_ALIASES = new Map([
|
|
@@ -327,6 +411,14 @@ const GOOGLE_ALIASES = new Map([
|
|
|
327
411
|
]);
|
|
328
412
|
const GRAPH_PREFIX = /^https:\/\/graph\.microsoft\.com\//i;
|
|
329
413
|
/** `scopes` in the dialect's one spelling, deduplicated, order kept. */
|
|
414
|
+
/**
|
|
415
|
+
* `scopes` in the dialect's canonical spelling (Google's long names,
|
|
416
|
+
* Microsoft's bare lower-case names), for comparing a set's scopes with
|
|
417
|
+
* what a token response says it granted.
|
|
418
|
+
*/
|
|
419
|
+
export function canonicalScopes(dialect, scopes) {
|
|
420
|
+
return canonical(dialect, [...scopes]);
|
|
421
|
+
}
|
|
330
422
|
function canonical(dialect, scopes) {
|
|
331
423
|
return pushNew([], scopes.map((scope) => {
|
|
332
424
|
switch (dialect) {
|
|
@@ -335,6 +427,8 @@ function canonical(dialect, scopes) {
|
|
|
335
427
|
case "microsoft":
|
|
336
428
|
return scope.replace(GRAPH_PREFIX, "").toLowerCase();
|
|
337
429
|
case "slack":
|
|
430
|
+
case "space":
|
|
431
|
+
case "comma":
|
|
338
432
|
return scope;
|
|
339
433
|
}
|
|
340
434
|
}));
|
|
@@ -347,7 +441,7 @@ function canonical(dialect, scopes) {
|
|
|
347
441
|
function splitScopes(dialect, value) {
|
|
348
442
|
if (typeof value !== "string")
|
|
349
443
|
return null;
|
|
350
|
-
const separator = dialect === "slack" ? /[,\s]+/ : /\s+/;
|
|
444
|
+
const separator = dialect === "slack" || dialect === "comma" ? /[,\s]+/ : /\s+/;
|
|
351
445
|
const scopes = canonical(dialect, value.split(separator).filter(Boolean));
|
|
352
446
|
return scopes.length > 0 ? scopes : null;
|
|
353
447
|
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `oauth2-user` half of a provider spec
|
|
3
|
+
* (docs/design/2026-10-oauth-providers.md section 3): a registered OAuth
|
|
4
|
+
* provider, or a preset (./oauthPresets.ts), as JSON, turned into the
|
|
5
|
+
* same {@link OAuthClientCapability} a catalog client is, with a `flow`
|
|
6
|
+
* the Gateway runs itself. `parseProviderSpec` (./providerSpec.ts) hands
|
|
7
|
+
* the common fields here once it sees `auth.kind: "oauth2-user"`; nothing
|
|
8
|
+
* here reads a value: a spec names Gateway settings, never holds one.
|
|
9
|
+
*/
|
|
10
|
+
import { type CapabilityAccess, type OAuthClientCapability } from "./capabilities.js";
|
|
11
|
+
export interface SpecProblem {
|
|
12
|
+
path: string;
|
|
13
|
+
message: string;
|
|
14
|
+
}
|
|
15
|
+
/** A scope set's name: `identity`, or `<area>.<access>` (`repo.read`), lowercase. */
|
|
16
|
+
export declare const SCOPE_SET_NAME: RegExp;
|
|
17
|
+
/** Segments no set unlocks on any host: batch tunnels carry whole requests inside. */
|
|
18
|
+
export declare const DEFAULT_DENIED_SEGMENTS: readonly string[];
|
|
19
|
+
/** The fields of `auth` when its kind is `oauth2-user`. */
|
|
20
|
+
export declare const OAUTH_AUTH_FIELDS: readonly ["kind", "authorizeUrl", "tokenUrl", "revokeUrl", "revokeMethod", "clientId", "clientSecret", "inject", "pkce", "scopeDialect", "authorizeParams", "tokenHeaders", "identity"];
|
|
21
|
+
/** The common fields `parseProviderSpec` parsed before handing over. */
|
|
22
|
+
export interface OAuthSpecCommon {
|
|
23
|
+
id: string;
|
|
24
|
+
name: string;
|
|
25
|
+
docs: string;
|
|
26
|
+
hosts: readonly string[];
|
|
27
|
+
description?: string;
|
|
28
|
+
reference?: string;
|
|
29
|
+
access?: readonly CapabilityAccess[];
|
|
30
|
+
readMethods?: readonly string[];
|
|
31
|
+
writeMethods?: readonly string[];
|
|
32
|
+
hint?: string;
|
|
33
|
+
example?: string;
|
|
34
|
+
tags?: readonly string[];
|
|
35
|
+
}
|
|
36
|
+
/** What `parseOAuthUserSpec` returns on success, before the registry's rules. */
|
|
37
|
+
export interface ParsedOAuthSpec {
|
|
38
|
+
capability: OAuthClientCapability;
|
|
39
|
+
/** Every host a row's rules must accept: the API hosts and the endpoints'. */
|
|
40
|
+
hosts: string[];
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Parse the OAuth half of a spec whose `auth.kind` is `oauth2-user`:
|
|
44
|
+
* `auth` itself, `scopeSets`, `alwaysRequested` and `tolerated`, with
|
|
45
|
+
* the common fields already parsed. Every problem is reported; on
|
|
46
|
+
* success the catalog-shaped capability with its `flow`.
|
|
47
|
+
*/
|
|
48
|
+
export declare function parseOAuthUserSpec(input: Record<string, unknown>, common: OAuthSpecCommon, problems: SpecProblem[]): ParsedOAuthSpec | undefined;
|
|
49
|
+
/**
|
|
50
|
+
* The JSON spec of an OAuth capability that has a `flow` (`provider
|
|
51
|
+
* show`, a preset's round trip): `parseProviderSpec` of it gives the
|
|
52
|
+
* capability back. A catalog client without a `flow` has no spec.
|
|
53
|
+
*/
|
|
54
|
+
export declare function oauthSpecOf(id: string, capability: OAuthClientCapability): Record<string, unknown> | null;
|
|
55
|
+
/** The methods a held-token write may use on `capability` beyond its reads. */
|
|
56
|
+
export declare function oauthWriteMethods(capability: OAuthClientCapability): readonly string[];
|
|
57
|
+
/** The methods a read grant may use on `capability` (GET and HEAD unless the spec says). */
|
|
58
|
+
export declare function oauthReadMethods(capability: OAuthClientCapability): readonly string[];
|
|
59
|
+
//# sourceMappingURL=oauthSpec.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauthSpec.d.ts","sourceRoot":"","sources":["../../src/internal/oauthSpec.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAEL,KAAK,gBAAgB,EACrB,KAAK,qBAAqB,EAQ3B,MAAM,mBAAmB,CAAC;AAE3B,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,qFAAqF;AACrF,eAAO,MAAM,cAAc,QAC0B,CAAC;AA4BtD,sFAAsF;AACtF,eAAO,MAAM,uBAAuB,EAAE,SAAS,MAAM,EAAwB,CAAC;AAE9E,2DAA2D;AAC3D,eAAO,MAAM,iBAAiB,yLAcpB,CAAC;AAEX,wEAAwE;AACxE,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,SAAS,gBAAgB,EAAE,CAAC;IACrC,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAChC,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC1B;AAmXD,iFAAiF;AACjF,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,qBAAqB,CAAC;IAClC,8EAA8E;IAC9E,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,MAAM,EAAE,eAAe,EACvB,QAAQ,EAAE,WAAW,EAAE,GACtB,eAAe,GAAG,SAAS,CAqN7B;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CACzB,EAAE,EAAE,MAAM,EACV,UAAU,EAAE,qBAAqB,GAChC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAyFhC;AAED,+EAA+E;AAC/E,wBAAgB,iBAAiB,CAC/B,UAAU,EAAE,qBAAqB,GAChC,SAAS,MAAM,EAAE,CAEnB;AAED,4FAA4F;AAC5F,wBAAgB,gBAAgB,CAC9B,UAAU,EAAE,qBAAqB,GAChC,SAAS,MAAM,EAAE,CAEnB"}
|