@rafads/plugin-openapi 1.5.38

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.
Files changed (122) hide show
  1. package/README.md +83 -0
  2. package/dist/AddOpenApiIntegration-JPAEXE56.js +512 -0
  3. package/dist/AddOpenApiIntegration-JPAEXE56.js.map +1 -0
  4. package/dist/OpenApiAccountsPanel-GZFDSTAU.js +106 -0
  5. package/dist/OpenApiAccountsPanel-GZFDSTAU.js.map +1 -0
  6. package/dist/UpdateSpecSection-KUSNI44Q.js +106 -0
  7. package/dist/UpdateSpecSection-KUSNI44Q.js.map +1 -0
  8. package/dist/api/group.d.ts +239 -0
  9. package/dist/api/handlers.d.ts +7 -0
  10. package/dist/api/index.d.ts +237 -0
  11. package/dist/chunk-6V45G2XQ.js +199 -0
  12. package/dist/chunk-6V45G2XQ.js.map +1 -0
  13. package/dist/chunk-CURJJXB3.js +132 -0
  14. package/dist/chunk-CURJJXB3.js.map +1 -0
  15. package/dist/chunk-CXFO6TLJ.js +39 -0
  16. package/dist/chunk-CXFO6TLJ.js.map +1 -0
  17. package/dist/chunk-HTHEUUJA.js +2873 -0
  18. package/dist/chunk-HTHEUUJA.js.map +1 -0
  19. package/dist/chunk-IG6QTTZB.js +79 -0
  20. package/dist/chunk-IG6QTTZB.js.map +1 -0
  21. package/dist/chunk-O2LMSZ2Z.js +120 -0
  22. package/dist/chunk-O2LMSZ2Z.js.map +1 -0
  23. package/dist/chunk-OR27BCXQ.js +956 -0
  24. package/dist/chunk-OR27BCXQ.js.map +1 -0
  25. package/dist/chunk-R7TVM3XD.js +275 -0
  26. package/dist/chunk-R7TVM3XD.js.map +1 -0
  27. package/dist/client.js +38 -0
  28. package/dist/client.js.map +1 -0
  29. package/dist/core.js +331 -0
  30. package/dist/core.js.map +1 -0
  31. package/dist/index.js +19 -0
  32. package/dist/index.js.map +1 -0
  33. package/dist/providers/google/config.d.ts +34 -0
  34. package/dist/providers/google/discovery.d.ts +49 -0
  35. package/dist/providers/google/discovery.test.d.ts +1 -0
  36. package/dist/providers/google/index.d.ts +5 -0
  37. package/dist/providers/google/oauth-scopes.d.ts +3 -0
  38. package/dist/providers/google/oauth-scopes.test.d.ts +1 -0
  39. package/dist/providers/google/openapi-ownership-migration.d.ts +7 -0
  40. package/dist/providers/google/openapi-ownership-migration.test.d.ts +1 -0
  41. package/dist/providers/google/presets.d.ts +31 -0
  42. package/dist/providers/google/presets.test.d.ts +1 -0
  43. package/dist/providers/google/spec-format-adapter.d.ts +3 -0
  44. package/dist/providers/google/spec-format-adapter.test.d.ts +1 -0
  45. package/dist/providers/google.js +1446 -0
  46. package/dist/providers/google.js.map +1 -0
  47. package/dist/providers/microsoft/graph.d.ts +76 -0
  48. package/dist/providers/microsoft/graph.test.d.ts +1 -0
  49. package/dist/providers/microsoft/index.d.ts +3 -0
  50. package/dist/providers/microsoft/presets.d.ts +46 -0
  51. package/dist/providers/microsoft/presets.test.d.ts +1 -0
  52. package/dist/providers/microsoft/spec-format-adapter.d.ts +2 -0
  53. package/dist/providers/microsoft/spec-format-adapter.test.d.ts +1 -0
  54. package/dist/providers/microsoft.js +1056 -0
  55. package/dist/providers/microsoft.js.map +1 -0
  56. package/dist/react/AddOpenApiIntegration.d.ts +22 -0
  57. package/dist/react/AddOpenApiIntegration.test.d.ts +1 -0
  58. package/dist/react/OpenApiAccountsPanel.d.ts +6 -0
  59. package/dist/react/OpenApiIntegrationDetailsFields.d.ts +25 -0
  60. package/dist/react/UpdateSpecSection.d.ts +2 -0
  61. package/dist/react/atoms.d.ts +317 -0
  62. package/dist/react/auth-method-config.d.ts +18 -0
  63. package/dist/react/auth-method-config.test.d.ts +1 -0
  64. package/dist/react/client.d.ts +233 -0
  65. package/dist/react/index.d.ts +5 -0
  66. package/dist/react/integration-plugin.d.ts +6 -0
  67. package/dist/react/plugin-client.d.ts +2 -0
  68. package/dist/sdk/backing.d.ts +188 -0
  69. package/dist/sdk/client-credentials-oauth.test.d.ts +1 -0
  70. package/dist/sdk/compiled-spec-cache.test.d.ts +1 -0
  71. package/dist/sdk/config.d.ts +81 -0
  72. package/dist/sdk/configure.test.d.ts +1 -0
  73. package/dist/sdk/definitions.d.ts +57 -0
  74. package/dist/sdk/derive-auth.d.ts +11 -0
  75. package/dist/sdk/describe-auth-methods.test.d.ts +1 -0
  76. package/dist/sdk/errors.d.ts +45 -0
  77. package/dist/sdk/extract.d.ts +157 -0
  78. package/dist/sdk/extract.test.d.ts +1 -0
  79. package/dist/sdk/form-urlencoded-body.test.d.ts +1 -0
  80. package/dist/sdk/index.d.ts +19 -0
  81. package/dist/sdk/index.test.d.ts +1 -0
  82. package/dist/sdk/invoke.d.ts +150 -0
  83. package/dist/sdk/migrate-config.d.ts +4 -0
  84. package/dist/sdk/migrate-config.test.d.ts +1 -0
  85. package/dist/sdk/multi-scope-bearer.test.d.ts +1 -0
  86. package/dist/sdk/multi-scope-oauth.test.d.ts +1 -0
  87. package/dist/sdk/ndjson-output-migration.d.ts +13 -0
  88. package/dist/sdk/ndjson-output-migration.test.d.ts +1 -0
  89. package/dist/sdk/non-json-body.test.d.ts +1 -0
  90. package/dist/sdk/oauth-refresh.test.d.ts +1 -0
  91. package/dist/sdk/openapi-utils.d.ts +65 -0
  92. package/dist/sdk/output-schema-migration.d.ts +21 -0
  93. package/dist/sdk/output-schema-migration.test.d.ts +1 -0
  94. package/dist/sdk/parse.d.ts +33 -0
  95. package/dist/sdk/parse.test.d.ts +1 -0
  96. package/dist/sdk/plugin.d.ts +109 -0
  97. package/dist/sdk/plugin.test.d.ts +1 -0
  98. package/dist/sdk/presets.d.ts +15 -0
  99. package/dist/sdk/preview-oauth2.test.d.ts +1 -0
  100. package/dist/sdk/preview.d.ts +514 -0
  101. package/dist/sdk/query-serialization.test.d.ts +1 -0
  102. package/dist/sdk/real-specs.test.d.ts +1 -0
  103. package/dist/sdk/request-user-agent.test.d.ts +1 -0
  104. package/dist/sdk/response-headers-timeout.test.d.ts +1 -0
  105. package/dist/sdk/server-url-resolution.test.d.ts +1 -0
  106. package/dist/sdk/spec-blob-migration.d.ts +7 -0
  107. package/dist/sdk/spec-blob.test.d.ts +1 -0
  108. package/dist/sdk/spec-format.d.ts +36 -0
  109. package/dist/sdk/spec-format.test.d.ts +1 -0
  110. package/dist/sdk/split.d.ts +84 -0
  111. package/dist/sdk/store.d.ts +49 -0
  112. package/dist/sdk/store.test.d.ts +1 -0
  113. package/dist/sdk/streaming-response.test.d.ts +1 -0
  114. package/dist/sdk/tool-row-projection.test.d.ts +1 -0
  115. package/dist/sdk/types.d.ts +352 -0
  116. package/dist/sdk/upstream-failures.test.d.ts +1 -0
  117. package/dist/sdk/usage-scope-isolation.test.d.ts +1 -0
  118. package/dist/testing/index.d.ts +177 -0
  119. package/dist/testing.js +454 -0
  120. package/dist/testing.js.map +1 -0
  121. package/dist/testing.test.d.ts +1 -0
  122. package/package.json +103 -0
