@executor-js/plugin-openapi 1.5.5 → 1.5.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/{AddOpenApiSource-7M52SRUX.js → AddOpenApiSource-7O4LSD7C.js} +79 -241
- package/dist/AddOpenApiSource-7O4LSD7C.js.map +1 -0
- package/dist/{EditOpenApiSource-WTAMRJUK.js → EditOpenApiSource-GIN5RQPL.js} +3 -3
- package/dist/{OpenApiAccountsPanel-3VJJXNQF.js → OpenApiAccountsPanel-7XT6ZMD5.js} +30 -28
- package/dist/OpenApiAccountsPanel-7XT6ZMD5.js.map +1 -0
- package/dist/api/group.d.ts +38 -37
- package/dist/api/index.d.ts +39 -38
- package/dist/{chunk-YVRI7KRC.js → chunk-C3IJX4AN.js} +257 -219
- package/dist/chunk-C3IJX4AN.js.map +1 -0
- package/dist/{chunk-OSIFYIQP.js → chunk-C6PH4R7Q.js} +94 -5
- package/dist/chunk-C6PH4R7Q.js.map +1 -0
- package/dist/{chunk-BSLE6HCE.js → chunk-IB36ED7Y.js} +13 -27
- package/dist/chunk-IB36ED7Y.js.map +1 -0
- package/dist/chunk-RCBR3QMJ.js +73 -0
- package/dist/chunk-RCBR3QMJ.js.map +1 -0
- package/dist/{chunk-V7VCHYOY.js → chunk-WJQIWTZF.js} +97 -172
- package/dist/chunk-WJQIWTZF.js.map +1 -0
- package/dist/client.js +3 -3
- package/dist/core.js +133 -7
- package/dist/core.js.map +1 -1
- package/dist/index.js +7 -5
- package/dist/index.js.map +1 -1
- package/dist/react/AddOpenApiSource.d.ts +0 -1
- package/dist/react/OpenApiSourceDetailsFields.d.ts +3 -0
- package/dist/react/atoms.d.ts +40 -52
- package/dist/react/auth-method-config.d.ts +7 -4
- package/dist/react/client.d.ts +38 -37
- package/dist/sdk/config.d.ts +27 -27
- package/dist/sdk/derive-auth.d.ts +9 -0
- package/dist/sdk/extract.d.ts +11 -1
- package/dist/sdk/index.d.ts +6 -2
- package/dist/sdk/invoke.d.ts +11 -1
- package/dist/sdk/migrate-config.d.ts +4 -0
- package/dist/sdk/migrate-config.test.d.ts +1 -0
- package/dist/sdk/openapi-utils.d.ts +4 -8
- package/dist/sdk/output-schema-migration.d.ts +21 -0
- package/dist/sdk/output-schema-migration.test.d.ts +1 -0
- package/dist/sdk/plugin.d.ts +6 -4
- package/dist/sdk/preview.d.ts +77 -1
- package/dist/sdk/server-url-resolution.test.d.ts +1 -0
- package/dist/sdk/spec-blob-migration.d.ts +7 -0
- package/dist/sdk/spec-blob.test.d.ts +1 -0
- package/dist/sdk/store.d.ts +10 -1
- package/dist/sdk/tool-row-projection.test.d.ts +1 -0
- package/dist/sdk/types.d.ts +61 -36
- package/dist/testing/index.d.ts +1 -1
- package/dist/testing.js +4 -20
- package/dist/testing.js.map +1 -1
- package/package.json +3 -3
- package/dist/AddOpenApiSource-7M52SRUX.js.map +0 -1
- package/dist/OpenApiAccountsPanel-3VJJXNQF.js.map +0 -1
- package/dist/chunk-BSLE6HCE.js.map +0 -1
- package/dist/chunk-OSIFYIQP.js.map +0 -1
- package/dist/chunk-QSSRVK6M.js +0 -139
- package/dist/chunk-QSSRVK6M.js.map +0 -1
- package/dist/chunk-V7VCHYOY.js.map +0 -1
- package/dist/chunk-YVRI7KRC.js.map +0 -1
- /package/dist/{EditOpenApiSource-WTAMRJUK.js.map → EditOpenApiSource-GIN5RQPL.js.map} +0 -0
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
// src/react/auth-method-config.ts
|
|
2
|
+
import { AuthTemplateSlug } from "@executor-js/sdk/shared";
|
|
3
|
+
import {
|
|
4
|
+
authMethodFromSharedTemplate,
|
|
5
|
+
editorPlacementsFromWire,
|
|
6
|
+
editorValueFromSharedMethod,
|
|
7
|
+
wireAuthInputFromShared,
|
|
8
|
+
wirePlacementsFromEditor
|
|
9
|
+
} from "@executor-js/react/lib/shared-auth-method-codec";
|
|
10
|
+
var openApiWireAuthInput = (method) => method.kind === "oauth2" ? method : wireAuthInputFromShared(method);
|
|
11
|
+
var oauthAuthMethod = (template) => {
|
|
12
|
+
const slug = String(template.slug);
|
|
13
|
+
return {
|
|
14
|
+
id: slug,
|
|
15
|
+
label: "OAuth2",
|
|
16
|
+
kind: "oauth",
|
|
17
|
+
source: slug.startsWith("custom_") ? "custom" : "spec",
|
|
18
|
+
template: AuthTemplateSlug.make(slug),
|
|
19
|
+
placements: [],
|
|
20
|
+
// Carry the integration's declared endpoints/scopes so the
|
|
21
|
+
// client-registration form pre-fills them.
|
|
22
|
+
oauth: {
|
|
23
|
+
authorizationUrl: template.authorizationUrl,
|
|
24
|
+
tokenUrl: template.tokenUrl,
|
|
25
|
+
scopes: template.scopes
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
};
|
|
29
|
+
function authMethodsFromConfig(templates) {
|
|
30
|
+
return templates.map((template) => {
|
|
31
|
+
if (template.kind === "oauth2") return oauthAuthMethod(template);
|
|
32
|
+
return authMethodFromSharedTemplate(template);
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
function templateFromPlacements(placements, slug) {
|
|
36
|
+
return {
|
|
37
|
+
slug: slug ?? "",
|
|
38
|
+
kind: "apikey",
|
|
39
|
+
placements: wirePlacementsFromEditor(placements)
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
function editorValueFromAuthentication(template) {
|
|
43
|
+
if (template.kind === "oauth2") {
|
|
44
|
+
return {
|
|
45
|
+
kind: "oauth",
|
|
46
|
+
authorizationUrl: template.authorizationUrl ?? "",
|
|
47
|
+
tokenUrl: template.tokenUrl ?? "",
|
|
48
|
+
scopes: template.scopes ?? []
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
return editorValueFromSharedMethod(template);
|
|
52
|
+
}
|
|
53
|
+
var oauthTemplateFromEditorValue = (value, slug) => ({
|
|
54
|
+
slug: AuthTemplateSlug.make(slug ?? ""),
|
|
55
|
+
kind: "oauth2",
|
|
56
|
+
authorizationUrl: value.authorizationUrl,
|
|
57
|
+
tokenUrl: value.tokenUrl,
|
|
58
|
+
scopes: [...value.scopes]
|
|
59
|
+
});
|
|
60
|
+
function authenticationFromEditorValue(value, slug) {
|
|
61
|
+
if (value.kind === "none") return null;
|
|
62
|
+
if (value.kind === "oauth") return oauthTemplateFromEditorValue(value, slug);
|
|
63
|
+
return templateFromPlacements(value.placements, slug);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export {
|
|
67
|
+
openApiWireAuthInput,
|
|
68
|
+
authMethodsFromConfig,
|
|
69
|
+
templateFromPlacements,
|
|
70
|
+
editorValueFromAuthentication,
|
|
71
|
+
authenticationFromEditorValue
|
|
72
|
+
};
|
|
73
|
+
//# sourceMappingURL=chunk-RCBR3QMJ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/react/auth-method-config.ts"],"sourcesContent":["// ---------------------------------------------------------------------------\n// OpenAPI ↔ generic auth-method converters — a thin oauth adapter over the\n// shared codec (`@executor-js/react/lib/shared-auth-method-codec`). The\n// apikey/none paths (multi-placement, multi-variable) live in the shared\n// codec; OpenAPI only contributes its oauth flavor: stored endpoints + scopes\n// (`kind: \"oauth2\"`, the core `OAuthAuthentication` shape) that pre-fill the client-registration form.\n// ---------------------------------------------------------------------------\n\nimport { AuthTemplateSlug } from \"@executor-js/sdk/shared\";\nimport type { AuthMethod, Placement } from \"@executor-js/react/lib/auth-placements\";\nimport type { AuthTemplateEditorValue } from \"@executor-js/react/components/auth-template-editor\";\nimport {\n authMethodFromSharedTemplate,\n editorPlacementsFromWire,\n editorValueFromSharedMethod,\n wireAuthInputFromShared,\n wirePlacementsFromEditor,\n} from \"@executor-js/react/lib/shared-auth-method-codec\";\n\nimport type { APIKeyAuthentication, Authentication, AuthenticationInput } from \"../sdk/types\";\n\n/** Serialize a canonical method into the wire input union (apikey → the\n * request-shaped dialect; oauth passes through). */\nexport const openApiWireAuthInput = (method: Authentication): AuthenticationInput =>\n method.kind === \"oauth2\" ? method : (wireAuthInputFromShared(method) as AuthenticationInput);\n\nexport const placementsFromApiKey = (template: APIKeyAuthentication): readonly Placement[] =>\n editorPlacementsFromWire(template.placements);\n\nconst oauthAuthMethod = (template: Extract<Authentication, { kind: \"oauth2\" }>): AuthMethod => {\n const slug = String(template.slug);\n return {\n id: slug,\n label: \"OAuth2\",\n kind: \"oauth\",\n source: slug.startsWith(\"custom_\") ? \"custom\" : \"spec\",\n template: AuthTemplateSlug.make(slug),\n placements: [],\n // Carry the integration's declared endpoints/scopes so the\n // client-registration form pre-fills them.\n oauth: {\n authorizationUrl: template.authorizationUrl,\n tokenUrl: template.tokenUrl,\n scopes: template.scopes,\n },\n };\n};\n\n/** Map each stored auth template to a generic `AuthMethod`. */\nexport function authMethodsFromConfig(templates: readonly Authentication[]): AuthMethod[] {\n return templates.map((template: Authentication): AuthMethod => {\n if (template.kind === \"oauth2\") return oauthAuthMethod(template);\n return authMethodFromSharedTemplate(template);\n });\n}\n\n/** Build an apikey method from generic placements. When `slug` is omitted the\n * backend assigns a `custom_<id>` slug. */\nexport function templateFromPlacements(\n placements: readonly Placement[],\n slug?: string,\n): APIKeyAuthentication {\n return {\n slug: slug ?? \"\",\n kind: \"apikey\",\n placements: wirePlacementsFromEditor(placements),\n };\n}\n\n// ---------------------------------------------------------------------------\n// Stored `Authentication` ⇆ generic `AuthTemplateEditorValue`.\n// ---------------------------------------------------------------------------\n\n/** Convert one stored `Authentication` template into a generic editor value. */\nexport function editorValueFromAuthentication(template: Authentication): AuthTemplateEditorValue {\n if (template.kind === \"oauth2\") {\n return {\n kind: \"oauth\",\n authorizationUrl: template.authorizationUrl ?? \"\",\n tokenUrl: template.tokenUrl ?? \"\",\n scopes: template.scopes ?? [],\n };\n }\n return editorValueFromSharedMethod(template);\n}\n\n/** Build an `OAuthAuthentication` template from a generic oauth editor value. */\nconst oauthTemplateFromEditorValue = (\n value: Extract<AuthTemplateEditorValue, { kind: \"oauth\" }>,\n slug?: string,\n): Authentication => ({\n slug: AuthTemplateSlug.make(slug ?? \"\"),\n kind: \"oauth2\",\n authorizationUrl: value.authorizationUrl,\n tokenUrl: value.tokenUrl,\n scopes: [...value.scopes],\n});\n\n/** Convert one generic editor value back into a stored `Authentication`, or\n * `null` for `none` (no method to register). The optional `slug` names the\n * template; when omitted the backend backfills `custom_<id>`. */\nexport function authenticationFromEditorValue(\n value: AuthTemplateEditorValue,\n slug?: string,\n): Authentication | null {\n if (value.kind === \"none\") return null;\n if (value.kind === \"oauth\") return oauthTemplateFromEditorValue(value, slug);\n return templateFromPlacements(value.placements, slug);\n}\n"],"mappings":";AAQA,SAAS,wBAAwB;AAGjC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAMA,IAAM,uBAAuB,CAAC,WACnC,OAAO,SAAS,WAAW,SAAU,wBAAwB,MAAM;AAKrE,IAAM,kBAAkB,CAAC,aAAsE;AAC7F,QAAM,OAAO,OAAO,SAAS,IAAI;AACjC,SAAO;AAAA,IACL,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,MAAM;AAAA,IACN,QAAQ,KAAK,WAAW,SAAS,IAAI,WAAW;AAAA,IAChD,UAAU,iBAAiB,KAAK,IAAI;AAAA,IACpC,YAAY,CAAC;AAAA;AAAA;AAAA,IAGb,OAAO;AAAA,MACL,kBAAkB,SAAS;AAAA,MAC3B,UAAU,SAAS;AAAA,MACnB,QAAQ,SAAS;AAAA,IACnB;AAAA,EACF;AACF;AAGO,SAAS,sBAAsB,WAAoD;AACxF,SAAO,UAAU,IAAI,CAAC,aAAyC;AAC7D,QAAI,SAAS,SAAS,SAAU,QAAO,gBAAgB,QAAQ;AAC/D,WAAO,6BAA6B,QAAQ;AAAA,EAC9C,CAAC;AACH;AAIO,SAAS,uBACd,YACA,MACsB;AACtB,SAAO;AAAA,IACL,MAAM,QAAQ;AAAA,IACd,MAAM;AAAA,IACN,YAAY,yBAAyB,UAAU;AAAA,EACjD;AACF;AAOO,SAAS,8BAA8B,UAAmD;AAC/F,MAAI,SAAS,SAAS,UAAU;AAC9B,WAAO;AAAA,MACL,MAAM;AAAA,MACN,kBAAkB,SAAS,oBAAoB;AAAA,MAC/C,UAAU,SAAS,YAAY;AAAA,MAC/B,QAAQ,SAAS,UAAU,CAAC;AAAA,IAC9B;AAAA,EACF;AACA,SAAO,4BAA4B,QAAQ;AAC7C;AAGA,IAAM,+BAA+B,CACnC,OACA,UACoB;AAAA,EACpB,MAAM,iBAAiB,KAAK,QAAQ,EAAE;AAAA,EACtC,MAAM;AAAA,EACN,kBAAkB,MAAM;AAAA,EACxB,UAAU,MAAM;AAAA,EAChB,QAAQ,CAAC,GAAG,MAAM,MAAM;AAC1B;AAKO,SAAS,8BACd,OACA,MACuB;AACvB,MAAI,MAAM,SAAS,OAAQ,QAAO;AAClC,MAAI,MAAM,SAAS,QAAS,QAAO,6BAA6B,OAAO,IAAI;AAC3E,SAAO,uBAAuB,MAAM,YAAY,IAAI;AACtD;","names":[]}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
convertGoogleDiscoveryBundleToOpenApi,
|
|
3
3
|
convertGoogleDiscoveryToOpenApi,
|
|
4
|
+
deriveAuthenticationTemplateFromPreview,
|
|
4
5
|
fetchGoogleDiscoveryDocument,
|
|
6
|
+
firstBaseUrlForPreview,
|
|
5
7
|
isGoogleDiscoveryUrl
|
|
6
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-C6PH4R7Q.js";
|
|
7
9
|
import {
|
|
8
10
|
openApiPresets
|
|
9
11
|
} from "./chunk-AQ7JDDRM.js";
|
|
@@ -12,48 +14,40 @@ import {
|
|
|
12
14
|
OpenApiExtractionError,
|
|
13
15
|
OpenApiInvocationError,
|
|
14
16
|
OperationBinding,
|
|
15
|
-
TOKEN_VARIABLE,
|
|
16
17
|
extract,
|
|
18
|
+
normalizeOpenApiAuthInputs,
|
|
17
19
|
parse,
|
|
18
20
|
previewSpec,
|
|
21
|
+
previewSpecText,
|
|
22
|
+
resolveServerUrl,
|
|
19
23
|
resolveSpecText
|
|
20
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-C3IJX4AN.js";
|
|
21
25
|
|
|
22
26
|
// src/sdk/config.ts
|
|
23
27
|
import { Option, Schema } from "effect";
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
Schema.Array(Schema.Union([Schema.String, AuthenticationVariableSchema]))
|
|
31
|
-
]);
|
|
32
|
-
var APIKeyAuthenticationSchema = Schema.Struct({
|
|
33
|
-
slug: Schema.String,
|
|
34
|
-
type: Schema.Literal("apiKey"),
|
|
35
|
-
headers: Schema.optional(Schema.Record(Schema.String, AuthenticationTemplateValueSchema)),
|
|
36
|
-
queryParams: Schema.optional(Schema.Record(Schema.String, AuthenticationTemplateValueSchema))
|
|
37
|
-
});
|
|
28
|
+
import {
|
|
29
|
+
ApiKeyAuthMethod,
|
|
30
|
+
TOKEN_VARIABLE,
|
|
31
|
+
renderAuthPlacements,
|
|
32
|
+
requiredPlacementVariables
|
|
33
|
+
} from "@executor-js/sdk/http-auth";
|
|
38
34
|
var OAuthAuthenticationSchema = Schema.Struct({
|
|
39
35
|
slug: Schema.String,
|
|
40
|
-
|
|
36
|
+
kind: Schema.Literal("oauth2"),
|
|
41
37
|
authorizationUrl: Schema.String,
|
|
42
38
|
tokenUrl: Schema.String,
|
|
43
39
|
scopes: Schema.Array(Schema.String)
|
|
44
40
|
});
|
|
45
|
-
var AuthenticationSchema = Schema.Union([
|
|
46
|
-
OAuthAuthenticationSchema,
|
|
47
|
-
APIKeyAuthenticationSchema
|
|
48
|
-
]);
|
|
41
|
+
var AuthenticationSchema = Schema.Union([OAuthAuthenticationSchema, ApiKeyAuthMethod]);
|
|
49
42
|
var OpenApiIntegrationConfigSchema = Schema.Struct({
|
|
50
|
-
/**
|
|
51
|
-
spec
|
|
43
|
+
/** Hex SHA-256 of the resolved spec text — the content address of the spec
|
|
44
|
+
* blob (`spec/<hash>` in the plugin blob store). */
|
|
45
|
+
specHash: Schema.optional(Schema.String),
|
|
52
46
|
/** Origin URL the spec was fetched from, when known. Enables refresh. */
|
|
53
47
|
sourceUrl: Schema.optional(Schema.String),
|
|
54
48
|
/** Google Discovery bundle URLs, when the spec came from a Google bundle. */
|
|
55
49
|
googleDiscoveryUrls: Schema.optional(Schema.Array(Schema.String)),
|
|
56
|
-
/**
|
|
50
|
+
/** Optional base URL override. */
|
|
57
51
|
baseUrl: Schema.optional(Schema.String),
|
|
58
52
|
/** Static headers applied to every request (no secret material). */
|
|
59
53
|
headers: Schema.optional(Schema.Record(Schema.String, Schema.String)),
|
|
@@ -64,40 +58,18 @@ var OpenApiIntegrationConfigSchema = Schema.Struct({
|
|
|
64
58
|
});
|
|
65
59
|
var decodeConfig = Schema.decodeUnknownOption(OpenApiIntegrationConfigSchema);
|
|
66
60
|
var decodeOpenApiIntegrationConfig = (value) => Option.getOrNull(decodeConfig(value));
|
|
67
|
-
var isVariable = (part) => typeof part !== "string";
|
|
68
|
-
var renderTemplateValue = (template, values) => {
|
|
69
|
-
if (typeof template === "string") return template;
|
|
70
|
-
return template.map((part) => isVariable(part) ? values[part.name] ?? "" : part).join("");
|
|
71
|
-
};
|
|
72
61
|
var renderAuthTemplate = (template, values) => {
|
|
73
|
-
if (template.
|
|
62
|
+
if (template.kind === "oauth2") {
|
|
74
63
|
return {
|
|
75
64
|
headers: { authorization: `Bearer ${values[TOKEN_VARIABLE] ?? ""}` },
|
|
76
65
|
queryParams: {}
|
|
77
66
|
};
|
|
78
67
|
}
|
|
79
|
-
|
|
80
|
-
const queryParams = {};
|
|
81
|
-
for (const [name, tmpl] of Object.entries(template.headers ?? {})) {
|
|
82
|
-
headers[name] = renderTemplateValue(tmpl, values);
|
|
83
|
-
}
|
|
84
|
-
for (const [name, tmpl] of Object.entries(template.queryParams ?? {})) {
|
|
85
|
-
queryParams[name] = renderTemplateValue(tmpl, values);
|
|
86
|
-
}
|
|
87
|
-
return { headers, queryParams };
|
|
68
|
+
return renderAuthPlacements(template.placements, values);
|
|
88
69
|
};
|
|
89
70
|
var requiredTemplateVariables = (template) => {
|
|
90
|
-
if (template.
|
|
91
|
-
|
|
92
|
-
const collect = (tmpl) => {
|
|
93
|
-
if (typeof tmpl === "string") return;
|
|
94
|
-
for (const part of tmpl) {
|
|
95
|
-
if (isVariable(part)) names.add(part.name);
|
|
96
|
-
}
|
|
97
|
-
};
|
|
98
|
-
for (const tmpl of Object.values(template.headers ?? {})) collect(tmpl);
|
|
99
|
-
for (const tmpl of Object.values(template.queryParams ?? {})) collect(tmpl);
|
|
100
|
-
return [...names];
|
|
71
|
+
if (template.kind === "oauth2") return [TOKEN_VARIABLE];
|
|
72
|
+
return requiredPlacementVariables(template.placements);
|
|
101
73
|
};
|
|
102
74
|
|
|
103
75
|
// src/sdk/invoke.ts
|
|
@@ -442,9 +414,21 @@ var invoke = Effect.fn("OpenApi.invoke")(function* (operation, args, resolvedHea
|
|
|
442
414
|
error: ok ? null : responseBody
|
|
443
415
|
});
|
|
444
416
|
});
|
|
417
|
+
var resolveRequestHost = (servers, serverArg, baseUrl) => {
|
|
418
|
+
if (baseUrl) return baseUrl;
|
|
419
|
+
if (servers.length === 0) return "";
|
|
420
|
+
const arg = typeof serverArg === "object" && serverArg !== null && !Array.isArray(serverArg) ? serverArg : {};
|
|
421
|
+
const chosen = servers.find((server) => server.url === arg.url) ?? servers[0];
|
|
422
|
+
const overrides = {};
|
|
423
|
+
if (typeof arg.variables === "object" && arg.variables !== null) {
|
|
424
|
+
for (const [name, value] of Object.entries(arg.variables)) {
|
|
425
|
+
if (value != null && value !== "") overrides[name] = String(value);
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
return resolveServerUrl(chosen.url, Option2.getOrUndefined(chosen.variables), overrides);
|
|
429
|
+
};
|
|
445
430
|
var invokeWithLayer = (operation, args, baseUrl, resolvedHeaders, sourceQueryParams, httpClientLayer) => {
|
|
446
|
-
const
|
|
447
|
-
const effectiveBaseUrl = operationBaseUrl ?? baseUrl;
|
|
431
|
+
const effectiveBaseUrl = resolveRequestHost(operation.servers ?? [], args.server, baseUrl);
|
|
448
432
|
const clientWithBaseUrl = effectiveBaseUrl ? Layer.effect(
|
|
449
433
|
HttpClient.HttpClient,
|
|
450
434
|
Effect.map(
|
|
@@ -500,7 +484,8 @@ var rowToOperation = (row) => {
|
|
|
500
484
|
};
|
|
501
485
|
};
|
|
502
486
|
var operationKey = (integration, toolName) => `${integration}.${toolName}`;
|
|
503
|
-
var
|
|
487
|
+
var specBlobKey = (specHash) => `spec/${specHash}`;
|
|
488
|
+
var makeDefaultOpenapiStore = ({ pluginStorage, blobs }) => {
|
|
504
489
|
const operationData = (operation) => ({
|
|
505
490
|
integration: operation.integration,
|
|
506
491
|
toolName: operation.toolName,
|
|
@@ -534,14 +519,15 @@ var makeDefaultOpenapiStore = ({ pluginStorage }) => {
|
|
|
534
519
|
listOperations: (integration) => listRows(integration).pipe(
|
|
535
520
|
Effect2.map((rows) => rows.map(rowToOperation).filter(Predicate.isNotNull))
|
|
536
521
|
),
|
|
537
|
-
removeOperations
|
|
522
|
+
removeOperations,
|
|
523
|
+
putSpec: (specHash, specText) => blobs.put(specBlobKey(specHash), specText, { owner: STORE_OWNER }),
|
|
524
|
+
getSpec: (specHash) => blobs.get(specBlobKey(specHash))
|
|
538
525
|
};
|
|
539
526
|
};
|
|
540
527
|
|
|
541
528
|
// src/sdk/plugin.ts
|
|
542
529
|
import { Effect as Effect3, Option as Option5, Schema as Schema3 } from "effect";
|
|
543
530
|
import {
|
|
544
|
-
AuthTemplateSlug,
|
|
545
531
|
IntegrationAlreadyExistsError,
|
|
546
532
|
IntegrationDetectionResult,
|
|
547
533
|
IntegrationSlug,
|
|
@@ -549,6 +535,8 @@ import {
|
|
|
549
535
|
ToolResult,
|
|
550
536
|
authToolFailure,
|
|
551
537
|
definePlugin,
|
|
538
|
+
mergeAuthTemplates,
|
|
539
|
+
sha256Hex,
|
|
552
540
|
tool
|
|
553
541
|
} from "@executor-js/sdk/core";
|
|
554
542
|
|
|
@@ -698,6 +686,7 @@ var compileToolDefinitions = (operations) => {
|
|
|
698
686
|
};
|
|
699
687
|
|
|
700
688
|
// src/sdk/plugin.ts
|
|
689
|
+
import { ApiKeyAuthTemplate, describeApiKeyAuthMethod } from "@executor-js/sdk/http-auth";
|
|
701
690
|
var STRINGIFIED_BODY_CAP = 1024;
|
|
702
691
|
var UpstreamMessageBody = Schema3.Struct({ message: Schema3.String });
|
|
703
692
|
var UpstreamErrorMessageBody = Schema3.Struct({ errorMessage: Schema3.String });
|
|
@@ -844,28 +833,18 @@ var OpenApiSpecInputSchema = Schema3.Union([
|
|
|
844
833
|
urls: Schema3.Array(Schema3.String)
|
|
845
834
|
})
|
|
846
835
|
]);
|
|
847
|
-
var AuthenticationVariableSchema2 = Schema3.Struct({
|
|
848
|
-
type: Schema3.Literal("variable"),
|
|
849
|
-
name: Schema3.String
|
|
850
|
-
});
|
|
851
|
-
var AuthenticationTemplateValueSchema2 = Schema3.Union([
|
|
852
|
-
Schema3.String,
|
|
853
|
-
Schema3.Array(Schema3.Union([Schema3.String, AuthenticationVariableSchema2]))
|
|
854
|
-
]);
|
|
855
836
|
var AuthenticationSchema2 = Schema3.Union([
|
|
856
837
|
Schema3.Struct({
|
|
857
838
|
slug: Schema3.String,
|
|
858
|
-
|
|
859
|
-
headers: Schema3.optional(Schema3.Record(Schema3.String, AuthenticationTemplateValueSchema2)),
|
|
860
|
-
queryParams: Schema3.optional(Schema3.Record(Schema3.String, AuthenticationTemplateValueSchema2))
|
|
861
|
-
}),
|
|
862
|
-
Schema3.Struct({
|
|
863
|
-
slug: Schema3.String,
|
|
864
|
-
type: Schema3.Literal("oauth"),
|
|
839
|
+
kind: Schema3.Literal("oauth2"),
|
|
865
840
|
authorizationUrl: Schema3.String,
|
|
866
841
|
tokenUrl: Schema3.String,
|
|
867
842
|
scopes: Schema3.Array(Schema3.String)
|
|
868
|
-
})
|
|
843
|
+
}),
|
|
844
|
+
// Credential methods are authored request-shaped — the ONE apikey input
|
|
845
|
+
// dialect: `{ type: "apiKey", headers: { Authorization: ["Bearer ",
|
|
846
|
+
// variable("token")] }, queryParams: { … } }`.
|
|
847
|
+
ApiKeyAuthTemplate
|
|
869
848
|
]);
|
|
870
849
|
var AddSourceInputSchema = Schema3.Struct({
|
|
871
850
|
spec: OpenApiSpecInputSchema,
|
|
@@ -998,7 +977,7 @@ var normalizeOpenApiRefs = (node) => {
|
|
|
998
977
|
};
|
|
999
978
|
var toBinding = (def) => OperationBinding.make({
|
|
1000
979
|
method: def.operation.method,
|
|
1001
|
-
|
|
980
|
+
servers: def.operation.servers,
|
|
1002
981
|
pathTemplate: def.operation.pathTemplate,
|
|
1003
982
|
parameters: [...def.operation.parameters],
|
|
1004
983
|
requestBody: def.operation.requestBody
|
|
@@ -1010,84 +989,19 @@ var descriptionFor = (def) => {
|
|
|
1010
989
|
() => Option5.getOrElse(op.summary, () => `${op.method.toUpperCase()} ${op.pathTemplate}`)
|
|
1011
990
|
);
|
|
1012
991
|
};
|
|
1013
|
-
var openApiTransportOutputSchema = (dataSchema) => ({
|
|
1014
|
-
type: "object",
|
|
1015
|
-
additionalProperties: false,
|
|
1016
|
-
required: ["status", "headers", "data"],
|
|
1017
|
-
properties: {
|
|
1018
|
-
status: { type: "integer" },
|
|
1019
|
-
headers: {
|
|
1020
|
-
type: "object",
|
|
1021
|
-
additionalProperties: { type: "string" }
|
|
1022
|
-
},
|
|
1023
|
-
data: dataSchema ?? {}
|
|
1024
|
-
}
|
|
1025
|
-
});
|
|
1026
992
|
var specInputToSourceUrl = (spec) => spec.kind === "url" || spec.kind === "googleDiscovery" ? spec.url : void 0;
|
|
1027
993
|
var specInputToGoogleBundle = (spec) => spec.kind === "googleDiscoveryBundle" ? spec.urls : void 0;
|
|
1028
|
-
var shortId = () => Math.random().toString(36).slice(2, 8);
|
|
1029
|
-
var freshCustomSlug = (taken) => {
|
|
1030
|
-
let candidate = `custom_${shortId()}`;
|
|
1031
|
-
while (taken.has(candidate)) candidate = `custom_${shortId()}`;
|
|
1032
|
-
return AuthTemplateSlug.make(candidate);
|
|
1033
|
-
};
|
|
1034
|
-
var mergeAuthenticationTemplate = (existing, incoming) => {
|
|
1035
|
-
const result = existing.map((entry) => entry);
|
|
1036
|
-
const taken = new Set(result.map((entry) => String(entry.slug)));
|
|
1037
|
-
for (const entry of incoming) {
|
|
1038
|
-
const rawSlug = entry.slug;
|
|
1039
|
-
const requested = typeof rawSlug === "string" ? rawSlug.trim() : "";
|
|
1040
|
-
const existingIndex = result.findIndex((current) => String(current.slug) === requested);
|
|
1041
|
-
if (requested.length > 0 && existingIndex >= 0) {
|
|
1042
|
-
result[existingIndex] = entry;
|
|
1043
|
-
continue;
|
|
1044
|
-
}
|
|
1045
|
-
const slug = requested.length > 0 && !taken.has(requested) ? AuthTemplateSlug.make(requested) : freshCustomSlug(taken);
|
|
1046
|
-
taken.add(String(slug));
|
|
1047
|
-
result.push({ ...entry, slug });
|
|
1048
|
-
}
|
|
1049
|
-
return result;
|
|
1050
|
-
};
|
|
1051
|
-
var parseTemplateValue = (value) => {
|
|
1052
|
-
if (typeof value === "string") return { prefix: "", variable: TOKEN_VARIABLE };
|
|
1053
|
-
const parts = [];
|
|
1054
|
-
for (const part of value) {
|
|
1055
|
-
if (typeof part !== "string" && part.type === "variable") {
|
|
1056
|
-
return { prefix: parts.join(""), variable: part.name };
|
|
1057
|
-
}
|
|
1058
|
-
if (typeof part === "string") parts.push(part);
|
|
1059
|
-
}
|
|
1060
|
-
return { prefix: parts.join(""), variable: TOKEN_VARIABLE };
|
|
1061
|
-
};
|
|
1062
|
-
var placementsFromAuthentication = (template) => {
|
|
1063
|
-
const placements = [];
|
|
1064
|
-
for (const [name, value] of Object.entries(template.headers ?? {})) {
|
|
1065
|
-
const { prefix, variable } = parseTemplateValue(value);
|
|
1066
|
-
placements.push({ carrier: "header", name, prefix, variable });
|
|
1067
|
-
}
|
|
1068
|
-
for (const [name, value] of Object.entries(template.queryParams ?? {})) {
|
|
1069
|
-
const { prefix, variable } = parseTemplateValue(value);
|
|
1070
|
-
placements.push({ carrier: "query", name, prefix, variable });
|
|
1071
|
-
}
|
|
1072
|
-
return placements;
|
|
1073
|
-
};
|
|
1074
|
-
var apiKeyLabel = (slug, placements) => {
|
|
1075
|
-
const first = placements[0];
|
|
1076
|
-
if (first) return `API key (${first.name || (first.carrier === "header" ? "header" : "query")})`;
|
|
1077
|
-
return `API key (${slug})`;
|
|
1078
|
-
};
|
|
1079
994
|
var describeOpenApiAuthMethods = (record) => {
|
|
1080
995
|
const config = decodeOpenApiIntegrationConfig(record.config);
|
|
1081
996
|
if (!config) return [];
|
|
1082
997
|
return (config.authenticationTemplate ?? []).map(
|
|
1083
998
|
(template) => {
|
|
1084
|
-
|
|
1085
|
-
if (template.type === "oauth") {
|
|
999
|
+
if (template.kind === "oauth2") {
|
|
1086
1000
|
return {
|
|
1087
|
-
id: slug,
|
|
1001
|
+
id: String(template.slug),
|
|
1088
1002
|
label: "OAuth2",
|
|
1089
1003
|
kind: "oauth",
|
|
1090
|
-
template: slug,
|
|
1004
|
+
template: String(template.slug),
|
|
1091
1005
|
oauth: {
|
|
1092
1006
|
authorizationUrl: template.authorizationUrl,
|
|
1093
1007
|
tokenUrl: template.tokenUrl,
|
|
@@ -1095,14 +1009,7 @@ var describeOpenApiAuthMethods = (record) => {
|
|
|
1095
1009
|
}
|
|
1096
1010
|
};
|
|
1097
1011
|
}
|
|
1098
|
-
|
|
1099
|
-
return {
|
|
1100
|
-
id: slug,
|
|
1101
|
-
label: apiKeyLabel(slug, placements),
|
|
1102
|
-
kind: "apikey",
|
|
1103
|
-
template: slug,
|
|
1104
|
-
placements
|
|
1105
|
-
};
|
|
1012
|
+
return describeApiKeyAuthMethod(template);
|
|
1106
1013
|
}
|
|
1107
1014
|
);
|
|
1108
1015
|
};
|
|
@@ -1110,6 +1017,7 @@ var describeOpenApiIntegrationDisplay = (record) => {
|
|
|
1110
1017
|
const config = decodeOpenApiIntegrationConfig(record.config);
|
|
1111
1018
|
return { url: config?.baseUrl ?? config?.sourceUrl };
|
|
1112
1019
|
};
|
|
1020
|
+
var loadSpecText = (storage, config) => config.specHash != null ? storage.getSpec(config.specHash) : Effect3.succeed(null);
|
|
1113
1021
|
var compileSpec = (specText) => Effect3.gen(function* () {
|
|
1114
1022
|
const doc = yield* parse(specText);
|
|
1115
1023
|
const result = yield* extract(doc);
|
|
@@ -1130,9 +1038,10 @@ var toolDefsFromCompiled = (compiled) => compiled.definitions.map(
|
|
|
1130
1038
|
name: ToolName.make(def.toolPath),
|
|
1131
1039
|
description: descriptionFor(def),
|
|
1132
1040
|
inputSchema: normalizeOpenApiRefs(Option5.getOrUndefined(def.operation.inputSchema)),
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
)
|
|
1041
|
+
// The output schema is the upstream response body only — transport
|
|
1042
|
+
// status/headers live in the ToolResult `http` side channel, not the
|
|
1043
|
+
// payload (see the invoke handler).
|
|
1044
|
+
outputSchema: normalizeOpenApiRefs(Option5.getOrUndefined(def.operation.outputSchema)),
|
|
1136
1045
|
annotations: annotationsForOperation(def.operation.method, def.operation.pathTemplate)
|
|
1137
1046
|
})
|
|
1138
1047
|
);
|
|
@@ -1198,23 +1107,38 @@ var openApiPlugin = definePlugin((options) => {
|
|
|
1198
1107
|
const addSpec = (config) => Effect3.gen(function* () {
|
|
1199
1108
|
const resolved = yield* resolveSpecForInput(config.spec, httpClientLayer);
|
|
1200
1109
|
const compiled = yield* compileSpec(resolved.specText);
|
|
1110
|
+
const explicitBaseUrl = config.baseUrl ?? resolved.baseUrl;
|
|
1111
|
+
const needsDerivedBaseUrl = explicitBaseUrl == null;
|
|
1112
|
+
const needsDerivedAuth = config.authenticationTemplate == null && resolved.authenticationTemplate == null;
|
|
1113
|
+
const preview = needsDerivedBaseUrl || needsDerivedAuth ? yield* previewSpecText(resolved.specText) : void 0;
|
|
1114
|
+
const derivedBaseUrl = needsDerivedBaseUrl && preview ? firstBaseUrlForPreview(preview) : void 0;
|
|
1115
|
+
const effectiveBaseUrl = explicitBaseUrl ?? (derivedBaseUrl || void 0);
|
|
1116
|
+
const derivedAuthenticationTemplate = needsDerivedAuth && preview ? deriveAuthenticationTemplateFromPreview(preview, effectiveBaseUrl) : void 0;
|
|
1201
1117
|
const slug = IntegrationSlug.make(config.slug);
|
|
1202
1118
|
const existing = yield* ctx.core.integrations.get(slug);
|
|
1203
1119
|
if (existing) {
|
|
1204
1120
|
return yield* new IntegrationAlreadyExistsError({ slug });
|
|
1205
1121
|
}
|
|
1122
|
+
const specHash = yield* sha256Hex(resolved.specText);
|
|
1206
1123
|
const integrationConfig = {
|
|
1207
|
-
|
|
1124
|
+
specHash,
|
|
1208
1125
|
...specInputToSourceUrl(config.spec) !== void 0 ? { sourceUrl: specInputToSourceUrl(config.spec) } : {},
|
|
1209
1126
|
...specInputToGoogleBundle(config.spec) !== void 0 ? { googleDiscoveryUrls: specInputToGoogleBundle(config.spec) } : {},
|
|
1210
|
-
|
|
1127
|
+
// baseUrl is an optional override only. The host is otherwise
|
|
1128
|
+
// resolved per call from the operation's `servers` (extracted from
|
|
1129
|
+
// the spec), so we never bake a derived base URL into the config.
|
|
1130
|
+
...config.baseUrl ? { baseUrl: config.baseUrl } : {},
|
|
1211
1131
|
...config.headers ? { headers: config.headers } : {},
|
|
1212
1132
|
...config.queryParams ? { queryParams: config.queryParams } : {},
|
|
1213
1133
|
// Prefer the caller's explicit template; otherwise adopt the one the
|
|
1214
1134
|
// Google Discovery converter derived from the spec (the bundle add
|
|
1215
|
-
// path relies on this — it has no preview to detect auth from)
|
|
1216
|
-
|
|
1135
|
+
// path relies on this — it has no preview to detect auth from);
|
|
1136
|
+
// otherwise derive from the spec's declared security schemes.
|
|
1137
|
+
...config.authenticationTemplate ? {
|
|
1138
|
+
authenticationTemplate: normalizeOpenApiAuthInputs(config.authenticationTemplate)
|
|
1139
|
+
} : resolved.authenticationTemplate ? { authenticationTemplate: resolved.authenticationTemplate } : derivedAuthenticationTemplate && derivedAuthenticationTemplate.length > 0 ? { authenticationTemplate: derivedAuthenticationTemplate } : {}
|
|
1217
1140
|
};
|
|
1141
|
+
yield* ctx.storage.putSpec(specHash, resolved.specText);
|
|
1218
1142
|
yield* ctx.transaction(
|
|
1219
1143
|
Effect3.gen(function* () {
|
|
1220
1144
|
yield* ctx.core.integrations.register({
|
|
@@ -1276,10 +1200,8 @@ var openApiPlugin = definePlugin((options) => {
|
|
|
1276
1200
|
if (!record) return [];
|
|
1277
1201
|
const current = decodeOpenApiIntegrationConfig(record.config);
|
|
1278
1202
|
if (!current) return [];
|
|
1279
|
-
const
|
|
1280
|
-
|
|
1281
|
-
input.authenticationTemplate
|
|
1282
|
-
);
|
|
1203
|
+
const incoming = normalizeOpenApiAuthInputs(input.authenticationTemplate);
|
|
1204
|
+
const merged = input.mode === "replace" ? incoming : mergeAuthTemplates(current.authenticationTemplate ?? [], incoming);
|
|
1283
1205
|
const next = {
|
|
1284
1206
|
...current,
|
|
1285
1207
|
authenticationTemplate: merged
|
|
@@ -1314,7 +1236,7 @@ var openApiPlugin = definePlugin((options) => {
|
|
|
1314
1236
|
}),
|
|
1315
1237
|
tool({
|
|
1316
1238
|
name: "addSpec",
|
|
1317
|
-
description: "Add an OpenAPI integration to the catalog and persist its operations as tools. Recommended flow: call `previewSpec`, choose a `slug`,
|
|
1239
|
+
description: "Add an OpenAPI integration to the catalog and persist its operations as tools. Recommended flow: call `previewSpec`, choose a `slug`, then create a connection for that integration with the user's API key or via `oauth.start`. When `baseUrl` is omitted it defaults to the spec's first server; when `authenticationTemplate` is omitted the auth methods are derived from the spec's declared security schemes (pass an explicit template to override how a credential is applied \u2014 apiKey header/query, or oauth bearer \u2014 or an empty array for no auth methods).",
|
|
1318
1240
|
annotations: {
|
|
1319
1241
|
requiresApproval: true,
|
|
1320
1242
|
approvalDescription: "Add an OpenAPI integration"
|
|
@@ -1357,13 +1279,17 @@ var openApiPlugin = definePlugin((options) => {
|
|
|
1357
1279
|
// Produce one tool per spec operation. Spec-derived, identical for every
|
|
1358
1280
|
// connection on the integration — so `getValue` is never called here. The
|
|
1359
1281
|
// operation bindings invokeTool needs are persisted at addSpec time; this
|
|
1360
|
-
// hook only shapes the per-connection ToolDefs from the
|
|
1282
|
+
// hook only shapes the per-connection ToolDefs from the spec blob the
|
|
1283
|
+
// catalog config points at.
|
|
1361
1284
|
resolveTools: ({
|
|
1362
|
-
config
|
|
1285
|
+
config,
|
|
1286
|
+
storage
|
|
1363
1287
|
}) => Effect3.gen(function* () {
|
|
1364
1288
|
const openApiConfig = decodeOpenApiIntegrationConfig(config);
|
|
1365
1289
|
if (!openApiConfig) return { tools: [], definitions: {} };
|
|
1366
|
-
const
|
|
1290
|
+
const specText = yield* loadSpecText(storage, openApiConfig);
|
|
1291
|
+
if (specText == null) return { tools: [], definitions: {} };
|
|
1292
|
+
const compiled = yield* compileSpec(specText).pipe(
|
|
1367
1293
|
Effect3.catch(() => Effect3.succeed(null))
|
|
1368
1294
|
);
|
|
1369
1295
|
if (!compiled) return { tools: [], definitions: {} };
|
|
@@ -1383,9 +1309,10 @@ var openApiPlugin = definePlugin((options) => {
|
|
|
1383
1309
|
const config = decodeOpenApiIntegrationConfig(credential.config);
|
|
1384
1310
|
let binding = (yield* invokeCtx.storage.getOperation(integration, toolRow.name))?.binding;
|
|
1385
1311
|
if (!binding && config) {
|
|
1386
|
-
const
|
|
1312
|
+
const specText = yield* loadSpecText(invokeCtx.storage, config).pipe(
|
|
1387
1313
|
Effect3.catch(() => Effect3.succeed(null))
|
|
1388
1314
|
);
|
|
1315
|
+
const compiled = specText == null ? null : yield* compileSpec(specText).pipe(Effect3.catch(() => Effect3.succeed(null)));
|
|
1389
1316
|
binding = compiled ? storedOperationsFromCompiled(integration, compiled).find(
|
|
1390
1317
|
(op) => op.toolName === toolRow.name
|
|
1391
1318
|
)?.binding : void 0;
|
|
@@ -1409,12 +1336,12 @@ var openApiPlugin = definePlugin((options) => {
|
|
|
1409
1336
|
});
|
|
1410
1337
|
if (missing.length > 0) {
|
|
1411
1338
|
return openApiAuthToolFailure({
|
|
1412
|
-
code: template.
|
|
1339
|
+
code: template.kind === "oauth2" ? "oauth_connection_missing" : "connection_value_missing",
|
|
1413
1340
|
message: `Connection "${credential.connection}" for "${integration}" has no resolvable credential value. Re-authenticate or update the connection.`,
|
|
1414
1341
|
owner: credential.owner,
|
|
1415
1342
|
integration,
|
|
1416
1343
|
connection: String(credential.connection),
|
|
1417
|
-
credentialKind: template.
|
|
1344
|
+
credentialKind: template.kind === "oauth2" ? "oauth" : "secret"
|
|
1418
1345
|
});
|
|
1419
1346
|
}
|
|
1420
1347
|
const rendered = renderAuthTemplate(template, credential.values);
|
|
@@ -1451,10 +1378,8 @@ var openApiPlugin = definePlugin((options) => {
|
|
|
1451
1378
|
details: result.error
|
|
1452
1379
|
});
|
|
1453
1380
|
}
|
|
1454
|
-
return ToolResult.ok({
|
|
1455
|
-
status: result.status,
|
|
1456
|
-
headers: result.headers,
|
|
1457
|
-
data: result.data
|
|
1381
|
+
return ToolResult.ok(result.data, {
|
|
1382
|
+
http: { status: result.status, headers: result.headers }
|
|
1458
1383
|
});
|
|
1459
1384
|
}),
|
|
1460
1385
|
resolveAnnotations: ({
|
|
@@ -1541,4 +1466,4 @@ export {
|
|
|
1541
1466
|
makeDefaultOpenapiStore,
|
|
1542
1467
|
openApiPlugin
|
|
1543
1468
|
};
|
|
1544
|
-
//# sourceMappingURL=chunk-
|
|
1469
|
+
//# sourceMappingURL=chunk-WJQIWTZF.js.map
|