@powerhousedao/reactor-workflow 6.2.3-dev.11

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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":["logger","asRecord","toNumber","logger","up","logger","logger","asRecord","connectionActions"],"sources":["../src/reactor/attachment-port.ts","../src/reactor/package-name.ts","../src/reactor/reactor-piece.ts","../src/reactor/output-tree.ts","../src/reactor/first-party-logos.ts","../src/reactor/unsupported-pieces.ts","../src/reactor/piece-catalog.ts","../src/reactor/local-catalog.ts","../src/reactor/block-search.ts","../src/reactor/reactor-port.ts","../src/reactor/run-scope.ts","../src/reactor/connector-id.ts","../src/reactor/lib.ts","../src/reactor/schedule.ts","../src/reactor/piece-store-port.ts","../src/reactor/secret-store.ts","../src/reactor/store.ts","../src/reactor/trigger-supervisor.ts","../src/reactor/webhook.ts","../src/reactor/piece-handshake.ts","../src/reactor/trigger-filters.ts","../src/reactor/service.ts","../src/reactor/workflow-triggers-read-model.ts"],"sourcesContent":["// Adapts the reactor's attachment client to the engine's AttachmentPort: both\n// directions go through the filesystem, so a step's bytes never cross the\n// worker's JSON IPC channel.\nimport type { AttachmentPort } from \"../pieces/index.js\";\nimport { FileTooLargeError, maxFileBytes } from \"../pieces/index.js\";\nimport { childLogger } from \"document-model\";\nimport { open, readFile, rm } from \"node:fs/promises\";\n\nconst logger = childLogger([\"workflow\", \"attachments\"]);\n\n// The slice of IAttachmentClient this needs, declared structurally so the\n// subgraph does not depend on the attachments package's types.\nexport interface AttachmentClientLike {\n upload(input: {\n file: Blob;\n fileName?: string;\n mimeType?: string;\n }): Promise<{ ref?: string } & Record<string, unknown>>;\n // Streamed rather than materialized: the size limit has to refuse an\n // oversized attachment before its bytes are in this process's memory.\n download(input: { documentId: string; ref: string }): Promise<{\n header: { sizeBytes?: number; mimeType?: string; fileName?: string };\n body: ReadableStream<Uint8Array>;\n }>;\n}\n\nfunction refOf(result: Record<string, unknown>): string {\n const direct = result.ref;\n if (typeof direct === \"string\") return direct;\n // Some client versions nest the reference under the reservation.\n const nested = (result.reservation as { ref?: unknown } | undefined)?.ref;\n if (typeof nested === \"string\") return nested;\n throw new Error(\"The attachment store returned no reference for the upload\");\n}\n\n// Writes the body out while counting it, so a stream that outgrows the limit\n// is cancelled mid-flight and its partial file removed.\nasync function writeCapped(\n body: ReadableStream<Uint8Array>,\n destPath: string,\n limit: number,\n): Promise<void> {\n const reader = body.getReader();\n const handle = await open(destPath, \"w\");\n let written = 0;\n try {\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n written += value.byteLength;\n if (written > limit) {\n await reader.cancel();\n throw new FileTooLargeError(written, limit);\n }\n await handle.write(value);\n }\n } catch (error) {\n await handle.close();\n await rm(destPath, { force: true });\n throw error;\n }\n await handle.close();\n}\n\nexport function createAttachmentPort(\n client: AttachmentClientLike,\n // Attachment reads are authorized against a document, and a step's refs come\n // from its own run journal: the workflow document is what vouches for them.\n documentIdFor: () => string | undefined,\n // Whether that document really references the ref. A step carries no caller,\n // so this relationship is all that stands between it and any known blob.\n canReadRef: (documentId: string, ref: string) => Promise<boolean>,\n): AttachmentPort {\n return {\n async read(ref, destPath) {\n const documentId = documentIdFor();\n if (!documentId) {\n throw new Error(\n `Cannot resolve ${ref}: no workflow document is in scope to authorize the read`,\n );\n }\n if (!(await canReadRef(documentId, ref))) {\n throw new Error(\n `Cannot resolve ${ref}: workflow document \"${documentId}\" does not reference it`,\n );\n }\n const limit = maxFileBytes();\n const { header, body } = await client.download({ documentId, ref });\n // The declared size refuses before a byte is read; writeCapped's own\n // count is what catches a header that understated the body.\n if (\n typeof header.sizeBytes === \"number\" &&\n Number.isFinite(header.sizeBytes) &&\n header.sizeBytes > limit\n ) {\n await body.cancel().catch(() => undefined);\n throw new FileTooLargeError(header.sizeBytes, limit);\n }\n await writeCapped(body, destPath, limit);\n const contentType =\n header.mimeType !== undefined && header.mimeType !== \"\"\n ? header.mimeType\n : undefined;\n return { fileName: header.fileName, contentType };\n },\n\n async write(file) {\n const bytes = await readFile(file.path);\n const result = await client.upload({\n file: new Blob([new Uint8Array(bytes)], {\n type: file.contentType ?? \"application/octet-stream\",\n }),\n fileName: file.fileName,\n mimeType: file.contentType,\n });\n const ref = refOf(result);\n logger.debug(`Ingested ${file.fileName} (${file.size} bytes) as ${ref}`);\n return ref;\n },\n };\n}\n","// The reactor package whose document models the runtime serves, and whose HTTP\n// namespace its webhook endpoints live under.\nexport const WORKFLOW_PACKAGE_NAME = \"@powerhousedao/workflow\";\n","// The block types of the piece this package ships.\n\n// The runtime knows these by name for two reasons only: the document triggers\n// are fired by the host rather than polled, and the output shape of a document\n// block depends on the model an author picked, which static piece metadata\n// cannot express. Everything else about them comes from the piece.\nexport const REACTOR_PIECE = \"@powerhousedao/piece-reactor\";\n\nfunction action(name: string): string {\n return `${REACTOR_PIECE}#${name}`;\n}\n\nfunction trigger(name: string): string {\n return `${REACTOR_PIECE}#trigger:${name}`;\n}\n\nexport const DOCUMENT_CREATE_BLOCK = action(\"document-create\");\nexport const DOCUMENT_DISPATCH_BLOCK = action(\"document-dispatch\");\nexport const DOCUMENT_GET_BLOCK = action(\"document-get\");\nexport const DOCUMENT_FIND_BLOCK = action(\"document-find\");\nexport const DOCUMENT_SCHEMA_BLOCK = action(\"document-schema\");\nexport const DOCUMENT_TYPES_BLOCK = action(\"document-types\");\n\nexport const DOCUMENT_EVENT_BLOCK = trigger(\"document-event\");\nexport const DOCUMENT_CREATED_BLOCK = trigger(\"document-created\");\nexport const DOCUMENT_DELETED_BLOCK = trigger(\"document-deleted\");\n\n// A design-time value that can actually be resolved: an expression cannot, so\n// a tree built from one falls back to the block's static shape.\nexport function staticString(value: unknown): string | undefined {\n if (typeof value !== \"string\") return undefined;\n const trimmed = value.trim();\n if (!trimmed || trimmed.includes(\"{{\")) return undefined;\n return trimmed;\n}\n","// Authored output shapes for the {} expression picker: document-model SDL,\n// piece outputSchema/sampleData, and static shapes for core blocks.\nimport {\n Kind,\n parse,\n type FieldDefinitionNode,\n type InputValueDefinitionNode,\n type TypeNode,\n} from \"graphql\";\n\nexport interface OutputTreeNode {\n name: string;\n // Display type, e.g. \"String!\", \"OID\", \"array\", \"string (sample)\".\n type: string;\n description?: string;\n children?: OutputTreeNode[];\n}\n\nexport interface OutputTree {\n source: \"schema\" | \"sample\" | \"static\" | \"none\";\n nodes: OutputTreeNode[];\n}\n\nconst MAX_DEPTH = 6;\n\nfunction typeName(node: TypeNode): { name: string; display: string } {\n switch (node.kind) {\n case Kind.NON_NULL_TYPE: {\n const inner = typeName(node.type);\n return { name: inner.name, display: `${inner.display}!` };\n }\n case Kind.LIST_TYPE: {\n const inner = typeName(node.type);\n return { name: inner.name, display: `[${inner.display}]` };\n }\n default:\n return { name: node.name.value, display: node.name.value };\n }\n}\n\ntype FieldNode = FieldDefinitionNode | InputValueDefinitionNode;\n\n// Field tree of `rootType` (object or input), recursing into types defined in\n// the same SDL; unknown/scalar types are leaves labeled by their display name.\nexport function fieldsFromSdl(\n sdl: string,\n rootType?: string,\n): OutputTreeNode[] {\n let definitions;\n try {\n definitions = parse(sdl).definitions;\n } catch {\n return [];\n }\n const types = new Map<string, readonly FieldNode[]>();\n let firstType: string | undefined;\n let stateType: string | undefined;\n for (const def of definitions) {\n if (\n def.kind !== Kind.OBJECT_TYPE_DEFINITION &&\n def.kind !== Kind.INPUT_OBJECT_TYPE_DEFINITION\n ) {\n continue;\n }\n const name = def.name.value;\n types.set(name, def.fields ?? []);\n firstType ??= name;\n if (name.endsWith(\"State\") && !name.endsWith(\"LocalState\")) {\n stateType ??= name;\n }\n }\n const root = rootType ?? stateType ?? firstType;\n if (!root) return [];\n\n const build = (name: string, depth: number): OutputTreeNode[] => {\n const fields = types.get(name);\n if (!fields || depth > MAX_DEPTH) return [];\n return fields.map((field) => {\n const { name: inner, display } = typeName(field.type);\n const children = build(inner, depth + 1);\n return {\n name: field.name.value,\n type: display,\n description: field.description?.value,\n ...(children.length > 0 ? { children } : {}),\n };\n });\n };\n return build(root, 0);\n}\n\ninterface ApOutputSchemaField {\n key?: string;\n label?: string;\n // Path into run()'s return value; defaults to key, \"\" means the whole output.\n value?: string;\n format?: string;\n description?: string;\n children?: ApOutputSchemaField[];\n properties?: ApOutputSchemaField[];\n listItems?: ApOutputSchemaField[];\n}\n\n// Nodes from separate fields can share a path prefix (a.b + a.c): merge them.\nfunction mergeNodes(nodes: OutputTreeNode[]): OutputTreeNode[] {\n const byName = new Map<string, OutputTreeNode>();\n for (const node of nodes) {\n const existing = byName.get(node.name);\n if (existing?.children && node.children) {\n existing.children = mergeNodes([...existing.children, ...node.children]);\n } else if (!byName.has(node.name)) {\n byName.set(node.name, node);\n }\n }\n return [...byName.values()];\n}\n\n// Activepieces action/trigger outputSchema → tree. Expression paths follow\n// each field's `value` (the real path into run()'s return), not its key.\nexport function fromOutputSchema(schema: unknown): OutputTreeNode[] {\n const fields = (schema as { fields?: ApOutputSchemaField[] } | null)?.fields;\n if (!Array.isArray(fields)) return [];\n const convert = (field: ApOutputSchemaField): OutputTreeNode[] => {\n const inner = field.children ?? field.properties;\n const items = field.listItems;\n const childNodes = mergeNodes((inner ?? items ?? []).flatMap(convert));\n const path =\n typeof field.value === \"string\" ? field.value : (field.key ?? \"\");\n // Whole-output field: hoist children; a scalar contributes no sub-path.\n if (path === \"\") return childNodes;\n const segments = path.split(\".\");\n let node: OutputTreeNode = {\n name: segments[segments.length - 1],\n type: items\n ? \"array\"\n : (field.format ?? (childNodes.length > 0 ? \"object\" : \"value\")),\n description: field.description,\n ...(childNodes.length > 0 ? { children: childNodes } : {}),\n };\n for (let i = segments.length - 2; i >= 0; i--) {\n node = { name: segments[i], type: \"object\", children: [node] };\n }\n return [node];\n };\n return mergeNodes(fields.flatMap(convert)).filter((node) => node.name);\n}\n\nexport function hasOutputSchemaFields(schema: unknown): boolean {\n const fields = (schema as { fields?: unknown[] } | null)?.fields;\n return Array.isArray(fields) && fields.length > 0;\n}\n\n// Piece-authored sampleData → tree; types inferred from the sample's values.\nexport function fromSample(value: unknown, depth = 0): OutputTreeNode[] {\n if (value === null || typeof value !== \"object\" || depth > MAX_DEPTH) {\n return [];\n }\n const entries = Array.isArray(value)\n ? value.slice(0, 1).map((item) => [\"0\", item] as const)\n : Object.entries(value as Record<string, unknown>);\n return entries.map(([name, child]) => {\n const kind = Array.isArray(child)\n ? \"array\"\n : child === null\n ? \"null\"\n : typeof child;\n const children = fromSample(child, depth + 1);\n return {\n name,\n type: kind,\n ...(children.length > 0 ? { children } : {}),\n };\n });\n}\n\nconst leaf = (name: string, type: string, description?: string) => ({\n name,\n type,\n ...(description ? { description } : {}),\n});\n\nexport const OPERATION_NODE: OutputTreeNode = {\n name: \"operation\",\n type: \"object\",\n children: [leaf(\"index\", \"Int!\"), leaf(\"timestampUtcMs\", \"String!\")],\n};\n\n// Envelope both document blocks return; state children come from the model.\nexport function documentBlockTree(\n stateChildren: OutputTreeNode[],\n): OutputTreeNode[] {\n return [\n leaf(\"documentId\", \"PHID!\"),\n leaf(\"documentType\", \"String!\"),\n leaf(\"name\", \"String\"),\n {\n name: \"state\",\n type: \"object\",\n description: \"Document global state after the actions applied\",\n ...(stateChildren.length > 0 ? { children: stateChildren } : {}),\n },\n ];\n}\n\nexport function documentGetTree(\n stateChildren: OutputTreeNode[],\n): OutputTreeNode[] {\n return [\n ...documentBlockTree(stateChildren).filter((node) => node.name !== \"state\"),\n leaf(\"slug\", \"String\"),\n {\n name: \"state\",\n type: \"object\",\n description: \"Document global state as read\",\n ...(stateChildren.length > 0 ? { children: stateChildren } : {}),\n },\n ];\n}\n\nexport function documentFindTree(): OutputTreeNode[] {\n return [\n leaf(\"count\", \"Int!\"),\n {\n name: \"documents\",\n type: \"array\",\n children: [\n leaf(\"documentId\", \"PHID!\"),\n leaf(\"documentType\", \"String!\"),\n leaf(\"name\", \"String\"),\n leaf(\"slug\", \"String\"),\n ],\n },\n ];\n}\n\nexport function documentTypesTree(): OutputTreeNode[] {\n return [\n leaf(\"count\", \"Int!\"),\n {\n name: \"types\",\n type: \"array\",\n children: [leaf(\"documentType\", \"String!\"), leaf(\"name\", \"String\")],\n },\n ];\n}\n\nexport function documentSchemaTree(): OutputTreeNode[] {\n return [\n leaf(\"documentType\", \"String!\"),\n leaf(\"name\", \"String\"),\n leaf(\"stateSchema\", \"String\", \"SDL of the global state type\"),\n {\n name: \"actions\",\n type: \"array\",\n description: \"Dispatchable actions with their input SDL\",\n children: [\n leaf(\"type\", \"String!\"),\n leaf(\"module\", \"String\"),\n leaf(\"inputSchema\", \"String\"),\n ],\n },\n ];\n}\n\nexport function lifecycleTriggerTree(): OutputTreeNode[] {\n return [\n leaf(\"documentId\", \"PHID!\"),\n leaf(\"documentType\", \"String\"),\n leaf(\"name\", \"String\", \"Set on creation only\"),\n leaf(\"driveId\", \"PHID\", \"Null for a document that belongs to no drive\"),\n leaf(\"parentId\", \"PHID\"),\n OPERATION_NODE,\n ];\n}\n\n// core#schedule payload; exactly one of cron / everyMs is present.\nexport function scheduleTriggerTree(): OutputTreeNode[] {\n return [\n leaf(\"scheduledFor\", \"DateTime!\", \"The slot that came due (ISO 8601)\"),\n leaf(\"firedAt\", \"DateTime!\", \"When the run actually started\"),\n leaf(\"timezone\", \"String!\"),\n leaf(\"cron\", \"String\", \"Cron mode only\"),\n leaf(\"everyMs\", \"Int\", \"Interval mode only\"),\n ];\n}\n\n// core#webhook payload: Activepieces' catch-webhook shape. Headers and query\n// are open maps, so they stay leaves the author addresses by name.\nexport function webhookTriggerTree(): OutputTreeNode[] {\n return [\n leaf(\"method\", \"String!\", \"Uppercase HTTP method\"),\n leaf(\"path\", \"String!\"),\n leaf(\"headers\", \"JSONObject!\", \"Lowercased names; credentials redacted\"),\n leaf(\"queryParams\", \"JSONObject!\"),\n leaf(\"body\", \"Unknown\", \"Parsed JSON or form fields; text otherwise\"),\n ];\n}\n\nexport function documentEventTree(\n actionInputChildren: OutputTreeNode[],\n): OutputTreeNode[] {\n return [\n leaf(\"documentId\", \"PHID!\"),\n leaf(\"documentType\", \"String!\"),\n leaf(\"branch\", \"String!\"),\n leaf(\"scope\", \"String!\"),\n {\n name: \"action\",\n type: \"object\",\n children: [\n leaf(\"type\", \"String!\"),\n {\n name: \"input\",\n type: \"object\",\n ...(actionInputChildren.length > 0\n ? { children: actionInputChildren }\n : {}),\n },\n ],\n },\n OPERATION_NODE,\n ];\n}\n","// Logos for pieces we publish ourselves, inlined the way the editor shim\n// already inlines the core piece: a first-party piece has no entry on the\n// Activepieces logo CDN, and the catalog is served to the browser.\nexport const PAPERLESS_LOGO =\n \"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA0OCA0OCI+PHJlY3Qgd2lkdGg9IjQ4IiBoZWlnaHQ9IjQ4IiByeD0iOCIgZmlsbD0iIzE3NTQxZiIvPjxwYXRoIGQ9Ik0xNCAxMGgxM2w3IDd2MjFhMiAyIDAgMCAxLTIgMkgxNmEyIDIgMCAwIDEtMi0yVjEyYTIgMiAwIDAgMSAyLTJ6IiBmaWxsPSIjZmZmIi8+PHBhdGggZD0iTTI3IDEwbDcgN2gtN3oiIGZpbGw9IiM5ZmQzYTYiLz48ZyBmaWxsPSIjMTc1NDFmIj48cmVjdCB4PSIxOCIgeT0iMjIiIHdpZHRoPSIxNiIgaGVpZ2h0PSIyIiByeD0iMSIvPjxyZWN0IHg9IjE4IiB5PSIyNyIgd2lkdGg9IjE2IiBoZWlnaHQ9IjIiIHJ4PSIxIi8+PHJlY3QgeD0iMTgiIHk9IjMyIiB3aWR0aD0iMTAiIGhlaWdodD0iMiIgcng9IjEiLz48L2c+PC9zdmc+\";\n","// Pieces whose ACTIONS only run inside the Activepieces platform (ctx.server\n// AI proxy, or platform agents/todos/tables/flows APIs). Hidden everywhere.\nexport const SERVER_ONLY_PIECES = new Set<string>([\n // Platform AI proxy (v1/ai-providers): no own auth, keys live server-side.\n \"@activepieces/piece-ai\",\n \"@activepieces/piece-text-ai\",\n \"@activepieces/piece-image-ai\",\n \"@activepieces/piece-utility-ai\",\n // AI proxy + platform agents API (ctx.agent.tools).\n \"@activepieces/piece-agent\",\n // Platform-feature APIs: todos, tables, calling other platform flows.\n \"@activepieces/piece-todos\",\n \"@activepieces/piece-tables\",\n \"@activepieces/piece-subflows\",\n]);\n","// Piece catalog proxied from the Activepieces public metadata API — the same\n// source their piece selector uses. Bundles themselves load lazily on use.\n\nimport type {\n ActionBase,\n PieceMetadataModel,\n TriggerBase,\n} from \"@powerhousedao/pieces-framework\";\nimport { PAPERLESS_LOGO } from \"./first-party-logos.js\";\nimport { SERVER_ONLY_PIECES } from \"./unsupported-pieces.js\";\n\nconst CATALOG_URL = \"https://cloud.activepieces.com/api/v1/pieces\";\nconst CACHE_TTL_MS = 60 * 60 * 1000;\n\n// Their piece endpoints default to audience=human, which hides actions tagged\n// audience: \"ai\" -- atomics added for agents that would clutter their flow\n// builder (activepieces/activepieces#13960). We want the whole surface, the\n// way their own non-builder callers ask for it.\nfunction aiLast(audience: string | null): number {\n return audience === \"ai\" ? 1 : 0;\n}\n\nfunction pieceUrl(packageName: string): string {\n return `${CATALOG_URL}/${packageName}?audience=all`;\n}\n\nexport interface PieceSummary {\n name: string;\n displayName: string;\n description: string;\n logoUrl: string;\n version: string;\n actionCount: number;\n triggerCount: number;\n categories: string[];\n // The piece's PieceAuth descriptor, verbatim; null when authless.\n auth: unknown;\n}\n\nexport interface PieceActionEntry {\n name: string;\n displayName: string;\n description: string;\n blockType: string;\n // \"human\" | \"ai\" | \"both\"; absent on most pieces, which means \"both\".\n audience: string | null;\n}\n\nexport interface PieceActionsResult {\n name: string;\n displayName: string;\n version: string;\n actions: PieceActionEntry[];\n auth: unknown;\n}\n\nexport interface PieceTriggerEntry {\n name: string;\n displayName: string;\n description: string;\n strategy: string;\n blockType: string;\n}\n\nexport interface PieceTriggersResult {\n name: string;\n displayName: string;\n version: string;\n triggers: PieceTriggerEntry[];\n auth: unknown;\n}\n\n// An untrusted HTTP response in the shape of their own metadata types, so every\n// field is optional and the closed enums stay widened to string.\ntype CatalogEntry = Partial<\n Pick<\n PieceMetadataModel,\n \"name\" | \"displayName\" | \"description\" | \"logoUrl\" | \"version\"\n >\n> & {\n actions?: number | Record<string, PieceDetailAction>;\n triggers?: number | Record<string, PieceDetailTrigger>;\n categories?: string[];\n auth?: unknown;\n};\n\ntype PieceDetailAction = Partial<\n Pick<ActionBase, \"name\" | \"displayName\" | \"description\">\n> & {\n // Their discovery filter: \"ai\" marks agent-targeted atomics.\n audience?: string;\n};\n\ntype PieceDetailTrigger = Partial<\n Pick<TriggerBase, \"name\" | \"displayName\" | \"description\">\n> & {\n // POLLING | WEBHOOK | APP_WEBHOOK; runtime support varies by strategy.\n type?: string;\n};\n\n// List entry with suggestionType=ACTION_AND_TRIGGER: the same list endpoint\n// their selector searches, carrying every action/trigger name inline.\nexport interface CatalogSuggestionEntry {\n name?: string;\n displayName?: string;\n version?: string;\n logoUrl?: string;\n suggestedActions?: PieceDetailAction[];\n suggestedTriggers?: PieceDetailTrigger[];\n}\n\ninterface Cached<T> {\n value: T;\n expiresAt: number;\n}\n\nasync function fetchJson(url: string, timeoutMs = 30_000): Promise<unknown> {\n const response = await fetch(url, { signal: AbortSignal.timeout(timeoutMs) });\n if (!response.ok) {\n throw new Error(`${url} responded ${response.status}`);\n }\n return response.json();\n}\n\n// ~17 MB for the whole catalog; fetched once per index build, never cached\n// here (block-search keeps the compact index instead).\nexport async function fetchCatalogWithSuggestions(): Promise<\n CatalogSuggestionEntry[]\n> {\n const raw = await fetchJson(\n `${CATALOG_URL}?suggestionType=ACTION_AND_TRIGGER`,\n 120_000,\n );\n return Array.isArray(raw) ? (raw as CatalogSuggestionEntry[]) : [];\n}\n\nlet catalogCache: Cached<PieceSummary[]> | undefined;\n\n// First-party pieces not (yet) listed by the cloud catalog. After upstream\n// publication the cloud entry wins (short-name dedupe below), so remove the\n// entry from here at that point.\nconst FIRST_PARTY_PIECES: PieceSummary[] = [\n {\n name: \"@powerhousedao/piece-paperless-ngx\",\n displayName: \"Paperless-ngx\",\n description:\n \"Manage documents in a self-hosted paperless-ngx archive: upload, search, tag, and react to new documents.\",\n // Data URI, since a first-party piece has no logo on their CDN.\n logoUrl: PAPERLESS_LOGO,\n version: \"0.1.0\",\n actionCount: 9,\n triggerCount: 2,\n categories: [\"CONTENT_AND_FILES\"],\n auth: {\n type: \"CUSTOM_AUTH\",\n displayName: \"paperless-ngx\",\n required: true,\n props: {\n base_url: {\n type: \"SHORT_TEXT\",\n displayName: \"Base URL\",\n required: true,\n description:\n \"e.g. https://paperless.example.com — no trailing slash, no /api suffix\",\n },\n token: {\n type: \"SECRET_TEXT\",\n displayName: \"API Token\",\n required: true,\n description: \"paperless web UI -> My Profile -> API Token\",\n },\n },\n },\n },\n {\n name: \"@powerhousedao/piece-docling\",\n displayName: \"Docling\",\n description:\n \"Convert documents (PDF, DOCX, PPTX, images, HTML, …) to Markdown, docling-document JSON, HTML, DocTags and plain text via a docling-serve v1 API (self-hosted or Docling for IBM watsonx).\",\n logoUrl:\n \"data:image/svg+xml,\" +\n encodeURIComponent(\n '<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 48 48\"><rect width=\"48\" height=\"48\" rx=\"10\" fill=\"#1e3a8a\"/><path d=\"M14 10h14l8 8v20a2 2 0 0 1-2 2H14a2 2 0 0 1-2-2V12a2 2 0 0 1 2-2z\" fill=\"#fff\"/><path d=\"M28 10v8h8\" fill=\"none\" stroke=\"#1e3a8a\" stroke-width=\"2\"/><path d=\"M18 24h12M18 29h12M18 34h8\" stroke=\"#1e3a8a\" stroke-width=\"2\"/></svg>',\n ),\n version: \"1.0.0\",\n actionCount: 6,\n triggerCount: 0,\n categories: [\"CONTENT_AND_FILES\"],\n // Mirrors the piece's PieceAuth descriptor (the shape the connection\n // editor's planFromAuth consumes).\n auth: {\n type: \"CUSTOM_AUTH\",\n displayName: \"Docling Serve\",\n required: true,\n props: {\n base_url: {\n type: \"SHORT_TEXT\",\n displayName: \"Service URL\",\n required: true,\n },\n api_key: {\n type: \"SECRET_TEXT\",\n displayName: \"API Key\",\n required: false,\n },\n },\n },\n },\n];\n\n// Test-only: the module caches the catalog for CACHE_TTL_MS.\nexport function __resetCatalogCacheForTests(): void {\n catalogCache = undefined;\n}\n\nexport async function fetchPieceCatalog(): Promise<PieceSummary[]> {\n if (catalogCache && catalogCache.expiresAt > Date.now()) {\n return catalogCache.value;\n }\n const raw = (await fetchJson(CATALOG_URL)) as CatalogEntry[];\n const cloud = raw\n .filter(\n (entry) =>\n typeof entry.name === \"string\" &&\n typeof entry.version === \"string\" &&\n !SERVER_ONLY_PIECES.has(entry.name) &&\n ((typeof entry.actions === \"number\" && entry.actions > 0) ||\n (typeof entry.triggers === \"number\" && entry.triggers > 0)),\n )\n .map((entry) => ({\n name: entry.name!,\n displayName: entry.displayName ?? entry.name!,\n description: entry.description ?? \"\",\n logoUrl: entry.logoUrl ?? \"\",\n version: entry.version!,\n actionCount: typeof entry.actions === \"number\" ? entry.actions : 0,\n triggerCount: typeof entry.triggers === \"number\" ? entry.triggers : 0,\n categories: entry.categories ?? [],\n auth: entry.auth ?? null,\n }));\n // First-party pieces the cloud catalog doesn't carry yet; the cloud wins on\n // short-name collisions (once upstream publishes the same piece).\n const shortName = (n: string) => n.slice(n.lastIndexOf(\"/\") + 1);\n const cloudShorts = new Set(cloud.map((e) => shortName(e.name)));\n const value = [\n ...cloud,\n ...FIRST_PARTY_PIECES.filter((p) => !cloudShorts.has(shortName(p.name))),\n ].sort((a, b) => a.displayName.localeCompare(b.displayName));\n catalogCache = { value, expiresAt: Date.now() + CACHE_TTL_MS };\n return value;\n}\n\nconst detailCache = new Map<string, Cached<unknown>>();\n\n// Full piece detail, verbatim from the cloud API (PieceMetadataModel-shaped).\nexport async function fetchPieceDetail(packageName: string): Promise<unknown> {\n const cached = detailCache.get(packageName);\n if (cached && cached.expiresAt > Date.now()) return cached.value;\n const value = await fetchJson(pieceUrl(packageName));\n detailCache.set(packageName, { value, expiresAt: Date.now() + CACHE_TTL_MS });\n return value;\n}\n\nconst triggersCache = new Map<string, Cached<PieceTriggersResult>>();\n\nexport async function fetchPieceTriggers(\n packageName: string,\n): Promise<PieceTriggersResult> {\n const cached = triggersCache.get(packageName);\n if (cached && cached.expiresAt > Date.now()) return cached.value;\n const detail = (await fetchJson(pieceUrl(packageName))) as CatalogEntry;\n const version = detail.version ?? \"\";\n const triggersRecord =\n detail.triggers && typeof detail.triggers === \"object\"\n ? detail.triggers\n : {};\n const triggers = Object.entries(triggersRecord).map(([name, trigger]) => ({\n name,\n displayName: trigger.displayName ?? name,\n description: trigger.description ?? \"\",\n strategy: trigger.type ?? \"\",\n blockType: `${packageName}@${version}#trigger:${name}`,\n }));\n const value: PieceTriggersResult = {\n name: packageName,\n displayName: detail.displayName ?? packageName,\n version,\n triggers,\n auth: detail.auth ?? null,\n };\n triggersCache.set(packageName, {\n value,\n expiresAt: Date.now() + CACHE_TTL_MS,\n });\n return value;\n}\n\nconst actionsCache = new Map<string, Cached<PieceActionsResult>>();\n\nexport async function fetchPieceActions(\n packageName: string,\n): Promise<PieceActionsResult> {\n const cached = actionsCache.get(packageName);\n if (cached && cached.expiresAt > Date.now()) return cached.value;\n const detail = (await fetchJson(pieceUrl(packageName))) as CatalogEntry;\n const version = detail.version ?? \"\";\n const actionsRecord =\n detail.actions && typeof detail.actions === \"object\" ? detail.actions : {};\n const actions = Object.entries(actionsRecord)\n .map(([name, action]) => ({\n name,\n displayName: action.displayName ?? name,\n description: action.description ?? \"\",\n blockType: `${packageName}@${version}#${name}`,\n audience: action.audience ?? null,\n }))\n // Agent-targeted atomics last, so the actions a person would pick stay at\n // the top. Same predicate their own human view filters on, and an absent\n // audience counts as human-visible.\n .sort((a, b) => aiLast(a.audience) - aiLast(b.audience));\n const value: PieceActionsResult = {\n name: packageName,\n displayName: detail.displayName ?? packageName,\n version,\n actions,\n auth: detail.auth ?? null,\n };\n actionsCache.set(packageName, {\n value,\n expiresAt: Date.now() + CACHE_TTL_MS,\n });\n return value;\n}\n","// A package piece as the editor's catalog sees it, read from the piece itself.\n\n// A published piece is described by a listing the cloud API serves; one that\n// ships inside a reactor package has no listing, so its descriptor — built in\n// the worker from the piece module — is the listing.\nimport type { PieceDescriptor } from \"../pieces/index.js\";\nimport type { BlockSearchHit } from \"./block-search.js\";\nimport type {\n PieceActionsResult,\n PieceSummary,\n PieceTriggersResult,\n} from \"./piece-catalog.js\";\n\n// Block types of a package piece carry no version. The copy this reactor\n// installed is the one that runs, so an upgrade must not orphan the workflows\n// that name it — the registry answers with the installed version instead.\nexport function localBlockType(\n pieceName: string,\n name: string,\n kind: \"action\" | \"trigger\",\n): string {\n return kind === \"trigger\"\n ? `${pieceName}#trigger:${name}`\n : `${pieceName}#${name}`;\n}\n\nexport function catalogEntry(\n descriptor: PieceDescriptor,\n pieceName: string,\n version: string,\n): PieceSummary {\n return {\n name: pieceName,\n displayName: descriptor.displayName || pieceName,\n description: descriptor.description ?? \"\",\n logoUrl: descriptor.logoUrl ?? \"\",\n version,\n actionCount: descriptor.actions.length,\n triggerCount: descriptor.triggers.length,\n categories: descriptor.categories ?? [],\n auth: descriptor.auth ?? null,\n };\n}\n\nexport function actionsResult(\n descriptor: PieceDescriptor,\n pieceName: string,\n version: string,\n): PieceActionsResult {\n return {\n name: pieceName,\n displayName: descriptor.displayName || pieceName,\n version,\n actions: descriptor.actions.map((action) => ({\n name: action.name,\n displayName: action.displayName,\n description: action.description ?? \"\",\n blockType: localBlockType(pieceName, action.name, \"action\"),\n // The cloud's discovery filter; a package piece declares no audience,\n // and an absent one already counts as human-visible everywhere.\n audience: null,\n })),\n auth: descriptor.auth ?? null,\n };\n}\n\nexport function triggersResult(\n descriptor: PieceDescriptor,\n pieceName: string,\n version: string,\n): PieceTriggersResult {\n return {\n name: pieceName,\n displayName: descriptor.displayName || pieceName,\n version,\n triggers: descriptor.triggers.map((trigger) => ({\n name: trigger.name,\n displayName: trigger.displayName,\n description: trigger.description ?? \"\",\n strategy: trigger.strategy,\n blockType: localBlockType(pieceName, trigger.name, \"trigger\"),\n })),\n auth: descriptor.auth ?? null,\n };\n}\n\n// The piece's blocks as search hits, so a block the reactor ships is findable\n// whether or not the published catalog answered.\nexport function localSearchHits(\n descriptor: PieceDescriptor,\n pieceName: string,\n): BlockSearchHit[] {\n const pieceDisplayName = descriptor.displayName || pieceName;\n const logoUrl = descriptor.logoUrl ?? \"\";\n return [\n ...descriptor.actions.map((action) => ({\n blockType: localBlockType(pieceName, action.name, \"action\"),\n pieceName,\n pieceDisplayName,\n logoUrl,\n displayName: action.displayName,\n description: action.description ?? \"\",\n kind: \"action\" as const,\n strategy: null,\n })),\n ...descriptor.triggers.map((trigger) => ({\n blockType: localBlockType(pieceName, trigger.name, \"trigger\"),\n pieceName,\n pieceDisplayName,\n logoUrl,\n displayName: trigger.displayName,\n description: trigger.description ?? \"\",\n kind: \"trigger\" as const,\n strategy: trigger.strategy,\n })),\n ];\n}\n\n// The PieceMetadataModel shape the editor's detail query expects: actions and\n// triggers keyed by name. Output schemas are absent because a descriptor does\n// not carry them — a caller reading one treats that as \"not authored\".\nexport function detailResult(\n descriptor: PieceDescriptor,\n pieceName: string,\n version: string,\n): Record<string, unknown> {\n return {\n name: pieceName,\n displayName: descriptor.displayName || pieceName,\n description: descriptor.description ?? \"\",\n logoUrl: descriptor.logoUrl ?? \"\",\n version,\n categories: descriptor.categories ?? [],\n auth: descriptor.auth ?? null,\n actions: Object.fromEntries(\n descriptor.actions.map((action) => [\n action.name,\n {\n name: action.name,\n displayName: action.displayName,\n description: action.description ?? \"\",\n props: action.props,\n requireAuth: action.requireAuth,\n },\n ]),\n ),\n triggers: Object.fromEntries(\n descriptor.triggers.map((trigger) => [\n trigger.name,\n {\n name: trigger.name,\n displayName: trigger.displayName,\n description: trigger.description ?? \"\",\n type: trigger.strategy,\n props: trigger.props,\n requireAuth: trigger.requireAuth,\n },\n ]),\n ),\n };\n}\n","// Action/trigger name search over the whole catalog. The index is built\n// lazily from one list request (suggestionType=ACTION_AND_TRIGGER) and cached.\nimport {\n fetchCatalogWithSuggestions,\n type CatalogSuggestionEntry,\n} from \"./piece-catalog.js\";\nimport { SERVER_ONLY_PIECES } from \"./unsupported-pieces.js\";\n\nexport type BlockSearchKind = \"action\" | \"trigger\";\n\nexport interface BlockSearchHit {\n blockType: string;\n pieceName: string;\n pieceDisplayName: string;\n logoUrl: string;\n displayName: string;\n description: string;\n kind: BlockSearchKind;\n // Triggers only: POLLING | WEBHOOK | APP_WEBHOOK.\n strategy: string | null;\n}\n\nexport type BlockSearchStatus = \"ready\" | \"indexing\" | \"error\";\n\nexport interface BlockSearchResult {\n status: BlockSearchStatus;\n hits: BlockSearchHit[];\n // Number of pieces the index covers; 0 while indexing.\n indexedPieces: number;\n error: string | null;\n}\n\ninterface IndexEntry {\n hit: BlockSearchHit;\n // Lower-cased searchable text, in ranking order.\n name: string;\n description: string;\n piece: string;\n}\n\nexport interface BlockSearchIndex {\n entries: IndexEntry[];\n pieces: number;\n}\n\nconst INDEX_TTL_MS = 60 * 60 * 1000;\nconst DEFAULT_LIMIT = 30;\nconst MAX_LIMIT = 100;\n\nexport function buildSearchIndex(\n raw: CatalogSuggestionEntry[],\n): BlockSearchIndex {\n const entries: IndexEntry[] = [];\n let pieces = 0;\n for (const entry of raw) {\n if (\n typeof entry.name !== \"string\" ||\n typeof entry.version !== \"string\" ||\n SERVER_ONLY_PIECES.has(entry.name)\n ) {\n continue;\n }\n const pieceName = entry.name;\n const pieceDisplayName = entry.displayName ?? pieceName;\n const logoUrl = entry.logoUrl ?? \"\";\n const push = (\n kind: BlockSearchKind,\n item: {\n name?: string;\n displayName?: string;\n description?: string;\n type?: string;\n },\n ) => {\n if (typeof item.name !== \"string\" || item.name === \"\") return;\n const displayName = item.displayName ?? item.name;\n const description = item.description ?? \"\";\n entries.push({\n hit: {\n blockType:\n kind === \"trigger\"\n ? `${pieceName}@${entry.version}#trigger:${item.name}`\n : `${pieceName}@${entry.version}#${item.name}`,\n pieceName,\n pieceDisplayName,\n logoUrl,\n displayName,\n description,\n kind,\n strategy: kind === \"trigger\" ? (item.type ?? null) : null,\n },\n name: `${displayName} ${item.name}`.toLowerCase(),\n description: description.toLowerCase(),\n piece: pieceDisplayName.toLowerCase(),\n });\n };\n for (const action of entry.suggestedActions ?? []) push(\"action\", action);\n for (const trigger of entry.suggestedTriggers ?? [])\n push(\"trigger\", trigger);\n pieces += 1;\n }\n return { entries, pieces };\n}\n\n// Pieces a reactor package ships, indexed the same way. They are handed in\n// rather than fetched: the catalog API has never heard of them.\nexport function indexFromHits(hits: BlockSearchHit[]): BlockSearchIndex {\n const pieces = new Set<string>();\n const entries = hits.map((hit) => {\n pieces.add(hit.pieceName);\n return {\n hit,\n name: `${hit.displayName} ${hit.blockType.split(\"#\").pop() ?? \"\"}`.toLowerCase(),\n description: hit.description.toLowerCase(),\n piece: hit.pieceDisplayName.toLowerCase(),\n };\n });\n return { entries, pieces: pieces.size };\n}\n\n// A piece this reactor installed wins its own name, the way it does in the\n// catalog: listing both would offer a versioned published block beside the\n// installed one, and picking the published block would bypass the copy that\n// actually runs.\nfunction merge(\n index: BlockSearchIndex | undefined,\n local: BlockSearchIndex | undefined,\n): BlockSearchIndex {\n const localEntries = local?.entries ?? [];\n const localNames = new Set(localEntries.map((entry) => entry.hit.pieceName));\n const published = (index?.entries ?? []).filter(\n (entry) => !localNames.has(entry.hit.pieceName),\n );\n const shadowed = new Set(\n (index?.entries ?? [])\n .map((entry) => entry.hit.pieceName)\n .filter((name) => localNames.has(name)),\n );\n return {\n entries: [...localEntries, ...published],\n // Each package counted once, so the total says how many pieces were\n // searched rather than how many listings were merged.\n pieces: (local?.pieces ?? 0) + (index?.pieces ?? 0) - shadowed.size,\n };\n}\n\n// Every query token must appear somewhere; hits rank by where the first\n// token lands: name prefix, then name, then piece name, then description.\nexport function searchIndex(\n index: BlockSearchIndex,\n query: string,\n limit = DEFAULT_LIMIT,\n): BlockSearchHit[] {\n const tokens = query.toLowerCase().split(/\\s+/).filter(Boolean);\n if (tokens.length === 0) return [];\n const scored: { score: number; entry: IndexEntry }[] = [];\n for (const entry of index.entries) {\n const haystack = `${entry.name} ${entry.piece} ${entry.description}`;\n if (!tokens.every((token) => haystack.includes(token))) continue;\n const first = tokens[0];\n const score = entry.name.startsWith(first)\n ? 0\n : entry.name.includes(first)\n ? 1\n : entry.piece.includes(first)\n ? 2\n : 3;\n scored.push({ score, entry });\n }\n scored.sort(\n (a, b) =>\n a.score - b.score ||\n a.entry.hit.displayName.localeCompare(b.entry.hit.displayName),\n );\n return scored\n .slice(0, Math.min(Math.max(limit, 1), MAX_LIMIT))\n .map(({ entry }) => entry.hit);\n}\n\ninterface CachedIndex {\n promise: Promise<BlockSearchIndex>;\n value?: BlockSearchIndex;\n error?: string;\n expiresAt: number;\n}\n\nlet cached: CachedIndex | undefined;\n\nfunction ensureIndex(): CachedIndex {\n if (cached && cached.expiresAt > Date.now() && !cached.error) return cached;\n const entry: CachedIndex = {\n promise: fetchCatalogWithSuggestions().then(buildSearchIndex),\n expiresAt: Date.now() + INDEX_TTL_MS,\n };\n entry.promise.then(\n (value) => {\n entry.value = value;\n },\n (error: unknown) => {\n entry.error = error instanceof Error ? error.message : String(error);\n },\n );\n cached = entry;\n return entry;\n}\n\n// Never blocks on the index build: callers poll while status is \"indexing\".\n\n// The status describes the published catalog alone, because that is the half\n// that can be slow or unreachable. Local pieces are searched either way, so a\n// reactor with no network still finds the blocks it ships.\nexport function searchBlocks(\n query: string,\n limit?: number,\n local?: BlockSearchIndex,\n): BlockSearchResult {\n const index = ensureIndex();\n if (index.error) {\n const message = index.error;\n // Drop the failed build so the next call retries.\n cached = undefined;\n return {\n status: \"error\",\n hits: searchIndex(merge(undefined, local), query, limit),\n indexedPieces: local?.pieces ?? 0,\n error: message,\n };\n }\n if (!index.value) {\n return {\n status: \"indexing\",\n hits: searchIndex(merge(undefined, local), query, limit),\n indexedPieces: local?.pieces ?? 0,\n error: null,\n };\n }\n const merged = merge(index.value, local);\n return {\n status: \"ready\",\n hits: searchIndex(merged, query, limit),\n indexedPieces: merged.pieces,\n error: null,\n };\n}\n\n// Test seam.\nexport function resetBlockSearchIndex(): void {\n cached = undefined;\n}\n","// The host's half of `ctx.reactor`: the operations a package piece asks for,\n// run against this reactor through the subgraph's client.\n\n// Everything here is what could not cross the worker boundary — model modules\n// and their factories, drive nodes, a PHDocument's operations — so the piece\n// keeps the block's own semantics and the reactor stays on this side of it.\nimport type { WorkflowCaller, WorkflowRuntimeHostDeps } from \"./host.js\";\nimport type {\n ReactorCreateInput,\n ReactorDocumentSummary,\n ReactorExecuteInput,\n ReactorFindInput,\n ReactorModelDetail,\n ReactorModelSummary,\n ReactorPort,\n} from \"../pieces/index.js\";\nimport { createAction, type Action, type PHDocument } from \"document-model\";\n\nconst DRIVE_DOCUMENT_TYPE = \"powerhouse/document-drive\";\nconst DRIVE_DOCUMENT_TYPES = new Set([\n DRIVE_DOCUMENT_TYPE,\n \"powerhouse/reactor-drive\",\n]);\n\n// The index rejects an empty filter, so a typeless sweep asks per type; this\n// caps what each one contributes before the caller slices.\nconst FIND_PAGE_LIMIT = 100;\n\n// Design time resolves options for an editor, never edits documents: a piece\n// asking to write there is refused rather than authorized.\nconst DESIGN_TIME_WRITES_REFUSED =\n \"Reactor writes are not available while resolving design-time options\";\n\nconst DESIGN_TIME_CALLER_REQUIRED =\n \"Design-time reactor access requires an authenticated request\";\n\n// Base actions every document type accepts, beyond its model's own.\nconst BASE_ACTIONS = [\n {\n type: \"SET_NAME\",\n module: \"base\",\n inputSchema: \"input SetNameInput {\\n name: String!\\n}\",\n },\n];\n\ninterface DriveTarget {\n driveId: string;\n parentFolder?: string;\n}\n\n// The value at a dotted path inside a document's global state. Anything that\n// is not a plain object on the way down ends the walk: a path into a scalar is\n// a mismatch, not an error, because the documents being filtered are of one\n// type only by convention and the step cannot know every shape it will meet.\nfunction stateValueAt(document: PHDocument, path: string): unknown {\n const globalState = (document.state as Record<string, unknown>).global;\n let current: unknown = globalState;\n for (const segment of path.split(\".\")) {\n if (typeof current !== \"object\" || current === null) return undefined;\n current = (current as Record<string, unknown>)[segment];\n }\n return current;\n}\n\n// Compared as strings, so a step whose value came from an expression matches a\n// number in state: every expression resolves to text by the time it reaches\n// here, and `\"42\" !== 42` would make the match silently impossible.\nexport function matchesState(\n document: PHDocument,\n match: { path: string; value: string } | undefined,\n): boolean {\n if (!match) return true;\n const value = stateValueAt(document, match.path);\n if (typeof value === \"string\") return value === match.value;\n // Only the scalars a state field plausibly holds. A path landing on an\n // object, an array or nothing is a mismatch rather than an error — the\n // documents being filtered share a type only by convention, and the step\n // cannot know every shape it will meet.\n if (\n typeof value === \"number\" ||\n typeof value === \"boolean\" ||\n typeof value === \"bigint\"\n ) {\n return String(value) === match.value;\n }\n return false;\n}\n\nexport function documentSummary(\n document: PHDocument,\n withState: boolean,\n): ReactorDocumentSummary {\n const globalState = (document.state as Record<string, unknown>).global;\n const stateName =\n globalState && typeof globalState === \"object\"\n ? (globalState as Record<string, unknown>).name\n : undefined;\n return {\n documentId: document.header.id,\n documentType: document.header.documentType,\n // Models usually keep the display name in state; header name can lag.\n name:\n (typeof stateName === \"string\" && stateName) ||\n document.header.name ||\n \"\",\n slug: document.header.slug,\n ...(withState ? { state: globalState } : {}),\n };\n}\n\n// Reducer failures don't reject execute(); they land on the operations. Fail\n// the call when any of the freshly appended operations carries an error.\nfunction assertOperationsApplied(document: PHDocument, count: number): void {\n const operations = Object.values(document.operations).flat();\n const recent = operations\n .sort((a, b) => a.index - b.index)\n .slice(-Math.max(count, 1));\n const failed = recent.find((operation) => operation.error !== undefined);\n if (failed) {\n throw new Error(\n `Action ${failed.action.type} failed: ${failed.error ?? \"unknown error\"}`,\n );\n }\n}\n\nexport class SubgraphReactorPort implements ReactorPort {\n constructor(private readonly host: WorkflowRuntimeHostDeps) {}\n\n private get client() {\n return this.host.reactorClient;\n }\n\n async models(): Promise<ReactorModelSummary[]> {\n const page = await this.client.getDocumentModelModules();\n return page.results\n .map((module) => module.documentModel.global)\n .map((model) => ({ documentType: model.id, name: model.name }))\n .filter((entry) => entry.documentType)\n .sort((a, b) => a.documentType.localeCompare(b.documentType));\n }\n\n async model(documentType: string): Promise<ReactorModelDetail> {\n const module = await this.client.getDocumentModelModule(documentType);\n const model = module.documentModel.global;\n const latest = model.specifications.at(-1);\n return {\n documentType,\n name: model.name,\n stateSchema: latest?.state.global.schema ?? null,\n actions: [\n // flatMap rather than filter+map: an unnamed operation is dropped, and\n // this is the shape that narrows `name` for the caller's benefit.\n ...(latest?.modules ?? []).flatMap((specModule) =>\n specModule.operations.flatMap((operation) =>\n operation.name\n ? [\n {\n type: operation.name,\n module: specModule.name,\n inputSchema: operation.schema ?? null,\n },\n ]\n : [],\n ),\n ),\n ...BASE_ACTIONS,\n ],\n };\n }\n\n async get(input: {\n documentId: string;\n branch?: string;\n }): Promise<ReactorDocumentSummary> {\n const document = await this.client.get<PHDocument>(input.documentId);\n return documentSummary(document, true);\n }\n\n async find(input: ReactorFindInput): Promise<ReactorDocumentSummary[]> {\n const limit = input.limit ?? FIND_PAGE_LIMIT;\n let results: PHDocument[];\n if (input.documentType) {\n // The index takes both, so a step that named a type and a drive gets\n // documents of that type in that drive — not every document of the type.\n results = await this.findByType(\n input.documentType,\n limit,\n input.parentId,\n );\n } else if (input.parentId) {\n const page = await this.client.find(\n { parentId: input.parentId },\n undefined,\n {\n cursor: \"\",\n limit,\n },\n );\n results = page.results;\n } else {\n // The index rejects an empty filter, so sweep every installed type.\n const types = (await this.models()).map((model) => model.documentType);\n const pages = await Promise.all(\n types.map((type) => this.findByType(type, limit)),\n );\n results = pages.flat();\n }\n const seen = new Set<string>();\n return (\n results\n .filter((document) => {\n if (seen.has(document.header.id)) return false;\n seen.add(document.header.id);\n return true;\n })\n // The index cannot query state, so a state match is applied to the page\n // that was read. A caller that needs to match across more documents than\n // the page holds raises `limit`; silently matching a prefix of the type\n // would look like \"no such document\".\n .filter((document) => matchesState(document, input.match))\n .map((document) => documentSummary(document, input.withState === true))\n );\n }\n\n async create(input: ReactorCreateInput): Promise<ReactorDocumentSummary> {\n const target = input.parentId\n ? await this.resolveDriveTarget(input.parentId)\n : null;\n if (!target) {\n const created = await this.client.createEmpty<PHDocument>(\n input.documentType,\n { parentIdentifier: input.parentId },\n );\n // createEmpty takes no name, so naming it is a first operation. The\n // drive path below sets the header instead, before the file lands.\n if (!input.name) return documentSummary(created, true);\n const named = await this.client.execute<PHDocument>(\n created.header.id,\n \"main\",\n [createAction(\"SET_NAME\", { name: input.name })],\n );\n assertOperationsApplied(named, 1);\n return documentSummary(named, true);\n }\n // createEmpty only records the parent relationship; a drive also needs an\n // ADD_FILE node, or the document is created but invisible in the drive.\n const module = await this.client.getDocumentModelModule(input.documentType);\n const empty = module.utils.createDocument() as PHDocument;\n // The node name comes from the header, so set it before the file lands.\n if (input.name) empty.header.name = input.name;\n const created = await this.client.drives.addFile<PHDocument>(\n target.driveId,\n empty,\n target.parentFolder,\n );\n return documentSummary(created, true);\n }\n\n async execute(input: ReactorExecuteInput): Promise<ReactorDocumentSummary> {\n const actions: Action[] = input.actions.map((entry) =>\n createAction(\n entry.type,\n entry.input,\n undefined,\n undefined,\n entry.scope ?? \"global\",\n ),\n );\n const document = await this.client.execute<PHDocument>(\n input.documentId,\n input.branch ?? \"main\",\n actions,\n );\n assertOperationsApplied(document, actions.length);\n return documentSummary(document, true);\n }\n\n private async findByType(\n type: string,\n limit: number,\n parentId?: string,\n ): Promise<PHDocument[]> {\n try {\n const page = await this.client.find(\n { type, ...(parentId ? { parentId } : {}) },\n undefined,\n { cursor: \"\", limit },\n );\n return page.results;\n } catch {\n // One unreadable model must not sink a whole-reactor sweep.\n return [];\n }\n }\n\n // Where a new document's drive node belongs, when the parent implies one.\n private async resolveDriveTarget(\n parentId: string,\n ): Promise<DriveTarget | null> {\n try {\n const parent = await this.client.get<PHDocument>(parentId);\n // A plain document parent gets a relationship only, as before.\n return DRIVE_DOCUMENT_TYPES.has(parent.header.documentType)\n ? { driveId: parent.header.id }\n : null;\n } catch {\n // Not a document at all: it may be a folder node inside a drive.\n return this.findFolderDrive(parentId);\n }\n }\n\n private async findFolderDrive(nodeId: string): Promise<DriveTarget | null> {\n // Every type that counts as a drive, not just the common one: a folder in\n // a reactor-drive would otherwise look like no drive at all.\n const pages = await Promise.all(\n [...DRIVE_DOCUMENT_TYPES].map((type) =>\n this.findByType(type, FIND_PAGE_LIMIT),\n ),\n );\n for (const drive of pages.flat()) {\n try {\n const node = await this.client.drives.getNode(drive.header.id, nodeId);\n if (node.kind === \"folder\") {\n return { driveId: drive.header.id, parentFolder: nodeId };\n }\n } catch {\n // Not in this drive.\n }\n }\n return null;\n }\n}\n\n// Design-time `ctx.reactor`, bound to the caller behind the GraphQL request.\n// A piece's options()/props() code is the package's, not the reactor's.\nexport class ScopedDesignTimeReactorPort implements ReactorPort {\n private readonly inner: SubgraphReactorPort;\n\n constructor(\n private readonly host: WorkflowRuntimeHostDeps,\n private readonly caller: WorkflowCaller | undefined,\n ) {\n this.inner = new SubgraphReactorPort(host);\n }\n\n models(): Promise<ReactorModelSummary[]> {\n return this.inner.models();\n }\n\n model(documentType: string): Promise<ReactorModelDetail> {\n return this.inner.model(documentType);\n }\n\n async get(input: {\n documentId: string;\n branch?: string;\n }): Promise<ReactorDocumentSummary> {\n if (!this.caller) throw new Error(DESIGN_TIME_CALLER_REQUIRED);\n await this.host.assertCanRead(input.documentId, this.caller);\n return this.inner.get(input);\n }\n\n async find(input: ReactorFindInput): Promise<ReactorDocumentSummary[]> {\n const found = await this.inner.find(input);\n // Filtered rather than refused: one unreadable document in a sweep is not\n // the caller's error, and the list is what options() offers.\n const allowed = await Promise.all(\n found.map((document) => this.canRead(document.documentId)),\n );\n return found.filter((_, index) => allowed[index]);\n }\n\n create(_input: ReactorCreateInput): Promise<ReactorDocumentSummary> {\n return Promise.reject(new Error(DESIGN_TIME_WRITES_REFUSED));\n }\n\n execute(_input: ReactorExecuteInput): Promise<ReactorDocumentSummary> {\n return Promise.reject(new Error(DESIGN_TIME_WRITES_REFUSED));\n }\n\n private async canRead(documentId: string): Promise<boolean> {\n if (!this.caller) return false;\n return this.host\n .assertCanRead(documentId, this.caller)\n .then(() => true)\n .catch(() => false);\n }\n}\n","// Which workflow document a step is running for, available to services that\n// sit below the coordinator. Attachment reads are authorized per document, and\n// the block executor is shared across concurrent runs, so the scope travels\n// with the async context rather than on the executor.\nimport type { IPieceWorker } from \"../pieces/index.js\";\nimport { AsyncLocalStorage } from \"node:async_hooks\";\n\nexport interface RunScope {\n workflowId: string;\n runId?: string | null;\n // The connections the definition this run pinned declared; a step resolves\n // nothing outside this set, and an edit mid-run never widens it.\n connections?: ReadonlySet<string>;\n // The worker child this run's piece steps go to, held for the length of the\n // run. Absent outside a pooled run, where the executor falls back to its own.\n pieceWorker?: IPieceWorker;\n}\n\nconst storage = new AsyncLocalStorage<RunScope>();\n\nexport function withRunScope<T>(\n scope: RunScope,\n fn: () => Promise<T>,\n): Promise<T> {\n return storage.run(scope, fn);\n}\n\nexport function currentWorkflowId(): string | undefined {\n return storage.getStore()?.workflowId;\n}\n\n// Undefined outside a run, which the block executor treats as \"resolve\n// nothing\": only a run establishes a binding.\nexport function currentBoundConnections(): ReadonlySet<string> | undefined {\n return storage.getStore()?.connections;\n}\n\n// The run's own worker, asked for per step rather than held by the executor:\n// the executor is shared, and the child it should use is not.\nexport function currentPieceWorker(): IPieceWorker | undefined {\n return storage.getStore()?.pieceWorker;\n}\n","// A connection's connectorId is \"<piece package>#<piece short name>\"; the\n// runtime only ever needs the package half back out of it.\nexport function packageFromConnectorId(connectorId: string): string {\n const separator = connectorId.lastIndexOf(\"#\");\n return separator > 0 ? connectorId.slice(0, separator) : connectorId;\n}\n","// Scaffold file meant for customization; delete and re-run codegen to reset.\nimport type { WorkflowRuntimeHostDeps } from \"./host.js\";\nimport {\n ActivepiecesBlockExecutor,\n BoundConnectionResolver,\n CompositeBlockExecutor,\n ensurePieceBundle,\n localFirstResolver,\n shapeConnection,\n type BlockExecutor,\n type ConnectionAuthType,\n type ConnectionRequest,\n type EngineConnectionResolver,\n type AttachmentPort,\n type PieceResolver,\n type PieceStorePort,\n type ResolvedConnection,\n type EgressPolicy,\n type SecretProvider,\n type WorkflowDefinition,\n} from \"../pieces/index.js\";\nimport type {\n ConnectionDocument,\n ConnectionState,\n} from \"@powerhousedao/workflow/document-models/connection\";\nimport type { WorkflowState } from \"@powerhousedao/workflow/document-models/workflow\";\nimport { childLogger } from \"document-model\";\nimport { join } from \"node:path\";\nimport {\n currentBoundConnections,\n currentPieceWorker,\n currentWorkflowId,\n} from \"./run-scope.js\";\nimport { packagePieces } from \"./piece-registry.js\";\nimport { SubgraphReactorPort } from \"./reactor-port.js\";\nimport { packageFromConnectorId } from \"./connector-id.js\";\n\nconst pieceLogger = childLogger([\"workflow\", \"piece\"]);\nconst connectionLogger = childLogger([\"workflow\", \"connection\"]);\n\n// A connection is bound to its connector (doc 08 §10): a step of one piece\n// never receives another piece's credentials.\n\n// Absent information refuses. A caller that named no piece, or a connection\n// whose connectorId is blank, leaves nothing to check against.\nfunction assertConnectorMatches(\n state: ConnectionState,\n request: ConnectionRequest | undefined,\n): void {\n const wanted = request?.piecePackage;\n const owner = state.connectorId\n ? packageFromConnectorId(state.connectorId)\n : \"\";\n if (!wanted || !owner || wanted !== owner) {\n throw new ConnectorMismatchError();\n }\n}\n\n// Says only that this connection is not this caller's to use: naming the\n// owning package would tell an author which connector a guessed id belongs to.\nexport class ConnectorMismatchError extends Error {\n constructor() {\n super(\"Connection is not available to this block\");\n this.name = \"ConnectorMismatchError\";\n }\n}\n\n// Resolves a step's connectionId to a powerhouse/connection document and\n// shapes its auth value; secret refs resolve through the managed store.\nexport class DocumentConnectionResolver implements EngineConnectionResolver {\n constructor(\n private readonly host: WorkflowRuntimeHostDeps,\n private readonly secrets: SecretProvider,\n ) {}\n\n async resolve(\n connectionId: string,\n request?: ConnectionRequest,\n ): Promise<unknown> {\n return (await this.resolveWithSecrets(connectionId, request)).auth;\n }\n\n // The secret half is what journal redaction matches on, so it is resolved\n // here rather than guessed from the shaped auth value.\n async resolveWithSecrets(\n connectionId: string,\n request?: ConnectionRequest,\n ): Promise<ResolvedConnection> {\n const document =\n await this.host.reactorClient.get<ConnectionDocument>(connectionId);\n return resolveConnectionWithSecrets(document, this.secrets, request);\n }\n}\n\n// The one place that decides whether a connection's credentials may be shaped\n// at all. Takes the document so a caller holding one need not fetch it twice.\nexport async function resolveConnectionAuth(\n document: ConnectionDocument,\n secrets: SecretProvider,\n request?: ConnectionRequest,\n): Promise<unknown> {\n return (await resolveConnectionWithSecrets(document, secrets, request)).auth;\n}\n\n// The same resolution, with the concrete secret strings the journal redacts\n// on. It runs every check above it: getting the secrets is not a way around\n// the question of who is asking.\nexport async function resolveConnectionWithSecrets(\n document: ConnectionDocument,\n secrets: SecretProvider,\n request?: ConnectionRequest,\n): Promise<ResolvedConnection> {\n // Nothing before the connector check describes what was found: a document\n // of the wrong type answers exactly as a foreign connection does.\n if (document.header.documentType !== \"powerhouse/connection\") {\n throw new ConnectorMismatchError();\n }\n const state: ConnectionState = document.state.global;\n assertConnectorMatches(state, request);\n // Past the check the caller already holds this connection, so the reason it\n // cannot be used is theirs to see.\n if (state.status === \"REVOKED\") {\n throw new Error(\n `Connection \"${state.name || document.header.id}\" is revoked`,\n );\n }\n return shapeConnection(\n {\n authType: state.authType as ConnectionAuthType,\n config: (state.config ?? {}) as Record<string, unknown>,\n secretRefs: state.secretRefs,\n },\n secrets,\n );\n}\n\n// Piece code runs under an egress policy that denies private address space —\n// loopback, the RFC1918 ranges, the cloud metadata endpoint — because a piece\n// config is an SSRF surface and a workflow author is not always the operator.\n//\n// A reactor co-hosted with what it integrates has to widen that, or every one\n// of its connections is unreachable: a local demo pointing at\n// http://localhost:18081 fails at the first poll, and so does the dropdown that\n// would have offered it. The widening names addresses rather than switching the\n// guard off, so allowing a demo's loopback services leaves the rest of private\n// space — and the metadata endpoint — denied.\n//\n// WORKFLOW_EGRESS_ALLOW_ADDRESSES=127.0.0.1/32,::1/128\n//\n// Unset, the default policy applies and nothing private is reachable.\nconst EGRESS_ALLOW_ENV = \"WORKFLOW_EGRESS_ALLOW_ADDRESSES\";\n\n// A bare address is one host, not a guess at the network around it.\nfunction asCidr(entry: string): string {\n if (entry.includes(\"/\")) return entry;\n return entry.includes(\":\") ? `${entry}/128` : `${entry}/32`;\n}\n\nexport function configuredEgress(): EgressPolicy | undefined {\n const raw = process.env[EGRESS_ALLOW_ENV];\n if (raw === undefined || raw.trim() === \"\") return undefined;\n const allowAddresses = raw\n .split(\",\")\n .map((entry) => entry.trim())\n .filter((entry) => entry !== \"\")\n .map(asCidr);\n if (allowAddresses.length === 0) return undefined;\n pieceLogger.info(\n `Egress policy widened by ${EGRESS_ALLOW_ENV}: ${allowAddresses.join(\", \")}`,\n );\n return { allowAddresses };\n}\n\nexport const BUNDLE_CACHE_DIR = join(process.cwd(), \".ph\", \"ap-bundles\");\n\n// Where a piece's ctx.files output and its staged attachment inputs live for\n// the length of one step. Under .ph so a host can sweep it on startup after a\n// crash; the executor removes each step's directory itself.\nexport const ATTACHMENT_STAGING_DIR = join(\n process.cwd(),\n \".ph\",\n \"ap-attachment-staging\",\n);\n\n// Where every piece in this runtime comes from: a package that ships one wins\n// for its own name, and everything else is fetched and cached as before.\n\n// One instance, because the registry behind it is one — a block type must not\n// resolve to a package piece in a run and to a published bundle in the editor.\nlet resolver: PieceResolver | undefined;\n\n// Spelled out rather than taken from the connectors package so the fetch goes\n// through this module's own import of it, which is the seam tests replace.\nexport function fetchingResolver(cacheDir: string): PieceResolver {\n return {\n async resolve(name: string, version: string) {\n const bundle = await ensurePieceBundle({ name, version, cacheDir });\n return { name, version, bundleDir: bundle.dir, local: false };\n },\n };\n}\n\nexport function pieceResolver(): PieceResolver {\n return (resolver ??= localFirstResolver(\n // Loads the registry on the first ask, so nothing has to have loaded it\n // before a step, an editor query or a trigger enable reaches here.\n async (name) => {\n await packagePieces.ready();\n return packagePieces.lookup(name);\n },\n fetchingResolver(BUNDLE_CACHE_DIR),\n ));\n}\n\n// The executor is shared by every concurrent run, so the binding travels with\n// the run scope rather than sitting on the resolver.\nexport function boundConnections(\n inner: EngineConnectionResolver,\n): EngineConnectionResolver {\n return new BoundConnectionResolver(\n inner,\n currentBoundConnections,\n (connectionId, request) => {\n // Named apart from a missing connection so an operator can tell a\n // misconfigured step from an attempt to reach a foreign credential.\n connectionLogger.warn(\n `Step \"${request?.stepKey ?? \"?\"}\" of workflow \"${currentWorkflowId() ?? \"?\"}\" asked for connection \"${connectionId}\", which its definition does not declare`,\n );\n },\n );\n}\n\nexport function createBlockExecutor(\n host: WorkflowRuntimeHostDeps,\n secrets: SecretProvider,\n attachments?: AttachmentPort,\n pieceStore?: PieceStorePort,\n): BlockExecutor {\n // No handler map: the document blocks are a piece now, and they reach the\n // reactor through the port below like any other package piece would.\n return new CompositeBlockExecutor(\n new ActivepiecesBlockExecutor({\n cacheDir: BUNDLE_CACHE_DIR,\n // Undefined leaves the connectors' default policy in force; a value only\n // ever widens it.\n egress: configuredEgress(),\n // Asked per step, for the same reason the binding is: one executor,\n // many runs, and each run has a child of its own.\n worker: currentPieceWorker,\n resolver: pieceResolver(),\n // A package piece's block type carries no version; this is where the\n // installed one comes from, and it loads the registry if a step is the\n // first thing to ask.\n packages: async () => {\n await packagePieces.ready();\n return packagePieces.versions();\n },\n // Served only to a piece this reactor's packages ship; the executor\n // withholds it from everything the resolver fetched.\n reactor: new SubgraphReactorPort(host),\n connections: boundConnections(\n new DocumentConnectionResolver(host, secrets),\n ),\n // Without it an action's ctx.store lives only in the worker's heap.\n ...(pieceStore ? { pieceStore } : {}),\n // The worker's stdio is discarded, so a piece's own console output is\n // invisible until it is forwarded here.\n onPieceLog: (entry, execution) => {\n const line = `[${execution.step.key}] ${entry.message}`;\n if (entry.level === \"error\") pieceLogger.error(line);\n else if (entry.level === \"warn\") pieceLogger.warn(line);\n else if (entry.level === \"debug\") pieceLogger.debug(line);\n else pieceLogger.info(line);\n },\n // Without an attachment store a piece's ctx.files still works, but\n // inline as a data URI; with one, bytes go to the store and the output\n // carries a reference.\n ...(attachments\n ? { attachments, stagingRoot: ATTACHMENT_STAGING_DIR }\n : {}),\n }),\n );\n}\n\n// The document state is the definition; strip nulls into engine shape.\nexport function toWorkflowDefinition(state: WorkflowState): WorkflowDefinition {\n if (!state.trigger) {\n throw new Error(\"Workflow has no trigger binding\");\n }\n return {\n name: state.name,\n trigger: {\n id: state.trigger.id,\n blockType: state.trigger.blockType,\n connectionId: state.trigger.connectionId,\n config: state.trigger.config,\n filter: state.trigger.filter,\n },\n steps: state.steps.map((step) => ({\n id: step.id,\n key: step.key,\n name: step.name,\n blockType: step.blockType,\n connectionId: step.connectionId,\n config: step.config,\n timeoutSeconds: step.timeoutSeconds,\n })),\n edges: state.edges.map((edge) => ({\n id: edge.id,\n from: edge.from,\n to: edge.to,\n port: edge.port,\n condition: edge.condition,\n })),\n variables: state.variables.map((variable) => ({\n key: variable.key,\n value: variable.value,\n })),\n };\n}\n","// Pure config parsing and next-fire math for the core#schedule trigger: a\n// 5-field cron in an IANA timezone, or a fixed interval (min one minute).\nimport { Cron } from \"croner\";\n\nexport const SCHEDULE_BLOCK = \"core#schedule\";\n\nexport const MIN_SCHEDULE_INTERVAL_MS = 60_000;\nexport const DEFAULT_TIMEZONE = \"UTC\";\n\nexport const INTERVAL_UNIT_MS = {\n minutes: 60_000,\n hours: 3_600_000,\n days: 86_400_000,\n} as const;\n\nexport type IntervalUnit = keyof typeof INTERVAL_UNIT_MS;\n\nexport type ScheduleConfig =\n | { mode: \"cron\"; cron: string; timezone: string }\n | { mode: \"interval\"; everyMs: number; timezone: string };\n\nfunction asRecord(config: unknown): Record<string, unknown> {\n if (config && typeof config === \"object\" && !Array.isArray(config)) {\n return config as Record<string, unknown>;\n }\n if (typeof config === \"string\") {\n try {\n return asRecord(JSON.parse(config));\n } catch {\n return {};\n }\n }\n return {};\n}\n\n// Intl is the authority on IANA names; croner defers to it as well.\nfunction parseTimezone(value: unknown): string {\n if (value === undefined || value === null || value === \"\") {\n return DEFAULT_TIMEZONE;\n }\n if (typeof value !== \"string\") {\n throw new Error(`${SCHEDULE_BLOCK}: \"timezone\" must be an IANA name`);\n }\n try {\n new Intl.DateTimeFormat(\"en-US\", { timeZone: value });\n } catch {\n throw new Error(\n `${SCHEDULE_BLOCK}: unknown timezone \"${value}\" (use an IANA name such as Europe/Lisbon)`,\n );\n }\n return value;\n}\n\nfunction toNumber(value: unknown): number | undefined {\n if (typeof value === \"number\") return value;\n if (typeof value === \"string\" && value.trim() !== \"\") {\n const parsed = Number(value);\n return Number.isNaN(parsed) ? undefined : parsed;\n }\n return undefined;\n}\n\n// Exactly five fields: seconds would only mislead under a one-minute floor.\nfunction parseCronPattern(cron: unknown, timezone: string): string {\n if (typeof cron !== \"string\" || cron.trim() === \"\") {\n throw new Error(`${SCHEDULE_BLOCK}: \"cron\" is required in cron mode`);\n }\n const pattern = cron.trim().replace(/\\s+/g, \" \");\n if (pattern.split(\" \").length !== 5) {\n throw new Error(\n `${SCHEDULE_BLOCK}: cron \"${pattern}\" must have exactly five fields (minute hour day month weekday)`,\n );\n }\n let cronJob: Cron;\n try {\n cronJob = new Cron(pattern, { timezone, legacyMode: false });\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n throw new Error(\n `${SCHEDULE_BLOCK}: invalid cron \"${pattern}\": ${message}`,\n {\n cause: error,\n },\n );\n }\n if (!cronJob.nextRun()) {\n throw new Error(`${SCHEDULE_BLOCK}: cron \"${pattern}\" never fires`);\n }\n return pattern;\n}\n\n// Config: { mode?, cron?, every?, unit?, everyMs?, timezone? }; an omitted\n// mode follows whichever of cron / every is present (cron wins).\nexport function parseScheduleConfig(config: unknown): ScheduleConfig {\n const record = asRecord(config);\n const timezone = parseTimezone(record.timezone);\n const mode =\n record.mode === \"cron\" || record.mode === \"interval\"\n ? record.mode\n : record.cron\n ? \"cron\"\n : record.every !== undefined || record.everyMs !== undefined\n ? \"interval\"\n : undefined;\n if (!mode) {\n throw new Error(\n `${SCHEDULE_BLOCK}: \"mode\" must be \"cron\" or \"interval\" (or set \"cron\" / \"every\")`,\n );\n }\n if (mode === \"cron\") {\n return { mode, cron: parseCronPattern(record.cron, timezone), timezone };\n }\n return { mode, everyMs: intervalMsFrom(record), timezone };\n}\n\nfunction intervalMsFrom(record: Record<string, unknown>): number {\n const every = toNumber(record.every);\n let everyMs: number | undefined;\n if (every !== undefined) {\n const unit = (record.unit ?? \"minutes\") as string;\n if (!(unit in INTERVAL_UNIT_MS)) {\n throw new Error(\n `${SCHEDULE_BLOCK}: \"unit\" must be one of ${Object.keys(INTERVAL_UNIT_MS).join(\", \")}`,\n );\n }\n everyMs = every * INTERVAL_UNIT_MS[unit as IntervalUnit];\n } else {\n everyMs = toNumber(record.everyMs);\n }\n if (everyMs === undefined) {\n throw new Error(\n `${SCHEDULE_BLOCK}: \"every\" (with \"unit\") or \"everyMs\" is required in interval mode`,\n );\n }\n if (!Number.isFinite(everyMs) || everyMs <= 0) {\n throw new Error(\n `${SCHEDULE_BLOCK}: the interval must be a positive number`,\n );\n }\n if (everyMs < MIN_SCHEDULE_INTERVAL_MS) {\n throw new Error(\n `${SCHEDULE_BLOCK}: the interval must be at least ${MIN_SCHEDULE_INTERVAL_MS / 1000}s`,\n );\n }\n return Math.round(everyMs);\n}\n\n// Strictly after `from`. A cron slot erased by a DST jump resolves to the\n// first valid instant after it, so it still fires once.\nexport function nextFireAt(schedule: ScheduleConfig, from: Date): Date {\n if (schedule.mode === \"interval\") {\n return new Date(from.getTime() + schedule.everyMs);\n }\n const next = new Cron(schedule.cron, {\n timezone: schedule.timezone,\n legacyMode: false,\n }).nextRun(from);\n if (!next) {\n throw new Error(`${SCHEDULE_BLOCK}: cron \"${schedule.cron}\" never fires`);\n }\n return next;\n}\n\n// Interval mode keeps its phase while still ahead of `now` (no tick drift);\n// an overdue slot fires once and rebases on `now` rather than replaying.\nexport function rescheduleAfterFire(\n schedule: ScheduleConfig,\n scheduledFor: Date,\n now: Date,\n): Date {\n if (schedule.mode === \"interval\") {\n const onPhase = new Date(scheduledFor.getTime() + schedule.everyMs);\n return onPhase > now ? onPhase : nextFireAt(schedule, now);\n }\n return nextFireAt(schedule, now);\n}\n\nexport interface SchedulePayload {\n scheduledFor: string;\n firedAt: string;\n timezone: string;\n cron?: string;\n everyMs?: number;\n}\n\nexport function schedulePayload(\n schedule: ScheduleConfig,\n scheduledFor: Date,\n firedAt: Date,\n): SchedulePayload {\n return {\n scheduledFor: scheduledFor.toISOString(),\n firedAt: firedAt.toISOString(),\n timezone: schedule.timezone,\n ...(schedule.mode === \"cron\"\n ? { cron: schedule.cron }\n : { everyMs: schedule.everyMs }),\n };\n}\n\n// Poll cadence implied by a piece's setSchedule cron: the gap between its\n// next two runs, floored. Undefined when it is invalid or never repeats.\nexport function cronIntervalMs(\n cron: string,\n from = new Date(),\n): number | undefined {\n try {\n const job = new Cron(cron.trim(), { timezone: \"UTC\", legacyMode: false });\n const runs = job.nextRuns(2, from);\n if (runs.length < 2) return undefined;\n return Math.max(\n runs[1].getTime() - runs[0].getTime(),\n MIN_SCHEDULE_INTERVAL_MS,\n );\n } catch {\n return undefined;\n }\n}\n","// Adapts the run journal's `piece_store` table to the engine's PieceStorePort,\n// so an action's `ctx.store` is durable the moment the piece writes it.\n\n// Which workflow a step belongs to travels on the run scope, not the executor,\n// which concurrent runs share.\nimport type { PieceStorePort, StoreScopeName } from \"../pieces/index.js\";\nimport { childLogger } from \"document-model\";\nimport type { WorkflowRunStore } from \"./store.js\";\n\nconst logger = childLogger([\"workflow\", \"piece-store\"]);\n\n// PROJECT means \"shared by every workflow in the project\", and this reactor is\n// that project: the trigger registry, the run journal and the secret store are\n// all already instance-wide, so nothing new is shared by saying so.\n\n// When a real tenancy model arrives this constant becomes its default project\n// id, and the migration is one UPDATE. See issue #16.\nexport const PROJECT_SCOPE_KEY = \"reactor\";\n\n// Appended to both partition keys for a design-time sample, so a test run\n// cannot alias a live key however the piece happens to name it.\n\n// The supervisor drops these partitions when the sample returns; a key prefix\n// could do neither, since prefixes alias and nothing enumerates them.\nconst TEST_PARTITION_SUFFIX = \"#test\";\n\n// A sample partitions by workflow in *both* scopes, unlike a live run: two\n// samples on one project partition would read and then delete each other's.\nexport function testPartitionKey(\n scope: StoreScopeName,\n workflowId: string,\n): string {\n const base =\n scope === \"PROJECT\" ? `${PROJECT_SCOPE_KEY}#${workflowId}` : workflowId;\n return base + TEST_PARTITION_SUFFIX;\n}\n\n// pollingHelper's cursor. Math.max over one unparseable date yields NaN, which\n// then re-delivers the whole feed forever, or nothing ever again.\nconst CURSOR_KEY = \"lastPoll\";\n\n// A provider's clock can run ahead of ours; beyond a day it is not skew, it is\n// a cursor that would hold the trigger silent until that date passes.\nconst MAX_CURSOR_SKEW_MS = 24 * 60 * 60_000;\n\nfunction isPlausibleCursor(value: unknown, now: number): value is number {\n return (\n typeof value === \"number\" &&\n Number.isFinite(value) &&\n value > 0 &&\n value <= now + MAX_CURSOR_SKEW_MS\n );\n}\n\n// The worker JSON-serialises what it writes, so a NaN or Infinity cursor\n// arrives as null — still ours to reject, just no longer a number.\nfunction isCursorShaped(value: unknown): boolean {\n return value === null || typeof value === \"number\";\n}\n\n// NaN and Infinity both serialise as \"null\", which is the one thing an\n// operator reading the warning must not be told.\nfunction showCursor(value: unknown): string {\n return typeof value === \"number\" ? String(value) : JSON.stringify(value);\n}\n\nfunction isCursorRef(key: string): boolean {\n return key === CURSOR_KEY || key.endsWith(`/${CURSOR_KEY}`);\n}\n\nexport function createPieceStorePort(\n store: WorkflowRunStore,\n workflowIdFor: () => string | undefined,\n sample = false,\n clock: () => number = Date.now,\n): PieceStorePort {\n // A step with no workflow in scope must fail rather than read or write\n // another workflow's keys.\n const flowKey = () => {\n const workflowId = workflowIdFor();\n if (!workflowId) {\n throw new Error(\"ctx.store is unavailable: no workflow is in scope\");\n }\n return workflowId;\n };\n\n const partition = (scope: StoreScopeName): string =>\n sample\n ? testPartitionKey(scope, flowKey())\n : scope === \"PROJECT\"\n ? PROJECT_SCOPE_KEY\n : flowKey();\n\n // Async so that a missing run scope rejects rather than throwing out of a\n // method whose contract is a promise.\n return {\n get: async (key, scope) =>\n store.getPieceStoreValue(scope, partition(scope), key),\n // A durable store means the cursor no longer passes the supervisor on its\n // way to the database, so the guard that policed it lives here instead.\n put: async (key, value, scope) => {\n const now = clock();\n if (!isCursorRef(key) || isPlausibleCursor(value, now)) {\n return store.setPieceStoreValue(scope, partition(scope), key, value);\n }\n const kept = await store.getPieceStoreValue(scope, partition(scope), key);\n // Only our own cursor shape is ours to police: a piece that keeps its\n // own `lastPoll` as a string or an object is left to it.\n if (!isCursorShaped(value) && !isPlausibleCursor(kept, now)) {\n return store.setPieceStoreValue(scope, partition(scope), key, value);\n }\n logger.warn(\n `Rejected ${key}=${showCursor(value)} from workflow ${flowKey()}; keeping ${\n isPlausibleCursor(kept, now) ? String(kept) : \"no cursor\"\n }`,\n );\n // With nothing to fall back to the key is dropped, so the next poll\n // fails loudly rather than running on a cursor nobody chose.\n if (!isPlausibleCursor(kept, now)) {\n await store.deletePieceStoreValue(scope, partition(scope), key);\n }\n },\n delete: async (key, scope) =>\n store.deletePieceStoreValue(scope, partition(scope), key),\n };\n}\n","// Managed secrets in the relational \"secrets\" namespace, AES-256-GCM at rest;\n// master key from PH_SECRETS_MASTER_KEY or a generated key file.\nimport type { IRelationalDb } from \"@powerhousedao/shared/processors\";\nimport {\n parseSecretRef,\n secretRefFromId,\n SecretDeletedError,\n SecretNotFoundError,\n type SecretStat,\n type SecretStore,\n} from \"../pieces/index.js\";\nimport { createCipheriv, createDecipheriv, randomBytes } from \"node:crypto\";\nimport { mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\n\nconst IV_BYTES = 12;\nconst TAG_BYTES = 16;\nconst KEY_BYTES = 32;\n\nexport interface SecretRow {\n id: string;\n label: string | null;\n version: number;\n // base64(iv || tag || ciphertext); null once deleted.\n enc: string | null;\n status: string; // ACTIVE | DELETED\n created_at: string;\n updated_at: string;\n}\n\ninterface SecretsDB {\n secret: SecretRow;\n}\n\nasync function up(db: IRelationalDb<SecretsDB>): Promise<void> {\n await db.schema\n .createTable(\"secret\")\n .addColumn(\"id\", \"text\", (col) => col.primaryKey())\n .addColumn(\"label\", \"text\")\n .addColumn(\"version\", \"integer\", (col) => col.notNull())\n .addColumn(\"enc\", \"text\")\n .addColumn(\"status\", \"text\", (col) => col.notNull())\n .addColumn(\"created_at\", \"text\", (col) => col.notNull())\n .addColumn(\"updated_at\", \"text\", (col) => col.notNull())\n .ifNotExists()\n .execute();\n}\n\nexport interface LocalSecretStoreOptions {\n // 64 hex chars (32 bytes); defaults to PH_SECRETS_MASTER_KEY.\n masterKeyHex?: string;\n // Dev fallback when no master key is set; generated on first use.\n keyFile?: string;\n}\n\nfunction loadKey(options: LocalSecretStoreOptions): Buffer {\n const hex = options.masterKeyHex ?? process.env.PH_SECRETS_MASTER_KEY;\n if (hex !== undefined) {\n if (!/^[0-9a-f]{64}$/i.test(hex)) {\n throw new Error(\"Secrets master key must be 64 hex chars (32 bytes)\");\n }\n return Buffer.from(hex, \"hex\");\n }\n const file = options.keyFile ?? join(process.cwd(), \".ph\", \"secrets.key\");\n try {\n const key = Buffer.from(readFileSync(file, \"utf8\").trim(), \"hex\");\n if (key.length !== KEY_BYTES) {\n throw new Error(`Key file \"${file}\" is not 32 bytes of hex`);\n }\n return key;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") throw error;\n }\n const key = randomBytes(KEY_BYTES);\n mkdirSync(dirname(file), { recursive: true });\n writeFileSync(file, key.toString(\"hex\") + \"\\n\", { mode: 0o600 });\n return key;\n}\n\nexport class LocalEncryptedSecretStore implements SecretStore {\n private constructor(\n private readonly db: IRelationalDb<SecretsDB>,\n private readonly key: Buffer,\n ) {}\n\n static async create(\n relationalDb: IRelationalDb,\n options: LocalSecretStoreOptions = {},\n ): Promise<LocalEncryptedSecretStore> {\n const db = (await relationalDb.createNamespace(\n \"secrets\",\n )) as IRelationalDb<SecretsDB>;\n await up(db);\n return new LocalEncryptedSecretStore(db, loadKey(options));\n }\n\n private encrypt(value: string): string {\n const iv = randomBytes(IV_BYTES);\n const cipher = createCipheriv(\"aes-256-gcm\", this.key, iv);\n const ciphertext = Buffer.concat([\n cipher.update(value, \"utf8\"),\n cipher.final(),\n ]);\n return Buffer.concat([iv, cipher.getAuthTag(), ciphertext]).toString(\n \"base64\",\n );\n }\n\n private decrypt(enc: string): string {\n const raw = Buffer.from(enc, \"base64\");\n const iv = raw.subarray(0, IV_BYTES);\n const tag = raw.subarray(IV_BYTES, IV_BYTES + TAG_BYTES);\n const decipher = createDecipheriv(\"aes-256-gcm\", this.key, iv);\n decipher.setAuthTag(tag);\n return Buffer.concat([\n decipher.update(raw.subarray(IV_BYTES + TAG_BYTES)),\n decipher.final(),\n ]).toString(\"utf8\");\n }\n\n private async row(ref: string): Promise<SecretRow> {\n const id = parseSecretRef(ref);\n const row = await this.db\n .selectFrom(\"secret\")\n .selectAll()\n .where(\"id\", \"=\", id)\n .executeTakeFirst();\n if (!row) throw new SecretNotFoundError(ref);\n return row;\n }\n\n private toStat(row: SecretRow): SecretStat {\n return {\n ref: secretRefFromId(row.id),\n label: row.label,\n version: row.version,\n status: row.status as SecretStat[\"status\"],\n createdAt: row.created_at,\n updatedAt: row.updated_at,\n };\n }\n\n async create(input: { value: string; label?: string }): Promise<SecretStat> {\n const now = new Date().toISOString();\n const row: SecretRow = {\n id: randomBytes(16).toString(\"hex\"),\n label: input.label ?? null,\n version: 1,\n enc: this.encrypt(input.value),\n status: \"ACTIVE\",\n created_at: now,\n updated_at: now,\n };\n await this.db.insertInto(\"secret\").values(row).execute();\n return this.toStat(row);\n }\n\n async rotate(ref: string, value: string): Promise<SecretStat> {\n const row = await this.row(ref);\n if (row.status !== \"ACTIVE\") throw new SecretDeletedError(ref);\n const updated: SecretRow = {\n ...row,\n version: row.version + 1,\n enc: this.encrypt(value),\n updated_at: new Date().toISOString(),\n };\n await this.db\n .updateTable(\"secret\")\n .set({\n version: updated.version,\n enc: updated.enc,\n updated_at: updated.updated_at,\n })\n .where(\"id\", \"=\", row.id)\n .execute();\n return this.toStat(updated);\n }\n\n async get(ref: string): Promise<string> {\n const row = await this.row(ref);\n if (row.status !== \"ACTIVE\" || row.enc === null) {\n throw new SecretDeletedError(ref);\n }\n return this.decrypt(row.enc);\n }\n\n async stat(ref: string): Promise<SecretStat> {\n return this.toStat(await this.row(ref));\n }\n\n async list(): Promise<SecretStat[]> {\n const rows = await this.db\n .selectFrom(\"secret\")\n .selectAll()\n .where(\"status\", \"=\", \"ACTIVE\")\n .orderBy(\"created_at\", \"desc\")\n .execute();\n return rows.map((row) => this.toStat(row));\n }\n\n // Tombstone: the ciphertext is dropped so the value is unrecoverable, but\n // the row survives so dangling refs error as \"deleted\", not \"not found\".\n async delete(ref: string): Promise<void> {\n const row = await this.row(ref);\n await this.db\n .updateTable(\"secret\")\n .set({\n status: \"DELETED\",\n enc: null,\n updated_at: new Date().toISOString(),\n })\n .where(\"id\", \"=\", row.id)\n .execute();\n }\n}\n","// Persisted run journal in the relational \"workflow_runtime\" namespace.\n// Dates are ISO text columns: PGlite parses `timestamp` as local time.\nimport type { IRelationalDb } from \"@powerhousedao/shared/processors\";\nimport {\n redact,\n redactMessage,\n type StepExecutionRecord,\n type WorkflowRunResult,\n} from \"../pieces/index.js\";\nimport { childLogger } from \"document-model\";\nimport { randomUUID } from \"node:crypto\";\nimport { PROJECT_SCOPE_KEY } from \"./piece-store-port.js\";\n\nexport interface RunRow {\n id: string;\n workflow_id: string;\n workflow_name: string;\n workflow_version: number;\n trigger_kind: string;\n trigger_payload: string | null;\n status: string;\n error: string | null;\n started_at: string;\n ended_at: string | null;\n // Failed run this one resumes; null for first-hand runs.\n rerun_of: string | null;\n}\n\nexport interface StepExecutionRow {\n id: string;\n run_id: string;\n // Execution order; runs journaled before per-step journaling landed hold\n // the definition index. Both are per-run, and nothing compares across runs.\n ordinal: number;\n step_id: string;\n step_key: string;\n block_type: string;\n status: string;\n input: string | null;\n output: string | null;\n port: string | null;\n error: string | null;\n}\n\nexport interface TriggerStateRow {\n workflow_id: string;\n block_type: string;\n config_hash: string;\n status: string; // ENABLED | DISABLED | ERROR\n // Vestigial: hook state lives in piece_store now, and this is written \"{}\"\n // and never read. Rolling back past the migration re-delivers; see up().\n store_state: string;\n interval_ms: number;\n next_poll_at: string | null;\n last_poll_at: string | null;\n last_error: string | null;\n consecutive_failures: number;\n // Written for rolling-deploy overlap; not enforced yet.\n lease_owner: string | null;\n lease_expires_at: string | null;\n updated_at: string;\n}\n\nexport interface TriggerDedupeRow {\n workflow_id: string;\n dedupe_key: string;\n run_id: string | null;\n created_at: string;\n}\n\n// One key a piece wrote through `ctx.store`, from an action or a trigger hook\n// alike — the same table for both, as Activepieces has.\n\n// `scope` mirrors their StoreScope: FLOW partitions by workflow, PROJECT by\n// the reactor, which is the only project identity we have. See issue #16.\nexport interface PieceStoreRow {\n scope: string; // FLOW | PROJECT\n scope_key: string;\n key: string;\n value: string; // JSON\n updated_at: string;\n}\n\nexport interface WorkflowRuntimeDB {\n run: RunRow;\n step_execution: StepExecutionRow;\n trigger_state: TriggerStateRow;\n trigger_dedupe: TriggerDedupeRow;\n piece_store: PieceStoreRow;\n}\n\nconst logger = childLogger([\"workflow\", \"runtime\", \"store\"]);\n\n// Recorded as the run's error when the reactor died mid-run, so the cause is\n// legible in the UI rather than the run just stopping.\nexport const ORPHANED_RUN_ERROR =\n \"Reactor stopped before the run finished; steps completed before then were journaled\";\n\n// A run that was matched and journaled but never started. Recorded as FAILED\n// so it is both visible and rerunnable: rerun() replays the trigger payload\n// with no completed steps, which is exactly the run that never happened.\nexport const ABANDONED_PENDING_RUN_ERROR =\n \"Reactor stopped before the matched trigger started its run; rerun it to fire the workflow with the same payload\";\n\n// A matched fire, durable before the operation batch that matched it returns.\n// Nothing executes it yet: fire() adopts the row and turns it RUNNING.\nexport const PENDING_RUN_STATUS = \"PENDING\";\n\nfunction errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\n// Postgres 42P07: the constraint's backing index is already there, which is\n// what a re-run migration looks like. Bad data raises 23505 instead.\nfunction isDuplicateObject(error: unknown): boolean {\n if (typeof error !== \"object\" || error === null) return false;\n return (error as { code?: unknown }).code === \"42P07\";\n}\n\nasync function up(db: IRelationalDb<WorkflowRuntimeDB>): Promise<Set<string>> {\n await db.schema\n .createTable(\"run\")\n .addColumn(\"id\", \"text\", (col) => col.primaryKey())\n .addColumn(\"workflow_id\", \"text\", (col) => col.notNull())\n .addColumn(\"workflow_name\", \"text\", (col) => col.notNull())\n .addColumn(\"workflow_version\", \"integer\", (col) => col.notNull())\n .addColumn(\"trigger_kind\", \"text\", (col) => col.notNull())\n .addColumn(\"trigger_payload\", \"text\")\n .addColumn(\"status\", \"text\", (col) => col.notNull())\n .addColumn(\"error\", \"text\")\n .addColumn(\"started_at\", \"text\", (col) => col.notNull())\n .addColumn(\"ended_at\", \"text\")\n .addColumn(\"rerun_of\", \"text\")\n .ifNotExists()\n .execute();\n\n // Additive migration for journals created before rerun support.\n try {\n await db.schema.alterTable(\"run\").addColumn(\"rerun_of\", \"text\").execute();\n } catch {\n // column already exists\n }\n\n await db.schema\n .createTable(\"trigger_state\")\n .addColumn(\"workflow_id\", \"text\", (col) => col.primaryKey())\n .addColumn(\"block_type\", \"text\", (col) => col.notNull())\n .addColumn(\"config_hash\", \"text\", (col) => col.notNull())\n .addColumn(\"status\", \"text\", (col) => col.notNull())\n .addColumn(\"store_state\", \"text\", (col) => col.notNull())\n .addColumn(\"interval_ms\", \"integer\", (col) => col.notNull())\n .addColumn(\"next_poll_at\", \"text\")\n .addColumn(\"last_poll_at\", \"text\")\n .addColumn(\"last_error\", \"text\")\n .addColumn(\"consecutive_failures\", \"integer\", (col) => col.notNull())\n .addColumn(\"lease_owner\", \"text\")\n .addColumn(\"lease_expires_at\", \"text\")\n .addColumn(\"updated_at\", \"text\", (col) => col.notNull())\n .ifNotExists()\n .execute();\n\n await db.schema\n .createTable(\"trigger_dedupe\")\n .addColumn(\"workflow_id\", \"text\", (col) => col.notNull())\n .addColumn(\"dedupe_key\", \"text\", (col) => col.notNull())\n .addColumn(\"run_id\", \"text\")\n .addColumn(\"created_at\", \"text\", (col) => col.notNull())\n .addPrimaryKeyConstraint(\"trigger_dedupe_pk\", [\"workflow_id\", \"dedupe_key\"])\n .ifNotExists()\n .execute();\n\n await db.schema\n .createTable(\"step_execution\")\n .addColumn(\"id\", \"text\", (col) => col.primaryKey())\n .addColumn(\"run_id\", \"text\", (col) => col.notNull())\n .addColumn(\"ordinal\", \"integer\", (col) => col.notNull())\n .addColumn(\"step_id\", \"text\", (col) => col.notNull())\n .addColumn(\"step_key\", \"text\", (col) => col.notNull())\n .addColumn(\"block_type\", \"text\", (col) => col.notNull())\n .addColumn(\"status\", \"text\", (col) => col.notNull())\n .addColumn(\"input\", \"text\")\n .addColumn(\"output\", \"text\")\n .addColumn(\"port\", \"text\")\n .addColumn(\"error\", \"text\")\n .addUniqueConstraint(\"step_execution_run_step\", [\"run_id\", \"step_id\"])\n .ifNotExists()\n .execute();\n\n // Additive migration for journals created before per-step journaling: the\n // upsert in recordStep/finishRun needs this constraint to conflict on.\n try {\n await db.schema\n .alterTable(\"step_execution\")\n .addUniqueConstraint(\"step_execution_run_step\", [\"run_id\", \"step_id\"])\n .execute();\n } catch (error) {\n // Only \"already there\" is benign. Swallowing anything else would leave\n // every later upsert failing on a missing ON CONFLICT target.\n if (!isDuplicateObject(error)) {\n throw new Error(\n `Could not add the step_execution (run_id, step_id) unique constraint, ` +\n `which per-step journaling upserts against: ${errorMessage(error)}`,\n { cause: error },\n );\n }\n }\n\n await db.schema\n .createTable(\"piece_store\")\n .addColumn(\"scope\", \"text\", (col) => col.notNull())\n .addColumn(\"scope_key\", \"text\", (col) => col.notNull())\n .addColumn(\"key\", \"text\", (col) => col.notNull())\n .addColumn(\"value\", \"text\", (col) => col.notNull())\n .addColumn(\"updated_at\", \"text\", (col) => col.notNull())\n .addPrimaryKeyConstraint(\"piece_store_pk\", [\"scope\", \"scope_key\", \"key\"])\n .ifNotExists()\n .execute();\n\n // The reactor's webhook service owns tokens now, in its own namespace, so\n // the local table is dead weight wherever the GraphQL ingress once ran.\n\n // Nothing is migrated: those tokens addressed a mutation that no longer\n // exists, so a trigger re-enables onto a freshly minted endpoint.\n try {\n await db.schema.dropTable(\"webhook_endpoint\").ifExists().execute();\n } catch {\n // Never blocks the journal: a leftover table costs nothing.\n }\n\n return migrateTriggerStoreState(db);\n}\n\n// MIGRATION: trigger store state used to round-trip through\n// trigger_state.store_state as one JSON blob; it lives in piece_store now.\n\n// Stranding it would strand a WEBHOOK trigger's registered endpoint id, and\n// then onDisable can never delete that endpoint: it leaks at the provider.\n\n// ONE-WAY DOOR: the blob is blanked once moved and never written again, so a\n// reactor rolled back past this point reads an empty cursor and re-delivers.\ninterface LegacyStoreStateRow {\n workflow_id: string;\n store_state: string;\n}\n\ninterface LegacyEntry {\n scope: \"FLOW\" | \"PROJECT\";\n scopeKey: string;\n key: string;\n value: unknown;\n}\n\ninterface PendingMigration {\n workflowId: string;\n entries: LegacyEntry[];\n}\n\n// Returns the workflows whose blob did not move: nothing reads store_state any\n// more, so their hooks would run against an empty piece_store.\nasync function migrateTriggerStoreState(\n db: IRelationalDb<WorkflowRuntimeDB>,\n): Promise<Set<string>> {\n const unmigrated = new Set<string>();\n let rows: LegacyStoreStateRow[];\n try {\n // Oldest first, so a later row's project key overwrites an earlier one;\n // workflow_id settles a tie rather than leaving it to row order.\n rows = await db\n .selectFrom(\"trigger_state\")\n .select([\"workflow_id\", \"store_state\"])\n .orderBy(\"updated_at\", \"asc\")\n .orderBy(\"workflow_id\", \"asc\")\n .execute();\n } catch (error) {\n // Never blocks the journal: a store that fails to open is returned as\n // `undefined` forever, which silently stops every trigger in the process.\n logger.error(\"Could not read trigger_state to migrate it: @error\", error);\n return unmigrated;\n }\n const pending: PendingMigration[] = [];\n for (const row of rows) {\n const entries = parseLegacyBlob(row, unmigrated);\n if (entries) pending.push({ workflowId: row.workflow_id, entries });\n }\n const projectWinner = resolveProjectCollisions(pending);\n for (const row of pending) {\n try {\n await migrateOneRow(db, row, projectWinner);\n } catch (error) {\n // Per row, for the same reason. The blob is only blanked on success, so\n // a row that failed here is retried on the next startup.\n unmigrated.add(row.workflowId);\n logger.error(\n `Could not migrate trigger store state for ${row.workflowId}`,\n error,\n );\n }\n }\n return unmigrated;\n}\n\n// A blob that cannot be read is left exactly as it is, and its workflow is\n// reported unmigrated: guessing at it would lose the state for good.\nfunction parseLegacyBlob(\n row: LegacyStoreStateRow,\n unmigrated: Set<string>,\n): LegacyEntry[] | null {\n if (!row.store_state || row.store_state === \"{}\") return null;\n let state: unknown;\n try {\n state = JSON.parse(row.store_state);\n } catch {\n logger.warn(\n `Leaving unparseable store_state for ${row.workflow_id} in place`,\n );\n unmigrated.add(row.workflow_id);\n return null;\n }\n if (typeof state !== \"object\" || state === null) {\n unmigrated.add(row.workflow_id);\n return null;\n }\n const entries: LegacyEntry[] = [];\n for (const [key, value] of Object.entries(state)) {\n // Only the unambiguous shape a test hook wrote is dropped. A bare \"test…\"\n // key may be a piece's own (\"testimonials\"), so it migrates instead.\n if (/^testflow_.+\\//.test(key)) continue;\n const flow = /^flow_(.+?)\\/(.+)$/.exec(key);\n if (flow) {\n entries.push({\n scope: \"FLOW\",\n scopeKey: flow[1],\n key: flow[2],\n value,\n });\n continue;\n }\n if (key.startsWith(\"test\")) {\n logger.info(\n `Migrating \"${key}\" for ${row.workflow_id} as a project key; it may be a test leftover`,\n );\n }\n entries.push({\n scope: \"PROJECT\",\n scopeKey: PROJECT_SCOPE_KEY,\n key,\n value,\n });\n }\n return entries;\n}\n\n// A bare project key lived inside each workflow's own row, so two workflows\n// can hold different values for one key and only one can survive the move.\n\n// Last write wins, over the whole set rather than whichever row the database\n// returned first, and every discarded value is named so an operator sees it.\nfunction resolveProjectCollisions(\n pending: PendingMigration[],\n): Map<string, string> {\n const winner = new Map<string, string>();\n const contested = new Map<string, string[]>();\n for (const row of pending) {\n for (const entry of row.entries) {\n if (entry.scope !== \"PROJECT\") continue;\n const previous = winner.get(entry.key);\n if (previous !== undefined) {\n const seen = contested.get(entry.key) ?? [previous];\n contested.set(entry.key, [...seen, row.workflowId]);\n }\n winner.set(entry.key, row.workflowId);\n }\n }\n for (const [key, workflows] of contested) {\n logger.warn(\n `Project store key \"${key}\" was written by ${workflows.join(\", \")}; keeping the value last updated, from ${winner.get(key)}, and discarding the rest`,\n );\n }\n return winner;\n}\n\nasync function migrateOneRow(\n db: IRelationalDb<WorkflowRuntimeDB>,\n row: PendingMigration,\n projectWinner: Map<string, string>,\n): Promise<void> {\n for (const entry of row.entries) {\n // Another workflow updated its row later, so its copy of this project key\n // is the surviving one.\n if (\n entry.scope === \"PROJECT\" &&\n projectWinner.get(entry.key) !== row.workflowId\n ) {\n continue;\n }\n await insertPieceStoreIfAbsent(\n db,\n entry.scope,\n entry.scopeKey,\n entry.key,\n entry.value,\n );\n }\n // Blanked once moved, so a later startup cannot replay a stale blob over\n // what the trigger has written since.\n await db\n .updateTable(\"trigger_state\")\n .set({ store_state: \"{}\" })\n .where(\"workflow_id\", \"=\", row.workflowId)\n .execute();\n}\n\n// A key the piece has already rewritten under the new layout wins: the blob is\n// the older copy by construction.\nasync function insertPieceStoreIfAbsent(\n db: IRelationalDb<WorkflowRuntimeDB>,\n scope: string,\n scopeKey: string,\n key: string,\n value: unknown,\n): Promise<void> {\n const encoded = jsonOrNull(value);\n if (encoded === null) return;\n // The blob had no ceilings; piece_store inherits the action ones. A value\n // over them still migrates, but every later put on it will throw.\n warnIfOverPieceStoreLimits(scope, scopeKey, key, encoded);\n const existing = await db\n .selectFrom(\"piece_store\")\n .select(\"key\")\n .where(\"scope\", \"=\", scope)\n .where(\"scope_key\", \"=\", scopeKey)\n .where(\"key\", \"=\", key)\n .executeTakeFirst();\n if (existing) return;\n // doNothing, not a bare insert: two reactors starting against one journal\n // both see no row, and a PK violation here would reject up() and the store.\n await db\n .insertInto(\"piece_store\")\n .values({\n scope,\n scope_key: scopeKey,\n key,\n value: encoded,\n updated_at: new Date().toISOString(),\n })\n .onConflict((oc) => oc.columns([\"scope\", \"scope_key\", \"key\"]).doNothing())\n .execute();\n}\n\n// Loud rather than fatal: a trigger whose accumulated state is already over\n// the ceiling would otherwise start failing on its next put with no clue why.\nfunction warnIfOverPieceStoreLimits(\n scope: string,\n scopeKey: string,\n key: string,\n encoded: string,\n): void {\n const at = `${scope}/${scopeKey}/${key}`;\n if (key.length > PIECE_STORE_MAX_KEY_LENGTH) {\n logger.warn(\n `Migrated store key ${at} is ${key.length} chars, over the ${PIECE_STORE_MAX_KEY_LENGTH} limit; writes to it will fail`,\n );\n }\n const size = Buffer.byteLength(encoded, \"utf8\");\n if (size > PIECE_STORE_MAX_VALUE_BYTES) {\n logger.warn(\n `Migrated store value ${at} is ${size} bytes, over the ${PIECE_STORE_MAX_VALUE_BYTES} limit; writes to it will fail`,\n );\n }\n}\n\n// Their own ceilings (STORE_KEY_MAX_LENGTH, STORE_VALUE_MAX_SIZE), so a piece\n// that behaves on Activepieces behaves here. Enforced on the host, not the child.\nexport const PIECE_STORE_MAX_KEY_LENGTH = 128;\nexport const PIECE_STORE_MAX_VALUE_BYTES = 512 * 1024;\n\nexport class PieceStoreLimitError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"PieceStoreLimitError\";\n }\n}\n\nfunction assertPieceStoreEntry(key: string, value: unknown): void {\n if (key.length === 0 || key.length > PIECE_STORE_MAX_KEY_LENGTH) {\n throw new PieceStoreLimitError(\n `Store key must be 1-${PIECE_STORE_MAX_KEY_LENGTH} characters, got ${key.length}`,\n );\n }\n // stringify yields undefined for functions/symbols despite its typing.\n const encoded = JSON.stringify(value) as string | undefined;\n if (encoded === undefined) {\n throw new PieceStoreLimitError(`Store value for \"${key}\" is not JSON`);\n }\n const size = Buffer.byteLength(encoded, \"utf8\");\n if (size > PIECE_STORE_MAX_VALUE_BYTES) {\n throw new PieceStoreLimitError(\n `Store value for \"${key}\" is ${size} bytes, over the ${PIECE_STORE_MAX_VALUE_BYTES} byte limit`,\n );\n }\n}\n\n// Every column of a step_execution row but its surrogate id, shared by the\n// per-step write and the closing sweep so the two cannot drift.\n\n// It is also the last gate before a credential becomes a database row, which\n// is why the redaction sits here rather than at each writer.\n\n// Only the key-based pass runs here; the run's own secret values are the\n// engine's to match, and the store never sees them.\nfunction stepValues(runId: string, ordinal: number, step: StepExecutionRecord) {\n return {\n run_id: runId,\n ordinal,\n step_id: step.stepId,\n step_key: step.key,\n block_type: step.blockType,\n status: step.status,\n input: jsonOrNull(redact(step.input)),\n output: jsonOrNull(redact(step.output)),\n port: step.port ?? null,\n error: step.error ? redactMessage(step.error) : null,\n };\n}\n\nfunction jsonOrNull(value: unknown): string | null {\n if (value === undefined) return null;\n try {\n // stringify yields undefined for functions/symbols despite its typing.\n const text = JSON.stringify(value) as string | undefined;\n return text ?? null;\n } catch {\n return null;\n }\n}\n\nexport interface EnqueueRunOptions {\n workflowId: string;\n triggerKind: string;\n triggerPayload?: unknown;\n}\n\nexport interface StartRunOptions {\n workflowId: string;\n workflowName: string;\n workflowVersion: number;\n triggerKind: string;\n triggerPayload?: unknown;\n rerunOf?: string;\n}\n\n// Runs this process started and has not closed out. A run outlives its store:\n// configure() opens a new one on each hot reload, mid-flight runs and all.\n\nexport class WorkflowRunStore {\n // Runtime-local on purpose. A second reactor over the same journal would\n // need a lease, and one that can block startup costs more than a sweep.\n private readonly runsInFlight = new Set<string>();\n\n private constructor(\n private readonly db: IRelationalDb<WorkflowRuntimeDB>,\n private readonly unmigrated: Set<string>,\n ) {}\n\n static async create(relationalDb: IRelationalDb): Promise<WorkflowRunStore> {\n const db = (await relationalDb.createNamespace(\n \"workflow_runtime\",\n )) as IRelationalDb<WorkflowRuntimeDB>;\n const unmigrated = await up(db);\n const store = new WorkflowRunStore(db, unmigrated);\n await store.recoverOrphanedRuns();\n await store.recoverAbandonedRuns();\n return store;\n }\n\n // Its legacy store_state never reached piece_store, so the hook would run\n // against an empty one, unable to name the endpoint onDisable has to free.\n hasUnmigratedTriggerState(workflowId: string): boolean {\n return this.unmigrated.has(workflowId);\n }\n\n // The trigger no longer depends on the blob — it was re-enabled from\n // scratch — so it may be scheduled again without waiting for a restart.\n clearUnmigratedTriggerState(workflowId: string): void {\n this.unmigrated.delete(workflowId);\n }\n\n // A run still RUNNING when the journal opens, and not one of ours, belongs\n // to a process that is gone: close it out as FAILED.\n\n // Without this the steps journaled before the crash are unreachable, since\n // rerun() only accepts a FAILED run.\n async recoverOrphanedRuns(): Promise<number> {\n let query = this.db\n .updateTable(\"run\")\n .set({\n status: \"FAILED\",\n error: ORPHANED_RUN_ERROR,\n ended_at: new Date().toISOString(),\n })\n .where(\"status\", \"=\", \"RUNNING\");\n // Failing a run this process is still executing would hand rerun() a live\n // run, and its side effects would happen twice.\n if (this.runsInFlight.size > 0) {\n query = query.where(\"id\", \"not in\", [...this.runsInFlight]);\n }\n const result = await query.executeTakeFirst();\n const recovered = Number(result.numUpdatedRows);\n if (recovered > 0) {\n logger.warn(\n `Recovered ${recovered} workflow run(s) left RUNNING by a stopped reactor; they are now FAILED and rerunnable`,\n );\n }\n return recovered;\n }\n\n // A PENDING run left by a stopped process: it was matched and journaled but\n // nothing ever started it. Recovery for RUNNING runs cannot reach it — that\n // sweep must not touch a row a live enqueue is about to adopt — so it gets\n // its own pass, run once when the journal opens.\n async recoverAbandonedRuns(): Promise<number> {\n let query = this.db\n .updateTable(\"run\")\n .set({\n status: \"FAILED\",\n error: ABANDONED_PENDING_RUN_ERROR,\n ended_at: new Date().toISOString(),\n })\n .where(\"status\", \"=\", PENDING_RUN_STATUS);\n if (this.runsInFlight.size > 0) {\n query = query.where(\"id\", \"not in\", [...this.runsInFlight]);\n }\n const result = await query.executeTakeFirst();\n const recovered = Number(result.numUpdatedRows);\n if (recovered > 0) {\n logger.warn(\n `Recovered ${recovered} workflow run(s) journaled by a stopped reactor but never started; they are now FAILED and rerunnable`,\n );\n }\n return recovered;\n }\n\n // The durable record of a matched trigger, written before the operation\n // batch that matched it is acknowledged. The workflow's name and version are\n // only known once fire() reads the document, so beginRun fills them in.\n async enqueueRun(options: EnqueueRunOptions): Promise<string> {\n const id = randomUUID();\n await this.db\n .insertInto(\"run\")\n .values({\n id,\n workflow_id: options.workflowId,\n workflow_name: \"\",\n workflow_version: 0,\n trigger_kind: options.triggerKind,\n trigger_payload: jsonOrNull(redact(options.triggerPayload)),\n status: PENDING_RUN_STATUS,\n error: null,\n started_at: new Date().toISOString(),\n ended_at: null,\n rerun_of: null,\n })\n .execute();\n // In flight from here: the row is this process's to finish, and no sweep\n // of either kind may close it out underneath the run about to start.\n this.runsInFlight.add(id);\n return id;\n }\n\n // Adopts an enqueued row: the run starts now, with the definition fire() read.\n async beginRun(\n runId: string,\n details: { workflowName: string; workflowVersion: number },\n ): Promise<void> {\n this.runsInFlight.add(runId);\n await this.db\n .updateTable(\"run\")\n .set({\n status: \"RUNNING\",\n workflow_name: details.workflowName,\n workflow_version: details.workflowVersion,\n // The wait between enqueue and start is queueing, not run time.\n started_at: new Date().toISOString(),\n })\n .where(\"id\", \"=\", runId)\n .execute();\n }\n\n async startRun(options: StartRunOptions): Promise<string> {\n const id = randomUUID();\n await this.db\n .insertInto(\"run\")\n .values({\n id,\n workflow_id: options.workflowId,\n workflow_name: options.workflowName,\n workflow_version: options.workflowVersion,\n trigger_kind: options.triggerKind,\n trigger_payload: jsonOrNull(redact(options.triggerPayload)),\n status: \"RUNNING\",\n error: null,\n started_at: new Date().toISOString(),\n ended_at: null,\n rerun_of: options.rerunOf ?? null,\n })\n .execute();\n this.runsInFlight.add(id);\n return id;\n }\n\n // One step's terminal state, written the moment it reaches it, so a\n // reactor killed mid-run leaves the work it finished behind.\n\n // Keyed by (run_id, step_id): a re-executed step corrects its row.\n async recordStep(\n runId: string,\n ordinal: number,\n step: StepExecutionRecord,\n ): Promise<void> {\n const values = stepValues(runId, ordinal, step);\n const { run_id: _run, step_id: _step, ...mutable } = values;\n await this.db\n .insertInto(\"step_execution\")\n .values({ id: randomUUID(), ...values })\n .onConflict((oc) =>\n oc.columns([\"run_id\", \"step_id\"]).doUpdateSet(mutable),\n )\n .execute();\n }\n\n // Closes the run out. `executionOrder` maps step id to the ordinal the step\n // ran with, which a lost row cannot otherwise be given back.\n async finishRun(\n runId: string,\n result: WorkflowRunResult,\n executionOrder?: ReadonlyMap<string, number>,\n ): Promise<void> {\n // Terminal from here whatever the writes below do: if we leave the run\n // RUNNING, a later sweep should be free to reach it.\n this.runsInFlight.delete(runId);\n if (result.steps.length > 0) {\n try {\n await this.sweepSteps(runId, result, executionOrder);\n } catch (error) {\n // The work is done and the caller is owed its result: a journal that\n // cannot record the steps must not also cost the run its status.\n logger.warn(\n `Run ${runId}: writing the closing step journal failed; the run is closed out without it`,\n error,\n );\n }\n }\n await this.db\n .updateTable(\"run\")\n .set({\n status: result.status,\n error: result.error ? redactMessage(result.error) : null,\n ended_at: new Date().toISOString(),\n })\n .where(\"id\", \"=\", runId)\n .execute();\n }\n\n // Upserts the whole step set: fills in the SKIPPED sweep per-step journaling\n // omits, and repairs the rows a failed journal write left behind.\n private async sweepSteps(\n runId: string,\n result: WorkflowRunResult,\n executionOrder?: ReadonlyMap<string, number>,\n ): Promise<void> {\n const journaled = await this.db\n .selectFrom(\"step_execution\")\n .select([\"step_id\", \"ordinal\"])\n .where(\"run_id\", \"=\", runId)\n .execute();\n // A journaled step keeps the ordinal it ran with; the sweep lands after\n // the highest of them.\n const ordinals = new Map(\n journaled.map((row) => [row.step_id, row.ordinal]),\n );\n let nextOrdinal = journaled.reduce(\n (max, row) => Math.max(max, row.ordinal + 1),\n 0,\n );\n for (const step of result.steps) {\n const ran = executionOrder?.get(step.stepId);\n // A step that ran but lost its write goes back where it ran, not where\n // the definition happens to list it.\n if (ran === undefined || ordinals.has(step.stepId)) continue;\n ordinals.set(step.stepId, ran);\n nextOrdinal = Math.max(nextOrdinal, ran + 1);\n }\n // Skips never ran and never journaled an ordinal, so they trail everything\n // that did, in definition order.\n const ordinalFor = (step: StepExecutionRecord) =>\n ordinals.get(step.stepId) ?? nextOrdinal++;\n await this.db\n .insertInto(\"step_execution\")\n .values(\n result.steps.map((step) => ({\n id: randomUUID(),\n ...stepValues(runId, ordinalFor(step), step),\n })),\n )\n .onConflict((oc) =>\n oc.columns([\"run_id\", \"step_id\"]).doUpdateSet((eb) => ({\n ordinal: eb.ref(\"excluded.ordinal\"),\n step_key: eb.ref(\"excluded.step_key\"),\n block_type: eb.ref(\"excluded.block_type\"),\n status: eb.ref(\"excluded.status\"),\n input: eb.ref(\"excluded.input\"),\n output: eb.ref(\"excluded.output\"),\n port: eb.ref(\"excluded.port\"),\n error: eb.ref(\"excluded.error\"),\n })),\n )\n .execute();\n }\n\n async failRun(runId: string, error: string): Promise<void> {\n this.runsInFlight.delete(runId);\n await this.db\n .updateTable(\"run\")\n .set({\n status: \"FAILED\",\n error: redactMessage(error),\n ended_at: new Date().toISOString(),\n })\n .where(\"id\", \"=\", runId)\n .execute();\n }\n\n // Scope is one workflow id, or a set of them (a drive's workflows). An\n // empty set matches nothing, which is not the same as an unscoped listing.\n async listRuns(\n workflowId?: string | string[],\n limit = 25,\n ): Promise<RunRow[]> {\n if (Array.isArray(workflowId) && workflowId.length === 0) return [];\n let query = this.db\n .selectFrom(\"run\")\n .selectAll()\n .orderBy(\"started_at\", \"desc\")\n .limit(Math.min(Math.max(limit, 1), 100));\n if (Array.isArray(workflowId)) {\n query = query.where(\"workflow_id\", \"in\", workflowId);\n } else if (workflowId) {\n query = query.where(\"workflow_id\", \"=\", workflowId);\n }\n return query.execute();\n }\n\n async getRun(id: string): Promise<RunRow | undefined> {\n return this.db\n .selectFrom(\"run\")\n .selectAll()\n .where(\"id\", \"=\", id)\n .executeTakeFirst();\n }\n\n async getSteps(runId: string): Promise<StepExecutionRow[]> {\n return this.db\n .selectFrom(\"step_execution\")\n .selectAll()\n .where(\"run_id\", \"=\", runId)\n .orderBy(\"ordinal\", \"asc\")\n .execute();\n }\n\n async getTriggerState(\n workflowId: string,\n ): Promise<TriggerStateRow | undefined> {\n return this.db\n .selectFrom(\"trigger_state\")\n .selectAll()\n .where(\"workflow_id\", \"=\", workflowId)\n .executeTakeFirst();\n }\n\n // last_error is whatever a piece's onEnable or a schedule parse threw, so it\n // goes through the same gate a poll failure does.\n async upsertTriggerState(row: TriggerStateRow): Promise<void> {\n const values = {\n ...row,\n last_error: row.last_error ? redactMessage(row.last_error) : null,\n };\n await this.db\n .insertInto(\"trigger_state\")\n .values(values)\n .onConflict((oc) => {\n const { workflow_id: _, ...rest } = values;\n return oc.column(\"workflow_id\").doUpdateSet(rest);\n })\n .execute();\n }\n\n async setTriggerStatus(\n workflowId: string,\n status: string,\n error?: string,\n ): Promise<void> {\n await this.db\n .updateTable(\"trigger_state\")\n .set({\n status,\n last_error: error ? redactMessage(error) : null,\n updated_at: new Date().toISOString(),\n })\n .where(\"workflow_id\", \"=\", workflowId)\n .execute();\n }\n\n async listDueTriggerStates(nowIso: string): Promise<TriggerStateRow[]> {\n const rows = await this.db\n .selectFrom(\"trigger_state\")\n .selectAll()\n .where(\"status\", \"=\", \"ENABLED\")\n .where(\"next_poll_at\", \"<=\", nowIso)\n .execute();\n // A row whose state is still trapped in the blob is not runnable: polling\n // it would advance an empty cursor and re-deliver everything it ever saw.\n return rows.filter((row) => !this.unmigrated.has(row.workflow_id));\n }\n\n async listTriggerStates(): Promise<TriggerStateRow[]> {\n return this.db\n .selectFrom(\"trigger_state\")\n .selectAll()\n .orderBy(\"workflow_id\", \"asc\")\n .execute();\n }\n\n // A null next_poll_at leaves the trigger unscheduled, which is what a\n // webhook delivery wants: it recorded a success without becoming a poll.\n async recordPollSuccess(\n workflowId: string,\n storeState: string,\n nowIso: string,\n nextPollAtIso: string | null,\n ): Promise<void> {\n await this.db\n .updateTable(\"trigger_state\")\n .set({\n store_state: storeState,\n last_poll_at: nowIso,\n next_poll_at: nextPollAtIso,\n last_error: null,\n consecutive_failures: 0,\n updated_at: nowIso,\n })\n .where(\"workflow_id\", \"=\", workflowId)\n .execute();\n }\n\n async recordPollFailure(\n workflowId: string,\n error: string,\n nowIso: string,\n nextPollAtIso: string,\n consecutiveFailures: number,\n ): Promise<void> {\n await this.db\n .updateTable(\"trigger_state\")\n .set({\n last_poll_at: nowIso,\n next_poll_at: nextPollAtIso,\n last_error: redactMessage(error),\n consecutive_failures: consecutiveFailures,\n updated_at: nowIso,\n })\n .where(\"workflow_id\", \"=\", workflowId)\n .execute();\n }\n\n // Claim-with-status dedupe: true when the key was free (caller fires).\n // The insert's own conflict outcome is the claim; a prior select can't be trusted.\n async claimDedupe(\n workflowId: string,\n dedupeKey: string,\n ttlMs: number,\n nowIso: string,\n ): Promise<boolean> {\n const cutoff = new Date(Date.parse(nowIso) - ttlMs).toISOString();\n await this.db\n .deleteFrom(\"trigger_dedupe\")\n .where(\"workflow_id\", \"=\", workflowId)\n .where(\"created_at\", \"<\", cutoff)\n .execute();\n const inserted = await this.db\n .insertInto(\"trigger_dedupe\")\n .values({\n workflow_id: workflowId,\n dedupe_key: dedupeKey,\n run_id: null,\n created_at: nowIso,\n })\n .onConflict((oc) => oc.columns([\"workflow_id\", \"dedupe_key\"]).doNothing())\n .returning(\"dedupe_key\")\n .executeTakeFirst();\n return inserted !== undefined;\n }\n\n async recordDedupeRun(\n workflowId: string,\n dedupeKey: string,\n runId: string,\n ): Promise<void> {\n await this.db\n .updateTable(\"trigger_dedupe\")\n .set({ run_id: runId })\n .where(\"workflow_id\", \"=\", workflowId)\n .where(\"dedupe_key\", \"=\", dedupeKey)\n .execute();\n }\n\n async getPieceStoreValue(\n scope: string,\n scopeKey: string,\n key: string,\n ): Promise<unknown> {\n const row = await this.db\n .selectFrom(\"piece_store\")\n .select(\"value\")\n .where(\"scope\", \"=\", scope)\n .where(\"scope_key\", \"=\", scopeKey)\n .where(\"key\", \"=\", key)\n .executeTakeFirst();\n if (!row) return null;\n try {\n return JSON.parse(row.value);\n } catch {\n // A row we cannot parse is a row we cannot honour; the piece sees the\n // key as absent and the next write replaces it.\n return null;\n }\n }\n\n async setPieceStoreValue(\n scope: string,\n scopeKey: string,\n key: string,\n value: unknown,\n ): Promise<void> {\n assertPieceStoreEntry(key, value);\n const encoded = JSON.stringify(value);\n const nowIso = new Date().toISOString();\n // One upsert, not select-then-branch: concurrent writers can share a scope\n // (PROJECT scope_key is one row for every workflow) and would otherwise race.\n await this.db\n .insertInto(\"piece_store\")\n .values({\n scope,\n scope_key: scopeKey,\n key,\n value: encoded,\n updated_at: nowIso,\n })\n .onConflict((oc) =>\n oc\n .columns([\"scope\", \"scope_key\", \"key\"])\n .doUpdateSet({ value: encoded, updated_at: nowIso }),\n )\n .execute();\n }\n\n async deletePieceStoreValue(\n scope: string,\n scopeKey: string,\n key: string,\n ): Promise<void> {\n await this.db\n .deleteFrom(\"piece_store\")\n .where(\"scope\", \"=\", scope)\n .where(\"scope_key\", \"=\", scopeKey)\n .where(\"key\", \"=\", key)\n .execute();\n }\n\n // Every key one scope holds; for inspection and for tearing a workflow down.\n async listPieceStore(\n scope: string,\n scopeKey: string,\n ): Promise<Record<string, unknown>> {\n const rows = await this.db\n .selectFrom(\"piece_store\")\n .selectAll()\n .where(\"scope\", \"=\", scope)\n .where(\"scope_key\", \"=\", scopeKey)\n .execute();\n const out: Record<string, unknown> = {};\n for (const row of rows) {\n try {\n out[row.key] = JSON.parse(row.value);\n } catch {\n // Same reasoning as the single-key read above.\n }\n }\n return out;\n }\n\n async deletePieceStore(scope: string, scopeKey: string): Promise<void> {\n await this.db\n .deleteFrom(\"piece_store\")\n .where(\"scope\", \"=\", scope)\n .where(\"scope_key\", \"=\", scopeKey)\n .execute();\n }\n}\n","// Timer-driven trigger supervisor: owns piece-trigger lifecycle (enable/\n// disable, poll cursors) and core#schedule fires.\n\n// Scheduling state lives in trigger_state; whatever a hook writes through\n// ctx.store lives in piece_store, beside what actions write.\nimport {\n DEFAULT_EGRESS_POLICY,\n extractDedupeKey,\n pieceModuleRef,\n PieceWorker,\n PieceWorkerError,\n secretsFor,\n storeHandlers,\n type ConnectionRequest,\n type PieceDescriptor,\n type EgressPolicy,\n type PieceResolver,\n type PieceWorkerResult,\n type RecordedSchedule,\n type TriggerHookRequest,\n} from \"../pieces/index.js\";\nimport { childLogger } from \"document-model\";\nimport { createHash } from \"node:crypto\";\nimport { fetchingResolver } from \"./lib.js\";\nimport {\n cronIntervalMs,\n MIN_SCHEDULE_INTERVAL_MS,\n nextFireAt,\n parseScheduleConfig,\n rescheduleAfterFire,\n schedulePayload,\n SCHEDULE_BLOCK,\n} from \"./schedule.js\";\nimport { createPieceStorePort, testPartitionKey } from \"./piece-store-port.js\";\nimport type { TriggerStateRow, WorkflowRunStore } from \"./store.js\";\n\nconst logger = childLogger([\"workflow\", \"trigger-supervisor\"]);\n\nexport interface PieceTriggerBinding {\n kind?: \"piece\";\n workflowId: string;\n blockType: string;\n packageName: string;\n version: string;\n triggerName: string;\n config: Record<string, unknown>;\n connectionId?: string | null;\n // Author's poll cadence, from the trigger's pollEverySeconds. Overrides both\n // the piece's own setSchedule and the runtime default; the 60s floor holds.\n pollIntervalMs?: number;\n}\n\n// core#schedule: no piece hooks; next_poll_at is the next fire time.\nexport interface ScheduleTriggerBinding {\n kind: \"schedule\";\n workflowId: string;\n blockType: typeof SCHEDULE_BLOCK;\n config: Record<string, unknown>;\n}\n\nexport type TriggerBinding = PieceTriggerBinding | ScheduleTriggerBinding;\n\nexport const SCHEDULE_TRIGGER_KIND = \"schedule\";\n\nexport interface TriggerSupervisorOptions {\n store: () => Promise<WorkflowRunStore | undefined>;\n resolveAuth: (\n connectionId: string | null | undefined,\n request?: ConnectionRequest,\n ) => Promise<unknown>;\n fire: (workflowId: string, payload: unknown, kind: string) => void;\n cacheDir: string;\n // Where a trigger's piece comes from. Defaults to fetching into cacheDir,\n // so a host that ships pieces in a package passes its own.\n resolver?: PieceResolver;\n worker?: PieceWorker;\n // Where a trigger's piece may connect to. Left unset it is the default\n // policy, which refuses private address space; `null` lifts it entirely.\n egress?: EgressPolicy | null;\n tickMs?: number;\n defaultIntervalMs?: number;\n hookTimeoutMs?: number;\n // The endpoint a WEBHOOK-strategy piece registers with its provider, minted\n // per workflow by the reactor's webhook service. Without one, such a trigger\n // refuses to enable rather than registering a URL nothing can reach.\n webhookUrlFor?: (workflowId: string) => Promise<string | undefined>;\n // How often a webhook trigger reconciles by polling anyway. A provider that\n // drops a delivery — paperless never retries a transport error — would\n // otherwise lose the event for good.\n reconcileIntervalMs?: number;\n // Clock override for tests; defaults to the wall clock.\n now?: () => Date;\n}\n\nconst MIN_INTERVAL_MS = MIN_SCHEDULE_INTERVAL_MS;\nconst MAX_BACKOFF_MS = 30 * 60_000;\nconst DEDUPE_TTL_MS = 30_000;\nconst DEFAULT_RECONCILE_INTERVAL_MS = 15 * 60_000;\n\nfunction isSchedule(\n binding: TriggerBinding,\n): binding is ScheduleTriggerBinding {\n return binding.kind === \"schedule\";\n}\n\nexport function configHash(blockType: string, config: unknown): string {\n return createHash(\"sha256\")\n .update(blockType)\n .update(JSON.stringify(config ?? {}))\n .digest(\"hex\")\n .slice(0, 16);\n}\n\n// The poll cadence setSchedule asked for: the named interval, or the gap between\n// the cron's next two runs (60s floor); an unparseable cron uses the default.\nexport function intervalFromSchedules(\n schedules: RecordedSchedule[] | undefined,\n defaultMs: number,\n): number {\n const schedule = schedules?.at(-1);\n if (!schedule) return Math.max(defaultMs, MIN_INTERVAL_MS);\n if (\"intervalMs\" in schedule) {\n return Math.max(schedule.intervalMs, MIN_INTERVAL_MS);\n }\n const cron = schedule.cronExpression;\n const intervalMs = cronIntervalMs(cron);\n if (intervalMs === undefined) {\n logger.warn(`Unsupported setSchedule cron \"${cron}\"; using the default`);\n return Math.max(defaultMs, MIN_INTERVAL_MS);\n }\n return intervalMs;\n}\n\n// The cadence to poll a piece trigger at: the author's override when set,\n// else what the piece asked for, else the runtime default. Never below the floor.\nexport function pollIntervalFor(\n binding: PieceTriggerBinding,\n schedules: RecordedSchedule[] | undefined,\n defaultMs: number,\n): number {\n if (binding.pollIntervalMs !== undefined) {\n return Math.max(binding.pollIntervalMs, MIN_INTERVAL_MS);\n }\n return intervalFromSchedules(schedules, defaultMs);\n}\n\n// Trigger store state lives in piece_store now, beside the actions'. The\n// column is written but never read: see MIGRATION in store.ts on rollback.\nconst VESTIGIAL_STORE_STATE = \"{}\";\n\n// Raised where the journal is first found missing, rather than deeper: every\n// caller logs it, and a silent return here reads to them as success.\nexport class MissingJournalError extends Error {\n constructor(what: string) {\n super(`${what} needs a run journal, and none is configured`);\n this.name = \"MissingJournalError\";\n }\n}\n\n// A failure the operator has to fix: retrying it only burns cycles and buries\n// the real error under a growing failure count.\nexport class TriggerConfigError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"TriggerConfigError\";\n }\n}\n\n// Everything a piece throws looks alike once it crosses the worker boundary —\n// an expired token and a timeout are both name/message.\n\n// So only failures we can name structurally park; the rest retry.\nfunction isPermanentFailure(error: unknown): boolean {\n if (error instanceof TriggerConfigError) return true;\n return (\n error instanceof PieceWorkerError &&\n error.serialized.unsupportedMember !== undefined\n );\n}\n\ninterface EnableRetry {\n // Epoch ms of the next attempt.\n at: number;\n failures: number;\n // The last attempt reached onEnable, so the provider may be holding a\n // registration the next attempt has to release before making another.\n release: boolean;\n}\n\n// Same shape the poll path backs off with, so a trigger that cannot enable and\n// one that cannot poll retreat at the same rate and to the same ceiling.\nfunction backoffMs(intervalMs: number, failures: number): number {\n return Math.min(intervalMs * 2 ** failures, MAX_BACKOFF_MS);\n}\n\nexport class TriggerSupervisor {\n private readonly bindings = new Map<string, TriggerBinding>();\n private readonly worker: PieceWorker;\n private readonly tickMs: number;\n private readonly defaultIntervalMs: number;\n private readonly hookTimeoutMs: number;\n private readonly now: () => Date;\n private readonly egress: EgressPolicy | undefined;\n private timer?: NodeJS.Timeout;\n // Lifecycle ops serialize so enable/disable/poll never interleave per store.\n private ops: Promise<unknown> = Promise.resolve();\n private ticking = false;\n private warnedMissingJournal = false;\n\n constructor(private readonly options: TriggerSupervisorOptions) {\n this.worker = options.worker ?? new PieceWorker();\n this.tickMs = options.tickMs ?? 15_000;\n this.defaultIntervalMs = options.defaultIntervalMs ?? 300_000;\n this.hookTimeoutMs = options.hookTimeoutMs ?? 60_000;\n this.now = options.now ?? (() => new Date());\n this.egress =\n options.egress === undefined\n ? DEFAULT_EGRESS_POLICY\n : (options.egress ?? undefined);\n }\n\n start(): void {\n if (this.timer) return;\n this.timer = setInterval(() => {\n this.tick().catch((error: unknown) => {\n logger.error(\"Trigger tick failed: @error\", error);\n });\n }, this.tickMs);\n this.timer.unref();\n logger.info(`Trigger supervisor started (tick ${this.tickMs}ms)`);\n }\n\n stop(): void {\n if (this.timer) clearInterval(this.timer);\n this.timer = undefined;\n if (!this.options.worker) this.worker.dispose();\n logger.info(\"Trigger supervisor stopped\");\n }\n\n // Serialized: registration churn and ticks share one lane.\n private enqueue<T>(task: () => Promise<T>): Promise<T> {\n const run = this.ops.then(task);\n this.ops = run.catch(() => undefined);\n return run;\n }\n\n // Successfully enabled workflows; identical re-registrations are no-ops.\n private readonly enabledOk = new Set<string>();\n\n // Piece descriptors by package@version, for the trigger strategy lookup.\n private readonly descriptors = new Map<string, PieceDescriptor>();\n\n private own: PieceResolver | undefined;\n\n // The host's resolver when it supplied one — the runtime passes its\n // local-first one — else a fetch into the cache directory this supervisor\n // was configured with, which a direct caller may have warmed itself.\n private resolver(): PieceResolver {\n return (\n this.options.resolver ??\n (this.own ??= fetchingResolver(this.options.cacheDir))\n );\n }\n\n // Workflows whose onEnable failed and when to try again. The ERROR row keeps\n // the same time so a restart resumes the backoff instead of restarting it.\n private readonly enableRetries = new Map<string, EnableRetry>();\n\n upsert(binding: TriggerBinding): Promise<void> {\n const previous = this.bindings.get(binding.workflowId);\n if (\n previous &&\n this.enabledOk.has(binding.workflowId) &&\n JSON.stringify(previous) === JSON.stringify(binding)\n ) {\n return Promise.resolve();\n }\n this.bindings.set(binding.workflowId, binding);\n // The binding it replaces is the only thing that can still name the old\n // registration: the row holds neither the config nor the connection.\n return this.enqueue(() => this.enable(binding, previous));\n }\n\n remove(workflowId: string): Promise<void> {\n const binding = this.bindings.get(workflowId);\n this.bindings.delete(workflowId);\n this.enabledOk.delete(workflowId);\n this.enableRetries.delete(workflowId);\n return this.enqueue(() => this.disable(workflowId, binding));\n }\n\n // Design-time sample, run against its own partitions so no key it writes can\n // alias a live one, and dropped afterwards so none of it outlives the sample.\n test(binding: PieceTriggerBinding): Promise<unknown> {\n return this.enqueue(async () => {\n const store = await this.options.store();\n try {\n const result = await this.hook(binding, \"test\");\n return result.output;\n } finally {\n await this.dropTestPartitions(store, binding.workflowId);\n }\n });\n }\n\n // Best-effort: a sample that leaves rows behind is untidy, but failing the\n // sample over it would be worse, and the next one overwrites them anyway.\n private async dropTestPartitions(\n store: WorkflowRunStore | undefined,\n workflowId: string,\n ): Promise<void> {\n if (!store) return;\n try {\n await store.deletePieceStore(\n \"FLOW\",\n testPartitionKey(\"FLOW\", workflowId),\n );\n await store.deletePieceStore(\n \"PROJECT\",\n testPartitionKey(\"PROJECT\", workflowId),\n );\n } catch (error) {\n logger.warn(`Could not clear test store for ${workflowId}`, error);\n }\n }\n\n // The sender's probe, answered by the piece rather than by us: only its own\n // code knows what the sender wants echoed back. Serialised with\n // enable/disable like a delivery, so a probe arriving during a\n // re-registration cannot read a half-written store.\n handshake(\n binding: PieceTriggerBinding,\n payload: unknown,\n ): Promise<PieceWorkerResult> {\n return this.enqueue(() => this.hook(binding, \"onHandshake\", { payload }));\n }\n\n // Ingress path: a verified delivery runs the trigger's `run` hook with the\n // payload, then goes through the same dedupe and fire path a poll does. The\n // resolver never waits for this — providers time out fast (paperless allows\n // five seconds) and a slow run would look like a failed delivery.\n deliverWebhook(workflowId: string, payload: unknown): Promise<void> {\n return this.enqueue(async () => {\n const binding = this.bindings.get(workflowId);\n if (!binding || isSchedule(binding)) {\n logger.warn(`Webhook delivery for unknown workflow ${workflowId}`);\n return;\n }\n const store = await this.options.store();\n // Rejecting is what stops the resolver logging \"Webhook delivered\" for a\n // delivery that was dropped on the floor.\n if (!store) throw new MissingJournalError(\"Webhook delivery\");\n const row = await store.getTriggerState(workflowId);\n const now = this.now();\n // A dropped delivery is the provider's to retry, and paperless never\n // does — but a rewound cursor lets the reconcile poll find it again.\n const rewind = await this.cursorRewind(store, workflowId);\n try {\n const result = await this.hook(binding, \"run\", { payload });\n // Checked before the checkpoint, as a poll does: coercing a scalar to\n // no items leaves nothing to rewind, and the delivery is lost for good.\n if (!Array.isArray(result.output)) {\n throw new Error(\n `Trigger run returned ${typeof result.output}, expected an array`,\n );\n }\n // A delivery to a trigger that never enabled still fires, but it must\n // not clear the enable error or reset the backoff by recording a\n // success.\n if (row?.status === \"ENABLED\") {\n await store.recordPollSuccess(\n workflowId,\n VESTIGIAL_STORE_STATE,\n now.toISOString(),\n new Date(now.getTime() + row.interval_ms).toISOString(),\n );\n }\n for (const item of result.output) {\n await this.fireItem(store, binding, item, now);\n }\n } catch (error) {\n await rewind();\n throw error;\n }\n });\n }\n\n // Trigger delivery is at-least-once, and a durable store puts that at risk:\n // pollingHelper advances its cursor *inside* the hook.\n\n // A failure after that checkpoint would skip items the hook read but never\n // delivered, so a delivery attempt first takes the FLOW partition as it was.\n\n // Putting it back on any failure through the fire means the next read\n // re-delivers, and the dedupe table absorbs the repeats.\n private async cursorRewind(\n store: WorkflowRunStore,\n workflowId: string,\n ): Promise<() => Promise<void>> {\n const before = await store.listPieceStore(\"FLOW\", workflowId);\n return async () => {\n try {\n await store.deletePieceStore(\"FLOW\", workflowId);\n for (const [key, value] of Object.entries(before)) {\n await store.setPieceStoreValue(\"FLOW\", workflowId, key, value);\n }\n } catch (error) {\n // The poll already failed; losing the rewind too costs at-most-once\n // for this cursor, which still beats failing the supervisor's lane.\n logger.warn(`Could not rewind the cursor for ${workflowId}`, error);\n }\n };\n }\n\n // The hook's `ctx.store` is the journal's piece_store, served call by call,\n // so a registration id is durable the instant the piece writes it.\n private async hook(\n binding: PieceTriggerBinding,\n hook: TriggerHookRequest[\"hook\"],\n options: {\n isRepublish?: boolean;\n payload?: unknown;\n webhookUrl?: string;\n } = {},\n ): Promise<PieceWorkerResult> {\n const store = await this.options.store();\n // A cursor on the heap resets on restart and re-delivers everything the\n // trigger ever saw, so only a design-time sample may run without a journal.\n if (!store && hook !== \"test\") {\n throw new MissingJournalError(`Trigger hook \"${hook}\"`);\n }\n const pieceStore = store\n ? createPieceStorePort(store, () => binding.workflowId, hook === \"test\")\n : undefined;\n const piece = await this.resolver().resolve(\n binding.packageName,\n binding.version,\n );\n // A trigger's connection is the workflow's own, declared beside it, so it\n // needs no run binding — but it is still bound to its connector.\n const auth = await this.options.resolveAuth(binding.connectionId, {\n blockType: binding.blockType,\n piecePackage: binding.packageName,\n });\n // Redacted in the child, so a hook's error crosses back without the\n // credential the connection resolved to.\n const redactValues = secretsFor(auth);\n return this.worker.runTriggerHook(\n {\n ...pieceModuleRef(piece),\n triggerName: binding.triggerName,\n hook,\n propsValue: binding.config,\n auth,\n ...(redactValues.length > 0 ? { redactValues } : {}),\n ...(pieceStore ? { durableStore: true } : {}),\n identity: { flowId: binding.workflowId },\n isRepublish: options.isRepublish,\n payload: options.payload,\n // A poll binding gets an unroutable URL on purpose: a live one would\n // let a piece register an endpoint that nothing ever delivers to.\n webhookUrl:\n options.webhookUrl ??\n `http://localhost:0/v1/webhooks/${binding.workflowId}`,\n ...(this.egress ? { egress: this.egress } : {}),\n },\n {\n timeoutMs: this.hookTimeoutMs,\n ...(pieceStore ? { hostCalls: storeHandlers(pieceStore) } : {}),\n },\n );\n }\n\n // A trigger's strategy lives in the piece descriptor, so it takes loading\n // the bundle. Enables are rare and the descriptor is cached per version.\n private async strategyFor(binding: PieceTriggerBinding): Promise<string> {\n const key = `${binding.packageName}@${binding.version}`;\n let descriptor = this.descriptors.get(key);\n if (!descriptor) {\n const piece = await this.resolver().resolve(\n binding.packageName,\n binding.version,\n );\n const result = await this.worker.describePiece(\n {\n ...pieceModuleRef(piece),\n packageName: binding.packageName,\n version: binding.version,\n ...(this.egress ? { egress: this.egress } : {}),\n },\n { timeoutMs: this.hookTimeoutMs },\n );\n descriptor = result.output as PieceDescriptor;\n this.descriptors.set(key, descriptor);\n }\n const trigger = descriptor.triggers.find(\n (candidate) => candidate.name === binding.triggerName,\n );\n return trigger?.strategy ?? \"POLLING\";\n }\n\n private async enable(\n binding: TriggerBinding,\n superseded?: TriggerBinding,\n ): Promise<void> {\n const store = await this.options.store();\n // enableSupervised logs this; returning quietly would leave a workflow\n // that looks registered and never fires.\n if (!store) throw new MissingJournalError(\"Enabling a trigger\");\n const hash = configHash(binding.blockType, binding.config);\n const existing = await store.getTriggerState(binding.workflowId);\n const now = this.now();\n // Only a completed enable is a republish: a retry after a failed one must\n // register again, or a piece that skips registration never delivers.\n\n // A republish also keeps the cursor and the _webhook_id the hook wrote\n // before, which is exactly what a blob that never migrated no longer holds.\n const isRepublish =\n existing?.config_hash === hash &&\n existing.status === \"ENABLED\" &&\n !store.hasUnmigratedTriggerState(binding.workflowId);\n if (existing && !isRepublish && existing.status === \"ENABLED\") {\n // The trigger changed: release the old registration first.\n await this.disableRow(binding.workflowId, existing, superseded);\n }\n const pending = this.enableRetries.get(binding.workflowId);\n if (isSchedule(binding)) {\n // A piece trigger replaced by core#schedule takes its retry with it;\n // left behind, the entry wins a slot on every tick and never resolves.\n this.enableRetries.delete(binding.workflowId);\n if (\n pending?.release &&\n existing &&\n superseded &&\n !isSchedule(superseded)\n ) {\n await this.releaseRegistration(superseded);\n }\n await this.enableSchedule(store, binding, hash, existing);\n return;\n }\n if (this.deferToStoredRetry(binding, hash, existing, now)) return;\n if (pending?.release && existing) {\n // The failed attempt may have subscribed at the provider already, and\n // only one subscription is ever released; drop it before making another.\n await this.releaseRegistration(binding);\n }\n // A changed config is a different trigger: carrying the old cursor and,\n // worse, the old _webhook_id would point it at a dead registration.\n if (!isRepublish) {\n await store.deletePieceStore(\"FLOW\", binding.workflowId);\n }\n let reachedProvider = false;\n try {\n const strategy = await this.strategyFor(binding);\n const webhook = strategy === \"WEBHOOK\" || strategy === \"APP_WEBHOOK\";\n // The reactor's webhook service owns the token and the URL it lives in,\n // so the piece is handed an address rather than a credential to place.\n const webhookUrl = webhook\n ? await this.webhookUrlOrThrow(binding.workflowId)\n : undefined;\n if (webhook && !webhookUrl) {\n throw new Error(\n \"This trigger delivers by webhook, but no public webhook endpoint is configured for the reactor\",\n );\n }\n reachedProvider = true;\n const result = await this.hook(binding, \"onEnable\", {\n isRepublish,\n webhookUrl,\n });\n // A webhook trigger still polls, just slowly: the poll is the\n // reconciliation sweep that recovers deliveries the provider dropped.\n const intervalMs = webhook\n ? (this.options.reconcileIntervalMs ?? DEFAULT_RECONCILE_INTERVAL_MS)\n : pollIntervalFor(binding, result.schedules, this.defaultIntervalMs);\n await store.upsertTriggerState({\n workflow_id: binding.workflowId,\n block_type: binding.blockType,\n config_hash: hash,\n status: \"ENABLED\",\n store_state: VESTIGIAL_STORE_STATE,\n interval_ms: intervalMs,\n next_poll_at: new Date(now.getTime() + intervalMs).toISOString(),\n last_poll_at: null,\n last_error: null,\n consecutive_failures: 0,\n lease_owner: null,\n lease_expires_at: null,\n updated_at: now.toISOString(),\n });\n this.enabledOk.add(binding.workflowId);\n this.enableRetries.delete(binding.workflowId);\n store.clearUnmigratedTriggerState(binding.workflowId);\n logger.info(\n `Enabled ${binding.blockType} for workflow ${binding.workflowId} (every ${intervalMs}ms)`,\n );\n } catch (error) {\n this.enabledOk.delete(binding.workflowId);\n const message = error instanceof Error ? error.message : String(error);\n const failures = (existing?.consecutive_failures ?? 0) + 1;\n const intervalMs = pollIntervalFor(\n binding,\n undefined,\n this.defaultIntervalMs,\n );\n // A third-party API down for a minute must not park the trigger for good,\n // so onEnable retries on the tick loop; the row stays ERROR until it takes.\n const retryAt = isPermanentFailure(error)\n ? undefined\n : new Date(now.getTime() + backoffMs(intervalMs, failures));\n if (retryAt) {\n this.enableRetries.set(binding.workflowId, {\n at: retryAt.getTime(),\n failures,\n release: reachedProvider,\n });\n } else this.enableRetries.delete(binding.workflowId);\n await store.upsertTriggerState({\n workflow_id: binding.workflowId,\n block_type: binding.blockType,\n config_hash: hash,\n status: \"ERROR\",\n store_state: VESTIGIAL_STORE_STATE,\n interval_ms: intervalMs,\n next_poll_at: retryAt?.toISOString() ?? null,\n last_poll_at: null,\n last_error: message,\n consecutive_failures: failures,\n lease_owner: null,\n lease_expires_at: null,\n updated_at: now.toISOString(),\n });\n logger.error(\n `onEnable failed for workflow ${binding.workflowId} (${failures}x): ${message}` +\n (retryAt\n ? `; retrying at ${retryAt.toISOString()}`\n : \"; not retrying\"),\n );\n }\n }\n\n // A reactor with no webhook service will never mint a URL; one that has not\n // finished starting has simply not minted this workflow's yet.\n private async webhookUrlOrThrow(workflowId: string): Promise<string> {\n const mint = this.options.webhookUrlFor;\n if (!mint) {\n throw new TriggerConfigError(\n \"This trigger delivers by webhook, but no public webhook endpoint is configured for the reactor\",\n );\n }\n const url = await mint(workflowId);\n if (!url) {\n throw new Error(\n \"The reactor's webhook endpoint is not available yet for this workflow\",\n );\n }\n return url;\n }\n\n // Backoff that only lives in memory is no backoff at all against a crash\n // loop, so a restart picks the retry time back up off the row.\n\n // A re-registration of the same config waits its turn too; only a changed\n // config is an operator saying \"try this one now\".\n private deferToStoredRetry(\n binding: PieceTriggerBinding,\n hash: string,\n existing: TriggerStateRow | undefined,\n now: Date,\n ): boolean {\n if (existing?.status !== \"ERROR\" || existing.config_hash !== hash) {\n return false;\n }\n const pending = this.enableRetries.get(binding.workflowId);\n const stored = existing.next_poll_at\n ? Date.parse(existing.next_poll_at)\n : NaN;\n const at = pending?.at ?? (Number.isFinite(stored) ? stored : undefined);\n if (at === undefined || at <= now.getTime()) return false;\n if (!pending) {\n this.enableRetries.set(binding.workflowId, {\n at,\n failures: existing.consecutive_failures,\n // Nothing in memory says how far the pre-restart attempt got, and a\n // stale subscription costs more than a redundant onDisable.\n release: true,\n });\n logger.info(\n `Enable for workflow ${binding.workflowId} still backing off until ${existing.next_poll_at}`,\n );\n }\n return true;\n }\n\n // Best effort: the ids a piece unsubscribes with reach us only when onEnable\n // returns, so a timed-out first attempt has nothing here to release with.\n\n // Closing that gap needs the worker to report store writes as they happen.\n private async releaseRegistration(\n binding: PieceTriggerBinding,\n ): Promise<void> {\n try {\n await this.hook(binding, \"onDisable\");\n } catch (error) {\n logger.warn(\n `onDisable before retrying workflow ${binding.workflowId} failed`,\n error,\n );\n }\n }\n\n // An unchanged, still-ENABLED row keeps its next fire time: that is what\n // carries a schedule across a restart. Anything else rebases on now.\n private async enableSchedule(\n store: WorkflowRunStore,\n binding: ScheduleTriggerBinding,\n hash: string,\n existing: TriggerStateRow | undefined,\n ): Promise<void> {\n const now = this.now();\n const base = {\n workflow_id: binding.workflowId,\n block_type: binding.blockType,\n config_hash: hash,\n store_state: VESTIGIAL_STORE_STATE,\n last_poll_at: existing?.last_poll_at ?? null,\n lease_owner: null,\n lease_expires_at: null,\n updated_at: now.toISOString(),\n };\n try {\n const schedule = parseScheduleConfig(binding.config);\n const carried =\n existing?.status === \"ENABLED\" && existing.config_hash === hash\n ? existing.next_poll_at\n : null;\n const nextAt = carried ? new Date(carried) : nextFireAt(schedule, now);\n await store.upsertTriggerState({\n ...base,\n status: \"ENABLED\",\n interval_ms:\n schedule.mode === \"interval\"\n ? schedule.everyMs\n : MIN_SCHEDULE_INTERVAL_MS,\n next_poll_at: nextAt.toISOString(),\n last_error: null,\n consecutive_failures: 0,\n });\n this.enabledOk.add(binding.workflowId);\n logger.info(\n `Scheduled workflow ${binding.workflowId}: next fire ${nextAt.toISOString()}` +\n (carried ? \" (carried over)\" : \"\"),\n );\n } catch (error) {\n this.enabledOk.delete(binding.workflowId);\n const message = error instanceof Error ? error.message : String(error);\n await store.upsertTriggerState({\n ...base,\n status: \"ERROR\",\n interval_ms: MIN_SCHEDULE_INTERVAL_MS,\n next_poll_at: null,\n last_error: message,\n consecutive_failures: (existing?.consecutive_failures ?? 0) + 1,\n });\n logger.error(\n `Invalid schedule for workflow ${binding.workflowId}: ${message}`,\n );\n }\n }\n\n private async disable(\n workflowId: string,\n binding?: TriggerBinding,\n ): Promise<void> {\n const store = await this.options.store();\n if (!store) throw new MissingJournalError(\"Disabling a trigger\");\n const row = await store.getTriggerState(workflowId);\n if (!row || row.status === \"DISABLED\") return;\n await this.disableRow(workflowId, row, binding);\n }\n\n // The piece_store rows are kept: an unchanged re-enable republishes onto the\n // cursor, and onDisable is the only thing that can release a registration.\n private async disableRow(\n workflowId: string,\n row: TriggerStateRow,\n binding?: TriggerBinding,\n ): Promise<void> {\n const store = await this.options.store();\n if (!store) return;\n const target = binding ?? this.bindingFromRow(row);\n if (target && !isSchedule(target) && row.block_type !== SCHEDULE_BLOCK) {\n try {\n await this.hook(target, \"onDisable\");\n } catch (error) {\n logger.warn(`onDisable failed for workflow ${workflowId}`, error);\n }\n }\n await store.setTriggerStatus(workflowId, \"DISABLED\");\n }\n\n private bindingFromRow(row: TriggerStateRow): TriggerBinding | undefined {\n return this.bindings.get(row.workflow_id);\n }\n\n async tick(): Promise<void> {\n if (this.ticking) return;\n this.ticking = true;\n try {\n await this.enqueue(() => this.pollDue());\n } finally {\n this.ticking = false;\n }\n }\n\n // An ERROR row is never due for a poll, so the enable retry rides the same\n // tick rather than a timer of its own.\n\n // One per tick, and after the due rows: an enable hook can burn the whole\n // hook timeout, and a queue of them must not push schedule fires late.\n private async retryOneEnable(): Promise<void> {\n const now = this.now().getTime();\n const next = [...this.enableRetries]\n .filter(([, retry]) => retry.at <= now)\n .sort((a, b) => a[1].at - b[1].at)\n .at(0);\n if (!next) return;\n const [workflowId, retry] = next;\n const binding = this.bindings.get(workflowId);\n if (!binding) {\n this.enableRetries.delete(workflowId);\n return;\n }\n // The entry is only dropped by an attempt that got as far as writing its\n // own outcome; anything else keeps it, backed off, rather than parking.\n try {\n await this.enable(binding);\n } catch (error) {\n const failures = retry.failures + 1;\n // The same cadence the attempt itself would have backed off on: a store\n // that just failed is the last thing to poll faster than configured.\n const intervalMs = isSchedule(binding)\n ? MIN_INTERVAL_MS\n : pollIntervalFor(binding, undefined, this.defaultIntervalMs);\n this.enableRetries.set(workflowId, {\n at: now + backoffMs(intervalMs, failures),\n failures,\n release: retry.release,\n });\n logger.error(`Enable retry for workflow ${workflowId} threw`, error);\n }\n }\n\n private async pollDue(): Promise<void> {\n const store = await this.options.store();\n // Once, not on every tick: the tick repeats forever and the condition\n // never changes without a restart.\n if (!store) {\n if (!this.warnedMissingJournal) {\n this.warnedMissingJournal = true;\n logger.error(\n \"Trigger polling is off: @error\",\n new MissingJournalError(\"Polling\"),\n );\n }\n return;\n }\n const due = await store.listDueTriggerStates(this.now().toISOString());\n for (const row of due) {\n const binding = this.bindings.get(row.workflow_id);\n if (!binding) {\n // Zombie row: the registry no longer knows this workflow.\n await store.setTriggerStatus(row.workflow_id, \"DISABLED\");\n continue;\n }\n if (isSchedule(binding)) {\n await this.fireSchedule(store, row, binding);\n } else {\n await this.poll(store, row, binding);\n }\n }\n await this.retryOneEnable();\n }\n\n // One fire per due row, however overdue; the next slot is computed from\n // now, so a restart never replays the slots it slept through.\n private async fireSchedule(\n store: WorkflowRunStore,\n row: TriggerStateRow,\n binding: ScheduleTriggerBinding,\n ): Promise<void> {\n const now = this.now();\n try {\n const schedule = parseScheduleConfig(binding.config);\n const scheduledFor = row.next_poll_at ? new Date(row.next_poll_at) : now;\n const nextAt = rescheduleAfterFire(schedule, scheduledFor, now);\n await store.recordPollSuccess(\n row.workflow_id,\n \"{}\",\n now.toISOString(),\n nextAt.toISOString(),\n );\n this.options.fire(\n binding.workflowId,\n schedulePayload(schedule, scheduledFor, now),\n SCHEDULE_TRIGGER_KIND,\n );\n } catch (error) {\n // Only a config that stopped parsing gets here; stop until it is edited.\n const message = error instanceof Error ? error.message : String(error);\n this.enabledOk.delete(binding.workflowId);\n await store.setTriggerStatus(row.workflow_id, \"ERROR\", message);\n logger.error(\n `Schedule fire failed for workflow ${row.workflow_id}: ${message}`,\n );\n }\n }\n\n private async poll(\n store: WorkflowRunStore,\n row: TriggerStateRow,\n binding: PieceTriggerBinding,\n ): Promise<void> {\n const now = this.now();\n const rewind = await this.cursorRewind(store, row.workflow_id);\n try {\n const result = await this.hook(binding, \"run\");\n if (!Array.isArray(result.output)) {\n throw new Error(\n `Trigger run returned ${typeof result.output}, expected an array`,\n );\n }\n await store.recordPollSuccess(\n row.workflow_id,\n VESTIGIAL_STORE_STATE,\n now.toISOString(),\n new Date(now.getTime() + row.interval_ms).toISOString(),\n );\n for (const item of result.output) {\n await this.fireItem(store, binding, item, now);\n }\n } catch (error) {\n await rewind();\n const message = error instanceof Error ? error.message : String(error);\n const failures = row.consecutive_failures + 1;\n const backoff = backoffMs(row.interval_ms, failures);\n await store.recordPollFailure(\n row.workflow_id,\n message,\n now.toISOString(),\n new Date(now.getTime() + backoff).toISOString(),\n failures,\n );\n logger.warn(\n `Poll failed for workflow ${row.workflow_id} (${failures}x): ${message}`,\n );\n }\n }\n\n // One workflow run per output item; _dedupe_key suppresses 30s repeats.\n private async fireItem(\n store: WorkflowRunStore,\n binding: PieceTriggerBinding,\n item: unknown,\n now: Date,\n ): Promise<void> {\n const dedupeKey = extractDedupeKey(item);\n if (dedupeKey) {\n const claimed = await store.claimDedupe(\n binding.workflowId,\n dedupeKey,\n DEDUPE_TTL_MS,\n now.toISOString(),\n );\n if (!claimed) return;\n }\n this.options.fire(binding.workflowId, item, `piece:${binding.blockType}`);\n }\n}\n","// Config parsing for core#webhook: the editor-facing shape of the trigger block.\n// Verification, redaction and payload mechanics belong to the reactor's service.\nimport type {\n WebhookField,\n WebhookHashAlgorithm,\n WebhookSignatureEncoding,\n} from \"@powerhousedao/shared/processors\";\n\nexport const WEBHOOK_BLOCK = \"core#webhook\";\n\nexport const WEBHOOK_TRIGGER_KIND = \"webhook\";\n\nexport const DEFAULT_TOLERANCE_SECONDS = 300;\nexport const DEFAULT_DEDUPE_TTL_SECONDS = 300;\nexport const DEFAULT_RESPONSE_STATUS = 202;\nexport const DEFAULT_SYNC_RESPONSE_STATUS = 200;\n\n// Signature layout named by wire format, not by sender; hash and encoding are\n// separate, so no name carries them. Mirrors the reactor's own WebhookScheme.\nexport type WebhookScheme =\n | \"none\"\n | \"token\"\n | \"hmac\"\n | \"hmac-prefixed\"\n | \"hmac-timestamped\";\n\nconst ALGORITHMS = new Set<WebhookHashAlgorithm>([\"sha1\", \"sha256\", \"sha512\"]);\nconst ENCODINGS = new Set<WebhookSignatureEncoding>([\"hex\", \"base64\"]);\n\n// A signed scheme with no secret is a configuration error, not a runtime one.\nconst SIGNED_SCHEMES = new Set<WebhookScheme>([\n \"token\",\n \"hmac\",\n \"hmac-prefixed\",\n \"hmac-timestamped\",\n]);\n\nconst SCHEMES = new Set<WebhookScheme>([\n \"none\",\n \"token\",\n \"hmac\",\n \"hmac-prefixed\",\n \"hmac-timestamped\",\n]);\n\n// The header each format is most often carried in; the author can override it.\nconst DEFAULT_HEADER: Record<WebhookScheme, string> = {\n none: \"\",\n token: \"x-webhook-token\",\n hmac: \"x-signature\",\n \"hmac-prefixed\": \"x-hub-signature-256\",\n \"hmac-timestamped\": \"stripe-signature\",\n};\n\nexport const HTTP_METHODS = [\n \"GET\",\n \"POST\",\n \"PUT\",\n \"PATCH\",\n \"DELETE\",\n \"HEAD\",\n] as const;\n\nexport interface WebhookConfig {\n // Uppercase; undefined accepts every method.\n methods?: string[];\n scheme: WebhookScheme;\n // Lowercase header the signature/token is read from; \"\" when scheme is none.\n header: string;\n // secret://v1: ref resolved through the secret store at delivery time.\n secretRef?: string;\n // Replay window for the timestamped scheme.\n toleranceSeconds: number;\n // Digest options a sender picks independently of the layout; undefined leaves\n // the reactor's defaults (sha256, hex, algorithm-derived label) in place.\n algorithm?: WebhookHashAlgorithm;\n encoding?: WebhookSignatureEncoding;\n // \"\" is a real value: a prefixed layout carrying no label at all. Only\n // undefined means \"the algorithm's own label\".\n prefix?: string;\n // async answers before the run; sync waits for it and reports the outcome.\n responseMode: \"async\" | \"sync\";\n responseStatus: number;\n // A field echoed back verbatim instead of starting a run; Activepieces\n // spends onHandshake on the same provider round.\n challengeField?: WebhookField;\n // Where the provider's own event id is. Present, it is the authoritative\n // dedup key for redeliveries (plan/08 §7.2).\n dedupeField?: WebhookField;\n dedupeTtlSeconds: number;\n}\n\nfunction asRecord(config: unknown): Record<string, unknown> {\n if (config && typeof config === \"object\" && !Array.isArray(config)) {\n return config as Record<string, unknown>;\n }\n if (typeof config === \"string\") {\n try {\n return asRecord(JSON.parse(config));\n } catch {\n return {};\n }\n }\n return {};\n}\n\nfunction toNumber(value: unknown): number | undefined {\n if (typeof value === \"number\") return value;\n if (typeof value === \"string\" && value.trim() !== \"\") {\n const parsed = Number(value);\n return Number.isNaN(parsed) ? undefined : parsed;\n }\n return undefined;\n}\n\nfunction nonEmptyString(value: unknown): string | undefined {\n return typeof value === \"string\" && value.trim() !== \"\"\n ? value.trim()\n : undefined;\n}\n\n// Where a provider put a value: a bare name is a query param or top-level body field.\n// `header:`/`body:` prefixes exist because senders disagree; object form is accepted too.\nfunction parseWebhookField(value: unknown): WebhookField | undefined {\n if (value && typeof value === \"object\" && !Array.isArray(value)) {\n const record = value as Record<string, unknown>;\n const header = nonEmptyString(record.header);\n if (header) return { header: header.toLowerCase() };\n const body = nonEmptyString(record.body);\n if (body) return { body };\n throw new Error(\n `${WEBHOOK_BLOCK}: a field source must name either \"header\" or \"body\"`,\n );\n }\n const text = nonEmptyString(value);\n if (!text) return undefined;\n // Only these two prefixes are a source. Any other colon is part of the name,\n // so a provider that uses one in a field name still resolves.\n const match = /^(header|body)\\s*:\\s*(\\S.*)$/i.exec(text);\n if (!match) return text;\n const source = match[1].toLowerCase();\n const name = match[2].trim();\n return source === \"header\" ? { header: name.toLowerCase() } : { body: name };\n}\n\n// A named choice, rejected loudly: an unknown hash would otherwise reach the\n// reactor and fail every delivery with nothing pointing at the config.\nfunction parseEnum<T extends string>(\n value: unknown,\n allowed: Set<T>,\n field: string,\n): T | undefined {\n const text = nonEmptyString(value)?.toLowerCase();\n if (!text) return undefined;\n if (!allowed.has(text as T)) {\n throw new Error(\n `${WEBHOOK_BLOCK}: \"${field}\" must be one of ${[...allowed].join(\", \")}`,\n );\n }\n return text as T;\n}\n\n// \"ANY\" and \"\" both mean every method, which is how the editor spells it.\nfunction parseMethods(value: unknown): string[] | undefined {\n const list =\n typeof value === \"string\"\n ? value === \"\" || value.toUpperCase() === \"ANY\"\n ? []\n : [value]\n : Array.isArray(value)\n ? value.filter((item): item is string => typeof item === \"string\")\n : [];\n if (list.length === 0) return undefined;\n const methods = list.map((method) => method.trim().toUpperCase());\n for (const method of methods) {\n if (!(HTTP_METHODS as readonly string[]).includes(method)) {\n throw new Error(\n `${WEBHOOK_BLOCK}: \"${method}\" is not one of ${HTTP_METHODS.join(\", \")}`,\n );\n }\n }\n return methods;\n}\n\n// Config: { methods?, scheme?, header?, secretRef?, toleranceSeconds?,\n// responseMode?, responseStatus?, challengeField? }.\nexport function parseWebhookConfig(config: unknown): WebhookConfig {\n const record = asRecord(config);\n const rawScheme = nonEmptyString(record.scheme) ?? \"none\";\n if (!SCHEMES.has(rawScheme as WebhookScheme)) {\n throw new Error(\n `${WEBHOOK_BLOCK}: \"scheme\" must be one of ${[...SCHEMES].join(\", \")}`,\n );\n }\n const scheme = rawScheme as WebhookScheme;\n const secretRef = nonEmptyString(record.secretRef);\n if (SIGNED_SCHEMES.has(scheme) && !secretRef) {\n throw new Error(\n `${WEBHOOK_BLOCK}: the \"${scheme}\" scheme needs a \"secretRef\"`,\n );\n }\n const responseMode =\n record.responseMode === \"sync\" ? (\"sync\" as const) : (\"async\" as const);\n const status =\n toNumber(record.responseStatus) ??\n (responseMode === \"sync\"\n ? DEFAULT_SYNC_RESPONSE_STATUS\n : DEFAULT_RESPONSE_STATUS);\n if (!Number.isInteger(status) || status < 200 || status > 599) {\n throw new Error(\n `${WEBHOOK_BLOCK}: \"responseStatus\" must be an integer between 200 and 599`,\n );\n }\n const tolerance =\n toNumber(record.toleranceSeconds) ?? DEFAULT_TOLERANCE_SECONDS;\n if (!Number.isFinite(tolerance) || tolerance <= 0) {\n throw new Error(\n `${WEBHOOK_BLOCK}: \"toleranceSeconds\" must be a positive number`,\n );\n }\n const dedupeTtl =\n toNumber(record.dedupeTtlSeconds) ?? DEFAULT_DEDUPE_TTL_SECONDS;\n if (!Number.isFinite(dedupeTtl) || dedupeTtl <= 0) {\n throw new Error(\n `${WEBHOOK_BLOCK}: \"dedupeTtlSeconds\" must be a positive number`,\n );\n }\n return {\n methods: parseMethods(record.methods),\n scheme,\n header: (\n nonEmptyString(record.header) ?? DEFAULT_HEADER[scheme]\n ).toLowerCase(),\n secretRef,\n toleranceSeconds: tolerance,\n responseMode,\n responseStatus: status,\n algorithm: parseEnum(record.algorithm, ALGORITHMS, \"algorithm\"),\n encoding: parseEnum(record.encoding, ENCODINGS, \"encoding\"),\n prefix: typeof record.prefix === \"string\" ? record.prefix : undefined,\n challengeField: parseWebhookField(record.challengeField),\n dedupeField: parseWebhookField(record.dedupeField),\n dedupeTtlSeconds: dedupeTtl,\n };\n}\n\n/** The trigger payload, shaped like Activepieces' catch-webhook contract so\n * authored expressions and adapted pieces agree on where a request's parts are. */\nexport interface WebhookPayload {\n method: string;\n path: string;\n headers: Record<string, string>;\n queryParams: Record<string, string>;\n body: unknown;\n}\n","// The probe a sender sends before it will register a webhook endpoint.\n\n// A trigger declares which shape its sender uses; the piece's own onHandshake\n// decides the answer. Only \"is this a probe\" is decided here.\nimport type {\n WebhookReply,\n WebhookRequest,\n} from \"@powerhousedao/shared/processors\";\nimport { WebhookHandshakeStrategy } from \"@powerhousedao/pieces-framework\";\n\n// The framework's strategies as the strings they carry: a bundle inlines its\n// own copy of the enum, so the value is what crosses, never the member.\nconst strategies: Record<`${WebhookHandshakeStrategy}`, string> =\n WebhookHandshakeStrategy;\n\nexport interface PieceHandshake {\n strategy: string;\n paramName?: string;\n}\n\n// The framework's four live strategies. HEAD_REQUEST names a method rather\n// than a field, so it is the one that does not read `paramName`.\nexport function handshakeMatches(\n handshake: PieceHandshake,\n request: WebhookRequest,\n): boolean {\n if (handshake.strategy === strategies.HEAD_REQUEST) {\n return request.method.toUpperCase() === \"HEAD\";\n }\n const name = handshake.paramName;\n\n // A strategy naming no field can never match: treating it as \"always\" would\n // answer every delivery as a probe and the workflow would never run.\n if (!name) return false;\n switch (handshake.strategy) {\n // Presence, not truthiness: a sender may probe with an empty value, and\n // the indexed types claim a string is always there.\n case strategies.HEADER_PRESENT:\n return Object.hasOwn(request.headers, name.toLowerCase());\n case strategies.QUERY_PRESENT:\n return Object.hasOwn(request.queryParams, name);\n case strategies.BODY_PARAM_PRESENT:\n return (\n typeof request.body === \"object\" &&\n request.body !== null &&\n !Array.isArray(request.body) &&\n name in (request.body as Record<string, unknown>)\n );\n default:\n return false;\n }\n}\n\n// The framework's own default onHandshake is a bare 200, so a hook returning\n// nothing is answered that way rather than treated as a refusal.\nexport function handshakeReply(output: unknown): WebhookReply {\n if (typeof output !== \"object\" || output === null) return { status: 200 };\n const record = output as Record<string, unknown>;\n const status = typeof record.status === \"number\" ? record.status : 200;\n const body = record.body;\n if (body === undefined || body === null) return { status };\n if (typeof body === \"string\") return { status, body };\n return {\n status,\n body: JSON.stringify(body),\n contentType: \"application/json\",\n };\n}\n","// Pure config parsing/matching for the document trigger kinds. Each config\n// field is a string or list; an omitted field matches every value.\n\n// Declared by the reactor piece, fired by this host: the processor sees every\n// operation, so matching one against a filter never leaves the process.\nimport {\n DOCUMENT_CREATED_BLOCK,\n DOCUMENT_DELETED_BLOCK,\n DOCUMENT_EVENT_BLOCK,\n} from \"./reactor-piece.js\";\n\nexport { DOCUMENT_CREATED_BLOCK, DOCUMENT_DELETED_BLOCK, DOCUMENT_EVENT_BLOCK };\n\nexport type TriggerKind =\n | \"document-event\"\n | \"document-created\"\n | \"document-deleted\";\n\nexport const TRIGGER_KIND_BY_BLOCK: Record<string, TriggerKind> = {\n [DOCUMENT_EVENT_BLOCK]: \"document-event\",\n [DOCUMENT_CREATED_BLOCK]: \"document-created\",\n [DOCUMENT_DELETED_BLOCK]: \"document-deleted\",\n};\n\nexport interface DocumentEventFilter {\n documentType?: string[];\n documentId?: string[];\n actionType?: string[];\n}\n\n// Lifecycle triggers match the document-scope CREATE_DOCUMENT /\n// DELETE_DOCUMENT operations, and fall back to the drive's ADD_FILE /\n// DELETE_NODE when no document-scope operation reaches the processor.\nexport interface LifecycleFilter {\n documentType?: string[];\n // A document that lives outside every drive has no drive id, so a set\n // driveId narrows the trigger to drive members.\n driveId?: string[];\n}\n\n// A created/deleted document is announced by a document-scope operation on\n// the document itself: CREATE_DOCUMENT carries the type and name, and\n// DELETE_DOCUMENT is the only signal that a document is really gone.\nexport function lifecycleKindForDocumentAction(\n actionType: string,\n): TriggerKind | undefined {\n if (actionType === \"CREATE_DOCUMENT\") return \"document-created\";\n if (actionType === \"DELETE_DOCUMENT\") return \"document-deleted\";\n return undefined;\n}\n\n// The drive's own view of the same events. ADD_FILE always accompanies a\n// CREATE_DOCUMENT, so this is a fallback; DELETE_NODE is on its own only\n// unlinking the document from the drive, which the trigger still reports.\nexport function lifecycleKindForDriveAction(\n actionType: string,\n): TriggerKind | undefined {\n if (actionType === \"ADD_FILE\") return \"document-created\";\n if (actionType === \"DELETE_NODE\") return \"document-deleted\";\n return undefined;\n}\n\nfunction toList(value: unknown): string[] | undefined {\n if (typeof value === \"string\") return value ? [value] : undefined;\n if (Array.isArray(value)) {\n const strings = value.filter((item) => typeof item === \"string\");\n return strings.length > 0 ? strings : undefined;\n }\n return undefined;\n}\n\nfunction asRecord(config: unknown): Record<string, unknown> {\n if (config === null || typeof config !== \"object\") return {};\n return config as Record<string, unknown>;\n}\n\nexport function parseEventFilter(config: unknown): DocumentEventFilter {\n const record = asRecord(config);\n return {\n documentType: toList(record.documentType),\n documentId: toList(record.documentId),\n actionType: toList(record.actionType),\n };\n}\n\nexport function parseLifecycleFilter(config: unknown): LifecycleFilter {\n const record = asRecord(config);\n return {\n documentType: toList(record.documentType),\n driveId: toList(record.driveId),\n };\n}\n\nconst ok = (list: string[] | undefined, value: string | undefined) =>\n !list || (value !== undefined && list.includes(value));\n\nexport function matchesEventFilter(\n filter: DocumentEventFilter,\n documentType: string,\n documentId: string,\n actionType: string,\n): boolean {\n return (\n ok(filter.documentType, documentType) &&\n ok(filter.documentId, documentId) &&\n ok(filter.actionType, actionType)\n );\n}\n\n// documentType is undefined when it can't be resolved (e.g. a drive node\n// deletion for a document that is already gone); a set type filter then\n// rejects rather than firing on an unconfirmed match. driveId is null for a\n// document that belongs to no drive, which a set driveId also rejects.\nexport function matchesLifecycleFilter(\n filter: LifecycleFilter,\n documentType: string | undefined | null,\n driveId: string | undefined | null,\n): boolean {\n return (\n ok(filter.documentType, documentType ?? undefined) &&\n ok(filter.driveId, driveId ?? undefined)\n );\n}\n","// The workflow runtime: one instance per host, serving the GraphQL subgraph\n// (config + manual fire) and the workflow-triggers read model alike.\nimport type {\n IWebhookEndpoints,\n IWebhookScope,\n WebhookPolicy,\n WebhookReply,\n WebhookRequest,\n} from \"@powerhousedao/shared/processors\";\nimport type { WorkflowCaller, WorkflowRuntimeHostDeps } from \"./host.js\";\n\nimport {\n containsRedactedMarker,\n declaredConnectionIds,\n DEFAULT_EGRESS_POLICY,\n parseBlockType,\n pieceModuleRef,\n reactorHandlers,\n PieceWorker,\n PieceWorkerError,\n PieceWorkerPool,\n PieceWorkerTimeoutError,\n rememberSecrets,\n runWorkflow,\n type BlockExecutor,\n type LocalPiece,\n type PieceModuleRef,\n type CheckConnectionOutcome,\n type PieceDescriptor,\n type EgressPolicy,\n type PieceWorkerSession,\n type SecretProvider,\n type SecretStore,\n type WorkflowRunResult,\n} from \"../pieces/index.js\";\nimport {\n childLogger,\n type ILogger,\n type OperationWithContext,\n} from \"document-model\";\nimport {\n actions as connectionActions,\n type ConnectionDocument,\n} from \"@powerhousedao/workflow/document-models/connection\";\nimport type {\n WorkflowDocument,\n WorkflowState,\n} from \"@powerhousedao/workflow/document-models/workflow\";\nimport {\n DOCUMENT_CREATE_BLOCK,\n DOCUMENT_CREATED_BLOCK,\n DOCUMENT_DELETED_BLOCK,\n DOCUMENT_DISPATCH_BLOCK,\n DOCUMENT_EVENT_BLOCK,\n DOCUMENT_FIND_BLOCK,\n DOCUMENT_GET_BLOCK,\n DOCUMENT_SCHEMA_BLOCK,\n DOCUMENT_TYPES_BLOCK,\n staticString,\n} from \"./reactor-piece.js\";\nimport {\n documentBlockTree,\n documentEventTree,\n documentFindTree,\n documentGetTree,\n documentSchemaTree,\n documentTypesTree,\n fieldsFromSdl,\n fromOutputSchema,\n hasOutputSchemaFields,\n fromSample,\n lifecycleTriggerTree,\n scheduleTriggerTree,\n webhookTriggerTree,\n type OutputTree,\n} from \"./output-tree.js\";\nimport {\n fetchPieceActions,\n fetchPieceCatalog,\n fetchPieceDetail,\n fetchPieceTriggers,\n type PieceActionsResult,\n type PieceSummary,\n type PieceTriggersResult,\n} from \"./piece-catalog.js\";\nimport {\n actionsResult,\n catalogEntry,\n detailResult,\n localSearchHits,\n triggersResult,\n} from \"./local-catalog.js\";\nimport {\n indexFromHits,\n searchBlocks,\n type BlockSearchIndex,\n type BlockSearchResult,\n} from \"./block-search.js\";\nimport { packagePieces } from \"./piece-registry.js\";\nimport { ScopedDesignTimeReactorPort } from \"./reactor-port.js\";\nimport {\n BUNDLE_CACHE_DIR,\n configuredEgress,\n createBlockExecutor,\n DocumentConnectionResolver,\n pieceResolver,\n resolveConnectionAuth,\n toWorkflowDefinition,\n} from \"./lib.js\";\nimport { packageFromConnectorId } from \"./connector-id.js\";\nimport { SCHEDULE_BLOCK } from \"./schedule.js\";\nimport type { AttachmentPort } from \"../pieces/index.js\";\nimport { createAttachmentPort } from \"./attachment-port.js\";\nimport { createPieceStorePort } from \"./piece-store-port.js\";\nimport { currentWorkflowId, withRunScope } from \"./run-scope.js\";\nimport { LocalEncryptedSecretStore } from \"./secret-store.js\";\nimport {\n WorkflowRunStore,\n type RunRow,\n type StepExecutionRow,\n type TriggerStateRow,\n} from \"./store.js\";\nimport {\n TriggerSupervisor,\n type PieceTriggerBinding,\n type TriggerBinding,\n} from \"./trigger-supervisor.js\";\nimport {\n parseWebhookConfig,\n WEBHOOK_BLOCK,\n WEBHOOK_TRIGGER_KIND,\n type WebhookConfig,\n type WebhookPayload,\n} from \"./webhook.js\";\nimport {\n handshakeMatches,\n handshakeReply,\n type PieceHandshake,\n} from \"./piece-handshake.js\";\nimport {\n lifecycleKindForDocumentAction,\n lifecycleKindForDriveAction,\n matchesEventFilter,\n matchesLifecycleFilter,\n parseEventFilter,\n parseLifecycleFilter,\n TRIGGER_KIND_BY_BLOCK,\n type DocumentEventFilter,\n type LifecycleFilter,\n type TriggerKind,\n} from \"./trigger-filters.js\";\n\nexport type PersistedRunResult = WorkflowRunResult & { runId: string | null };\n\nexport interface ConnectionSummary {\n id: string;\n name: string;\n connectorId: string;\n authType: string;\n status: string;\n accountLabel: string | null;\n}\n\nexport interface ConnectionCheckResult {\n ok: boolean;\n detail: string | null;\n accountLabel: string | null;\n}\n\n/** A journal row with the steps that belong to it, as the subgraph serves it. */\nexport interface RunRecord {\n row: RunRow;\n steps: StepExecutionRow[];\n}\n\nexport interface WebhookEndpointRecord {\n workflowId: string;\n url: string;\n absoluteUrl: boolean;\n armed: boolean;\n createdAt: string;\n}\n\n// Matches the piece worker's default action timeout; a hung check kills the\n// worker instead of hanging the mutation.\nconst CHECK_TIMEOUT_MS = 30_000;\n// Same convention for the design-time descriptor build; a bundle that hangs\n// on import kills the worker instead of the request.\nconst DESCRIBE_TIMEOUT_MS = 30_000;\n\n// Bounded because the registry is seeded once, from the constructor: a sweep\n// that fails past this is reported rather than retried forever.\nconst SEED_ATTEMPTS = 3;\nconst SEED_RETRY_BASE_MS = 250;\n\nconst sleep = (ms: number) =>\n new Promise<void>((resolve) => setTimeout(resolve, ms).unref());\n\nconst logger = childLogger([\"workflow\", \"runtime\"]);\n\nconst DRIVE_DOCUMENT_TYPE = \"powerhouse/document-drive\";\nconst WORKFLOW_DOCUMENT_TYPE = \"powerhouse/workflow\";\n// Document creation, deletion and parent linking are appended to the document\n// itself in this scope, not to any drive.\nconst DOCUMENT_SCOPE = \"document\";\n// The relationship type the reactor uses for containment: a drive (or any\n// parent document) -> child document edge.\nconst CHILD_RELATIONSHIP = \"child\";\n\n// What identifies an operation to both dedupe lines below. The ordinal is the\n// reactor's own sequence; a batch without one falls back to the document's.\nfunction operationKey(op: OperationWithContext): string {\n return op.context.ordinal > 0\n ? `o:${op.context.ordinal}`\n : `${op.context.documentId}:${op.context.scope}:${op.context.branch}:${op.operation.index}`;\n}\n\n// A day, because the redelivery this guards is a restart replaying from a\n// cursor that trailed the runs it had already journaled.\nconst OPERATION_DEDUPE_TTL_MS = 24 * 60 * 60_000;\n\nfunction stringField(\n record: Record<string, unknown>,\n key: string,\n): string | undefined {\n const value = record[key];\n return typeof value === \"string\" && value !== \"\" ? value : undefined;\n}\n\nfunction inputRecord(input: unknown): Record<string, unknown> {\n if (input === null || typeof input !== \"object\") return {};\n return input as Record<string, unknown>;\n}\n\n// Where a lifecycle payload's driveId / parentId come from: CREATE_DOCUMENT knows\n// nothing about containment, so the parent is read off siblings in the same job.\nexport interface LifecycleParentHint {\n // Set only by a drive operation, which is the only place the drive is named\n // outright.\n driveId?: string;\n // A drive node's parentFolder, or the parent document of a \"child\" edge.\n parentId?: string;\n // The document id a relationship names as its parent, whose type decides\n // whether it is a drive.\n parentCandidate?: string;\n}\n\n// Indexes operations by the document a lifecycle event is about. addFile writes CREATE_DOCUMENT\n// and ADD_RELATIONSHIP in one job (drive known without a read); the drive's ADD_FILE lands later.\nexport function collectLifecycleParentHints(\n operations: OperationWithContext[],\n): Map<string, LifecycleParentHint> {\n const hints = new Map<string, LifecycleParentHint>();\n const merge = (documentId: string, hint: LifecycleParentHint) => {\n const existing = hints.get(documentId);\n hints.set(documentId, existing ? { ...existing, ...hint } : hint);\n };\n for (const { operation, context } of operations) {\n const actionType = operation.action.type;\n const input = inputRecord(operation.action.input);\n if (context.scope === DOCUMENT_SCOPE) {\n if (\n actionType !== \"ADD_RELATIONSHIP\" &&\n actionType !== \"REMOVE_RELATIONSHIP\"\n ) {\n continue;\n }\n if (stringField(input, \"relationshipType\") !== CHILD_RELATIONSHIP) {\n continue;\n }\n const target = stringField(input, \"targetId\");\n const source = stringField(input, \"sourceId\");\n if (!target || !source) continue;\n merge(target, { parentId: source, parentCandidate: source });\n continue;\n }\n if (context.documentType !== DRIVE_DOCUMENT_TYPE) continue;\n if (actionType !== \"ADD_FILE\" && actionType !== \"DELETE_NODE\") continue;\n const nodeId = stringField(input, \"id\");\n if (!nodeId) continue;\n // parentFolder is absent at a drive's root, where the document has no\n // folder parent; the drive itself is reported as driveId, not as parentId.\n merge(nodeId, {\n driveId: context.documentId,\n parentId: stringField(input, \"parentFolder\"),\n });\n }\n return hints;\n}\n\n// A piece's checkConnection returns void | boolean |\n// { name | username | email | sub }; anything string-valued labels the account.\nfunction accountLabelFromCheckResult(result: unknown): string | undefined {\n if (!result || typeof result !== \"object\") return undefined;\n const record = result as Record<string, unknown>;\n for (const key of [\"name\", \"username\", \"email\", \"sub\"]) {\n const value = record[key];\n if (typeof value === \"string\" && value !== \"\") return value;\n }\n return undefined;\n}\n\n// User-visible detail of a failed worker request; a piece error contributes only\n// its message, as its serialized properties may hold echoed credentials.\nfunction pieceFailureDetail(error: unknown, timeoutDetail: string): string {\n if (error instanceof PieceWorkerTimeoutError) return timeoutDetail;\n if (error instanceof PieceWorkerError) return error.serialized.message;\n return error instanceof Error ? error.message : String(error);\n}\n\nfunction checkFailureDetail(error: unknown): string {\n return pieceFailureDetail(\n error,\n `Connection check timed out after ${Math.round(CHECK_TIMEOUT_MS / 1000)}s`,\n );\n}\n\ntype TriggerRegistration = {\n workflowId: string;\n} & (\n | { kind: \"document-event\"; filter: DocumentEventFilter }\n | { kind: \"document-created\" | \"document-deleted\"; filter: LifecycleFilter }\n // Request-driven; the reactor mints and owns the endpoint's token.\n | { kind: \"webhook\"; config: WebhookConfig }\n // A piece whose strategy is WEBHOOK: the supervisor still owns its\n // enable/disable state, but requests drive it instead of the tick.\n | { kind: \"piece-webhook\"; binding: PieceTriggerBinding }\n // Timer-driven kinds live in the TriggerSupervisor.\n | { kind: \"piece\" | \"schedule\" }\n);\n\nexport const PIECE_WEBHOOK_KIND = \"piece-webhook\";\n\n// Kinds whose enable/disable lifecycle the supervisor owns, so leaving one\n// has to release its registration.\nconst SUPERVISED_KINDS = new Set([\"piece\", \"schedule\", PIECE_WEBHOOK_KIND]);\n\n// Shared so no refusal path can accidentally answer with a distinguishing body.\nconst UNAUTHORIZED: WebhookReply = { status: 401 };\n\nconst JSON_CONTENT_TYPE = \"application/json; charset=utf-8\";\n\n// How long a sync-mode delivery holds the provider's socket; beyond this the run\n// keeps going and the provider is told so, lest a wedged step tie up connections.\nconst DELIVERY_TIMEOUT_MS =\n Number(process.env.WORKFLOW_WEBHOOK_TIMEOUT_MS) || 30_000;\n\nconst TIMED_OUT = Symbol(\"webhook delivery timed out\");\n\n/** Resolves to TIMED_OUT, and never keeps the process alive waiting to. */\nfunction timeout(ms: number): Promise<typeof TIMED_OUT> {\n return new Promise((resolve) => {\n setTimeout(() => resolve(TIMED_OUT), ms).unref();\n });\n}\n\n/** Shaped like Activepieces' catch-webhook contract so authored expressions and adapted\n * pieces agree where a request's parts are; headers arrive redacted, body decoded. */\nfunction webhookPayload(request: WebhookRequest): WebhookPayload {\n return {\n method: request.method,\n path: request.path,\n headers: request.headers,\n queryParams: request.queryParams,\n body: request.body,\n };\n}\n\nexport const POLL_INTERVAL_CONFIG_KEY = \"pollEverySeconds\";\n\n// pollEverySeconds is ours, not the piece's: lifted out of the trigger config so it\n// never reaches the piece as a prop, yet a change to it alone still rewrites the hash.\nexport function splitPollInterval(config: Record<string, unknown>): {\n config: Record<string, unknown>;\n pollIntervalMs?: number;\n} {\n if (!(POLL_INTERVAL_CONFIG_KEY in config)) return { config };\n const { [POLL_INTERVAL_CONFIG_KEY]: raw, ...rest } = config;\n const seconds = typeof raw === \"string\" ? Number(raw) : raw;\n if (\n typeof seconds !== \"number\" ||\n !Number.isFinite(seconds) ||\n seconds <= 0\n ) {\n logger.warn(\n `Ignoring ${POLL_INTERVAL_CONFIG_KEY}=${JSON.stringify(raw)}: expected a positive number of seconds`,\n );\n return { config: rest };\n }\n return { config: rest, pollIntervalMs: Math.round(seconds * 1000) };\n}\n\nfunction parseWorkflowState(\n resultingState?: string,\n): WorkflowState | undefined {\n if (!resultingState) return undefined;\n try {\n return JSON.parse(resultingState) as WorkflowState;\n } catch {\n return undefined;\n }\n}\n\nfunction configRecord(config: unknown): Record<string, unknown> {\n if (config && typeof config === \"object\" && !Array.isArray(config)) {\n return config as Record<string, unknown>;\n }\n if (typeof config === \"string\") {\n try {\n const parsed = JSON.parse(config) as unknown;\n if (parsed && typeof parsed === \"object\" && !Array.isArray(parsed)) {\n return parsed as Record<string, unknown>;\n }\n } catch {\n // fall through\n }\n }\n return {};\n}\n\nexport class WorkflowRuntimeService {\n private readonly host: WorkflowRuntimeHostDeps;\n private readonly logger: ILogger;\n // The only host surface that carries an attachment client; without one\n // ctx.files stays an inline data URI instead of an attachment reference.\n private readonly attachments?: AttachmentPort;\n private executor?: BlockExecutor;\n private pieceWorkers?: PieceWorkerPool;\n private readonly storePromise: Promise<WorkflowRunStore>;\n private secretsPromise?: Promise<SecretStore>;\n private readonly registry = new Map<string, TriggerRegistration>();\n // Awaited before an endpoint answers: a delivery reaching an unseeded\n // registry is refused exactly as an unknown token is, so it looks like one.\n private readonly seedPromise: Promise<void>;\n // What the last seeding attempt failed with, once the retries are spent.\n private seedError?: unknown;\n\n // Seeds the trigger registry and opens the run journal. The host owns this\n // instance's lifetime, so a replaced host means a replaced runtime.\n constructor(host: WorkflowRuntimeHostDeps) {\n this.host = host;\n this.logger = host.logger ?? logger;\n this.attachments = host.attachments\n ? createAttachmentPort(\n host.attachments,\n () => currentWorkflowId(),\n // A host that serves attachments without answering for them reads\n // nothing: an unanswerable relationship is not a permitted one.\n (documentId, ref) =>\n host.canReadAttachmentRef?.(documentId, ref) ??\n Promise.resolve(false),\n )\n : undefined;\n this.storePromise = WorkflowRunStore.create(host.relationalDb);\n this.storePromise.catch((error: unknown) => {\n this.logger.error(\"Failed to open the workflow run store: @error\", error);\n });\n this.seedPromise = this.seedWithRetries();\n }\n\n // The journal is best-effort: a broken store never blocks runs.\n async store(): Promise<WorkflowRunStore | undefined> {\n try {\n return await this.storePromise;\n } catch {\n return undefined;\n }\n }\n\n // Unlike the journal, a broken secret store must fail resolution loudly.\n secrets(): Promise<SecretStore> {\n this.secretsPromise ??=\n this.host.secrets !== undefined\n ? Promise.resolve(this.host.secrets)\n : LocalEncryptedSecretStore.create(this.host.relationalDb);\n return this.secretsPromise;\n }\n\n private secretProvider(): SecretProvider {\n return { get: (ref) => this.secrets().then((store) => store.get(ref)) };\n }\n\n /** The seeding failure a restart is needed to clear, or undefined while the\n * registry is seeded. Resolves once seeding has finished either way. */\n async seedFailure(): Promise<unknown> {\n await this.seedPromise;\n return this.seedError;\n }\n\n // A seed that never lands leaves every poll and webhook trigger inert until\n // the process restarts, so a transient failure is retried before it stands.\n private async seedWithRetries(): Promise<void> {\n for (let attempt = 1; attempt <= SEED_ATTEMPTS; attempt += 1) {\n try {\n await this.seedRegistry();\n this.seedError = undefined;\n return;\n } catch (error) {\n this.seedError = error;\n if (attempt === SEED_ATTEMPTS) break;\n this.logger.warn(\n `Seeding the trigger registry failed (attempt ${attempt}/${SEED_ATTEMPTS}), retrying: @error`,\n error,\n );\n await sleep(SEED_RETRY_BASE_MS * 2 ** (attempt - 1));\n }\n }\n // Resolved rather than rejected: a delivery racing a dead registry is\n // still answered as an unknown token, not as a broken endpoint.\n this.logger.error(\n `Failed to seed the trigger registry after ${SEED_ATTEMPTS} attempts; its workflows stay inactive until the reactor restarts: @error`,\n this.seedError,\n );\n }\n\n private async seedRegistry(): Promise<void> {\n const page = await this.host.reactorClient.find({\n type: \"powerhouse/workflow\",\n });\n for (const document of page.results as WorkflowDocument[]) {\n await this.updateRegistration(document.header.id, document.state.global);\n }\n\n // Seeding nothing while endpoints exist is always a fault, and every\n // webhook for this package is dead until the next seed succeeds.\n if (this.registry.size === 0 && (await this.hasWebhookEndpoints())) {\n this.logger.warn(\n \"Trigger registry seeded no workflows, but @count webhook endpoint(s) exist: their deliveries will be refused as unknown tokens\",\n await this.endpointCount(),\n );\n return;\n }\n this.logger.info(\n `Trigger registry seeded: ${this.registry.size} workflow(s)`,\n );\n }\n\n private async endpointCount(): Promise<number> {\n const endpoints = await this.endpoints();\n return endpoints ? (await endpoints.list()).length : 0;\n }\n\n private async hasWebhookEndpoints(): Promise<boolean> {\n return (await this.endpointCount()) > 0;\n }\n\n // Awaited by callers: the registry must be current before the next request\n // can arrive. Only arming, which does I/O, is left to run on its own.\n private async updateRegistration(\n workflowId: string,\n state: WorkflowState,\n ): Promise<void> {\n // An unversioned block type is pinned by what this reactor installed, so\n // the registry answers before any of it is parsed.\n await packagePieces.ready();\n const trigger = state.status === \"ENABLED\" ? state.trigger : undefined;\n if (trigger?.blockType === WEBHOOK_BLOCK) {\n await this.registerWebhook(workflowId, trigger.config);\n return;\n }\n const kind: TriggerKind | undefined = trigger\n ? TRIGGER_KIND_BY_BLOCK[trigger.blockType]\n : undefined;\n const supervised =\n trigger && !kind\n ? this.supervisedBinding(workflowId, trigger)\n : undefined;\n\n if (!kind && !supervised) {\n const had = this.registry.get(workflowId);\n this.registry.delete(workflowId);\n if (had && SUPERVISED_KINDS.has(had.kind))\n this.dropSupervised(workflowId);\n return;\n }\n if (supervised) {\n if (supervised.kind === \"schedule\") {\n this.registry.set(workflowId, { workflowId, kind: \"schedule\" });\n this.enableSupervised(workflowId, supervised);\n return;\n }\n // Registered as a poll binding first, then corrected once the piece's\n // strategy is known: a WEBHOOK trigger must never be handed to the tick.\n this.registry.set(workflowId, { workflowId, kind: \"piece\" });\n await this.registerPieceTrigger(workflowId, supervised);\n return;\n }\n const had = this.registry.get(workflowId);\n if (had && SUPERVISED_KINDS.has(had.kind)) this.dropSupervised(workflowId);\n const config = trigger?.config;\n this.registry.set(\n workflowId,\n kind === \"document-event\"\n ? { workflowId, kind, filter: parseEventFilter(config) }\n : { workflowId, kind: kind!, filter: parseLifecycleFilter(config) },\n );\n }\n\n private enableSupervised(workflowId: string, binding: TriggerBinding): void {\n this.supervisor()\n .upsert(binding)\n .catch((error: unknown) => {\n this.logger.error(`Trigger enable failed for ${workflowId}`, error);\n });\n }\n\n // A WEBHOOK-strategy piece needs its endpoint minted before onEnable runs:\n // the piece registers that URL with the provider from inside the hook.\n private async registerPieceTrigger(\n workflowId: string,\n binding: PieceTriggerBinding,\n ): Promise<void> {\n const delivery = await this.pieceDelivery(binding);\n const resolved = { ...binding, delivery };\n if (delivery === \"webhook\") {\n this.registry.set(workflowId, {\n workflowId,\n kind: PIECE_WEBHOOK_KIND,\n binding: resolved,\n });\n // Awaited: a delivery landing before the token exists would be refused,\n // and the piece registers this URL with the provider from onEnable.\n await (await this.endpoints())?.endpointFor(workflowId);\n }\n // Arming downloads a bundle and calls the provider; that stays off the\n // operation-ingestion path.\n this.enableSupervised(workflowId, resolved);\n }\n\n // Strategy comes from the piece catalog rather than the bundle: deciding\n // poll-vs-webhook must not require loading piece code.\n private async pieceDelivery(\n binding: PieceTriggerBinding,\n ): Promise<\"poll\" | \"webhook\"> {\n try {\n const { triggers } = await this.pieceTriggers(binding.packageName);\n const strategy = triggers.find(\n (entry) => entry.name === binding.triggerName,\n )?.strategy;\n return strategy === \"WEBHOOK\" ? \"webhook\" : \"poll\";\n } catch (error) {\n // Unknown strategy polls: a poll that returns nothing is recoverable,\n // a webhook endpoint nobody serves is not.\n this.logger.warn(\n \"Could not resolve the trigger strategy for @block; polling\",\n binding.blockType,\n error,\n );\n return \"poll\";\n }\n }\n\n // A disabled or retyped webhook trigger loses its registry entry, so\n // deliveries stop; the endpoint row stays so re-enabling keeps the URL.\n private async registerWebhook(\n workflowId: string,\n rawConfig: unknown,\n ): Promise<void> {\n const had = this.registry.get(workflowId);\n if (had && SUPERVISED_KINDS.has(had.kind)) this.dropSupervised(workflowId);\n let config: WebhookConfig;\n try {\n config = parseWebhookConfig(configRecord(rawConfig));\n } catch (error) {\n this.registry.delete(workflowId);\n const message = error instanceof Error ? error.message : String(error);\n this.logger.error(\n `Webhook trigger rejected for ${workflowId}: ${message}`,\n );\n return;\n }\n this.registry.set(workflowId, {\n workflowId,\n kind: WEBHOOK_TRIGGER_KIND,\n config,\n });\n // Awaited: a delivery landing before the token exists would be refused.\n await (await this.endpoints())?.endpointFor(workflowId);\n }\n\n // Triggers the supervisor drives on its tick: piece polls and schedules.\n private supervisedBinding(\n workflowId: string,\n trigger: NonNullable<WorkflowState[\"trigger\"]>,\n ): TriggerBinding | undefined {\n if (trigger.blockType === SCHEDULE_BLOCK) {\n return {\n kind: \"schedule\",\n workflowId,\n blockType: SCHEDULE_BLOCK,\n config: configRecord(trigger.config),\n };\n }\n return this.pieceBinding(workflowId, trigger);\n }\n\n private pieceBinding(\n workflowId: string,\n trigger: NonNullable<WorkflowState[\"trigger\"]>,\n ): PieceTriggerBinding | undefined {\n const parsed = parseBlockType(trigger.blockType, packagePieces.versions());\n if (!parsed || parsed.kind !== \"trigger\") return undefined;\n const { config, pollIntervalMs } = splitPollInterval(\n configRecord(trigger.config),\n );\n return {\n workflowId,\n blockType: trigger.blockType,\n packageName: parsed.packageName,\n version: parsed.version,\n triggerName: parsed.name,\n config,\n connectionId: trigger.connectionId,\n pollIntervalMs,\n };\n }\n\n private dropSupervised(workflowId: string): void {\n this.supervisor()\n .remove(workflowId)\n .catch((error: unknown) => {\n this.logger.error(`Trigger disable failed for ${workflowId}`, error);\n });\n }\n\n private async refreshRegistration(\n workflowId: string,\n resultingState?: string,\n ): Promise<void> {\n // Parsed before awaiting, so only a malformed state falls through to a\n // fresh read; a registration failure must not trigger one.\n const carried = parseWorkflowState(resultingState);\n if (carried) {\n await this.updateRegistration(workflowId, carried);\n return;\n }\n const document =\n await this.host.reactorClient.get<WorkflowDocument>(workflowId);\n await this.updateRegistration(workflowId, document.state.global);\n }\n\n // The manager routes by filter only, so every per-drive processor instance\n // delivers every matching operation; dedup keeps fires once-per-operation.\n private readonly seenOps = new Set<string>();\n private readonly seenOpsQueue: string[] = [];\n\n private alreadySeen(key: string): boolean {\n if (this.seenOps.has(key)) return true;\n this.seenOps.add(key);\n this.seenOpsQueue.push(key);\n if (this.seenOpsQueue.length > 8192) {\n const evicted = this.seenOpsQueue.shift();\n if (evicted) this.seenOps.delete(evicted);\n }\n return false;\n }\n\n // Called by the workflow-triggers read model. Registry updates and the\n // journal write for every matched fire are awaited; execution is not, so\n // runs never block operation ingestion.\n async onOperations(operations: OperationWithContext[]): Promise<void> {\n const hints = collectLifecycleParentHints(operations);\n for (const { operation, context } of operations) {\n if (context.scope !== DOCUMENT_SCOPE && context.scope !== \"global\") {\n continue;\n }\n const opKey = operationKey({ operation, context });\n if (this.alreadySeen(opKey)) continue;\n if (context.scope === DOCUMENT_SCOPE) {\n await this.matchDocumentLifecycle(operation, context, hints, opKey);\n continue;\n }\n // A workflow edit updates the registry, then falls through: workflow docs are\n // also a document-event source, so a workflow can watch its own type.\n if (context.documentType === \"powerhouse/workflow\") {\n await this.refreshRegistration(\n context.documentId,\n operation.resultingState,\n );\n }\n if (operation.error !== undefined) continue;\n for (const registration of this.registry.values()) {\n if (registration.kind !== \"document-event\") continue;\n const matched = matchesEventFilter(\n registration.filter,\n context.documentType,\n context.documentId,\n operation.action.type,\n );\n if (!matched) continue;\n const payload = {\n documentId: context.documentId,\n documentType: context.documentType,\n branch: context.branch,\n scope: context.scope,\n action: {\n type: operation.action.type,\n input: operation.action.input,\n },\n operation: {\n index: operation.index,\n timestampUtcMs: operation.timestampUtcMs,\n },\n };\n await this.enqueueFire(\n registration.workflowId,\n payload,\n registration.kind,\n opKey,\n );\n }\n if (context.documentType === DRIVE_DOCUMENT_TYPE) {\n await this.matchDriveLifecycle(\n context.documentId,\n operation.action.type,\n operation.action.input,\n { index: operation.index, timestampUtcMs: operation.timestampUtcMs },\n opKey,\n );\n }\n }\n }\n\n // Journals the fire, then lets it run on its own. Awaiting only the write is\n // the whole point: once this resolves the run is durable, so the read model's\n // cursor may pass the operation that matched it, but nothing here waits on a\n // piece. A journal that cannot take the row still fires, best-effort.\n private async enqueueFire(\n workflowId: string,\n payload: unknown,\n kind: string,\n opKey: string,\n ): Promise<void> {\n const store = await this.store();\n if (!store) {\n this.fireFromTrigger(workflowId, payload, kind);\n return;\n }\n // The durable half of the dedupe: a crash can leave the cursor behind the\n // run it already wrote, so the replay delivers this operation a second time.\n const claimed = await store.claimDedupe(\n workflowId,\n `op:${opKey}`,\n OPERATION_DEDUPE_TTL_MS,\n new Date().toISOString(),\n );\n if (!claimed) return;\n let runId: string;\n try {\n runId = await store.enqueueRun({\n workflowId,\n triggerKind: kind,\n triggerPayload: payload,\n });\n } catch (error) {\n this.logger.error(\n `Could not journal the ${kind} fire for workflow ${workflowId}; running it without a durable record`,\n error,\n );\n this.fireFromTrigger(workflowId, payload, kind);\n return;\n }\n this.fireFromTrigger(workflowId, payload, kind, runId);\n }\n\n private fireFromTrigger(\n workflowId: string,\n payload: unknown,\n kind: string,\n enqueuedRunId?: string,\n ): void {\n this.fire(\n workflowId,\n payload,\n kind,\n undefined,\n undefined,\n enqueuedRunId,\n ).then(\n (run) => {\n this.logger.info(`${kind} fired workflow ${workflowId}: ${run.status}`);\n },\n (error: unknown) => {\n this.logger.error(\n `${kind} run failed for workflow ${workflowId}`,\n error,\n );\n },\n );\n }\n\n // Fires once per document, from whichever source reports it first. Only a fire that\n // matched is recorded, so a creation with an unknown drive leaves ADD_FILE its turn.\n private readonly firedLifecycle = new Set<string>();\n private readonly firedLifecycleQueue: string[] = [];\n\n private lifecycleAlreadyFired(\n kind: TriggerKind,\n documentId: string,\n ): boolean {\n return this.firedLifecycle.has(`${kind}:${documentId}`);\n }\n\n private recordLifecycleFired(kind: TriggerKind, documentId: string): void {\n const key = `${kind}:${documentId}`;\n if (this.firedLifecycle.has(key)) return;\n this.firedLifecycle.add(key);\n this.firedLifecycleQueue.push(key);\n if (this.firedLifecycleQueue.length > 4096) {\n const evicted = this.firedLifecycleQueue.shift();\n if (evicted) this.firedLifecycle.delete(evicted);\n }\n }\n\n private lifecycleTargets(\n kind: TriggerKind,\n ): { workflowId: string; filter: LifecycleFilter }[] {\n const targets: { workflowId: string; filter: LifecycleFilter }[] = [];\n for (const registration of this.registry.values()) {\n if (registration.kind !== kind) continue;\n // Redundant at runtime, but it is what tells the compiler the surviving\n // registrations carry a LifecycleFilter rather than an event filter.\n if (registration.kind === \"document-event\") continue;\n targets.push({\n workflowId: registration.workflowId,\n filter: registration.filter,\n });\n }\n return targets;\n }\n\n private async fireLifecycle(\n kind: TriggerKind,\n payload: {\n documentId: string;\n documentType: string | null;\n name: string | null;\n driveId: string | null;\n parentId: string | null;\n operation: { index: number; timestampUtcMs: string };\n },\n opKey: string,\n ): Promise<void> {\n let matched = false;\n for (const target of this.lifecycleTargets(kind)) {\n if (\n !matchesLifecycleFilter(\n target.filter,\n payload.documentType,\n payload.driveId,\n )\n ) {\n continue;\n }\n matched = true;\n await this.enqueueFire(target.workflowId, payload, kind, opKey);\n }\n if (matched) this.recordLifecycleFired(kind, payload.documentId);\n }\n\n // A \"child\" edge names the parent document but not its type, and only a drive\n // parent matters to a driveId filter. Cached: a drive gathers many documents.\n private readonly driveParentCache = new Map<string, boolean>();\n\n private async driveIdFromParent(\n parentId: string | undefined,\n ): Promise<string | undefined> {\n if (!parentId) return undefined;\n const cached = this.driveParentCache.get(parentId);\n if (cached !== undefined) return cached ? parentId : undefined;\n try {\n const parent = await this.host.reactorClient.get(parentId);\n const isDrive = parent.header.documentType === DRIVE_DOCUMENT_TYPE;\n if (this.driveParentCache.size > 1024) this.driveParentCache.clear();\n this.driveParentCache.set(parentId, isDrive);\n return isDrive ? parentId : undefined;\n } catch {\n return undefined;\n }\n }\n\n // The document's own CREATE_DOCUMENT / DELETE_DOCUMENT, the source of truth: it covers\n // documents outside any drive, carries the real type and name, and alone proves deletion.\n private async matchDocumentLifecycle(\n operation: OperationWithContext[\"operation\"],\n context: OperationWithContext[\"context\"],\n hints: Map<string, LifecycleParentHint>,\n opKey: string,\n ): Promise<void> {\n const kind = lifecycleKindForDocumentAction(operation.action.type);\n if (!kind) return;\n if (operation.error !== undefined) return;\n const input = inputRecord(operation.action.input);\n // DELETE_DOCUMENT names its target in the input; CREATE_DOCUMENT's input\n // and context agree.\n const documentId = stringField(input, \"documentId\") ?? context.documentId;\n if (this.lifecycleAlreadyFired(kind, documentId)) return;\n if (this.lifecycleTargets(kind).length === 0) return;\n\n const hint = hints.get(documentId);\n const driveId =\n hint?.driveId ?? (await this.driveIdFromParent(hint?.parentCandidate));\n const created = kind === \"document-created\";\n await this.fireLifecycle(\n kind,\n {\n documentId,\n // CREATE_DOCUMENT names the model it creates; the stored context type\n // answers for a deletion, where the document can no longer be read.\n documentType:\n (created ? stringField(input, \"model\") : undefined) ??\n (context.documentType || null),\n // Only a creation carries a name; a deleted document's name is gone.\n name: stringField(input, \"name\") ?? null,\n driveId: driveId ?? null,\n parentId: hint?.parentId ?? null,\n operation: {\n index: operation.index,\n timestampUtcMs: operation.timestampUtcMs,\n },\n },\n opKey,\n );\n }\n\n // The drive's fallback view: ADD_FILE always accompanies a CREATE_DOCUMENT, so it fires only\n // when that never reached the processor. DELETE_NODE stands alone — the document stays alive.\n private async matchDriveLifecycle(\n driveId: string,\n actionType: string,\n input: unknown,\n operation: { index: number; timestampUtcMs: string },\n opKey: string,\n ): Promise<void> {\n const kind = lifecycleKindForDriveAction(actionType);\n if (!kind) return;\n if (this.lifecycleTargets(kind).length === 0) return;\n\n const record = inputRecord(input);\n const documentId = stringField(record, \"id\");\n if (!documentId) return;\n if (this.lifecycleAlreadyFired(kind, documentId)) return;\n let documentType = stringField(record, \"documentType\");\n let name = stringField(record, \"name\") ?? null;\n if (kind === \"document-deleted\") {\n // Best-effort: unlinking a node leaves the document in place. Folder\n // nodes never resolve, so a type filter also skips them.\n try {\n const document = await this.host.reactorClient.get(documentId);\n documentType = document.header.documentType;\n name ??= document.header.name;\n } catch {\n documentType = undefined;\n }\n }\n\n await this.fireLifecycle(\n kind,\n {\n documentId,\n documentType: documentType ?? null,\n name,\n driveId,\n parentId: stringField(record, \"parentFolder\") ?? null,\n operation,\n },\n opKey,\n );\n }\n\n private triggerSupervisor?: TriggerSupervisor;\n\n // Lazily built; started/stopped by the trigger processor's lifecycle.\n supervisor(): TriggerSupervisor {\n this.triggerSupervisor ??= new TriggerSupervisor({\n store: () => this.store(),\n resolveAuth: async (connectionId, request) => {\n if (!connectionId) return undefined;\n const resolved = await new DocumentConnectionResolver(\n this.host,\n this.secretProvider(),\n ).resolveWithSecrets(connectionId, request);\n // The supervisor reads these back off the auth value to redact what a\n // trigger hook throws; nothing else travels with it.\n return rememberSecrets(resolved.auth, resolved.secretValues);\n },\n fire: (workflowId, payload, kind) => {\n this.fireFromTrigger(workflowId, payload, kind);\n },\n webhookUrlFor: async (workflowId) =>\n (await this.mintWebhookEndpoint(workflowId))?.url,\n cacheDir: BUNDLE_CACHE_DIR,\n resolver: pieceResolver(),\n // Trigger hooks reach the same services steps do.\n egress: configuredEgress(),\n // Dev override; the 60s floor still applies.\n defaultIntervalMs:\n Number(process.env.WORKFLOW_POLL_INTERVAL_MS) || undefined,\n reconcileIntervalMs:\n Number(process.env.WORKFLOW_WEBHOOK_RECONCILE_MS) || undefined,\n });\n return this.triggerSupervisor;\n }\n\n startTriggerSupervisor(): void {\n this.supervisor().start();\n }\n\n stopTriggerSupervisor(): void {\n this.triggerSupervisor?.stop();\n }\n\n // Teardown for the whole runtime, driven by the host. The run children\n // outlive the reactor otherwise — they are forked, not\n // spawned by it — and a run holding one is over the moment we stop.\n shutdown(): void {\n this.stopTriggerSupervisor();\n // Left in place, disposed: clearing it here would let a run that is still\n // between awaits build a replacement and fork into it after teardown.\n this.pieceWorkers?.dispose();\n // Forked on the editor's first request and never replaced, so it outlives\n // a hot reload unless it goes with everything else.\n this.designWorker?.dispose();\n this.designWorker = undefined;\n }\n\n // A trigger's state names its workflow and its last error, so the rows are\n // filtered to the workflows this caller may read.\n async triggerStates(ctx?: WorkflowCaller): Promise<TriggerStateRow[]> {\n const store = await this.store();\n if (!store) return [];\n const rows = await store.listTriggerStates();\n return this.readableRows(rows, (row) => row.workflow_id, ctx);\n }\n\n private webhookEndpoints?: IWebhookEndpoints;\n private webhookScope?: IWebhookScope;\n // Held as a promise: seeding runs from the constructor, before the host\n // registers, so a seeded webhook workflow would mint no token and fail to arm.\n private webhookRegistration?: Promise<IWebhookEndpoints | undefined>;\n\n /** Registers the workflow endpoint family with the reactor's webhook service\n * (idempotent). Everything transport-shaped is the service's; only workflow identity is ours. */\n async registerWebhookEndpoint(): Promise<void> {\n if (this.webhookRegistration) {\n await this.webhookRegistration;\n return;\n }\n const webhooks = this.host.webhooks;\n if (!webhooks) {\n this.logger.warn(\n \"This host serves no webhooks; workflows with a webhook trigger will not arm\",\n );\n return;\n }\n this.webhookScope = webhooks;\n this.webhookRegistration = webhooks\n .register({\n name: \"trigger\",\n policyFor: (workflowId) => this.webhookPolicy(workflowId),\n onRequest: (request) => this.deliverWebhook(request),\n })\n .then((endpoints) => {\n this.webhookEndpoints = endpoints;\n return endpoints;\n })\n .catch((error: unknown) => {\n // No webhook store means no webhook triggers, not no workflows:\n // rethrowing would take every other trigger down with it.\n this.logger.warn(\n \"Webhook triggers are unavailable on this host; other triggers are unaffected: @error\",\n error,\n );\n return undefined;\n });\n await this.webhookRegistration;\n }\n\n /** The endpoint family, once registered. Seeding runs before the host starts\n * the runtime, so a caller that needs a token waits rather than finds it missing. */\n private async endpoints(): Promise<IWebhookEndpoints | undefined> {\n if (this.webhookEndpoints) return this.webhookEndpoints;\n // The host normally registers on start, but seeding runs from the\n // constructor and an enable can reach here first. Registering on demand\n // makes the order irrelevant, rather than failing the trigger on a race.\n if (!this.webhookRegistration && this.host.webhooks) {\n await this.registerWebhookEndpoint();\n }\n return await this.webhookRegistration;\n }\n\n /** The per-document policy the service enforces before a delivery reaches this code;\n * undefined means the workflow is not armed, answered exactly as an unknown token is. */\n async webhookPolicy(workflowId: string): Promise<WebhookPolicy | undefined> {\n // Seeding starts from the constructor and a delivery can beat it, and an\n // unseeded registry is indistinguishable from a bad token.\n await this.seedPromise;\n\n const registration = this.registry.get(workflowId);\n if (!registration) return undefined;\n\n // A piece owns its own verification and parsing: its run hook decides what\n // the request means, or rejects it.\n if (registration.kind === PIECE_WEBHOOK_KIND) return {};\n if (registration.kind !== WEBHOOK_TRIGGER_KIND) return undefined;\n\n const { config } = registration;\n return {\n methods: config.methods,\n challengeField: config.challengeField,\n dedupe: config.dedupeField\n ? {\n field: config.dedupeField,\n ttlSeconds: config.dedupeTtlSeconds,\n }\n : undefined,\n verify:\n config.scheme === \"none\"\n ? undefined\n : {\n scheme: config.scheme,\n header: config.header,\n secret: await this.webhookSecret(config, workflowId),\n toleranceSeconds: config.toleranceSeconds,\n algorithm: config.algorithm,\n encoding: config.encoding,\n prefix: config.prefix,\n },\n };\n }\n\n // Design-time: the URL to hand the provider. Minted on demand so an author\n // can copy it before the first delivery.\n async webhookEndpoint(\n workflowId: string,\n ctx?: WorkflowCaller,\n ): Promise<WebhookEndpointRecord | null> {\n // The URL carries the token that is the entire credential for a public\n // route, so handing it out is a read of the workflow itself.\n await this.assertCanReadDocument(workflowId, ctx);\n return this.mintWebhookEndpoint(workflowId);\n }\n\n // The supervisor's own lookup: server-side, with no caller to authorize.\n private async mintWebhookEndpoint(\n workflowId: string,\n ): Promise<WebhookEndpointRecord | null> {\n const endpoints = await this.endpoints();\n if (!endpoints) return null;\n const registration = this.registry.get(workflowId);\n const armed =\n registration?.kind === WEBHOOK_TRIGGER_KIND ||\n registration?.kind === PIECE_WEBHOOK_KIND;\n\n // Minted whether or not the workflow is armed: an author has to give the\n // URL to the sender before enabling, and enabling is what accepts.\n\n // `armed` carries the difference instead, so nothing is hidden — and this\n // never scans, which listing every endpoint to find one would.\n\n // A host that does not know its own public origin advertises a bare path; copying that into\n // a provider's console fails with nothing to read, so the author is told here instead.\n const absoluteUrl = this.webhookScope?.hasPublicOrigin ?? false;\n\n const minted = await endpoints.endpointFor(workflowId);\n return {\n workflowId,\n url: minted.url,\n absoluteUrl,\n armed,\n createdAt: minted.createdAt,\n };\n }\n\n /** A delivery the service has already rate-limited, verified, de-duplicated and\n * answered any challenge for; all that is left is deciding what it means. */\n async deliverWebhook(request: WebhookRequest): Promise<WebhookReply> {\n const workflowId = request.key;\n const registration = this.registry.get(workflowId);\n if (!registration) return UNAUTHORIZED;\n if (registration.kind === PIECE_WEBHOOK_KIND) {\n return this.deliverToPiece(registration.binding, request);\n }\n if (registration.kind !== WEBHOOK_TRIGGER_KIND) return UNAUTHORIZED;\n\n const { config } = registration;\n const payload = webhookPayload(request);\n\n if (config.responseMode === \"async\") {\n this.fireFromTrigger(workflowId, payload, WEBHOOK_TRIGGER_KIND);\n return { status: config.responseStatus };\n }\n // Sync mode holds the provider's socket, so the wait is bounded. On expiry the run is left\n // going — cancelling would lose announced work — and the 504 retry is what dedupe absorbs.\n const run = await Promise.race([\n this.fire(workflowId, payload, WEBHOOK_TRIGGER_KIND).then(\n (result) => ({ ok: true, result }) as const,\n (error: unknown) => ({ ok: false, error }) as const,\n ),\n timeout(DELIVERY_TIMEOUT_MS),\n ]);\n\n if (run === TIMED_OUT) {\n this.logger.warn(\n `Webhook run for ${workflowId} exceeded ${DELIVERY_TIMEOUT_MS}ms; answering 504 while it continues`,\n );\n return {\n status: 504,\n contentType: JSON_CONTENT_TYPE,\n body: JSON.stringify({\n status: \"RUNNING\",\n error: \"The run did not finish in time\",\n }),\n };\n }\n\n if (!run.ok) {\n const message =\n run.error instanceof Error ? run.error.message : String(run.error);\n this.logger.error(`Webhook run failed for ${workflowId}: ${message}`);\n return {\n status: 500,\n contentType: JSON_CONTENT_TYPE,\n body: JSON.stringify({ error: message }),\n };\n }\n\n return {\n status: run.result.status === \"SUCCEEDED\" ? config.responseStatus : 500,\n contentType: JSON_CONTENT_TYPE,\n body: JSON.stringify({\n runId: run.result.runId,\n status: run.result.status,\n error: run.result.error ?? null,\n }),\n };\n }\n\n // The probe a sender sends before it will register the endpoint. Answered by\n // the piece: only its own code knows what the sender wants echoed back.\n private async pieceHandshake(\n binding: PieceTriggerBinding,\n request: WebhookRequest,\n ): Promise<WebhookReply | undefined> {\n const handshake = await this.pieceHandshakeConfig(binding);\n if (!handshake || !handshakeMatches(handshake, request)) return undefined;\n try {\n const result = await this.supervisor().handshake(\n binding,\n webhookPayload(request),\n );\n return handshakeReply(result.output);\n } catch (error) {\n // A failed probe is the sender's answer, so it must not look like a\n // delivery: 500 tells it to retry rather than that the endpoint is gone.\n this.logger.error(\n \"Handshake failed for @block on workflow @workflow\",\n binding.blockType,\n binding.workflowId,\n error,\n );\n return { status: 500 };\n }\n }\n\n private async pieceHandshakeConfig(\n binding: PieceTriggerBinding,\n ): Promise<PieceHandshake | undefined> {\n try {\n const descriptor = await this.pieceDescriptor(\n binding.packageName,\n binding.version,\n );\n return descriptor.triggers.find(\n (entry) => entry.name === binding.triggerName,\n )?.handshake;\n } catch (error) {\n // A delivery must not fail because the descriptor could not be read; the\n // cost of guessing wrong is one probe answered as a delivery.\n this.logger.warn(\n \"Could not read the handshake config for @block\",\n binding.blockType,\n error,\n );\n return undefined;\n }\n }\n\n // The piece owns verification and parsing, so there is no scheme to check\n // here: its run hook decides what the request means, or rejects it.\n private async deliverToPiece(\n binding: PieceTriggerBinding,\n request: WebhookRequest,\n ): Promise<WebhookReply> {\n const probe = await this.pieceHandshake(binding, request);\n if (probe) return probe;\n\n const payload = webhookPayload(request);\n // Answered before the hook runs, as Activepieces does: a provider must not\n // wait on piece code, and its retry would only duplicate the delivery.\n this.supervisor()\n .deliverWebhook(binding.workflowId, payload)\n .then(\n () => {\n this.logger.info(\n \"Webhook delivered to @block for workflow @workflow\",\n binding.blockType,\n binding.workflowId,\n );\n },\n (error: unknown) => {\n this.logger.error(\n `Webhook delivery failed for workflow ${binding.workflowId}`,\n error,\n );\n },\n );\n return { status: 200 };\n }\n\n // A missing or deleted secret is a rejection, not an error: the endpoint is\n // configured as signed and there is nothing to verify against.\n private async webhookSecret(\n config: WebhookConfig,\n workflowId: string,\n ): Promise<string | undefined> {\n if (!config.secretRef) return undefined;\n try {\n return await (await this.secrets()).get(config.secretRef);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n this.logger.error(\n `Webhook secret unavailable for ${workflowId}: ${message}`,\n );\n return undefined;\n }\n }\n\n private readonly descriptors = new Map<string, PieceDescriptor>();\n private designWorker?: PieceWorker;\n\n // Design-time piece code runs under the policy a run would get, so nothing\n // the editor does reaches somewhere a step could not.\n\n // Held rather than inlined for the reason the supervisor holds one: a\n // deployment whose isolation lives elsewhere has to be able to widen it.\n // Design-time piece code — a dropdown's options(), a connection check — runs\n // under the same policy a step does, widened the same way. Without that, the\n // editor cannot offer the lines of a floor it is about to poll.\n private designEgress: EgressPolicy | undefined =\n configuredEgress() ?? DEFAULT_EGRESS_POLICY;\n\n private async pieceDescriptor(\n packageName: string,\n version: string,\n ): Promise<PieceDescriptor> {\n const cacheKey = `${packageName}@${version}`;\n let descriptor = this.descriptors.get(cacheKey);\n if (!descriptor) {\n const piece = await pieceResolver().resolve(packageName, version);\n // Loading the bundle runs the piece module's top-level code, so the\n // descriptor is built in the worker, never in the reactor process.\n this.designWorker ??= new PieceWorker();\n let output: unknown;\n try {\n const result = await this.designWorker.describePiece(\n // Loading the module runs piece-authored top-level code, which\n // has no business reaching anything at all.\n {\n ...pieceModuleRef(piece),\n packageName,\n version,\n ...(this.designEgress ? { egress: this.designEgress } : {}),\n },\n { timeoutMs: DESCRIBE_TIMEOUT_MS },\n );\n output = result.output;\n } catch (error) {\n throw new Error(\n pieceFailureDetail(\n error,\n `Loading piece \"${packageName}\" timed out after ${Math.round(DESCRIBE_TIMEOUT_MS / 1000)}s`,\n ),\n { cause: error },\n );\n }\n descriptor = output as PieceDescriptor;\n this.descriptors.set(cacheKey, descriptor);\n }\n return descriptor;\n }\n\n // The workflows a drive holds that this caller may read, so a drive app can\n // scope runs to its own.\n async driveWorkflowIds(\n driveId: string,\n ctx?: WorkflowCaller,\n ): Promise<string[]> {\n await this.assertCanReadDocument(driveId, ctx);\n let page = await this.host.reactorClient.drives.listNodes(driveId);\n const nodes = [...page.results];\n // A drive past one page would otherwise scope runs to a prefix of its\n // workflows and read as a history that never happened.\n while (page.next) {\n page = await page.next();\n nodes.push(...page.results);\n }\n // Only file nodes carry a documentType, so `in` also rules out folders.\n const ids = nodes\n .filter(\n (node) =>\n \"documentType\" in node &&\n node.documentType === WORKFLOW_DOCUMENT_TYPE,\n )\n .map((node) => node.id);\n return this.readableRows(ids, (id) => id, ctx);\n }\n\n // The run journal, scoped to what this caller may read: a run carries its\n // trigger payload and every step's input and output.\n async runs(\n args: { workflowId?: string; driveId?: string; limit?: number },\n ctx?: WorkflowCaller,\n ): Promise<RunRecord[]> {\n const store = await this.store();\n if (!store) return [];\n // A drive scopes runs to the workflows it holds; an explicit workflowId is\n // narrower still, so it wins.\n let scope: string | string[] | undefined;\n if (args.workflowId) {\n await this.assertCanReadDocument(args.workflowId, ctx);\n scope = args.workflowId;\n } else if (args.driveId) {\n scope = await this.driveWorkflowIds(args.driveId, ctx);\n if (scope.length === 0) return [];\n } else if (!ctx) {\n // An unscoped listing is every workflow in the reactor, so it needs a\n // caller to filter by.\n return [];\n }\n const rows = await store.listRuns(scope, args.limit ?? 25);\n const readable = await this.readableRows(\n rows,\n (row) => row.workflow_id,\n ctx,\n );\n return Promise.all(\n readable.map(async (row) => ({\n row,\n steps: await store.getSteps(row.id),\n })),\n );\n }\n\n // One run, or null when the caller may not read its workflow: \"not yours\"\n // and \"no such run\" must not be distinguishable.\n async run(runId: string, ctx?: WorkflowCaller): Promise<RunRecord | null> {\n const store = await this.store();\n if (!store || !ctx) return null;\n const row = await store.getRun(runId);\n if (!row) return null;\n if (!(await this.canReadDocument(row.workflow_id, ctx))) return null;\n return { row, steps: await store.getSteps(row.id) };\n }\n\n // Design-time: the powerhouse/connection documents this caller may read.\n // The reactor client is unscoped, so the filter is ours to apply.\n async connections(ctx?: WorkflowCaller): Promise<ConnectionSummary[]> {\n const page = await this.host.reactorClient.find({\n type: \"powerhouse/connection\",\n });\n const readable = await this.readableDocuments(\n page.results as ConnectionDocument[],\n ctx,\n );\n return readable.map((document) => {\n const state = document.state.global;\n return {\n id: document.header.id,\n name: state.name,\n connectorId: state.connectorId,\n authType: state.authType,\n status: state.status,\n accountLabel: state.accountLabel ?? null,\n };\n });\n }\n\n // Runs the piece's app.checkConnection (when declared) against the\n // connection's credentials and records the outcome on the document.\n async checkConnection(\n connectionId: string,\n ctx?: WorkflowCaller,\n ): Promise<ConnectionCheckResult> {\n await this.assertCanReadDocument(connectionId, ctx);\n // A check records its outcome on the connection, so this is a write: a\n // read-only caller is refused before anything is fetched or resolved.\n await this.assertCanWriteDocument(connectionId, ctx);\n const document =\n await this.host.reactorClient.get<ConnectionDocument>(connectionId);\n if (document.header.documentType !== \"powerhouse/connection\") {\n throw new Error(\n `Document \"${connectionId}\" is not a powerhouse/connection`,\n );\n }\n const state = document.state.global;\n const accountLabel = state.accountLabel ?? null;\n\n // Revocation is a decision, not an observation: recording any result here\n // would write ERROR over it and let the next check resolve the secrets.\n if (state.status === \"REVOKED\") {\n return { ok: false, detail: \"Connection is revoked\", accountLabel };\n }\n if (state.status === \"UNCONFIGURED\") {\n return this.recordCheckResult(document, {\n ok: false,\n detail: \"Connection is not configured\",\n accountLabel,\n });\n }\n // No bundle work for auth kinds the runtime cannot execute yet.\n if (state.authType === \"OAUTH2\" || state.authType === \"OIDC\") {\n return this.recordCheckResult(document, {\n ok: false,\n detail: `${state.authType} connections are not supported by the runtime yet`,\n accountLabel,\n });\n }\n\n const packageName = packageFromConnectorId(state.connectorId);\n let moduleRef: PieceModuleRef;\n try {\n const version = await this.pieceVersion(packageName);\n moduleRef = pieceModuleRef(\n await pieceResolver().resolve(packageName, version),\n );\n } catch (error) {\n return this.recordCheckResult(document, {\n ok: false,\n detail: error instanceof Error ? error.message : String(error),\n accountLabel,\n });\n }\n\n // Through the shared decision, so a revoked connection is refused here as\n // it is on a run; the document is already in hand, so no second fetch.\n let shapedAuth: unknown;\n try {\n shapedAuth = await resolveConnectionAuth(\n document,\n this.secretProvider(),\n {\n blockType: state.connectorId,\n piecePackage: packageName,\n },\n );\n } catch (error) {\n // A missing or deleted secret names its ref in the message.\n return this.recordCheckResult(document, {\n ok: false,\n detail: error instanceof Error ? error.message : String(error),\n accountLabel,\n });\n }\n\n // Plaintext auth crosses only into the piece worker: checkConnection is\n // untrusted piece code and must not run in the reactor process.\n let outcome: CheckConnectionOutcome;\n try {\n this.designWorker ??= new PieceWorker();\n const result = await this.designWorker.checkConnection(\n // A check that reaches somewhere a run could not would call a\n // connection healthy that every step using it will fail on.\n {\n ...moduleRef,\n auth: shapedAuth,\n ...(this.designEgress ? { egress: this.designEgress } : {}),\n },\n { timeoutMs: CHECK_TIMEOUT_MS },\n );\n outcome = result.output as CheckConnectionOutcome;\n } catch (error) {\n return this.recordCheckResult(document, {\n ok: false,\n detail: checkFailureDetail(error),\n accountLabel,\n });\n }\n\n if (!outcome.declared) {\n return this.recordCheckResult(document, {\n ok: true,\n detail: \"piece declares no connection check; credentials resolved\",\n accountLabel,\n });\n }\n if (outcome.result === false) {\n return this.recordCheckResult(document, {\n ok: false,\n detail: \"Connection check failed\",\n accountLabel,\n });\n }\n return this.recordCheckResult(document, {\n ok: true,\n detail: null,\n accountLabel: accountLabelFromCheckResult(outcome.result) ?? accountLabel,\n });\n }\n\n // Catalog first, piece detail as fallback; the cache keeps this cheap.\n private async pieceVersion(packageName: string): Promise<string> {\n // A package piece is pinned by what this reactor installed, and no\n // published listing has anything to say about it.\n await packagePieces.ready();\n const local = packagePieces.lookup(packageName);\n if (local) return local.version;\n try {\n const catalog = await fetchPieceCatalog();\n const version = catalog.find(\n (entry) => entry.name === packageName,\n )?.version;\n if (version) return version;\n } catch {\n // Catalog unreachable; fall through to the piece detail.\n }\n const detail = (await fetchPieceDetail(packageName)) as {\n version?: unknown;\n };\n if (typeof detail.version === \"string\" && detail.version !== \"\") {\n return detail.version;\n }\n throw new Error(`Could not resolve a version for piece \"${packageName}\"`);\n }\n\n private async recordCheckResult(\n document: ConnectionDocument,\n result: ConnectionCheckResult,\n ): Promise<ConnectionCheckResult> {\n const action = connectionActions.recordCheckResult({\n status: result.ok ? \"OK\" : \"ERROR\",\n checkedAt: new Date().toISOString(),\n error: result.ok ? undefined : (result.detail ?? undefined),\n });\n await this.host.reactorClient.execute(document.header.id, \"main\", [action]);\n return result;\n }\n\n // The pieces this reactor holds locally, described from their own code.\n\n // One failure does not sink the catalog: a package whose piece cannot be\n // loaded is logged and left out, the way an unreachable listing would be.\n private async localPieces(): Promise<\n { piece: LocalPiece; descriptor: PieceDescriptor }[]\n > {\n await packagePieces.ready();\n const described = await Promise.all(\n packagePieces.entries().map(async (piece) => {\n try {\n const descriptor = await this.pieceDescriptor(\n piece.name,\n piece.version,\n );\n return { piece, descriptor };\n } catch (error) {\n this.logger.warn(\n `Could not describe the package piece \"${piece.name}\": ${String(error)}`,\n );\n return undefined;\n }\n }),\n );\n return described.filter((entry) => entry !== undefined);\n }\n\n private async localPiece(\n packageName: string,\n ): Promise<{ piece: LocalPiece; descriptor: PieceDescriptor } | undefined> {\n await packagePieces.ready();\n const piece = packagePieces.lookup(packageName);\n if (!piece) return undefined;\n return {\n piece,\n descriptor: await this.pieceDescriptor(piece.name, piece.version),\n };\n }\n\n // Package pieces plus the published catalog, the local ones winning their\n // own names. The listing is remote, so it may be the half that fails: with\n // local pieces to show, that is logged rather than served as no catalog.\n async pieceCatalog(): Promise<PieceSummary[]> {\n const local = await this.localPieces();\n const entries = local.map(({ piece, descriptor }) =>\n catalogEntry(descriptor, piece.name, piece.version),\n );\n const names = new Set(entries.map((entry) => entry.name));\n let published: PieceSummary[];\n try {\n published = await fetchPieceCatalog();\n } catch (error) {\n if (entries.length === 0) throw error;\n this.logger.warn(`Serving package pieces only: ${String(error)}`);\n published = [];\n }\n return [\n ...entries,\n ...published.filter((entry) => !names.has(entry.name)),\n ].sort((a, b) => a.displayName.localeCompare(b.displayName));\n }\n\n async pieceActions(packageName: string): Promise<PieceActionsResult> {\n const local = await this.localPiece(packageName);\n return local\n ? actionsResult(local.descriptor, local.piece.name, local.piece.version)\n : fetchPieceActions(packageName);\n }\n\n async pieceTriggers(packageName: string): Promise<PieceTriggersResult> {\n const local = await this.localPiece(packageName);\n return local\n ? triggersResult(local.descriptor, local.piece.name, local.piece.version)\n : fetchPieceTriggers(packageName);\n }\n\n // Catalog search, with this reactor's own pieces always in it: the index\n // behind the published half may still be building, or unreachable.\n async searchBlocks(\n query: string,\n limit?: number,\n ): Promise<BlockSearchResult> {\n let local: BlockSearchIndex | undefined;\n try {\n local = indexFromHits(\n (await this.localPieces()).flatMap(({ piece, descriptor }) =>\n localSearchHits(descriptor, piece.name),\n ),\n );\n } catch (error) {\n // The published half is still worth serving without them.\n this.logger.warn(`Could not index the package pieces: ${String(error)}`);\n }\n return searchBlocks(query, limit, local);\n }\n\n async pieceDetail(packageName: string): Promise<unknown> {\n const local = await this.localPiece(packageName);\n return local\n ? detailResult(local.descriptor, local.piece.name, local.piece.version)\n : fetchPieceDetail(packageName);\n }\n\n // Design-time: the action/trigger descriptor (props, auth) driving the\n // editor form; triggers come back under a \"trigger\" key.\n async blockDescriptor(blockType: string): Promise<unknown> {\n await packagePieces.ready();\n const parsed = parseBlockType(blockType, packagePieces.versions());\n if (!parsed) return null;\n const descriptor = await this.pieceDescriptor(\n parsed.packageName,\n parsed.version,\n );\n const common = {\n displayName: descriptor.displayName,\n logoUrl: descriptor.logoUrl,\n auth: descriptor.auth ?? null,\n };\n if (parsed.kind === \"trigger\") {\n const trigger = descriptor.triggers.find(\n (entry) => entry.name === parsed.name,\n );\n return trigger ? { ...common, trigger } : null;\n }\n const action = descriptor.actions.find(\n (entry) => entry.name === parsed.name,\n );\n return action ? { ...common, action } : null;\n }\n\n // Design-time entry points hand a connection's live credentials to piece\n // code, so the caller must be allowed to read the connection document.\n\n // A missing context means the request arrived through a path that cannot\n // identify its caller; that is a refusal, not a pass.\n // Keeps only what this caller may read. Without a context nothing is\n // readable, which is what an unauthenticated listing should return.\n private async readableDocuments<T extends { header: { id: string } }>(\n documents: T[],\n ctx: WorkflowCaller | undefined,\n ): Promise<T[]> {\n if (!ctx) return [];\n const host = this.host;\n const allowed = await Promise.all(\n documents.map((document) =>\n host\n .assertCanRead(document.header.id, ctx)\n .then(() => true)\n .catch(() => false),\n ),\n );\n return documents.filter((_, index) => allowed[index]);\n }\n\n // The same filter for journal rows, which carry the document they belong to\n // rather than being one.\n private async readableRows<T>(\n rows: T[],\n documentIdOf: (row: T) => string,\n ctx: WorkflowCaller | undefined,\n ): Promise<T[]> {\n if (!ctx) return [];\n const allowed = await Promise.all(\n rows.map((row) => this.canReadDocument(documentIdOf(row), ctx)),\n );\n return rows.filter((_, index) => allowed[index]);\n }\n\n private canReadDocument(\n documentId: string,\n ctx: WorkflowCaller,\n ): Promise<boolean> {\n return this.host\n .assertCanRead(documentId, ctx)\n .then(() => true)\n .catch(() => false);\n }\n\n private async assertCanReadDocument(\n documentId: string,\n ctx: WorkflowCaller | undefined,\n ): Promise<void> {\n if (!ctx) {\n throw new Error(\"Connection access requires an authenticated request\");\n }\n await this.host.assertCanRead(documentId, ctx);\n }\n\n private async assertCanWriteDocument(\n documentId: string,\n ctx: WorkflowCaller | undefined,\n ): Promise<void> {\n if (!ctx) {\n throw new Error(\"Connection access requires an authenticated request\");\n }\n await this.host.assertCanWrite(documentId, ctx);\n }\n\n // Design-time DROPDOWN options() / DYNAMIC props(), run in the piece worker.\n async blockOptions(\n blockType: string,\n propName: string,\n input?: unknown,\n connectionId?: string,\n ctx?: WorkflowCaller,\n ): Promise<unknown> {\n await packagePieces.ready();\n const parsed = parseBlockType(blockType, packagePieces.versions());\n if (!parsed) {\n throw new Error(`Not a piece block type: \"${blockType}\"`);\n }\n // Auth-dependent options() resolvers need the step's connection. Nothing\n // about the request authorizes it, so the caller's own read access does.\n let auth: unknown;\n if (connectionId) {\n await this.assertCanReadDocument(connectionId, ctx);\n auth = await new DocumentConnectionResolver(\n this.host,\n this.secretProvider(),\n ).resolve(connectionId, {\n blockType,\n piecePackage: parsed.packageName,\n });\n }\n const piece = await pieceResolver().resolve(\n parsed.packageName,\n parsed.version,\n );\n this.designWorker ??= new PieceWorker();\n const result = await this.designWorker.resolveOptions(\n {\n ...pieceModuleRef(piece),\n actionName: parsed.name,\n kind: parsed.kind,\n propName,\n refresherValues: (input ?? {}) as Record<string, unknown>,\n auth,\n // A package piece's options() reads the reactor it offers choices\n // from, over the same port a step of it would use — offered only when\n // there is a host to answer, or the member would fail as a missing\n // handler rather than as the unsupported member it is.\n ...(piece.local ? { reactorAccess: true } : {}),\n // Options come from the same service the step will call: the editor\n // must not offer a choice a run cannot reach.\n ...(this.designEgress ? { egress: this.designEgress } : {}),\n },\n piece.local\n ? {\n hostCalls: reactorHandlers(\n new ScopedDesignTimeReactorPort(this.host, ctx),\n ),\n }\n : {},\n );\n return result.output;\n }\n\n // Authored output shape of a block, for the editor's expression picker.\n async blockOutputTree(\n blockType: string,\n config?: unknown,\n ): Promise<OutputTree> {\n await packagePieces.ready();\n const record = (config ?? {}) as Record<string, unknown>;\n switch (blockType) {\n case \"core#manual\":\n return { source: \"none\", nodes: [] };\n case SCHEDULE_BLOCK:\n return { source: \"static\", nodes: scheduleTriggerTree() };\n case WEBHOOK_BLOCK:\n return { source: \"static\", nodes: webhookTriggerTree() };\n case \"core#branch\":\n return {\n source: \"static\",\n nodes: [{ name: \"condition\", type: \"value\" }],\n };\n case \"core#assert\":\n return { source: \"static\", nodes: [{ name: \"value\", type: \"value\" }] };\n case DOCUMENT_CREATED_BLOCK:\n case DOCUMENT_DELETED_BLOCK:\n return { source: \"static\", nodes: lifecycleTriggerTree() };\n case DOCUMENT_EVENT_BLOCK: {\n const inputChildren = await this.operationInputFields(\n staticString(record.documentType),\n staticString(record.actionType),\n );\n return {\n source: inputChildren.length > 0 ? \"schema\" : \"static\",\n nodes: documentEventTree(inputChildren),\n };\n }\n case DOCUMENT_FIND_BLOCK:\n return { source: \"static\", nodes: documentFindTree() };\n case DOCUMENT_SCHEMA_BLOCK:\n return { source: \"static\", nodes: documentSchemaTree() };\n case DOCUMENT_TYPES_BLOCK:\n return { source: \"static\", nodes: documentTypesTree() };\n case DOCUMENT_GET_BLOCK: {\n // The type may come from a sibling hint when the id is an expression.\n const stateChildren = await this.stateFields(\n staticString(record.documentType),\n );\n return {\n source: stateChildren.length > 0 ? \"schema\" : \"static\",\n nodes: documentGetTree(stateChildren),\n };\n }\n case DOCUMENT_CREATE_BLOCK:\n case DOCUMENT_DISPATCH_BLOCK: {\n const stateChildren = await this.stateFields(\n staticString(record.documentType),\n );\n return {\n source: stateChildren.length > 0 ? \"schema\" : \"static\",\n nodes: documentBlockTree(stateChildren),\n };\n }\n default: {\n const parsed = parseBlockType(blockType, packagePieces.versions());\n if (!parsed) return { source: \"none\", nodes: [] };\n // Through the service, not the published catalog: a package piece is\n // often unpublished, and its detail comes from its own descriptor.\n const detail = (await this.pieceDetail(parsed.packageName)) as {\n actions?: Record<string, unknown>;\n triggers?: Record<string, unknown>;\n };\n const entry = (\n parsed.kind === \"trigger\" ? detail.triggers : detail.actions\n )?.[parsed.name] as\n | { outputSchema?: unknown; sampleData?: unknown }\n | undefined;\n if (entry?.outputSchema) {\n const nodes = fromOutputSchema(entry.outputSchema);\n if (nodes.length > 0) return { source: \"schema\", nodes };\n // Fields that all map to the whole output: the output is a scalar.\n if (hasOutputSchemaFields(entry.outputSchema)) {\n return { source: \"schema\", nodes: [] };\n }\n }\n if (entry?.sampleData !== undefined && entry.sampleData !== null) {\n const nodes = fromSample(entry.sampleData);\n if (nodes.length > 0) return { source: \"sample\", nodes };\n }\n return { source: \"none\", nodes: [] };\n }\n }\n }\n\n private async stateFields(documentType?: string) {\n if (!documentType) return [];\n try {\n const module =\n await this.host.reactorClient.getDocumentModelModule(documentType);\n const sdl =\n module.documentModel.global.specifications.at(-1)?.state.global.schema;\n return sdl ? fieldsFromSdl(sdl) : [];\n } catch {\n return [];\n }\n }\n\n private async operationInputFields(\n documentType?: string,\n actionType?: string,\n ) {\n if (!documentType || !actionType) return [];\n try {\n const module =\n await this.host.reactorClient.getDocumentModelModule(documentType);\n const latest = module.documentModel.global.specifications.at(-1);\n for (const specModule of latest?.modules ?? []) {\n for (const operation of specModule.operations) {\n if (operation.name === actionType && operation.schema) {\n return fieldsFromSdl(operation.schema);\n }\n }\n }\n return [];\n } catch {\n return [];\n }\n }\n\n // Runs the trigger's test hook; the test store prefix keeps cursors intact.\n\n // It resolves the trigger's connection and hands the credentials to piece\n // code, so the caller must be able to read both documents.\n async testTrigger(\n workflowId: string,\n ctx?: WorkflowCaller,\n ): Promise<unknown> {\n await this.assertCanReadDocument(workflowId, ctx);\n const document =\n await this.host.reactorClient.get<WorkflowDocument>(workflowId);\n const trigger = document.state.global.trigger;\n if (!trigger) throw new Error(\"Workflow has no trigger\");\n if (trigger.connectionId) {\n await this.assertCanReadDocument(trigger.connectionId, ctx);\n }\n await packagePieces.ready();\n const binding = this.pieceBinding(workflowId, trigger);\n if (!binding) {\n throw new Error(`\"${trigger.blockType}\" is not a piece trigger`);\n }\n return this.supervisor().test(binding);\n }\n\n // One child per run, N runs at a time. Sized by the operator: each slot is a\n // node process, so this is the reactor's real connector concurrency.\n private workers(): PieceWorkerPool {\n // A queue depth of 0 waits without limit, which is what one shared worker\n // did — a cap turns a saturated pool into failures instead of latency.\n return (this.pieceWorkers ??= new PieceWorkerPool({\n size: Number(process.env.WORKFLOW_RUN_CONCURRENCY) || undefined,\n maxQueueDepth: Number(process.env.WORKFLOW_RUN_QUEUE_DEPTH) || undefined,\n }));\n }\n\n async fire(\n workflowId: string,\n triggerPayload?: unknown,\n triggerKind = \"manual\",\n resume?: {\n completedSteps: Map<string, { output?: unknown; port?: string | null }>;\n rerunOf: string;\n },\n ctx?: WorkflowCaller,\n // A run this workflow's trigger already journaled as PENDING. Adopted\n // rather than created, so the row a matched operation left behind is the\n // row the run finishes in.\n enqueuedRunId?: string,\n ): Promise<PersistedRunResult> {\n const store = await this.store();\n let state: WorkflowState;\n let definition: ReturnType<typeof toWorkflowDefinition>;\n try {\n // \"manual\" is the only kind a caller can ask for; every other one is\n // system-initiated and already authorized by whatever armed the trigger.\n if (triggerKind === \"manual\") {\n await this.assertCanReadDocument(workflowId, ctx);\n }\n const document =\n await this.host.reactorClient.get<WorkflowDocument>(workflowId);\n if (document.header.documentType !== \"powerhouse/workflow\") {\n throw new Error(\n `Document \"${workflowId}\" is not a powerhouse/workflow`,\n );\n }\n state = document.state.global;\n if (state.status !== \"ENABLED\") {\n throw new Error(\n `Workflow is ${state.status}; only ENABLED workflows can fire`,\n );\n }\n definition = toWorkflowDefinition(state);\n } catch (error) {\n // An adopted row is already durable: closing it out here is what keeps\n // a refused fire from leaving a PENDING run nothing will ever start.\n if (enqueuedRunId) {\n await store?.failRun(\n enqueuedRunId,\n error instanceof Error ? error.message : String(error),\n );\n }\n throw error;\n }\n // Bound once, to the connections this definition names: an edit landing\n // mid-run cannot widen what the run may resolve.\n const connections = declaredConnectionIds(definition);\n // Without a journal there is nowhere durable to keep ctx.store, so the\n // executor falls back to the worker's heap.\n this.executor ??= createBlockExecutor(\n this.host,\n this.secretProvider(),\n this.attachments,\n store ? createPieceStorePort(store, currentWorkflowId) : undefined,\n );\n\n let runId: string | null = enqueuedRunId ?? null;\n if (enqueuedRunId) {\n await store?.beginRun(enqueuedRunId, {\n workflowName: state.name,\n workflowVersion: state.version,\n });\n } else {\n runId =\n (await store?.startRun({\n workflowId,\n workflowName: state.name,\n workflowVersion: state.version,\n triggerKind,\n triggerPayload,\n rerunOf: resume?.rerunOf,\n })) ?? null;\n }\n let journalFailed = false;\n // Recorded whether or not the write lands: it is what lets finishRun put a\n // lost row back where the step ran.\n const executionOrder = new Map<string, number>();\n // This run's child, forked at its first piece step and killed below. Free\n // until then, so a run of document blocks never takes a slot.\n let session: PieceWorkerSession | undefined;\n try {\n // Inside the try: a pool disposed while this run was starting up refuses\n // here, and the journal records the run as failed rather than leaving it\n // to be swept up as an orphan.\n session = this.workers().session();\n const result = await withRunScope(\n { workflowId, runId, connections, pieceWorker: session },\n () =>\n runWorkflow({\n definition,\n executor: this.executor!,\n triggerPayload,\n completedSteps: resume?.completedSteps,\n // Journal each step as it lands, so a reactor that dies mid-run\n // still leaves a rerunnable record of the work it finished.\n onStep:\n store && runId\n ? async (record, ordinal) => {\n executionOrder.set(record.stepId, ordinal);\n try {\n await store.recordStep(runId, ordinal, record);\n } catch (error) {\n // Swallowed on purpose, but logged once per run: a dead\n // journal must not look exactly like a healthy one.\n if (journalFailed) return;\n journalFailed = true;\n this.logger.warn(\n `Run ${runId}: journaling step \"${record.key}\" failed; the run continues without per-step durability`,\n error,\n );\n }\n }\n : undefined,\n }),\n );\n if (store && runId) {\n try {\n await store.finishRun(runId, result, executionOrder);\n } catch (error) {\n // The run is over and its result is the caller's; a journal that\n // cannot say so must not turn a finished run into a failed one.\n this.logger.warn(\n `Run ${runId}: closing the run journal out failed; the run's outcome stands`,\n error,\n );\n }\n }\n return { ...result, runId };\n } catch (error) {\n if (store && runId) {\n await store.failRun(\n runId,\n error instanceof Error ? error.message : String(error),\n );\n }\n throw error;\n } finally {\n // The run owns the child, however it ended: closing kills it and hands\n // the slot to whichever run is waiting.\n session?.close();\n }\n }\n\n // Resume a FAILED run: journaled step outputs replay, execution restarts\n // at the first step that didn't succeed. Runs the current definition.\n async rerun(\n runId: string,\n ctx?: WorkflowCaller,\n ): Promise<PersistedRunResult> {\n const store = await this.store();\n if (!store) throw new Error(\"Run journal is unavailable\");\n const run = await store.getRun(runId);\n if (!run) throw new Error(`Run \"${runId}\" not found`);\n // A replay is the workflow's own side effects again, so it is the\n // workflow — not the run id — that the caller has to be allowed to touch.\n await this.assertCanReadDocument(run.workflow_id, ctx);\n if (run.status !== \"FAILED\") {\n throw new Error(`Only FAILED runs can be rerun; run is ${run.status}`);\n }\n const triggerPayload =\n run.trigger_payload === null\n ? undefined\n : (JSON.parse(run.trigger_payload) as unknown);\n // The journal holds a redacted copy of the payload, so replaying it would\n // hand a marker to whatever the trigger fed. Refuse before anything runs.\n if (containsRedactedMarker(triggerPayload)) {\n throw new Error(\n `Trigger payload of run \"${runId}\" was redacted and cannot be ` +\n \"replayed; fire the workflow again instead of rerunning it\",\n );\n }\n const document = await this.host.reactorClient.get<WorkflowDocument>(\n run.workflow_id,\n );\n const currentSteps = new Map(\n document.state.global.steps.map((step) => [step.id, step]),\n );\n // Reuse an output only while the step is still the same step: outputs\n // from renamed/retyped steps would poison downstream expressions.\n const completedSteps = new Map<\n string,\n { output?: unknown; port?: string | null }\n >();\n for (const row of await store.getSteps(runId)) {\n if (row.status !== \"SUCCEEDED\" && row.status !== \"REPLAYED\") continue;\n const current = currentSteps.get(row.step_id);\n if (\n !current ||\n current.blockType !== row.block_type ||\n current.key !== row.step_key\n ) {\n continue;\n }\n completedSteps.set(row.step_id, {\n output:\n row.output === null ? undefined : (JSON.parse(row.output) as unknown),\n port: row.port,\n });\n }\n return this.fire(run.workflow_id, triggerPayload, \"rerun\", {\n completedSteps,\n rerunOf: runId,\n });\n }\n}\n\n/** The runtime a host composes: one instance, its lifetime the host's. */\nexport function createWorkflowRuntime(\n deps: WorkflowRuntimeHostDeps,\n): WorkflowRuntimeService {\n return new WorkflowRuntimeService(deps);\n}\n","// The runtime's operation intake, as a reactor read model: the cursor beneath\n// it makes an event written while the runtime was down catch up, not vanish.\nimport {\n BaseReadModel,\n defaultReadModelIndexingConfig,\n type DocumentViewDatabase,\n type IConsistencyTracker,\n type IOperationIndex,\n type IWriteCache,\n type ReadModelRegistrationStage,\n} from \"@powerhousedao/reactor\";\nimport type { OperationWithContext } from \"document-model\";\nimport type { Kysely, Transaction } from \"kysely\";\nimport type { WorkflowRuntimeService } from \"./service.js\";\n\nexport const WORKFLOW_TRIGGERS_READ_MODEL = \"workflow-triggers\";\n\n// Post-ready, so a piece that reads the document that fired it sees the state\n// that fired it. The host registers with this; the engine decides it.\nexport const WORKFLOW_TRIGGERS_READ_MODEL_STAGE: ReadModelRegistrationStage =\n \"post_ready\";\n\n// Hands every batch to onOperations and keeps the reactor's ViewState cursor.\n// Triggers fire forward only, so a first registration starts at head, not zero.\nexport class WorkflowTriggersReadModel extends BaseReadModel {\n // Set by init() when no cursor row exists, cleared by the first batch that\n // writes one: nothing else tells a fresh registration from a restart.\n private freshRegistration = false;\n\n constructor(\n db: Kysely<DocumentViewDatabase>,\n operationIndex: IOperationIndex,\n writeCache: IWriteCache,\n consistencyTracker: IConsistencyTracker,\n private readonly runtime: WorkflowRuntimeService,\n ) {\n super(db, operationIndex, writeCache, consistencyTracker, {\n readModelId: WORKFLOW_TRIGGERS_READ_MODEL,\n rebuildStateOnInit: false,\n indexing: defaultReadModelIndexingConfig,\n });\n }\n\n // No row means no backlog a trigger could want, so base init()'s ordinal-zero\n // row and full replay are precisely what a first registration must skip.\n override async init(): Promise<void> {\n if ((await this.loadState()) === undefined) {\n this.freshRegistration = true;\n return;\n }\n this.freshRegistration = false;\n await super.init();\n }\n\n // The fresh mark lifts only once a batch is through: a pass that threw rolled\n // back the insert below, and the batch after it has to write the row again.\n override async indexOperations(items: OperationWithContext[]): Promise<void> {\n if (items.length === 0) return;\n await super.indexOperations(items);\n this.freshRegistration = false;\n }\n\n // The only await that matters here: onOperations journals every matched fire\n // before it resolves, so the cursor saved after it never passes a lost event.\n protected override async commitOperations(\n items: OperationWithContext[],\n ): Promise<void> {\n await this.runtime.onOperations(items);\n }\n\n // super.saveState only UPDATEs, so the row init() skipped appears here, in the\n // transaction that first advances the cursor. Conflict-safe: a second process.\n protected override async saveState(\n trx: Transaction<DocumentViewDatabase>,\n items: OperationWithContext[],\n ): Promise<void> {\n if (this.freshRegistration) {\n await trx\n .insertInto(\"ViewState\")\n .values({ readModelId: this.config.readModelId, lastOrdinal: 0 })\n .onConflict((oc) => oc.column(\"readModelId\").doNothing())\n .execute();\n }\n await super.saveState(trx, items);\n }\n}\n"],"mappings":"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"}