@@ -0,0 +1,956 @@
1
+ import {
2
+ openApiPresets
3
+ } from "./chunk-CURJJXB3.js";
4
+ import {
5
+ deriveAuthenticationTemplateFromPreview,
6
+ firstBaseUrlForPreview
7
+ } from "./chunk-O2LMSZ2Z.js";
8
+ import {
9
+ OAuth2AuthorizationCodeFlow,
10
+ OAuth2Flows,
11
+ OAuth2Preset,
12
+ OperationBinding,
13
+ SecurityScheme,
14
+ checkHealthOpenApi,
15
+ compileAndPersistOpenApiSpecStreaming,
16
+ compileOpenApiSpec,
17
+ extract,
18
+ invokeOpenApiBackedTool,
19
+ listHealthCheckCandidatesOpenApi,
20
+ normalizeOpenApiAuthInputs,
21
+ openApiStoredOperationsFromCompiled,
22
+ parse,
23
+ previewSpecText,
24
+ resolveOpenApiBackedAnnotations,
25
+ resolveOpenApiBackedTools,
26
+ resolveServerUrl,
27
+ resolveSpecText,
28
+ validateOpenApiBackedToolArgs
29
+ } from "./chunk-HTHEUUJA.js";
30
+ import {
31
+ decodeOpenApiIntegrationConfig
32
+ } from "./chunk-R7TVM3XD.js";
33
+ import {
34
+ OpenApiParseError
35
+ } from "./chunk-CXFO6TLJ.js";
36
+
37
+ // src/sdk/store.ts
38
+ import { Effect, Option, Predicate, Schema } from "effect";
39
+ var OPERATION_COLLECTION = "operation";
40
+ var STORE_OWNER = "org";
41
+ var OPERATION_KEY_VERSION = "op";
42
+ var encodeBinding = Schema.encodeSync(OperationBinding);
43
+ var decodeBinding = Schema.decodeUnknownSync(OperationBinding);
44
+ var decodeBindingJson = Schema.decodeUnknownSync(Schema.fromJsonString(OperationBinding));
45
+ var toJsonRecord = (value) => value;
46
+ var OperationStorage = Schema.Struct({
47
+ integration: Schema.String,
48
+ toolName: Schema.String,
49
+ binding: Schema.Unknown,
50
+ // Resolved tool description (operation description / summary / method+path
51
+ // fallback), persisted so the serve path can rebuild the tool def without
52
+ // re-parsing the spec. Optional: legacy rows predate it and resolve via the
53
+ // parse fallback.
54
+ description: Schema.optional(Schema.String)
55
+ });
56
+ var decodeOperationStorage = Schema.decodeUnknownOption(OperationStorage);
57
+ var rowToOperation = (row) => {
58
+ const decoded = decodeOperationStorage(row.data);
59
+ if (Option.isNone(decoded)) return null;
60
+ const operation = decoded.value;
61
+ return {
62
+ integration: operation.integration,
63
+ toolName: operation.toolName,
64
+ binding: decodeBinding(
65
+ typeof operation.binding === "string" ? decodeBindingJson(operation.binding) : operation.binding
66
+ ),
67
+ ...operation.description !== void 0 ? { description: operation.description } : {}
68
+ };
69
+ };
70
+ var stableKeyHash = (value) => {
71
+ let hash = 0xcbf29ce484222325n;
72
+ const prime = 0x100000001b3n;
73
+ const mask = 0xffffffffffffffffn;
74
+ for (let index = 0; index < value.length; index += 1) {
75
+ hash ^= BigInt(value.charCodeAt(index));
76
+ hash = hash * prime & mask;
77
+ }
78
+ return hash.toString(36).padStart(13, "0");
79
+ };
80
+ var operationKey = (integration, toolName) => `${OPERATION_KEY_VERSION}.${stableKeyHash(integration)}.${stableKeyHash(toolName)}`;
81
+ var legacyOperationKey = (integration, toolName) => `${integration}.${toolName}`;
82
+ var specBlobKey = (specHash) => `spec/${specHash}`;
83
+ var defsBlobKey = (specHash) => `defs/${specHash}`;
84
+ var makeDefaultOpenapiStore = ({ pluginStorage, blobs }) => {
85
+ const operationData = (operation) => ({
86
+ integration: operation.integration,
87
+ toolName: operation.toolName,
88
+ binding: toJsonRecord(encodeBinding(operation.binding)),
89
+ ...operation.description !== void 0 ? { description: operation.description } : {}
90
+ });
91
+ const listRows = (integration) => pluginStorage.list({ collection: OPERATION_COLLECTION }).pipe(
92
+ Effect.map(
93
+ (rows) => rows.filter((row) => rowToOperation(row)?.integration === integration)
94
+ )
95
+ );
96
+ const removeOperations = (integration) => Effect.gen(function* () {
97
+ const rows = yield* listRows(integration);
98
+ yield* pluginStorage.removeMany({
99
+ owner: STORE_OWNER,
100
+ entries: rows.map((row) => ({ collection: OPERATION_COLLECTION, key: row.key }))
101
+ });
102
+ });
103
+ const appendOperations = (integration, operations) => pluginStorage.putMany({
104
+ owner: STORE_OWNER,
105
+ entries: operations.map((operation) => ({
106
+ collection: OPERATION_COLLECTION,
107
+ key: operationKey(integration, operation.toolName),
108
+ data: operationData(operation)
109
+ }))
110
+ });
111
+ return {
112
+ putOperations: (integration, operations) => Effect.gen(function* () {
113
+ yield* removeOperations(integration);
114
+ yield* appendOperations(integration, operations);
115
+ }),
116
+ appendOperations,
117
+ getOperation: (integration, toolName) => Effect.gen(function* () {
118
+ const row = yield* pluginStorage.get({
119
+ collection: OPERATION_COLLECTION,
120
+ key: operationKey(integration, toolName)
121
+ });
122
+ if (row) return rowToOperation(row);
123
+ const legacyKey = legacyOperationKey(integration, toolName);
124
+ if (legacyKey.length > 255) return null;
125
+ const legacyRow = yield* pluginStorage.get({
126
+ collection: OPERATION_COLLECTION,
127
+ key: legacyKey
128
+ });
129
+ return legacyRow ? rowToOperation(legacyRow) : null;
130
+ }),
131
+ listOperations: (integration) => listRows(integration).pipe(
132
+ Effect.map((rows) => rows.map(rowToOperation).filter(Predicate.isNotNull))
133
+ ),
134
+ removeOperations,
135
+ putSpec: (specHash, specText) => blobs.put(specBlobKey(specHash), specText, { owner: STORE_OWNER }),
136
+ getSpec: (specHash) => blobs.get(specBlobKey(specHash)),
137
+ putDefs: (specHash, defsJson) => blobs.put(defsBlobKey(specHash), defsJson, { owner: STORE_OWNER }),
138
+ getDefs: (specHash) => blobs.get(defsBlobKey(specHash))
139
+ };
140
+ };
141
+
142
+ // src/sdk/spec-format.ts
143
+ import { Effect as Effect2 } from "effect";
144
+ var resolveSpecFormatAdapter = (adapters, id) => {
145
+ if (!id) return Effect2.succeed(null);
146
+ const adapter = adapters.find((candidate) => candidate.id === id);
147
+ if (adapter) return Effect2.succeed(adapter);
148
+ return Effect2.fail(new OpenApiParseError({ message: `Unknown OpenAPI spec format: ${id}` }));
149
+ };
150
+
151
+ // src/sdk/plugin.ts
152
+ import { Effect as Effect3, Option as Option2, Schema as Schema2 } from "effect";
153
+ import {
154
+ IntegrationAlreadyExistsError,
155
+ IntegrationDetectionResult,
156
+ IntegrationNotFoundError,
157
+ IntegrationSlug,
158
+ ToolResult,
159
+ definePlugin,
160
+ HealthCheckSpec,
161
+ mergeAuthTemplates,
162
+ sha256Hex,
163
+ tool
164
+ } from "@rafads/sdk/core";
165
+ import { ApiKeyAuthTemplate, describeApiKeyAuthMethod } from "@rafads/sdk/http-auth";
166
+ var PreviewSpecInputSchema = Schema2.Struct({
167
+ spec: Schema2.String,
168
+ specFormat: Schema2.optional(Schema2.String)
169
+ });
170
+ var StaticPreviewServerVariableSchema = Schema2.Struct({
171
+ default: Schema2.String,
172
+ enum: Schema2.NullOr(Schema2.Array(Schema2.String)),
173
+ description: Schema2.NullOr(Schema2.String)
174
+ });
175
+ var StaticPreviewServerSchema = Schema2.Struct({
176
+ url: Schema2.String,
177
+ description: Schema2.NullOr(Schema2.String),
178
+ variables: Schema2.NullOr(Schema2.Record(Schema2.String, StaticPreviewServerVariableSchema))
179
+ });
180
+ var StaticPreviewOAuthAuthorizationCodeFlowSchema = Schema2.Struct({
181
+ authorizationUrl: Schema2.String,
182
+ tokenUrl: Schema2.String,
183
+ refreshUrl: Schema2.NullOr(Schema2.String),
184
+ scopes: Schema2.Record(Schema2.String, Schema2.String)
185
+ });
186
+ var StaticPreviewOAuthClientCredentialsFlowSchema = Schema2.Struct({
187
+ tokenUrl: Schema2.String,
188
+ refreshUrl: Schema2.NullOr(Schema2.String),
189
+ scopes: Schema2.Record(Schema2.String, Schema2.String)
190
+ });
191
+ var StaticPreviewOAuthFlowsSchema = Schema2.Struct({
192
+ authorizationCode: Schema2.NullOr(StaticPreviewOAuthAuthorizationCodeFlowSchema),
193
+ clientCredentials: Schema2.NullOr(StaticPreviewOAuthClientCredentialsFlowSchema)
194
+ });
195
+ var StaticPreviewSecuritySchemeSchema = Schema2.Struct({
196
+ name: Schema2.String,
197
+ type: Schema2.Literals(["http", "apiKey", "oauth2", "openIdConnect"]),
198
+ scheme: Schema2.NullOr(Schema2.String),
199
+ bearerFormat: Schema2.NullOr(Schema2.String),
200
+ in: Schema2.NullOr(Schema2.Literals(["header", "query", "cookie"])),
201
+ headerName: Schema2.NullOr(Schema2.String),
202
+ description: Schema2.NullOr(Schema2.String),
203
+ flows: Schema2.NullOr(StaticPreviewOAuthFlowsSchema),
204
+ openIdConnectUrl: Schema2.NullOr(Schema2.String)
205
+ });
206
+ var StaticPreviewOAuth2PresetSchema = Schema2.Struct({
207
+ label: Schema2.String,
208
+ securitySchemeName: Schema2.String,
209
+ flow: Schema2.Literals(["authorizationCode", "clientCredentials"]),
210
+ authorizationUrl: Schema2.NullOr(Schema2.String),
211
+ tokenUrl: Schema2.String,
212
+ resource: Schema2.NullOr(Schema2.String),
213
+ refreshUrl: Schema2.NullOr(Schema2.String),
214
+ scopes: Schema2.Record(Schema2.String, Schema2.String),
215
+ identityScopes: Schema2.Union([
216
+ Schema2.Literal("auto"),
217
+ Schema2.Literal(false),
218
+ Schema2.Array(Schema2.String)
219
+ ]),
220
+ supportsClientIdMetadataDocument: Schema2.optional(Schema2.Boolean)
221
+ });
222
+ var StaticPreviewSpecOutputSchema = Schema2.Struct({
223
+ title: Schema2.NullOr(Schema2.String),
224
+ version: Schema2.NullOr(Schema2.String),
225
+ servers: Schema2.Array(StaticPreviewServerSchema),
226
+ operationCount: Schema2.Number,
227
+ tags: Schema2.Array(Schema2.String),
228
+ securitySchemes: Schema2.Array(StaticPreviewSecuritySchemeSchema),
229
+ authStrategies: Schema2.Array(Schema2.Struct({ schemes: Schema2.Array(Schema2.String) })),
230
+ headerPresets: Schema2.Array(
231
+ Schema2.Struct({
232
+ label: Schema2.String,
233
+ headers: Schema2.Record(Schema2.String, Schema2.NullOr(Schema2.String)),
234
+ secretHeaders: Schema2.Array(Schema2.String)
235
+ })
236
+ ),
237
+ oauth2Presets: Schema2.Array(StaticPreviewOAuth2PresetSchema)
238
+ });
239
+ var OpenApiSpecInputSchema = Schema2.Union([
240
+ Schema2.Struct({ kind: Schema2.Literal("url"), url: Schema2.String }),
241
+ Schema2.Struct({ kind: Schema2.Literal("blob"), value: Schema2.String })
242
+ ]);
243
+ var AuthenticationSchema = Schema2.Union([
244
+ Schema2.Struct({
245
+ slug: Schema2.String,
246
+ kind: Schema2.Literal("oauth2"),
247
+ authorizationUrl: Schema2.String,
248
+ tokenUrl: Schema2.String,
249
+ resource: Schema2.optional(Schema2.NullOr(Schema2.String)),
250
+ scopes: Schema2.Array(Schema2.String),
251
+ supportsClientIdMetadataDocument: Schema2.optional(Schema2.Boolean)
252
+ }),
253
+ // Credential methods are authored request-shaped - the ONE apikey input
254
+ // dialect: `{ type: "apiKey", headers: { Authorization: ["Bearer ",
255
+ // variable("token")] }, queryParams: { … } }`.
256
+ ApiKeyAuthTemplate
257
+ ]);
258
+ var AddIntegrationInputSchema = Schema2.Struct({
259
+ spec: OpenApiSpecInputSchema,
260
+ slug: Schema2.optional(Schema2.String),
261
+ name: Schema2.optional(Schema2.String),
262
+ description: Schema2.optional(Schema2.String),
263
+ baseUrl: Schema2.optional(Schema2.String),
264
+ headers: Schema2.optional(Schema2.Record(Schema2.String, Schema2.String)),
265
+ queryParams: Schema2.optional(Schema2.Record(Schema2.String, Schema2.String)),
266
+ specFormat: Schema2.optional(Schema2.String),
267
+ family: Schema2.optional(Schema2.String),
268
+ healthCheck: Schema2.optional(HealthCheckSpec),
269
+ authenticationTemplate: Schema2.optional(Schema2.Array(AuthenticationSchema))
270
+ });
271
+ var AddIntegrationOutputSchema = Schema2.Struct({
272
+ slug: Schema2.String,
273
+ toolCount: Schema2.Number
274
+ });
275
+ var PreviewSpecInputStandardSchema = Schema2.toStandardSchemaV1(
276
+ Schema2.toStandardJSONSchemaV1(PreviewSpecInputSchema)
277
+ );
278
+ var PreviewSpecOutputStandardSchema = Schema2.toStandardSchemaV1(
279
+ Schema2.toStandardJSONSchemaV1(StaticPreviewSpecOutputSchema)
280
+ );
281
+ var AddIntegrationInputStandardSchema = Schema2.toStandardSchemaV1(
282
+ Schema2.toStandardJSONSchemaV1(AddIntegrationInputSchema)
283
+ );
284
+ var AddIntegrationOutputStandardSchema = Schema2.toStandardSchemaV1(
285
+ Schema2.toStandardJSONSchemaV1(AddIntegrationOutputSchema)
286
+ );
287
+ var openApiToolFailure = (code, message, details) => ToolResult.fail({
288
+ code,
289
+ message,
290
+ ...details === void 0 ? {} : { details }
291
+ });
292
+ var staticPreviewOutput = (preview) => ({
293
+ title: Option2.getOrNull(preview.title),
294
+ version: Option2.getOrNull(preview.version),
295
+ servers: preview.servers.map((server) => ({
296
+ url: server.url,
297
+ description: Option2.getOrNull(server.description),
298
+ variables: Option2.getOrNull(server.variables) ? Object.fromEntries(
299
+ Object.entries(Option2.getOrNull(server.variables) ?? {}).map(([name, variable]) => [
300
+ name,
301
+ {
302
+ default: variable.default,
303
+ enum: Option2.getOrNull(variable.enum),
304
+ description: Option2.getOrNull(variable.description)
305
+ }
306
+ ])
307
+ ) : null
308
+ })),
309
+ operationCount: preview.operationCount,
310
+ tags: preview.tags,
311
+ securitySchemes: preview.securitySchemes.map((scheme) => ({
312
+ name: scheme.name,
313
+ type: scheme.type,
314
+ scheme: Option2.getOrNull(scheme.scheme),
315
+ bearerFormat: Option2.getOrNull(scheme.bearerFormat),
316
+ in: Option2.getOrNull(scheme.in),
317
+ headerName: Option2.getOrNull(scheme.headerName),
318
+ description: Option2.getOrNull(scheme.description),
319
+ flows: Option2.isSome(scheme.flows) ? {
320
+ authorizationCode: Option2.isSome(scheme.flows.value.authorizationCode) ? {
321
+ authorizationUrl: scheme.flows.value.authorizationCode.value.authorizationUrl,
322
+ tokenUrl: scheme.flows.value.authorizationCode.value.tokenUrl,
323
+ refreshUrl: Option2.getOrNull(scheme.flows.value.authorizationCode.value.refreshUrl),
324
+ scopes: scheme.flows.value.authorizationCode.value.scopes
325
+ } : null,
326
+ clientCredentials: Option2.isSome(scheme.flows.value.clientCredentials) ? {
327
+ tokenUrl: scheme.flows.value.clientCredentials.value.tokenUrl,
328
+ refreshUrl: Option2.getOrNull(scheme.flows.value.clientCredentials.value.refreshUrl),
329
+ scopes: scheme.flows.value.clientCredentials.value.scopes
330
+ } : null
331
+ } : null,
332
+ openIdConnectUrl: Option2.getOrNull(scheme.openIdConnectUrl)
333
+ })),
334
+ authStrategies: preview.authStrategies,
335
+ headerPresets: preview.headerPresets,
336
+ oauth2Presets: preview.oauth2Presets.map((preset) => ({
337
+ label: preset.label,
338
+ securitySchemeName: preset.securitySchemeName,
339
+ flow: preset.flow,
340
+ authorizationUrl: Option2.getOrNull(preset.authorizationUrl),
341
+ tokenUrl: preset.tokenUrl,
342
+ resource: Option2.getOrNull(preset.resource),
343
+ refreshUrl: Option2.getOrNull(preset.refreshUrl),
344
+ scopes: preset.scopes,
345
+ identityScopes: preset.identityScopes,
346
+ supportsClientIdMetadataDocument: preset.supportsClientIdMetadataDocument
347
+ }))
348
+ });
349
+ var specInputToSpecUrl = (spec) => spec.kind === "url" ? spec.url : void 0;
350
+ var OAUTH_DISCOVERED_SCHEME_NAME = "DiscoveredOAuth2";
351
+ var OPENAPI_HTTP_METHODS = /* @__PURE__ */ new Set([
352
+ "get",
353
+ "put",
354
+ "post",
355
+ "delete",
356
+ "patch",
357
+ "head",
358
+ "options",
359
+ "trace"
360
+ ]);
361
+ var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
362
+ var maybeUrl = (value) => {
363
+ try {
364
+ return new URL(value);
365
+ } catch {
366
+ return null;
367
+ }
368
+ };
369
+ var addProbeCandidate = (candidates, value) => {
370
+ const trimmed = value?.trim();
371
+ if (!trimmed) return;
372
+ const parsed = maybeUrl(trimmed);
373
+ if (!parsed || parsed.protocol !== "https:" && parsed.protocol !== "http:") return;
374
+ const normalized = parsed.toString();
375
+ const origin = parsed.origin;
376
+ if (!candidates.includes(normalized)) candidates.push(normalized);
377
+ if (!candidates.includes(origin)) candidates.push(origin);
378
+ };
379
+ var oauthProbeCandidates = (preview, specUrl, baseUrl) => {
380
+ const candidates = [];
381
+ addProbeCandidate(candidates, baseUrl);
382
+ for (const server of preview.servers) {
383
+ addProbeCandidate(
384
+ candidates,
385
+ resolveServerUrl(server.url, Option2.getOrUndefined(server.variables), {})
386
+ );
387
+ }
388
+ addProbeCandidate(candidates, specUrl);
389
+ return candidates;
390
+ };
391
+ var securityRequirementScopes = (security, targetSchemes) => {
392
+ if (!Array.isArray(security)) return [];
393
+ const scopes = /* @__PURE__ */ new Set();
394
+ for (const requirement of security) {
395
+ if (!isRecord(requirement)) continue;
396
+ for (const [scheme, rawScopes] of Object.entries(requirement)) {
397
+ if (targetSchemes.size > 0 && !targetSchemes.has(scheme)) continue;
398
+ if (!Array.isArray(rawScopes)) continue;
399
+ for (const scope of rawScopes) {
400
+ if (typeof scope === "string" && scope.trim().length > 0) scopes.add(scope.trim());
401
+ }
402
+ }
403
+ }
404
+ return [...scopes];
405
+ };
406
+ var collectDeclaredSecurityScopes = (doc, targetSchemes) => {
407
+ const scopes = /* @__PURE__ */ new Set();
408
+ if (!isRecord(doc)) return [];
409
+ for (const scope of securityRequirementScopes(doc.security, targetSchemes)) scopes.add(scope);
410
+ const paths = doc.paths;
411
+ if (!isRecord(paths)) return [...scopes].sort();
412
+ for (const pathItem of Object.values(paths)) {
413
+ if (!isRecord(pathItem)) continue;
414
+ for (const [method, operation] of Object.entries(pathItem)) {
415
+ if (!OPENAPI_HTTP_METHODS.has(method.toLowerCase()) || !isRecord(operation)) continue;
416
+ for (const scope of securityRequirementScopes(operation.security, targetSchemes)) {
417
+ scopes.add(scope);
418
+ }
419
+ }
420
+ }
421
+ return [...scopes].sort();
422
+ };
423
+ var nonOAuthSecuritySchemeNames = (preview) => new Set(
424
+ preview.securitySchemes.filter((scheme) => scheme.type === "http" || scheme.type === "apiKey").map((scheme) => scheme.name)
425
+ );
426
+ var discoveredOAuthPreview = (input) => {
427
+ const scopes = Object.fromEntries(input.scopes.map((scope) => [scope, ""]));
428
+ const flow = OAuth2AuthorizationCodeFlow.make({
429
+ authorizationUrl: input.authorizationUrl,
430
+ tokenUrl: input.tokenUrl,
431
+ refreshUrl: Option2.none(),
432
+ scopes
433
+ });
434
+ const flows = OAuth2Flows.make({
435
+ authorizationCode: Option2.some(flow),
436
+ clientCredentials: Option2.none()
437
+ });
438
+ return {
439
+ ...input.preview,
440
+ securitySchemes: [
441
+ ...input.preview.securitySchemes,
442
+ SecurityScheme.make({
443
+ name: OAUTH_DISCOVERED_SCHEME_NAME,
444
+ type: "oauth2",
445
+ scheme: Option2.none(),
446
+ bearerFormat: Option2.none(),
447
+ in: Option2.none(),
448
+ headerName: Option2.none(),
449
+ description: Option2.some("Discovered from OAuth authorization-server metadata"),
450
+ flows: Option2.some(flows),
451
+ openIdConnectUrl: Option2.none()
452
+ })
453
+ ],
454
+ oauth2Presets: [
455
+ ...input.preview.oauth2Presets,
456
+ OAuth2Preset.make({
457
+ label: `OAuth2 Authorization Code \xB7 ${OAUTH_DISCOVERED_SCHEME_NAME}`,
458
+ securitySchemeName: OAUTH_DISCOVERED_SCHEME_NAME,
459
+ flow: "authorizationCode",
460
+ authorizationUrl: Option2.some(input.authorizationUrl),
461
+ tokenUrl: input.tokenUrl,
462
+ resource: input.resource ? Option2.some(input.resource) : Option2.none(),
463
+ refreshUrl: Option2.none(),
464
+ scopes,
465
+ identityScopes: "auto",
466
+ ...input.supportsClientIdMetadataDocument === true ? { supportsClientIdMetadataDocument: true } : {}
467
+ })
468
+ ]
469
+ };
470
+ };
471
+ var describeOpenApiAuthMethods = (record) => {
472
+ const config = decodeOpenApiIntegrationConfig(record.config);
473
+ if (!config) return [];
474
+ return (config.authenticationTemplate ?? []).map(
475
+ (template) => {
476
+ if (template.kind === "oauth2") {
477
+ return {
478
+ id: String(template.slug),
479
+ label: "OAuth2",
480
+ kind: "oauth",
481
+ template: String(template.slug),
482
+ oauth: {
483
+ authorizationUrl: template.authorizationUrl,
484
+ tokenUrl: template.tokenUrl,
485
+ resource: template.resource ?? null,
486
+ scopes: template.scopes,
487
+ supportsClientIdMetadataDocument: template.supportsClientIdMetadataDocument
488
+ }
489
+ };
490
+ }
491
+ return describeApiKeyAuthMethod(template);
492
+ }
493
+ );
494
+ };
495
+ var describeOpenApiIntegrationDisplay = (record) => {
496
+ const config = decodeOpenApiIntegrationConfig(record.config);
497
+ return {
498
+ url: config?.baseUrl ?? config?.specUrl,
499
+ ...config?.family ? { family: config.family } : {}
500
+ };
501
+ };
502
+ var openApiPlugin = definePlugin((options) => {
503
+ const resolveSpecForInput = (config, httpClientLayer) => Effect3.gen(function* () {
504
+ const adapter = yield* resolveSpecFormatAdapter(
505
+ options?.specFormats ?? [],
506
+ config.specFormat
507
+ );
508
+ if (adapter) {
509
+ if (config.spec.kind !== "url") {
510
+ return yield* new OpenApiParseError({
511
+ message: "Spec format adapters require a URL spec input"
512
+ });
513
+ }
514
+ return yield* adapter.fetch({
515
+ urls: [config.spec.url],
516
+ credentials: {
517
+ ...config.headers ? { headers: config.headers } : {},
518
+ ...config.queryParams ? { queryParams: config.queryParams } : {}
519
+ },
520
+ httpClientLayer
521
+ });
522
+ }
523
+ if (config.spec.kind === "url") {
524
+ const specText = yield* resolveSpecText(config.spec.url).pipe(
525
+ Effect3.provide(httpClientLayer)
526
+ );
527
+ return { specText, specUrl: config.spec.url };
528
+ }
529
+ return { specText: config.spec.value };
530
+ });
531
+ return {
532
+ id: "openapi",
533
+ packageName: "@rafads/plugin-openapi",
534
+ clientConfig: options?.presets ? { presets: options.presets } : void 0,
535
+ integrationPresets: [...openApiPresets, ...options?.presets ?? []].map((preset) => ({
536
+ id: preset.id,
537
+ name: preset.name,
538
+ summary: preset.summary,
539
+ ...preset.url ? { url: preset.url } : {},
540
+ ...preset.icon ? { icon: preset.icon } : {},
541
+ ...preset.featured ? { featured: preset.featured } : {},
542
+ ...preset.family ? { family: preset.family } : {},
543
+ ...preset.specFormat ? { specFormat: preset.specFormat } : {},
544
+ ...preset.defaultSlug ? { defaultSlug: preset.defaultSlug } : {},
545
+ ...preset.authTemplate ? { authTemplate: preset.authTemplate } : {},
546
+ ...preset.healthCheck ? { healthCheck: preset.healthCheck } : {}
547
+ })),
548
+ storage: (deps) => makeDefaultOpenapiStore(deps),
549
+ extension: (ctx) => {
550
+ const httpClientLayer = options?.httpClientLayer ?? ctx.httpClientLayer;
551
+ const enrichPreviewWithDiscoveredOAuth = (input) => Effect3.gen(function* () {
552
+ if (input.preview.oauth2Presets.length > 0) return input.preview;
553
+ const candidates = oauthProbeCandidates(input.preview, input.specUrl, input.baseUrl);
554
+ if (candidates.length === 0) return input.preview;
555
+ for (const candidate of candidates) {
556
+ const oauth = yield* ctx.oauth.probe({ url: candidate }).pipe(
557
+ Effect3.map((result) => ({ ok: true, result })),
558
+ Effect3.catch(() => Effect3.succeed({ ok: false, result: null }))
559
+ );
560
+ if (!oauth.ok) continue;
561
+ const doc = yield* parse(input.specText);
562
+ const declaredScopes = collectDeclaredSecurityScopes(
563
+ doc,
564
+ nonOAuthSecuritySchemeNames(input.preview)
565
+ );
566
+ const supportedScopes = oauth.result.scopesSupported && oauth.result.scopesSupported.length > 0 ? new Set(oauth.result.scopesSupported) : null;
567
+ const scopes = supportedScopes ? declaredScopes.filter((scope) => supportedScopes.has(scope)) : declaredScopes;
568
+ return discoveredOAuthPreview({
569
+ preview: input.preview,
570
+ authorizationUrl: oauth.result.authorizationUrl,
571
+ tokenUrl: oauth.result.tokenUrl,
572
+ resource: oauth.result.resource ?? null,
573
+ scopes,
574
+ supportsClientIdMetadataDocument: oauth.result.clientIdMetadataDocumentSupported === true
575
+ });
576
+ }
577
+ return input.preview;
578
+ });
579
+ const addSpec = (config) => Effect3.gen(function* () {
580
+ const resolved = yield* resolveSpecForInput(config, httpClientLayer);
581
+ const compiled = resolved.keepPathItem ? void 0 : yield* compileOpenApiSpec(resolved.specText);
582
+ const adapter = yield* resolveSpecFormatAdapter(
583
+ options?.specFormats ?? [],
584
+ config.specFormat
585
+ );
586
+ const derivedIdentity = adapter?.deriveIdentity && resolved.document ? adapter.deriveIdentity(resolved.document) : null;
587
+ const resolvedSlug = config.slug?.trim() || derivedIdentity?.slug;
588
+ if (!resolvedSlug) {
589
+ return yield* new OpenApiParseError({
590
+ message: "OpenAPI integration slug is required"
591
+ });
592
+ }
593
+ const explicitBaseUrl = config.baseUrl ?? resolved.baseUrl;
594
+ const needsDerivedBaseUrl = explicitBaseUrl == null;
595
+ const needsDerivedAuth = config.authenticationTemplate == null;
596
+ const preview = needsDerivedBaseUrl || needsDerivedAuth ? yield* previewSpecText(resolved.specText).pipe(
597
+ Effect3.flatMap(
598
+ (rawPreview) => enrichPreviewWithDiscoveredOAuth({
599
+ specText: resolved.specText,
600
+ preview: rawPreview,
601
+ specUrl: resolved.specUrl ?? specInputToSpecUrl(config.spec),
602
+ baseUrl: explicitBaseUrl
603
+ })
604
+ )
605
+ ) : void 0;
606
+ const derivedBaseUrl = needsDerivedBaseUrl && preview ? firstBaseUrlForPreview(preview) : void 0;
607
+ const effectiveBaseUrl = explicitBaseUrl ?? (derivedBaseUrl || void 0);
608
+ const derivedAuthenticationTemplate = needsDerivedAuth && preview ? deriveAuthenticationTemplateFromPreview(preview, effectiveBaseUrl) : void 0;
609
+ const slug = IntegrationSlug.make(resolvedSlug);
610
+ const existing = yield* ctx.core.integrations.get(slug);
611
+ if (existing) {
612
+ return yield* new IntegrationAlreadyExistsError({ slug });
613
+ }
614
+ const specHash = yield* sha256Hex(resolved.specText);
615
+ const integrationConfig = {
616
+ ...resolved.config ?? {},
617
+ specHash,
618
+ ...(resolved.specUrl ?? specInputToSpecUrl(config.spec)) !== void 0 ? { specUrl: resolved.specUrl ?? specInputToSpecUrl(config.spec) } : {},
619
+ // baseUrl is an optional override only. The host is otherwise
620
+ // resolved per call from the operation's `servers` (extracted from
621
+ // the spec), so we never bake a derived base URL into the config.
622
+ ...config.baseUrl ? { baseUrl: config.baseUrl } : {},
623
+ ...config.headers ? { headers: config.headers } : {},
624
+ ...config.queryParams ? { queryParams: config.queryParams } : {},
625
+ ...config.specFormat ? { specFormat: config.specFormat } : {},
626
+ ...config.family ? { family: config.family } : {},
627
+ // Prefer the caller's explicit template; otherwise derive from the
628
+ // spec's declared security schemes.
629
+ ...config.authenticationTemplate ? {
630
+ authenticationTemplate: normalizeOpenApiAuthInputs(config.authenticationTemplate)
631
+ } : resolved.authenticationTemplate && resolved.authenticationTemplate.length > 0 ? { authenticationTemplate: resolved.authenticationTemplate } : derivedAuthenticationTemplate && derivedAuthenticationTemplate.length > 0 ? { authenticationTemplate: derivedAuthenticationTemplate } : {}
632
+ };
633
+ yield* ctx.storage.putSpec(specHash, resolved.specText);
634
+ if (compiled) {
635
+ yield* ctx.storage.putDefs(specHash, JSON.stringify(compiled.hoistedDefs));
636
+ }
637
+ yield* ctx.transaction(
638
+ Effect3.gen(function* () {
639
+ yield* ctx.core.integrations.register({
640
+ slug,
641
+ name: config.name?.trim() || derivedIdentity?.name || compiled?.title || resolvedSlug,
642
+ description: config.description ?? derivedIdentity?.description ?? compiled?.description ?? compiled?.title ?? resolvedSlug,
643
+ config: integrationConfig,
644
+ canRemove: true,
645
+ canRefresh: integrationConfig.specUrl != null
646
+ });
647
+ if (config.healthCheck) {
648
+ yield* ctx.core.integrations.setHealthCheck(slug, config.healthCheck);
649
+ }
650
+ if (compiled) {
651
+ yield* ctx.storage.putOperations(
652
+ resolvedSlug,
653
+ openApiStoredOperationsFromCompiled(resolvedSlug, compiled)
654
+ );
655
+ return compiled.definitions.length;
656
+ }
657
+ const persisted = yield* compileAndPersistOpenApiSpecStreaming({
658
+ specText: resolved.specText,
659
+ integration: resolvedSlug,
660
+ storage: ctx.storage,
661
+ specHash,
662
+ keepPathItem: resolved.keepPathItem
663
+ });
664
+ return persisted.toolCount;
665
+ })
666
+ );
667
+ const toolCount = compiled ? compiled.definitions.length : yield* ctx.storage.listOperations(resolvedSlug).pipe(Effect3.map((operations) => operations.length));
668
+ return { slug, toolCount };
669
+ });
670
+ const updateSpec = (rawSlug, input) => Effect3.gen(function* () {
671
+ const slug = IntegrationSlug.make(rawSlug);
672
+ const record = yield* ctx.core.integrations.get(slug);
673
+ const current = record ? decodeOpenApiIntegrationConfig(record.config) : null;
674
+ if (!record || !current) {
675
+ return yield* new IntegrationNotFoundError({ slug });
676
+ }
677
+ const specInput = input?.spec ?? (current.specUrl ? { kind: "url", url: current.specUrl } : null);
678
+ if (specInput === null) {
679
+ return yield* new OpenApiParseError({
680
+ message: "This integration's spec was pasted inline and has no source URL to re-fetch. Provide the updated spec content."
681
+ });
682
+ }
683
+ const resolved = yield* resolveSpecForInput(
684
+ {
685
+ spec: specInput,
686
+ specFormat: current.specFormat,
687
+ headers: current.headers,
688
+ queryParams: current.queryParams,
689
+ baseUrl: current.baseUrl
690
+ },
691
+ httpClientLayer
692
+ );
693
+ const compiled = resolved.keepPathItem ? void 0 : yield* compileOpenApiSpec(resolved.specText);
694
+ const previousOperations = yield* ctx.storage.listOperations(rawSlug);
695
+ const previousNames = new Set(previousOperations.map((op) => op.toolName));
696
+ const specHash = yield* sha256Hex(resolved.specText);
697
+ yield* ctx.storage.putSpec(specHash, resolved.specText);
698
+ if (compiled) {
699
+ yield* ctx.storage.putDefs(specHash, JSON.stringify(compiled.hoistedDefs));
700
+ }
701
+ const nextConfig = {
702
+ ...current,
703
+ specHash,
704
+ ...(resolved.specUrl ?? specInputToSpecUrl(specInput)) !== void 0 ? { specUrl: resolved.specUrl ?? specInputToSpecUrl(specInput) } : {}
705
+ };
706
+ yield* ctx.transaction(
707
+ Effect3.gen(function* () {
708
+ yield* ctx.core.integrations.update(slug, {
709
+ config: nextConfig
710
+ });
711
+ if (compiled) {
712
+ yield* ctx.storage.putOperations(
713
+ rawSlug,
714
+ openApiStoredOperationsFromCompiled(rawSlug, compiled)
715
+ );
716
+ } else {
717
+ yield* compileAndPersistOpenApiSpecStreaming({
718
+ specText: resolved.specText,
719
+ integration: rawSlug,
720
+ storage: ctx.storage,
721
+ specHash,
722
+ keepPathItem: resolved.keepPathItem
723
+ });
724
+ }
725
+ })
726
+ );
727
+ const nextOperations = compiled ? openApiStoredOperationsFromCompiled(rawSlug, compiled) : yield* ctx.storage.listOperations(rawSlug);
728
+ const nextNames = new Set(nextOperations.map((op) => op.toolName));
729
+ const connections = yield* ctx.connections.list({ integration: slug });
730
+ yield* Effect3.forEach(
731
+ connections,
732
+ (connection) => ctx.connections.refresh({
733
+ owner: connection.owner,
734
+ integration: connection.integration,
735
+ name: connection.name
736
+ }).pipe(Effect3.catchTag("ConnectionNotFoundError", () => Effect3.succeed([]))),
737
+ { discard: true }
738
+ ).pipe(
739
+ Effect3.catchTag("IntegrationNotFoundError", () => Effect3.void),
740
+ Effect3.withSpan("openapi.plugin.update_spec.refresh_connections", {
741
+ attributes: { "openapi.connection_count": connections.length }
742
+ })
743
+ );
744
+ return {
745
+ slug,
746
+ toolCount: nextNames.size,
747
+ addedTools: [...nextNames].filter((name) => !previousNames.has(name)).sort(),
748
+ removedTools: [...previousNames].filter((name) => !nextNames.has(name)).sort()
749
+ };
750
+ }).pipe(
751
+ Effect3.withSpan("openapi.plugin.update_spec", {
752
+ attributes: { "openapi.integration.slug": rawSlug }
753
+ })
754
+ );
755
+ return {
756
+ previewSpec: (input) => Effect3.gen(function* () {
757
+ const previewInput = typeof input === "string" ? { spec: input } : input;
758
+ const spec = maybeUrl(previewInput.spec.trim()) ? { kind: "url", url: previewInput.spec.trim() } : { kind: "blob", value: previewInput.spec };
759
+ const resolved = yield* resolveSpecForInput(
760
+ { spec, specFormat: previewInput.specFormat },
761
+ httpClientLayer
762
+ );
763
+ const preview = yield* previewSpecText(resolved.specText);
764
+ return yield* enrichPreviewWithDiscoveredOAuth({
765
+ specText: resolved.specText,
766
+ preview,
767
+ specUrl: resolved.specUrl ?? (spec.kind === "url" ? spec.url : void 0)
768
+ });
769
+ }),
770
+ addSpec,
771
+ updateSpec,
772
+ removeSpec: (slug) => ctx.transaction(
773
+ Effect3.gen(function* () {
774
+ yield* ctx.storage.removeOperations(slug);
775
+ yield* ctx.core.integrations.remove(IntegrationSlug.make(slug)).pipe(Effect3.catchTag("IntegrationRemovalNotAllowedError", () => Effect3.void));
776
+ })
777
+ ),
778
+ getIntegration: (slug) => ctx.core.integrations.get(IntegrationSlug.make(slug)).pipe(
779
+ Effect3.map(
780
+ (record) => record ? {
781
+ slug: record.slug,
782
+ description: record.description,
783
+ kind: record.kind,
784
+ canRemove: record.canRemove,
785
+ canRefresh: record.canRefresh
786
+ } : null
787
+ )
788
+ ),
789
+ getConfig: (slug) => ctx.core.integrations.get(IntegrationSlug.make(slug)).pipe(
790
+ Effect3.map(
791
+ (record) => record ? decodeOpenApiIntegrationConfig(record.config) : null
792
+ )
793
+ ),
794
+ configure: (slug, input) => ctx.transaction(
795
+ Effect3.gen(function* () {
796
+ const record = yield* ctx.core.integrations.get(IntegrationSlug.make(slug));
797
+ if (!record) return [];
798
+ const current = decodeOpenApiIntegrationConfig(record.config);
799
+ if (!current) return [];
800
+ const merged = input.authenticationTemplate === void 0 ? current.authenticationTemplate ?? [] : input.mode === "replace" ? normalizeOpenApiAuthInputs(input.authenticationTemplate) : mergeAuthTemplates(
801
+ current.authenticationTemplate ?? [],
802
+ normalizeOpenApiAuthInputs(input.authenticationTemplate)
803
+ );
804
+ const next = {
805
+ ...current,
806
+ ...input.baseUrl !== void 0 ? { baseUrl: input.baseUrl } : {},
807
+ authenticationTemplate: merged
808
+ };
809
+ yield* ctx.core.integrations.update(IntegrationSlug.make(slug), {
810
+ config: next
811
+ });
812
+ return merged;
813
+ })
814
+ )
815
+ };
816
+ },
817
+ staticIntegrations: (self) => [
818
+ {
819
+ id: "openapi",
820
+ kind: "executor",
821
+ name: "OpenAPI",
822
+ tools: [
823
+ tool({
824
+ name: "previewSpec",
825
+ description: "Preview an OpenAPI document before adding it as an integration. Call this first when the user provides a spec URL/blob so you can inspect servers, auth schemes, operation count, and tags before `addSpec`. Do not collect API keys or OAuth client secrets in chat; use the connections tools for those values.",
826
+ inputSchema: PreviewSpecInputStandardSchema,
827
+ outputSchema: PreviewSpecOutputStandardSchema,
828
+ execute: (input) => self.previewSpec(input).pipe(
829
+ Effect3.map((preview) => ToolResult.ok(staticPreviewOutput(preview))),
830
+ Effect3.catchTags({
831
+ OpenApiParseError: ({ message }) => Effect3.succeed(openApiToolFailure("openapi_parse_failed", message)),
832
+ OpenApiExtractionError: ({ message }) => Effect3.succeed(openApiToolFailure("openapi_extraction_failed", message)),
833
+ OpenApiOAuthError: ({ message }) => Effect3.succeed(openApiToolFailure("openapi_oauth_failed", message))
834
+ })
835
+ )
836
+ }),
837
+ tool({
838
+ name: "addSpec",
839
+ 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 - apiKey header/query, or oauth bearer - or an empty array for no auth methods).",
840
+ annotations: {
841
+ requiresApproval: true,
842
+ approvalDescription: "Add an OpenAPI integration"
843
+ },
844
+ inputSchema: AddIntegrationInputStandardSchema,
845
+ outputSchema: AddIntegrationOutputStandardSchema,
846
+ execute: (input) => self.addSpec({
847
+ spec: input.spec,
848
+ slug: input.slug,
849
+ name: input.name,
850
+ description: input.description,
851
+ baseUrl: input.baseUrl,
852
+ headers: input.headers,
853
+ queryParams: input.queryParams,
854
+ specFormat: input.specFormat,
855
+ family: input.family,
856
+ healthCheck: input.healthCheck,
857
+ authenticationTemplate: input.authenticationTemplate
858
+ }).pipe(
859
+ Effect3.map(
860
+ (result) => ToolResult.ok({
861
+ slug: String(result.slug),
862
+ toolCount: result.toolCount
863
+ })
864
+ ),
865
+ Effect3.catchTags({
866
+ OpenApiParseError: ({ message }) => Effect3.succeed(openApiToolFailure("openapi_parse_failed", message)),
867
+ OpenApiExtractionError: ({ message }) => Effect3.succeed(openApiToolFailure("openapi_extraction_failed", message)),
868
+ OpenApiOAuthError: ({ message }) => Effect3.succeed(openApiToolFailure("openapi_oauth_failed", message)),
869
+ IntegrationAlreadyExistsError: ({ slug }) => Effect3.succeed(
870
+ openApiToolFailure(
871
+ "integration_already_exists",
872
+ `Integration ${slug} already exists; update it instead of re-adding.`
873
+ )
874
+ )
875
+ })
876
+ )
877
+ })
878
+ ]
879
+ }
880
+ ],
881
+ describeAuthMethods: describeOpenApiAuthMethods,
882
+ describeIntegrationDisplay: describeOpenApiIntegrationDisplay,
883
+ // Health checks: the declared liveness/identity probe. Core owns the spec
884
+ // storage; the plugin only enumerates candidates and runs probes.
885
+ listHealthCheckCandidates: (input) => listHealthCheckCandidatesOpenApi({ ctx: input.ctx, integration: input.integration }),
886
+ checkHealth: (input) => checkHealthOpenApi({
887
+ ctx: input.ctx,
888
+ integration: input.integration,
889
+ credential: input.credential,
890
+ spec: input.spec,
891
+ httpClientLayer: options?.httpClientLayer ?? input.ctx.httpClientLayer
892
+ }),
893
+ // Produce one tool per spec operation. Spec-derived, identical for every
894
+ // connection on the integration - so `getValue` is never called here. The
895
+ // operation bindings invokeTool needs are persisted at addSpec time; this
896
+ // hook only shapes the per-connection ToolDefs from the spec blob the
897
+ // catalog config points at.
898
+ resolveTools: ({ integration, config, storage }) => resolveOpenApiBackedTools({ integration, config, storage }),
899
+ invokeTool: ({ ctx: invokeCtx, toolRow, credential, args }) => {
900
+ const httpClientLayer = options?.httpClientLayer ?? invokeCtx.httpClientLayer;
901
+ return invokeOpenApiBackedTool({
902
+ ctx: invokeCtx,
903
+ toolRow,
904
+ credential,
905
+ args,
906
+ httpClientLayer,
907
+ invokeOptions: options?.invokeOptions
908
+ });
909
+ },
910
+ validateToolArgs: ({ ctx: validateCtx, toolRow, args }) => validateOpenApiBackedToolArgs({ ctx: validateCtx, toolRow, args }),
911
+ resolveAnnotations: ({ ctx: annotationsCtx, integration, toolRows }) => resolveOpenApiBackedAnnotations({
912
+ ctx: annotationsCtx,
913
+ integration: String(integration),
914
+ toolRows
915
+ }),
916
+ removeConnection: () => Effect3.void,
917
+ detect: ({
918
+ ctx: detectCtx,
919
+ url
920
+ }) => Effect3.gen(function* () {
921
+ const httpClientLayer = options?.httpClientLayer ?? detectCtx.httpClientLayer;
922
+ const trimmed = url.trim();
923
+ if (!trimmed) return null;
924
+ const parsed = yield* Effect3.try({
925
+ try: () => new URL(trimmed),
926
+ catch: (error) => error
927
+ }).pipe(Effect3.option);
928
+ if (Option2.isNone(parsed)) return null;
929
+ const specText = yield* resolveSpecText(trimmed).pipe(
930
+ Effect3.provide(httpClientLayer),
931
+ Effect3.catch(() => Effect3.succeed(null))
932
+ );
933
+ if (specText === null) return null;
934
+ const doc = yield* parse(specText).pipe(Effect3.catch(() => Effect3.succeed(null)));
935
+ if (!doc) return null;
936
+ const result = yield* extract(doc).pipe(Effect3.catch(() => Effect3.succeed(null)));
937
+ if (!result) return null;
938
+ const slug = Option2.getOrElse(result.title, () => "api").toLowerCase().replace(/[^a-z0-9]+/g, "_");
939
+ const name = Option2.getOrElse(result.title, () => slug);
940
+ return IntegrationDetectionResult.make({
941
+ kind: "openapi",
942
+ confidence: "high",
943
+ endpoint: trimmed,
944
+ name,
945
+ slug
946
+ });
947
+ })
948
+ };
949
+ });
950
+
951
+ export {
952
+ makeDefaultOpenapiStore,
953
+ resolveSpecFormatAdapter,
954
+ openApiPlugin
955
+ };
956
+ //# sourceMappingURL=chunk-OR27BCXQ.js.map