@executor-js/sdk 1.5.20 → 1.5.22

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 (43) hide show
  1. package/dist/{chunk-EJKXSREX.js → chunk-DN5AKD4U.js} +3 -1
  2. package/dist/chunk-DN5AKD4U.js.map +1 -0
  3. package/dist/{chunk-MYRPYTSV.js → chunk-GUZHNTDQ.js} +197 -57
  4. package/dist/chunk-GUZHNTDQ.js.map +1 -0
  5. package/dist/{chunk-PCSRC6WP.js → chunk-SNWDGE3G.js} +47 -17
  6. package/dist/chunk-SNWDGE3G.js.map +1 -0
  7. package/dist/client.d.ts +9 -1
  8. package/dist/client.d.ts.map +1 -1
  9. package/dist/client.js.map +1 -1
  10. package/dist/core.js +11 -5
  11. package/dist/core.js.map +1 -1
  12. package/dist/executor.d.ts +2 -0
  13. package/dist/executor.d.ts.map +1 -1
  14. package/dist/index.d.ts +3 -3
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +2 -2
  17. package/dist/integration.d.ts +4 -3
  18. package/dist/integration.d.ts.map +1 -1
  19. package/dist/oauth-callback-state.test.d.ts +2 -0
  20. package/dist/oauth-callback-state.test.d.ts.map +1 -0
  21. package/dist/oauth-service.d.ts +23 -13
  22. package/dist/oauth-service.d.ts.map +1 -1
  23. package/dist/oauth.d.ts +23 -0
  24. package/dist/oauth.d.ts.map +1 -1
  25. package/dist/plugin.d.ts +35 -1
  26. package/dist/plugin.d.ts.map +1 -1
  27. package/dist/server-connection.d.ts +1 -0
  28. package/dist/server-connection.d.ts.map +1 -1
  29. package/dist/shared.d.ts +2 -1
  30. package/dist/shared.d.ts.map +1 -1
  31. package/dist/shared.js +8 -2
  32. package/dist/test-config.d.ts +1 -0
  33. package/dist/test-config.d.ts.map +1 -1
  34. package/dist/testing/oauth-test-server.d.ts +3 -0
  35. package/dist/testing/oauth-test-server.d.ts.map +1 -1
  36. package/dist/testing.d.ts +1 -1
  37. package/dist/testing.d.ts.map +1 -1
  38. package/dist/testing.js +9 -3
  39. package/dist/testing.js.map +1 -1
  40. package/package.json +1 -1
  41. package/dist/chunk-EJKXSREX.js.map +0 -1
  42. package/dist/chunk-MYRPYTSV.js.map +0 -1
  43. package/dist/chunk-PCSRC6WP.js.map +0 -1
@@ -307,31 +307,57 @@ var OAuthSessionNotFoundError = class extends Schema4.TaggedErrorClass()(
307
307
  ) {
308
308
  };
309
309
 
310
+ // src/oauth.ts
311
+ import { Encoding, Option, Result, Schema as Schema5 } from "effect";
312
+ var OAUTH2_PROVIDER_KEY = "oauth2";
313
+ var OAUTH2_SESSION_TTL_MS = 15 * 60 * 1e3;
314
+ var OAuthCallbackStateSchema = Schema5.Struct({
315
+ state: Schema5.String,
316
+ orgSlug: Schema5.String
317
+ });
318
+ var OAuthCallbackStateFromJson = Schema5.fromJsonString(OAuthCallbackStateSchema);
319
+ var decodeOAuthCallbackStateJson = Schema5.decodeUnknownOption(OAuthCallbackStateFromJson);
320
+ var encodeOAuthCallbackStateJson = Schema5.encodeSync(OAuthCallbackStateFromJson);
321
+ var encodeOAuthCallbackState = (input) => {
322
+ const orgSlug = input.orgSlug?.trim();
323
+ if (!orgSlug) return input.state;
324
+ return Encoding.encodeBase64Url(encodeOAuthCallbackStateJson({ state: input.state, orgSlug }));
325
+ };
326
+ var decodeOAuthCallbackState = (value) => {
327
+ if (!value) return null;
328
+ const json = Result.getOrNull(Encoding.decodeBase64UrlString(value));
329
+ if (json === null) return null;
330
+ const decoded = Option.getOrNull(decodeOAuthCallbackStateJson(json));
331
+ if (decoded === null) return null;
332
+ const orgSlug = decoded.orgSlug.trim();
333
+ return orgSlug ? { state: decoded.state, orgSlug } : null;
334
+ };
335
+
310
336
  // src/types.ts
