@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 @@
1
+ {"version":3,"sources":["../src/react/AddOpenApiIntegration.tsx","../src/react/OpenApiIntegrationDetailsFields.tsx"],"sourcesContent":["import { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { useAtomSet } from \"@effect/atom-react\";\nimport * as Effect from \"effect/Effect\";\nimport * as Exit from \"effect/Exit\";\nimport * as Option from \"effect/Option\";\n\nimport {\n AuthTemplateSlug,\n IntegrationSlug,\n type HealthCheckCandidate,\n type HealthCheckSpec,\n} from \"@rafads/sdk/shared\";\nimport { useIntegrationPlugins } from \"@rafads/sdk/client\";\nimport { integrationWriteKeys, healthCheckWriteKeys } from \"@rafads/react/api/reactivity-keys\";\nimport { setIntegrationHealthCheck } from \"@rafads/react/api/atoms\";\nimport {\n slugifyNamespace,\n useIntegrationIdentity,\n} from \"@rafads/react/plugins/integration-identity\";\nimport { Button } from \"@rafads/react/components/button\";\nimport { HealthCheckConfigFields } from \"@rafads/react/components/health-check-editor\";\nimport {\n AuthMethodListEditor,\n useAuthMethodList,\n type AuthMethodRow,\n type AuthMethodSeed,\n} from \"@rafads/react/components/auth-method-list-editor\";\nimport { CardStack, CardStackContent } from \"@rafads/react/components/card-stack\";\nimport { FieldLabel } from \"@rafads/react/components/field\";\nimport { FloatActions } from \"@rafads/react/components/float-actions\";\nimport { Textarea } from \"@rafads/react/components/textarea\";\nimport { IOSSpinner } from \"@rafads/react/components/spinner\";\nimport {\n addIntegrationErrorMessage,\n errorMessageFromExit,\n FormErrorAlert,\n SlugCollisionAlert,\n useSlugAlreadyExists,\n} from \"@rafads/react/lib/integration-add\";\n\nimport {\n authenticationFromEditorValue,\n editorValueFromAuthentication,\n openApiWireAuthInput,\n} from \"./auth-method-config\";\nimport { addOpenApiSpec, previewOpenApiSpec } from \"./atoms\";\nimport { OpenApiIntegrationDetailsFields } from \"./OpenApiIntegrationDetailsFields\";\nimport type { SpecPreviewSummary } from \"../sdk/preview\";\nimport { type Authentication } from \"../sdk/types\";\nimport { resolveServerUrl } from \"../sdk/openapi-utils\";\nimport { detectedAuthenticationTemplates } from \"../sdk/derive-auth\";\n\nconst normalizePresetUrl = (url: string): string => {\n const trimmed = url.trim();\n if (!URL.canParse(trimmed)) return trimmed.replace(/\\/$/, \"\");\n const parsed = new URL(trimmed);\n parsed.hash = \"\";\n parsed.searchParams.sort();\n return parsed.toString().replace(/\\/$/, \"\");\n};\n\nconst specInputForAdd = (input: string) => {\n const value = input.trim();\n const parsed = Effect.runSyncExit(\n Effect.try({\n try: () => new URL(value),\n catch: () => null,\n }),\n );\n return Exit.isSuccess(parsed)\n ? { kind: \"url\" as const, url: value }\n : { kind: \"blob\" as const, value };\n};\n\nexport const baseUrlFromSpecInput = (input: string): string => {\n const value = input.trim();\n if (!URL.canParse(value)) return \"\";\n const parsed = new URL(value);\n if (parsed.protocol !== \"https:\" && parsed.protocol !== \"http:\") return \"\";\n return parsed.origin;\n};\n\nexport const openApiPreviewFailureMessage = (message: string | null | undefined): string =>\n `Couldn't load or parse this spec: ${message && message.trim().length > 0 ? message : \"unknown error\"}`;\n\nexport function AddOpenApiHealthCheckSection(props: {\n readonly presetHealthCheck?: HealthCheckSpec;\n readonly candidates: readonly HealthCheckCandidate[];\n readonly selected: HealthCheckCandidate | null;\n readonly operation: string;\n readonly onOperationChange: (operation: string) => void;\n readonly identityField: string;\n readonly onIdentityFieldChange: (field: string) => void;\n readonly args: Record<string, string>;\n readonly onArgChange: (name: string, value: string) => void;\n readonly disabled: boolean;\n}) {\n if (props.presetHealthCheck) {\n return (\n <section className=\"space-y-2\">\n <h3 className=\"text-sm font-medium text-foreground\">Health check</h3>\n <p className=\"text-[11px] text-muted-foreground\">\n <span className=\"font-mono text-foreground\">{props.presetHealthCheck.operation}</span>{\" \"}\n From the catalog. Change it later from the integration page.\n </p>\n </section>\n );\n }\n\n if (props.candidates.length === 0) return null;\n\n return (\n <section className=\"space-y-4\">\n <div className=\"space-y-1\">\n <h3 className=\"text-sm font-medium text-foreground\">Health check (optional)</h3>\n <p className=\"text-[11px] text-muted-foreground\">\n An optional read-only probe adds live upstream depth. For OAuth connections, validity and\n identity come from the OAuth grant itself. For non-OAuth methods, the probe can validate\n the credential and identify the account.\n </p>\n </div>\n <HealthCheckConfigFields\n candidates={props.candidates}\n selected={props.selected}\n operation={props.operation}\n onOperationChange={props.onOperationChange}\n identityField={props.identityField}\n onIdentityFieldChange={props.onIdentityFieldChange}\n args={props.args}\n onArgChange={props.onArgChange}\n disabled={props.disabled}\n idPrefix=\"add-health-check\"\n />\n </section>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Component: single progressive form. Post-redesign: preview -> addSpec\n// (register the integration catalog entry with ALL detected auth methods) →\n// route to the integration's detail hub, where the user adds accounts. The add\n// flow no longer creates a connection.\n// ---------------------------------------------------------------------------\n\nexport default function AddOpenApiIntegration(props: {\n onComplete: (slug?: string) => void;\n onCancel: () => void;\n initialUrl?: string;\n initialPreset?: string;\n initialNamespace?: string;\n}) {\n const integrationPlugins = useIntegrationPlugins();\n const openApiPlugin = integrationPlugins.find((plugin) => plugin.key === \"openapi\");\n const openApiPresets = openApiPlugin?.presets;\n const initialPreset = openApiPresets?.find((preset) => preset.id === props.initialPreset) ?? null;\n const [specUrl, setSpecUrl] = useState(props.initialUrl ?? \"\");\n const [analyzing, setAnalyzing] = useState(false);\n const [analyzeError, setAnalyzeError] = useState<string | null>(null);\n\n // After analysis\n const [preview, setPreview] = useState<SpecPreviewSummary | null>(null);\n const [baseUrl, setBaseUrl] = useState(\"\");\n // Agent-visible description: prefilled from the spec's `info.description`\n // until the user types (null = untouched, keep deriving from the preview).\n const [descriptionDraft, setDescriptionDraft] = useState<string | null>(null);\n const identityFallbackName =\n initialPreset?.name ?? (preview ? Option.getOrElse(preview.title, () => \"\") : \"\");\n const identity = useIntegrationIdentity({\n fallbackName: identityFallbackName,\n fallbackNamespace: props.initialNamespace,\n });\n\n // Submit\n const [adding, setAdding] = useState(false);\n const [addError, setAddError] = useState<string | null>(null);\n\n // Optional health check drafted while adding. Empty `hcOperation` means \"not\n // drafted\": we then leave the integration's auto-detected default untouched\n // rather than persisting a blank. No live preview here (no integration/key\n // exists pre-creation, and `validateConnection` requires a persisted one).\n const [hcOperation, setHcOperation] = useState(\"\");\n const [hcIdentityField, setHcIdentityField] = useState(\"\");\n const [hcArgs, setHcArgs] = useState<Record<string, string>>({});\n\n const doPreview = useAtomSet(previewOpenApiSpec, { mode: \"promiseExit\" });\n const doAdd = useAtomSet(addOpenApiSpec, { mode: \"promiseExit\" });\n const doSetHealthCheck = useAtomSet(setIntegrationHealthCheck, { mode: \"promiseExit\" });\n\n // Keep the latest handleAnalyze in a ref so the debounced effect doesn't need\n // it as a dependency (it closes over fresh state).\n const handleAnalyzeRef = useRef<() => void>(() => {});\n\n useEffect(() => {\n const trimmed = specUrl.trim();\n if (!trimmed) return;\n if (preview) return;\n const handle = setTimeout(() => {\n handleAnalyzeRef.current();\n }, 400);\n return () => clearTimeout(handle);\n }, [specUrl, preview]);\n\n // ---- Derived state ----\n\n const previewHasNoServers = preview !== null && preview.servers.length === 0;\n // Offer the spec's servers (resolved with defaults) as base-URL choices when\n // there's more than one; a single/no server uses a plain input.\n const baseUrlOptions =\n preview && preview.servers.length > 1\n ? preview.servers.map((server) => {\n const url = resolveServerUrl(server.url, Option.getOrUndefined(server.variables), {});\n return { value: url, label: url };\n })\n : undefined;\n const firstServer = preview?.servers[0];\n const firstServerUrl = firstServer\n ? resolveServerUrl(firstServer.url, Option.getOrUndefined(firstServer.variables), {})\n : \"\";\n const previewPresetIcon =\n openApiPresets?.find(\n (preset) => preset.url && normalizePresetUrl(preset.url) === normalizePresetUrl(specUrl),\n )?.icon ?? null;\n\n const resolvedBaseUrl = baseUrl.trim();\n const resolvedIntegrationId =\n initialPreset?.defaultSlug ||\n slugifyNamespace(identity.namespace) ||\n (preview ? Option.getOrElse(preview.title, () => \"openapi\") : \"openapi\");\n const resolvedDisplayName =\n identity.name.trim() ||\n (preview\n ? Option.getOrElse(preview.title, () => resolvedIntegrationId)\n : resolvedIntegrationId);\n const resolvedDescription =\n descriptionDraft ?? (preview ? Option.getOrElse(preview.description, () => \"\") : \"\");\n\n // Register EVERY spec-detected auth method, not just a single selected one.\n // Keyed off `preview` (stable per analysis) so the memo doesn't re-run on the\n // freshly-allocated `?? []` fallback arrays.\n const authenticationTemplate: readonly Authentication[] = useMemo(() => {\n if (initialPreset?.authTemplate) {\n return initialPreset.authTemplate.flatMap((template): readonly Authentication[] =>\n template.kind === \"oauth2\"\n ? [\n {\n ...template,\n slug: AuthTemplateSlug.make(template.slug),\n resource: template.resource ?? undefined,\n },\n ]\n : [],\n );\n }\n return detectedAuthenticationTemplates(\n preview?.headerPresets ?? [],\n preview?.oauth2Presets ?? [],\n resolvedBaseUrl,\n );\n }, [initialPreset?.authTemplate, preview, resolvedBaseUrl]);\n\n // Editable auth methods, seeded from the spec-detected templates. The add flow\n // registers EVERY method (P6), so this is a LIST, preserving multi-method\n // specs (e.g. apiKey + OAuth). Each seed carries the detected template's\n // original slug, so an unedited detected method submits with its EXACT\n // original slug (preserving behavior); added methods (no seed) get a\n // deterministic fresh slug. Re-seeded whenever a fresh detection arrives\n // (keyed on the detected templates, stable per analysis + base URL).\n const authMethodSeeds: readonly AuthMethodSeed[] = useMemo(() => {\n const labels = [\n ...(preview?.headerPresets ?? []).map((preset) => preset.label),\n ...(preview?.oauth2Presets ?? []).map((preset) => preset.label),\n ];\n return authenticationTemplate.map(\n (template: Authentication, index: number): AuthMethodSeed => ({\n value: editorValueFromAuthentication(template),\n slug: String(template.slug),\n ...(labels[index] !== undefined ? { label: labels[index] } : {}),\n }),\n );\n }, [preview, authenticationTemplate]);\n const authMethodList = useAuthMethodList(authMethodSeeds);\n\n // The methods to register, mapped back to stored `Authentication[]`. Drops\n // `none` rows (nothing to register). An unedited detected method keeps its\n // original `seedSlug`; an added method gets a deterministic fresh slug.\n const editedAuthenticationTemplate: readonly Authentication[] = useMemo(() => {\n const templates: Authentication[] = [];\n authMethodList.rows.forEach((row: AuthMethodRow, index: number) => {\n const slug =\n row.seedSlug ?? (row.value.kind === \"oauth\" ? `oauth-${index}` : `apikey-${index}`);\n const template = authenticationFromEditorValue(row.value, slug);\n if (template !== null) templates.push(template);\n });\n return templates;\n }, [authMethodList.rows]);\n\n // Health-check candidates from the bounded preview (top-ranked operations with\n // their response fields). The picker is freeform, so a custom op is still\n // reachable when the spec exposes none.\n const healthCheckCandidates = useMemo<readonly HealthCheckCandidate[]>(\n () => preview?.healthCheckCandidates ?? [],\n [preview?.healthCheckCandidates],\n );\n const hcSelected = useMemo(\n () => healthCheckCandidates.find((c) => c.operation === hcOperation) ?? null,\n [healthCheckCandidates, hcOperation],\n );\n const hcRequiredParams = useMemo(\n () => (hcSelected?.parameters ?? []).filter((p) => p.required),\n [hcSelected],\n );\n const hcMissingRequired = hcRequiredParams.some(\n (p) => (hcArgs[p.name] ?? \"\").trim().length === 0,\n );\n\n const onHcOperationChange = (next: string) => {\n setHcOperation(next);\n // Args and identity path are operation-specific; drop them so neither\n // dangles onto a freshly picked operation.\n setHcArgs({});\n setHcIdentityField(\"\");\n };\n const onHcArgChange = (name: string, value: string) =>\n setHcArgs((prev) => ({ ...prev, [name]: value }));\n\n // Pre-empt the API's `IntegrationAlreadyExistsError`: adding an integration\n // whose slug already exists clobbers the existing one's connections/policies,\n // so the API blocks it. Surface that here from the tenant-scoped catalog list.\n const slugAlreadyExists = useSlugAlreadyExists(resolvedIntegrationId);\n\n // The base URL is optional when the spec declares servers (resolved per call);\n // required only when it doesn't. A drafted health check must have its required\n // args filled (an empty draft, `hcOperation === \"\"`, imposes no constraint).\n const canAdd =\n preview !== null &&\n !slugAlreadyExists &&\n (!previewHasNoServers || resolvedBaseUrl.length > 0) &&\n !(hcOperation.length > 0 && hcMissingRequired);\n\n // ---- Handlers ----\n\n const handleAnalyze = async () => {\n setAnalyzing(true);\n setAnalyzeError(null);\n setAddError(null);\n const exit = await doPreview({\n payload: { spec: specUrl, specFormat: initialPreset?.specFormat },\n });\n if (Exit.isFailure(exit)) {\n setAnalyzeError(errorMessageFromExit(exit, \"Failed to parse spec\"));\n setAnalyzing(false);\n return;\n }\n const result = exit.value;\n setPreview(result);\n setBaseUrl(result.servers.length === 0 ? baseUrlFromSpecInput(specUrl) : \"\");\n setAnalyzing(false);\n };\n\n handleAnalyzeRef.current = handleAnalyze;\n\n // Persist the integration and return its slug. Registers the catalog entry\n // with every detected auth method. Adding a slug that already exists is\n // rejected by the API (`IntegrationAlreadyExistsError`), surfaced inline.\n const ensureIntegration = useCallback(async (): Promise<IntegrationSlug | null> => {\n const exit = await doAdd({\n payload: {\n spec: specInputForAdd(specUrl),\n slug: resolvedIntegrationId,\n name: resolvedDisplayName,\n ...(resolvedDescription.trim().length > 0\n ? { description: resolvedDescription.trim() }\n : {}),\n baseUrl: resolvedBaseUrl,\n specFormat: initialPreset?.specFormat,\n family: initialPreset?.family,\n healthCheck: initialPreset?.healthCheck,\n // Always send the edited method list (even empty) when the user has\n // inspected a preview: an explicit [] means \"no auth methods\", while\n // OMITTING the field tells the server to derive defaults from the\n // spec, which would silently resurrect methods the user deleted.\n // Serialize to the wire input dialect (apikey -> request-shaped).\n authenticationTemplate: editedAuthenticationTemplate.map(openApiWireAuthInput),\n },\n reactivityKeys: integrationWriteKeys,\n });\n if (Exit.isFailure(exit)) {\n setAddError(\n addIntegrationErrorMessage(exit, resolvedIntegrationId, \"Failed to add integration\"),\n );\n return null;\n }\n return exit.value.slug;\n }, [\n specUrl,\n doAdd,\n resolvedIntegrationId,\n resolvedDisplayName,\n resolvedDescription,\n resolvedBaseUrl,\n editedAuthenticationTemplate,\n initialPreset?.family,\n initialPreset?.healthCheck,\n initialPreset?.specFormat,\n ]);\n\n const handleAdd = async () => {\n setAdding(true);\n setAddError(null);\n\n const integration = await ensureIntegration();\n if (!integration) {\n setAdding(false);\n return;\n }\n\n // Persist the drafted health check only when the user actively picked an\n // operation; otherwise leave the integration's auto-detected default in\n // place. A failure here is non-fatal, and must NOT block navigation: the\n // integration is already created server-side, so returning here would strand\n // the user (re-submitting the form hits the slug-already-exists guard). The\n // check stays editable from the integration's detail page, so on failure we\n // proceed to onComplete regardless and let the user fix it there.\n if (hcOperation.length > 0) {\n const identity = hcIdentityField.trim();\n const argEntries = Object.entries(hcArgs)\n .map(([key, value]) => [key, value.trim()] as const)\n .filter(([, value]) => value.length > 0);\n const spec: HealthCheckSpec = {\n operation: hcOperation,\n ...(argEntries.length > 0 ? { args: Object.fromEntries(argEntries) } : {}),\n ...(identity.length > 0 ? { identityField: identity } : {}),\n };\n // Best-effort: the exit is intentionally ignored so a save failure cannot\n // block completion.\n await doSetHealthCheck({\n params: { slug: integration },\n payload: { spec },\n reactivityKeys: healthCheckWriteKeys,\n });\n }\n\n props.onComplete(String(integration));\n };\n\n // ---- Render ----\n\n return (\n <div className=\"flex flex-1 flex-col gap-6\">\n <div>\n <h1 className=\"text-xl font-semibold text-foreground\">Add OpenAPI integration</h1>\n </div>\n\n {!preview ? (\n <CardStack>\n <CardStackContent className=\"border-t-0\">\n <div className=\"space-y-2 p-3\">\n <FieldLabel>OpenAPI Spec</FieldLabel>\n <div className=\"relative\">\n <Textarea\n value={specUrl}\n onChange={(e) => {\n setSpecUrl((e.target as HTMLTextAreaElement).value);\n setAnalyzeError(null);\n }}\n placeholder=\"https://api.example.com/openapi.json\"\n rows={3}\n maxRows={10}\n className=\"font-mono text-sm\"\n />\n {analyzing && (\n <div className=\"pointer-events-none absolute right-2 top-2\">\n <IOSSpinner className=\"size-4\" />\n </div>\n )}\n </div>\n <p className=\"text-[11px] text-muted-foreground\">\n Paste a URL or raw JSON/YAML content.\n </p>\n {analyzing && (\n <p className=\"flex items-center gap-2 text-xs text-muted-foreground\">\n <IOSSpinner className=\"size-3.5\" />\n Checking spec…\n </p>\n )}\n {analyzeError && !analyzing && (\n <div className=\"flex flex-wrap items-center gap-2 text-xs text-destructive\">\n <span>{openApiPreviewFailureMessage(analyzeError)}</span>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n className=\"h-7 px-2\"\n onClick={() => void handleAnalyze()}\n >\n Retry\n </Button>\n </div>\n )}\n </div>\n </CardStackContent>\n </CardStack>\n ) : null}\n\n {preview ? (\n <OpenApiIntegrationDetailsFields\n title={Option.getOrElse(preview.title, () => \"API\")}\n subtitle={`${Option.getOrElse(preview.version, () => \"\")}${\n Option.isSome(preview.version) ? \" · \" : \"\"\n }${preview.operationCount} operation${preview.operationCount !== 1 ? \"s\" : \"\"}${\n preview.tags.length > 0\n ? ` · ${preview.tags.length} tag${preview.tags.length !== 1 ? \"s\" : \"\"}`\n : \"\"\n }`}\n identity={identity}\n description={resolvedDescription}\n onDescriptionChange={setDescriptionDraft}\n baseUrl={resolvedBaseUrl}\n onBaseUrlChange={setBaseUrl}\n baseUrlOptions={baseUrlOptions}\n baseUrlLabel={previewHasNoServers ? \"Base URL\" : \"Base URL override (optional)\"}\n baseUrlPlaceholder={firstServerUrl || \"https://api.example.com\"}\n baseUrlHint={\n previewHasNoServers\n ? undefined\n : \"Overrides the spec's servers; leave empty to choose the server (and variables) per tool call.\"\n }\n baseUrlMissingMessage={\n previewHasNoServers ? \"This spec declares no servers, enter a base URL.\" : undefined\n }\n specUrl={specUrl}\n onSpecUrlChange={(value) => {\n setSpecUrl(value);\n setPreview(null);\n setBaseUrl(\"\");\n }}\n faviconIcon={previewPresetIcon}\n faviconUrl={resolvedBaseUrl || firstServerUrl}\n />\n ) : null}\n\n {preview && (\n <AuthMethodListEditor\n list={authMethodList}\n emptyHint=\"No authentication detected. Add a method, or add the integration without auth and connect an account from the integration page later.\"\n footerHint=\"Every method here is registered with the integration. Connect an account from the integration page after adding.\"\n />\n )}\n\n {preview ? (\n <AddOpenApiHealthCheckSection\n presetHealthCheck={initialPreset?.healthCheck}\n candidates={healthCheckCandidates}\n selected={hcSelected}\n operation={hcOperation}\n onOperationChange={onHcOperationChange}\n identityField={hcIdentityField}\n onIdentityFieldChange={setHcIdentityField}\n args={hcArgs}\n onArgChange={onHcArgChange}\n disabled={adding}\n />\n ) : null}\n\n {preview && slugAlreadyExists && !adding && (\n <SlugCollisionAlert slug={resolvedIntegrationId} />\n )}\n\n {addError && <FormErrorAlert message={addError} />}\n\n <FloatActions>\n <Button variant=\"ghost\" onClick={() => props.onCancel()} disabled={adding}>\n Cancel\n </Button>\n <Button onClick={() => void handleAdd()} disabled={!canAdd || analyzing} loading={adding}>\n Add integration\n </Button>\n </FloatActions>\n </div>\n );\n}\n","import {\n CardStack,\n CardStackContent,\n CardStackEntry,\n CardStackEntryContent,\n CardStackEntryDescription,\n CardStackEntryField,\n CardStackEntryTitle,\n} from \"@rafads/react/components/card-stack\";\nimport { FreeformCombobox, type FreeformComboboxOption } from \"@rafads/react/components/combobox\";\nimport { Input } from \"@rafads/react/components/input\";\nimport { Textarea } from \"@rafads/react/components/textarea\";\nimport { IntegrationFavicon } from \"@rafads/react/components/integration-favicon\";\nimport {\n IntegrationIdentityFieldRows,\n type IntegrationIdentity,\n} from \"@rafads/react/plugins/integration-identity\";\n\n/** The spec input is shown as a one-line \"Spec URL\" field only when it IS a\n * URL; pasted document content gets a multi-line editor instead. */\nconst isUrlInput = (value: string): boolean => URL.canParse(value.trim());\n\nexport function OpenApiIntegrationDetailsFields(props: {\n readonly title: string;\n readonly subtitle?: string;\n readonly identity: IntegrationIdentity;\n /** The integration's agent-visible description (prefilled from the spec). */\n readonly description?: string;\n readonly onDescriptionChange?: (value: string) => void;\n readonly baseUrl: string;\n readonly onBaseUrlChange: (value: string) => void;\n readonly baseUrlOptions?: readonly FreeformComboboxOption[];\n readonly baseUrlLabel?: string;\n readonly baseUrlPlaceholder?: string;\n readonly baseUrlHint?: string;\n readonly specUrl?: string;\n readonly onSpecUrlChange?: (value: string) => void;\n readonly faviconIcon?: string | null;\n readonly faviconUrl?: string;\n readonly namespaceReadOnly?: boolean;\n readonly specUrlDisabled?: boolean;\n readonly saveState?: \"idle\" | \"saving\" | \"saved\";\n readonly baseUrlMissingMessage?: string;\n readonly footer?: string;\n}) {\n const specIsUrl = props.specUrl !== undefined && isUrlInput(props.specUrl);\n\n return (\n <CardStack>\n <CardStackContent className=\"border-t-0\">\n <CardStackEntry>\n {(props.faviconIcon || props.faviconUrl) && (\n <IntegrationFavicon icon={props.faviconIcon} url={props.faviconUrl} size={16} />\n )}\n <CardStackEntryContent>\n <CardStackEntryTitle>{props.title}</CardStackEntryTitle>\n {props.subtitle && (\n <CardStackEntryDescription>{props.subtitle}</CardStackEntryDescription>\n )}\n </CardStackEntryContent>\n {props.saveState && props.saveState !== \"idle\" && (\n <span className=\"text-xs text-muted-foreground\">\n {props.saveState === \"saving\" ? \"Saving…\" : \"Saved\"}\n </span>\n )}\n </CardStackEntry>\n <IntegrationIdentityFieldRows\n identity={props.identity}\n namespaceReadOnly={props.namespaceReadOnly}\n />\n {props.onDescriptionChange && (\n <CardStackEntryField label=\"Description\">\n <Textarea\n value={props.description ?? \"\"}\n onChange={(e) => props.onDescriptionChange?.((e.target as HTMLTextAreaElement).value)}\n placeholder=\"What this API is and when to reach for it\"\n rows={2}\n maxRows={6}\n className=\"text-sm\"\n />\n </CardStackEntryField>\n )}\n <div className=\"grid grid-cols-1 md:grid-cols-2\">\n <CardStackEntryField label={props.baseUrlLabel ?? \"Base URL\"}>\n {props.baseUrlOptions && props.baseUrlOptions.length > 0 ? (\n <FreeformCombobox\n value={props.baseUrl}\n onValueChange={props.onBaseUrlChange}\n options={props.baseUrlOptions}\n placeholder={props.baseUrlPlaceholder ?? \"https://api.example.com\"}\n className=\"w-full\"\n inputClassName=\"font-mono text-sm\"\n />\n ) : (\n <Input\n value={props.baseUrl}\n onChange={(e) => props.onBaseUrlChange((e.target as HTMLInputElement).value)}\n placeholder={props.baseUrlPlaceholder ?? \"https://api.example.com\"}\n className=\"font-mono text-sm\"\n />\n )}\n\n {props.baseUrlMissingMessage && !props.baseUrl && (\n <p className=\"text-[11px] text-muted-foreground\">{props.baseUrlMissingMessage}</p>\n )}\n {props.baseUrlHint && (\n <p className=\"text-[11px] text-muted-foreground\">{props.baseUrlHint}</p>\n )}\n </CardStackEntryField>\n {specIsUrl && props.onSpecUrlChange && (\n <CardStackEntryField label=\"Spec URL\">\n <Input\n value={props.specUrl}\n onChange={(e) => props.onSpecUrlChange?.((e.target as HTMLInputElement).value)}\n placeholder=\"https://api.example.com/openapi.json\"\n className=\"font-mono text-sm\"\n disabled={props.specUrlDisabled}\n />\n </CardStackEntryField>\n )}\n </div>\n {props.specUrl !== undefined && !specIsUrl && props.onSpecUrlChange && (\n <CardStackEntryField label=\"Spec\">\n <Textarea\n value={props.specUrl}\n onChange={(e) => props.onSpecUrlChange?.((e.target as HTMLTextAreaElement).value)}\n placeholder=\"Pasted OpenAPI JSON/YAML\"\n rows={4}\n maxRows={12}\n className=\"font-mono text-xs\"\n disabled={props.specUrlDisabled}\n />\n </CardStackEntryField>\n )}\n {props.footer && (\n <CardStackEntry>\n <CardStackEntryContent>\n <CardStackEntryTitle>{props.footer}</CardStackEntryTitle>\n </CardStackEntryContent>\n </CardStackEntry>\n )}\n </CardStackContent>\n </CardStack>\n );\n}\n"],"mappings":"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","names":["CardStack","CardStackContent","Textarea","jsx","jsxs","identity","CardStack","CardStackContent","Textarea"]}
@@ -0,0 +1,106 @@
1
+ import {
2
+ authMethodsFromConfig,
3
+ openApiWireAuthInput,
4
+ templateFromPlacements
5
+ } from "./chunk-IG6QTTZB.js";
6
+ import {
7
+ openApiConfigAtom,
8
+ openapiConfigure
9
+ } from "./chunk-6V45G2XQ.js";
10
+ import "./chunk-HTHEUUJA.js";
11
+ import "./chunk-R7TVM3XD.js";
12
+ import "./chunk-CXFO6TLJ.js";
13
+
14
+ // src/react/OpenApiAccountsPanel.tsx
15
+ import { useCallback, useMemo } from "react";
16
+ import { useAtomValue, useAtomSet } from "@effect/atom-react";
17
+ import * as Exit from "effect/Exit";
18
+ import * as AsyncResult from "effect/unstable/reactivity/AsyncResult";
19
+ import { AuthTemplateSlug, IntegrationSlug } from "@rafads/sdk/shared";
20
+ import { AccountsSection } from "@rafads/react/components/accounts-section";
21
+ import {
22
+ HealthCheckEditor
23
+ } from "@rafads/react/components/health-check-editor";
24
+ import { integrationWriteKeys } from "@rafads/react/api/reactivity-keys";
25
+ import { useOrganizationId } from "@rafads/react/api/organization-context";
26
+ import { defaultConnectionOwnerForHost } from "@rafads/react/plugins/connection-owner";
27
+ import {
28
+ useCustomMethodActions
29
+ } from "@rafads/react/lib/custom-auth-methods";
30
+ import { jsx, jsxs } from "react/jsx-runtime";
31
+ var NO_AUTH_METHOD = {
32
+ id: "none",
33
+ label: "No authentication",
34
+ kind: "none",
35
+ source: "spec",
36
+ template: AuthTemplateSlug.make("none"),
37
+ placements: []
38
+ };
39
+ function OpenApiAccountsPanel(props) {
40
+ const { integrationId, integrationName, accountHandoff } = props;
41
+ const slug = IntegrationSlug.make(integrationId);
42
+ const configResult = useAtomValue(openApiConfigAtom(slug));
43
+ const doConfigure = useAtomSet(openapiConfigure, { mode: "promiseExit" });
44
+ const existingTemplate = useMemo(() => {
45
+ if (!AsyncResult.isSuccess(configResult) || configResult.value == null) return [];
46
+ return configResult.value.authenticationTemplate ?? [];
47
+ }, [configResult]);
48
+ const methods = useMemo(() => {
49
+ const declared = authMethodsFromConfig(existingTemplate);
50
+ return declared.length > 0 ? declared : [NO_AUTH_METHOD];
51
+ }, [existingTemplate]);
52
+ const configure = useCallback(
53
+ async (input) => {
54
+ const exit = await doConfigure({
55
+ params: { slug },
56
+ payload: {
57
+ authenticationTemplate: input.authenticationTemplate.map(openApiWireAuthInput),
58
+ ...input.mode ? { mode: input.mode } : {}
59
+ },
60
+ reactivityKeys: integrationWriteKeys
61
+ });
62
+ return Exit.map(exit, (result) => result.authenticationTemplate);
63
+ },
64
+ [doConfigure, slug]
65
+ );
66
+ const codec = useMemo(
67
+ () => ({
68
+ toAuthMethods: authMethodsFromConfig,
69
+ // Slug omitted → backend backfills `custom_<id>`.
70
+ templatesFromPlacements: (placements) => [
71
+ templateFromPlacements(placements)
72
+ ],
73
+ slugOf: (template) => String(template.slug)
74
+ }),
75
+ []
76
+ );
77
+ const { createCustomMethod, removeCustomMethod } = useCustomMethodActions({
78
+ existing: existingTemplate,
79
+ codec,
80
+ configure
81
+ });
82
+ const organizationId = useOrganizationId();
83
+ const livePreview = useMemo(() => {
84
+ const templates = methods.filter((m) => m.kind === "apikey").map((m) => ({ template: m.template, label: m.label }));
85
+ if (templates.length === 0) return void 0;
86
+ return { owner: defaultConnectionOwnerForHost(organizationId), templates };
87
+ }, [methods, organizationId]);
88
+ return /* @__PURE__ */ jsxs("div", { className: "mx-auto max-w-3xl space-y-8 px-6 py-8", children: [
89
+ /* @__PURE__ */ jsx(
90
+ AccountsSection,
91
+ {
92
+ integration: slug,
93
+ integrationName,
94
+ methods,
95
+ accountHandoff,
96
+ createCustomMethod,
97
+ removeCustomMethod
98
+ }
99
+ ),
100
+ /* @__PURE__ */ jsx(HealthCheckEditor, { integration: slug, livePreview })
101
+ ] });
102
+ }
103
+ export {
104
+ OpenApiAccountsPanel as default
105
+ };
106
+ //# sourceMappingURL=OpenApiAccountsPanel-GZFDSTAU.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/react/OpenApiAccountsPanel.tsx"],"sourcesContent":["import { useCallback, useMemo } from \"react\";\nimport { useAtomValue, useAtomSet } from \"@effect/atom-react\";\nimport * as Exit from \"effect/Exit\";\nimport * as AsyncResult from \"effect/unstable/reactivity/AsyncResult\";\nimport { AuthTemplateSlug, IntegrationSlug } from \"@rafads/sdk/shared\";\nimport type { IntegrationAccountHandoff } from \"@rafads/sdk/client\";\n\nimport { AccountsSection } from \"@rafads/react/components/accounts-section\";\nimport {\n HealthCheckEditor,\n type HealthCheckLivePreview,\n} from \"@rafads/react/components/health-check-editor\";\nimport { integrationWriteKeys } from \"@rafads/react/api/reactivity-keys\";\nimport { useOrganizationId } from \"@rafads/react/api/organization-context\";\nimport { defaultConnectionOwnerForHost } from \"@rafads/react/plugins/connection-owner\";\nimport type { AuthMethod, Placement } from \"@rafads/react/lib/auth-placements\";\nimport {\n useCustomMethodActions,\n type AuthMethodsCodec,\n type ConfigureAuthMethods,\n} from \"@rafads/react/lib/custom-auth-methods\";\n\nimport { openApiConfigAtom, openapiConfigure } from \"./atoms\";\nimport {\n authMethodsFromConfig,\n templateFromPlacements,\n openApiWireAuthInput,\n} from \"./auth-method-config\";\nimport type { Authentication } from \"../sdk/types\";\n\nconst NO_AUTH_METHOD: AuthMethod = {\n id: \"none\",\n label: \"No authentication\",\n kind: \"none\",\n source: \"spec\",\n template: AuthTemplateSlug.make(\"none\"),\n placements: [],\n};\n\n// ---------------------------------------------------------------------------\n// OpenAPI Accounts hub: fills the generic detail page's `accounts` slot.\n//\n// Reads the integration's real `authenticationTemplate` (via `getConfig`),\n// converts it to generic `AuthMethod[]`, and composes the generic\n// `AccountsSection`, whose Add-account offers those methods plus a \"+ Custom\n// method\" row (apiKey-only). The custom-method create is INJECTED here\n// (`createCustomMethod`): generic placements → an `APIKeyAuthentication`\n// (`templateFromPlacements`, slug omitted → backend `custom_<id>`) merge-\n// appended onto the existing template and persisted via `configure`. Stays\n// plugin-side because it touches the OpenAPI sdk `Authentication` types.\n// ---------------------------------------------------------------------------\n\nexport default function OpenApiAccountsPanel(props: {\n readonly integrationId: string;\n readonly integrationName: string;\n readonly accountHandoff?: IntegrationAccountHandoff | null;\n}) {\n const { integrationId, integrationName, accountHandoff } = props;\n const slug = IntegrationSlug.make(integrationId);\n const configResult = useAtomValue(openApiConfigAtom(slug));\n const doConfigure = useAtomSet(openapiConfigure, { mode: \"promiseExit\" });\n\n // The wire `getConfig` template is structurally an `Authentication[]` (the\n // `slug` is an unbranded string on the wire); treat it as such for the\n // plugin-side converters that brand the slug back.\n const existingTemplate = useMemo<readonly Authentication[]>(() => {\n if (!AsyncResult.isSuccess(configResult) || configResult.value == null) return [];\n return (configResult.value.authenticationTemplate ?? []) as readonly Authentication[];\n }, [configResult]);\n\n const methods = useMemo<readonly AuthMethod[]>(() => {\n const declared = authMethodsFromConfig(existingTemplate);\n return declared.length > 0 ? declared : [NO_AUTH_METHOD];\n }, [existingTemplate]);\n\n // Custom-method create/remove: the shared skeleton (merge-append → diff out\n // the created method; filter → replace) parameterized by the OpenAPI codec.\n // Stays plugin-side only where it touches the OpenAPI `Authentication` types.\n const configure = useCallback<ConfigureAuthMethods<Authentication>>(\n async (input) => {\n const exit = await doConfigure({\n params: { slug },\n payload: {\n authenticationTemplate: input.authenticationTemplate.map(openApiWireAuthInput),\n ...(input.mode ? { mode: input.mode } : {}),\n },\n reactivityKeys: integrationWriteKeys,\n });\n return Exit.map(exit, (result) => result.authenticationTemplate as readonly Authentication[]);\n },\n [doConfigure, slug],\n );\n\n const codec = useMemo<AuthMethodsCodec<Authentication>>(\n () => ({\n toAuthMethods: authMethodsFromConfig,\n // Slug omitted → backend backfills `custom_<id>`.\n templatesFromPlacements: (placements: readonly Placement[]) => [\n templateFromPlacements(placements),\n ],\n slugOf: (template: Authentication) => String(template.slug),\n }),\n [],\n );\n\n const { createCustomMethod, removeCustomMethod } = useCustomMethodActions({\n existing: existingTemplate,\n codec,\n configure,\n });\n\n // Live-preview context for the health-check edit sheet: probe as the host's\n // default owner against the integration's API-key auth methods (the only kind\n // a pasted test key can validate). OAuth/none methods can't be previewed with\n // a key, so they're filtered out; with no apikey method the sheet hides the\n // preview block entirely.\n const organizationId = useOrganizationId();\n const livePreview = useMemo<HealthCheckLivePreview | undefined>(() => {\n const templates = methods\n .filter((m) => m.kind === \"apikey\")\n .map((m) => ({ template: m.template, label: m.label }));\n if (templates.length === 0) return undefined;\n return { owner: defaultConnectionOwnerForHost(organizationId), templates };\n }, [methods, organizationId]);\n\n return (\n <div className=\"mx-auto max-w-3xl space-y-8 px-6 py-8\">\n <AccountsSection\n integration={slug}\n integrationName={integrationName}\n methods={methods}\n accountHandoff={accountHandoff}\n createCustomMethod={createCustomMethod}\n removeCustomMethod={removeCustomMethod}\n />\n <HealthCheckEditor integration={slug} livePreview={livePreview} />\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;AAAA,SAAS,aAAa,eAAe;AACrC,SAAS,cAAc,kBAAkB;AACzC,YAAY,UAAU;AACtB,YAAY,iBAAiB;AAC7B,SAAS,kBAAkB,uBAAuB;AAGlD,SAAS,uBAAuB;AAChC;AAAA,EACE;AAAA,OAEK;AACP,SAAS,4BAA4B;AACrC,SAAS,yBAAyB;AAClC,SAAS,qCAAqC;AAE9C;AAAA,EACE;AAAA,OAGK;AA0GH,SACE,KADF;AAhGJ,IAAM,iBAA6B;AAAA,EACjC,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,UAAU,iBAAiB,KAAK,MAAM;AAAA,EACtC,YAAY,CAAC;AACf;AAee,SAAR,qBAAsC,OAI1C;AACD,QAAM,EAAE,eAAe,iBAAiB,eAAe,IAAI;AAC3D,QAAM,OAAO,gBAAgB,KAAK,aAAa;AAC/C,QAAM,eAAe,aAAa,kBAAkB,IAAI,CAAC;AACzD,QAAM,cAAc,WAAW,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAKxE,QAAM,mBAAmB,QAAmC,MAAM;AAChE,QAAI,CAAa,sBAAU,YAAY,KAAK,aAAa,SAAS,KAAM,QAAO,CAAC;AAChF,WAAQ,aAAa,MAAM,0BAA0B,CAAC;AAAA,EACxD,GAAG,CAAC,YAAY,CAAC;AAEjB,QAAM,UAAU,QAA+B,MAAM;AACnD,UAAM,WAAW,sBAAsB,gBAAgB;AACvD,WAAO,SAAS,SAAS,IAAI,WAAW,CAAC,cAAc;AAAA,EACzD,GAAG,CAAC,gBAAgB,CAAC;AAKrB,QAAM,YAAY;AAAA,IAChB,OAAO,UAAU;AACf,YAAM,OAAO,MAAM,YAAY;AAAA,QAC7B,QAAQ,EAAE,KAAK;AAAA,QACf,SAAS;AAAA,UACP,wBAAwB,MAAM,uBAAuB,IAAI,oBAAoB;AAAA,UAC7E,GAAI,MAAM,OAAO,EAAE,MAAM,MAAM,KAAK,IAAI,CAAC;AAAA,QAC3C;AAAA,QACA,gBAAgB;AAAA,MAClB,CAAC;AACD,aAAY,SAAI,MAAM,CAAC,WAAW,OAAO,sBAAmD;AAAA,IAC9F;AAAA,IACA,CAAC,aAAa,IAAI;AAAA,EACpB;AAEA,QAAM,QAAQ;AAAA,IACZ,OAAO;AAAA,MACL,eAAe;AAAA;AAAA,MAEf,yBAAyB,CAAC,eAAqC;AAAA,QAC7D,uBAAuB,UAAU;AAAA,MACnC;AAAA,MACA,QAAQ,CAAC,aAA6B,OAAO,SAAS,IAAI;AAAA,IAC5D;AAAA,IACA,CAAC;AAAA,EACH;AAEA,QAAM,EAAE,oBAAoB,mBAAmB,IAAI,uBAAuB;AAAA,IACxE,UAAU;AAAA,IACV;AAAA,IACA;AAAA,EACF,CAAC;AAOD,QAAM,iBAAiB,kBAAkB;AACzC,QAAM,cAAc,QAA4C,MAAM;AACpE,UAAM,YAAY,QACf,OAAO,CAAC,MAAM,EAAE,SAAS,QAAQ,EACjC,IAAI,CAAC,OAAO,EAAE,UAAU,EAAE,UAAU,OAAO,EAAE,MAAM,EAAE;AACxD,QAAI,UAAU,WAAW,EAAG,QAAO;AACnC,WAAO,EAAE,OAAO,8BAA8B,cAAc,GAAG,UAAU;AAAA,EAC3E,GAAG,CAAC,SAAS,cAAc,CAAC;AAE5B,SACE,qBAAC,SAAI,WAAU,yCACb;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,aAAa;AAAA,QACb;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA;AAAA,IACF;AAAA,IACA,oBAAC,qBAAkB,aAAa,MAAM,aAA0B;AAAA,KAClE;AAEJ;","names":[]}
@@ -0,0 +1,106 @@
1
+ import {
2
+ openApiConfigAtom,
3
+ updateOpenApiSpec
4
+ } from "./chunk-6V45G2XQ.js";
5
+ import "./chunk-HTHEUUJA.js";
6
+ import "./chunk-R7TVM3XD.js";
7
+ import "./chunk-CXFO6TLJ.js";
8
+
9
+ // src/react/UpdateSpecSection.tsx
10
+ import { useCallback, useEffect, useRef, useState } from "react";
11
+ import { useAtomSet, useAtomValue } from "@effect/atom-react";
12
+ import * as AsyncResult from "effect/unstable/reactivity/AsyncResult";
13
+ import * as Exit from "effect/Exit";
14
+ import { integrationWriteKeys } from "@rafads/react/api/reactivity-keys";
15
+ import { messageFromExit } from "@rafads/react/api/error-reporting";
16
+ import { FormErrorAlert } from "@rafads/react/lib/integration-add";
17
+ import { IntegrationSlug } from "@rafads/sdk/shared";
18
+ import { Checkbox } from "@rafads/react/components/checkbox";
19
+ import { Label } from "@rafads/react/components/label";
20
+ import { Textarea } from "@rafads/react/components/textarea";
21
+ import { jsx, jsxs } from "react/jsx-runtime";
22
+ var outcomeSummary = (outcome) => {
23
+ const added = outcome.addedTools.length;
24
+ const removed = outcome.removedTools.length;
25
+ if (added === 0 && removed === 0) {
26
+ return `Spec updated \u2014 ${outcome.toolCount} tools, no changes to the tool list.`;
27
+ }
28
+ const parts = [
29
+ ...added > 0 ? [`+${added} tool${added !== 1 ? "s" : ""}`] : [],
30
+ ...removed > 0 ? [`\u2212${removed} tool${removed !== 1 ? "s" : ""}`] : []
31
+ ];
32
+ return `Spec updated \u2014 ${parts.join(", ")} (${outcome.toolCount} total).`;
33
+ };
34
+ function UpdateSpecSection(props) {
35
+ const slug = IntegrationSlug.make(props.integrationId);
36
+ const configResult = useAtomValue(openApiConfigAtom(slug));
37
+ const doUpdate = useAtomSet(updateOpenApiSpec, { mode: "promiseExit" });
38
+ const [refetchStaged, setRefetchStaged] = useState(false);
39
+ const [pasted, setPasted] = useState("");
40
+ const [error, setError] = useState(null);
41
+ const config = AsyncResult.isSuccess(configResult) && configResult.value ? configResult.value : null;
42
+ const specUrl = config?.specUrl;
43
+ const applyStaged = useCallback(async () => {
44
+ const spec = pasted.trim().length > 0 ? { kind: "blob", value: pasted } : void 0;
45
+ if (!spec && !refetchStaged) return { ok: true, summary: null };
46
+ setError(null);
47
+ const exit = await doUpdate({
48
+ params: { slug },
49
+ payload: spec ? { spec } : {},
50
+ reactivityKeys: integrationWriteKeys
51
+ });
52
+ if (Exit.isFailure(exit)) {
53
+ setError(messageFromExit(exit, "Failed to update spec"));
54
+ return { ok: false };
55
+ }
56
+ setRefetchStaged(false);
57
+ setPasted("");
58
+ return { ok: true, summary: outcomeSummary(exit.value) };
59
+ }, [doUpdate, pasted, refetchStaged, slug]);
60
+ const onPendingChangeRef = useRef(props.onPendingChange);
61
+ onPendingChangeRef.current = props.onPendingChange;
62
+ const hasStagedChange = refetchStaged || pasted.trim().length > 0;
63
+ useEffect(() => {
64
+ onPendingChangeRef.current?.(hasStagedChange ? applyStaged : null);
65
+ return () => onPendingChangeRef.current?.(null);
66
+ }, [hasStagedChange, applyStaged]);
67
+ if (!config) return null;
68
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-3 border-t border-border/60 pt-5", children: [
69
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
70
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-foreground", children: "Update spec" }),
71
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: "Rebuild this integration's tools from the latest spec when you save. Connections, credentials, and policies are kept." })
72
+ ] }),
73
+ specUrl ? /* @__PURE__ */ jsx("div", { className: "space-y-2", children: /* @__PURE__ */ jsxs(Label, { className: "flex items-start gap-2 text-sm font-normal", children: [
74
+ /* @__PURE__ */ jsx(
75
+ Checkbox,
76
+ {
77
+ checked: refetchStaged,
78
+ onCheckedChange: (checked) => setRefetchStaged(checked === true)
79
+ }
80
+ ),
81
+ /* @__PURE__ */ jsxs("span", { className: "space-y-0.5", children: [
82
+ /* @__PURE__ */ jsx("span", { className: "block", children: "Re-fetch the spec on save" }),
83
+ /* @__PURE__ */ jsx("span", { className: "block break-all font-mono text-xs text-muted-foreground", children: specUrl })
84
+ ] })
85
+ ] }) }) : /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
86
+ /* @__PURE__ */ jsx(Label, { htmlFor: "update-spec-content", className: "text-xs text-muted-foreground", children: "Updated spec content" }),
87
+ /* @__PURE__ */ jsx(
88
+ Textarea,
89
+ {
90
+ id: "update-spec-content",
91
+ value: pasted,
92
+ onChange: (e) => setPasted(e.target.value),
93
+ placeholder: "Paste the updated OpenAPI JSON/YAML \u2014 applied when you save. This spec was added inline, so there is no URL to re-fetch.",
94
+ rows: 4,
95
+ maxRows: 10,
96
+ className: "font-mono text-xs"
97
+ }
98
+ )
99
+ ] }),
100
+ error && /* @__PURE__ */ jsx(FormErrorAlert, { message: error })
101
+ ] });
102
+ }
103
+ export {
104
+ UpdateSpecSection as default
105
+ };
106
+ //# sourceMappingURL=UpdateSpecSection-KUSNI44Q.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/react/UpdateSpecSection.tsx"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from \"react\";\nimport { useAtomSet, useAtomValue } from \"@effect/atom-react\";\nimport * as AsyncResult from \"effect/unstable/reactivity/AsyncResult\";\nimport * as Exit from \"effect/Exit\";\n\nimport { integrationWriteKeys } from \"@rafads/react/api/reactivity-keys\";\nimport { messageFromExit } from \"@rafads/react/api/error-reporting\";\nimport { FormErrorAlert } from \"@rafads/react/lib/integration-add\";\nimport { IntegrationSlug } from \"@rafads/sdk/shared\";\nimport type { EditSheetApplyResult, EditSheetSectionProps } from \"@rafads/sdk/client\";\nimport { Checkbox } from \"@rafads/react/components/checkbox\";\nimport { Label } from \"@rafads/react/components/label\";\nimport { Textarea } from \"@rafads/react/components/textarea\";\n\nimport { openApiConfigAtom, updateOpenApiSpec } from \"./atoms\";\n\n// ---------------------------------------------------------------------------\n// Update spec — the openapi plugin's section of the integration Edit sheet.\n// The user STAGES a spec update here (check re-fetch, or paste new content);\n// nothing runs until the sheet's Save. The staged apply re-resolves the spec\n// and rebuilds the tool catalog in place — connections, credentials, policies,\n// and the curated description all survive.\n// ---------------------------------------------------------------------------\n\ntype UpdateOutcome = {\n readonly toolCount: number;\n readonly addedTools: readonly string[];\n readonly removedTools: readonly string[];\n};\n\nconst outcomeSummary = (outcome: UpdateOutcome): string => {\n const added = outcome.addedTools.length;\n const removed = outcome.removedTools.length;\n if (added === 0 && removed === 0) {\n return `Spec updated — ${outcome.toolCount} tools, no changes to the tool list.`;\n }\n const parts = [\n ...(added > 0 ? [`+${added} tool${added !== 1 ? \"s\" : \"\"}`] : []),\n ...(removed > 0 ? [`−${removed} tool${removed !== 1 ? \"s\" : \"\"}`] : []),\n ];\n return `Spec updated — ${parts.join(\", \")} (${outcome.toolCount} total).`;\n};\n\nexport default function UpdateSpecSection(props: EditSheetSectionProps) {\n const slug = IntegrationSlug.make(props.integrationId);\n const configResult = useAtomValue(openApiConfigAtom(slug));\n const doUpdate = useAtomSet(updateOpenApiSpec, { mode: \"promiseExit\" });\n const [refetchStaged, setRefetchStaged] = useState(false);\n const [pasted, setPasted] = useState(\"\");\n const [error, setError] = useState<string | null>(null);\n\n const config =\n AsyncResult.isSuccess(configResult) && configResult.value ? configResult.value : null;\n\n const specUrl = config?.specUrl;\n\n // The staged apply, rebuilt whenever the staged inputs change. Reported to\n // the sheet through a ref-stable callback so Save can run it.\n const applyStaged = useCallback(async (): Promise<EditSheetApplyResult> => {\n const spec = pasted.trim().length > 0 ? { kind: \"blob\" as const, value: pasted } : undefined;\n if (!spec && !refetchStaged) return { ok: true, summary: null };\n setError(null);\n const exit = await doUpdate({\n params: { slug },\n payload: spec ? { spec } : {},\n reactivityKeys: integrationWriteKeys,\n });\n if (Exit.isFailure(exit)) {\n setError(messageFromExit(exit, \"Failed to update spec\"));\n return { ok: false };\n }\n setRefetchStaged(false);\n setPasted(\"\");\n return { ok: true, summary: outcomeSummary(exit.value) };\n }, [doUpdate, pasted, refetchStaged, slug]);\n\n const onPendingChangeRef = useRef(props.onPendingChange);\n onPendingChangeRef.current = props.onPendingChange;\n const hasStagedChange = refetchStaged || pasted.trim().length > 0;\n useEffect(() => {\n onPendingChangeRef.current?.(hasStagedChange ? applyStaged : null);\n // Clear the staged apply if this section unmounts mid-edit.\n return () => onPendingChangeRef.current?.(null);\n }, [hasStagedChange, applyStaged]);\n\n if (!config) return null;\n\n return (\n <div className=\"space-y-3 border-t border-border/60 pt-5\">\n <div className=\"space-y-1\">\n <p className=\"text-sm font-medium text-foreground\">Update spec</p>\n <p className=\"text-xs text-muted-foreground\">\n Rebuild this integration's tools from the latest spec when you save. Connections,\n credentials, and policies are kept.\n </p>\n </div>\n\n {specUrl ? (\n <div className=\"space-y-2\">\n <Label className=\"flex items-start gap-2 text-sm font-normal\">\n <Checkbox\n checked={refetchStaged}\n onCheckedChange={(checked: boolean | \"indeterminate\") =>\n setRefetchStaged(checked === true)\n }\n />\n <span className=\"space-y-0.5\">\n <span className=\"block\">Re-fetch the spec on save</span>\n <span className=\"block break-all font-mono text-xs text-muted-foreground\">\n {specUrl}\n </span>\n </span>\n </Label>\n </div>\n ) : (\n <div className=\"space-y-2\">\n <Label htmlFor=\"update-spec-content\" className=\"text-xs text-muted-foreground\">\n Updated spec content\n </Label>\n <Textarea\n id=\"update-spec-content\"\n value={pasted}\n onChange={(e: React.ChangeEvent<HTMLTextAreaElement>) => setPasted(e.target.value)}\n placeholder=\"Paste the updated OpenAPI JSON/YAML — applied when you save. This spec was added inline, so there is no URL to re-fetch.\"\n rows={4}\n maxRows={10}\n className=\"font-mono text-xs\"\n />\n </div>\n )}\n\n {error && <FormErrorAlert message={error} />}\n </div>\n );\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,239 @@
1
+ import { HttpApiEndpoint, HttpApiGroup } from "effect/unstable/httpapi";
2
+ import { Schema } from "effect";
3
+ import { InternalError, IntegrationAlreadyExistsError, IntegrationNotFoundError } from "@rafads/sdk/shared";
4
+ import { OpenApiParseError, OpenApiExtractionError, OpenApiOAuthError } from "../sdk/errors";
5
+ export declare const OpenApiGroup: HttpApiGroup.HttpApiGroup<"openapi", HttpApiEndpoint.HttpApiEndpoint<"previewSpec", "POST", "/openapi/preview", HttpApiEndpoint.StringTree<never>, HttpApiEndpoint.StringTree<never>, HttpApiEndpoint.Json<Schema.Struct<{
6
+ readonly spec: Schema.String;
7
+ readonly specFormat: Schema.optional<Schema.String>;
8
+ }>>, HttpApiEndpoint.StringTree<never>, HttpApiEndpoint.Json<Schema.Struct<{
9
+ readonly title: Schema.OptionFromOptional<Schema.String>;
10
+ readonly description: Schema.OptionFromOptional<Schema.String>;
11
+ readonly version: Schema.OptionFromOptional<Schema.String>;
12
+ readonly servers: Schema.$Array<Schema.Struct<{
13
+ readonly url: Schema.String;
14
+ readonly description: Schema.OptionFromOptional<Schema.String>;
15
+ readonly variables: Schema.OptionFromOptional<Schema.$Record<Schema.String, Schema.Struct<{
16
+ readonly default: Schema.String;
17
+ readonly enum: Schema.OptionFromOptional<Schema.$Array<Schema.String>>;
18
+ readonly description: Schema.OptionFromOptional<Schema.String>;
19
+ }>>>;
20
+ }>>;
21
+ readonly operationCount: Schema.Number;
22
+ readonly tags: Schema.$Array<Schema.String>;
23
+ readonly securitySchemes: Schema.$Array<Schema.Struct<{
24
+ readonly name: Schema.String;
25
+ readonly type: Schema.Literals<readonly ["http", "apiKey", "oauth2", "openIdConnect"]>;
26
+ readonly scheme: Schema.OptionFromOptional<Schema.String>;
27
+ readonly bearerFormat: Schema.OptionFromOptional<Schema.String>;
28
+ readonly in: Schema.OptionFromOptional<Schema.Literals<readonly ["header", "query", "cookie"]>>;
29
+ readonly headerName: Schema.OptionFromOptional<Schema.String>;
30
+ readonly description: Schema.OptionFromOptional<Schema.String>;
31
+ readonly flows: Schema.OptionFromOptional<Schema.Struct<{
32
+ readonly authorizationCode: Schema.OptionFromOptional<Schema.Struct<{
33
+ readonly authorizationUrl: Schema.String;
34
+ readonly tokenUrl: Schema.String;
35
+ readonly refreshUrl: Schema.OptionFromOptional<Schema.String>;
36
+ readonly scopes: Schema.$Record<Schema.String, Schema.String>;
37
+ }>>;
38
+ readonly clientCredentials: Schema.OptionFromOptional<Schema.Struct<{
39
+ readonly tokenUrl: Schema.String;
40
+ readonly refreshUrl: Schema.OptionFromOptional<Schema.String>;
41
+ readonly scopes: Schema.$Record<Schema.String, Schema.String>;
42
+ }>>;
43
+ }>>;
44
+ readonly openIdConnectUrl: Schema.OptionFromOptional<Schema.String>;
45
+ }>>;
46
+ readonly authStrategies: Schema.$Array<Schema.Struct<{
47
+ readonly schemes: Schema.$Array<Schema.String>;
48
+ }>>;
49
+ readonly headerPresets: Schema.$Array<Schema.Struct<{
50
+ readonly label: Schema.String;
51
+ readonly headers: Schema.$Record<Schema.String, Schema.NullOr<Schema.String>>;
52
+ readonly secretHeaders: Schema.$Array<Schema.String>;
53
+ }>>;
54
+ readonly oauth2Presets: Schema.$Array<Schema.Struct<{
55
+ readonly label: Schema.String;
56
+ readonly securitySchemeName: Schema.String;
57
+ readonly flow: Schema.Literals<readonly ["authorizationCode", "clientCredentials"]>;
58
+ readonly authorizationUrl: Schema.OptionFromOptional<Schema.String>;
59
+ readonly tokenUrl: Schema.String;
60
+ readonly resource: Schema.OptionFromOptional<Schema.String>;
61
+ readonly refreshUrl: Schema.OptionFromOptional<Schema.String>;
62
+ readonly scopes: Schema.$Record<Schema.String, Schema.String>;
63
+ readonly identityScopes: Schema.Union<readonly [Schema.Literal<"auto">, Schema.Literal<false>, Schema.$Array<Schema.String>]>;
64
+ readonly supportsClientIdMetadataDocument: Schema.optional<Schema.Boolean>;
65
+ }>>;
66
+ readonly healthCheckCandidates: Schema.$Array<Schema.Struct<{
67
+ readonly operation: Schema.String;
68
+ readonly method: Schema.String;
69
+ readonly requiredArgCount: Schema.Number;
70
+ readonly destructive: Schema.Boolean;
71
+ readonly summary: Schema.optional<Schema.String>;
72
+ readonly parameters: Schema.optional<Schema.$Array<Schema.Struct<{
73
+ readonly name: Schema.String;
74
+ readonly location: Schema.String;
75
+ readonly required: Schema.Boolean;
76
+ readonly description: Schema.optional<Schema.String>;
77
+ }>>>;
78
+ readonly responseFields: Schema.optional<Schema.$Array<Schema.Struct<{
79
+ readonly path: Schema.String;
80
+ readonly type: Schema.String;
81
+ }>>>;
82
+ }>>;
83
+ }>>, HttpApiEndpoint.Json<typeof IntegrationAlreadyExistsError | typeof InternalError | typeof OpenApiParseError | typeof OpenApiExtractionError | typeof OpenApiOAuthError>, never, never> | HttpApiEndpoint.HttpApiEndpoint<"addSpec", "POST", "/openapi/specs", HttpApiEndpoint.StringTree<never>, HttpApiEndpoint.StringTree<never>, HttpApiEndpoint.Json<Schema.Struct<{
84
+ readonly spec: Schema.Union<readonly [Schema.Struct<{
85
+ readonly kind: Schema.Literal<"url">;
86
+ readonly url: Schema.String;
87
+ }>, Schema.Struct<{
88
+ readonly kind: Schema.Literal<"blob">;
89
+ readonly value: Schema.String;
90
+ }>]>;
91
+ readonly slug: Schema.optional<Schema.String>;
92
+ readonly name: Schema.optional<Schema.String>;
93
+ readonly description: Schema.optional<Schema.String>;
94
+ readonly baseUrl: Schema.optional<Schema.String>;
95
+ readonly headers: Schema.optional<Schema.$Record<Schema.String, Schema.String>>;
96
+ readonly queryParams: Schema.optional<Schema.$Record<Schema.String, Schema.String>>;
97
+ readonly specFormat: Schema.optional<Schema.String>;
98
+ readonly family: Schema.optional<Schema.String>;
99
+ readonly healthCheck: Schema.optional<Schema.Struct<{
100
+ readonly operation: Schema.String;
101
+ readonly args: Schema.optional<Schema.$Record<Schema.String, Schema.Unknown>>;
102
+ readonly identityField: Schema.optional<Schema.String>;
103
+ }>>;
104
+ readonly authenticationTemplate: Schema.optional<Schema.$Array<Schema.Union<readonly [Schema.Struct<{
105
+ readonly slug: Schema.String;
106
+ readonly kind: Schema.Literal<"oauth2">;
107
+ readonly authorizationUrl: Schema.String;
108
+ readonly tokenUrl: Schema.String;
109
+ readonly resource: Schema.optional<Schema.NullOr<Schema.String>>;
110
+ readonly scopes: Schema.$Array<Schema.String>;
111
+ readonly supportsClientIdMetadataDocument: Schema.optional<Schema.Boolean>;
112
+ }>, Schema.Struct<{
113
+ readonly slug: Schema.optional<Schema.String>;
114
+ readonly type: Schema.Literal<"apiKey">;
115
+ readonly label: Schema.optional<Schema.String>;
116
+ readonly headers: Schema.optional<Schema.$Record<Schema.String, Schema.Union<readonly [Schema.String, Schema.$Array<Schema.Union<readonly [Schema.String, Schema.Struct<{
117
+ readonly type: Schema.Literal<"variable">;
118
+ readonly name: Schema.String;
119
+ }>]>>]>>>;
120
+ readonly queryParams: Schema.optional<Schema.$Record<Schema.String, Schema.Union<readonly [Schema.String, Schema.$Array<Schema.Union<readonly [Schema.String, Schema.Struct<{
121
+ readonly type: Schema.Literal<"variable">;
122
+ readonly name: Schema.String;
123
+ }>]>>]>>>;
124
+ }>]>>>;
125
+ }>>, HttpApiEndpoint.StringTree<never>, HttpApiEndpoint.Json<Schema.Struct<{
126
+ readonly slug: Schema.brand<Schema.String, "IntegrationSlug">;
127
+ readonly toolCount: Schema.Number;
128
+ }>>, HttpApiEndpoint.Json<typeof IntegrationAlreadyExistsError | typeof InternalError | typeof OpenApiParseError | typeof OpenApiExtractionError | typeof OpenApiOAuthError>, never, never> | HttpApiEndpoint.HttpApiEndpoint<"getIntegration", "GET", "/openapi/integrations/:slug", HttpApiEndpoint.StringTree<Schema.Struct<{
129
+ slug: Schema.String;
130
+ }>>, HttpApiEndpoint.StringTree<never>, HttpApiEndpoint.StringTree<never>, HttpApiEndpoint.StringTree<never>, HttpApiEndpoint.Json<Schema.NullOr<Schema.Struct<{
131
+ readonly slug: Schema.brand<Schema.String, "IntegrationSlug">;
132
+ readonly description: Schema.String;
133
+ readonly kind: Schema.String;
134
+ readonly canRemove: Schema.Boolean;
135
+ readonly canRefresh: Schema.Boolean;
136
+ }>>>, HttpApiEndpoint.Json<typeof IntegrationAlreadyExistsError | typeof InternalError | typeof OpenApiParseError | typeof OpenApiExtractionError | typeof OpenApiOAuthError>, never, never> | HttpApiEndpoint.HttpApiEndpoint<"getConfig", "GET", "/openapi/integrations/:slug/config", HttpApiEndpoint.StringTree<Schema.Struct<{
137
+ slug: Schema.String;
138
+ }>>, HttpApiEndpoint.StringTree<never>, HttpApiEndpoint.StringTree<never>, HttpApiEndpoint.StringTree<never>, HttpApiEndpoint.Json<Schema.NullOr<Schema.Struct<{
139
+ readonly specUrl: Schema.optional<Schema.String>;
140
+ readonly baseUrl: Schema.optional<Schema.String>;
141
+ readonly headers: Schema.optional<Schema.$Record<Schema.String, Schema.String>>;
142
+ readonly queryParams: Schema.optional<Schema.$Record<Schema.String, Schema.String>>;
143
+ readonly authenticationTemplate: Schema.optional<Schema.$Array<Schema.Union<readonly [Schema.Struct<{
144
+ readonly slug: Schema.String;
145
+ readonly kind: Schema.Literal<"oauth2">;
146
+ readonly authorizationUrl: Schema.String;
147
+ readonly tokenUrl: Schema.String;
148
+ readonly resource: Schema.optional<Schema.NullOr<Schema.String>>;
149
+ readonly scopes: Schema.$Array<Schema.String>;
150
+ readonly supportsClientIdMetadataDocument: Schema.optional<Schema.Boolean>;
151
+ }>, Schema.Struct<{
152
+ readonly slug: Schema.String;
153
+ readonly kind: Schema.Literal<"apikey">;
154
+ readonly label: Schema.optional<Schema.String>;
155
+ readonly placements: Schema.$Array<Schema.Struct<{
156
+ readonly carrier: Schema.Literals<readonly ["header", "query"]>;
157
+ readonly name: Schema.String;
158
+ readonly prefix: Schema.optional<Schema.String>;
159
+ readonly variable: Schema.optional<Schema.String>;
160
+ readonly literal: Schema.optional<Schema.String>;
161
+ }>>;
162
+ }>]>>>;
163
+ }>>>, HttpApiEndpoint.Json<typeof IntegrationAlreadyExistsError | typeof InternalError | typeof OpenApiParseError | typeof OpenApiExtractionError | typeof OpenApiOAuthError>, never, never> | HttpApiEndpoint.HttpApiEndpoint<"configure", "POST", "/openapi/integrations/:slug/config", HttpApiEndpoint.StringTree<Schema.Struct<{
164
+ slug: Schema.String;
165
+ }>>, HttpApiEndpoint.StringTree<never>, HttpApiEndpoint.Json<Schema.Struct<{
166
+ readonly authenticationTemplate: Schema.optional<Schema.$Array<Schema.Union<readonly [Schema.Struct<{
167
+ readonly slug: Schema.String;
168
+ readonly kind: Schema.Literal<"oauth2">;
169
+ readonly authorizationUrl: Schema.String;
170
+ readonly tokenUrl: Schema.String;
171
+ readonly resource: Schema.optional<Schema.NullOr<Schema.String>>;
172
+ readonly scopes: Schema.$Array<Schema.String>;
173
+ readonly supportsClientIdMetadataDocument: Schema.optional<Schema.Boolean>;
174
+ }>, Schema.Struct<{
175
+ readonly slug: Schema.optional<Schema.String>;
176
+ readonly type: Schema.Literal<"apiKey">;
177
+ readonly label: Schema.optional<Schema.String>;
178
+ readonly headers: Schema.optional<Schema.$Record<Schema.String, Schema.Union<readonly [Schema.String, Schema.$Array<Schema.Union<readonly [Schema.String, Schema.Struct<{
179
+ readonly type: Schema.Literal<"variable">;
180
+ readonly name: Schema.String;
181
+ }>]>>]>>>;
182
+ readonly queryParams: Schema.optional<Schema.$Record<Schema.String, Schema.Union<readonly [Schema.String, Schema.$Array<Schema.Union<readonly [Schema.String, Schema.Struct<{
183
+ readonly type: Schema.Literal<"variable">;
184
+ readonly name: Schema.String;
185
+ }>]>>]>>>;
186
+ }>]>>>;
187
+ readonly mode: Schema.optional<Schema.Literals<readonly ["merge", "replace"]>>;
188
+ readonly baseUrl: Schema.optional<Schema.String>;
189
+ }>>, HttpApiEndpoint.StringTree<never>, HttpApiEndpoint.Json<Schema.Struct<{
190
+ readonly authenticationTemplate: Schema.$Array<Schema.Union<readonly [Schema.Struct<{
191
+ readonly slug: Schema.String;
192
+ readonly kind: Schema.Literal<"oauth2">;
193
+ readonly authorizationUrl: Schema.String;
194
+ readonly tokenUrl: Schema.String;
195
+ readonly resource: Schema.optional<Schema.NullOr<Schema.String>>;
196
+ readonly scopes: Schema.$Array<Schema.String>;
197
+ readonly supportsClientIdMetadataDocument: Schema.optional<Schema.Boolean>;
198
+ }>, Schema.Struct<{
199
+ readonly slug: Schema.String;
200
+ readonly kind: Schema.Literal<"apikey">;
201
+ readonly label: Schema.optional<Schema.String>;
202
+ readonly placements: Schema.$Array<Schema.Struct<{
203
+ readonly carrier: Schema.Literals<readonly ["header", "query"]>;
204
+ readonly name: Schema.String;
205
+ readonly prefix: Schema.optional<Schema.String>;
206
+ readonly variable: Schema.optional<Schema.String>;
207
+ readonly literal: Schema.optional<Schema.String>;
208
+ }>>;
209
+ }>]>>;
210
+ }>>, HttpApiEndpoint.Json<typeof IntegrationAlreadyExistsError | typeof InternalError | typeof OpenApiParseError | typeof OpenApiExtractionError | typeof OpenApiOAuthError>, never, never> | HttpApiEndpoint.HttpApiEndpoint<"updateSpec", "POST", "/openapi/integrations/:slug/spec", HttpApiEndpoint.StringTree<Schema.Struct<{
211
+ slug: Schema.String;
212
+ }>>, HttpApiEndpoint.StringTree<never>, HttpApiEndpoint.Json<Schema.Struct<{
213
+ readonly spec: Schema.optional<Schema.Union<readonly [Schema.Struct<{
214
+ readonly kind: Schema.Literal<"url">;
215
+ readonly url: Schema.String;
216
+ }>, Schema.Struct<{
217
+ readonly kind: Schema.Literal<"blob">;
218
+ readonly value: Schema.String;
219
+ }>]>>;
220
+ }>>, HttpApiEndpoint.StringTree<never>, HttpApiEndpoint.Json<Schema.Struct<{
221
+ readonly slug: Schema.brand<Schema.String, "IntegrationSlug">;
222
+ readonly toolCount: Schema.Number;
223
+ /** Tool names new in this spec version (same diff for every connection). */
224
+ readonly addedTools: Schema.$Array<Schema.String>;
225
+ /** Tool names the new spec no longer defines. */
226
+ readonly removedTools: Schema.$Array<Schema.String>;
227
+ }>>, HttpApiEndpoint.Json<Schema.decodeTo<Schema.declareConstructor<IntegrationNotFoundError, {
228
+ readonly _tag: "IntegrationNotFoundError";
229
+ readonly slug: string;
230
+ }, readonly [Schema.TaggedStruct<"IntegrationNotFoundError", {
231
+ readonly slug: Schema.brand<Schema.String, "IntegrationSlug">;
232
+ }>], {
233
+ readonly _tag: "IntegrationNotFoundError";
234
+ readonly slug: string & import("effect/Brand").Brand<"IntegrationSlug">;
235
+ }>, Schema.TaggedStruct<"IntegrationNotFoundError", {
236
+ readonly slug: Schema.brand<Schema.String, "IntegrationSlug">;
237
+ }>, never, never> | typeof InternalError | typeof OpenApiParseError | typeof OpenApiExtractionError | typeof OpenApiOAuthError>, never, never> | HttpApiEndpoint.HttpApiEndpoint<"removeSpec", "DELETE", "/openapi/integrations/:slug", HttpApiEndpoint.StringTree<Schema.Struct<{
238
+ slug: Schema.String;
239
+ }>>, HttpApiEndpoint.StringTree<never>, HttpApiEndpoint.Json<never>, HttpApiEndpoint.StringTree<never>, HttpApiEndpoint.Json<Schema.Void>, HttpApiEndpoint.Json<typeof IntegrationAlreadyExistsError | typeof InternalError | typeof OpenApiParseError | typeof OpenApiExtractionError | typeof OpenApiOAuthError>, never, never>, false>;
@@ -0,0 +1,7 @@
1
+ import { Context } from "effect";
2
+ import type { OpenApiPluginExtension } from "../sdk/plugin";
3
+ declare const OpenApiExtensionService_base: Context.ServiceClass<OpenApiExtensionService, "OpenApiExtensionService", OpenApiPluginExtension>;
4
+ export declare class OpenApiExtensionService extends OpenApiExtensionService_base {
5
+ }
6
+ export declare const OpenApiHandlers: import("effect/Layer").Layer<import("effect/unstable/httpapi/HttpApiGroup").ApiGroup<"executor", "openapi">, never, import("effect/unstable/http/HttpRouter").Request<"Requires", OpenApiExtensionService>>;
7
+ export {};