311
- import { Schema as Schema5 } from "effect";
312
- var ToolSchemaView = Schema5.Struct({
337
+ import { Schema as Schema6 } from "effect";
338
+ var ToolSchemaView = Schema6.Struct({
313
339
  address: ToolAddress,
314
- name: Schema5.optional(Schema5.String),
315
- description: Schema5.optional(Schema5.String),
316
- inputSchema: Schema5.optional(Schema5.Unknown),
317
- outputSchema: Schema5.optional(Schema5.Unknown),
318
- schemaDefinitions: Schema5.optional(Schema5.Record(Schema5.String, Schema5.Unknown)),
319
- inputTypeScript: Schema5.optional(Schema5.String),
320
- outputTypeScript: Schema5.optional(Schema5.String),
321
- typeScriptDefinitions: Schema5.optional(Schema5.Record(Schema5.String, Schema5.String))
340
+ name: Schema6.optional(Schema6.String),
341
+ description: Schema6.optional(Schema6.String),
342
+ inputSchema: Schema6.optional(Schema6.Unknown),
343
+ outputSchema: Schema6.optional(Schema6.Unknown),
344
+ schemaDefinitions: Schema6.optional(Schema6.Record(Schema6.String, Schema6.Unknown)),
345
+ inputTypeScript: Schema6.optional(Schema6.String),
346
+ outputTypeScript: Schema6.optional(Schema6.String),
347
+ typeScriptDefinitions: Schema6.optional(Schema6.Record(Schema6.String, Schema6.String))
322
348
  });
323
- var IntegrationDetectionResult = Schema5.Struct({
349
+ var IntegrationDetectionResult = Schema6.Struct({
324
350
  /** Plugin id that recognized the URL (e.g. "openapi", "graphql"). */
325
- kind: Schema5.String,
351
+ kind: Schema6.String,
326
352
  /** Confidence tier — UI uses this to pick a winner when multiple plugins
327
353
  * claim a URL. */
328
- confidence: Schema5.Literals(["high", "medium", "low"]),
354
+ confidence: Schema6.Literals(["high", "medium", "low"]),
329
355
  /** The (possibly normalized) endpoint the plugin will use. */
330
- endpoint: Schema5.String,
356
+ endpoint: Schema6.String,
331
357
  /** Human-readable name suggestion, typically derived from spec title or URL. */
332
- name: Schema5.String,
358
+ name: Schema6.String,
333
359
  /** Slug suggestion — the plugin's recommendation for the integration slug. */
334
- slug: Schema5.String
360
+ slug: Schema6.String
335
361
  });
336
362
 
337
363
  export {
@@ -364,7 +390,11 @@ export {
364
390
  OAuthProbeError,
365
391
  OAuthRegisterDynamicError,
366
392
  OAuthSessionNotFoundError,
393
+ OAUTH2_PROVIDER_KEY,
394
+ OAUTH2_SESSION_TTL_MS,
395
+ encodeOAuthCallbackState,
396
+ decodeOAuthCallbackState,
367
397
  ToolSchemaView,
368
398
  IntegrationDetectionResult
369
399
  };
370
- //# sourceMappingURL=chunk-PCSRC6WP.js.map
400
+ //# sourceMappingURL=chunk-SNWDGE3G.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/policies.ts","../src/elicitation.ts","../src/errors.ts","../src/oauth-client.ts","../src/oauth.ts","../src/types.ts"],"sourcesContent":["// ---------------------------------------------------------------------------\n// Tool policies — pattern matcher + policy resolution. Pure functions; the\n// executor stitches them into `tools.list`, `execute`, and the public\n// `executor.policies` CRUD surface. Plugins consume the same surface.\n//\n// v2: policies are owner-scoped (org | user) instead of scope-stacked. Each\n// owner contributes its first matching rule by local position; the final answer\n// is the most restrictive matched action across owners, so a user preference\n// cannot weaken an org guardrail (org = outer, user = inner).\n// ---------------------------------------------------------------------------\n\nimport { Match, Schema } from \"effect\";\n\nimport type { ToolPolicyAction, ToolPolicyRow } from \"./core-schema\";\nimport { Owner, PolicyId } from \"./ids\";\n\nexport interface ToolPolicy {\n readonly id: PolicyId;\n readonly owner: Owner;\n readonly pattern: string;\n readonly action: ToolPolicyAction;\n /** Fractional-indexing key. Lower lex order = higher precedence. */\n readonly position: string;\n readonly createdAt: Date;\n readonly updatedAt: Date;\n}\n\nexport interface CreateToolPolicyInput {\n readonly owner: Owner;\n readonly pattern: string;\n /** Optional explicit position. Defaults to a key above the current minimum\n * (top of the owner's list; highest precedence). */\n readonly action: ToolPolicyAction;\n readonly position?: string;\n}\n\nexport interface UpdateToolPolicyInput {\n readonly id: string;\n readonly owner: Owner;\n readonly pattern?: string;\n readonly action?: ToolPolicyAction;\n readonly position?: string;\n}\n\nexport interface RemoveToolPolicyInput {\n readonly id: string;\n readonly owner: Owner;\n}\n\n// ---------------------------------------------------------------------------\n// Match result.\n// ---------------------------------------------------------------------------\n\nexport interface PolicyMatch {\n readonly action: ToolPolicyAction;\n readonly pattern: string;\n readonly policyId: string;\n}\n\nexport type PolicySource = \"user\" | \"plugin-default\";\n\nexport interface EffectivePolicy {\n readonly action: ToolPolicyAction;\n readonly source: PolicySource;\n readonly pattern?: string;\n readonly policyId?: string;\n}\n\n// ---------------------------------------------------------------------------\n// Pattern matching. Grammar (matched against the full tool address\n// `<integration>.<owner>.<connection>.<tool>` or a shorter form the executor\n// passes in):\n// - universal: `*`\n// - exact: `vercel.dns.create`\n// - subtree (trailing `*`): `vercel.dns.*` — the literal prefix plus anything deeper\n// - plugin-wide: `vercel.*`\n// - mid-segment `*`: `vercel.*.*.dns.create` — each NON-trailing `*` matches\n// EXACTLY ONE segment (e.g. wildcard the owner/connection\n// segments to target a tool across every connection).\n// A `*` is always a complete segment: mid-pattern it consumes one segment,\n// trailing it is a subtree. Partial wildcards (`me*`) and a leading `*` (other\n// than the universal `*`) are rejected by `isValidPattern`.\n// ---------------------------------------------------------------------------\n\nexport const matchPattern = (pattern: string, toolId: string): boolean => {\n if (pattern === \"*\") return true;\n const patternSegments = pattern.split(\".\");\n const toolSegments = toolId.split(\".\");\n for (let i = 0; i < patternSegments.length; i++) {\n const seg = patternSegments[i]!;\n if (seg === \"*\") {\n // Trailing `*` is a subtree: the literal prefix already matched, so the\n // address matches at this position and anything deeper (or nothing).\n if (i === patternSegments.length - 1) return toolSegments.length >= i;\n // A non-trailing `*` consumes EXACTLY ONE segment; one must exist here.\n if (i >= toolSegments.length) return false;\n continue;\n }\n if (i >= toolSegments.length || toolSegments[i] !== seg) return false;\n }\n // Pattern exhausted with no trailing `*`: an exact match requires equal length.\n return patternSegments.length === toolSegments.length;\n};\n\nexport const isValidPattern = (pattern: string): boolean => {\n if (pattern.length === 0) return false;\n if (pattern === \"*\") return true;\n if (pattern.startsWith(\".\") || pattern.endsWith(\".\")) return false;\n if (pattern.includes(\"..\")) return false;\n if (pattern.startsWith(\"*\")) return false;\n const segments = pattern.split(\".\");\n for (let i = 0; i < segments.length; i++) {\n const seg = segments[i]!;\n if (seg.length === 0) return false;\n // A `*` segment must be the WHOLE segment — no partial wildcards (`me*`).\n // A `*` is valid mid-pattern (one segment) or trailing (subtree).\n if (seg.includes(\"*\") && seg !== \"*\") return false;\n }\n return true;\n};\n\n// ---------------------------------------------------------------------------\n// Resolution — each owner contributes its first matching rule by local\n// position; the most restrictive matched action across owners wins. Caller\n// passes an `ownerRank` so the resolver doesn't need to know which owner is\n// the outer guardrail.\n// ---------------------------------------------------------------------------\n\nexport const comparePolicyRow = (\n a: Pick<ToolPolicyRow, \"position\" | \"id\">,\n b: Pick<ToolPolicyRow, \"position\" | \"id\">,\n): number => {\n const pa = a.position;\n const pb = b.position;\n if (pa < pb) return -1;\n if (pa > pb) return 1;\n const ia = a.id;\n const ib = b.id;\n return ia < ib ? -1 : ia > ib ? 1 : 0;\n};\n\nconst actionRestrictionRank = (action: ToolPolicyAction): number =>\n Match.value(action).pipe(\n Match.when(\"block\", () => 3),\n Match.when(\"require_approval\", () => 2),\n Match.when(\"approve\", () => 1),\n Match.exhaustive,\n );\n\nconst moreRestrictive = <T extends { readonly action: ToolPolicyAction }>(\n current: T | undefined,\n candidate: T,\n): T => {\n if (!current) return candidate;\n const currentRank = actionRestrictionRank(current.action);\n const candidateRank = actionRestrictionRank(candidate.action);\n return candidateRank > currentRank ? candidate : current;\n};\n\nexport const resolveToolPolicy = (\n toolId: string,\n policies: readonly ToolPolicyRow[],\n ownerRank: (row: Pick<ToolPolicyRow, \"owner\">) => number,\n): PolicyMatch | undefined => {\n if (policies.length === 0) return undefined;\n const sorted = [...policies].sort((a, b) => {\n const sa = ownerRank(a);\n const sb = ownerRank(b);\n if (sa !== sb) return sa - sb;\n return comparePolicyRow(a, b);\n });\n const firstMatchByOwner = new Map<string, PolicyMatch>();\n for (const row of sorted) {\n if (firstMatchByOwner.has(row.owner)) continue;\n if (matchPattern(row.pattern, toolId)) {\n firstMatchByOwner.set(row.owner, {\n action: row.action as ToolPolicyAction,\n pattern: row.pattern,\n policyId: row.id,\n });\n }\n }\n let selected: PolicyMatch | undefined;\n for (const match of firstMatchByOwner.values()) {\n selected = moreRestrictive(selected, match);\n }\n return selected;\n};\n\n// ---------------------------------------------------------------------------\n// Layered resolution — user-authored rules + plugin default `requiresApproval`.\n// ---------------------------------------------------------------------------\n\nconst liftPlugin = (defaultRequiresApproval: boolean | undefined): EffectivePolicy =>\n defaultRequiresApproval\n ? { action: \"require_approval\", source: \"plugin-default\" }\n : { action: \"approve\", source: \"plugin-default\" };\n\nconst liftUser = (match: PolicyMatch): EffectivePolicy => ({\n action: match.action,\n source: \"user\",\n pattern: match.pattern,\n policyId: match.policyId,\n});\n\nexport const resolveEffectivePolicy = (\n toolId: string,\n policies: readonly ToolPolicyRow[],\n ownerRank: (row: Pick<ToolPolicyRow, \"owner\">) => number,\n defaultRequiresApproval?: boolean,\n): EffectivePolicy => {\n const match = resolveToolPolicy(toolId, policies, ownerRank);\n return match ? liftUser(match) : liftPlugin(defaultRequiresApproval);\n};\n\nexport const effectivePolicyFromSorted = (\n toolId: string,\n sortedPolicies: readonly (Pick<ToolPolicy, \"pattern\" | \"action\" | \"id\"> &\n Partial<Pick<ToolPolicy, \"owner\">>)[],\n defaultRequiresApproval?: boolean,\n): EffectivePolicy => {\n const firstMatchByOwner = new Map<string, EffectivePolicy>();\n for (const p of sortedPolicies) {\n const ownerKey = \"owner\" in p && p.owner ? String(p.owner) : \"__flat__\";\n if (firstMatchByOwner.has(ownerKey)) continue;\n if (matchPattern(p.pattern, toolId)) {\n firstMatchByOwner.set(ownerKey, {\n action: p.action,\n source: \"user\",\n pattern: p.pattern,\n policyId: p.id,\n });\n }\n }\n let selected: EffectivePolicy | undefined;\n for (const match of firstMatchByOwner.values()) {\n selected = moreRestrictive(selected, match);\n }\n return selected ?? liftPlugin(defaultRequiresApproval);\n};\n\n// ---------------------------------------------------------------------------\n// Row → public projection.\n// ---------------------------------------------------------------------------\n\nexport const rowToToolPolicy = (row: ToolPolicyRow): ToolPolicy => ({\n id: PolicyId.make(row.id),\n owner: row.owner as Owner,\n pattern: row.pattern,\n action: row.action as ToolPolicyAction,\n position: row.position,\n createdAt: row.created_at,\n updatedAt: row.updated_at,\n});\n\nexport const ToolPolicyActionSchema = Schema.Literals([\"approve\", \"require_approval\", \"block\"]);\n","import { Effect, Schema } from \"effect\";\n\nimport { ElicitationId, ToolAddress } from \"./ids\";\n\n/* A tool that needs user input mid-call suspends and the host's `onElicitation`\n * handler (executor-level, overridable per `execute`) answers. Tools that never\n * elicit never trigger it. Schema-tagged so requests/responses cross the wire. */\n\n/** Tool needs structured input from the user (render a form). */\nexport const FormElicitation = Schema.TaggedStruct(\"FormElicitation\", {\n message: Schema.String,\n /** JSON Schema describing the fields to collect. */\n requestedSchema: Schema.Record(Schema.String, Schema.Unknown),\n});\nexport type FormElicitation = typeof FormElicitation.Type;\n\n/** Tool needs the user to visit a URL (OAuth, approval page, etc.). */\nexport const UrlElicitation = Schema.TaggedStruct(\"UrlElicitation\", {\n message: Schema.String,\n url: Schema.String,\n /** Unique id so the host can correlate the callback. */\n elicitationId: ElicitationId,\n});\nexport type UrlElicitation = typeof UrlElicitation.Type;\n\nexport type ElicitationRequest = FormElicitation | UrlElicitation;\n\nexport const ElicitationAction = Schema.Literals([\"accept\", \"decline\", \"cancel\"]);\nexport type ElicitationAction = typeof ElicitationAction.Type;\n\nexport const ElicitationResponse = Schema.Struct({\n action: ElicitationAction,\n /** Present when `action` is \"accept\" — the data the user provided. */\n content: Schema.optional(Schema.Record(Schema.String, Schema.Unknown)),\n});\nexport type ElicitationResponse = typeof ElicitationResponse.Type;\n\n/** Handler input — the tool address being invoked, its args, and the request. */\nexport interface ElicitationContext {\n readonly address: ToolAddress;\n readonly args: unknown;\n readonly request: ElicitationRequest;\n}\n\n/** Host-provided handler the SDK calls when a tool suspends for input. */\nexport type ElicitationHandler = (ctx: ElicitationContext) => Effect.Effect<ElicitationResponse>;\n\n/** Executor-level elicitation policy: a handler, or `\"accept-all\"` to\n * auto-accept every request (tests / non-interactive hosts). */\nexport type OnElicitation = ElicitationHandler | \"accept-all\";\n\n/** Per-call options for `execute`. */\nexport interface InvokeOptions {\n /** Override the executor-level handler for this single call. */\n readonly onElicitation?: OnElicitation;\n}\n\n/** A tool was declined or cancelled during elicitation. */\nexport class ElicitationDeclinedError extends Schema.TaggedErrorClass<ElicitationDeclinedError>()(\n \"ElicitationDeclinedError\",\n {\n address: ToolAddress,\n action: Schema.Literals([\"decline\", \"cancel\"]),\n },\n) {\n // Derived message so telemetry (span status, logs) labels the failure\n // instead of rendering an Error with an empty message.\n override get message(): string {\n return `Tool approval ${this.action === \"cancel\" ? \"cancelled\" : \"declined\"}: ${this.address}`;\n }\n}\n","import { Schema } from \"effect\";\n\nimport { ElicitationDeclinedError } from \"./elicitation\";\nimport type { StorageFailure } from \"./fuma-runtime\";\nimport { ConnectionName, IntegrationSlug, Owner, ProviderKey, ToolAddress } from \"./ids\";\n\n/* The failure set the SDK surfaces. `execute`'s invoke failures are ported from\n * v1 but re-keyed by `address` (the full `tools.<integration>.<owner>.<connection>.<tool>`\n * handle) instead of an opaque tool id. Storage failures reuse fuma-runtime's\n * `StorageError`/`UniqueViolationError` (`StorageFailure`) — not redefined here. */\n\n// ---------------------------------------------------------------------------\n// Tool lifecycle\n// ---------------------------------------------------------------------------\n\n/* Tagged errors without an explicit `message` field define a `message` getter:\n * `Schema.TaggedErrorClass` instances are real Errors with `message: \"\"`, and\n * an empty message propagates everywhere errors are rendered — span\n * status.message in the tracer, Cause.pretty output, log lines — leaving the\n * failure unlabeled in telemetry. The getter is derived from the schema fields\n * (not an own property), so encoding/serialization is unaffected. */\n\nexport class ToolNotFoundError extends Schema.TaggedErrorClass<ToolNotFoundError>()(\n \"ToolNotFoundError\",\n {\n address: ToolAddress,\n suggestions: Schema.optional(Schema.Array(ToolAddress)),\n },\n) {\n override get message(): string {\n return `Tool not found: ${this.address}`;\n }\n}\n\nexport class ToolInvocationError extends Schema.TaggedErrorClass<ToolInvocationError>()(\n \"ToolInvocationError\",\n {\n address: ToolAddress,\n message: Schema.String,\n cause: Schema.optional(Schema.Unknown),\n },\n) {}\n\n/** Tool invocation was rejected because a workspace `tool_policy` rule with\n * `action: \"block\"` matched. `pattern` is the matched policy pattern. */\nexport class ToolBlockedError extends Schema.TaggedErrorClass<ToolBlockedError>()(\n \"ToolBlockedError\",\n {\n address: ToolAddress,\n pattern: Schema.String,\n },\n) {\n override get message(): string {\n return `Tool blocked by policy \"${this.pattern}\": ${this.address}`;\n }\n}\n\n/** Tool row exists but its owning plugin isn't loaded in this executor config. */\nexport class PluginNotLoadedError extends Schema.TaggedErrorClass<PluginNotLoadedError>()(\n \"PluginNotLoadedError\",\n {\n address: ToolAddress,\n pluginId: Schema.String,\n },\n) {\n override get message(): string {\n return `Plugin \"${this.pluginId}\" is not loaded for tool: ${this.address}`;\n }\n}\n\n/** Tool was found but its owning plugin has no `invokeTool` handler. */\nexport class NoHandlerError extends Schema.TaggedErrorClass<NoHandlerError>()(\"NoHandlerError\", {\n address: ToolAddress,\n pluginId: Schema.String,\n}) {\n override get message(): string {\n return `Plugin \"${this.pluginId}\" has no invokeTool handler for tool: ${this.address}`;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Integration / connection lifecycle\n// ---------------------------------------------------------------------------\n\nexport class IntegrationNotFoundError extends Schema.TaggedErrorClass<IntegrationNotFoundError>()(\n \"IntegrationNotFoundError\",\n { slug: IntegrationSlug },\n) {\n override get message(): string {\n return `Integration not found: ${this.slug}`;\n }\n}\n\n/** An \"add integration\" operation targeted a slug (namespace) that is already\n * registered. The core `integrations.register` primitive upserts by design\n * (for idempotent boot re-registration); add-operation layers gate on this to\n * prevent silently clobbering an existing integration's tools, connections,\n * and policies. */\nexport class IntegrationAlreadyExistsError extends Schema.TaggedErrorClass<IntegrationAlreadyExistsError>()(\n \"IntegrationAlreadyExistsError\",\n { slug: IntegrationSlug },\n { httpApiStatus: 409 },\n) {\n override get message(): string {\n return `Integration already exists: ${this.slug}`;\n }\n}\n\n/** `integrations.remove` was called on an integration declared statically by a\n * plugin at startup (`canRemove: false`). */\nexport class IntegrationRemovalNotAllowedError extends Schema.TaggedErrorClass<IntegrationRemovalNotAllowedError>()(\n \"IntegrationRemovalNotAllowedError\",\n { slug: IntegrationSlug },\n) {\n override get message(): string {\n return `Integration cannot be removed (declared statically by a plugin): ${this.slug}`;\n }\n}\n\nexport class ConnectionNotFoundError extends Schema.TaggedErrorClass<ConnectionNotFoundError>()(\n \"ConnectionNotFoundError\",\n {\n owner: Owner,\n integration: IntegrationSlug,\n name: ConnectionName,\n },\n) {\n override get message(): string {\n return `Connection not found: ${this.integration}.${this.owner}.${this.name}`;\n }\n}\n\n/** A connection create request was rejected before anything was written: the\n * input is structurally invalid (no credential inputs for a credentialed\n * template, mixed pasted/external origins, …) or targets owner `user` in a\n * context that has no user subject. The message says which — it is safe to\n * show to the caller. */\nexport class InvalidConnectionInputError extends Schema.TaggedErrorClass<InvalidConnectionInputError>()(\n \"InvalidConnectionInputError\",\n { message: Schema.String },\n) {}\n\n/** A connection references a credential provider key that isn't registered on\n * the executor. */\nexport class CredentialProviderNotRegisteredError extends Schema.TaggedErrorClass<CredentialProviderNotRegisteredError>()(\n \"CredentialProviderNotRegisteredError\",\n { provider: ProviderKey },\n) {\n override get message(): string {\n return `Credential provider not registered: ${this.provider}`;\n }\n}\n\n/** A connection's value could not be resolved — the provider returned nothing,\n * or an OAuth token refresh failed and the user must re-auth. */\nexport class CredentialResolutionError extends Schema.TaggedErrorClass<CredentialResolutionError>()(\n \"CredentialResolutionError\",\n {\n owner: Owner,\n integration: IntegrationSlug,\n name: ConnectionName,\n message: Schema.String,\n /** True when the stored grant is permanently invalid and the user must\n * sign in again (RFC 6749 §5.2 invalid_grant and friends). */\n reauthRequired: Schema.optional(Schema.Boolean),\n },\n) {}\n\n// ---------------------------------------------------------------------------\n// Union — the failure channel of `execute`.\n// ---------------------------------------------------------------------------\n\nexport type ExecuteError =\n | ToolNotFoundError\n | ToolInvocationError\n | ToolBlockedError\n | PluginNotLoadedError\n | NoHandlerError\n | ConnectionNotFoundError\n | CredentialProviderNotRegisteredError\n | CredentialResolutionError\n | ElicitationDeclinedError\n | StorageFailure;\n\n/** Convenience union spanning every typed error the SDK raises. */\nexport type ExecutorError =\n | ExecuteError\n | IntegrationNotFoundError\n | IntegrationRemovalNotAllowedError;\n","import type { Effect } from \"effect\";\nimport { Schema } from \"effect\";\n\nimport type { Connection } from \"./connection\";\nimport type { StorageFailure } from \"./fuma-runtime\";\nimport {\n type AuthTemplateSlug,\n type ConnectionName,\n type IntegrationSlug,\n OAuthClientSlug,\n OAuthState,\n type Owner,\n} from \"./ids\";\n\n/* The v2 OAuth surface contracts. OAuth is a credential mechanism, not an\n * integration type. A client is a registered app; running its flow mints a\n * Connection. The client is self-contained (carries its own endpoints) and\n * integration-independent, so the same app can back connections on whatever\n * integrations share that provider.\n *\n * The OAuth 2.1 *implementation* (PKCE, DCR, token exchange + refresh) lives in\n * `oauth-helpers` / `oauth-discovery` / `oauth-service`; these are the public\n * input/output shapes the executor's `oauth.*` namespace speaks. */\n\nexport type OAuthGrant = \"authorization_code\" | \"client_credentials\";\n\n/** Provider OAuth config an integration declares as one of its auth templates —\n * what to request. (The flow itself runs off the self-contained OAuthClient.)\n * Keyed `kind: \"oauth2\"` like every auth method across the plugins. */\nexport interface OAuthAuthentication {\n readonly slug: AuthTemplateSlug;\n readonly kind: \"oauth2\";\n readonly authorizationUrl: string;\n readonly tokenUrl: string;\n readonly scopes: readonly string[];\n}\n\n/** A registered OAuth app — pure app identity: clientId/secret + its endpoints.\n * Owner-scoped: a shared org app or a user's own BYO app. The app does NOT carry\n * scopes — what to request is the INTEGRATION's concern (`OAuthAuthentication.\n * scopes`, surfaced via the declared auth method), so the same app can back any\n * integration without pinning a scope set. */\nexport interface OAuthClient {\n readonly owner: Owner;\n readonly slug: OAuthClientSlug;\n readonly authorizationUrl: string;\n readonly tokenUrl: string;\n readonly grant: OAuthGrant;\n readonly clientId: string;\n /** The literal client secret. Stored out-of-band in the credential provider\n * (vault item id), never inline. Empty string for public / PKCE clients. */\n readonly clientSecret: string;\n /** RFC 8707 Resource Indicator (MCP). Carried so the refresh request can keep\n * the re-minted token bound to the same resource. Null/omitted otherwise. */\n readonly resource?: string | null;\n}\n\nexport type OAuthClientOrigin =\n | { readonly kind: \"manual\" }\n | {\n readonly kind: \"dynamic_client_registration\";\n readonly integration?: IntegrationSlug | null;\n };\n\nexport type CreateOAuthClientInput = OAuthClient & {\n readonly origin?: OAuthClientOrigin;\n};\n\n/** Metadata-only projection of a registered client for listing in the UI.\n * Deliberately omits `clientSecret` — the secret is never returned over the\n * read surface. `clientId` is included (it is not a secret; it is sent in the\n * authorize URL the user's browser visits). */\nexport interface OAuthClientSummary {\n readonly owner: Owner;\n readonly slug: OAuthClientSlug;\n readonly grant: OAuthGrant;\n readonly authorizationUrl: string;\n readonly tokenUrl: string;\n readonly resource?: string | null;\n readonly clientId: string;\n readonly origin: OAuthClientOrigin;\n}\n\n/** Flow-aware result of `oauth.start` — the status says what's next. */\nexport type ConnectResult =\n | { readonly status: \"connected\"; readonly connection: Connection }\n | {\n readonly status: \"redirect\";\n readonly authorizationUrl: string;\n readonly state: OAuthState;\n };\n\n/** Start a flow through a client to mint a connection for one integration.\n * `template` is the integration's oauth template the minted token is applied\n * through. */\nexport interface OAuthStartInput {\n readonly client: OAuthClientSlug;\n /** The owner that owns `client`. Supplied explicitly (the picker knows it), so\n * a Personal connection can be minted through a shared Workspace app without\n * any owner-derivation rule. A Workspace connection must use a Workspace app. */\n readonly clientOwner: Owner;\n /** The owner the minted CONNECTION is saved under (may differ from `clientOwner`). */\n readonly owner: Owner;\n readonly name: ConnectionName;\n readonly integration: IntegrationSlug;\n readonly template: AuthTemplateSlug;\n readonly identityLabel?: string | null;\n /** Browser-facing callback URL for this flow. Defaults to the executor's configured redirectUri. */\n readonly redirectUri?: string | null;\n}\n\nexport interface OAuthCompleteInput {\n readonly state: OAuthState;\n readonly code: string;\n /** Non-standard regional host the authorization server returns on the\n * callback (Datadog's `domain`/`site` params) so the code is redeemed at the\n * org's actual region rather than the statically advertised one. Used only\n * when it is a sibling subdomain of the client's configured token host. */\n readonly callbackDomain?: string | null;\n}\n\n/** Probe a base/issuer URL for OAuth 2.1 authorization-server metadata so the\n * onboarding UI can pre-fill a client's endpoints. */\nexport interface OAuthProbeInput {\n readonly url: string;\n}\n\nexport interface OAuthProbeResult {\n readonly authorizationUrl: string;\n readonly tokenUrl: string;\n /** RFC 8707 resource indicator discovered from protected-resource metadata.\n * Persist this on DCR clients so authorize/token/refresh requests stay bound\n * to the protected resource. */\n readonly resource?: string | null;\n readonly scopesSupported?: readonly string[];\n /** Whether the server advertises dynamic client registration (RFC 7591). */\n readonly registrationEndpoint?: string | null;\n /** RFC 8414 `token_endpoint_auth_methods_supported`. Surfaced so DCR can pick\n * a public (\"none\") client when the server allows it. */\n readonly tokenEndpointAuthMethodsSupported?: readonly string[];\n}\n\n/** Mint an OAuth client via RFC 7591 Dynamic Client Registration and persist it.\n * The user pastes NO client id/secret — the authorization server mints a\n * (public, PKCE) client which is stored as an owner-scoped `oauth_client`. */\nexport interface RegisterDynamicClientInput {\n readonly owner: Owner;\n readonly slug: OAuthClientSlug;\n /** RFC 7591 registration endpoint advertised by the authorization server. */\n readonly registrationEndpoint: string;\n readonly authorizationUrl: string;\n readonly tokenUrl: string;\n /** RFC 8707 Resource Indicator (MCP). Persisted on the minted client when known. */\n readonly resource?: string | null;\n readonly scopes: readonly string[];\n /** Auth methods the server advertises. When it allows `none` a public\n * (PKCE-only, no secret) client is registered; otherwise `client_secret_post`. */\n readonly tokenEndpointAuthMethodsSupported?: readonly string[];\n /** Human label for the registered app (RFC 7591 `client_name`). */\n readonly clientName?: string;\n /** Browser-facing callback URL to register. Defaults to the executor's configured redirectUri. */\n readonly redirectUri?: string | null;\n /** Integration that requested this dynamic client, when known. */\n readonly originIntegration?: IntegrationSlug | null;\n}\n\nexport class OAuthStartError extends Schema.TaggedErrorClass<OAuthStartError>()(\"OAuthStartError\", {\n message: Schema.String,\n}) {}\n\nexport class OAuthCompleteError extends Schema.TaggedErrorClass<OAuthCompleteError>()(\n \"OAuthCompleteError\",\n {\n message: Schema.String,\n /** True when the auth-code exchange failed in a way the user must restart. */\n restartRequired: Schema.optional(Schema.Boolean),\n },\n) {}\n\nexport class OAuthProbeError extends Schema.TaggedErrorClass<OAuthProbeError>()(\"OAuthProbeError\", {\n message: Schema.String,\n}) {}\n\nexport class OAuthRegisterDynamicError extends Schema.TaggedErrorClass<OAuthRegisterDynamicError>()(\n \"OAuthRegisterDynamicError\",\n { message: Schema.String },\n) {}\n\nexport class OAuthSessionNotFoundError extends Schema.TaggedErrorClass<OAuthSessionNotFoundError>()(\n \"OAuthSessionNotFoundError\",\n { state: OAuthState },\n) {}\n\n/** The OAuth surface the executor's `oauth.*` namespace and `ctx.oauth` expose.\n * Implemented by `makeOAuthService` (oauth-service.ts), wired by the executor\n * with the deps it needs to mint connections. */\nexport interface OAuthService {\n readonly createClient: (\n input: CreateOAuthClientInput,\n ) => Effect.Effect<OAuthClientSlug, StorageFailure>;\n /** Mint a client via RFC 7591 Dynamic Client Registration (no pre-shared\n * client id/secret) and persist it as an owner-scoped `oauth_client`. */\n readonly registerDynamicClient: (\n input: RegisterDynamicClientInput,\n ) => Effect.Effect<OAuthClientSlug, OAuthRegisterDynamicError | StorageFailure>;\n /** All registered clients visible to the caller (their org's shared clients +\n * their own user clients), as metadata-only summaries — never the secret. */\n readonly listClients: () => Effect.Effect<readonly OAuthClientSummary[], StorageFailure>;\n /** Permanently remove a registered OAuth app, keyed by (owner, slug). The\n * owner policy on `oauth_client` prevents removing another subject's user app.\n * Idempotent: removing an already-gone app succeeds. Connections that\n * referenced the slug keep their stored value and fail at the next token\n * refresh, prompting a reconnect — this op never cascades into connections. */\n readonly removeClient: (\n owner: Owner,\n slug: OAuthClientSlug,\n ) => Effect.Effect<void, StorageFailure>;\n readonly start: (\n input: OAuthStartInput,\n ) => Effect.Effect<ConnectResult, OAuthStartError | StorageFailure>;\n readonly complete: (\n input: OAuthCompleteInput,\n ) => Effect.Effect<Connection, OAuthCompleteError | OAuthSessionNotFoundError | StorageFailure>;\n readonly cancel: (state: OAuthState) => Effect.Effect<void, StorageFailure>;\n readonly probe: (\n input: OAuthProbeInput,\n ) => Effect.Effect<OAuthProbeResult, OAuthProbeError | StorageFailure>;\n}\n","// ---------------------------------------------------------------------------\n// OAuth — v2 surface re-exports.\n//\n// The v2 OAuth contracts (the `OAuthClient`, `OAuthService`, input/result\n// shapes, and tagged errors) live in `oauth-client.ts`; this module re-exports\n// them so existing imports of `./oauth` keep resolving. The OAuth 2.1 *protocol*\n// implementation (PKCE/DCR/token exchange + refresh) lives in `oauth-helpers`\n// and `oauth-discovery`; the runtime service is `oauth-service.ts`.\n//\n// v1's scope/secret-coupled OAuthService, strategy descriptors, and provider\n// state schemas are gone — OAuth refresh material now lives on the connection\n// row and core owns the flow (D14).\n// ---------------------------------------------------------------------------\n\nimport { Encoding, Option, Result, Schema } from \"effect\";\n\nexport {\n type OAuthGrant,\n type OAuthAuthentication,\n type OAuthClient,\n type CreateOAuthClientInput,\n type ConnectResult,\n type OAuthStartInput,\n type OAuthCompleteInput,\n type OAuthProbeInput,\n type OAuthProbeResult,\n type OAuthService,\n OAuthStartError,\n OAuthCompleteError,\n OAuthProbeError,\n OAuthSessionNotFoundError,\n} from \"./oauth-client\";\n\n/** The canonical credential-provider key OAuth-minted connections persist\n * their access token under (the default writable store). */\nexport const OAUTH2_PROVIDER_KEY = \"oauth2\" as const;\n\n/** How long a pending authorization stays redeemable. */\nexport const OAUTH2_SESSION_TTL_MS = 15 * 60 * 1000;\n\nconst OAuthCallbackStateSchema = Schema.Struct({\n state: Schema.String,\n orgSlug: Schema.String,\n});\n\nexport type OAuthCallbackState = typeof OAuthCallbackStateSchema.Type;\n\nconst OAuthCallbackStateFromJson = Schema.fromJsonString(OAuthCallbackStateSchema);\nconst decodeOAuthCallbackStateJson = Schema.decodeUnknownOption(OAuthCallbackStateFromJson);\nconst encodeOAuthCallbackStateJson = Schema.encodeSync(OAuthCallbackStateFromJson);\n\n/** Encode URL selected callback routing data into OAuth `state`.\n *\n * The persisted OAuth session still uses the raw random state. Only the value\n * sent to the authorization server is wrapped, so providers can keep a static\n * redirect_uri while echoing enough state for the callback edge to pick the\n * correct organization before completing the flow.\n */\nexport const encodeOAuthCallbackState = (input: {\n readonly state: string;\n readonly orgSlug?: string | null;\n}): string => {\n const orgSlug = input.orgSlug?.trim();\n if (!orgSlug) return input.state;\n return Encoding.encodeBase64Url(encodeOAuthCallbackStateJson({ state: input.state, orgSlug }));\n};\n\n/** Decode a callback state value minted by `encodeOAuthCallbackState`.\n *\n * Returns null for raw or foreign state values, which lets non-org hosts use\n * the raw OAuth state unchanged.\n */\nexport const decodeOAuthCallbackState = (\n value: string | null | undefined,\n): OAuthCallbackState | null => {\n if (!value) return null;\n const json = Result.getOrNull(Encoding.decodeBase64UrlString(value));\n if (json === null) return null;\n const decoded = Option.getOrNull(decodeOAuthCallbackStateJson(json));\n if (decoded === null) return null;\n const orgSlug = decoded.orgSlug.trim();\n return orgSlug ? { state: decoded.state, orgSlug } : null;\n};\n","// ---------------------------------------------------------------------------\n// Public projections beyond the core domain types. The integration / connection\n// / tool views live in their own domain files (`integration.ts`, `connection.ts`,\n// `tool.ts`); this file holds the schema-side views and the onboarding URL\n// autodetect result.\n// ---------------------------------------------------------------------------\n\nimport { Schema } from \"effect\";\n\nimport { ToolAddress } from \"./ids\";\n\n// ---------------------------------------------------------------------------\n// ToolSchemaView — the full schema-side view of a tool, returned by\n// `executor.tools.schema(address)`. Includes JSON schema roots plus shared\n// definitions for schema exploration, and optionally TypeScript preview strings.\n// ---------------------------------------------------------------------------\n\nexport const ToolSchemaView = Schema.Struct({\n address: ToolAddress,\n name: Schema.optional(Schema.String),\n description: Schema.optional(Schema.String),\n inputSchema: Schema.optional(Schema.Unknown),\n outputSchema: Schema.optional(Schema.Unknown),\n schemaDefinitions: Schema.optional(Schema.Record(Schema.String, Schema.Unknown)),\n inputTypeScript: Schema.optional(Schema.String),\n outputTypeScript: Schema.optional(Schema.String),\n typeScriptDefinitions: Schema.optional(Schema.Record(Schema.String, Schema.String)),\n});\nexport type ToolSchemaView = typeof ToolSchemaView.Type;\n\n// ---------------------------------------------------------------------------\n// Integration detection — optional capability on `PluginSpec.detect`. When a\n// user pastes a URL in the onboarding UI, `executor.integrations.detect(url)`\n// asks every plugin \"is this yours?\" and returns the best-confidence match so\n// the UI can auto-fill the onboarding form for the right plugin.\n// ---------------------------------------------------------------------------\n\nexport const IntegrationDetectionResult = Schema.Struct({\n /** Plugin id that recognized the URL (e.g. \"openapi\", \"graphql\"). */\n kind: Schema.String,\n /** Confidence tier — UI uses this to pick a winner when multiple plugins\n * claim a URL. */\n confidence: Schema.Literals([\"high\", \"medium\", \"low\"]),\n /** The (possibly normalized) endpoint the plugin will use. */\n endpoint: Schema.String,\n /** Human-readable name suggestion, typically derived from spec title or URL. */\n name: Schema.String,\n /** Slug suggestion — the plugin's recommendation for the integration slug. */\n slug: Schema.String,\n});\nexport type IntegrationDetectionResult = typeof IntegrationDetectionResult.Type;\n"],"mappings":"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","names":["Schema","Schema","Schema","Schema","Schema","Schema","Schema","Schema","Schema"]}
package/dist/client.d.ts CHANGED
@@ -8,10 +8,18 @@ export * as AsyncResult from "effect/unstable/reactivity/AsyncResult";
8
8
  export * as Atom from "effect/unstable/reactivity/Atom";
9
9
  export * as AtomHttpApi from "effect/unstable/reactivity/AtomHttpApi";
10
10
  export { useAtomValue, useAtomSet, useAtomMount, useAtomRefresh } from "@effect/atom-react";
11
+ export interface PluginPageProps {
12
+ /** Plugin-relative route params captured from `PageDecl.path` segments. */
13
+ readonly params: Readonly<Record<string, string>>;
14
+ /** The normalized plugin-relative URL path that matched this page. */
15
+ readonly path: string;
16
+ /** The plugin id from `/plugins/$pluginId/...`. */
17
+ readonly pluginId: string;
18
+ }
11
19
  export interface PageDecl {
12
20
  /** Path relative to the plugin's mount point, e.g. `/`, `/edit/$id`. */
13
21
  readonly path: string;
14
- readonly component: ComponentType;
22
+ readonly component: ComponentType<PluginPageProps>;
15
23
  /** Optional sidebar nav metadata — the host renders these alongside its
16
24
  * own nav links. Omit to register a page without a nav entry. */
17
25
  readonly nav?: {
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAWA,OAAO,EAEL,aAAa,EAIb,KAAK,aAAa,EAClB,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAEf,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAC7E,OAAO,EAA+B,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACtF,OAAO,KAAK,WAAW,MAAM,wCAAwC,CAAC;AAOtE,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAEjF,OAAO,KAAK,WAAW,MAAM,wCAAwC,CAAC;AACtE,OAAO,KAAK,IAAI,MAAM,iCAAiC,CAAC;AACxD,OAAO,KAAK,WAAW,MAAM,wCAAwC,CAAC;AAEtE,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAW5F,MAAM,WAAW,eAAe;IAC9B,2EAA2E;IAC3E,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAClD,sEAAsE;IACtE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,mDAAmD;IACnD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,QAAQ;IACvB,wEAAwE;IACxE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,EAAE,aAAa,CAAC,eAAe,CAAC,CAAC;IACnD;sEACkE;IAClE,QAAQ,CAAC,GAAG,CAAC,EAAE;QACb,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QACvB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;KAC3B,CAAC;CACH;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,SAAS,EAAE,aAAa,CAAC,WAAW,CAAC,CAAC;IAC/C,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACjC;AAED;;;;;GAKG;AACH,MAAM,MAAM,aAAa,GAAG,aAAa,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;AAcnE,MAAM,WAAW,iBAAiB;IAChC,mDAAmD;IACnD,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB;oDACgD;IAChD,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB;4CACwC;IACxC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,yCAAyC;IACzC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,sEAAsE;IACtE,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED,MAAM,WAAW,yBAAyB;IACxC,8EAA8E;IAC9E,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,KAAK,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC;IAChC,sDAAsD;IACtD,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,8CAA8C;IAC9C,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB;;;mEAG+D;IAC/D,QAAQ,CAAC,WAAW,CAAC,EAAE;QACrB,kEAAkE;QAClE,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QACvB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QACxB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAC3B,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;QACnC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAC3B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;KAC5B,CAAC;CACH;AAED;;6BAE6B;AAC7B,MAAM,MAAM,oBAAoB,GAC5B;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GACtD;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAA;CAAE,CAAC;AAE3B,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,MAAM,OAAO,CAAC,oBAAoB,CAAC,CAAC,GAAG,IAAI,KAAK,IAAI,CAAC;CAC1F;AAED,MAAM,WAAW,iBAAiB;IAChC,8DAA8D;IAC9D,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,GAAG,EAAE,aAAa,CAAC;QAC1B;;;sEAG8D;QAC9D,QAAQ,CAAC,UAAU,EAAE,CAAC,IAAI,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;QAC7C,QAAQ,CAAC,QAAQ,EAAE,MAAM,IAAI,CAAC;QAC9B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;QAC7B,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;QAChC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;KACpC,CAAC,CAAC;IACH;6EACyE;IACzE,QAAQ,CAAC,IAAI,CAAC,EAAE,aAAa,CAAC;QAC5B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;QAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,IAAI,CAAC;KAC7B,CAAC,CAAC;IACH;;;;;6EAKyE;IACzE,QAAQ,CAAC,SAAS,CAAC,EAAE,aAAa,CAAC,qBAAqB,CAAC,CAAC;IAC1D,QAAQ,CAAC,OAAO,CAAC,EAAE,aAAa,CAAC;QAC/B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;QAC1B,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC;QACrC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;KAChC,CAAC,CAAC;IACH;;4EAEwE;IACxE,QAAQ,CAAC,QAAQ,CAAC,EAAE,aAAa,CAAC;QAChC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;QAC1B,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;QACjC,QAAQ,CAAC,cAAc,CAAC,EAAE,yBAAyB,GAAG,IAAI,CAAC;KAC5D,CAAC,CAAC;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,iBAAiB,EAAE,CAAC;IAChD;;wDAEoD;IACpD,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CAC/B;AAQD,MAAM,WAAW,oBAAoB;IACnC,kEAAkE;IAClE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC;CACzD;AAED,MAAM,WAAW,gBAAgB,CAAC,GAAG,SAAS,MAAM,GAAG,MAAM;IAC3D,QAAQ,CAAC,EAAE,EAAE,GAAG,CAAC;IACjB,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,QAAQ,EAAE,CAAC;IACrC,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,UAAU,EAAE,CAAC;IACzC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IAC/C;;;4EAGwE;IACxE,QAAQ,CAAC,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;IAC/C;;yEAEqE;IACrE,QAAQ,CAAC,oBAAoB,CAAC,EAAE,oBAAoB,CAAC;CACtD;AAED;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,GAAI,KAAK,CAAC,GAAG,SAAS,MAAM,EACzD,MAAM,gBAAgB,CAAC,GAAG,CAAC,KAC1B,gBAAgB,CAAC,GAAG,CAAS,CAAC;AAkBjC,MAAM,WAAW,6BAA6B;IAC5C;;oCAEgC;IAChC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,CAAC;IAC3C;oEACgE;IAChE,QAAQ,CAAC,mBAAmB,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,CAAC,MAAM,MAAM,GAAG,IAAI,CAAC,CAAC;IACrE,mEAAmE;IACnE,QAAQ,CAAC,OAAO,CAAC,EACb,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC,GACnD,CAAC,MAAM,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;CACjE;AAED,MAAM,WAAW,uCAAuC;IACtD,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,MAAM,CAAC;IAChC,QAAQ,CAAC,mBAAmB,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,CAAC,MAAM,MAAM,GAAG,IAAI,CAAC,CAAC;IACrE,QAAQ,CAAC,OAAO,CAAC,EACb,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC,GACnD,CAAC,MAAM,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;CACjE;AAED,gBAAgB;AAChB,eAAO,MAAM,qCAAqC,GAChD,SAAS,iBAAiB,CAAC,iBAAiB,EAC5C,SAAS,uCAAuC,KAC/C,iBAAiB,CAAC,iBAkBpB,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,sBAAsB,GACjC,CAAC,SAAS,YAAY,CAAC,YAAY,CAAC,MAAM,EAAE,eAAe,CAAC,GAAG,EAAE,OAAO,CAAC,EAEzE,OAAO,CAAC,EACR,UAAS,6BAAkC,kGAgC5C,CAAC;AA0BF,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,CAAC,OAAO,EAAE,SAAS,gBAAgB,EAAE,CAAC;IAC9C,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAC;CAC9B;AAED,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,4BAA4B,GAClC,UAAU,CAAC,OAAO,aAAa,CAAC,CAoBlC;AAWD,qDAAqD;AACrD,eAAO,MAAM,gBAAgB,QAAO,SAAS,gBAAgB,EAClB,CAAC;AAE5C,8EAA8E;AAC9E,eAAO,MAAM,qBAAqB,QAAO,SAAS,iBAAiB,EACR,CAAC;AAE5D,qFAAqF;AACrF,eAAO,MAAM,wBAAwB,QAAO,SAAS,oBAAoB,EACR,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/client.ts"],"sourcesContent":["// ---------------------------------------------------------------------------\n// @executor-js/sdk/client — frontend half of the plugin SDK.\n//\n// Plugins import from this entry to register pages/widgets and consume\n// their own typed reactive client. Server bundles must NOT import this\n// module — it pulls in React + @effect/atom-react. Plugin packages should\n// keep React/atom imports inside `./client.tsx` and Effect/Node imports\n// inside `./server.ts`; shared schema definitions go in `./shared.ts` and\n// can be imported from both halves.\n// ---------------------------------------------------------------------------\n\nimport {\n createContext,\n createElement,\n useContext,\n useEffect,\n useMemo,\n type ComponentType,\n type ReactNode,\n} from \"react\";\nimport { HttpApi } from \"effect/unstable/httpapi\";\nimport type { HttpApiEndpoint, HttpApiGroup } from \"effect/unstable/httpapi\";\nimport { FetchHttpClient, HttpClient, HttpClientRequest } from \"effect/unstable/http\";\nimport * as AtomHttpApi from \"effect/unstable/reactivity/AtomHttpApi\";\n\n// ---------------------------------------------------------------------------\n// Re-exports — the curated set of primitives a plugin author needs to\n// build a typed reactive UI without reaching into `effect/*` directly.\n// ---------------------------------------------------------------------------\n\nexport { Schema } from \"effect\";\nexport { HttpApi, HttpApiEndpoint, HttpApiGroup } from \"effect/unstable/httpapi\";\n\nexport * as AsyncResult from \"effect/unstable/reactivity/AsyncResult\";\nexport * as Atom from \"effect/unstable/reactivity/Atom\";\nexport * as AtomHttpApi from \"effect/unstable/reactivity/AtomHttpApi\";\n\nexport { useAtomValue, useAtomSet, useAtomMount, useAtomRefresh } from \"@effect/atom-react\";\n\n// ---------------------------------------------------------------------------\n// defineClientPlugin — declarative spec for the frontend half of a plugin.\n//\n// Mirror of `definePlugin` on the server, but everything here is React /\n// browser-only. The host treats the value as data: collects routes,\n// widgets, and slot components from every loaded plugin and mounts them\n// alongside the host's own UI.\n// ---------------------------------------------------------------------------\n\nexport interface PageDecl {\n /** Path relative to the plugin's mount point, e.g. `/`, `/edit/$id`. */\n readonly path: string;\n readonly component: ComponentType;\n /** Optional sidebar nav metadata — the host renders these alongside its\n * own nav links. Omit to register a page without a nav entry. */\n readonly nav?: {\n readonly label: string;\n readonly section?: string;\n };\n}\n\nexport interface WidgetProps {\n readonly scopeId?: string;\n}\n\nexport interface WidgetDecl {\n readonly id: string;\n readonly component: ComponentType<WidgetProps>;\n readonly size?: \"half\" | \"full\";\n}\n\n/**\n * Open record of host-defined slot components a plugin can fill. Slot\n * names are part of the host UI contract — plugins opt in by registering\n * a component for the slot they care about. Adding a slot is a host-side\n * change; plugin authors don't define new slots.\n */\nexport type SlotComponent = ComponentType<Record<string, unknown>>;\n\n// ---------------------------------------------------------------------------\n// IntegrationPlugin / IntegrationPreset — UI contract for plugins that expose\n// \"integrations\" (OpenAPI specs, MCP servers, GraphQL endpoints, etc.). The\n// host owns the integration list / detail chrome; the plugin owns the\n// add-flow, edit form, and (optional) summary + sign-in buttons.\n//\n// Lives here, not in `@executor-js/react`, so it's part of the plugin\n// contract: a plugin's `./client` entry assembles its `integrationPlugin`\n// alongside `pages`/`widgets`, and the host derives the union list\n// from `virtual:executor/plugins-client`.\n// ---------------------------------------------------------------------------\n\nexport interface IntegrationPreset {\n /** Unique id (e.g. \"stripe\", \"github-graphql\"). */\n readonly id: string;\n readonly name: string;\n readonly summary: string;\n /** URL passed as `initialUrl` to the add form. Omit for presets that\n * don't use a URL (e.g. stdio MCP presets). */\n readonly url?: string;\n /** Endpoint passed to agent-facing probe/add tools when their schema\n * uses `endpoint` instead of `url`. */\n readonly endpoint?: string;\n /** Optional icon URL (favicon, logo). */\n readonly icon?: string;\n /** Shown in the top-level grid on the integrations page when true. */\n readonly featured?: boolean;\n}\n\nexport interface IntegrationAccountHandoff {\n /** Changes on each handoff URL, so the accounts UI can open once per link. */\n readonly key: string;\n readonly owner?: \"org\" | \"user\";\n /** Auth template/method to preselect when present. */\n readonly template?: string;\n /** Non-secret connection label to prefill. */\n readonly label?: string;\n /** Present when the agent handed off a CONFIDENTIAL OAuth-app registration\n * (via `oauth.clients.createHandoff`): the accounts UI opens the\n * Register-OAuth-app form pre-filled with these NON-secret fields, and the\n * human types the client secret directly into the browser. */\n readonly oauthClient?: {\n /** Preselected client slug; when set the form's slug is fixed. */\n readonly slug?: string;\n readonly grant?: string;\n readonly clientId?: string;\n readonly authorizationUrl?: string;\n readonly tokenUrl?: string;\n readonly resource?: string;\n };\n}\n\n/** Outcome of applying an edit-sheet section's staged change. `summary` is\n * toasted on success; `ok: false` keeps the sheet open (the section renders\n * its own error inline). */\nexport type EditSheetApplyResult =\n | { readonly ok: true; readonly summary: string | null }\n | { readonly ok: false };\n\nexport interface EditSheetSectionProps {\n readonly sourceId: string;\n readonly onPendingChange?: (apply: (() => Promise<EditSheetApplyResult>) | null) => void;\n}\n\nexport interface IntegrationPlugin {\n /** Unique key matching the SDK plugin id (e.g. \"openapi\"). */\n readonly key: string;\n readonly label: string;\n readonly add: ComponentType<{\n /** Called when the integration has been registered. Receives the slug of\n * the just-registered integration, so the host can route to its detail\n * hub (`/integrations/<slug>`). Optional so existing no-arg calls still\n * typecheck while plugins are threading the slug through. */\n readonly onComplete: (slug?: string) => void;\n readonly onCancel: () => void;\n readonly initialUrl?: string;\n readonly initialPreset?: string;\n readonly initialNamespace?: string;\n }>;\n /** Legacy full-page edit surface. No host renders this anymore — plugin\n * configuration lives in the integration Edit sheet via `editSheet`. */\n readonly edit?: ComponentType<{\n readonly sourceId: string;\n readonly onSave: () => void;\n }>;\n /** Plugin-owned configuration rendered inside the integration's Edit sheet,\n * below the shared metadata fields (e.g. the OpenAPI spec-update controls).\n * The sheet has ONE Save: the section stages its pending change locally and\n * reports it through `onPendingChange` — a thunk that applies the staged\n * change. Save runs the metadata update, then the staged apply; a failed\n * apply keeps the sheet open with the section showing its own error. */\n readonly editSheet?: ComponentType<EditSheetSectionProps>;\n readonly summary?: ComponentType<{\n readonly sourceId: string;\n readonly variant?: \"badge\" | \"panel\";\n readonly onAction?: () => void;\n }>;\n /** Renders the integration's Accounts hub (auth methods + connections) inside\n * the detail page's Accounts tab. Plugins that declare auth methods implement\n * this; the page falls back to a generic accounts list when absent. */\n readonly accounts?: ComponentType<{\n readonly sourceId: string;\n readonly integrationName: string;\n readonly accountHandoff?: IntegrationAccountHandoff | null;\n }>;\n readonly presets?: readonly IntegrationPreset[];\n /** Trigger early download of the plugin's lazy component chunks (add/edit/etc.).\n * Call from the host on intent (hover/focus) so the chunks land before the\n * user navigates into the add page. Idempotent. */\n readonly preload?: () => void;\n}\n\n// ---------------------------------------------------------------------------\n// SecretProviderPlugin — UI contract for plugins that contribute secret\n// providers (1Password, WorkOS Vault, etc.). The host owns the secrets\n// page chrome; the plugin owns the settings card rendered inside.\n// ---------------------------------------------------------------------------\n\nexport interface SecretProviderPlugin {\n /** Unique key matching the SDK plugin id (e.g. \"onepassword\"). */\n readonly key: string;\n readonly label: string;\n readonly settings: ComponentType<Record<string, never>>;\n}\n\nexport interface ClientPluginSpec<TId extends string = string> {\n readonly id: TId;\n readonly pages?: readonly PageDecl[];\n readonly widgets?: readonly WidgetDecl[];\n readonly slots?: Record<string, SlotComponent>;\n /** Integration plugin contribution — populated by plugins that expose\n * `kind` rows in the core `source` table (openapi, mcp, graphql).\n * The host's integrations page derives its provider\n * list from the union of every loaded plugin's `integrationPlugin`. */\n readonly integrationPlugin?: IntegrationPlugin;\n /** Secret provider plugin contribution — populated by plugins that\n * also ship a `secretProviders` (or related) server-side capability\n * AND want to expose a settings card on the host's secrets page. */\n readonly secretProviderPlugin?: SecretProviderPlugin;\n}\n\n/**\n * Identity factory — returns the spec unchanged but pins the inferred\n * literal type of `id` so the host can index plugin records by id with\n * full autocomplete. Plugins export this as their package's default\n * (or named) export from `./client`.\n */\nexport const defineClientPlugin = <const TId extends string>(\n spec: ClientPluginSpec<TId>,\n): ClientPluginSpec<TId> => spec;\n\n// ---------------------------------------------------------------------------\n// createPluginAtomClient — typed reactive HTTP client for one plugin.\n//\n// Wraps the plugin's `HttpApiGroup` in a per-plugin `HttpApi`, then\n// hands back an `AtomHttpApi.Service` keyed to that bundle. The\n// resulting service exposes `.query(\"group\", \"endpoint\", opts)` and\n// `.mutation(\"group\", \"endpoint\")` factories — same shape as the host's\n// existing `ExecutorApiClient` (see packages/react/src/api/client.tsx).\n// Per-endpoint payload/response/error types flow through from the\n// imported group, so plugin client code typechecks without codegen.\n//\n// The plugin id (used for the Service Tag and the synthetic API id) is\n// read from `group.identifier` — the same string the plugin passed to\n// `HttpApiGroup.make(\"foo\")`. No second-source duplication.\n// ---------------------------------------------------------------------------\n\nexport interface CreatePluginAtomClientOptions {\n /** Override the base URL. Defaults to `/api` (host strips this prefix\n * when forwarding to the Effect handler) — same convention as the\n * core `ExecutorApiClient`. */\n readonly baseUrl?: string | (() => string);\n /** Optional dynamic Authorization header for hosts whose active\n * Executor Server Connection requires Basic or Bearer auth. */\n readonly authorizationHeader?: string | null | (() => string | null);\n /** Optional dynamic request headers supplied by the host shell. */\n readonly headers?:\n | Readonly<Record<string, string | null | undefined>>\n | (() => Readonly<Record<string, string | null | undefined>>);\n}\n\nexport interface PluginAtomClientRequestTransformOptions {\n readonly baseUrl?: () => string;\n readonly authorizationHeader?: string | null | (() => string | null);\n readonly headers?:\n | Readonly<Record<string, string | null | undefined>>\n | (() => Readonly<Record<string, string | null | undefined>>);\n}\n\n/** @internal */\nexport const applyPluginAtomClientRequestTransform = (\n request: HttpClientRequest.HttpClientRequest,\n options: PluginAtomClientRequestTransformOptions,\n): HttpClientRequest.HttpClientRequest => {\n let next = options.baseUrl ? HttpClientRequest.prependUrl(request, options.baseUrl()) : request;\n const authorization =\n typeof options.authorizationHeader === \"function\"\n ? options.authorizationHeader()\n : options.authorizationHeader;\n if (authorization) {\n next = HttpClientRequest.setHeader(next, \"authorization\", authorization);\n }\n const headers = typeof options.headers === \"function\" ? options.headers() : options.headers;\n if (headers) {\n for (const [name, value] of Object.entries(headers)) {\n if (value !== undefined && value !== null) {\n next = HttpClientRequest.setHeader(next, name, value);\n }\n }\n }\n return next;\n};\n\n/**\n * Build a typed reactive client for a plugin's HttpApiGroup.\n *\n * const FooClient = createPluginAtomClient(FooApi)\n * export const fooThings = FooClient.query(\"foo\", \"listThings\", { ... })\n * export const fooSync = FooClient.mutation(\"foo\", \"syncThing\")\n *\n * Each plugin gets a private service Tag (`Plugin_<id>Client`) keyed by\n * the group's `identifier`, so multiple plugins coexist in the same\n * React tree without colliding.\n */\nexport const createPluginAtomClient = <\n G extends HttpApiGroup.HttpApiGroup<string, HttpApiEndpoint.Any, boolean>,\n>(\n group: G,\n options: CreatePluginAtomClientOptions = {},\n) => {\n const { baseUrl = \"/api\", authorizationHeader, headers } = options;\n const pluginId = group.identifier;\n const bundle = HttpApi.make(`plugin-${pluginId}`).add(group);\n const getBaseUrl = typeof baseUrl === \"function\" ? baseUrl : null;\n const staticBaseUrl = typeof baseUrl === \"function\" ? undefined : baseUrl;\n const getAuthorizationHeader =\n typeof authorizationHeader === \"function\" ? authorizationHeader : null;\n const hasAuthorization = authorizationHeader !== undefined && authorizationHeader !== null;\n const hasHeaders = headers !== undefined;\n const transformClient =\n getBaseUrl || hasAuthorization || hasHeaders\n ? HttpClient.mapRequest((request) =>\n applyPluginAtomClientRequestTransform(request, {\n ...(getBaseUrl ? { baseUrl: getBaseUrl } : {}),\n ...(getAuthorizationHeader\n ? { authorizationHeader: getAuthorizationHeader }\n : authorizationHeader !== undefined\n ? { authorizationHeader }\n : {}),\n ...(headers !== undefined ? { headers } : {}),\n }),\n )\n : undefined;\n\n return AtomHttpApi.Service<`Plugin_${G[\"identifier\"]}Client`>()(`Plugin_${pluginId}Client`, {\n api: bundle,\n httpClient: FetchHttpClient.layer,\n ...(staticBaseUrl !== undefined ? { baseUrl: staticBaseUrl } : {}),\n ...(transformClient ? { transformClient } : {}),\n });\n};\n\n// ---------------------------------------------------------------------------\n// ExecutorPluginsProvider + hooks — host-level distribution of the loaded\n// `ClientPluginSpec[]` via React context.\n//\n// The host wraps once at the root of its tree (typically reading from\n// `virtual:executor/plugins-client`); pages and shared components consume\n// via the focused hooks (`useIntegrationPlugins` etc.) so they don't import\n// from any host-app aggregator file. Pages stay portable across hosts —\n// the same component renders against whatever plugin set the surrounding\n// `<ExecutorPluginsProvider>` provides.\n//\n// Hooks throw if no provider is in scope so missing setup fails loudly;\n// matches the pattern of `useScope` / `useAuth` already in the codebase.\n// ---------------------------------------------------------------------------\n\ninterface ExecutorPluginsContextValue {\n readonly plugins: readonly ClientPluginSpec[];\n readonly integrationPlugins: readonly IntegrationPlugin[];\n readonly secretProviderPlugins: readonly SecretProviderPlugin[];\n}\n\nconst ExecutorPluginsContext = createContext<ExecutorPluginsContextValue | null>(null);\nExecutorPluginsContext.displayName = \"ExecutorPluginsContext\";\n\nexport interface ExecutorPluginsProviderProps {\n readonly plugins: readonly ClientPluginSpec[];\n readonly children: ReactNode;\n}\n\nexport function ExecutorPluginsProvider(\n props: ExecutorPluginsProviderProps,\n): ReturnType<typeof createElement> {\n const { plugins, children } = props;\n const value = useMemo<ExecutorPluginsContextValue>(\n () => ({\n plugins,\n integrationPlugins: plugins.flatMap((p) =>\n p.integrationPlugin ? [p.integrationPlugin] : [],\n ),\n secretProviderPlugins: plugins.flatMap((p) =>\n p.secretProviderPlugin ? [p.secretProviderPlugin] : [],\n ),\n }),\n [plugins],\n );\n // Kick off lazy chunk downloads for every integration plugin once the host\n // mounts, so navigating into an add/edit page doesn't suspend.\n useEffect(() => {\n for (const ip of value.integrationPlugins) ip.preload?.();\n }, [value.integrationPlugins]);\n return createElement(ExecutorPluginsContext.Provider, { value }, children);\n}\n\nconst usePluginsCtx = (hookName: string): ExecutorPluginsContextValue => {\n const ctx = useContext(ExecutorPluginsContext);\n if (!ctx) {\n // oxlint-disable-next-line executor/no-try-catch-or-throw, executor/no-error-constructor -- boundary: React hook invariant\n throw new Error(`${hookName} must be called inside an <ExecutorPluginsProvider>.`);\n }\n return ctx;\n};\n\n/** Full list of loaded `ClientPluginSpec` values. */\nexport const useClientPlugins = (): readonly ClientPluginSpec[] =>\n usePluginsCtx(\"useClientPlugins\").plugins;\n\n/** Integration plugins extracted from `clientPlugins[].integrationPlugin`. */\nexport const useIntegrationPlugins = (): readonly IntegrationPlugin[] =>\n usePluginsCtx(\"useIntegrationPlugins\").integrationPlugins;\n\n/** Secret-provider plugins extracted from `clientPlugins[].secretProviderPlugin`. */\nexport const useSecretProviderPlugins = (): readonly SecretProviderPlugin[] =>\n usePluginsCtx(\"useSecretProviderPlugins\").secretProviderPlugins;\n"],"mappings":"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","names":["HttpApi","AtomHttpApi"]}
1
+ {"version":3,"sources":["../src/client.ts"],"sourcesContent":["// ---------------------------------------------------------------------------\n// @executor-js/sdk/client — frontend half of the plugin SDK.\n//\n// Plugins import from this entry to register pages/widgets and consume\n// their own typed reactive client. Server bundles must NOT import this\n// module — it pulls in React + @effect/atom-react. Plugin packages should\n// keep React/atom imports inside `./client.tsx` and Effect/Node imports\n// inside `./server.ts`; shared schema definitions go in `./shared.ts` and\n// can be imported from both halves.\n// ---------------------------------------------------------------------------\n\nimport {\n createContext,\n createElement,\n useContext,\n useEffect,\n useMemo,\n type ComponentType,\n type ReactNode,\n} from \"react\";\nimport { HttpApi } from \"effect/unstable/httpapi\";\nimport type { HttpApiEndpoint, HttpApiGroup } from \"effect/unstable/httpapi\";\nimport { FetchHttpClient, HttpClient, HttpClientRequest } from \"effect/unstable/http\";\nimport * as AtomHttpApi from \"effect/unstable/reactivity/AtomHttpApi\";\n\n// ---------------------------------------------------------------------------\n// Re-exports — the curated set of primitives a plugin author needs to\n// build a typed reactive UI without reaching into `effect/*` directly.\n// ---------------------------------------------------------------------------\n\nexport { Schema } from \"effect\";\nexport { HttpApi, HttpApiEndpoint, HttpApiGroup } from \"effect/unstable/httpapi\";\n\nexport * as AsyncResult from \"effect/unstable/reactivity/AsyncResult\";\nexport * as Atom from \"effect/unstable/reactivity/Atom\";\nexport * as AtomHttpApi from \"effect/unstable/reactivity/AtomHttpApi\";\n\nexport { useAtomValue, useAtomSet, useAtomMount, useAtomRefresh } from \"@effect/atom-react\";\n\n// ---------------------------------------------------------------------------\n// defineClientPlugin — declarative spec for the frontend half of a plugin.\n//\n// Mirror of `definePlugin` on the server, but everything here is React /\n// browser-only. The host treats the value as data: collects routes,\n// widgets, and slot components from every loaded plugin and mounts them\n// alongside the host's own UI.\n// ---------------------------------------------------------------------------\n\nexport interface PluginPageProps {\n /** Plugin-relative route params captured from `PageDecl.path` segments. */\n readonly params: Readonly<Record<string, string>>;\n /** The normalized plugin-relative URL path that matched this page. */\n readonly path: string;\n /** The plugin id from `/plugins/$pluginId/...`. */\n readonly pluginId: string;\n}\n\nexport interface PageDecl {\n /** Path relative to the plugin's mount point, e.g. `/`, `/edit/$id`. */\n readonly path: string;\n readonly component: ComponentType<PluginPageProps>;\n /** Optional sidebar nav metadata — the host renders these alongside its\n * own nav links. Omit to register a page without a nav entry. */\n readonly nav?: {\n readonly label: string;\n readonly section?: string;\n };\n}\n\nexport interface WidgetProps {\n readonly scopeId?: string;\n}\n\nexport interface WidgetDecl {\n readonly id: string;\n readonly component: ComponentType<WidgetProps>;\n readonly size?: \"half\" | \"full\";\n}\n\n/**\n * Open record of host-defined slot components a plugin can fill. Slot\n * names are part of the host UI contract — plugins opt in by registering\n * a component for the slot they care about. Adding a slot is a host-side\n * change; plugin authors don't define new slots.\n */\nexport type SlotComponent = ComponentType<Record<string, unknown>>;\n\n// ---------------------------------------------------------------------------\n// IntegrationPlugin / IntegrationPreset — UI contract for plugins that expose\n// \"integrations\" (OpenAPI specs, MCP servers, GraphQL endpoints, etc.). The\n// host owns the integration list / detail chrome; the plugin owns the\n// add-flow, edit form, and (optional) summary + sign-in buttons.\n//\n// Lives here, not in `@executor-js/react`, so it's part of the plugin\n// contract: a plugin's `./client` entry assembles its `integrationPlugin`\n// alongside `pages`/`widgets`, and the host derives the union list\n// from `virtual:executor/plugins-client`.\n// ---------------------------------------------------------------------------\n\nexport interface IntegrationPreset {\n /** Unique id (e.g. \"stripe\", \"github-graphql\"). */\n readonly id: string;\n readonly name: string;\n readonly summary: string;\n /** URL passed as `initialUrl` to the add form. Omit for presets that\n * don't use a URL (e.g. stdio MCP presets). */\n readonly url?: string;\n /** Endpoint passed to agent-facing probe/add tools when their schema\n * uses `endpoint` instead of `url`. */\n readonly endpoint?: string;\n /** Optional icon URL (favicon, logo). */\n readonly icon?: string;\n /** Shown in the top-level grid on the integrations page when true. */\n readonly featured?: boolean;\n}\n\nexport interface IntegrationAccountHandoff {\n /** Changes on each handoff URL, so the accounts UI can open once per link. */\n readonly key: string;\n readonly owner?: \"org\" | \"user\";\n /** Auth template/method to preselect when present. */\n readonly template?: string;\n /** Non-secret connection label to prefill. */\n readonly label?: string;\n /** Present when the agent handed off a CONFIDENTIAL OAuth-app registration\n * (via `oauth.clients.createHandoff`): the accounts UI opens the\n * Register-OAuth-app form pre-filled with these NON-secret fields, and the\n * human types the client secret directly into the browser. */\n readonly oauthClient?: {\n /** Preselected client slug; when set the form's slug is fixed. */\n readonly slug?: string;\n readonly grant?: string;\n readonly clientId?: string;\n readonly authorizationUrl?: string;\n readonly tokenUrl?: string;\n readonly resource?: string;\n };\n}\n\n/** Outcome of applying an edit-sheet section's staged change. `summary` is\n * toasted on success; `ok: false` keeps the sheet open (the section renders\n * its own error inline). */\nexport type EditSheetApplyResult =\n | { readonly ok: true; readonly summary: string | null }\n | { readonly ok: false };\n\nexport interface EditSheetSectionProps {\n readonly sourceId: string;\n readonly onPendingChange?: (apply: (() => Promise<EditSheetApplyResult>) | null) => void;\n}\n\nexport interface IntegrationPlugin {\n /** Unique key matching the SDK plugin id (e.g. \"openapi\"). */\n readonly key: string;\n readonly label: string;\n readonly add: ComponentType<{\n /** Called when the integration has been registered. Receives the slug of\n * the just-registered integration, so the host can route to its detail\n * hub (`/integrations/<slug>`). Optional so existing no-arg calls still\n * typecheck while plugins are threading the slug through. */\n readonly onComplete: (slug?: string) => void;\n readonly onCancel: () => void;\n readonly initialUrl?: string;\n readonly initialPreset?: string;\n readonly initialNamespace?: string;\n }>;\n /** Legacy full-page edit surface. No host renders this anymore — plugin\n * configuration lives in the integration Edit sheet via `editSheet`. */\n readonly edit?: ComponentType<{\n readonly sourceId: string;\n readonly onSave: () => void;\n }>;\n /** Plugin-owned configuration rendered inside the integration's Edit sheet,\n * below the shared metadata fields (e.g. the OpenAPI spec-update controls).\n * The sheet has ONE Save: the section stages its pending change locally and\n * reports it through `onPendingChange` — a thunk that applies the staged\n * change. Save runs the metadata update, then the staged apply; a failed\n * apply keeps the sheet open with the section showing its own error. */\n readonly editSheet?: ComponentType<EditSheetSectionProps>;\n readonly summary?: ComponentType<{\n readonly sourceId: string;\n readonly variant?: \"badge\" | \"panel\";\n readonly onAction?: () => void;\n }>;\n /** Renders the integration's Accounts hub (auth methods + connections) inside\n * the detail page's Accounts tab. Plugins that declare auth methods implement\n * this; the page falls back to a generic accounts list when absent. */\n readonly accounts?: ComponentType<{\n readonly sourceId: string;\n readonly integrationName: string;\n readonly accountHandoff?: IntegrationAccountHandoff | null;\n }>;\n readonly presets?: readonly IntegrationPreset[];\n /** Trigger early download of the plugin's lazy component chunks (add/edit/etc.).\n * Call from the host on intent (hover/focus) so the chunks land before the\n * user navigates into the add page. Idempotent. */\n readonly preload?: () => void;\n}\n\n// ---------------------------------------------------------------------------\n// SecretProviderPlugin — UI contract for plugins that contribute secret\n// providers (1Password, WorkOS Vault, etc.). The host owns the secrets\n// page chrome; the plugin owns the settings card rendered inside.\n// ---------------------------------------------------------------------------\n\nexport interface SecretProviderPlugin {\n /** Unique key matching the SDK plugin id (e.g. \"onepassword\"). */\n readonly key: string;\n readonly label: string;\n readonly settings: ComponentType<Record<string, never>>;\n}\n\nexport interface ClientPluginSpec<TId extends string = string> {\n readonly id: TId;\n readonly pages?: readonly PageDecl[];\n readonly widgets?: readonly WidgetDecl[];\n readonly slots?: Record<string, SlotComponent>;\n /** Integration plugin contribution — populated by plugins that expose\n * `kind` rows in the core `source` table (openapi, mcp, graphql).\n * The host's integrations page derives its provider\n * list from the union of every loaded plugin's `integrationPlugin`. */\n readonly integrationPlugin?: IntegrationPlugin;\n /** Secret provider plugin contribution — populated by plugins that\n * also ship a `secretProviders` (or related) server-side capability\n * AND want to expose a settings card on the host's secrets page. */\n readonly secretProviderPlugin?: SecretProviderPlugin;\n}\n\n/**\n * Identity factory — returns the spec unchanged but pins the inferred\n * literal type of `id` so the host can index plugin records by id with\n * full autocomplete. Plugins export this as their package's default\n * (or named) export from `./client`.\n */\nexport const defineClientPlugin = <const TId extends string>(\n spec: ClientPluginSpec<TId>,\n): ClientPluginSpec<TId> => spec;\n\n// ---------------------------------------------------------------------------\n// createPluginAtomClient — typed reactive HTTP client for one plugin.\n//\n// Wraps the plugin's `HttpApiGroup` in a per-plugin `HttpApi`, then\n// hands back an `AtomHttpApi.Service` keyed to that bundle. The\n// resulting service exposes `.query(\"group\", \"endpoint\", opts)` and\n// `.mutation(\"group\", \"endpoint\")` factories — same shape as the host's\n// existing `ExecutorApiClient` (see packages/react/src/api/client.tsx).\n// Per-endpoint payload/response/error types flow through from the\n// imported group, so plugin client code typechecks without codegen.\n//\n// The plugin id (used for the Service Tag and the synthetic API id) is\n// read from `group.identifier` — the same string the plugin passed to\n// `HttpApiGroup.make(\"foo\")`. No second-source duplication.\n// ---------------------------------------------------------------------------\n\nexport interface CreatePluginAtomClientOptions {\n /** Override the base URL. Defaults to `/api` (host strips this prefix\n * when forwarding to the Effect handler) — same convention as the\n * core `ExecutorApiClient`. */\n readonly baseUrl?: string | (() => string);\n /** Optional dynamic Authorization header for hosts whose active\n * Executor Server Connection requires Basic or Bearer auth. */\n readonly authorizationHeader?: string | null | (() => string | null);\n /** Optional dynamic request headers supplied by the host shell. */\n readonly headers?:\n | Readonly<Record<string, string | null | undefined>>\n | (() => Readonly<Record<string, string | null | undefined>>);\n}\n\nexport interface PluginAtomClientRequestTransformOptions {\n readonly baseUrl?: () => string;\n readonly authorizationHeader?: string | null | (() => string | null);\n readonly headers?:\n | Readonly<Record<string, string | null | undefined>>\n | (() => Readonly<Record<string, string | null | undefined>>);\n}\n\n/** @internal */\nexport const applyPluginAtomClientRequestTransform = (\n request: HttpClientRequest.HttpClientRequest,\n options: PluginAtomClientRequestTransformOptions,\n): HttpClientRequest.HttpClientRequest => {\n let next = options.baseUrl ? HttpClientRequest.prependUrl(request, options.baseUrl()) : request;\n const authorization =\n typeof options.authorizationHeader === \"function\"\n ? options.authorizationHeader()\n : options.authorizationHeader;\n if (authorization) {\n next = HttpClientRequest.setHeader(next, \"authorization\", authorization);\n }\n const headers = typeof options.headers === \"function\" ? options.headers() : options.headers;\n if (headers) {\n for (const [name, value] of Object.entries(headers)) {\n if (value !== undefined && value !== null) {\n next = HttpClientRequest.setHeader(next, name, value);\n }\n }\n }\n return next;\n};\n\n/**\n * Build a typed reactive client for a plugin's HttpApiGroup.\n *\n * const FooClient = createPluginAtomClient(FooApi)\n * export const fooThings = FooClient.query(\"foo\", \"listThings\", { ... })\n * export const fooSync = FooClient.mutation(\"foo\", \"syncThing\")\n *\n * Each plugin gets a private service Tag (`Plugin_<id>Client`) keyed by\n * the group's `identifier`, so multiple plugins coexist in the same\n * React tree without colliding.\n */\nexport const createPluginAtomClient = <\n G extends HttpApiGroup.HttpApiGroup<string, HttpApiEndpoint.Any, boolean>,\n>(\n group: G,\n options: CreatePluginAtomClientOptions = {},\n) => {\n const { baseUrl = \"/api\", authorizationHeader, headers } = options;\n const pluginId = group.identifier;\n const bundle = HttpApi.make(`plugin-${pluginId}`).add(group);\n const getBaseUrl = typeof baseUrl === \"function\" ? baseUrl : null;\n const staticBaseUrl = typeof baseUrl === \"function\" ? undefined : baseUrl;\n const getAuthorizationHeader =\n typeof authorizationHeader === \"function\" ? authorizationHeader : null;\n const hasAuthorization = authorizationHeader !== undefined && authorizationHeader !== null;\n const hasHeaders = headers !== undefined;\n const transformClient =\n getBaseUrl || hasAuthorization || hasHeaders\n ? HttpClient.mapRequest((request) =>\n applyPluginAtomClientRequestTransform(request, {\n ...(getBaseUrl ? { baseUrl: getBaseUrl } : {}),\n ...(getAuthorizationHeader\n ? { authorizationHeader: getAuthorizationHeader }\n : authorizationHeader !== undefined\n ? { authorizationHeader }\n : {}),\n ...(headers !== undefined ? { headers } : {}),\n }),\n )\n : undefined;\n\n return AtomHttpApi.Service<`Plugin_${G[\"identifier\"]}Client`>()(`Plugin_${pluginId}Client`, {\n api: bundle,\n httpClient: FetchHttpClient.layer,\n ...(staticBaseUrl !== undefined ? { baseUrl: staticBaseUrl } : {}),\n ...(transformClient ? { transformClient } : {}),\n });\n};\n\n// ---------------------------------------------------------------------------\n// ExecutorPluginsProvider + hooks — host-level distribution of the loaded\n// `ClientPluginSpec[]` via React context.\n//\n// The host wraps once at the root of its tree (typically reading from\n// `virtual:executor/plugins-client`); pages and shared components consume\n// via the focused hooks (`useIntegrationPlugins` etc.) so they don't import\n// from any host-app aggregator file. Pages stay portable across hosts —\n// the same component renders against whatever plugin set the surrounding\n// `<ExecutorPluginsProvider>` provides.\n//\n// Hooks throw if no provider is in scope so missing setup fails loudly;\n// matches the pattern of `useScope` / `useAuth` already in the codebase.\n// ---------------------------------------------------------------------------\n\ninterface ExecutorPluginsContextValue {\n readonly plugins: readonly ClientPluginSpec[];\n readonly integrationPlugins: readonly IntegrationPlugin[];\n readonly secretProviderPlugins: readonly SecretProviderPlugin[];\n}\n\nconst ExecutorPluginsContext = createContext<ExecutorPluginsContextValue | null>(null);\nExecutorPluginsContext.displayName = \"ExecutorPluginsContext\";\n\nexport interface ExecutorPluginsProviderProps {\n readonly plugins: readonly ClientPluginSpec[];\n readonly children: ReactNode;\n}\n\nexport function ExecutorPluginsProvider(\n props: ExecutorPluginsProviderProps,\n): ReturnType<typeof createElement> {\n const { plugins, children } = props;\n const value = useMemo<ExecutorPluginsContextValue>(\n () => ({\n plugins,\n integrationPlugins: plugins.flatMap((p) =>\n p.integrationPlugin ? [p.integrationPlugin] : [],\n ),\n secretProviderPlugins: plugins.flatMap((p) =>\n p.secretProviderPlugin ? [p.secretProviderPlugin] : [],\n ),\n }),\n [plugins],\n );\n // Kick off lazy chunk downloads for every integration plugin once the host\n // mounts, so navigating into an add/edit page doesn't suspend.\n useEffect(() => {\n for (const ip of value.integrationPlugins) ip.preload?.();\n }, [value.integrationPlugins]);\n return createElement(ExecutorPluginsContext.Provider, { value }, children);\n}\n\nconst usePluginsCtx = (hookName: string): ExecutorPluginsContextValue => {\n const ctx = useContext(ExecutorPluginsContext);\n if (!ctx) {\n // oxlint-disable-next-line executor/no-try-catch-or-throw, executor/no-error-constructor -- boundary: React hook invariant\n throw new Error(`${hookName} must be called inside an <ExecutorPluginsProvider>.`);\n }\n return ctx;\n};\n\n/** Full list of loaded `ClientPluginSpec` values. */\nexport const useClientPlugins = (): readonly ClientPluginSpec[] =>\n usePluginsCtx(\"useClientPlugins\").plugins;\n\n/** Integration plugins extracted from `clientPlugins[].integrationPlugin`. */\nexport const useIntegrationPlugins = (): readonly IntegrationPlugin[] =>\n usePluginsCtx(\"useIntegrationPlugins\").integrationPlugins;\n\n/** Secret-provider plugins extracted from `clientPlugins[].secretProviderPlugin`. */\nexport const useSecretProviderPlugins = (): readonly SecretProviderPlugin[] =>\n usePluginsCtx(\"useSecretProviderPlugins\").secretProviderPlugins;\n"],"mappings":"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","names":["HttpApi","AtomHttpApi"]}
package/dist/core.js CHANGED
@@ -4,6 +4,7 @@ import {
4
4
  import {
5
5
  DEFAULT_EXECUTOR_SERVER_ORIGIN,
6
6
  DEFAULT_EXECUTOR_SERVER_USERNAME,
7
+ EXECUTOR_ORG_SELECTOR_HEADER,
7
8
  InternalError,
8
9
  OAUTH_POPUP_MESSAGE_TYPE,
9
10
  apiBaseUrlForServerOrigin,
@@ -12,10 +13,8 @@ import {
12
13
  normalizeExecutorServerConnection,
13
14
  normalizeExecutorServerOrigin,
14
15
  originFromApiBaseUrl
15
- } from "./chunk-EJKXSREX.js";
16
+ } from "./chunk-DN5AKD4U.js";
16
17
  import {
17
- OAUTH2_PROVIDER_KEY,
18
- OAUTH2_SESSION_TTL_MS,
19
18
  ORG_SUBJECT,
20
19
  StorageError,
21
20
  TOOL_POLICY_ACTIONS,
@@ -56,7 +55,7 @@ import {
56
55
  textColumn,
57
56
  tool,
58
57
  toolAddress
59
- } from "./chunk-MYRPYTSV.js";
58
+ } from "./chunk-GUZHNTDQ.js";
60
59
  import {
61
60
  ConnectionNotFoundError,
62
61
  CredentialProviderNotRegisteredError,
@@ -70,6 +69,8 @@ import {
70
69
  IntegrationNotFoundError,
71
70
  IntegrationRemovalNotAllowedError,
72
71
  NoHandlerError,
72
+ OAUTH2_PROVIDER_KEY,
73
+ OAUTH2_SESSION_TTL_MS,
73
74
  OAuthCompleteError,
74
75
  OAuthProbeError,
75
76
  OAuthRegisterDynamicError,
@@ -82,10 +83,12 @@ import {
82
83
  ToolPolicyActionSchema,
83
84
  ToolSchemaView,
84
85
  UrlElicitation,
86
+ decodeOAuthCallbackState,
85
87
  effectivePolicyFromSorted,
88
+ encodeOAuthCallbackState,
86
89
  isValidPattern,
87
90
  matchPattern
88
- } from "./chunk-PCSRC6WP.js";
91
+ } from "./chunk-SNWDGE3G.js";
89
92
  import "./chunk-BBLMWFXN.js";
90
93
  import {
91
94
  AuthTemplateSlug,
@@ -305,6 +308,7 @@ export {
305
308
  Data2 as Data,
306
309
  DataMigrationError,
307
310
  DuplicateDataMigrationError,
311
+ EXECUTOR_ORG_SELECTOR_HEADER,
308
312
  Effect3 as Effect,
309
313
  ElicitationAction,
310
314
  ElicitationDeclinedError,
@@ -374,10 +378,12 @@ export {
374
378
  coreTables,
375
379
  createExecutor,
376
380
  dateColumn,
381
+ decodeOAuthCallbackState,
377
382
  defineExecutorConfig,
378
383
  definePlugin,
379
384
  definePluginStorageCollection,
380
385
  effectivePolicyFromSorted,
386
+ encodeOAuthCallbackState,
381
387
  executorOwnerPolicyName,
382
388
  executorUnscopedPolicyName,
383
389
  freshCustomAuthSlug,