@objectstack/plugin-approvals 16.0.0-rc.0 → 16.0.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +10 -10
- package/CHANGELOG.md +63 -0
- package/dist/index.d.mts +36 -14
- package/dist/index.d.ts +36 -14
- package/dist/index.js +51 -21
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +51 -21
- package/dist/index.mjs.map +1 -1
- package/package.json +7 -7
- package/src/approval-service.test.ts +27 -0
- package/src/approval-service.ts +22 -0
- package/src/sys-approval-approver.object.ts +1 -1
- package/src/sys-approval-request.object.test.ts +14 -5
- package/src/sys-approval-request.object.ts +26 -17
- package/src/sys-approval-token.object.ts +1 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/translations/en.objects.generated.ts","../src/translations/zh-CN.objects.generated.ts","../src/translations/ja-JP.objects.generated.ts","../src/translations/es-ES.objects.generated.ts","../src/translations/index.ts","../src/index.ts","../src/sys-approval-request.object.ts","../src/sys-approval-action.object.ts","../src/sys-approval-approver.object.ts","../src/sys-approval-delegation.object.ts","../src/approval-service.ts","../src/sys-approval-token.object.ts","../src/action-link-pages.ts","../src/lifecycle-hooks.ts","../src/approval-node.ts","../src/approvals-plugin.ts"],"sourcesContent":["// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * Auto-generated by 'os i18n extract' for locale 'en'.\n * Edit translations in place; re-run extract (with --merge) to fill new gaps.\n * Do not hand-edit the structure — only the leaf string values.\n */\n\nimport type { TranslationData } from '@objectstack/spec/system';\n\nexport const enObjects: NonNullable<TranslationData['objects']> = {\n sys_approval_request: {\n label: \"Approval Request\",\n pluralLabel: \"Approval Requests\",\n description: \"Live approval instance tracked per submission\",\n fields: {\n id: {\n label: \"Request ID\"\n },\n organization_id: {\n label: \"Organization\",\n help: \"Tenant that owns this approval request (propagated from submitter context)\"\n },\n process_name: {\n label: \"Source\",\n help: \"Origin of the request — `flow:<flowName|nodeId>` for node-driven approvals\"\n },\n object_name: {\n label: \"Object\"\n },\n record_id: {\n label: \"Record ID\"\n },\n submitter_id: {\n label: \"Submitter\"\n },\n submitter_comment: {\n label: \"Submitter Comment\"\n },\n status: {\n label: \"Status\",\n help: \"Lifecycle state of the request\",\n options: {\n pending: \"pending\",\n approved: \"approved\",\n rejected: \"rejected\",\n recalled: \"recalled\"\n }\n },\n current_step: {\n label: \"Current Step\",\n help: \"Machine name of the step awaiting approval\"\n },\n current_step_index: {\n label: \"Current Step Index\"\n },\n pending_approvers: {\n label: \"Pending Approvers\",\n help: \"Comma-separated user ids who can act on the current step\"\n },\n payload_json: {\n label: \"Snapshot\",\n help: \"Record snapshot at submission time\"\n },\n flow_run_id: {\n label: \"Flow Run\",\n help: \"Suspended automation run id this request gates (ADR-0019). The decision resumes it.\"\n },\n flow_node_id: {\n label: \"Flow Node\",\n help: \"Approval node id within the flow that opened this request (ADR-0019).\"\n },\n node_config_json: {\n label: \"Node Config\",\n help: \"Snapshot of the Approval node config (approvers/behavior) for node-driven requests (ADR-0019).\"\n },\n completed_at: {\n label: \"Completed At\"\n },\n created_at: {\n label: \"Created At\"\n },\n updated_at: {\n label: \"Updated At\"\n }\n },\n _views: {\n my_pending: {\n label: \"My Pending\"\n },\n submitted_by_me: {\n label: \"I Submitted\"\n },\n completed: {\n label: \"Completed\"\n },\n all_requests: {\n label: \"All\"\n }\n }\n },\n sys_approval_action: {\n label: \"Approval Action\",\n pluralLabel: \"Approval Actions\",\n description: \"Append-only audit trail for approval actions\",\n fields: {\n id: {\n label: \"Action ID\"\n },\n organization_id: {\n label: \"Organization\",\n help: \"Tenant that owns this action (mirrors the parent request)\"\n },\n request_id: {\n label: \"Request\"\n },\n step_name: {\n label: \"Step\",\n help: \"Machine name of the step at the time of the action\"\n },\n step_index: {\n label: \"Step Index\"\n },\n action: {\n label: \"Action\",\n options: {\n submit: \"submit\",\n approve: \"approve\",\n reject: \"reject\",\n recall: \"recall\",\n escalate: \"escalate\"\n }\n },\n actor_id: {\n label: \"Actor\"\n },\n comment: {\n label: \"Comment\"\n },\n created_at: {\n label: \"Created At\"\n }\n },\n _views: {\n recent: {\n label: \"Recent\"\n },\n by_actor: {\n label: \"By Actor\"\n },\n all_actions: {\n label: \"All\"\n }\n }\n },\n sys_approval_delegation: {\n label: \"Approval Delegation\",\n pluralLabel: \"Approval Delegations\",\n description: \"Self-service out-of-office rule: route this user's approver slots to a delegate within a time window (#1322 M1).\",\n fields: {\n id: {\n label: \"Delegation ID\"\n },\n delegator_id: {\n label: \"Delegator\",\n help: \"The user going out of office; their individually-routed approver slots are rerouted while active.\"\n },\n delegate_id: {\n label: \"Delegate\",\n help: \"The backup who receives the delegator's approvals while this rule is active. Acts under their own identity.\"\n },\n valid_from: {\n label: \"Valid From\",\n help: \"Rule is inactive before this instant. Null = active immediately. Enforced at resolution time via isGrantActive (ADR-0091 D2 predicate) — never by a background job.\"\n },\n valid_until: {\n label: \"Valid Until\",\n help: \"Rule is inactive AT and AFTER this instant (half-open [from, until), UTC). Null = never expires.\"\n },\n reason: {\n label: \"Reason\",\n help: \"Why the delegation exists (e.g. \\\"Annual leave 5/26\\u20135/30\\\"). Recorded on the substitution audit row.\"\n },\n organization_id: {\n label: \"Organization\",\n help: \"Tenant that owns this rule; null = applies across tenants for this delegator.\"\n },\n created_at: {\n label: \"Created At\"\n },\n updated_at: {\n label: \"Updated At\"\n }\n },\n _views: {\n active: {\n label: \"Active\",\n emptyState: {\n title: \"No delegations\",\n message: \"Declare an out-of-office delegation so approvals route to a backup while you are away.\"\n }\n }\n }\n }\n};\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * Auto-generated by 'os i18n extract' for locale 'zh-CN'.\n * Edit translations in place; re-run extract (with --merge) to fill new gaps.\n * Do not hand-edit the structure — only the leaf string values.\n */\n\nimport type { TranslationData } from '@objectstack/spec/system';\n\nexport const zhCNObjects: NonNullable<TranslationData['objects']> = {\n sys_approval_request: {\n label: \"审批请求\",\n pluralLabel: \"审批请求\",\n description: \"按提交记录跟踪的实时审批实例\",\n fields: {\n id: {\n label: \"请求 ID\"\n },\n organization_id: {\n label: \"组织\",\n help: \"拥有该审批请求的租户(从提交方上下文传播)\"\n },\n process_name: {\n label: \"来源\",\n help: \"请求来源 —— 节点驱动的审批为 `flow:<flowName|nodeId>`\"\n },\n object_name: {\n label: \"对象\"\n },\n record_id: {\n label: \"记录 ID\"\n },\n submitter_id: {\n label: \"提交人\"\n },\n submitter_comment: {\n label: \"提交备注\"\n },\n status: {\n label: \"状态\",\n help: \"请求的生命周期状态\",\n options: {\n pending: \"待处理\",\n approved: \"已批准\",\n rejected: \"已拒绝\",\n recalled: \"已撤回\"\n }\n },\n current_step: {\n label: \"当前步骤\",\n help: \"当前等待审批的步骤机器名称\"\n },\n current_step_index: {\n label: \"当前步骤索引\"\n },\n pending_approvers: {\n label: \"待审批人\",\n help: \"可在当前步骤执行操作的用户 ID,逗号分隔\"\n },\n payload_json: {\n label: \"快照\",\n help: \"提交时的记录快照\"\n },\n flow_run_id: {\n label: \"Flow Run\",\n help: \"Suspended automation run id this request gates (ADR-0019). The decision resumes it.\"\n },\n flow_node_id: {\n label: \"Flow Node\",\n help: \"Approval node id within the flow that opened this request (ADR-0019).\"\n },\n node_config_json: {\n label: \"Node Config\",\n help: \"Snapshot of the Approval node config (approvers/behavior) for node-driven requests (ADR-0019).\"\n },\n completed_at: {\n label: \"完成时间\"\n },\n created_at: {\n label: \"创建时间\"\n },\n updated_at: {\n label: \"更新时间\"\n }\n },\n _views: {\n my_pending: {\n label: \"我的待办\"\n },\n submitted_by_me: {\n label: \"我提交的\"\n },\n completed: {\n label: \"已完成\"\n },\n all_requests: {\n label: \"全部\"\n }\n }\n },\n sys_approval_action: {\n label: \"审批动作\",\n pluralLabel: \"审批动作\",\n description: \"追加写入的审批操作审计记录\",\n fields: {\n id: {\n label: \"动作 ID\"\n },\n organization_id: {\n label: \"组织\",\n help: \"拥有该动作的租户(与父请求保持一致)\"\n },\n request_id: {\n label: \"请求\"\n },\n step_name: {\n label: \"步骤\",\n help: \"执行该动作时对应步骤的机器名称\"\n },\n step_index: {\n label: \"步骤索引\"\n },\n action: {\n label: \"操作\",\n options: {\n submit: \"提交\",\n approve: \"批准\",\n reject: \"拒绝\",\n recall: \"撤回\",\n escalate: \"升级\"\n }\n },\n actor_id: {\n label: \"执行人\"\n },\n comment: {\n label: \"评论\"\n },\n created_at: {\n label: \"创建时间\"\n }\n },\n _views: {\n recent: {\n label: \"最近\"\n },\n by_actor: {\n label: \"按执行人\"\n },\n all_actions: {\n label: \"全部\"\n }\n }\n },\n sys_approval_delegation: {\n label: \"审批委派\",\n pluralLabel: \"审批委派\",\n description: \"自助不在岗规则:在时间窗内把该用户的审批人槽位改派给候补人(#1322 M1)。\",\n fields: {\n id: {\n label: \"委派 ID\"\n },\n delegator_id: {\n label: \"委派人\",\n help: \"即将不在岗的用户;规则生效期间,路由到其个人的审批人槽位将被改派。\"\n },\n delegate_id: {\n label: \"候补人\",\n help: \"规则生效期间接收委派人审批的候补人。以其本人身份行使。\"\n },\n valid_from: {\n label: \"生效时间\",\n help: \"此刻之前规则不生效。留空 = 立即生效。在解析时通过 isGrantActive 强制(ADR-0091 D2 判定式)——绝不依赖后台任务。\"\n },\n valid_until: {\n label: \"失效时间\",\n help: \"此刻(含)及之后规则不生效(半开区间 [from, until),UTC)。留空 = 永不过期。\"\n },\n reason: {\n label: \"原因\",\n help: \"委派存在的原因(例如“年假 5/26–5/30”)。会记入改派审计行。\"\n },\n organization_id: {\n label: \"组织\",\n help: \"拥有此规则的租户;留空 = 对该委派人跨租户生效。\"\n },\n created_at: {\n label: \"创建时间\"\n },\n updated_at: {\n label: \"更新时间\"\n }\n },\n _views: {\n active: {\n label: \"生效中\",\n emptyState: {\n title: \"暂无委派\",\n message: \"声明一条不在岗委派,休假期间审批自动改派给候补人。\"\n }\n }\n }\n }\n};\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * Auto-generated by 'os i18n extract' for locale 'ja-JP'.\n * Edit translations in place; re-run extract (with --merge) to fill new gaps.\n * Do not hand-edit the structure — only the leaf string values.\n */\n\nimport type { TranslationData } from '@objectstack/spec/system';\n\nexport const jaJPObjects: NonNullable<TranslationData['objects']> = {\n sys_approval_request: {\n label: \"承認リクエスト\",\n pluralLabel: \"承認リクエスト\",\n description: \"送信ごとに追跡されるライブ承認インスタンス\",\n fields: {\n id: {\n label: \"リクエスト ID\"\n },\n organization_id: {\n label: \"組織\",\n help: \"この承認リクエストを所有するテナント(送信者コンテキストから伝播)\"\n },\n process_name: {\n label: \"ソース\",\n help: \"リクエストの発生元 — ノード駆動の承認では `flow:<flowName|nodeId>`\"\n },\n object_name: {\n label: \"オブジェクト\"\n },\n record_id: {\n label: \"レコード ID\"\n },\n submitter_id: {\n label: \"送信者\"\n },\n submitter_comment: {\n label: \"送信者コメント\"\n },\n status: {\n label: \"ステータス\",\n help: \"リクエストのライフサイクル状態\",\n options: {\n pending: \"保留中\",\n approved: \"承認済み\",\n rejected: \"却下済み\",\n recalled: \"取り消し済み\"\n }\n },\n current_step: {\n label: \"現在のステップ\",\n help: \"承認待ちのステップの機械名\"\n },\n current_step_index: {\n label: \"現在のステップ番号\"\n },\n pending_approvers: {\n label: \"承認待ち承認者\",\n help: \"現在のステップを処理できるユーザー ID のカンマ区切りリスト\"\n },\n payload_json: {\n label: \"スナップショット\",\n help: \"送信時のレコードスナップショット\"\n },\n flow_run_id: {\n label: \"Flow Run\",\n help: \"Suspended automation run id this request gates (ADR-0019). The decision resumes it.\"\n },\n flow_node_id: {\n label: \"Flow Node\",\n help: \"Approval node id within the flow that opened this request (ADR-0019).\"\n },\n node_config_json: {\n label: \"Node Config\",\n help: \"Snapshot of the Approval node config (approvers/behavior) for node-driven requests (ADR-0019).\"\n },\n completed_at: {\n label: \"完了日時\"\n },\n created_at: {\n label: \"作成日時\"\n },\n updated_at: {\n label: \"更新日時\"\n }\n },\n _views: {\n my_pending: {\n label: \"自分の保留中\"\n },\n submitted_by_me: {\n label: \"自分が送信\"\n },\n completed: {\n label: \"完了済み\"\n },\n all_requests: {\n label: \"すべて\"\n }\n }\n },\n sys_approval_action: {\n label: \"承認アクション\",\n pluralLabel: \"承認アクション\",\n description: \"承認アクションの追記専用監査証跡\",\n fields: {\n id: {\n label: \"アクション ID\"\n },\n organization_id: {\n label: \"組織\",\n help: \"このアクションを所有するテナント(親リクエストと同じ)\"\n },\n request_id: {\n label: \"リクエスト\"\n },\n step_name: {\n label: \"ステップ\",\n help: \"アクション時点のステップの機械名\"\n },\n step_index: {\n label: \"ステップ番号\"\n },\n action: {\n label: \"アクション\",\n options: {\n submit: \"申請\",\n approve: \"承認\",\n reject: \"却下\",\n recall: \"取消\",\n escalate: \"エスカレーション\"\n }\n },\n actor_id: {\n label: \"操作者\"\n },\n comment: {\n label: \"コメント\"\n },\n created_at: {\n label: \"作成日時\"\n }\n },\n _views: {\n recent: {\n label: \"最近\"\n },\n by_actor: {\n label: \"操作者別\"\n },\n all_actions: {\n label: \"すべて\"\n }\n }\n },\n sys_approval_delegation: {\n label: \"Approval Delegation\",\n pluralLabel: \"Approval Delegations\",\n description: \"Self-service out-of-office rule: route this user's approver slots to a delegate within a time window (#1322 M1).\",\n fields: {\n id: {\n label: \"Delegation ID\"\n },\n delegator_id: {\n label: \"Delegator\",\n help: \"The user going out of office; their individually-routed approver slots are rerouted while active.\"\n },\n delegate_id: {\n label: \"Delegate\",\n help: \"The backup who receives the delegator's approvals while this rule is active. Acts under their own identity.\"\n },\n valid_from: {\n label: \"Valid From\",\n help: \"Rule is inactive before this instant. Null = active immediately. Enforced at resolution time via isGrantActive (ADR-0091 D2 predicate) — never by a background job.\"\n },\n valid_until: {\n label: \"Valid Until\",\n help: \"Rule is inactive AT and AFTER this instant (half-open [from, until), UTC). Null = never expires.\"\n },\n reason: {\n label: \"Reason\",\n help: \"Why the delegation exists (e.g. \\\"Annual leave 5/26\\u20135/30\\\"). Recorded on the substitution audit row.\"\n },\n organization_id: {\n label: \"Organization\",\n help: \"Tenant that owns this rule; null = applies across tenants for this delegator.\"\n },\n created_at: {\n label: \"Created At\"\n },\n updated_at: {\n label: \"Updated At\"\n }\n },\n _views: {\n active: {\n label: \"Active\",\n emptyState: {\n title: \"No delegations\",\n message: \"Declare an out-of-office delegation so approvals route to a backup while you are away.\"\n }\n }\n }\n }\n};\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * Auto-generated by 'os i18n extract' for locale 'es-ES'.\n * Edit translations in place; re-run extract (with --merge) to fill new gaps.\n * Do not hand-edit the structure — only the leaf string values.\n */\n\nimport type { TranslationData } from '@objectstack/spec/system';\n\nexport const esESObjects: NonNullable<TranslationData['objects']> = {\n sys_approval_request: {\n label: \"Solicitud de aprobación\",\n pluralLabel: \"Solicitudes de aprobación\",\n description: \"Instancia activa de aprobación registrada por envío\",\n fields: {\n id: {\n label: \"ID de solicitud\"\n },\n organization_id: {\n label: \"Organización\",\n help: \"Tenant que posee esta solicitud de aprobación (propagado desde el contexto del solicitante).\"\n },\n process_name: {\n label: \"Origen\",\n help: \"Origen de la solicitud — `flow:<flowName|nodeId>` para aprobaciones por nodo\"\n },\n object_name: {\n label: \"Objeto\"\n },\n record_id: {\n label: \"ID de registro\"\n },\n submitter_id: {\n label: \"Solicitante\"\n },\n submitter_comment: {\n label: \"Comentario del solicitante\"\n },\n status: {\n label: \"Estado\",\n help: \"Estado del ciclo de vida de la solicitud.\",\n options: {\n pending: \"Pendiente\",\n approved: \"Aprobada\",\n rejected: \"Rechazada\",\n recalled: \"Retirada\"\n }\n },\n current_step: {\n label: \"Paso actual\",\n help: \"Nombre técnico del paso pendiente de aprobación.\"\n },\n current_step_index: {\n label: \"Índice del paso actual\"\n },\n pending_approvers: {\n label: \"Aprobadores pendientes\",\n help: \"ID de usuario separados por comas que pueden actuar en el paso actual.\"\n },\n payload_json: {\n label: \"Instantánea\",\n help: \"Instantánea del registro en el momento del envío.\"\n },\n flow_run_id: {\n label: \"Flow Run\",\n help: \"Suspended automation run id this request gates (ADR-0019). The decision resumes it.\"\n },\n flow_node_id: {\n label: \"Flow Node\",\n help: \"Approval node id within the flow that opened this request (ADR-0019).\"\n },\n node_config_json: {\n label: \"Node Config\",\n help: \"Snapshot of the Approval node config (approvers/behavior) for node-driven requests (ADR-0019).\"\n },\n completed_at: {\n label: \"Completado el\"\n },\n created_at: {\n label: \"Creado el\"\n },\n updated_at: {\n label: \"Actualizado el\"\n }\n },\n _views: {\n my_pending: {\n label: \"Mis pendientes\"\n },\n submitted_by_me: {\n label: \"Enviadas por mí\"\n },\n completed: {\n label: \"Completadas\"\n },\n all_requests: {\n label: \"Todas\"\n }\n }\n },\n sys_approval_action: {\n label: \"Acción de aprobación\",\n pluralLabel: \"Acciones de aprobación\",\n description: \"Registro de auditoría append-only para acciones de aprobación\",\n fields: {\n id: {\n label: \"ID de acción\"\n },\n organization_id: {\n label: \"Organización\",\n help: \"Tenant que posee esta acción (refleja la solicitud principal).\"\n },\n request_id: {\n label: \"Solicitud\"\n },\n step_name: {\n label: \"Paso\",\n help: \"Nombre técnico del paso en el momento de la acción.\"\n },\n step_index: {\n label: \"Índice del paso\"\n },\n action: {\n label: \"Acción\",\n options: {\n submit: \"Enviar\",\n approve: \"Aprobar\",\n reject: \"Rechazar\",\n recall: \"Retirar\",\n escalate: \"Escalar\"\n }\n },\n actor_id: {\n label: \"Actor\"\n },\n comment: {\n label: \"Comentario\"\n },\n created_at: {\n label: \"Creado el\"\n }\n },\n _views: {\n recent: {\n label: \"Recientes\"\n },\n by_actor: {\n label: \"Por actor\"\n },\n all_actions: {\n label: \"Todas\"\n }\n }\n },\n sys_approval_delegation: {\n label: \"Approval Delegation\",\n pluralLabel: \"Approval Delegations\",\n description: \"Self-service out-of-office rule: route this user's approver slots to a delegate within a time window (#1322 M1).\",\n fields: {\n id: {\n label: \"Delegation ID\"\n },\n delegator_id: {\n label: \"Delegator\",\n help: \"The user going out of office; their individually-routed approver slots are rerouted while active.\"\n },\n delegate_id: {\n label: \"Delegate\",\n help: \"The backup who receives the delegator's approvals while this rule is active. Acts under their own identity.\"\n },\n valid_from: {\n label: \"Valid From\",\n help: \"Rule is inactive before this instant. Null = active immediately. Enforced at resolution time via isGrantActive (ADR-0091 D2 predicate) — never by a background job.\"\n },\n valid_until: {\n label: \"Valid Until\",\n help: \"Rule is inactive AT and AFTER this instant (half-open [from, until), UTC). Null = never expires.\"\n },\n reason: {\n label: \"Reason\",\n help: \"Why the delegation exists (e.g. \\\"Annual leave 5/26\\u20135/30\\\"). Recorded on the substitution audit row.\"\n },\n organization_id: {\n label: \"Organization\",\n help: \"Tenant that owns this rule; null = applies across tenants for this delegator.\"\n },\n created_at: {\n label: \"Created At\"\n },\n updated_at: {\n label: \"Updated At\"\n }\n },\n _views: {\n active: {\n label: \"Active\",\n emptyState: {\n title: \"No delegations\",\n message: \"Declare an out-of-office delegation so approvals route to a backup while you are away.\"\n }\n }\n }\n }\n};\n","// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * ApprovalsTranslations — i18n bundle owned by this plugin (ADR-0029 D8).\n *\n * Object label/field/view/action translations for the sys_* objects this\n * plugin owns. Loaded at runtime via the plugin's `kernel:ready` hook\n * (`i18n.loadTranslations`). Regenerate with `os i18n extract` against\n * `scripts/i18n-extract.config.ts`.\n */\n\nimport type { TranslationBundle } from '@objectstack/spec/system';\nimport { enObjects } from './en.objects.generated.js';\nimport { zhCNObjects } from './zh-CN.objects.generated.js';\nimport { jaJPObjects } from './ja-JP.objects.generated.js';\nimport { esESObjects } from './es-ES.objects.generated.js';\n\nexport const ApprovalsTranslations: TranslationBundle = {\n en: { objects: enObjects },\n 'zh-CN': { objects: zhCNObjects },\n 'ja-JP': { objects: jaJPObjects },\n 'es-ES': { objects: esESObjects },\n};\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * @objectstack/plugin-approvals\n *\n * Approval-as-flow-node runtime (ADR-0019). Persists sys_approval_request /\n * sys_approval_action, resolves approvers, enforces the record lock, and\n * records decisions that resume the owning flow run. Approval orchestration\n * (when to pause, which branch to take) lives on the one automation engine via\n * the `approval` node.\n */\n\nexport { SysApprovalRequest } from './sys-approval-request.object.js';\nexport { SysApprovalAction } from './sys-approval-action.object.js';\nexport { SysApprovalApprover } from './sys-approval-approver.object.js';\nexport { SysApprovalDelegation } from './sys-approval-delegation.object.js';\nexport {\n ApprovalService,\n type ApprovalEngine,\n type ApprovalClock,\n type ApprovalServiceOptions,\n type ApprovalResumeSurface,\n} from './approval-service.js';\nexport {\n ApprovalsServicePlugin,\n type ApprovalsPluginOptions,\n} from './approvals-plugin.js';\nexport {\n registerApprovalNode,\n type ApprovalAutomationSurface,\n} from './approval-node.js';\nexport type {\n IApprovalService,\n ApprovalRequestRow,\n ApprovalActionRow,\n ApprovalDecisionInput,\n ApprovalDecisionResult,\n ApprovalStatus,\n} from '@objectstack/spec/contracts';\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { ObjectSchema, Field } from '@objectstack/spec/data';\n\n/**\n * sys_approval_request — Live approval instance.\n *\n * ADR-0019: opened by a flow's **Approval node** when the run reaches it; the\n * run suspends until a decision is recorded. The row's lifecycle:\n *\n * `pending` → (per-approver decisions) → `approved` | `rejected`\n * `pending` → recalled by submitter → `recalled`\n *\n * `flow_run_id` / `flow_node_id` tie the request back to the suspended run so a\n * decision can resume it; `current_step` mirrors the node id. `node_config_json`\n * snapshots the Approval node config (approvers / behaviour) the request was\n * opened with.\n *\n * `payload_json` captures a snapshot of the target record at submission\n * time — used by notifications so they can render before the record is\n * locked or changed.\n *\n * @namespace sys\n */\nexport const SysApprovalRequest = ObjectSchema.create({\n name: 'sys_approval_request',\n label: 'Approval Request',\n pluralLabel: 'Approval Requests',\n icon: 'inbox',\n isSystem: true,\n managedBy: 'system',\n description: 'Live approval instance tracked per submission',\n displayNameField: 'id',\n nameField: 'id', // [ADR-0079] canonical primary-title pointer (mirrors deprecated displayNameField)\n titleFormat: '{process_name} · {record_id}',\n highlightFields: ['process_name', 'object_name', 'record_id', 'status', 'current_step', 'submitter_id', 'updated_at'],\n\n // Curated built-in list views — render as segmented tabs in the console.\n // Filters use {current_user_id} substitution wired by the console.\n listViews: {\n my_pending: {\n type: 'grid',\n name: 'my_pending',\n label: 'My Pending',\n data: { provider: 'object', object: 'sys_approval_request' },\n columns: ['process_name', 'object_name', 'record_id', 'current_step', 'submitter_id', 'updated_at'],\n filter: [\n { field: 'status', operator: 'equals', value: 'pending' },\n { field: 'pending_approvers', operator: 'contains', value: '{current_user_id}' },\n ],\n sort: [{ field: 'updated_at', order: 'desc' }],\n pagination: { pageSize: 25 },\n emptyState: { title: 'No pending approvals', message: 'You\\'re all caught up.' },\n },\n submitted_by_me: {\n type: 'grid',\n name: 'submitted_by_me',\n label: 'I Submitted',\n data: { provider: 'object', object: 'sys_approval_request' },\n columns: ['process_name', 'object_name', 'record_id', 'status', 'current_step', 'updated_at'],\n filter: [{ field: 'submitter_id', operator: 'equals', value: '{current_user_id}' }],\n sort: [{ field: 'updated_at', order: 'desc' }],\n pagination: { pageSize: 25 },\n },\n completed: {\n type: 'grid',\n name: 'completed',\n label: 'Completed',\n data: { provider: 'object', object: 'sys_approval_request' },\n columns: ['process_name', 'object_name', 'record_id', 'status', 'submitter_id', 'completed_at'],\n filter: [{ field: 'status', operator: 'in', value: ['approved', 'rejected', 'recalled'] }],\n sort: [{ field: 'completed_at', order: 'desc' }],\n pagination: { pageSize: 25 },\n },\n all_requests: {\n type: 'grid',\n name: 'all_requests',\n label: 'All',\n data: { provider: 'object', object: 'sys_approval_request' },\n columns: ['process_name', 'object_name', 'record_id', 'status', 'current_step', 'submitter_id', 'updated_at'],\n sort: [{ field: 'updated_at', order: 'desc' }],\n pagination: { pageSize: 50 },\n },\n },\n\n fields: {\n id: Field.text({ label: 'Request ID', required: true, readonly: true, group: 'System' }),\n\n organization_id: Field.lookup('sys_organization', {\n label: 'Organization',\n required: false,\n group: 'System',\n description: 'Tenant that owns this approval request (propagated from submitter context)',\n }),\n\n process_name: Field.text({\n label: 'Source',\n required: true,\n maxLength: 100,\n description: 'Origin of the request — `flow:<flowName|nodeId>` for node-driven approvals',\n group: 'Target',\n }),\n\n object_name: Field.text({\n label: 'Object',\n required: true,\n maxLength: 100,\n group: 'Target',\n }),\n\n record_id: Field.text({\n label: 'Record ID',\n required: true,\n maxLength: 100,\n group: 'Target',\n }),\n\n submitter_id: Field.lookup('sys_user', {\n label: 'Submitter',\n required: false,\n group: 'Target',\n }),\n\n submitter_comment: Field.textarea({\n label: 'Submitter Comment',\n required: false,\n group: 'Target',\n }),\n\n status: Field.select(\n // Keep in sync with `ApprovalStatus` (spec/contracts). `returned` =\n // sent back for revision (ADR-0044) — terminal for this round.\n ['pending', 'approved', 'rejected', 'recalled', 'returned'],\n {\n label: 'Status',\n required: true,\n defaultValue: 'pending',\n description: 'Lifecycle state of the request',\n group: 'State',\n },\n ),\n\n current_step: Field.text({\n label: 'Current Step',\n required: false,\n maxLength: 100,\n description: 'Machine name of the step awaiting approval',\n group: 'State',\n }),\n\n current_step_index: Field.number({\n label: 'Current Step Index',\n required: false,\n defaultValue: 0,\n group: 'State',\n }),\n\n pending_approvers: Field.textarea({\n label: 'Pending Approvers',\n required: false,\n description: 'Comma-separated user ids who can act on the current step',\n group: 'State',\n }),\n\n payload_json: Field.textarea({\n label: 'Snapshot',\n required: false,\n description: 'Record snapshot at submission time',\n group: 'State',\n }),\n\n // ── ADR-0019: approval-as-flow-node correlation ──────────────────\n // When a request is opened by an Approval *node* (rather than a standalone\n // process), these tie it back to the suspended flow run so a decision can\n // resume it. Null for legacy process-driven requests.\n flow_run_id: Field.text({\n label: 'Flow Run',\n required: false,\n maxLength: 100,\n readonly: true,\n description: 'Suspended automation run id this request gates (ADR-0019). The decision resumes it.',\n group: 'State',\n }),\n\n flow_node_id: Field.text({\n label: 'Flow Node',\n required: false,\n maxLength: 100,\n readonly: true,\n description: 'Approval node id within the flow that opened this request (ADR-0019).',\n group: 'State',\n }),\n\n node_config_json: Field.textarea({\n label: 'Node Config',\n required: false,\n readonly: true,\n description: 'Snapshot of the Approval node config (approvers/behavior) for node-driven requests (ADR-0019).',\n group: 'State',\n }),\n\n completed_at: Field.datetime({\n label: 'Completed At',\n required: false,\n group: 'State',\n }),\n\n created_at: Field.datetime({\n label: 'Created At',\n required: true,\n defaultValue: 'NOW()',\n readonly: true,\n group: 'System',\n }),\n\n updated_at: Field.datetime({ label: 'Updated At', required: false, group: 'System' }),\n },\n\n indexes: [\n // Look up \"is there a pending request for this record?\" — common\n // guard on submit and on edit-while-locked checks.\n { fields: ['object_name', 'record_id'] },\n { fields: ['status', 'object_name'] },\n // Status-windowed listings (escalation sweep, \"All\" tab ordering).\n // \"My approvals\" matching no longer scans this table: the service keeps\n // a normalized per-approver index in `sys_approval_approver` (#1745) and\n // resolves approver filters there; `pending_approvers` stays the\n // human-readable CSV source of truth only.\n { fields: ['status', 'updated_at'] },\n { fields: ['submitter_id', 'status'] },\n ],\n\n // Server-declared decision actions (objectui#2678 P2-4). The console's\n // generic action runtime renders and executes these wherever this object is\n // surfaced — the approvals inbox included — so new decision capabilities\n // (and their params) ship as metadata, not as hand-written buttons. Each\n // targets the existing approvals REST route; `{id}` resolves from the row\n // and `actorId` defaults to the caller server-side. The service remains the\n // authority on who may act (pending-approver check) — `visible` only trims\n // the obvious non-pending case.\n actions: [\n {\n name: 'approval_approve',\n label: 'Approve',\n icon: 'check-circle',\n type: 'api',\n method: 'POST',\n target: '/api/v1/approvals/requests/{id}/approve',\n params: [\n { name: 'comment', label: 'Comment', type: 'textarea', required: false },\n ],\n visible: 'record.status == \"pending\"',\n locations: ['record_section', 'list_item'],\n successMessage: 'Approved.',\n refreshAfter: true,\n },\n {\n name: 'approval_reject',\n label: 'Reject',\n icon: 'x-circle',\n type: 'api',\n method: 'POST',\n target: '/api/v1/approvals/requests/{id}/reject',\n params: [\n { name: 'comment', label: 'Comment', type: 'textarea', required: false },\n ],\n visible: 'record.status == \"pending\"',\n confirmText: 'Reject this request? A rejection is final for every approver.',\n locations: ['record_section', 'list_item'],\n successMessage: 'Rejected.',\n refreshAfter: true,\n },\n {\n name: 'approval_reassign',\n label: 'Reassign',\n icon: 'arrow-right-left',\n type: 'api',\n method: 'POST',\n target: '/api/v1/approvals/requests/{id}/reassign',\n params: [\n // Field-backed on `submitter_id` (the object's only `sys_user` lookup):\n // the console resolves its lookup config (`reference_to: sys_user`) so the\n // dialog renders a real user picker, while `name: 'to'` overrides the\n // request-body key to the `to` the reassign route expects. This is a\n // config-borrow, not a submitter pre-fill (`defaultFromRow` stays off).\n { field: 'submitter_id', name: 'to', label: 'New approver', required: true, helpText: 'User to hand this step to' },\n { name: 'comment', label: 'Comment', type: 'textarea', required: false },\n ],\n visible: 'record.status == \"pending\"',\n locations: ['record_section'],\n successMessage: 'Reassigned.',\n refreshAfter: true,\n },\n\n // ── Approver secondary decisions ────────────────────────────────\n // Send back for revision / request more info (ADR-0044). Both are approver\n // actions on a pending request; the service is the authority on who may act,\n // so `visible` only trims the non-pending case (matching approve/reject).\n {\n name: 'approval_send_back',\n label: 'Send back',\n icon: 'corner-up-left',\n type: 'api',\n method: 'POST',\n target: '/api/v1/approvals/requests/{id}/revise',\n params: [\n { name: 'comment', label: 'Reason', type: 'textarea', required: false },\n ],\n visible: 'record.status == \"pending\"',\n locations: ['record_section'],\n successMessage: 'Sent back for revision.',\n refreshAfter: true,\n },\n {\n name: 'approval_request_info',\n label: 'Request info',\n icon: 'help-circle',\n type: 'api',\n method: 'POST',\n target: '/api/v1/approvals/requests/{id}/request-info',\n params: [\n { name: 'comment', label: 'What do you need?', type: 'textarea', required: true },\n ],\n visible: 'record.status == \"pending\"',\n locations: ['record_section'],\n successMessage: 'Information requested.',\n refreshAfter: true,\n },\n\n // ── Submitter continuity actions ────────────────────────────────\n // Remind / recall (pending) and resubmit / recall (returned). These are the\n // submitter's own levers, so `visible` gates on `submitter_id == ctx.user.id`\n // — the current user is exposed via the console's predicate scope. The\n // service re-checks ownership; the predicate keeps a non-submitter from ever\n // seeing a button they cannot use.\n {\n name: 'approval_remind',\n label: 'Send reminder',\n icon: 'bell-ring',\n type: 'api',\n method: 'POST',\n target: '/api/v1/approvals/requests/{id}/remind',\n params: [\n { name: 'comment', label: 'Note', type: 'textarea', required: false },\n ],\n visible: 'record.status == \"pending\" && record.submitter_id == ctx.user.id',\n locations: ['record_section'],\n successMessage: 'Reminder sent.',\n refreshAfter: true,\n },\n {\n name: 'approval_recall',\n label: 'Recall',\n icon: 'undo-2',\n type: 'api',\n method: 'POST',\n target: '/api/v1/approvals/requests/{id}/recall',\n params: [\n { name: 'comment', label: 'Comment', type: 'textarea', required: false },\n ],\n // Recall applies while the request is live for the submitter — pending\n // (withdraw) or returned (abandon the revision instead of resubmitting).\n visible: '(record.status == \"pending\" || record.status == \"returned\") && record.submitter_id == ctx.user.id',\n confirmText: 'Recall this request? Approvers can no longer act on it and the record is unlocked.',\n locations: ['record_section'],\n successMessage: 'Recalled.',\n refreshAfter: true,\n },\n {\n name: 'approval_resubmit',\n label: 'Resubmit',\n icon: 'refresh-cw',\n type: 'api',\n method: 'POST',\n target: '/api/v1/approvals/requests/{id}/resubmit',\n params: [\n { name: 'comment', label: 'What changed?', type: 'textarea', required: false },\n ],\n visible: 'record.status == \"returned\" && record.submitter_id == ctx.user.id',\n locations: ['record_section'],\n successMessage: 'Resubmitted.',\n refreshAfter: true,\n },\n ],\n\n enable: {\n // [ADR-0103] Engine-owned: the approval engine owns the request lifecycle\n // (SYSTEM_CTX); users act via domain actions (Submit/Approve/Recall), never\n // generic CRUD. Reads stay open.\n apiMethods: ['get', 'list'],\n },\n});\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { ObjectSchema, Field } from '@objectstack/spec/data';\n\n/**\n * sys_approval_action — Audit trail row per approval action.\n *\n * Append-only: every `submit`, `approve`, `reject`, `recall`, or\n * `escalate` event lands here. The engine reads back per-step approval\n * rows to evaluate `behavior: 'unanimous'` (all approvers must approve\n * before advancing) versus `first_response` (any single approval\n * advances the step).\n *\n * @namespace sys\n */\nexport const SysApprovalAction = ObjectSchema.create({\n name: 'sys_approval_action',\n label: 'Approval Action',\n pluralLabel: 'Approval Actions',\n icon: 'check-circle',\n isSystem: true,\n managedBy: 'append-only',\n description: 'Append-only audit trail for approval actions',\n displayNameField: 'id',\n nameField: 'id', // [ADR-0079] canonical primary-title pointer (mirrors deprecated displayNameField)\n titleFormat: '{action} · {step_name}',\n highlightFields: ['request_id', 'step_name', 'action', 'actor_id', 'created_at'],\n\n listViews: {\n recent: {\n type: 'grid',\n name: 'recent',\n label: 'Recent',\n data: { provider: 'object', object: 'sys_approval_action' },\n columns: ['created_at', 'request_id', 'step_name', 'action', 'actor_id', 'comment'],\n sort: [{ field: 'created_at', order: 'desc' }],\n pagination: { pageSize: 50 },\n emptyState: { title: 'No approval actions yet', message: 'Actions are logged automatically when approvals progress.' },\n },\n by_actor: {\n type: 'grid',\n name: 'by_actor',\n label: 'By Actor',\n data: { provider: 'object', object: 'sys_approval_action' },\n columns: ['actor_id', 'created_at', 'request_id', 'step_name', 'action'],\n sort: [{ field: 'actor_id', order: 'asc' }, { field: 'created_at', order: 'desc' }],\n grouping: { fields: [{ field: 'actor_id', order: 'asc', collapsed: false }] },\n pagination: { pageSize: 100 },\n },\n all_actions: {\n type: 'grid',\n name: 'all_actions',\n label: 'All',\n data: { provider: 'object', object: 'sys_approval_action' },\n columns: ['created_at', 'request_id', 'step_name', 'action', 'actor_id', 'comment'],\n sort: [{ field: 'created_at', order: 'desc' }],\n pagination: { pageSize: 100 },\n },\n },\n\n fields: {\n id: Field.text({ label: 'Action ID', required: true, readonly: true, group: 'System' }),\n\n organization_id: Field.lookup('sys_organization', {\n label: 'Organization',\n required: false,\n group: 'System',\n description: 'Tenant that owns this action (mirrors the parent request)',\n }),\n\n request_id: Field.lookup('sys_approval_request', {\n label: 'Request',\n required: true,\n group: 'Target',\n }),\n\n step_name: Field.text({\n label: 'Step',\n required: false,\n maxLength: 100,\n description: 'Machine name of the step at the time of the action',\n group: 'Target',\n }),\n\n step_index: Field.number({\n label: 'Step Index',\n required: false,\n group: 'Target',\n }),\n\n action: Field.select(\n // Keep in sync with `ApprovalActionKind` (spec/contracts). reassign /\n // remind / request_info / comment are thread interactions — they never\n // move the flow. revise / resubmit (ADR-0044) DO move it: send back for\n // revision and the later resubmission. ooo_substitute (#1322 M1) is a\n // system-recorded reroute of an out-of-office approver — no flow movement.\n ['submit', 'approve', 'reject', 'recall', 'escalate', 'reassign', 'remind', 'request_info', 'comment', 'revise', 'resubmit', 'ooo_substitute'],\n {\n label: 'Action',\n required: true,\n group: 'Action',\n },\n ),\n\n actor_id: Field.lookup('sys_user', {\n label: 'Actor',\n required: false,\n group: 'Action',\n }),\n\n comment: Field.textarea({ label: 'Comment', required: false, group: 'Action' }),\n\n attachments: Field.file({\n label: 'Attachments',\n required: false,\n multiple: true,\n group: 'Action',\n description: 'Files supporting this action — e.g. a signed contract or evidence (#3266).',\n }),\n\n created_at: Field.datetime({\n label: 'Created At',\n required: true,\n defaultValue: 'NOW()',\n readonly: true,\n group: 'System',\n }),\n },\n\n indexes: [\n { fields: ['request_id', 'created_at'] },\n { fields: ['request_id', 'step_index', 'action'] },\n ],\n\n enable: {\n // [ADR-0103] Engine-owned append-only decision log: appended by the approval\n // engine (SYSTEM_CTX). Reads stay open.\n apiMethods: ['get', 'list'],\n },\n});\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { ObjectSchema, Field } from '@objectstack/spec/data';\n\n/**\n * sys_approval_approver — Pending-approver index (issue #1745).\n *\n * One row per (request, approver identity) while the request is **pending**.\n * `sys_approval_request.pending_approvers` stays the human-readable source of\n * truth (a CSV column), but CSV substring matching can neither be indexed nor\n * pushed into an engine query — which made \"my pending\" a post-filter in\n * memory and broke pagination beyond the scan window.\n *\n * This table is that CSV, normalized: the service mirrors every change to\n * `pending_approvers` here (open / decide / recall / send-back / reassign /\n * escalate), and clears the rows when the request leaves `pending`. So the\n * table only ever holds the live work queue — its size tracks the number of\n * open approvals, not the append-only request history.\n *\n * `approver` holds one identity literal exactly as it appears in the CSV:\n * a user id, an email, or a `role:<name>` / `team:<name>` style literal.\n * Equality (or `$in`) on this column is the indexed replacement for the old\n * per-row substring match.\n *\n * @namespace sys\n */\nexport const SysApprovalApprover = ObjectSchema.create({\n name: 'sys_approval_approver',\n label: 'Approval Approver',\n pluralLabel: 'Approval Approvers',\n icon: 'users',\n isSystem: true,\n managedBy: 'system',\n description: 'Normalized pending-approver rows for indexed inbox queries',\n displayNameField: 'id',\n nameField: 'id', // [ADR-0079] canonical primary-title pointer (mirrors deprecated displayNameField)\n titleFormat: '{approver} · {request_id}',\n highlightFields: ['request_id', 'approver', 'created_at'],\n\n fields: {\n id: Field.text({ label: 'Row ID', required: true, readonly: true, group: 'System' }),\n\n organization_id: Field.lookup('sys_organization', {\n label: 'Organization',\n required: false,\n group: 'System',\n description: 'Tenant that owns this row (mirrors the parent request)',\n }),\n\n request_id: Field.lookup('sys_approval_request', {\n label: 'Request',\n required: true,\n group: 'Target',\n }),\n\n approver: Field.text({\n label: 'Approver',\n required: true,\n maxLength: 255,\n description: 'One pending-approver identity: user id, email, or role:/team: literal',\n group: 'Target',\n }),\n\n created_at: Field.datetime({\n label: 'Created At',\n required: true,\n defaultValue: 'NOW()',\n readonly: true,\n group: 'System',\n }),\n },\n\n indexes: [\n // \"My pending\" inbox: equality on the identity literal, scoped by tenant.\n { fields: ['approver', 'organization_id'] },\n // Sync path: rewrite all rows of one request on each approver-set change.\n { fields: ['request_id'] },\n ],\n\n enable: {\n // [ADR-0103] Engine-owned: approver rows are rewritten by the approval\n // engine (SYSTEM_CTX) on each approver-set change, never via generic CRUD.\n apiMethods: ['get', 'list'],\n },\n});\n","// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { ObjectSchema, Field } from '@objectstack/spec/data';\n\n/**\n * sys_approval_delegation — self-service out-of-office (OOO) delegation (#1322 M1).\n *\n * A standing, self-declared rule: \"while I (the delegator) am out between\n * `valid_from` and `valid_until`, route the approver slots that would resolve\n * to me onto my delegate instead.\" The approval service consults active rows\n * in `ApprovalService.expandApprovers` when resolving an approval node's\n * INDIVIDUALLY-routed approvers (`type: user` / `field` / `manager`) — the\n * delegate becomes a real pending approver and acts under their own identity,\n * so nothing is impersonated and the audit trail stays honest.\n *\n * Modelled as its own object (not a scalar on the better-auth-locked\n * `sys_user`), mirroring the `sys_user_position` delegation precedent\n * (ADR-0091): the validity window is enforced at RESOLUTION time via the\n * shared `isGrantActive` predicate — never by a background job (ADR-0049).\n * The window is half-open `[valid_from, valid_until)` in UTC.\n *\n * Scope note: this is the community-core OOO auto-skip only. Long-term proxy\n * \"act-as\" access (viewing/acting on another user's full queue under their\n * authority), delegation governance / segregation-of-duties, and org-wide\n * administration of others' delegations are enterprise concerns tracked\n * separately (objectstack-ai/cloud#855), not here.\n *\n * @namespace sys\n */\nexport const SysApprovalDelegation = ObjectSchema.create({\n name: 'sys_approval_delegation',\n label: 'Approval Delegation',\n pluralLabel: 'Approval Delegations',\n icon: 'user-clock',\n isSystem: true,\n managedBy: 'system',\n // [ADR-0103] Admin/user-writable DATA on a platform-defined schema: a user\n // authors their own out-of-office delegation. Affordance only (matches the\n // full-CRUD apiMethods below) — RLS/permission sets are the authz; opening it\n // keeps the system write guard from rejecting the self-service write.\n userActions: { create: true, edit: true, delete: true },\n description:\n 'Self-service out-of-office rule: route this user\\'s approver slots to a delegate within a time window (#1322 M1).',\n titleFormat: '{delegator_id} → {delegate_id}',\n highlightFields: ['delegator_id', 'delegate_id', 'valid_from', 'valid_until'],\n\n listViews: {\n active: {\n type: 'grid',\n name: 'active',\n label: 'Active',\n data: { provider: 'object', object: 'sys_approval_delegation' },\n columns: ['delegator_id', 'delegate_id', 'valid_from', 'valid_until', 'reason'],\n sort: [{ field: 'valid_until', order: 'asc' }],\n pagination: { pageSize: 50 },\n emptyState: {\n title: 'No delegations',\n message: 'Declare an out-of-office delegation so approvals route to a backup while you are away.',\n },\n },\n },\n\n fields: {\n id: Field.text({ label: 'Delegation ID', required: true, readonly: true, group: 'System' }),\n\n delegator_id: Field.lookup('sys_user', {\n label: 'Delegator',\n required: true,\n group: 'Delegation',\n description: 'The user going out of office; their individually-routed approver slots are rerouted while active.',\n }),\n\n delegate_id: Field.lookup('sys_user', {\n label: 'Delegate',\n required: true,\n group: 'Delegation',\n description: 'The backup who receives the delegator\\'s approvals while this rule is active. Acts under their own identity.',\n }),\n\n valid_from: Field.datetime({\n label: 'Valid From',\n required: false,\n group: 'Delegation',\n description:\n 'Rule is inactive before this instant. Null = active immediately. ' +\n 'Enforced at resolution time via isGrantActive (ADR-0091 D2 predicate) — never by a background job.',\n }),\n\n valid_until: Field.datetime({\n label: 'Valid Until',\n required: false,\n group: 'Delegation',\n description:\n 'Rule is inactive AT and AFTER this instant (half-open [from, until), UTC). Null = never expires.',\n }),\n\n reason: Field.text({\n label: 'Reason',\n required: false,\n maxLength: 500,\n group: 'Delegation',\n description: 'Why the delegation exists (e.g. \"Annual leave 5/26–5/30\"). Recorded on the substitution audit row.',\n }),\n\n organization_id: Field.lookup('sys_organization', {\n label: 'Organization',\n required: false,\n group: 'System',\n description: 'Tenant that owns this rule; null = applies across tenants for this delegator.',\n }),\n\n created_at: Field.datetime({\n label: 'Created At',\n defaultValue: 'NOW()',\n readonly: true,\n group: 'System',\n }),\n\n updated_at: Field.datetime({\n label: 'Updated At',\n defaultValue: 'NOW()',\n readonly: true,\n group: 'System',\n }),\n },\n\n indexes: [\n // Resolution-time lookup: \"active delegations for this delegator\".\n { fields: ['delegator_id', 'organization_id'] },\n { fields: ['delegate_id'] },\n { fields: ['valid_until'] },\n ],\n\n enable: {\n trackHistory: true,\n searchable: true,\n apiEnabled: true,\n apiMethods: ['get', 'list', 'create', 'update', 'delete'],\n trash: true,\n mru: false,\n },\n});\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { createHash, randomBytes } from 'node:crypto';\nimport {\n APPROVAL_BRANCH_LABELS,\n canonicalApproverType,\n type ApprovalNodeConfig,\n} from '@objectstack/spec/automation';\nimport type {\n IApprovalService,\n ApprovalRequestRow,\n ApprovalActionRow,\n ApprovalDecisionInput,\n ApprovalDecisionResult,\n ApprovalRecallInput,\n ApprovalRecallResult,\n ApprovalSendBackInput,\n ApprovalSendBackResult,\n ApprovalResubmitInput,\n ApprovalResubmitResult,\n ApprovalStatus,\n SharingExecutionContext,\n} from '@objectstack/spec/contracts';\nimport { isGrantActive } from '@objectstack/core';\n\n/**\n * Node-era approval runtime (ADR-0019).\n *\n * Approval is no longer a standalone engine — it is a **flow node**. A flow's\n * Approval node opens a request via {@link ApprovalService.openNodeRequest} and\n * the run suspends; a human decision via {@link ApprovalService.decide}\n * finalises the request and resumes the owning run down the matching\n * `approve` / `reject` edge.\n *\n * This service owns the durable approval *state* — `sys_approval_request` /\n * `sys_approval_action`, approver resolution (team / department / position /\n * role / manager graph), and the optional status-field mirror — plus the decision\n * API. It does not author processes, submit, or walk multi-step machinery\n * anymore; that orchestration lives on the one automation engine.\n */\nexport interface ApprovalEngine {\n find(object: string, options?: any): Promise<any[]>;\n insert(object: string, data: any, options?: any): Promise<any>;\n update(object: string, idOrData: any, dataOrOptions?: any, options?: any): Promise<any>;\n delete(object: string, options?: any): Promise<any>;\n}\n\nexport interface ApprovalClock { now(): Date }\n\n/**\n * Minimal automation surface the service uses to resume a suspended flow run\n * once a decision finalises a node-driven request. Optional — attached by the\n * plugin when an automation engine is present (see `approval-node.ts`).\n */\nexport interface ApprovalResumeSurface {\n resume?(runId: string, signal?: { output?: Record<string, unknown>; branchLabel?: string }): Promise<unknown>;\n /** Flow definition lookup, used to derive step-progress display data. */\n getFlow?(name: string): Promise<any | null>;\n /**\n * Terminally cancel a suspended run (ADR-0044). Used when a recall lands\n * during a revision window — the run is paused at the revise wait node,\n * which has no reject edge to resume down.\n */\n cancelRun?(runId: string, reason?: string): Promise<unknown>;\n}\n\n/**\n * Optional messaging surface (ADR-0012 `messaging` service). When attached,\n * thread interactions (reassign / remind / request-info / comment) notify the\n * affected users; without it they degrade to audit-only.\n */\nexport interface ApprovalMessagingSurface {\n emit(input: {\n topic: string;\n audience: string[];\n payload?: Record<string, unknown>;\n severity?: string;\n dedupKey?: string;\n source?: { object: string; id: string };\n actorId?: string;\n }): Promise<unknown>;\n}\n\n/** Minimum time between submitter reminders on one request. */\nexport const REMIND_COOLDOWN_MS = 4 * 60 * 60 * 1000;\n\n/** Named job under which the SLA escalation scan is registered (ADR-0042). */\nexport const ESCALATION_JOB_NAME = 'approvals-sla-escalation';\n/** Default interval between SLA escalation scans. */\nexport const ESCALATION_SCAN_INTERVAL_MS = 5 * 60 * 1000;\n/** Reserved actor id for machine decisions made by the SLA scanner. */\nexport const SLA_ACTOR_ID = 'system:sla';\n\n/** Default lifetime of an actionable-link token (ADR-0043). */\nexport const ACTION_TOKEN_TTL_MS = 72 * 60 * 60 * 1000;\n\n/** Outcome of redeeming (or peeking) an actionable-link token. */\nexport type ActionTokenOutcome =\n | { ok: true; action: 'approve' | 'reject'; request: ApprovalRequestRow; approverId: string }\n | { ok: false; reason: 'invalid' | 'expired' | 'consumed' | 'not_pending' | 'not_approver'; request?: ApprovalRequestRow };\n\nconst SYSTEM_CTX = { isSystem: true, positions: [], permissions: [] } as const;\n\n/**\n * Max hops when following an OOO delegation chain (#1322 M1): A out → B, B out\n * → C, … Bounds the walk so a mis-configured chain can't loop or resolve\n * unboundedly; a cycle or self-reference also stops it early.\n */\nconst OOO_MAX_CHAIN = 8;\n\n/** One OOO delegation hop applied while resolving an approver (#1322 M1/M4). */\ninterface OooSubstitution {\n /** The approver who was skipped (out of office). */\n from: string;\n /** The delegate the slot was routed to. */\n to: string;\n /** The delegator's declared reason, if any. */\n reason: string | null;\n}\n\nfunction uid(prefix: string): string {\n const g: any = globalThis as any;\n if (g.crypto?.randomUUID) return `${prefix}_${g.crypto.randomUUID()}`;\n return `${prefix}_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`;\n}\n\nfunction parseJson<T = any>(raw: unknown, fallback: T): T {\n if (raw == null || raw === '') return fallback;\n if (typeof raw === 'string') {\n try { return JSON.parse(raw) as T; } catch { return fallback; }\n }\n return raw as T;\n}\n\nfunction csvSplit(raw: unknown): string[] {\n if (!raw) return [];\n if (Array.isArray(raw)) return raw.map(String).filter(Boolean);\n return String(raw).split(',').map(s => s.trim()).filter(Boolean);\n}\n\n/**\n * Humanize a machine name for display fallback: strips a `flow:` prefix and\n * title-cases underscore/dash segments (`flow:manager_review` → \"Manager\n * Review\"). Used only when no authored label was snapshotted on the row.\n */\nfunction prettifyMachineName(raw: string | null | undefined): string | undefined {\n if (!raw) return undefined;\n const base = String(raw).replace(/^flow:/, '').trim();\n if (!base) return undefined;\n return base\n .split(/[_\\-\\s]+/)\n .filter(Boolean)\n .map(w => w.charAt(0).toUpperCase() + w.slice(1))\n .join(' ');\n}\n\nfunction rowFromRequest(row: any): ApprovalRequestRow {\n // Authored display labels ride the node-config snapshot (`__flowLabel` /\n // `__nodeLabel`) so they survive without a schema migration; fall back to a\n // prettified machine name for rows written before labels were captured.\n const cfg = parseJson<any>(row.node_config_json, undefined);\n return {\n id: String(row.id),\n organization_id: row.organization_id ?? undefined,\n process_name: String(row.process_name ?? ''),\n object_name: String(row.object_name ?? ''),\n record_id: String(row.record_id ?? ''),\n submitter_id: row.submitter_id ?? undefined,\n submitter_comment: row.submitter_comment ?? undefined,\n status: (row.status as ApprovalStatus) ?? 'pending',\n current_step: row.current_step ?? undefined,\n current_step_index: row.current_step_index ?? undefined,\n pending_approvers: csvSplit(row.pending_approvers),\n payload: parseJson(row.payload_json, undefined),\n flow_run_id: row.flow_run_id ?? undefined,\n flow_node_id: row.flow_node_id ?? undefined,\n completed_at: row.completed_at ?? undefined,\n created_at: row.created_at ?? undefined,\n updated_at: row.updated_at ?? undefined,\n // The row is created at submission time; expose the stable inbox-facing name.\n submitted_at: row.created_at ?? undefined,\n process_label: cfg?.__flowLabel ?? prettifyMachineName(row.process_name),\n step_label: cfg?.__nodeLabel ?? prettifyMachineName(row.current_step),\n sla_due_at: slaDueAt(row.created_at, cfg),\n // ADR-0044 revision round (rides the config snapshot; absent ⇒ round 1).\n round: typeof cfg?.__round === 'number' ? cfg.__round : undefined,\n } as any;\n}\n\n/** `created_at + escalation.timeoutHours`, when the node declares an SLA. */\nfunction slaDueAt(createdAt: unknown, cfg: any): string | undefined {\n const hours = cfg?.escalation?.timeoutHours;\n if (typeof hours !== 'number' || hours <= 0 || !createdAt) return undefined;\n const t = Date.parse(String(createdAt));\n if (Number.isNaN(t)) return undefined;\n return new Date(t + hours * 3600_000).toISOString();\n}\n\nfunction rowFromAction(row: any): ApprovalActionRow {\n return {\n id: String(row.id),\n request_id: String(row.request_id),\n step_name: row.step_name ?? undefined,\n step_index: row.step_index ?? undefined,\n action: row.action,\n actor_id: row.actor_id ?? undefined,\n comment: row.comment ?? undefined,\n // Decision attachments (#3266). The column shipped in #3268 but this\n // contract mapping didn't — the raw engine row carried the fileIds while\n // every consumer of listActions saw none (caught by browser verification).\n attachments: Array.isArray(row.attachments) && row.attachments.length ? row.attachments.map(String) : undefined,\n created_at: row.created_at ?? undefined,\n };\n}\n\nexport interface ApprovalServiceOptions {\n engine: ApprovalEngine;\n clock?: ApprovalClock;\n logger?: { info?: (msg: any, ...rest: any[]) => void; warn?: (msg: any, ...rest: any[]) => void; error?: (msg: any, ...rest: any[]) => void; debug?: (msg: any, ...rest: any[]) => void };\n /**\n * Optional automation surface used to resume a suspended flow run when a\n * decision finalises a request. Usually attached after construction via\n * {@link ApprovalService.attachAutomation} once the automation engine is\n * available.\n */\n automation?: ApprovalResumeSurface;\n /** Optional messaging service for thread notifications. */\n messaging?: ApprovalMessagingSurface;\n /**\n * Absolute origin prefixed onto actionable links (ADR-0043), e.g.\n * `https://app.example.com`. Defaults to relative URLs, which work inside\n * the Console and IM webviews; outbound email needs the absolute form.\n */\n publicBaseUrl?: string;\n}\n\nexport class ApprovalService implements IApprovalService {\n private readonly engine: ApprovalEngine;\n private readonly clock: ApprovalClock;\n private readonly logger?: ApprovalServiceOptions['logger'];\n private automation?: ApprovalResumeSurface;\n private messaging?: ApprovalMessagingSurface;\n private publicBaseUrl: string;\n\n constructor(opts: ApprovalServiceOptions) {\n this.engine = opts.engine;\n this.clock = opts.clock ?? { now: () => new Date() };\n this.logger = opts.logger;\n this.automation = opts.automation;\n this.messaging = opts.messaging;\n this.publicBaseUrl = (opts.publicBaseUrl ?? '').replace(/\\/$/, '');\n }\n\n /** Attach (or replace) the automation surface used to resume flow runs. */\n attachAutomation(automation: ApprovalResumeSurface): void {\n this.automation = automation;\n }\n\n /** Attach (or replace) the messaging surface used for thread notifications. */\n attachMessaging(messaging: ApprovalMessagingSurface): void {\n this.messaging = messaging;\n }\n\n /** Best-effort notification fan-out — failures only log. */\n private async notify(input: {\n topic: string;\n audience: string[];\n payload?: Record<string, unknown>;\n dedupKey?: string;\n source?: { object: string; id: string };\n actorId?: string;\n }): Promise<number> {\n const audience = input.audience.filter(a => a && !a.includes(':'));\n if (!this.messaging || !audience.length) return 0;\n // Deep-link the inbox (#2678 P1.5): a notification about one request should\n // land on that request, not the bare inbox. Rewritten centrally so every\n // call site — and any future one — inherits it; the query param is read by\n // the console inbox to auto-open the drawer.\n let payload = input.payload;\n if (\n payload?.actionUrl === '/system/approvals'\n && input.source?.object === 'sys_approval_request'\n && input.source.id\n ) {\n payload = { ...payload, actionUrl: `/system/approvals?request=${encodeURIComponent(input.source.id)}` };\n }\n try {\n await this.messaging.emit({ severity: 'info', ...input, payload, audience });\n return audience.length;\n } catch (err: any) {\n this.logger?.warn?.('[approvals] notification failed', {\n topic: input.topic, error: err?.message ?? String(err),\n });\n return 0;\n }\n }\n\n /** Load a request row and assert it is still pending. */\n private async loadPendingRow(requestId: string): Promise<any> {\n if (!requestId) throw new Error('VALIDATION_FAILED: requestId is required');\n const rows = await this.engine.find('sys_approval_request', {\n where: { id: requestId }, limit: 1, context: SYSTEM_CTX,\n });\n const raw: any = Array.isArray(rows) ? rows[0] : null;\n if (!raw) throw new Error(`REQUEST_NOT_FOUND: ${requestId}`);\n if (raw.status !== 'pending') throw new Error(`INVALID_STATE: request is ${raw.status}`);\n return raw;\n }\n\n /**\n * Expand the approvers on an Approval node into user IDs by querying the\n * graph tables for `team:` / `department:` / `position:` /\n * `org_membership_level:` / `manager:` approver types. Falls back to a\n * prefixed literal (`type:value`) when graph lookups produce nothing — so\n * existing fixtures and flows that rely on substring matching keep working.\n *\n * **Graph semantics:**\n * - `team` → flat members of `sys_team` (better-auth; no BFS)\n * - `department` → recursive BFS of `sys_business_unit.parent_business_unit_id`\n * → members of every descendant via `sys_business_unit_member`\n * - `position` → holders via `sys_user_position` ∪ `sys_member.role`\n * transition source (ADR-0090 D3 / ADR-0057 D4)\n * - `org_membership_level`\n * → users with `sys_member.role = value` in tenant — the\n * better-auth MEMBERSHIP TIER (owner/admin/member), not a\n * position; author `position` for org positions\n * - `manager` → `sys_user.manager_id` of `record[value] ?? record.owner_id`\n * - `field` → literal user id stored in `record[value]`\n * - `user` → literal value\n *\n * `role` is accepted as the deprecated spelling of `org_membership_level`\n * (ADR-0090 D3) for one window: it resolves identically and logs a warning.\n *\n * **Out-of-office (#1322 M1):** individually-routed approvers — the ones that\n * resolve to a specific person (`user` / `field` / `manager`) — are passed\n * through {@link ApprovalService.applyOooDelegation}, which reroutes them onto\n * an active delegate when the resolved user has declared OOO. Group/graph\n * approvers (`team` / `department` / `position` / `org_membership_level`) are\n * left untouched: a group still has its other members, and position-routed\n * leave is already covered by ADR-0091 job delegation. Pass an `opts.now` /\n * `opts.substitutions` collector to record the hops for audit + notification.\n */\n private async expandApprovers(\n step: any,\n record?: any,\n organizationId?: string | null,\n opts?: { now?: number; substitutions?: OooSubstitution[]; groups?: Record<string, string[]> },\n ): Promise<string[]> {\n if (!step || !Array.isArray(step.approvers)) return [];\n const now = opts?.now ?? this.clock.now().getTime();\n const out: string[] = [];\n const specs: any[] = step.approvers;\n for (let idx = 0; idx < specs.length; idx++) {\n const a = specs[idx];\n if (!a) continue;\n const ids = await this.resolveApproverSpec(a, record, organizationId, now, opts?.substitutions);\n // per_group (#3266): tag each resolved id with this spec's group. An\n // approver without an explicit `group` forms its own group keyed by\n // position, so a plain per-approver list still behaves predictably.\n const groupKey = a.group != null && String(a.group) !== '' ? String(a.group) : `#${idx}`;\n for (const u of ids) {\n if (!u) continue;\n out.push(u);\n if (opts?.groups) (opts.groups[u] ??= []).push(groupKey);\n }\n }\n return out.filter(Boolean);\n }\n\n /**\n * Resolve ONE approver spec to concrete approver identities, applying OOO\n * substitution (#1322) to individually-routed types. Extracted from\n * {@link ApprovalService.expandApprovers} so the caller can tag each spec's\n * resolved ids with a group (#3266) without duplicating the resolution logic.\n * Returns the `type:value` literal as a single-element fallback when a graph\n * lookup yields nothing — same behaviour as before the extraction.\n */\n private async resolveApproverSpec(\n a: any,\n record: any,\n organizationId: string | null | undefined,\n now: number,\n substitutions?: OooSubstitution[],\n ): Promise<string[]> {\n // ADR-0090 D3: `role` is the deprecated spelling of `org_membership_level`.\n // Resolve on the canonical type, but keep the AUTHORED spelling in the\n // `type:value` fallback below — stored `sys_approval_approver` rows and\n // `pending_approvers` slots from 15.x carry the old literal.\n const type = canonicalApproverType(String(a.type));\n if (type !== a.type) {\n this.logger?.warn?.(\n `[approvals] approver type '${a.type}' is deprecated (ADR-0090 D3) — author '${type}' instead`,\n { deprecated: a.type, canonical: type },\n );\n }\n if (type === 'user') {\n return this.applyOooDelegation(String(a.value), now, organizationId, substitutions);\n }\n if (type === 'field' && record) {\n return this.applyOooDelegation(String((record as any)[a.value] ?? ''), now, organizationId, substitutions);\n }\n try {\n if (type === 'team') {\n const users = await this.expandTeamUsers(String(a.value));\n if (users.length) return users;\n } else if (type === 'department' || type === 'business_unit' || type === 'bu') {\n const users = await this.expandBusinessUnitUsers(String(a.value), organizationId);\n if (users.length) return users;\n } else if (type === 'position') {\n const users = await this.expandPositionUsers(String(a.value), organizationId);\n if (users.length) return users;\n } else if (type === 'org_membership_level') {\n const users = await this.expandMembershipTierUsers(String(a.value), organizationId);\n if (users.length) return users;\n } else if (type === 'manager' && record) {\n const subject = (record as any)[a.value] ?? (record as any).owner_id;\n if (subject) {\n const mgr = await this.lookupManager(String(subject));\n if (mgr) return this.applyOooDelegation(mgr, now, organizationId, substitutions);\n }\n }\n } catch { /* fall through */ }\n return [`${a.type}:${a.value}`];\n }\n\n /** Flat team — `sys_team` is better-auth's collaboration grouping (no hierarchy). */\n private async expandTeamUsers(teamId: string): Promise<string[]> {\n if (!teamId) return [];\n let rows: any[] = [];\n try {\n rows = await this.engine.find('sys_team_member', {\n filter: { team_id: teamId },\n fields: ['user_id'],\n limit: 10000,\n context: SYSTEM_CTX,\n } as any);\n } catch { rows = []; }\n return Array.from(new Set((rows ?? []).map((r: any) => String(r.user_id ?? '')).filter(Boolean)));\n }\n\n /** Recursive department — walks `sys_business_unit.parent_business_unit_id`. */\n private async expandBusinessUnitUsers(businessUnitId: string, organizationId?: string | null): Promise<string[]> {\n if (!businessUnitId) return [];\n // Seed sanity check: skip if dept doesn't exist or is inactive within tenant.\n try {\n const seed = await this.engine.find('sys_business_unit', {\n filter: organizationId\n ? { id: businessUnitId, organization_id: organizationId }\n : { id: businessUnitId },\n fields: ['id', 'active'],\n limit: 1,\n context: SYSTEM_CTX,\n } as any);\n const seedRow: any = Array.isArray(seed) ? seed[0] : null;\n if (!seedRow || seedRow.active === false) return [];\n } catch { return []; }\n\n const seen = new Set<string>([businessUnitId]);\n const queue: string[] = [businessUnitId];\n while (queue.length) {\n const parent = queue.shift()!;\n let kids: any[] = [];\n try {\n const filter: any = { parent_business_unit_id: parent, active: { $ne: false } };\n if (organizationId) filter.organization_id = organizationId;\n kids = await this.engine.find('sys_business_unit', { filter, fields: ['id'], limit: 1000, context: SYSTEM_CTX } as any);\n } catch { kids = []; }\n for (const k of kids ?? []) {\n const kid = String((k as any).id ?? '');\n if (kid && !seen.has(kid)) { seen.add(kid); queue.push(kid); }\n }\n }\n let rows: any[] = [];\n try {\n rows = await this.engine.find('sys_business_unit_member', {\n filter: { business_unit_id: { $in: Array.from(seen) } },\n fields: ['user_id'],\n limit: 10000,\n context: SYSTEM_CTX,\n } as any);\n } catch { rows = []; }\n return Array.from(new Set((rows ?? []).map((r: any) => String(r.user_id ?? '')).filter(Boolean)));\n }\n\n /**\n * Position holders (ADR-0090 D3): `sys_user_position` is the platform-owned\n * assignment table, keyed by the position's machine name (ADR-0057 D4),\n * unioned with the better-auth membership string (`sys_member.role`) as a\n * transition source — the same semantics as `PositionGraphService` in\n * `plugin-sharing`, so an approval routes to exactly the users the sharing\n * engine would expand for the same position.\n */\n private async expandPositionUsers(positionName: string, organizationId?: string | null): Promise<string[]> {\n if (!positionName) return [];\n const users = new Set<string>();\n const filter: any = { position: positionName };\n if (organizationId) filter.organization_id = organizationId;\n try {\n const rows = await this.engine.find('sys_user_position', {\n filter, fields: ['user_id'], limit: 10000, context: SYSTEM_CTX,\n } as any);\n for (const r of (rows ?? []) as any[]) {\n const uid = String(r.user_id ?? '');\n if (uid) users.add(uid);\n }\n } catch { /* table may not exist on minimal stacks — union source below still applies */ }\n // ADR-0057 D4 transition source: pre-migration stacks still carry the\n // position name in better-auth's `sys_member.role` column, so the same\n // lookup serves a position name here and a membership tier for\n // `org_membership_level` — the column is one, the two concepts are not.\n for (const uid of await this.expandMembershipTierUsers(positionName, organizationId)) users.add(uid);\n return Array.from(users);\n }\n\n /**\n * better-auth org-membership tier (`sys_member.role`: owner/admin/member) —\n * NOT positions. Named for the projection (`org_membership_level`, ADR-0057\n * D7 / ADR-0090 D3), not for better-auth's column: the column name is theirs\n * and stays, the platform-facing word does not.\n */\n private async expandMembershipTierUsers(tier: string, organizationId?: string | null): Promise<string[]> {\n if (!tier) return [];\n const filter: any = { role: tier };\n if (organizationId) filter.organization_id = organizationId;\n let rows: any[] = [];\n try {\n rows = await this.engine.find('sys_member', { filter, fields: ['user_id'], limit: 10000, context: SYSTEM_CTX } as any);\n } catch { rows = []; }\n return Array.from(new Set((rows ?? []).map((r: any) => String(r.user_id ?? '')).filter(Boolean)));\n }\n\n private async lookupManager(userId: string): Promise<string | null> {\n try {\n const rows = await this.engine.find('sys_user', {\n filter: { id: userId }, fields: ['id', 'manager_id'], limit: 1, context: SYSTEM_CTX,\n } as any);\n const row: any = Array.isArray(rows) ? rows[0] : null;\n return row?.manager_id ? String(row.manager_id) : null;\n } catch { return null; }\n }\n\n /**\n * Out-of-office auto-skip (#1322 M1). Given an individually-routed approver\n * id, follow any active `sys_approval_delegation` chain and return the id the\n * slot should actually go to — the delegate acts under their own identity, so\n * no impersonation is involved. Returns `[userId]` unchanged when there is no\n * active delegation. Each hop is appended to `collector` (when supplied) so\n * the caller can audit + notify (M4).\n *\n * The chain (A out → B, B out → C, …) is bounded by {@link OOO_MAX_CHAIN} and\n * stops on a self-reference or a cycle, so a mis-declared loop degrades to the\n * last reachable delegate rather than hanging.\n */\n private async applyOooDelegation(\n userId: string,\n now: number,\n organizationId?: string | null,\n collector?: OooSubstitution[],\n ): Promise<string[]> {\n const start = String(userId ?? '').trim();\n if (!start) return [];\n let current = start;\n const visited = new Set<string>([current]);\n for (let hop = 0; hop < OOO_MAX_CHAIN; hop++) {\n const del = await this.lookupActiveDelegation(current, now, organizationId);\n if (!del) break;\n const to = String(del.delegate_id ?? '').trim();\n if (!to || to === current || visited.has(to)) break; // no-op / self / cycle\n collector?.push({ from: current, to, reason: del.reason != null ? String(del.reason) : null });\n visited.add(to);\n current = to;\n }\n return [current];\n }\n\n /**\n * The active OOO delegation for a delegator at `now`, or null. Validity is the\n * shared `isGrantActive` half-open window (ADR-0091 D2), enforced here at\n * resolution time — never by a background job. When several rows are active,\n * the one expiring soonest wins (the most specific coverage window).\n */\n private async lookupActiveDelegation(\n delegatorId: string,\n now: number,\n organizationId?: string | null,\n ): Promise<any | null> {\n if (!delegatorId) return null;\n let rows: any[] = [];\n try {\n rows = await this.engine.find('sys_approval_delegation', {\n filter: { delegator_id: delegatorId },\n fields: ['id', 'delegator_id', 'delegate_id', 'valid_from', 'valid_until', 'reason', 'organization_id'],\n limit: 50,\n context: SYSTEM_CTX,\n } as any);\n } catch { return null; } // table absent on minimal stacks — no OOO, resolve as-is\n const active = (rows ?? []).filter((r: any) =>\n isGrantActive(r, now)\n // A null-org rule applies across tenants; a scoped rule only within its tenant.\n && (organizationId == null || r.organization_id == null || String(r.organization_id) === String(organizationId)));\n if (!active.length) return null;\n active.sort((a: any, b: any) => {\n const au = a.valid_until ? Date.parse(String(a.valid_until)) : Number.POSITIVE_INFINITY;\n const bu = b.valid_until ? Date.parse(String(b.valid_until)) : Number.POSITIVE_INFINITY;\n return au - bu;\n });\n return active[0];\n }\n\n /** Mirror a request status onto a business-object field, if configured. */\n private async mirrorStatusField(object: string, recordId: string, field: string, status: string): Promise<void> {\n try {\n await this.engine.update(object, { id: recordId, [field]: status }, { context: SYSTEM_CTX });\n } catch (err: any) {\n this.logger?.warn?.(`[approvals] mirrorStatusField failed: ${err?.message ?? err}`);\n }\n }\n\n // ── ADR-0019: Approval-as-flow-node ──────────────────────────\n //\n // A flow's Approval node opens a request via `openNodeRequest` (carrying its\n // own approvers/behavior config and the suspended run id), then suspends. A\n // later `decide` finalizes it and resumes the flow run down the matching\n // `approve`/`reject` edge. The record lock is enforced by a beforeUpdate hook\n // keyed on a *pending* request, so finalizing auto-releases it.\n\n /**\n * Open a pending approval request on behalf of a flow's Approval node. The\n * node config (approvers / behavior / status field) is snapshotted on the row\n * so a decision can be made without any process to resolve against.\n */\n async openNodeRequest(\n input: {\n object: string;\n recordId: string;\n runId: string;\n nodeId: string;\n config: ApprovalNodeConfig;\n flowName?: string;\n /** Authored flow label, snapshotted for inbox display. */\n flowLabel?: string;\n /** Authored node label, snapshotted for inbox display. */\n nodeLabel?: string;\n submitterId?: string | null;\n record?: any;\n organizationId?: string | null;\n },\n context: SharingExecutionContext,\n ): Promise<ApprovalRequestRow> {\n if (!input.object) throw new Error('VALIDATION_FAILED: object is required');\n if (!input.recordId) throw new Error('VALIDATION_FAILED: recordId is required');\n if (!input.runId) throw new Error('VALIDATION_FAILED: runId is required');\n\n // One pending request per (object, record).\n const existing = await this.engine.find('sys_approval_request', {\n where: { object_name: input.object, record_id: input.recordId, status: 'pending' },\n limit: 1, context: SYSTEM_CTX,\n });\n if (Array.isArray(existing) && existing[0]) {\n throw new Error(`DUPLICATE_REQUEST: a pending approval already exists for ${input.object}/${input.recordId}`);\n }\n\n const ctxOrg = (context as any)?.organizationId ?? (context as any)?.tenantId ?? input.organizationId ?? null;\n const nowDate = this.clock.now();\n // OOO auto-skip (#1322 M1): reroute individually-routed approvers who are\n // out of office. Collected hops drive the audit + notification below (M4).\n const substitutions: OooSubstitution[] = [];\n // Group membership per resolved approver (#3266) — snapshotted so quorum /\n // per_group finalization is decided against the slate resolved at OPEN time\n // (OOO-substituted), not re-resolved live at each decision.\n const groups: Record<string, string[]> = {};\n const approvers = await this.expandApprovers(\n { approvers: input.config.approvers }, input.record, ctxOrg, { now: nowDate.getTime(), substitutions, groups },\n );\n\n const now = nowDate.toISOString();\n const id = uid('areq');\n const processName = `flow:${input.flowName ?? input.nodeId}`;\n // Display labels ride the config snapshot (no schema migration needed);\n // `rowFromRequest` surfaces them as `process_label` / `step_label`.\n const configSnapshot: any = { ...input.config };\n if (input.flowLabel) configSnapshot.__flowLabel = input.flowLabel;\n if (input.nodeLabel) configSnapshot.__nodeLabel = input.nodeLabel;\n // Snapshot the resolved approver→group map for quorum/per_group tallying.\n if (input.config.behavior === 'quorum' || input.config.behavior === 'per_group') {\n configSnapshot.__approverGroups = groups;\n }\n // ADR-0044 round numbering: rounds of a revise loop share the run — count\n // this (run, node)'s prior requests; the new one is round N+1. Stamped on\n // the snapshot (precedent: __flowLabel), so no schema migration.\n try {\n const prior = await this.engine.find('sys_approval_request', {\n where: { flow_run_id: input.runId, flow_node_id: input.nodeId }, limit: 500, context: SYSTEM_CTX,\n });\n const n = Array.isArray(prior) ? prior.length : 0;\n if (n > 0) configSnapshot.__round = n + 1;\n } catch { /* round display is best-effort */ }\n const row: any = {\n id,\n process_name: processName,\n object_name: input.object,\n record_id: input.recordId,\n submitter_id: input.submitterId ?? context.userId ?? null,\n status: 'pending',\n current_step: input.nodeId,\n current_step_index: 0,\n pending_approvers: approvers.join(','),\n payload_json: input.record != null ? JSON.stringify(input.record) : null,\n flow_run_id: input.runId,\n flow_node_id: input.nodeId,\n node_config_json: JSON.stringify(configSnapshot),\n organization_id: ctxOrg,\n created_at: now,\n updated_at: now,\n };\n await this.engine.insert('sys_approval_request', row, { context: SYSTEM_CTX });\n await this.syncApproverIndex(id, approvers, ctxOrg, now);\n await this.engine.insert('sys_approval_action', {\n id: uid('aact'), request_id: id, organization_id: ctxOrg,\n step_name: input.nodeId, step_index: 0, action: 'submit',\n actor_id: input.submitterId ?? context.userId ?? null, comment: null, created_at: now,\n }, { context: SYSTEM_CTX });\n\n // OOO substitution audit + notification (#1322 M4). Each hop that rerouted\n // an approver away from an out-of-office user is recorded on the request's\n // audit trail (a system action, no human actor) and notified to both the\n // delegate — who now owns the slot — and the skipped approver.\n for (const sub of substitutions) {\n await this.engine.insert('sys_approval_action', {\n id: uid('aact'), request_id: id, organization_id: ctxOrg,\n step_name: input.nodeId, step_index: 0, action: 'ooo_substitute',\n actor_id: null,\n comment: `${sub.from} → ${sub.to}${sub.reason ? ` — ${sub.reason}` : ''}`,\n created_at: now,\n }, { context: SYSTEM_CTX });\n await this.notify({\n topic: 'approval.ooo_substituted',\n audience: [sub.to],\n source: { object: 'sys_approval_request', id },\n dedupKey: `approval-ooo-${id}-${sub.to}`,\n payload: {\n title: 'Approval routed to you (out-of-office cover)',\n message: `You are covering an approval on ${input.object}/${input.recordId} while ${sub.from} is out of office.`,\n actionUrl: '/system/approvals',\n },\n });\n await this.notify({\n topic: 'approval.ooo_skipped',\n audience: [sub.from],\n source: { object: 'sys_approval_request', id },\n dedupKey: `approval-ooo-skip-${id}-${sub.from}`,\n payload: {\n title: 'Approval routed to your delegate',\n message: `An approval on ${input.object}/${input.recordId} was routed to ${sub.to} while you are out of office.`,\n actionUrl: '/system/approvals',\n },\n });\n }\n\n // Record lock (when `lockRecord !== false`) is enforced by the beforeUpdate\n // hook keyed on the now-pending request; no extra write needed here.\n if (input.config.approvalStatusField) {\n await this.mirrorStatusField(input.object, input.recordId, input.config.approvalStatusField, 'pending');\n }\n\n return rowFromRequest(row);\n }\n\n /**\n * True when the approve tally satisfies the node's `behavior` (#3266):\n * - `unanimous` — every resolved approver approved.\n * - `quorum` — at least `minApprovals` distinct approvals (default = all).\n * - `per_group` — every group reached `minApprovals` approvals (default 1).\n * Thresholds are clamped to the resolvable count / group size, so a mis-set\n * value can never deadlock a request.\n */\n private isApprovalSatisfied(\n behavior: string,\n config: ApprovalNodeConfig,\n original: string[],\n groupMap: Record<string, string[]>,\n approved: Set<string>,\n ): boolean {\n if (behavior === 'unanimous') {\n return original.length > 0 && original.every(a => approved.has(a));\n }\n if (behavior === 'quorum') {\n const n = original.length || 1;\n const need = Math.min(Math.max(1, config.minApprovals ?? n), n);\n // Count distinct approvals (robust to OOO/reassign changing who holds a slot).\n return approved.size >= need;\n }\n if (behavior === 'per_group') {\n const perGroupNeed = Math.max(1, config.minApprovals ?? 1);\n const size: Record<string, number> = {};\n for (const gs of Object.values(groupMap)) for (const g of gs) size[g] = (size[g] ?? 0) + 1;\n const groups = Object.keys(size);\n if (!groups.length) return true; // nothing to gate\n const got: Record<string, number> = {};\n for (const a of approved) for (const g of (groupMap[a] ?? [])) got[g] = (got[g] ?? 0) + 1;\n return groups.every(g => (got[g] ?? 0) >= Math.min(perGroupNeed, size[g]));\n }\n return true; // first_response and unknown → first approval finalizes\n }\n\n /**\n * Record a decision on a node-driven request. Honours the node's `behavior`\n * (#3266): `first_response` finalizes on the first approval; `unanimous`,\n * `quorum`, and `per_group` hold the request open until their tally is met\n * (see {@link ApprovalService.isApprovalSatisfied}). A rejection always\n * finalizes the node (one veto). When the request finalizes, returns the\n * suspended run id + node id so the caller (or {@link ApprovalService.decide})\n * can resume the flow down the matching branch.\n */\n async decideNode(\n requestId: string,\n input: { decision: 'approve' | 'reject'; actorId: string; comment?: string; attachments?: string[] },\n context: SharingExecutionContext,\n ): Promise<{ request: ApprovalRequestRow; runId: string | null; nodeId: string | null; finalized: boolean; decision: 'approve' | 'reject' }> {\n if (!requestId) throw new Error('VALIDATION_FAILED: requestId is required');\n if (!input?.actorId) throw new Error('VALIDATION_FAILED: actorId is required');\n if (input.decision !== 'approve' && input.decision !== 'reject') {\n throw new Error('VALIDATION_FAILED: decision must be approve|reject');\n }\n\n // Read the raw row to reach flow_* correlation + the node config snapshot.\n const rawRows = await this.engine.find('sys_approval_request', {\n where: { id: requestId }, limit: 1, context: SYSTEM_CTX,\n });\n const raw: any = Array.isArray(rawRows) ? rawRows[0] : null;\n if (!raw) throw new Error(`REQUEST_NOT_FOUND: ${requestId}`);\n if (raw.status !== 'pending') throw new Error(`INVALID_STATE: request is ${raw.status}`);\n\n const pendingApprovers = csvSplit(raw.pending_approvers);\n if (!context.isSystem && !pendingApprovers.includes(input.actorId)) {\n throw new Error(`FORBIDDEN: actor '${input.actorId}' is not a pending approver`);\n }\n\n const config = parseJson<ApprovalNodeConfig>(raw.node_config_json, { approvers: [], behavior: 'first_response' } as any);\n const org = raw.organization_id ?? null;\n const nodeId: string | null = raw.flow_node_id ?? raw.current_step ?? null;\n const runId: string | null = raw.flow_run_id ?? null;\n const now = this.clock.now().toISOString();\n\n // Audit the decision first so the quorum/per_group tally below sees it.\n await this.engine.insert('sys_approval_action', {\n id: uid('aact'), request_id: requestId, organization_id: org,\n step_name: nodeId, step_index: 0, action: input.decision,\n actor_id: input.actorId, comment: input.comment ?? null,\n attachments: input.attachments?.length ? input.attachments : null,\n created_at: now,\n }, { context: SYSTEM_CTX });\n\n // Multi-approver aggregation on approve (#3266). A rejection always\n // finalizes the node (one veto), so only the approve path can hold it open.\n // `first_response` finalizes on the first approval (falls straight through).\n const behavior = config.behavior ?? 'first_response';\n if (input.decision === 'approve' && behavior !== 'first_response') {\n const acts = await this.engine.find('sys_approval_action', {\n where: { request_id: requestId, step_index: 0, action: 'approve' }, limit: 1000, context: SYSTEM_CTX,\n });\n const approved = new Set<string>((acts ?? []).map((a: any) => String(a.actor_id ?? '')).filter(Boolean));\n\n // quorum / per_group tally against the OPEN-time snapshot (already\n // OOO-substituted). unanimous re-resolves for back-compat with requests\n // opened before the snapshot existed.\n const snapshotGroups = (config as any).__approverGroups as Record<string, string[]> | undefined;\n let original: string[];\n let groupMap: Record<string, string[]>;\n if (snapshotGroups && (behavior === 'quorum' || behavior === 'per_group')) {\n groupMap = snapshotGroups;\n original = Object.keys(snapshotGroups);\n } else {\n original = await this.expandApprovers(\n { approvers: config.approvers }, parseJson(raw.payload_json, undefined), org,\n );\n groupMap = {};\n }\n\n if (!this.isApprovalSatisfied(behavior, config, original, groupMap, approved)) {\n const stillPending = original.filter(a => !approved.has(a));\n await this.engine.update('sys_approval_request', {\n id: requestId, pending_approvers: stillPending.join(','), updated_at: now,\n }, { context: SYSTEM_CTX });\n await this.syncApproverIndex(requestId, stillPending, org, now);\n const fresh = await this.getRequest(requestId, context);\n return { request: fresh!, runId, nodeId, finalized: false, decision: input.decision };\n }\n }\n\n const finalStatus = input.decision === 'approve' ? 'approved' : 'rejected';\n await this.engine.update('sys_approval_request', {\n id: requestId, status: finalStatus, pending_approvers: null, completed_at: now, updated_at: now,\n }, { context: SYSTEM_CTX });\n await this.syncApproverIndex(requestId, [], org, now);\n if (config.approvalStatusField) {\n await this.mirrorStatusField(raw.object_name, raw.record_id, config.approvalStatusField, finalStatus);\n }\n const fresh = await this.getRequest(requestId, context);\n return { request: fresh!, runId, nodeId, finalized: true, decision: input.decision };\n }\n\n /**\n * Public contract entrypoint (ADR-0019). Records a decision on a node-driven\n * request via {@link ApprovalService.decideNode} and, when it finalizes,\n * resumes the owning flow run down the matching `approve` / `reject` edge.\n */\n async decide(\n requestId: string,\n input: ApprovalDecisionInput,\n context: SharingExecutionContext,\n ): Promise<ApprovalDecisionResult> {\n const result = await this.decideNode(requestId, input, context);\n\n let resumed = false;\n if (result.finalized && result.runId && typeof this.automation?.resume === 'function') {\n const branchLabel = result.decision === 'approve'\n ? APPROVAL_BRANCH_LABELS.approve\n : APPROVAL_BRANCH_LABELS.reject;\n try {\n await this.automation.resume(result.runId, {\n branchLabel,\n output: { decision: result.decision, requestId },\n });\n resumed = true;\n } catch (err: any) {\n this.logger?.warn?.('[approvals] resume after decision failed', {\n request: requestId, run: result.runId, error: err?.message ?? String(err),\n });\n }\n }\n\n return {\n request: result.request,\n finalized: result.finalized,\n decision: result.decision,\n runId: result.runId,\n resumed,\n };\n }\n\n /**\n * Withdraw a pending request (submitter only). Finalises the row as\n * `recalled`, releases the record lock (keyed on pending status), mirrors\n * the status field when configured, and resumes the owning flow run down\n * the `reject` branch with `output.decision = 'recall'` — leaving the run\n * suspended forever would leak it.\n *\n * ADR-0044: also valid on the LATEST `returned` request of its run — the\n * submitter abandons the revision window instead of resubmitting. The run\n * is then paused at the revise wait node (no reject edge), so it is\n * terminally cancelled via {@link ApprovalResumeSurface.cancelRun} rather\n * than resumed.\n */\n async recall(\n requestId: string,\n input: ApprovalRecallInput,\n context: SharingExecutionContext,\n ): Promise<ApprovalRecallResult> {\n if (!requestId) throw new Error('VALIDATION_FAILED: requestId is required');\n if (!input?.actorId) throw new Error('VALIDATION_FAILED: actorId is required');\n\n const rawRows = await this.engine.find('sys_approval_request', {\n where: { id: requestId }, limit: 1, context: SYSTEM_CTX,\n });\n const raw: any = Array.isArray(rawRows) ? rawRows[0] : null;\n if (!raw) throw new Error(`REQUEST_NOT_FOUND: ${requestId}`);\n const inReviseWindow = raw.status === 'returned';\n if (raw.status !== 'pending' && !inReviseWindow) {\n throw new Error(`INVALID_STATE: request is ${raw.status}`);\n }\n if (!context.isSystem && raw.submitter_id && String(raw.submitter_id) !== String(input.actorId)) {\n throw new Error(`FORBIDDEN: only the submitter may recall this request`);\n }\n // A returned request is only recallable while it is still the run's live\n // frontier — a resubmitted (or later-node) request supersedes it.\n if (inReviseWindow) await this.assertLatestForRun(raw);\n\n const config = parseJson<ApprovalNodeConfig>(raw.node_config_json, { approvers: [], behavior: 'first_response' } as any);\n const org = raw.organization_id ?? null;\n const nodeId: string | null = raw.flow_node_id ?? raw.current_step ?? null;\n const runId: string | null = raw.flow_run_id ?? null;\n const now = this.clock.now().toISOString();\n\n await this.engine.insert('sys_approval_action', {\n id: uid('aact'), request_id: requestId, organization_id: org,\n step_name: nodeId, step_index: 0, action: 'recall',\n actor_id: input.actorId, comment: input.comment ?? null, created_at: now,\n }, { context: SYSTEM_CTX });\n\n await this.engine.update('sys_approval_request', {\n id: requestId, status: 'recalled', pending_approvers: null, completed_at: now, updated_at: now,\n }, { context: SYSTEM_CTX });\n await this.syncApproverIndex(requestId, [], org, now);\n if (config.approvalStatusField) {\n await this.mirrorStatusField(raw.object_name, raw.record_id, config.approvalStatusField, 'recalled');\n }\n\n let resumed = false;\n if (inReviseWindow) {\n // ADR-0044: the run is paused at the revise wait node, which has no\n // reject out-edge to resume down — terminally cancel it instead.\n if (runId && typeof this.automation?.cancelRun === 'function') {\n try {\n await this.automation.cancelRun(runId, `approval request ${requestId} recalled during revision`);\n } catch (err: any) {\n this.logger?.warn?.('[approvals] cancelRun after revise-window recall failed', {\n request: requestId, run: runId, error: err?.message ?? String(err),\n });\n }\n }\n } else if (runId && typeof this.automation?.resume === 'function') {\n try {\n await this.automation.resume(runId, {\n branchLabel: APPROVAL_BRANCH_LABELS.reject,\n output: { decision: 'recall', requestId },\n });\n resumed = true;\n } catch (err: any) {\n this.logger?.warn?.('[approvals] resume after recall failed', {\n request: requestId, run: runId, error: err?.message ?? String(err),\n });\n }\n }\n\n const fresh = await this.getRequest(requestId, context);\n return { request: fresh!, runId, resumed };\n }\n\n // ── Send back for revision / resubmit (ADR-0044) ─────────────\n\n /**\n * ADR-0044 send back for revision. Finalises the pending request as\n * `returned` (a third terminal state — approver-initiated rework, distinct\n * from submitter-initiated `recalled`) and resumes the owning flow run down\n * its `revise` edge to a wait point: the record lock (keyed on `pending`)\n * releases, the submitter reworks the data, then {@link resubmit}s.\n *\n * Requires the approval node to declare a `revise` out-edge — validated\n * BEFORE any mutation, because resuming with an unmatched `branchLabel`\n * falls back to *all* out-edges. Past the node's `maxRevisions` budget the\n * request auto-rejects instead (resumes down `reject` with\n * `output.autoRejected = true`) so instances cannot orbit forever.\n */\n async sendBack(\n requestId: string,\n input: ApprovalSendBackInput,\n context: SharingExecutionContext,\n ): Promise<ApprovalSendBackResult> {\n if (!input?.actorId) throw new Error('VALIDATION_FAILED: actorId is required');\n const raw = await this.loadPendingRow(requestId);\n const pending = csvSplit(raw.pending_approvers);\n if (!context.isSystem && !pending.includes(input.actorId)) {\n throw new Error(`FORBIDDEN: actor '${input.actorId}' is not a pending approver`);\n }\n\n const config = parseJson<ApprovalNodeConfig>(raw.node_config_json, { approvers: [], behavior: 'first_response' } as any);\n const org = raw.organization_id ?? null;\n const nodeId: string | null = raw.flow_node_id ?? raw.current_step ?? null;\n const runId: string | null = raw.flow_run_id ?? null;\n\n await this.assertReviseEdge(raw, nodeId);\n\n const now = this.clock.now().toISOString();\n const maxRevisions = typeof (config as any).maxRevisions === 'number' ? (config as any).maxRevisions : 3;\n let priorSendBacks = 0;\n if (runId && nodeId) {\n const siblings = await this.engine.find('sys_approval_request', {\n where: { flow_run_id: runId, flow_node_id: nodeId, status: 'returned' }, limit: 500, context: SYSTEM_CTX,\n });\n priorSendBacks = Array.isArray(siblings) ? siblings.length : 0;\n }\n\n // Audit the revise intent first (audit-first, like decideNode) — on the\n // auto-reject path the trail then reads `revise → reject`, preserving\n // what the approver actually asked for.\n await this.engine.insert('sys_approval_action', {\n id: uid('aact'), request_id: requestId, organization_id: org,\n step_name: nodeId, step_index: 0, action: 'revise',\n actor_id: input.actorId, comment: input.comment ?? null, created_at: now,\n }, { context: SYSTEM_CTX });\n\n if (priorSendBacks >= maxRevisions) {\n // Revision budget exhausted — auto-reject (ADR-0044 loop guard).\n await this.engine.insert('sys_approval_action', {\n id: uid('aact'), request_id: requestId, organization_id: org,\n step_name: nodeId, step_index: 0, action: 'reject',\n actor_id: input.actorId,\n comment: `Auto-rejected: revision limit (${maxRevisions}) exceeded`, created_at: now,\n }, { context: SYSTEM_CTX });\n await this.engine.update('sys_approval_request', {\n id: requestId, status: 'rejected', pending_approvers: null, completed_at: now, updated_at: now,\n }, { context: SYSTEM_CTX });\n await this.syncApproverIndex(requestId, [], org, now);\n if (config.approvalStatusField) {\n await this.mirrorStatusField(raw.object_name, raw.record_id, config.approvalStatusField, 'rejected');\n }\n let resumed = false;\n if (runId && typeof this.automation?.resume === 'function') {\n try {\n await this.automation.resume(runId, {\n branchLabel: APPROVAL_BRANCH_LABELS.reject,\n output: { decision: 'reject', autoRejected: true, requestId },\n });\n resumed = true;\n } catch (err: any) {\n this.logger?.warn?.('[approvals] resume after auto-reject failed', {\n request: requestId, run: runId, error: err?.message ?? String(err),\n });\n }\n }\n if (raw.submitter_id) {\n await this.notify({\n topic: 'approval.returned',\n audience: [String(raw.submitter_id)],\n actorId: input.actorId,\n source: { object: 'sys_approval_request', id: requestId },\n payload: {\n title: 'Approval auto-rejected',\n message: `Your ${raw.object_name}/${raw.record_id} exceeded the revision limit (${maxRevisions}) and was rejected.`,\n actionUrl: '/system/approvals',\n },\n });\n }\n const fresh = await this.getRequest(requestId, context);\n return { request: fresh!, runId, resumed, autoRejected: true };\n }\n\n await this.engine.update('sys_approval_request', {\n id: requestId, status: 'returned', pending_approvers: null, completed_at: now, updated_at: now,\n }, { context: SYSTEM_CTX });\n await this.syncApproverIndex(requestId, [], org, now);\n if (config.approvalStatusField) {\n await this.mirrorStatusField(raw.object_name, raw.record_id, config.approvalStatusField, 'returned');\n }\n\n let resumed = false;\n if (runId && typeof this.automation?.resume === 'function') {\n try {\n await this.automation.resume(runId, {\n branchLabel: APPROVAL_BRANCH_LABELS.revise,\n output: { decision: 'revise', requestId },\n });\n resumed = true;\n } catch (err: any) {\n this.logger?.warn?.('[approvals] resume after send-back failed', {\n request: requestId, run: runId, error: err?.message ?? String(err),\n });\n }\n }\n\n if (raw.submitter_id) {\n await this.notify({\n topic: 'approval.returned',\n audience: [String(raw.submitter_id)],\n actorId: input.actorId,\n source: { object: 'sys_approval_request', id: requestId },\n payload: {\n title: 'Sent back for revision',\n message: input.comment?.trim() || `Your ${raw.object_name}/${raw.record_id} needs rework before it can be approved.`,\n actionUrl: '/system/approvals',\n },\n });\n }\n\n const fresh = await this.getRequest(requestId, context);\n return { request: fresh!, runId, resumed };\n }\n\n /**\n * ADR-0044 resubmit after rework. Valid on the LATEST `returned` request of\n * its run, submitter-only. Audits `resubmit` on the returned (round-N)\n * request and resumes the run from the revise wait node; traversal walks\n * the declared back-edge into the approval node, whose executor opens the\n * round-N+1 request — fresh approver slate, record re-locks.\n */\n async resubmit(\n requestId: string,\n input: ApprovalResubmitInput,\n context: SharingExecutionContext,\n ): Promise<ApprovalResubmitResult> {\n if (!input?.actorId) throw new Error('VALIDATION_FAILED: actorId is required');\n const rawRows = await this.engine.find('sys_approval_request', {\n where: { id: requestId }, limit: 1, context: SYSTEM_CTX,\n });\n const raw: any = Array.isArray(rawRows) ? rawRows[0] : null;\n if (!raw) throw new Error(`REQUEST_NOT_FOUND: ${requestId}`);\n if (raw.status !== 'returned') {\n throw new Error(`INVALID_STATE: request is ${raw.status} (resubmit applies to returned requests)`);\n }\n if (!context.isSystem && raw.submitter_id && String(raw.submitter_id) !== String(input.actorId)) {\n throw new Error('FORBIDDEN: only the submitter may resubmit');\n }\n await this.assertLatestForRun(raw);\n\n // A colliding pending request on the same record (e.g. a record-change\n // trigger re-fired off an edit made inside the revise window) would make\n // the approval node's re-entry fail AFTER the engine consumed the\n // suspension — permanently killing the run. Refuse up front instead; the\n // submitter resolves the collision (recall the other request) first.\n const colliding = await this.engine.find('sys_approval_request', {\n where: { object_name: raw.object_name, record_id: raw.record_id, status: 'pending' },\n limit: 1, context: SYSTEM_CTX,\n });\n if (Array.isArray(colliding) && colliding[0]) {\n throw new Error(\n `DUPLICATE_REQUEST: another approval request is already pending on ${raw.object_name}/${raw.record_id} — resolve it before resubmitting`,\n );\n }\n\n const org = raw.organization_id ?? null;\n const nodeId: string | null = raw.flow_node_id ?? raw.current_step ?? null;\n const runId: string | null = raw.flow_run_id ?? null;\n const now = this.clock.now().toISOString();\n\n await this.engine.insert('sys_approval_action', {\n id: uid('aact'), request_id: requestId, organization_id: org,\n step_name: nodeId, step_index: 0, action: 'resubmit',\n actor_id: input.actorId, comment: input.comment ?? null, created_at: now,\n }, { context: SYSTEM_CTX });\n\n // The next round only exists if this resume lands — surface `resumed`\n // honestly so a stuck run is visible instead of silently swallowed.\n let resumed = false;\n if (runId && typeof this.automation?.resume === 'function') {\n try {\n await this.automation.resume(runId, {\n branchLabel: APPROVAL_BRANCH_LABELS.resubmit,\n output: { resubmitted: true, requestId },\n });\n resumed = true;\n } catch (err: any) {\n this.logger?.warn?.('[approvals] resume after resubmit failed', {\n request: requestId, run: runId, error: err?.message ?? String(err),\n });\n }\n }\n\n const fresh = await this.getRequest(requestId, context);\n return { request: fresh!, runId, resumed };\n }\n\n /**\n * ADR-0044 guard: the flow's approval node must declare a `revise`\n * out-edge before send-back is allowed — the engine's branch-label fallback\n * (no matching label ⇒ ALL out-edges) must never be reachable from a user\n * action.\n */\n private async assertReviseEdge(raw: any, nodeId: string | null): Promise<void> {\n const processName = String(raw.process_name ?? '');\n const flowName = processName.startsWith('flow:') ? processName.slice('flow:'.length) : undefined;\n if (!flowName || !nodeId || typeof this.automation?.getFlow !== 'function') {\n throw new Error('VALIDATION_FAILED: send-back requires the owning flow definition (automation engine unavailable)');\n }\n const flow: any = await this.automation.getFlow(flowName);\n const hasRevise = Array.isArray(flow?.edges)\n && flow.edges.some((e: any) => e?.source === nodeId && e?.label === APPROVAL_BRANCH_LABELS.revise);\n if (!hasRevise) {\n throw new Error(\n `VALIDATION_FAILED: approval node '${nodeId}' has no '${APPROVAL_BRANCH_LABELS.revise}' out-edge — ` +\n 'the flow does not support send-back for revision',\n );\n }\n }\n\n /**\n * ADR-0044 guard: a `returned` request is only actionable (resubmit /\n * recall) while it is still the newest request on its run — a later round\n * or a later node's request supersedes it.\n */\n private async assertLatestForRun(raw: any): Promise<void> {\n const runId = raw.flow_run_id;\n if (!runId) return;\n // SortNode's key is `order` (spec/data/query.zod.ts) — `direction` would\n // silently default to ascending and return the OLDEST row.\n const rows = await this.engine.find('sys_approval_request', {\n where: { flow_run_id: runId },\n orderBy: [{ field: 'created_at', order: 'desc' }], limit: 1, context: SYSTEM_CTX,\n });\n const latest: any = Array.isArray(rows) ? rows[0] : null;\n if (latest && String(latest.id) !== String(raw.id)) {\n throw new Error('INVALID_STATE: a newer approval request supersedes this one');\n }\n }\n\n // ── Thread interactions (no flow movement) ───────────────────\n\n /**\n * Hand a pending-approver slot to someone else. `from` defaults to the\n * actor itself; the actor must hold the slot being handed over (or be a\n * system caller). Audits `reassign` and notifies the new approver.\n */\n async reassign(\n requestId: string,\n input: { actorId: string; to: string; from?: string; comment?: string },\n context: SharingExecutionContext,\n ): Promise<{ request: ApprovalRequestRow }> {\n if (!input?.actorId) throw new Error('VALIDATION_FAILED: actorId is required');\n const to = String(input?.to ?? '').trim();\n if (!to) throw new Error('VALIDATION_FAILED: `to` (new approver) is required');\n const raw = await this.loadPendingRow(requestId);\n\n const pending = csvSplit(raw.pending_approvers);\n const from = String(input.from ?? input.actorId).trim();\n if (!pending.includes(from)) {\n throw new Error(`FORBIDDEN: '${from}' is not a pending approver on this request`);\n }\n if (!context.isSystem && input.actorId !== from && !pending.includes(input.actorId)) {\n throw new Error(`FORBIDDEN: actor '${input.actorId}' is not a pending approver`);\n }\n if (pending.includes(to)) {\n throw new Error(`VALIDATION_FAILED: '${to}' is already a pending approver`);\n }\n\n const next = pending.map(a => (a === from ? to : a));\n const now = this.clock.now().toISOString();\n // Audit first, then mutate — mirrors decideNode(), so a failed audit\n // write can never leave a moved slot without a trail.\n await this.engine.insert('sys_approval_action', {\n id: uid('aact'), request_id: requestId, organization_id: raw.organization_id ?? null,\n step_name: raw.flow_node_id ?? raw.current_step ?? null, step_index: 0, action: 'reassign',\n actor_id: input.actorId, comment: input.comment ?? `${from} → ${to}`, created_at: now,\n }, { context: SYSTEM_CTX });\n // per_group / quorum (#3266): carry the delegated slot's group membership to\n // the new approver in the snapshot, so their approval still counts for the\n // original group.\n let configPatch: Record<string, unknown> = {};\n try {\n const cfg = parseJson<any>(raw.node_config_json, null);\n const groups = cfg?.__approverGroups as Record<string, string[]> | undefined;\n if (groups && groups[from] && !groups[to]) {\n groups[to] = groups[from];\n delete groups[from];\n configPatch = { node_config_json: JSON.stringify(cfg) };\n }\n } catch { /* snapshot left untouched on parse failure */ }\n await this.engine.update('sys_approval_request', {\n id: requestId, pending_approvers: next.join(','), updated_at: now, ...configPatch,\n }, { context: SYSTEM_CTX });\n await this.syncApproverIndex(requestId, next, raw.organization_id ?? null, now);\n\n await this.notify({\n topic: 'approval.reassigned',\n audience: [to],\n actorId: input.actorId,\n source: { object: 'sys_approval_request', id: requestId },\n dedupKey: `approval-reassign-${requestId}-${to}`,\n payload: {\n title: 'Approval handed to you',\n message: `You are now an approver on ${raw.object_name}/${raw.record_id}.`,\n actionUrl: '/system/approvals',\n },\n });\n\n const fresh = await this.getRequest(requestId, context);\n return { request: fresh! };\n }\n\n /**\n * Submitter nudge — notify every pending approver. Throttled to one\n * reminder per {@link REMIND_COOLDOWN_MS} per request.\n */\n async remind(\n requestId: string,\n input: { actorId: string; comment?: string },\n context: SharingExecutionContext,\n ): Promise<{ request: ApprovalRequestRow; notified: number }> {\n if (!input?.actorId) throw new Error('VALIDATION_FAILED: actorId is required');\n const raw = await this.loadPendingRow(requestId);\n if (!context.isSystem && raw.submitter_id && String(raw.submitter_id) !== String(input.actorId)) {\n throw new Error('FORBIDDEN: only the submitter may send reminders');\n }\n\n const acts = await this.engine.find('sys_approval_action', {\n where: { request_id: requestId, action: 'remind' },\n orderBy: [{ field: 'created_at', order: 'desc' }], limit: 1, context: SYSTEM_CTX,\n });\n const last: any = Array.isArray(acts) ? acts[0] : null;\n const now = this.clock.now();\n if (last?.created_at && now.getTime() - Date.parse(last.created_at) < REMIND_COOLDOWN_MS) {\n throw new Error('THROTTLED: a reminder was already sent recently');\n }\n\n const pending = csvSplit(raw.pending_approvers);\n const nowIso = now.toISOString();\n await this.engine.insert('sys_approval_action', {\n id: uid('aact'), request_id: requestId, organization_id: raw.organization_id ?? null,\n step_name: raw.flow_node_id ?? raw.current_step ?? null, step_index: 0, action: 'remind',\n actor_id: input.actorId, comment: input.comment ?? null, created_at: nowIso,\n }, { context: SYSTEM_CTX });\n\n // Per-approver fan-out: concrete identities (user ids / emails) each get\n // their OWN one-tap approve/reject links (ADR-0043); `role:*`-style\n // literals can't carry a personal token and fall back to a plain nudge.\n let notified = 0;\n const concrete = pending.filter(a => a && !a.includes(':'));\n const literals = pending.filter(a => a && a.includes(':'));\n for (const approver of concrete) {\n try {\n const tokens = await this.issueActionTokens(requestId, approver);\n notified += await this.notify({\n topic: 'approval.reminder',\n audience: [approver],\n actorId: input.actorId,\n source: { object: 'sys_approval_request', id: requestId },\n dedupKey: `approval-remind-${requestId}-${nowIso}-${approver}`,\n payload: {\n title: 'Approval reminder',\n message: `A decision on ${raw.object_name}/${raw.record_id} is still waiting on you.`,\n actionUrl: '/system/approvals',\n actions: [\n { label: 'Approve', url: this.actionLinkUrl(tokens.approve) },\n { label: 'Reject', url: this.actionLinkUrl(tokens.reject) },\n ],\n },\n });\n } catch (err: any) {\n this.logger?.warn?.('[approvals] reminder with action links failed', {\n request: requestId, approver, error: err?.message ?? String(err),\n });\n }\n }\n if (literals.length) {\n notified += await this.notify({\n topic: 'approval.reminder',\n audience: literals,\n actorId: input.actorId,\n source: { object: 'sys_approval_request', id: requestId },\n dedupKey: `approval-remind-${requestId}-${nowIso}`,\n payload: {\n title: 'Approval reminder',\n message: `A decision on ${raw.object_name}/${raw.record_id} is still waiting on you.`,\n actionUrl: '/system/approvals',\n },\n });\n }\n\n const fresh = await this.getRequest(requestId, context);\n return { request: fresh!, notified };\n }\n\n // ── Actionable links (ADR-0043) ──────────────────────────────\n\n /** Build the session-less confirm-page URL for a raw token. */\n actionLinkUrl(rawToken: string): string {\n return `${this.publicBaseUrl}/api/v1/approvals/act?token=${encodeURIComponent(rawToken)}`;\n }\n\n /**\n * Issue one-tap approve/reject tokens for one approver on one pending\n * request. Raw tokens are returned ONCE; only SHA-256 hashes are stored\n * (`sys_approval_token`), so a DB leak yields no usable links.\n */\n async issueActionTokens(\n requestId: string,\n approverId: string,\n opts?: { ttlMs?: number },\n ): Promise<{ approve: string; reject: string }> {\n if (!approverId?.trim()) throw new Error('VALIDATION_FAILED: approverId is required');\n const raw = await this.loadPendingRow(requestId);\n const pending = csvSplit(raw.pending_approvers);\n if (!pending.includes(approverId)) {\n throw new Error(`FORBIDDEN: '${approverId}' is not a pending approver on this request`);\n }\n const now = this.clock.now();\n const expires = new Date(now.getTime() + (opts?.ttlMs ?? ACTION_TOKEN_TTL_MS)).toISOString();\n const out = { approve: '', reject: '' };\n for (const action of ['approve', 'reject'] as const) {\n const rawToken = randomBytes(32).toString('base64url');\n await this.engine.insert('sys_approval_token', {\n id: uid('atok'),\n organization_id: raw.organization_id ?? null,\n token_hash: createHash('sha256').update(rawToken).digest('hex'),\n request_id: requestId,\n action,\n approver_id: approverId,\n expires_at: expires,\n consumed_at: null,\n created_at: now.toISOString(),\n }, { context: SYSTEM_CTX });\n out[action] = rawToken;\n }\n return out;\n }\n\n /** Shared validation chain for peek/redeem. Returns the token row when live. */\n private async resolveActionToken(rawToken: string): Promise<\n { ok: true; token: any; request: ApprovalRequestRow } | Extract<ActionTokenOutcome, { ok: false }>\n > {\n const trimmed = rawToken?.trim();\n if (!trimmed) return { ok: false, reason: 'invalid' };\n const hash = createHash('sha256').update(trimmed).digest('hex');\n const rows = await this.engine.find('sys_approval_token', {\n where: { token_hash: hash }, limit: 1, context: SYSTEM_CTX,\n });\n const token: any = Array.isArray(rows) ? rows[0] : null;\n if (!token) return { ok: false, reason: 'invalid' };\n if (token.consumed_at) return { ok: false, reason: 'consumed' };\n if (Date.parse(token.expires_at) < this.clock.now().getTime()) {\n return { ok: false, reason: 'expired' };\n }\n const request = await this.getRequest(token.request_id, SYSTEM_CTX as unknown as SharingExecutionContext);\n if (!request || request.status !== 'pending') {\n return { ok: false, reason: 'not_pending', request: request ?? undefined };\n }\n if (!(request.pending_approvers ?? []).includes(token.approver_id)) {\n // Reassigned away / slot consumed by a unanimous round — the link died\n // with the slot (ADR-0043 invalidation row).\n return { ok: false, reason: 'not_approver', request };\n }\n return { ok: true, token, request };\n }\n\n /** GET confirm page: validate WITHOUT consuming — never mutates. */\n async peekActionToken(rawToken: string): Promise<ActionTokenOutcome> {\n const res = await this.resolveActionToken(rawToken);\n if (!res.ok) return res;\n return { ok: true, action: res.token.action, request: res.request, approverId: res.token.approver_id };\n }\n\n /**\n * POST redemption: consume the token FIRST (a failed decide still burns\n * it — replay-safe), then decide as the bound approver.\n */\n async redeemActionToken(rawToken: string): Promise<ActionTokenOutcome> {\n const res = await this.resolveActionToken(rawToken);\n if (!res.ok) return res;\n await this.engine.update('sys_approval_token', {\n id: res.token.id, consumed_at: this.clock.now().toISOString(),\n }, { context: SYSTEM_CTX });\n const out = await this.decide(res.token.request_id, {\n decision: res.token.action,\n actorId: res.token.approver_id,\n comment: 'Via action link',\n }, SYSTEM_CTX as unknown as SharingExecutionContext);\n return { ok: true, action: res.token.action, request: out.request, approverId: res.token.approver_id };\n }\n\n /**\n * Approver asks the submitter for more information. The request stays\n * pending — a thread interaction, not a flow decision.\n */\n async requestInfo(\n requestId: string,\n input: { actorId: string; comment: string },\n context: SharingExecutionContext,\n ): Promise<{ request: ApprovalRequestRow }> {\n if (!input?.actorId) throw new Error('VALIDATION_FAILED: actorId is required');\n if (!input?.comment?.trim()) throw new Error('VALIDATION_FAILED: comment is required');\n const raw = await this.loadPendingRow(requestId);\n const pending = csvSplit(raw.pending_approvers);\n if (!context.isSystem && !pending.includes(input.actorId)) {\n throw new Error(`FORBIDDEN: actor '${input.actorId}' is not a pending approver`);\n }\n\n const now = this.clock.now().toISOString();\n await this.engine.insert('sys_approval_action', {\n id: uid('aact'), request_id: requestId, organization_id: raw.organization_id ?? null,\n step_name: raw.flow_node_id ?? raw.current_step ?? null, step_index: 0, action: 'request_info',\n actor_id: input.actorId, comment: input.comment.trim(), created_at: now,\n }, { context: SYSTEM_CTX });\n\n if (raw.submitter_id) {\n await this.notify({\n topic: 'approval.request_info',\n audience: [String(raw.submitter_id)],\n actorId: input.actorId,\n source: { object: 'sys_approval_request', id: requestId },\n payload: {\n title: 'More information requested',\n message: input.comment.trim(),\n actionUrl: '/system/approvals',\n },\n });\n }\n\n const fresh = await this.getRequest(requestId, context);\n return { request: fresh! };\n }\n\n /** Free-form reply on the thread (submitter or any pending approver). */\n async comment(\n requestId: string,\n input: { actorId: string; comment: string; attachments?: string[] },\n context: SharingExecutionContext,\n ): Promise<{ request: ApprovalRequestRow }> {\n if (!input?.actorId) throw new Error('VALIDATION_FAILED: actorId is required');\n if (!input?.comment?.trim()) throw new Error('VALIDATION_FAILED: comment is required');\n const raw = await this.loadPendingRow(requestId);\n const pending = csvSplit(raw.pending_approvers);\n const isSubmitter = raw.submitter_id && String(raw.submitter_id) === String(input.actorId);\n if (!context.isSystem && !isSubmitter && !pending.includes(input.actorId)) {\n throw new Error(`FORBIDDEN: actor '${input.actorId}' is not on this request`);\n }\n\n const now = this.clock.now().toISOString();\n await this.engine.insert('sys_approval_action', {\n id: uid('aact'), request_id: requestId, organization_id: raw.organization_id ?? null,\n step_name: raw.flow_node_id ?? raw.current_step ?? null, step_index: 0, action: 'comment',\n actor_id: input.actorId, comment: input.comment.trim(),\n attachments: input.attachments?.length ? input.attachments : null,\n created_at: now,\n }, { context: SYSTEM_CTX });\n\n // Notify the other side of the thread.\n const audience = isSubmitter ? pending : [String(raw.submitter_id ?? '')].filter(Boolean);\n await this.notify({\n topic: 'approval.comment',\n audience,\n actorId: input.actorId,\n source: { object: 'sys_approval_request', id: requestId },\n payload: {\n title: 'New comment on an approval',\n message: input.comment.trim(),\n actionUrl: '/system/approvals',\n },\n });\n\n const fresh = await this.getRequest(requestId, context);\n return { request: fresh! };\n }\n\n // ── SLA escalation (ADR-0042) ─────────────────────────────────\n\n /**\n * One escalation sweep: every *pending* request whose node config declares\n * `escalation.timeoutHours` and whose deadline has passed is escalated\n * **at most once, ever** — the `escalate` audit row is the idempotency\n * marker, written before any mutation (audit-first, like reassign). One\n * bad row never stops the sweep.\n */\n async runEscalations(): Promise<{ scanned: number; escalated: number }> {\n let rows: any[] = [];\n try {\n rows = await this.engine.find('sys_approval_request', {\n where: { status: 'pending' }, limit: 500, context: SYSTEM_CTX,\n }) ?? [];\n } catch (err: any) {\n this.logger?.warn?.('[approvals] escalation scan failed to list requests', {\n error: err?.message ?? String(err),\n });\n return { scanned: 0, escalated: 0 };\n }\n\n let escalated = 0;\n for (const raw of rows) {\n try {\n const cfg = parseJson<any>(raw.node_config_json, undefined);\n const esc = cfg?.escalation;\n if (!esc || typeof esc.timeoutHours !== 'number' || esc.timeoutHours <= 0) continue;\n const due = slaDueAt(raw.created_at, cfg);\n if (!due || Date.parse(due) > this.clock.now().getTime()) continue;\n\n // Single-shot: a prior 'escalate' action means this request is done.\n const prior = await this.engine.find('sys_approval_action', {\n where: { request_id: raw.id, action: 'escalate' }, limit: 1, context: SYSTEM_CTX,\n });\n if (Array.isArray(prior) && prior[0]) continue;\n\n await this.escalateRequest(raw, esc);\n escalated++;\n } catch (err: any) {\n this.logger?.warn?.('[approvals] escalation failed for request', {\n request: raw?.id, error: err?.message ?? String(err),\n });\n }\n }\n if (escalated > 0) {\n this.logger?.info?.('[approvals] SLA escalation sweep', { scanned: rows.length, escalated });\n }\n return { scanned: rows.length, escalated };\n }\n\n /** Execute the configured escalation action for one overdue request. */\n private async escalateRequest(raw: any, esc: any): Promise<void> {\n const action: string = esc.action ?? 'notify';\n const escalateTo: string | undefined =\n typeof esc.escalateTo === 'string' && esc.escalateTo.trim() ? esc.escalateTo.trim() : undefined;\n const now = this.clock.now().toISOString();\n const pending = csvSplit(raw.pending_approvers);\n\n // `escalateTo` is a position machine name or a user id (same contract as\n // the `position` ApproverType, ADR-0090 D3). Position holders win; an\n // empty expansion falls back to the literal, so a config naming a\n // specific user id keeps working unchanged.\n let escalatees: string[] = [];\n if (escalateTo) {\n try {\n escalatees = await this.expandPositionUsers(escalateTo, raw.organization_id ?? null);\n } catch { escalatees = []; }\n if (!escalatees.length) escalatees = [escalateTo];\n }\n\n // Audit first — this row IS the idempotency marker (ADR-0042 §1).\n await this.engine.insert('sys_approval_action', {\n id: uid('aact'), request_id: raw.id, organization_id: raw.organization_id ?? null,\n step_name: raw.flow_node_id ?? raw.current_step ?? null, step_index: 0, action: 'escalate',\n actor_id: SLA_ACTOR_ID,\n comment: `${action}${escalateTo ? ` → ${escalateTo}` : ''}`,\n created_at: now,\n }, { context: SYSTEM_CTX });\n\n if (action === 'reassign' && escalatees.length) {\n await this.engine.update('sys_approval_request', {\n id: raw.id, pending_approvers: escalatees.join(','), updated_at: now,\n }, { context: SYSTEM_CTX });\n await this.syncApproverIndex(raw.id, escalatees, raw.organization_id ?? null, now);\n await this.notify({\n topic: 'approval.escalated',\n audience: escalatees,\n actorId: SLA_ACTOR_ID,\n source: { object: 'sys_approval_request', id: raw.id },\n payload: {\n title: 'Approval escalated to you',\n message: `An overdue approval on ${raw.object_name}/${raw.record_id} was escalated to you.`,\n actionUrl: '/system/approvals',\n },\n });\n } else if (action === 'auto_approve' || action === 'auto_reject') {\n await this.decide(raw.id, {\n decision: action === 'auto_approve' ? 'approve' : 'reject',\n actorId: SLA_ACTOR_ID,\n comment: 'SLA escalation',\n }, SYSTEM_CTX as unknown as SharingExecutionContext);\n } else {\n // 'notify' (and the reassign-without-target fallback)\n await this.notify({\n topic: 'approval.sla_breached',\n audience: [...pending, ...escalatees],\n actorId: SLA_ACTOR_ID,\n source: { object: 'sys_approval_request', id: raw.id },\n payload: {\n title: 'Approval SLA breached',\n message: `A decision on ${raw.object_name}/${raw.record_id} is overdue.`,\n actionUrl: '/system/approvals',\n },\n });\n }\n\n if (esc.notifySubmitter !== false && raw.submitter_id) {\n await this.notify({\n topic: 'approval.sla_breached',\n audience: [String(raw.submitter_id)],\n actorId: SLA_ACTOR_ID,\n source: { object: 'sys_approval_request', id: raw.id },\n payload: {\n title: 'Your approval request breached its SLA',\n message: `${raw.object_name}/${raw.record_id}: escalation action '${action}' was taken.`,\n actionUrl: '/system/approvals',\n },\n });\n }\n }\n\n // ── Display enrichment ───────────────────────────────────────\n\n /**\n * Resolve the schema-declared display field for an object, when the engine\n * exposes schema metadata (`getSchema`). Falls back to common title-ish\n * field names so plain `ApprovalEngine` fakes still enrich sensibly.\n */\n private resolveDisplayField(object: string): string | undefined {\n try {\n const schema: any = (this.engine as any).getSchema?.(object);\n const fields = schema?.fields ?? {};\n // [ADR-0079] `nameField` is the canonical primary-title pointer;\n // `displayNameField` is the deprecated alias (still honored).\n const declared = schema?.nameField ?? schema?.displayNameField;\n if (declared && declared !== 'id' && fields[declared]) return declared;\n for (const cand of ['name', 'title', 'subject', 'label']) {\n if (fields[cand]) return cand;\n }\n } catch { /* schema unavailable — heuristics below still apply */ }\n return undefined;\n }\n\n private static pickTitle(rec: any, displayField?: string): string | undefined {\n const candidates = displayField\n ? [displayField, 'name', 'title', 'subject', 'label']\n : ['name', 'title', 'subject', 'label'];\n for (const f of candidates) {\n const v = rec?.[f];\n if (v != null && String(v).trim() && f !== 'id') return String(v);\n }\n return undefined;\n }\n\n /**\n * Batch-resolve `sys_user` display names for identifiers that may be user\n * ids or emails. Best-effort — failures leave entries unresolved.\n */\n private async resolveUserNames(identifiers: Array<string | null | undefined>): Promise<Map<string, string>> {\n const names = new Map<string, string>();\n const targets = Array.from(new Set(identifiers.filter(Boolean))) as string[];\n if (!targets.length) return names;\n try {\n const users = await this.engine.find('sys_user', {\n where: { id: { $in: targets } }, fields: ['id', 'name', 'email'],\n limit: targets.length, context: SYSTEM_CTX,\n });\n for (const u of (users ?? []) as any[]) {\n if (u?.id && (u.name || u.email)) names.set(String(u.id), String(u.name ?? u.email));\n }\n } catch { /* best-effort */ }\n const unresolvedEmails = targets.filter(t => !names.has(t) && t.includes('@'));\n if (unresolvedEmails.length) {\n try {\n const users = await this.engine.find('sys_user', {\n where: { email: { $in: unresolvedEmails } }, fields: ['email', 'name'],\n limit: unresolvedEmails.length, context: SYSTEM_CTX,\n });\n for (const u of (users ?? []) as any[]) {\n if (u?.email && u.name) names.set(String(u.email), String(u.name));\n }\n } catch { /* best-effort */ }\n }\n return names;\n }\n\n /** Lookup-typed fields (key + referenced object) of an object's schema. */\n private resolveLookupFields(object: string): Array<{ key: string; reference: string }> {\n try {\n const schema: any = (this.engine as any).getSchema?.(object);\n const fields = schema?.fields ?? {};\n const out: Array<{ key: string; reference: string }> = [];\n for (const [key, f] of Object.entries<any>(fields)) {\n if ((f?.type === 'lookup' || f?.type === 'master_detail' || f?.type === 'user') && f?.reference) {\n out.push({ key, reference: String(f.reference) });\n }\n }\n return out;\n } catch { return []; }\n }\n\n /**\n * Attach inbox display fields to rows so clients never render a raw\n * identifier: `record_title`, `submitter_name`, `object_label`,\n * `pending_approver_names` (user-id approvers), and `payload_display`\n * (lookup foreign keys in the snapshot → referenced record titles).\n * Batched: one query per distinct object (target + referenced) plus one\n * `sys_user` lookup. Best-effort — a deleted record falls back to the\n * payload snapshot, and any failure leaves the field unset rather than\n * failing the list.\n */\n private async enrichRows(rows: ApprovalRequestRow[]): Promise<void> {\n if (!rows.length) return;\n\n // Record titles + object labels, batched per object.\n const byObject = new Map<string, Set<string>>();\n for (const r of rows) {\n if (!r.object_name || !r.record_id) continue;\n let set = byObject.get(r.object_name);\n if (!set) { set = new Set(); byObject.set(r.object_name, set); }\n set.add(r.record_id);\n }\n const titles = new Map<string, string>();\n const objectLabels = new Map<string, string>();\n for (const [object, idSet] of byObject) {\n try {\n const schema: any = (this.engine as any).getSchema?.(object);\n if (schema?.label) objectLabels.set(object, String(schema.label));\n } catch { /* label optional */ }\n const ids = Array.from(idSet);\n const displayField = this.resolveDisplayField(object);\n try {\n const recs = await this.engine.find(object, {\n where: { id: { $in: ids } }, limit: ids.length, context: SYSTEM_CTX,\n });\n for (const rec of (recs ?? []) as any[]) {\n const title = ApprovalService.pickTitle(rec, displayField);\n if (rec?.id && title) titles.set(`${object} ${rec.id}`, title);\n }\n } catch { /* object may be unregistered — payload fallback below */ }\n }\n\n // Lookup foreign keys inside payload snapshots → referenced record titles.\n const lookupFieldsByObject = new Map<string, Array<{ key: string; reference: string }>>();\n for (const object of byObject.keys()) {\n const lookups = this.resolveLookupFields(object);\n if (lookups.length) lookupFieldsByObject.set(object, lookups);\n }\n const refIds = new Map<string, Set<string>>();\n for (const r of rows) {\n const lookups = lookupFieldsByObject.get(r.object_name);\n const payload: any = r.payload;\n if (!lookups || !payload || typeof payload !== 'object') continue;\n for (const { key, reference } of lookups) {\n const v = payload[key];\n if (v == null || typeof v === 'object' || !String(v).trim()) continue;\n let set = refIds.get(reference);\n if (!set) { set = new Set(); refIds.set(reference, set); }\n set.add(String(v));\n }\n }\n const refTitles = new Map<string, string>();\n for (const [object, idSet] of refIds) {\n const ids = Array.from(idSet);\n const displayField = this.resolveDisplayField(object);\n try {\n const recs = await this.engine.find(object, {\n where: { id: { $in: ids } }, limit: ids.length, context: SYSTEM_CTX,\n });\n for (const rec of (recs ?? []) as any[]) {\n const title = ApprovalService.pickTitle(rec, displayField);\n if (rec?.id && title) refTitles.set(`${object} ${rec.id}`, title);\n }\n } catch { /* referenced object unreadable — leave unresolved */ }\n }\n\n // Display names for submitters AND user-id approvers in one lookup.\n // `role:<r>` (and other `type:value` literals) are already readable.\n const userIdentifiers: Array<string | null | undefined> = [];\n for (const r of rows) {\n userIdentifiers.push(r.submitter_id);\n for (const a of r.pending_approvers ?? []) {\n if (a && !a.includes(':')) userIdentifiers.push(a);\n }\n }\n const names = await this.resolveUserNames(userIdentifiers);\n\n for (const r of rows as any[]) {\n const title = titles.get(`${r.object_name} ${r.record_id}`)\n ?? ApprovalService.pickTitle(r.payload, undefined);\n if (title) r.record_title = title;\n const name = r.submitter_id ? names.get(String(r.submitter_id)) : undefined;\n if (name) r.submitter_name = name;\n const label = objectLabels.get(r.object_name);\n if (label) r.object_label = label;\n\n const approverNames: Record<string, string> = {};\n for (const a of r.pending_approvers ?? []) {\n const n = names.get(String(a));\n if (n) approverNames[a] = n;\n }\n if (Object.keys(approverNames).length) r.pending_approver_names = approverNames;\n\n const lookups = lookupFieldsByObject.get(r.object_name);\n if (lookups && r.payload && typeof r.payload === 'object') {\n const display: Record<string, string> = {};\n for (const { key, reference } of lookups) {\n const v = (r.payload as any)[key];\n if (v == null) continue;\n const t = refTitles.get(`${reference} ${String(v)}`);\n if (t) display[key] = t;\n }\n if (Object.keys(display).length) r.payload_display = display;\n }\n }\n }\n\n // ── Pending-approver index (issue #1745) ─────────────────────\n\n /**\n * Mirror one request's `pending_approvers` CSV into the normalized\n * `sys_approval_approver` index. Called by every write path that changes\n * the approver set; an empty `approvers` clears the request's rows (the\n * request left `pending`). Diff-based so reassign/unanimous churn doesn't\n * rewrite untouched rows.\n */\n private async syncApproverIndex(\n requestId: string,\n approvers: string[],\n org: string | null,\n now: string,\n ): Promise<void> {\n const desired = new Set(approvers.map(a => String(a).trim()).filter(Boolean));\n const existing = await this.engine.find('sys_approval_approver', {\n where: { request_id: requestId }, limit: 500, context: SYSTEM_CTX,\n });\n const rows: any[] = Array.isArray(existing) ? existing : [];\n for (const row of rows) {\n if (desired.has(String(row.approver))) desired.delete(String(row.approver));\n else await this.engine.delete('sys_approval_approver', { where: { id: row.id }, context: SYSTEM_CTX });\n }\n for (const approver of desired) {\n await this.engine.insert('sys_approval_approver', {\n id: uid('aapr'), request_id: requestId, approver,\n organization_id: org, created_at: now,\n }, { context: SYSTEM_CTX });\n }\n }\n\n /**\n * Rebuild the whole `sys_approval_approver` index from the CSV source of\n * truth. Idempotent; run at plugin start so rows written before the index\n * existed (or drifted past a crashed sync) become queryable. Cost tracks\n * the number of *pending* requests, not the request history.\n */\n async rebuildApproverIndex(): Promise<{ requests: number; inserted: number; deleted: number }> {\n // Desired state: every pending request's CSV entries.\n const desired = new Map<string, { approvers: Set<string>; org: string | null }>();\n const PAGE = 500;\n for (let offset = 0; ; offset += PAGE) {\n const batch = await this.engine.find('sys_approval_request', {\n where: { status: 'pending' },\n fields: ['id', 'pending_approvers', 'organization_id'],\n limit: PAGE, offset, context: SYSTEM_CTX,\n });\n const rows: any[] = Array.isArray(batch) ? batch : [];\n for (const r of rows) {\n desired.set(String(r.id), {\n approvers: new Set(csvSplit(r.pending_approvers)),\n org: r.organization_id ?? null,\n });\n }\n if (rows.length < PAGE) break;\n }\n\n // Current state: read the whole index first (bounded by the live work\n // queue), THEN mutate — deleting while paginating would shift the cursor.\n const indexRows: any[] = [];\n for (let offset = 0; ; offset += PAGE) {\n const batch = await this.engine.find('sys_approval_approver', {\n orderBy: [{ field: 'created_at', order: 'asc' }],\n limit: PAGE, offset, context: SYSTEM_CTX,\n });\n const rows: any[] = Array.isArray(batch) ? batch : [];\n indexRows.push(...rows);\n if (rows.length < PAGE) break;\n }\n let inserted = 0; let deleted = 0;\n const seen = new Map<string, Set<string>>();\n for (const row of indexRows) {\n const reqId = String(row.request_id);\n const want = desired.get(reqId);\n const have = seen.get(reqId) ?? seen.set(reqId, new Set()).get(reqId)!;\n // Orphan (request no longer pending), stale entry, or duplicate → drop.\n if (!want || !want.approvers.has(String(row.approver)) || have.has(String(row.approver))) {\n await this.engine.delete('sys_approval_approver', { where: { id: row.id }, context: SYSTEM_CTX });\n deleted++;\n continue;\n }\n have.add(String(row.approver));\n }\n\n const now = this.clock.now().toISOString();\n for (const [reqId, want] of desired) {\n const have = seen.get(reqId);\n for (const approver of want.approvers) {\n if (have?.has(approver)) continue;\n await this.engine.insert('sys_approval_approver', {\n id: uid('aapr'), request_id: reqId, approver,\n organization_id: want.org, created_at: now,\n }, { context: SYSTEM_CTX });\n inserted++;\n }\n }\n return { requests: desired.size, inserted, deleted };\n }\n\n // ── Read API ─────────────────────────────────────────────────\n\n /** Filter type accepted by {@link listRequests} / {@link countRequests}. */\n private buildRequestWhere(\n filter: {\n object?: string;\n recordId?: string;\n status?: ApprovalStatus | ApprovalStatus[];\n submitterId?: string;\n q?: string;\n } | undefined,\n context: SharingExecutionContext,\n ): { where: any; tenantOrg: string | null } {\n const f: any = {};\n if (filter?.object) f.object_name = filter.object;\n if (filter?.recordId) f.record_id = filter.recordId;\n if (filter?.submitterId) f.submitter_id = filter.submitterId;\n // Tenant isolation: when a caller context carries a tenant identifier\n // (organizationId / tenantId), scope the query to that tenant. SYSTEM\n // callers (no tenant) see all rows. This prevents the bespoke endpoint\n // from leaking other-tenant rows since we deliberately query with\n // SYSTEM_CTX to bypass RLS on the engine (the approver-visibility rule\n // spans three identity forms, which RLS can't model cleanly).\n const tenantOrg = (context as any)?.organizationId ?? (context as any)?.tenantId ?? null;\n if (tenantOrg) f.organization_id = tenantOrg;\n // Free-text search, pushed down: `payload_json` carries the record\n // snapshot, so record titles match without any join. `$contains` is the\n // driver's escaped-LIKE operator.\n const q = filter?.q?.trim();\n if (q) {\n f.$or = [\n { process_name: { $contains: q } },\n { object_name: { $contains: q } },\n { record_id: { $contains: q } },\n { submitter_id: { $contains: q } },\n { payload_json: { $contains: q } },\n ];\n }\n // Status pushes down whole: `$in` for arrays (all bundled drivers\n // support it), equality for a single value.\n if (Array.isArray(filter?.status)) {\n const statuses = (filter!.status as ApprovalStatus[]).filter(Boolean);\n if (statuses.length === 1) f.status = statuses[0];\n else if (statuses.length > 1) f.status = { $in: statuses };\n } else if (filter?.status) {\n f.status = filter.status;\n }\n return { where: f, tenantOrg };\n }\n\n /** Window the approver-index probe — pending queues live far below this. */\n private static readonly APPROVER_INDEX_CAP = 10_000;\n\n /**\n * Resolve an approver filter to matching request ids via the normalized\n * `sys_approval_approver` index — the indexed replacement for the old\n * in-memory CSV scan, and what makes approver-filtered pagination correct\n * past any scan window (issue #1745). A request matches when ANY of the\n * caller's identities (user id / email / role:<r>) holds a pending slot.\n * Returns null when the filter is absent (callers skip the id constraint).\n */\n private async approverRequestIds(\n targets: string[],\n tenantOrg: string | null,\n ): Promise<string[] | null> {\n if (!targets.length) return null;\n const where: any = targets.length === 1\n ? { approver: targets[0] }\n : { approver: { $in: targets } };\n if (tenantOrg) where.organization_id = tenantOrg;\n const rows = await this.engine.find('sys_approval_approver', {\n where, fields: ['request_id'],\n limit: ApprovalService.APPROVER_INDEX_CAP, context: SYSTEM_CTX,\n });\n const list: any[] = Array.isArray(rows) ? rows : [];\n if (list.length >= ApprovalService.APPROVER_INDEX_CAP) {\n this.logger?.warn?.('[approvals] approver index probe hit its window — results may be truncated', {\n cap: ApprovalService.APPROVER_INDEX_CAP, targets: targets.length,\n });\n }\n return [...new Set<string>(list.map(r => String(r.request_id)))];\n }\n\n async listRequests(\n filter: {\n object?: string;\n recordId?: string;\n status?: ApprovalStatus | ApprovalStatus[];\n approverId?: string | string[];\n submitterId?: string;\n q?: string;\n limit?: number;\n offset?: number;\n } | undefined,\n context: SharingExecutionContext,\n ): Promise<ApprovalRequestRow[]> {\n const { where, tenantOrg } = this.buildRequestWhere(filter, context);\n const approverTargets = (Array.isArray(filter?.approverId) ? filter!.approverId : filter?.approverId ? [filter.approverId] : [])\n .map(t => String(t).trim())\n .filter(Boolean);\n\n // Every filter now pushes into the engine (issue #1745): approver via\n // the normalized index, status arrays via $in — so the page window is\n // always engine-side and correct at any table size.\n const ids = await this.approverRequestIds(approverTargets, tenantOrg);\n if (ids) {\n if (ids.length === 0) return [];\n where.id = ids.length === 1 ? ids[0] : { $in: ids };\n }\n\n const findOpts: any = {\n where,\n orderBy: [{ field: 'created_at', order: 'desc' }],\n context: SYSTEM_CTX,\n };\n if (filter?.limit != null || filter?.offset != null) {\n findOpts.limit = Math.min(Math.max(filter?.limit ?? 50, 1), 200);\n if (filter?.offset) findOpts.offset = Math.max(filter.offset, 0);\n } else {\n // Unpaginated callers keep the legacy bounded window.\n findOpts.limit = 500;\n }\n\n const rows = await this.engine.find('sys_approval_request', findOpts);\n const list = Array.isArray(rows) ? rows.map(rowFromRequest) : [];\n await this.enrichRows(list);\n return list;\n }\n\n async countRequests(\n filter: Parameters<IApprovalService['listRequests']>[0],\n context: SharingExecutionContext,\n ): Promise<number> {\n const { where, tenantOrg } = this.buildRequestWhere(filter, context);\n const approverTargets = (Array.isArray(filter?.approverId) ? filter!.approverId : filter?.approverId ? [filter.approverId] : [])\n .map(t => String(t).trim())\n .filter(Boolean);\n\n const ids = await this.approverRequestIds(approverTargets, tenantOrg);\n if (ids) {\n if (ids.length === 0) return 0;\n where.id = ids.length === 1 ? ids[0] : { $in: ids };\n }\n\n const countFn = (this.engine as any).count;\n if (typeof countFn === 'function') {\n try {\n const n = await countFn.call(this.engine, 'sys_approval_request', { where, context: SYSTEM_CTX });\n if (typeof n === 'number') return n;\n } catch { /* fall through to scan */ }\n }\n // Engine without count(): bounded scan. The approver-filtered case is\n // exact (the id set bounds it); the unfiltered case keeps the legacy\n // 500 window.\n const rows = await this.engine.find('sys_approval_request', {\n where, fields: ['id'], limit: ids ? Math.max(500, ids.length) : 500, context: SYSTEM_CTX,\n });\n return Array.isArray(rows) ? rows.length : 0;\n }\n\n async getRequest(requestId: string, context: SharingExecutionContext): Promise<ApprovalRequestRow | null> {\n if (!requestId) return null;\n const where: any = { id: requestId };\n const tenantOrg = (context as any)?.organizationId ?? (context as any)?.tenantId;\n if (tenantOrg) where.organization_id = tenantOrg;\n const rows = await this.engine.find('sys_approval_request', {\n where, limit: 1, context: SYSTEM_CTX,\n });\n if (!Array.isArray(rows) || !rows[0]) return null;\n const row = rowFromRequest(rows[0]);\n await this.enrichRows([row]);\n await this.attachFlowSteps(row);\n await this.attachDecisionProgress(row, rows[0]);\n return row;\n }\n\n /**\n * Server-computed decision aggregation progress (#3266 / objectui#2678 P1.5).\n * Single-read enrichment only (like {@link ApprovalService.attachFlowSteps}):\n * for a PENDING request whose behavior aggregates multiple approvals\n * (`unanimous` / `quorum` / `per_group`), expose\n * `decision_progress: { behavior, got, need, groups? }` so any client renders\n * \"2 of 3\" or per-group ticks without re-deriving the engine's tally rules.\n * `first_response` requests carry no progress (one approval finalizes).\n * Display-only and best-effort — errors leave the row untouched.\n */\n private async attachDecisionProgress(row: ApprovalRequestRow, raw: any): Promise<void> {\n try {\n if (row.status !== 'pending') return;\n const cfg = parseJson<any>(raw.node_config_json, undefined);\n const behavior = cfg?.behavior ?? 'first_response';\n if (behavior !== 'unanimous' && behavior !== 'quorum' && behavior !== 'per_group') return;\n\n const acts = await this.engine.find('sys_approval_action', {\n where: { request_id: row.id, step_index: 0, action: 'approve' }, limit: 1000, context: SYSTEM_CTX,\n });\n const approved = new Set<string>((acts ?? []).map((a: any) => String(a.actor_id ?? '')).filter(Boolean));\n\n const snapshot = cfg?.__approverGroups as Record<string, string[]> | undefined;\n const slate = snapshot ? Object.keys(snapshot) : [...approved, ...(row.pending_approvers ?? [])];\n const total = slate.length || 1;\n\n const progress: any = { behavior, got: approved.size, need: total };\n if (behavior === 'quorum') {\n progress.need = Math.min(Math.max(1, cfg?.minApprovals ?? total), total);\n } else if (behavior === 'per_group' && snapshot) {\n const perGroupNeed = Math.max(1, cfg?.minApprovals ?? 1);\n const size: Record<string, number> = {};\n for (const gs of Object.values(snapshot)) for (const g of gs) size[g] = (size[g] ?? 0) + 1;\n const got: Record<string, number> = {};\n for (const a of approved) for (const g of (snapshot[a] ?? [])) got[g] = (got[g] ?? 0) + 1;\n progress.groups = Object.keys(size).sort().map(g => {\n const need = Math.min(perGroupNeed, size[g]);\n return { group: g, got: Math.min(got[g] ?? 0, need), need, satisfied: (got[g] ?? 0) >= need };\n });\n progress.got = progress.groups.filter((g: any) => g.satisfied).length;\n progress.need = progress.groups.length;\n }\n (row as any).decision_progress = progress;\n } catch { /* display-only enrichment */ }\n }\n\n /**\n * Derive approval-step progress from the owning flow's graph (single-read\n * enrichment only — list reads skip it). Walks from the start node\n * preferring `approve`/`true` edges, so the result is the flow's main\n * approval trunk; conditional side-steps show as part of the potential\n * path. Display-only and best-effort.\n */\n private async attachFlowSteps(row: ApprovalRequestRow): Promise<void> {\n try {\n const flowName = row.process_name?.startsWith('flow:') ? row.process_name.slice(5) : undefined;\n if (!flowName || typeof this.automation?.getFlow !== 'function') return;\n const flow: any = await this.automation.getFlow(flowName);\n if (!flow?.nodes?.length) return;\n const nodesById = new Map<string, any>(flow.nodes.map((n: any) => [n.id, n]));\n const steps: Array<{ id: string; label: string }> = [];\n const seen = new Set<string>();\n let cur: any = flow.nodes.find((n: any) => n.type === 'start');\n while (cur && !seen.has(cur.id)) {\n seen.add(cur.id);\n if (cur.type === 'approval') steps.push({ id: cur.id, label: cur.label || cur.id });\n const out = (flow.edges ?? []).filter((e: any) => e.source === cur.id);\n if (!out.length) break;\n const pick = out.find((e: any) => e.label === 'approve')\n ?? out.find((e: any) => e.label === 'true')\n ?? out[0];\n cur = nodesById.get(pick.target);\n }\n if (steps.length === 0) return;\n const currentId = row.flow_node_id ?? row.current_step;\n const currentIdx = steps.findIndex(s => s.id === currentId);\n (row as any).flow_steps = steps.map((s, i) => ({\n ...s,\n state: currentIdx < 0 ? 'upcoming'\n : i < currentIdx ? 'done'\n : i === currentIdx ? (row.status === 'approved' ? 'done' : 'current')\n : 'upcoming',\n }));\n } catch { /* display-only — never fail the read */ }\n }\n\n async listActions(requestId: string, context: SharingExecutionContext): Promise<ApprovalActionRow[]> {\n if (!requestId) return [];\n // Tenant gate: ensure the caller can see the parent request before\n // returning its action history. Skipping this would leak history rows\n // across tenants the same way the unscoped list-requests path did.\n const req = await this.getRequest(requestId, context);\n if (!req) return [];\n const rows = await this.engine.find('sys_approval_action', {\n where: { request_id: requestId },\n limit: 500,\n orderBy: [{ field: 'created_at', order: 'asc' }],\n context: SYSTEM_CTX,\n });\n const actions = Array.isArray(rows) ? rows.map(rowFromAction) : [];\n // Timeline display: resolve actor ids to names so the audit trail never\n // shows a raw identifier. Role/team literals are already readable.\n const names = await this.resolveUserNames(\n actions.map(a => a.actor_id).filter(id => id && !id.includes(':')),\n );\n for (const a of actions as any[]) {\n const n = a.actor_id ? names.get(String(a.actor_id)) : undefined;\n if (n) a.actor_name = n;\n }\n return actions;\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { ObjectSchema, Field } from '@objectstack/spec/data';\n\n/**\n * sys_approval_token — single-use actionable-link tokens (ADR-0043).\n *\n * One row per issued approve/reject link. Only the SHA-256 **hash** of the\n * raw token is stored — a database leak yields no usable links. A token is\n * dead once any of these holds: `consumed_at` set, `expires_at` passed, the\n * request left `pending`, or the bound approver no longer holds a slot\n * (the last two are re-checked at redemption, not materialized here).\n *\n * @namespace sys\n */\nexport const SysApprovalToken = ObjectSchema.create({\n name: 'sys_approval_token',\n label: 'Approval Action Token',\n pluralLabel: 'Approval Action Tokens',\n icon: 'key',\n isSystem: true,\n managedBy: 'system',\n description: 'Single-use tokens behind actionable approval links',\n displayNameField: 'id',\n nameField: 'id', // [ADR-0079] canonical primary-title pointer (mirrors deprecated displayNameField)\n\n fields: {\n id: Field.text({ label: 'Token ID', required: true, readonly: true, group: 'System' }),\n\n organization_id: Field.lookup('sys_organization', {\n label: 'Organization',\n required: false,\n group: 'System',\n }),\n\n token_hash: Field.text({\n label: 'Token Hash',\n required: true,\n maxLength: 100,\n readonly: true,\n description: 'SHA-256 hex of the raw token — the raw value is never stored',\n group: 'Token',\n }),\n\n request_id: Field.text({\n label: 'Request',\n required: true,\n maxLength: 100,\n readonly: true,\n group: 'Token',\n }),\n\n action: Field.select(['approve', 'reject'], {\n label: 'Action',\n required: true,\n readonly: true,\n group: 'Token',\n }),\n\n approver_id: Field.text({\n label: 'Approver',\n required: true,\n maxLength: 200,\n readonly: true,\n description: 'Identity the token is bound to; the decision is audited as this approver',\n group: 'Token',\n }),\n\n expires_at: Field.datetime({\n label: 'Expires At',\n required: true,\n readonly: true,\n group: 'Lifecycle',\n }),\n\n consumed_at: Field.datetime({\n label: 'Consumed At',\n required: false,\n group: 'Lifecycle',\n }),\n\n created_at: Field.datetime({\n label: 'Created At',\n required: true,\n defaultValue: 'NOW()',\n readonly: true,\n group: 'System',\n }),\n },\n\n indexes: [\n { fields: ['token_hash'] },\n { fields: ['request_id'] },\n ],\n\n enable: {\n // [ADR-0103] Engine-owned: one-time email-approval tokens are minted and\n // consumed by the approval engine (SYSTEM_CTX), never via the data API.\n apiMethods: ['get', 'list'],\n },\n});\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * Session-less HTML for the actionable-link confirm/result pages (ADR-0043).\n *\n * Deliberately tiny and dependency-free: these pages are reached from an\n * email or IM message by a bearer with no session, so they must not assume\n * the Console bundle, auth state, or client-side i18n. Static bilingual\n * (EN / 中文) copy keeps them readable for the demo audience without a\n * locale negotiation step.\n *\n * The GET page NEVER mutates — the decision happens only on the POST form\n * submit (mail-gateway link prefetchers must not approve requests).\n */\n\nimport type { ApprovalRequestRow, ApprovalActionKind } from '@objectstack/spec/contracts';\n\nfunction esc(s: unknown): string {\n return String(s ?? '')\n .replaceAll('&', '&').replaceAll('<', '<').replaceAll('>', '>')\n .replaceAll('\"', '"').replaceAll(\"'\", ''');\n}\n\nfunction shell(title: string, body: string): string {\n return `<!doctype html>\n<html lang=\"en\"><head><meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n<meta name=\"robots\" content=\"noindex\">\n<title>${esc(title)}</title>\n<style>\n body{font:15px/1.6 -apple-system,BlinkMacSystemFont,\"Segoe UI\",Roboto,\"PingFang SC\",\"Microsoft YaHei\",sans-serif;\n background:#f6f7f9;color:#1a202c;margin:0;display:flex;min-height:100vh;align-items:center;justify-content:center}\n .card{background:#fff;border:1px solid #e2e8f0;border-radius:12px;max-width:440px;width:calc(100% - 32px);\n padding:28px 32px;box-shadow:0 1px 3px rgba(0,0,0,.06)}\n h1{font-size:18px;margin:0 0 4px}\n .sub{color:#64748b;font-size:13px;margin:0 0 20px}\n .row{display:flex;justify-content:space-between;gap:12px;padding:7px 0;border-bottom:1px solid #f1f5f9;font-size:14px}\n .row b{font-weight:600;text-align:right}\n .k{color:#64748b}\n .actions{margin-top:22px;display:flex;gap:10px}\n button{flex:1;padding:10px 16px;border-radius:8px;border:1px solid transparent;font-size:15px;font-weight:600;cursor:pointer}\n .approve{background:#059669;color:#fff}\n .reject{background:#fff;color:#dc2626;border-color:#fca5a5}\n .badge{display:inline-block;padding:2px 10px;border-radius:999px;font-size:12px;font-weight:600;margin-bottom:14px}\n .ok{background:#ecfdf5;color:#047857}.warn{background:#fffbeb;color:#b45309}.err{background:#fef2f2;color:#b91c1c}\n a{color:#2563eb;text-decoration:none}\n .foot{margin-top:18px;font-size:12px;color:#94a3b8}\n</style></head><body><div class=\"card\">${body}</div></body></html>`;\n}\n\nfunction summaryRows(req: ApprovalRequestRow): string {\n const rows: Array<[string, string]> = [\n ['Process · 流程', req.process_label || req.process_name],\n ['Step · 步骤', req.step_label || req.current_step || '—'],\n ['Record · 记录', req.record_title || req.record_id],\n ['Object · 对象', req.object_label || req.object_name],\n ['Requester · 申请人', req.submitter_name || req.submitter_id || '—'],\n ];\n return rows.map(([k, v]) => `<div class=\"row\"><span class=\"k\">${esc(k)}</span><b>${esc(v)}</b></div>`).join('');\n}\n\n/** GET page: summary + a POST form. Rendering only — no mutation. */\nexport function renderConfirmPage(input: {\n request: ApprovalRequestRow;\n action: Extract<ApprovalActionKind, 'approve' | 'reject'>;\n approverId: string;\n token: string;\n actPath: string;\n}): string {\n const approving = input.action === 'approve';\n const verb = approving ? 'Approve · 通过' : 'Reject · 拒绝';\n return shell(`${verb} — Approval`, `\n <h1>${approving ? '✅ Approve this request?' : '⛔ Reject this request?'}</h1>\n <p class=\"sub\">${approving ? '确认通过该审批请求?' : '确认拒绝该审批请求?'}\n Acting as · 操作身份:<b>${esc(input.approverId)}</b></p>\n ${summaryRows(input.request)}\n <form method=\"post\" action=\"${esc(input.actPath)}\" class=\"actions\">\n <input type=\"hidden\" name=\"token\" value=\"${esc(input.token)}\">\n <button type=\"submit\" class=\"${approving ? 'approve' : 'reject'}\">${verb}</button>\n </form>\n <p class=\"foot\">This link is single-use and expires automatically. · 此链接一次有效,过期自动失效。</p>`);\n}\n\nconst RESULT_COPY: Record<string, { cls: string; title: string; body: string }> = {\n approved: { cls: 'ok', title: '✅ Approved · 已通过', body: 'The decision was recorded. · 审批结果已记录。' },\n rejected: { cls: 'ok', title: '⛔ Rejected · 已拒绝', body: 'The decision was recorded. · 审批结果已记录。' },\n invalid: { cls: 'err', title: 'Invalid link · 链接无效', body: 'This link is not recognized. · 无法识别该链接。' },\n expired: { cls: 'warn', title: 'Link expired · 链接已过期', body: 'Ask the requester to send a new reminder. · 请让申请人重新发送催办。' },\n consumed: { cls: 'warn', title: 'Already used · 链接已使用', body: 'This link was already used once. · 该链接已被使用过。' },\n not_pending: { cls: 'warn', title: 'Already decided · 请求已处理', body: 'This request is no longer pending. · 该请求已不在待审批状态。' },\n not_approver: { cls: 'warn', title: 'No longer your approval · 已不在你名下', body: 'This approval was handed to someone else. · 该审批已转由他人处理。' },\n};\n\n/** Terminal page for every redemption outcome (and stale GETs). */\nexport function renderResultPage(kind: keyof typeof RESULT_COPY, request?: ApprovalRequestRow): string {\n const copy = RESULT_COPY[kind] ?? RESULT_COPY.invalid;\n return shell(copy.title, `\n <span class=\"badge ${copy.cls}\">${esc(copy.title)}</span>\n ${request ? summaryRows(request) : ''}\n <p>${esc(copy.body)}</p>\n <p class=\"foot\"><a href=\"/system/approvals\">Open the Approvals Inbox · 打开审批中心</a></p>`);\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * Lifecycle Hooks — node-era record lock (ADR-0019).\n *\n * Approval is now a flow node, so there is no per-object process registry to\n * bind auto-trigger hooks against — a flow decides *when* to open an approval.\n * What remains worth enforcing at the data layer is the **record lock**: while\n * a record has a pending `sys_approval_request`, block edits to it.\n *\n * A single global `beforeUpdate` hook handles every object (the target object\n * of an approval node is only known at flow-run time). For each update it:\n *\n * 1. Skips engine self-writes (status mirror) and `sys_approval_*` bookkeeping.\n * 2. Looks up a pending request for `(object, recordId)`.\n * 3. Reads the lock policy from that request's `node_config_json` snapshot:\n * - `lockRecord === false` → allow.\n * - otherwise block, EXCEPT when the only changed field is the configured\n * `approvalStatusField` (so the status mirror is never blocked) or the\n * caller is an `admin`.\n *\n * Registered under `packageId: 'plugin-approvals:lock'` so it can be cleanly\n * unbound on plugin stop.\n */\n\nexport const APPROVALS_HOOK_PACKAGE = 'plugin-approvals:lock';\n\ninterface MinimalEngine {\n registerHook(event: string, handler: (ctx: any) => any | Promise<any>, options?: {\n object?: string | string[];\n priority?: number;\n packageId?: string;\n }): void;\n unregisterHooksByPackage(packageId: string): number;\n find<T = any>(object: string, args: any, opts?: any): Promise<T[]>;\n}\n\ninterface MinimalLogger {\n debug?: (msg: any, ...rest: any[]) => void;\n info?: (msg: any, ...rest: any[]) => void;\n warn?: (msg: any, ...rest: any[]) => void;\n error?: (msg: any, ...rest: any[]) => void;\n}\n\nfunction parseJson<T = any>(raw: unknown, fallback: T): T {\n if (raw == null || raw === '') return fallback;\n if (typeof raw === 'string') {\n try { return JSON.parse(raw) as T; } catch { return fallback; }\n }\n return raw as T;\n}\n\n/** The pending request gating a record, plus its snapshotted node config. */\nasync function pendingRequestFor(\n engine: MinimalEngine,\n objectName: string,\n recordId: string,\n): Promise<any | null> {\n try {\n const rows = await engine.find('sys_approval_request', {\n where: { object_name: objectName, record_id: String(recordId), status: 'pending' },\n limit: 1,\n } as any);\n return Array.isArray(rows) && rows[0] ? rows[0] : null;\n } catch {\n return null;\n }\n}\n\n/**\n * Bind the global record-lock hook. Caller is responsible for calling\n * {@link unbindAllHooks} first if re-binding.\n */\nexport function bindApprovalLockHook(engine: MinimalEngine, logger?: MinimalLogger): void {\n engine.registerHook('beforeUpdate', async (ctx: any) => {\n const id = String((ctx?.input?.id ?? '') as string);\n if (!id) return;\n const object = (ctx?.object ?? ctx?.objectName) as string | undefined;\n // No object name (shouldn't happen) or our own bookkeeping objects → skip.\n if (!object || String(object).startsWith('sys_approval')) return;\n\n const data = (ctx?.input?.data ?? {}) as Record<string, unknown>;\n const changedFields = Object.keys(data).filter((k) => k !== 'id' && k !== 'updated_at');\n if (changedFields.length === 0) return;\n\n // Allow engine self-writes (status mirror from the approvals service, etc).\n if ((ctx?.session as any)?.isSystem) return;\n\n // Allow admin override.\n const roles = (ctx?.session?.roles ?? []) as string[];\n if (Array.isArray(roles) && roles.includes('admin')) return;\n\n const pending = await pendingRequestFor(engine, object, id);\n if (!pending) return;\n\n const config = parseJson<any>(pending.node_config_json, {});\n if (config?.lockRecord === false) return;\n\n // Allow when every changed field is the approval status mirror.\n const mirror = config?.approvalStatusField;\n if (typeof mirror === 'string' && mirror && changedFields.every((f) => f === mirror)) return;\n\n const err: any = new Error('RECORD_LOCKED: record is locked while an approval is in progress');\n err.code = 'RECORD_LOCKED';\n err.statusCode = 409;\n throw err;\n }, { packageId: APPROVALS_HOOK_PACKAGE, priority: 50 });\n\n logger?.info?.('[approvals] record-lock hook bound');\n}\n\n/** The self-service out-of-office delegation object (#1322). */\nexport const DELEGATION_OBJECT = 'sys_approval_delegation';\n\n/**\n * Self-service write guard for `sys_approval_delegation` (#1322 follow-up).\n *\n * The object is `apiEnabled` CRUD so a user can declare their own out-of-office\n * delegation. But it is a system object: it gets no auto `owner_id` anchor and\n * (with no `sharingModel`) defaults to a `public` sharing model, so an\n * unguarded member could **forge a delegation for someone else**\n * (`delegator_id = victim`) and reroute the victim's individually-routed\n * approvals to themselves. This guard forces a normal user's writes to name\n * themselves as the delegator:\n *\n * - **system** context (service / seed / import) → bypass;\n * - **admin** (`roles` includes `'admin'`) → may set `delegator_id` to anyone;\n * - otherwise `delegator_id` must equal the acting user — an absent delegator\n * on insert is stamped to the caller, a foreign delegator is rejected.\n *\n * Row-level ownership on update/delete (you can only touch a delegation you\n * created) is already enforced by `member_default`'s wildcard\n * `created_by == current_user.id` RLS; this guard adds the delegator-identity\n * check that RLS alone can't express. Mirrors the ADR-0092 identity write-guard\n * shape and the security plugin's `owner_id` anchor guard, scoped to this one\n * object.\n */\nexport function bindDelegationWriteGuard(engine: MinimalEngine, logger?: MinimalLogger): void {\n const makeGuard = (isInsert: boolean) => async (ctx: any) => {\n const session = (ctx?.session ?? {}) as any;\n if (session.isSystem) return; // service / seed / import\n const roles = (session.roles ?? []) as unknown[];\n if (Array.isArray(roles) && roles.includes('admin')) return; // admin may act for anyone\n const userId = session.userId != null ? String(session.userId) : '';\n const data = ctx?.input?.data;\n const rows = Array.isArray(data) ? data : (data && typeof data === 'object' ? [data] : []);\n const deny = (): never => {\n const err: any = new Error(\n 'FORBIDDEN: you may only manage out-of-office delegations where you are the delegator'\n + (userId ? ` ('${userId}')` : ''),\n );\n err.code = 'FORBIDDEN';\n err.statusCode = 403;\n throw err;\n };\n for (const row of rows) {\n if (!row || typeof row !== 'object' || Array.isArray(row)) continue;\n const has = Object.prototype.hasOwnProperty.call(row, 'delegator_id');\n const supplied = has ? String((row as any).delegator_id ?? '') : '';\n if (isInsert && (!has || supplied === '')) {\n // Self-service: stamp the caller as delegator when omitted (the schema's\n // `required` is the fallback if the engine doesn't persist the stamp).\n if (!userId) deny();\n (row as any).delegator_id = userId;\n continue;\n }\n // A foreign delegator on insert (forge) or update (relabel/hijack) → deny.\n if (has && supplied !== userId) deny();\n }\n };\n engine.registerHook('beforeInsert', makeGuard(true), { object: DELEGATION_OBJECT, packageId: APPROVALS_HOOK_PACKAGE, priority: 50 });\n engine.registerHook('beforeUpdate', makeGuard(false), { object: DELEGATION_OBJECT, packageId: APPROVALS_HOOK_PACKAGE, priority: 50 });\n logger?.info?.('[approvals] delegation write-guard bound');\n}\n\n/** Unregister every hook the lock module registered. */\nexport function unbindAllHooks(engine: MinimalEngine): number {\n return engine.unregisterHooksByPackage(APPROVALS_HOOK_PACKAGE);\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * Approval-as-flow-node provider (ADR-0019).\n *\n * Registers an `approval` node executor on the automation engine so an approval\n * rides the one flow engine as a durable-pause node:\n *\n * 1. On entry the node opens a `sys_approval_request` (reusing the mature\n * approver-resolution / audit / lock / status-mirror machinery) and returns\n * `{ suspend: true }` — the engine persists the run and stops traversal.\n * 2. A decision (`ApprovalService.decide`) finalizes the request and resumes\n * the run down the matching `approve` / `reject` out-edge.\n *\n * The approval *state* (request/action rows) stays first-class and owned by this\n * plugin — a flow-run log can't drive an inbox / recall / audit. Only the\n * orchestration (when to pause, which branch to take) moves onto the engine.\n */\n\nimport {\n defineActionDescriptor,\n ApprovalNodeConfigSchema,\n getApprovalNodeConfigJsonSchema,\n APPROVAL_NODE_TYPE,\n type ApprovalNodeConfig,\n} from '@objectstack/spec/automation';\nimport type { SharingExecutionContext } from '@objectstack/spec/contracts';\nimport type { ApprovalService } from './approval-service.js';\n\n/** Minimal surface of the automation engine this provider depends on. */\nexport interface ApprovalAutomationSurface {\n registerNodeExecutor(executor: {\n type: string;\n descriptor?: unknown;\n execute(node: any, variables: Map<string, unknown>, context: any): Promise<{\n success: boolean;\n output?: Record<string, unknown>;\n error?: string;\n suspend?: boolean;\n correlation?: string;\n }>;\n }): void;\n resume?(runId: string, signal?: { output?: Record<string, unknown>; branchLabel?: string }): Promise<unknown>;\n}\n\ninterface MinimalLogger {\n info?: (msg: any, ...rest: any[]) => void;\n warn?: (msg: any, ...rest: any[]) => void;\n}\n\nconst SYSTEM_CTX = { isSystem: true, positions: [], permissions: [] } as const;\n\n/**\n * Register the `approval` node executor on the automation engine. Idempotent at\n * the engine level (re-registering replaces). Safe to skip when no automation\n * service is present.\n */\nexport function registerApprovalNode(\n automation: ApprovalAutomationSurface,\n service: ApprovalService,\n logger?: MinimalLogger,\n): void {\n automation.registerNodeExecutor({\n type: APPROVAL_NODE_TYPE,\n descriptor: defineActionDescriptor({\n type: APPROVAL_NODE_TYPE,\n version: '1.0.0',\n name: 'Approval',\n description: 'Route a record for human approval; suspends the flow until a decision, '\n + 'then continues down the approve / reject branch.',\n icon: 'check-circle',\n category: 'human',\n paradigms: ['flow'],\n source: 'plugin',\n // Human decision: the run suspends here awaiting an external reply.\n supportsPause: true,\n isAsync: true,\n // Publish the node's config contract (ADR-0018 §configSchema) so the\n // Studio flow designer renders the Approval property form from the engine\n // rather than a hardcoded client form — the engine owns the shape.\n configSchema: getApprovalNodeConfigJsonSchema(),\n }),\n async execute(node, variables, context) {\n const parsed = ApprovalNodeConfigSchema.safeParse(node.config ?? {});\n if (!parsed.success) {\n const msg = parsed.error.issues.map(i => `${i.path.join('.')}: ${i.message}`).join('; ');\n return { success: false, error: `Approval node '${node.id}' has invalid config: ${msg}` };\n }\n const config = parsed.data as ApprovalNodeConfig;\n\n const runId = variables.get('$runId');\n const record = (variables.get('$record') ?? context?.record ?? {}) as Record<string, unknown>;\n const object = (context?.object ?? (record as any)?.object_name) as string | undefined;\n const recordId = (record as any)?.id as string | undefined;\n\n if (!runId) return { success: false, error: `Approval node '${node.id}': missing $runId` };\n if (!object) return { success: false, error: `Approval node '${node.id}': no target object in context` };\n if (!recordId) return { success: false, error: `Approval node '${node.id}': no record id in $record` };\n\n // Flow identity comes from engine-seeded variables (`$flowName` /\n // `$flowLabel`) so the request row can carry a human-readable origin;\n // `context.flowName` is a legacy fallback for direct callers.\n const flowName = (variables.get('$flowName') as string | undefined) ?? context?.flowName;\n const flowLabel = variables.get('$flowLabel') as string | undefined;\n\n try {\n const request = await service.openNodeRequest({\n object,\n recordId: String(recordId),\n runId: String(runId),\n nodeId: node.id,\n config,\n flowName,\n flowLabel,\n nodeLabel: typeof node.label === 'string' ? node.label : undefined,\n submitterId: context?.userId ?? null,\n record,\n organizationId: context?.organizationId ?? context?.tenantId ?? null,\n }, {\n ...SYSTEM_CTX,\n userId: context?.userId,\n organizationId: context?.organizationId,\n tenantId: context?.tenantId,\n } as unknown as SharingExecutionContext);\n\n logger?.info?.('[approvals] approval node suspended run', {\n node: node.id, request: request.id, run: String(runId),\n });\n // Suspend the run; the request id is the correlation key surfaced on\n // the suspended-run record for lookup.\n return { success: true, suspend: true, correlation: request.id };\n } catch (err: any) {\n return { success: false, error: `Approval node '${node.id}': ${err?.message ?? String(err)}` };\n }\n },\n });\n\n logger?.info?.('[approvals] approval node executor registered');\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { Plugin, PluginContext } from '@objectstack/core';\nimport { SysApprovalRequest } from './sys-approval-request.object.js';\nimport { SysApprovalAction } from './sys-approval-action.object.js';\nimport { SysApprovalApprover } from './sys-approval-approver.object.js';\nimport { SysApprovalToken } from './sys-approval-token.object.js';\nimport { SysApprovalDelegation } from './sys-approval-delegation.object.js';\nimport { renderConfirmPage, renderResultPage } from './action-link-pages.js';\nimport {\n ApprovalService,\n ESCALATION_JOB_NAME,\n ESCALATION_SCAN_INTERVAL_MS,\n type ApprovalEngine,\n} from './approval-service.js';\nimport { bindApprovalLockHook, bindDelegationWriteGuard, unbindAllHooks } from './lifecycle-hooks.js';\nimport { registerApprovalNode, type ApprovalAutomationSurface } from './approval-node.js';\n\nexport interface ApprovalsPluginOptions {\n /** Disable runtime registration (schemas still register). */\n disableService?: boolean;\n /**\n * Interval between SLA escalation scans (ADR-0042). Defaults to\n * {@link ESCALATION_SCAN_INTERVAL_MS} (5 min). Only takes effect when a\n * `job` service is installed; without one, SLA stays display-only.\n */\n escalationScanIntervalMs?: number;\n /**\n * Absolute origin for actionable links in outbound notifications\n * (ADR-0043), e.g. `https://app.example.com`. Relative by default.\n */\n publicBaseUrl?: string;\n /**\n * Disable the record-lock hook. Schema + service stay intact; only the\n * engine-level lock wiring is suppressed. Useful when a caller wants the\n * manual API only (e.g. tests).\n */\n disableAutoHooks?: boolean;\n}\n\n/**\n * ApprovalsServicePlugin — registers sys_approval_{request,action}, the\n * `approvals` service, the `approval` flow node executor (ADR-0019), and the\n * record-lock hook.\n *\n * ADR-0019: approval is no longer a standalone process engine. A flow's\n * Approval node opens a request and suspends the run; a decision via the\n * service resumes it down the matching branch.\n */\nexport class ApprovalsServicePlugin implements Plugin {\n name = 'com.objectstack.service.approvals';\n version = '1.0.0';\n type = 'standard';\n dependencies = ['com.objectstack.engine.objectql'];\n\n private readonly options: ApprovalsPluginOptions;\n private service?: ApprovalService;\n private engine?: any;\n private escalationJobScheduled = false;\n\n constructor(options: ApprovalsPluginOptions = {}) {\n this.options = options;\n }\n\n async init(ctx: PluginContext): Promise<void> {\n ctx.getService<{ register(m: any): void }>('manifest').register({\n id: 'com.objectstack.service.approvals',\n name: 'Approvals Service',\n version: '1.0.0',\n type: 'plugin',\n scope: 'system',\n defaultDatasource: 'cloud',\n namespace: 'sys',\n objects: [SysApprovalRequest, SysApprovalAction, SysApprovalApprover, SysApprovalToken, SysApprovalDelegation],\n // ADR-0029 D7 — contribute the Approvals entries into the Setup app's\n // `group_approvals` slot. This plugin owns these objects (K2.b), so it\n // ships their menu too; when the plugin isn't installed the slot is empty.\n navigationContributions: [\n {\n app: 'setup',\n group: 'group_approvals',\n priority: 100,\n items: [\n { id: 'nav_approval_requests', type: 'object', label: 'Requests', objectName: 'sys_approval_request', icon: 'inbox', requiresObject: 'sys_approval_request' },\n { id: 'nav_approval_actions', type: 'object', label: 'Action History', objectName: 'sys_approval_action', icon: 'history', requiresObject: 'sys_approval_action' },\n { id: 'nav_approval_delegations', type: 'object', label: 'Delegations (OOO)', objectName: 'sys_approval_delegation', icon: 'user-clock', requiresObject: 'sys_approval_delegation' },\n ],\n },\n ],\n });\n // ADR-0029 D8 — contribute this plugin's object translations to the i18n\n // service on kernel:ready (the i18n plugin may register after this one).\n if (typeof (ctx as any).hook === 'function') {\n (ctx as any).hook('kernel:ready', async () => {\n try {\n const i18n = ctx.getService<any>('i18n');\n if (i18n && typeof i18n.loadTranslations === 'function') {\n const { ApprovalsTranslations } = await import('./translations/index.js');\n for (const [locale, data] of Object.entries(ApprovalsTranslations)) {\n i18n.loadTranslations(locale, data as Record<string, unknown>);\n }\n }\n } catch { /* i18n optional */ }\n });\n }\n ctx.logger.info('ApprovalsServicePlugin: schemas registered');\n }\n\n async start(ctx: PluginContext): Promise<void> {\n if (this.options.disableService) return;\n let engine: any = null;\n try { engine = ctx.getService<any>('objectql'); }\n catch { try { engine = ctx.getService<any>('data'); } catch { /* ignore */ } }\n if (!engine) {\n ctx.logger.warn('ApprovalsServicePlugin: no ObjectQL engine — service NOT registered');\n return;\n }\n this.engine = engine;\n\n this.service = new ApprovalService({\n engine: engine as ApprovalEngine,\n logger: ctx.logger,\n publicBaseUrl: this.options.publicBaseUrl,\n });\n\n // Record lock: block edits to a record while it has a pending request.\n // Delegation write-guard: a self-service OOO delegation may only name the\n // acting user as delegator (#1322 follow-up). Both bind under the same\n // package id, so unbindAllHooks clears them together.\n if (!this.options.disableAutoHooks) {\n try {\n unbindAllHooks(engine);\n bindApprovalLockHook(engine, ctx.logger);\n bindDelegationWriteGuard(engine, ctx.logger);\n } catch (err: any) {\n ctx.logger.warn?.('[approvals] failed to bind approval hooks', { error: err?.message });\n }\n }\n\n ctx.registerService('approvals', this.service);\n ctx.logger.info('ApprovalsServicePlugin: service registered');\n\n // Optional messaging service (ADR-0012): thread interactions (reassign /\n // remind / request-info / comment) notify users when present; without it\n // they degrade to audit-only.\n try {\n const messaging = ctx.getService<any>('messaging');\n if (messaging && typeof messaging.emit === 'function') {\n this.service.attachMessaging(messaging);\n }\n } catch { /* messaging not installed */ }\n\n // SLA escalation clock (ADR-0042): a plugin-internal job, deliberately\n // NOT a flow trigger (ADR-0041 §1). Interval sweep + one catch-up scan at\n // boot so a restart doesn't extend a breach by a scan period. Wired on\n // kernel:ready — the job service may start after this plugin. No `job`\n // service → SLA stays display-only.\n const wireEscalationClock = async () => {\n try {\n const jobs = ctx.getService<any>('job');\n if (!jobs || typeof jobs.schedule !== 'function' || !this.service) return;\n const svc = this.service;\n const intervalMs = this.options.escalationScanIntervalMs ?? ESCALATION_SCAN_INTERVAL_MS;\n await jobs.schedule(ESCALATION_JOB_NAME, { type: 'interval', intervalMs }, async () => {\n await svc.runEscalations();\n });\n this.escalationJobScheduled = true;\n void svc.runEscalations().catch((err: any) => {\n ctx.logger.warn?.('[approvals] boot escalation sweep failed', { error: err?.message });\n });\n ctx.logger.info('ApprovalsServicePlugin: SLA escalation scan scheduled', { intervalMs });\n } catch { /* job service not installed */ }\n };\n // Actionable-link pages (ADR-0043): session-less confirm + redemption,\n // mounted straight on the host Hono app. GET only renders; the decision\n // happens exclusively on the POST (mail-gateway prefetch safe).\n const mountActionPages = async () => {\n try {\n const http = ctx.getService<any>('http-server');\n const rawApp = http && typeof http.getRawApp === 'function' ? http.getRawApp() : null;\n if (!rawApp || !this.service) return;\n const svc = this.service;\n const ACT_PATH = '/api/v1/approvals/act';\n const html = (c: any, body: string, status = 200) =>\n c.body(body, status, { 'Content-Type': 'text/html; charset=utf-8' });\n rawApp.get(ACT_PATH, async (c: any) => {\n const token = String(c.req.query('token') ?? '');\n const peek = await svc.peekActionToken(token);\n if (!peek.ok) return html(c, renderResultPage(peek.reason, peek.request), 200);\n return html(c, renderConfirmPage({\n request: peek.request, action: peek.action, approverId: peek.approverId,\n token, actPath: ACT_PATH,\n }));\n });\n rawApp.post(ACT_PATH, async (c: any) => {\n let token = '';\n try {\n const body = await c.req.parseBody();\n token = String(body?.token ?? '');\n } catch { /* fall through to invalid */ }\n const out = await svc.redeemActionToken(token);\n if (!out.ok) return html(c, renderResultPage(out.reason, out.request), 200);\n return html(c, renderResultPage(out.action === 'approve' ? 'approved' : 'rejected', out.request));\n });\n ctx.logger.info(`ApprovalsServicePlugin: actionable-link pages mounted at ${ACT_PATH}`);\n } catch { /* http server not installed */ }\n };\n\n // Pending-approver index backfill (issue #1745): rebuild the normalized\n // sys_approval_approver rows from the pending_approvers CSV so requests\n // written before the index existed (or drifted past a crashed sync) are\n // queryable. Idempotent; cost tracks the live pending queue.\n const backfillApproverIndex = async () => {\n try {\n const svc = this.service;\n if (!svc) return;\n const out = await svc.rebuildApproverIndex();\n if (out.inserted > 0 || out.deleted > 0) {\n ctx.logger.info('ApprovalsServicePlugin: approver index rebuilt', out);\n }\n } catch (err: any) {\n ctx.logger.warn?.('[approvals] approver index backfill failed', { error: err?.message });\n }\n };\n\n if (typeof (ctx as any).hook === 'function') {\n (ctx as any).hook('kernel:ready', wireEscalationClock);\n (ctx as any).hook('kernel:ready', mountActionPages);\n (ctx as any).hook('kernel:ready', backfillApproverIndex);\n } else {\n await wireEscalationClock();\n await mountActionPages();\n await backfillApproverIndex();\n }\n\n // ADR-0019: contribute the `approval` node to the flow engine when one is\n // present. The node lets a flow suspend on an approval and resume on\n // decision; the service is wired to the same engine so `decide()` can\n // resume the suspended run.\n try {\n const automation = ctx.getService<ApprovalAutomationSurface>('automation');\n if (automation && typeof automation.registerNodeExecutor === 'function') {\n this.service.attachAutomation(automation);\n registerApprovalNode(automation, this.service, ctx.logger);\n }\n } catch {\n ctx.logger.info('ApprovalsServicePlugin: no automation engine — approval node not registered');\n }\n }\n\n async stop(ctx: PluginContext): Promise<void> {\n if (this.escalationJobScheduled) {\n try {\n const jobs = ctx.getService<any>('job');\n await jobs?.cancel?.(ESCALATION_JOB_NAME);\n } catch { /* ignore */ }\n this.escalationJobScheduled = false;\n }\n if (this.engine) {\n try { unbindAllHooks(this.engine); } catch { /* ignore */ }\n }\n }\n}\n"],"mappings":"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","names":["import_data","import_data","import_data","uid","fresh","resumed","esc","import_data","parseJson","import_automation","SYSTEM_CTX","ApprovalsTranslations"]}
|
|
1
|
+
{"version":3,"sources":["../src/translations/en.objects.generated.ts","../src/translations/zh-CN.objects.generated.ts","../src/translations/ja-JP.objects.generated.ts","../src/translations/es-ES.objects.generated.ts","../src/translations/index.ts","../src/index.ts","../src/sys-approval-request.object.ts","../src/sys-approval-action.object.ts","../src/sys-approval-approver.object.ts","../src/sys-approval-delegation.object.ts","../src/approval-service.ts","../src/sys-approval-token.object.ts","../src/action-link-pages.ts","../src/lifecycle-hooks.ts","../src/approval-node.ts","../src/approvals-plugin.ts"],"sourcesContent":["// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * Auto-generated by 'os i18n extract' for locale 'en'.\n * Edit translations in place; re-run extract (with --merge) to fill new gaps.\n * Do not hand-edit the structure — only the leaf string values.\n */\n\nimport type { TranslationData } from '@objectstack/spec/system';\n\nexport const enObjects: NonNullable<TranslationData['objects']> = {\n sys_approval_request: {\n label: \"Approval Request\",\n pluralLabel: \"Approval Requests\",\n description: \"Live approval instance tracked per submission\",\n fields: {\n id: {\n label: \"Request ID\"\n },\n organization_id: {\n label: \"Organization\",\n help: \"Tenant that owns this approval request (propagated from submitter context)\"\n },\n process_name: {\n label: \"Source\",\n help: \"Origin of the request — `flow:<flowName|nodeId>` for node-driven approvals\"\n },\n object_name: {\n label: \"Object\"\n },\n record_id: {\n label: \"Record ID\"\n },\n submitter_id: {\n label: \"Submitter\"\n },\n submitter_comment: {\n label: \"Submitter Comment\"\n },\n status: {\n label: \"Status\",\n help: \"Lifecycle state of the request\",\n options: {\n pending: \"pending\",\n approved: \"approved\",\n rejected: \"rejected\",\n recalled: \"recalled\"\n }\n },\n current_step: {\n label: \"Current Step\",\n help: \"Machine name of the step awaiting approval\"\n },\n current_step_index: {\n label: \"Current Step Index\"\n },\n pending_approvers: {\n label: \"Pending Approvers\",\n help: \"Comma-separated user ids who can act on the current step\"\n },\n payload_json: {\n label: \"Snapshot\",\n help: \"Record snapshot at submission time\"\n },\n flow_run_id: {\n label: \"Flow Run\",\n help: \"Suspended automation run id this request gates (ADR-0019). The decision resumes it.\"\n },\n flow_node_id: {\n label: \"Flow Node\",\n help: \"Approval node id within the flow that opened this request (ADR-0019).\"\n },\n node_config_json: {\n label: \"Node Config\",\n help: \"Snapshot of the Approval node config (approvers/behavior) for node-driven requests (ADR-0019).\"\n },\n completed_at: {\n label: \"Completed At\"\n },\n created_at: {\n label: \"Created At\"\n },\n updated_at: {\n label: \"Updated At\"\n }\n },\n _views: {\n my_pending: {\n label: \"My Pending\"\n },\n submitted_by_me: {\n label: \"I Submitted\"\n },\n completed: {\n label: \"Completed\"\n },\n all_requests: {\n label: \"All\"\n }\n }\n },\n sys_approval_action: {\n label: \"Approval Action\",\n pluralLabel: \"Approval Actions\",\n description: \"Append-only audit trail for approval actions\",\n fields: {\n id: {\n label: \"Action ID\"\n },\n organization_id: {\n label: \"Organization\",\n help: \"Tenant that owns this action (mirrors the parent request)\"\n },\n request_id: {\n label: \"Request\"\n },\n step_name: {\n label: \"Step\",\n help: \"Machine name of the step at the time of the action\"\n },\n step_index: {\n label: \"Step Index\"\n },\n action: {\n label: \"Action\",\n options: {\n submit: \"submit\",\n approve: \"approve\",\n reject: \"reject\",\n recall: \"recall\",\n escalate: \"escalate\"\n }\n },\n actor_id: {\n label: \"Actor\"\n },\n comment: {\n label: \"Comment\"\n },\n created_at: {\n label: \"Created At\"\n }\n },\n _views: {\n recent: {\n label: \"Recent\"\n },\n by_actor: {\n label: \"By Actor\"\n },\n all_actions: {\n label: \"All\"\n }\n }\n },\n sys_approval_delegation: {\n label: \"Approval Delegation\",\n pluralLabel: \"Approval Delegations\",\n description: \"Self-service out-of-office rule: route this user's approver slots to a delegate within a time window (#1322 M1).\",\n fields: {\n id: {\n label: \"Delegation ID\"\n },\n delegator_id: {\n label: \"Delegator\",\n help: \"The user going out of office; their individually-routed approver slots are rerouted while active.\"\n },\n delegate_id: {\n label: \"Delegate\",\n help: \"The backup who receives the delegator's approvals while this rule is active. Acts under their own identity.\"\n },\n valid_from: {\n label: \"Valid From\",\n help: \"Rule is inactive before this instant. Null = active immediately. Enforced at resolution time via isGrantActive (ADR-0091 D2 predicate) — never by a background job.\"\n },\n valid_until: {\n label: \"Valid Until\",\n help: \"Rule is inactive AT and AFTER this instant (half-open [from, until), UTC). Null = never expires.\"\n },\n reason: {\n label: \"Reason\",\n help: \"Why the delegation exists (e.g. \\\"Annual leave 5/26\\u20135/30\\\"). Recorded on the substitution audit row.\"\n },\n organization_id: {\n label: \"Organization\",\n help: \"Tenant that owns this rule; null = applies across tenants for this delegator.\"\n },\n created_at: {\n label: \"Created At\"\n },\n updated_at: {\n label: \"Updated At\"\n }\n },\n _views: {\n active: {\n label: \"Active\",\n emptyState: {\n title: \"No delegations\",\n message: \"Declare an out-of-office delegation so approvals route to a backup while you are away.\"\n }\n }\n }\n }\n};\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * Auto-generated by 'os i18n extract' for locale 'zh-CN'.\n * Edit translations in place; re-run extract (with --merge) to fill new gaps.\n * Do not hand-edit the structure — only the leaf string values.\n */\n\nimport type { TranslationData } from '@objectstack/spec/system';\n\nexport const zhCNObjects: NonNullable<TranslationData['objects']> = {\n sys_approval_request: {\n label: \"审批请求\",\n pluralLabel: \"审批请求\",\n description: \"按提交记录跟踪的实时审批实例\",\n fields: {\n id: {\n label: \"请求 ID\"\n },\n organization_id: {\n label: \"组织\",\n help: \"拥有该审批请求的租户(从提交方上下文传播)\"\n },\n process_name: {\n label: \"来源\",\n help: \"请求来源 —— 节点驱动的审批为 `flow:<flowName|nodeId>`\"\n },\n object_name: {\n label: \"对象\"\n },\n record_id: {\n label: \"记录 ID\"\n },\n submitter_id: {\n label: \"提交人\"\n },\n submitter_comment: {\n label: \"提交备注\"\n },\n status: {\n label: \"状态\",\n help: \"请求的生命周期状态\",\n options: {\n pending: \"待处理\",\n approved: \"已批准\",\n rejected: \"已拒绝\",\n recalled: \"已撤回\"\n }\n },\n current_step: {\n label: \"当前步骤\",\n help: \"当前等待审批的步骤机器名称\"\n },\n current_step_index: {\n label: \"当前步骤索引\"\n },\n pending_approvers: {\n label: \"待审批人\",\n help: \"可在当前步骤执行操作的用户 ID,逗号分隔\"\n },\n payload_json: {\n label: \"快照\",\n help: \"提交时的记录快照\"\n },\n flow_run_id: {\n label: \"Flow Run\",\n help: \"Suspended automation run id this request gates (ADR-0019). The decision resumes it.\"\n },\n flow_node_id: {\n label: \"Flow Node\",\n help: \"Approval node id within the flow that opened this request (ADR-0019).\"\n },\n node_config_json: {\n label: \"Node Config\",\n help: \"Snapshot of the Approval node config (approvers/behavior) for node-driven requests (ADR-0019).\"\n },\n completed_at: {\n label: \"完成时间\"\n },\n created_at: {\n label: \"创建时间\"\n },\n updated_at: {\n label: \"更新时间\"\n }\n },\n _views: {\n my_pending: {\n label: \"我的待办\"\n },\n submitted_by_me: {\n label: \"我提交的\"\n },\n completed: {\n label: \"已完成\"\n },\n all_requests: {\n label: \"全部\"\n }\n }\n },\n sys_approval_action: {\n label: \"审批动作\",\n pluralLabel: \"审批动作\",\n description: \"追加写入的审批操作审计记录\",\n fields: {\n id: {\n label: \"动作 ID\"\n },\n organization_id: {\n label: \"组织\",\n help: \"拥有该动作的租户(与父请求保持一致)\"\n },\n request_id: {\n label: \"请求\"\n },\n step_name: {\n label: \"步骤\",\n help: \"执行该动作时对应步骤的机器名称\"\n },\n step_index: {\n label: \"步骤索引\"\n },\n action: {\n label: \"操作\",\n options: {\n submit: \"提交\",\n approve: \"批准\",\n reject: \"拒绝\",\n recall: \"撤回\",\n escalate: \"升级\"\n }\n },\n actor_id: {\n label: \"执行人\"\n },\n comment: {\n label: \"评论\"\n },\n created_at: {\n label: \"创建时间\"\n }\n },\n _views: {\n recent: {\n label: \"最近\"\n },\n by_actor: {\n label: \"按执行人\"\n },\n all_actions: {\n label: \"全部\"\n }\n }\n },\n sys_approval_delegation: {\n label: \"审批委派\",\n pluralLabel: \"审批委派\",\n description: \"自助不在岗规则:在时间窗内把该用户的审批人槽位改派给候补人(#1322 M1)。\",\n fields: {\n id: {\n label: \"委派 ID\"\n },\n delegator_id: {\n label: \"委派人\",\n help: \"即将不在岗的用户;规则生效期间,路由到其个人的审批人槽位将被改派。\"\n },\n delegate_id: {\n label: \"候补人\",\n help: \"规则生效期间接收委派人审批的候补人。以其本人身份行使。\"\n },\n valid_from: {\n label: \"生效时间\",\n help: \"此刻之前规则不生效。留空 = 立即生效。在解析时通过 isGrantActive 强制(ADR-0091 D2 判定式)——绝不依赖后台任务。\"\n },\n valid_until: {\n label: \"失效时间\",\n help: \"此刻(含)及之后规则不生效(半开区间 [from, until),UTC)。留空 = 永不过期。\"\n },\n reason: {\n label: \"原因\",\n help: \"委派存在的原因(例如“年假 5/26–5/30”)。会记入改派审计行。\"\n },\n organization_id: {\n label: \"组织\",\n help: \"拥有此规则的租户;留空 = 对该委派人跨租户生效。\"\n },\n created_at: {\n label: \"创建时间\"\n },\n updated_at: {\n label: \"更新时间\"\n }\n },\n _views: {\n active: {\n label: \"生效中\",\n emptyState: {\n title: \"暂无委派\",\n message: \"声明一条不在岗委派,休假期间审批自动改派给候补人。\"\n }\n }\n }\n }\n};\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * Auto-generated by 'os i18n extract' for locale 'ja-JP'.\n * Edit translations in place; re-run extract (with --merge) to fill new gaps.\n * Do not hand-edit the structure — only the leaf string values.\n */\n\nimport type { TranslationData } from '@objectstack/spec/system';\n\nexport const jaJPObjects: NonNullable<TranslationData['objects']> = {\n sys_approval_request: {\n label: \"承認リクエスト\",\n pluralLabel: \"承認リクエスト\",\n description: \"送信ごとに追跡されるライブ承認インスタンス\",\n fields: {\n id: {\n label: \"リクエスト ID\"\n },\n organization_id: {\n label: \"組織\",\n help: \"この承認リクエストを所有するテナント(送信者コンテキストから伝播)\"\n },\n process_name: {\n label: \"ソース\",\n help: \"リクエストの発生元 — ノード駆動の承認では `flow:<flowName|nodeId>`\"\n },\n object_name: {\n label: \"オブジェクト\"\n },\n record_id: {\n label: \"レコード ID\"\n },\n submitter_id: {\n label: \"送信者\"\n },\n submitter_comment: {\n label: \"送信者コメント\"\n },\n status: {\n label: \"ステータス\",\n help: \"リクエストのライフサイクル状態\",\n options: {\n pending: \"保留中\",\n approved: \"承認済み\",\n rejected: \"却下済み\",\n recalled: \"取り消し済み\"\n }\n },\n current_step: {\n label: \"現在のステップ\",\n help: \"承認待ちのステップの機械名\"\n },\n current_step_index: {\n label: \"現在のステップ番号\"\n },\n pending_approvers: {\n label: \"承認待ち承認者\",\n help: \"現在のステップを処理できるユーザー ID のカンマ区切りリスト\"\n },\n payload_json: {\n label: \"スナップショット\",\n help: \"送信時のレコードスナップショット\"\n },\n flow_run_id: {\n label: \"Flow Run\",\n help: \"Suspended automation run id this request gates (ADR-0019). The decision resumes it.\"\n },\n flow_node_id: {\n label: \"Flow Node\",\n help: \"Approval node id within the flow that opened this request (ADR-0019).\"\n },\n node_config_json: {\n label: \"Node Config\",\n help: \"Snapshot of the Approval node config (approvers/behavior) for node-driven requests (ADR-0019).\"\n },\n completed_at: {\n label: \"完了日時\"\n },\n created_at: {\n label: \"作成日時\"\n },\n updated_at: {\n label: \"更新日時\"\n }\n },\n _views: {\n my_pending: {\n label: \"自分の保留中\"\n },\n submitted_by_me: {\n label: \"自分が送信\"\n },\n completed: {\n label: \"完了済み\"\n },\n all_requests: {\n label: \"すべて\"\n }\n }\n },\n sys_approval_action: {\n label: \"承認アクション\",\n pluralLabel: \"承認アクション\",\n description: \"承認アクションの追記専用監査証跡\",\n fields: {\n id: {\n label: \"アクション ID\"\n },\n organization_id: {\n label: \"組織\",\n help: \"このアクションを所有するテナント(親リクエストと同じ)\"\n },\n request_id: {\n label: \"リクエスト\"\n },\n step_name: {\n label: \"ステップ\",\n help: \"アクション時点のステップの機械名\"\n },\n step_index: {\n label: \"ステップ番号\"\n },\n action: {\n label: \"アクション\",\n options: {\n submit: \"申請\",\n approve: \"承認\",\n reject: \"却下\",\n recall: \"取消\",\n escalate: \"エスカレーション\"\n }\n },\n actor_id: {\n label: \"操作者\"\n },\n comment: {\n label: \"コメント\"\n },\n created_at: {\n label: \"作成日時\"\n }\n },\n _views: {\n recent: {\n label: \"最近\"\n },\n by_actor: {\n label: \"操作者別\"\n },\n all_actions: {\n label: \"すべて\"\n }\n }\n },\n sys_approval_delegation: {\n label: \"Approval Delegation\",\n pluralLabel: \"Approval Delegations\",\n description: \"Self-service out-of-office rule: route this user's approver slots to a delegate within a time window (#1322 M1).\",\n fields: {\n id: {\n label: \"Delegation ID\"\n },\n delegator_id: {\n label: \"Delegator\",\n help: \"The user going out of office; their individually-routed approver slots are rerouted while active.\"\n },\n delegate_id: {\n label: \"Delegate\",\n help: \"The backup who receives the delegator's approvals while this rule is active. Acts under their own identity.\"\n },\n valid_from: {\n label: \"Valid From\",\n help: \"Rule is inactive before this instant. Null = active immediately. Enforced at resolution time via isGrantActive (ADR-0091 D2 predicate) — never by a background job.\"\n },\n valid_until: {\n label: \"Valid Until\",\n help: \"Rule is inactive AT and AFTER this instant (half-open [from, until), UTC). Null = never expires.\"\n },\n reason: {\n label: \"Reason\",\n help: \"Why the delegation exists (e.g. \\\"Annual leave 5/26\\u20135/30\\\"). Recorded on the substitution audit row.\"\n },\n organization_id: {\n label: \"Organization\",\n help: \"Tenant that owns this rule; null = applies across tenants for this delegator.\"\n },\n created_at: {\n label: \"Created At\"\n },\n updated_at: {\n label: \"Updated At\"\n }\n },\n _views: {\n active: {\n label: \"Active\",\n emptyState: {\n title: \"No delegations\",\n message: \"Declare an out-of-office delegation so approvals route to a backup while you are away.\"\n }\n }\n }\n }\n};\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * Auto-generated by 'os i18n extract' for locale 'es-ES'.\n * Edit translations in place; re-run extract (with --merge) to fill new gaps.\n * Do not hand-edit the structure — only the leaf string values.\n */\n\nimport type { TranslationData } from '@objectstack/spec/system';\n\nexport const esESObjects: NonNullable<TranslationData['objects']> = {\n sys_approval_request: {\n label: \"Solicitud de aprobación\",\n pluralLabel: \"Solicitudes de aprobación\",\n description: \"Instancia activa de aprobación registrada por envío\",\n fields: {\n id: {\n label: \"ID de solicitud\"\n },\n organization_id: {\n label: \"Organización\",\n help: \"Tenant que posee esta solicitud de aprobación (propagado desde el contexto del solicitante).\"\n },\n process_name: {\n label: \"Origen\",\n help: \"Origen de la solicitud — `flow:<flowName|nodeId>` para aprobaciones por nodo\"\n },\n object_name: {\n label: \"Objeto\"\n },\n record_id: {\n label: \"ID de registro\"\n },\n submitter_id: {\n label: \"Solicitante\"\n },\n submitter_comment: {\n label: \"Comentario del solicitante\"\n },\n status: {\n label: \"Estado\",\n help: \"Estado del ciclo de vida de la solicitud.\",\n options: {\n pending: \"Pendiente\",\n approved: \"Aprobada\",\n rejected: \"Rechazada\",\n recalled: \"Retirada\"\n }\n },\n current_step: {\n label: \"Paso actual\",\n help: \"Nombre técnico del paso pendiente de aprobación.\"\n },\n current_step_index: {\n label: \"Índice del paso actual\"\n },\n pending_approvers: {\n label: \"Aprobadores pendientes\",\n help: \"ID de usuario separados por comas que pueden actuar en el paso actual.\"\n },\n payload_json: {\n label: \"Instantánea\",\n help: \"Instantánea del registro en el momento del envío.\"\n },\n flow_run_id: {\n label: \"Flow Run\",\n help: \"Suspended automation run id this request gates (ADR-0019). The decision resumes it.\"\n },\n flow_node_id: {\n label: \"Flow Node\",\n help: \"Approval node id within the flow that opened this request (ADR-0019).\"\n },\n node_config_json: {\n label: \"Node Config\",\n help: \"Snapshot of the Approval node config (approvers/behavior) for node-driven requests (ADR-0019).\"\n },\n completed_at: {\n label: \"Completado el\"\n },\n created_at: {\n label: \"Creado el\"\n },\n updated_at: {\n label: \"Actualizado el\"\n }\n },\n _views: {\n my_pending: {\n label: \"Mis pendientes\"\n },\n submitted_by_me: {\n label: \"Enviadas por mí\"\n },\n completed: {\n label: \"Completadas\"\n },\n all_requests: {\n label: \"Todas\"\n }\n }\n },\n sys_approval_action: {\n label: \"Acción de aprobación\",\n pluralLabel: \"Acciones de aprobación\",\n description: \"Registro de auditoría append-only para acciones de aprobación\",\n fields: {\n id: {\n label: \"ID de acción\"\n },\n organization_id: {\n label: \"Organización\",\n help: \"Tenant que posee esta acción (refleja la solicitud principal).\"\n },\n request_id: {\n label: \"Solicitud\"\n },\n step_name: {\n label: \"Paso\",\n help: \"Nombre técnico del paso en el momento de la acción.\"\n },\n step_index: {\n label: \"Índice del paso\"\n },\n action: {\n label: \"Acción\",\n options: {\n submit: \"Enviar\",\n approve: \"Aprobar\",\n reject: \"Rechazar\",\n recall: \"Retirar\",\n escalate: \"Escalar\"\n }\n },\n actor_id: {\n label: \"Actor\"\n },\n comment: {\n label: \"Comentario\"\n },\n created_at: {\n label: \"Creado el\"\n }\n },\n _views: {\n recent: {\n label: \"Recientes\"\n },\n by_actor: {\n label: \"Por actor\"\n },\n all_actions: {\n label: \"Todas\"\n }\n }\n },\n sys_approval_delegation: {\n label: \"Approval Delegation\",\n pluralLabel: \"Approval Delegations\",\n description: \"Self-service out-of-office rule: route this user's approver slots to a delegate within a time window (#1322 M1).\",\n fields: {\n id: {\n label: \"Delegation ID\"\n },\n delegator_id: {\n label: \"Delegator\",\n help: \"The user going out of office; their individually-routed approver slots are rerouted while active.\"\n },\n delegate_id: {\n label: \"Delegate\",\n help: \"The backup who receives the delegator's approvals while this rule is active. Acts under their own identity.\"\n },\n valid_from: {\n label: \"Valid From\",\n help: \"Rule is inactive before this instant. Null = active immediately. Enforced at resolution time via isGrantActive (ADR-0091 D2 predicate) — never by a background job.\"\n },\n valid_until: {\n label: \"Valid Until\",\n help: \"Rule is inactive AT and AFTER this instant (half-open [from, until), UTC). Null = never expires.\"\n },\n reason: {\n label: \"Reason\",\n help: \"Why the delegation exists (e.g. \\\"Annual leave 5/26\\u20135/30\\\"). Recorded on the substitution audit row.\"\n },\n organization_id: {\n label: \"Organization\",\n help: \"Tenant that owns this rule; null = applies across tenants for this delegator.\"\n },\n created_at: {\n label: \"Created At\"\n },\n updated_at: {\n label: \"Updated At\"\n }\n },\n _views: {\n active: {\n label: \"Active\",\n emptyState: {\n title: \"No delegations\",\n message: \"Declare an out-of-office delegation so approvals route to a backup while you are away.\"\n }\n }\n }\n }\n};\n","// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * ApprovalsTranslations — i18n bundle owned by this plugin (ADR-0029 D8).\n *\n * Object label/field/view/action translations for the sys_* objects this\n * plugin owns. Loaded at runtime via the plugin's `kernel:ready` hook\n * (`i18n.loadTranslations`). Regenerate with `os i18n extract` against\n * `scripts/i18n-extract.config.ts`.\n */\n\nimport type { TranslationBundle } from '@objectstack/spec/system';\nimport { enObjects } from './en.objects.generated.js';\nimport { zhCNObjects } from './zh-CN.objects.generated.js';\nimport { jaJPObjects } from './ja-JP.objects.generated.js';\nimport { esESObjects } from './es-ES.objects.generated.js';\n\nexport const ApprovalsTranslations: TranslationBundle = {\n en: { objects: enObjects },\n 'zh-CN': { objects: zhCNObjects },\n 'ja-JP': { objects: jaJPObjects },\n 'es-ES': { objects: esESObjects },\n};\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * @objectstack/plugin-approvals\n *\n * Approval-as-flow-node runtime (ADR-0019). Persists sys_approval_request /\n * sys_approval_action, resolves approvers, enforces the record lock, and\n * records decisions that resume the owning flow run. Approval orchestration\n * (when to pause, which branch to take) lives on the one automation engine via\n * the `approval` node.\n */\n\nexport { SysApprovalRequest } from './sys-approval-request.object.js';\nexport { SysApprovalAction } from './sys-approval-action.object.js';\nexport { SysApprovalApprover } from './sys-approval-approver.object.js';\nexport { SysApprovalDelegation } from './sys-approval-delegation.object.js';\nexport {\n ApprovalService,\n type ApprovalEngine,\n type ApprovalClock,\n type ApprovalServiceOptions,\n type ApprovalResumeSurface,\n} from './approval-service.js';\nexport {\n ApprovalsServicePlugin,\n type ApprovalsPluginOptions,\n} from './approvals-plugin.js';\nexport {\n registerApprovalNode,\n type ApprovalAutomationSurface,\n} from './approval-node.js';\nexport type {\n IApprovalService,\n ApprovalRequestRow,\n ApprovalActionRow,\n ApprovalDecisionInput,\n ApprovalDecisionResult,\n ApprovalStatus,\n} from '@objectstack/spec/contracts';\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { ObjectSchema, Field } from '@objectstack/spec/data';\n\n/**\n * sys_approval_request — Live approval instance.\n *\n * ADR-0019: opened by a flow's **Approval node** when the run reaches it; the\n * run suspends until a decision is recorded. The row's lifecycle:\n *\n * `pending` → (per-approver decisions) → `approved` | `rejected`\n * `pending` → recalled by submitter → `recalled`\n *\n * `flow_run_id` / `flow_node_id` tie the request back to the suspended run so a\n * decision can resume it; `current_step` mirrors the node id. `node_config_json`\n * snapshots the Approval node config (approvers / behaviour) the request was\n * opened with.\n *\n * `payload_json` captures a snapshot of the target record at submission\n * time — used by notifications so they can render before the record is\n * locked or changed.\n *\n * @namespace sys\n */\nexport const SysApprovalRequest = ObjectSchema.create({\n name: 'sys_approval_request',\n label: 'Approval Request',\n pluralLabel: 'Approval Requests',\n icon: 'inbox',\n isSystem: true,\n managedBy: 'engine-owned',\n description: 'Live approval instance tracked per submission',\n displayNameField: 'id',\n nameField: 'id', // [ADR-0079] canonical primary-title pointer (mirrors deprecated displayNameField)\n titleFormat: '{process_name} · {record_id}',\n highlightFields: ['process_name', 'object_name', 'record_id', 'status', 'current_step', 'submitter_id', 'updated_at'],\n\n // Curated built-in list views — render as segmented tabs in the console.\n // Filters use {current_user_id} substitution wired by the console.\n listViews: {\n my_pending: {\n type: 'grid',\n name: 'my_pending',\n label: 'My Pending',\n data: { provider: 'object', object: 'sys_approval_request' },\n columns: ['process_name', 'object_name', 'record_id', 'current_step', 'submitter_id', 'updated_at'],\n filter: [\n { field: 'status', operator: 'equals', value: 'pending' },\n { field: 'pending_approvers', operator: 'contains', value: '{current_user_id}' },\n ],\n sort: [{ field: 'updated_at', order: 'desc' }],\n pagination: { pageSize: 25 },\n emptyState: { title: 'No pending approvals', message: 'You\\'re all caught up.' },\n },\n submitted_by_me: {\n type: 'grid',\n name: 'submitted_by_me',\n label: 'I Submitted',\n data: { provider: 'object', object: 'sys_approval_request' },\n columns: ['process_name', 'object_name', 'record_id', 'status', 'current_step', 'updated_at'],\n filter: [{ field: 'submitter_id', operator: 'equals', value: '{current_user_id}' }],\n sort: [{ field: 'updated_at', order: 'desc' }],\n pagination: { pageSize: 25 },\n },\n completed: {\n type: 'grid',\n name: 'completed',\n label: 'Completed',\n data: { provider: 'object', object: 'sys_approval_request' },\n columns: ['process_name', 'object_name', 'record_id', 'status', 'submitter_id', 'completed_at'],\n filter: [{ field: 'status', operator: 'in', value: ['approved', 'rejected', 'recalled'] }],\n sort: [{ field: 'completed_at', order: 'desc' }],\n pagination: { pageSize: 25 },\n },\n all_requests: {\n type: 'grid',\n name: 'all_requests',\n label: 'All',\n data: { provider: 'object', object: 'sys_approval_request' },\n columns: ['process_name', 'object_name', 'record_id', 'status', 'current_step', 'submitter_id', 'updated_at'],\n sort: [{ field: 'updated_at', order: 'desc' }],\n pagination: { pageSize: 50 },\n },\n },\n\n fields: {\n id: Field.text({ label: 'Request ID', required: true, readonly: true, group: 'System' }),\n\n organization_id: Field.lookup('sys_organization', {\n label: 'Organization',\n required: false,\n group: 'System',\n description: 'Tenant that owns this approval request (propagated from submitter context)',\n }),\n\n process_name: Field.text({\n label: 'Source',\n required: true,\n maxLength: 100,\n description: 'Origin of the request — `flow:<flowName|nodeId>` for node-driven approvals',\n group: 'Target',\n }),\n\n object_name: Field.text({\n label: 'Object',\n required: true,\n maxLength: 100,\n group: 'Target',\n }),\n\n record_id: Field.text({\n label: 'Record ID',\n required: true,\n maxLength: 100,\n group: 'Target',\n }),\n\n submitter_id: Field.lookup('sys_user', {\n label: 'Submitter',\n required: false,\n group: 'Target',\n }),\n\n submitter_comment: Field.textarea({\n label: 'Submitter Comment',\n required: false,\n group: 'Target',\n }),\n\n status: Field.select(\n // Keep in sync with `ApprovalStatus` (spec/contracts). `returned` =\n // sent back for revision (ADR-0044) — terminal for this round.\n ['pending', 'approved', 'rejected', 'recalled', 'returned'],\n {\n label: 'Status',\n required: true,\n defaultValue: 'pending',\n description: 'Lifecycle state of the request',\n group: 'State',\n },\n ),\n\n current_step: Field.text({\n label: 'Current Step',\n required: false,\n maxLength: 100,\n description: 'Machine name of the step awaiting approval',\n group: 'State',\n }),\n\n current_step_index: Field.number({\n label: 'Current Step Index',\n required: false,\n defaultValue: 0,\n group: 'State',\n }),\n\n pending_approvers: Field.textarea({\n label: 'Pending Approvers',\n required: false,\n description: 'Comma-separated user ids who can act on the current step',\n group: 'State',\n }),\n\n payload_json: Field.textarea({\n label: 'Snapshot',\n required: false,\n description: 'Record snapshot at submission time',\n group: 'State',\n }),\n\n // ── ADR-0019: approval-as-flow-node correlation ──────────────────\n // When a request is opened by an Approval *node* (rather than a standalone\n // process), these tie it back to the suspended flow run so a decision can\n // resume it. Null for legacy process-driven requests.\n flow_run_id: Field.text({\n label: 'Flow Run',\n required: false,\n maxLength: 100,\n readonly: true,\n description: 'Suspended automation run id this request gates (ADR-0019). The decision resumes it.',\n group: 'State',\n }),\n\n flow_node_id: Field.text({\n label: 'Flow Node',\n required: false,\n maxLength: 100,\n readonly: true,\n description: 'Approval node id within the flow that opened this request (ADR-0019).',\n group: 'State',\n }),\n\n node_config_json: Field.textarea({\n label: 'Node Config',\n required: false,\n readonly: true,\n description: 'Snapshot of the Approval node config (approvers/behavior) for node-driven requests (ADR-0019).',\n group: 'State',\n }),\n\n completed_at: Field.datetime({\n label: 'Completed At',\n required: false,\n group: 'State',\n }),\n\n created_at: Field.datetime({\n label: 'Created At',\n required: true,\n defaultValue: 'NOW()',\n readonly: true,\n group: 'System',\n }),\n\n updated_at: Field.datetime({ label: 'Updated At', required: false, group: 'System' }),\n },\n\n indexes: [\n // Look up \"is there a pending request for this record?\" — common\n // guard on submit and on edit-while-locked checks.\n { fields: ['object_name', 'record_id'] },\n { fields: ['status', 'object_name'] },\n // Status-windowed listings (escalation sweep, \"All\" tab ordering).\n // \"My approvals\" matching no longer scans this table: the service keeps\n // a normalized per-approver index in `sys_approval_approver` (#1745) and\n // resolves approver filters there; `pending_approvers` stays the\n // human-readable CSV source of truth only.\n { fields: ['status', 'updated_at'] },\n { fields: ['submitter_id', 'status'] },\n ],\n\n // Server-declared decision actions (objectui#2678 P2-4). The console's\n // generic action runtime renders and executes these wherever this object is\n // surfaced — the approvals inbox included — so new decision capabilities\n // (and their params) ship as metadata, not as hand-written buttons. Each\n // targets the existing approvals REST route; `{id}` resolves from the row\n // and `actorId` defaults to the caller server-side. The service remains the\n // authority on who may act; `visible` gates on the server-computed\n // per-viewer block (#3310): approver actions on `record.viewer.can_act`\n // (the caller is a current pending approver — same check the service\n // authorizes a decision with, so position/team approvers resolve correctly),\n // submitter actions on `record.viewer.is_submitter`. `viewer` is attached by\n // getRequest/listRequests; where it is absent the predicate fails closed.\n actions: [\n {\n name: 'approval_approve',\n label: 'Approve',\n icon: 'check-circle',\n type: 'api',\n method: 'POST',\n target: '/api/v1/approvals/requests/{id}/approve',\n params: [\n { name: 'comment', label: 'Comment', type: 'textarea', required: false },\n // Decision attachments (#3266). The console renders `type:'file'` params\n // through the shared upload widget and POSTs the resolved `attachments:\n // string[]`; the decision route persists them on `sys_approval_action`.\n { name: 'attachments', label: 'Attachments', type: 'file', multiple: true, required: false },\n ],\n visible: 'record.viewer.can_act',\n locations: ['record_section', 'list_item'],\n successMessage: 'Approved.',\n refreshAfter: true,\n },\n {\n name: 'approval_reject',\n label: 'Reject',\n icon: 'x-circle',\n type: 'api',\n method: 'POST',\n target: '/api/v1/approvals/requests/{id}/reject',\n params: [\n { name: 'comment', label: 'Comment', type: 'textarea', required: false },\n { name: 'attachments', label: 'Attachments', type: 'file', multiple: true, required: false },\n ],\n visible: 'record.viewer.can_act',\n confirmText: 'Reject this request? A rejection is final for every approver.',\n locations: ['record_section', 'list_item'],\n successMessage: 'Rejected.',\n refreshAfter: true,\n },\n {\n name: 'approval_reassign',\n label: 'Reassign',\n icon: 'arrow-right-left',\n type: 'api',\n method: 'POST',\n target: '/api/v1/approvals/requests/{id}/reassign',\n params: [\n // Field-backed on `submitter_id` (the object's only `sys_user` lookup):\n // the console resolves its lookup config (`reference_to: sys_user`) so the\n // dialog renders a real user picker, while `name: 'to'` overrides the\n // request-body key to the `to` the reassign route expects. This is a\n // config-borrow, not a submitter pre-fill (`defaultFromRow` stays off).\n { field: 'submitter_id', name: 'to', label: 'New approver', required: true, helpText: 'User to hand this step to' },\n { name: 'comment', label: 'Comment', type: 'textarea', required: false },\n ],\n visible: 'record.viewer.can_act',\n locations: ['record_section'],\n successMessage: 'Reassigned.',\n refreshAfter: true,\n },\n\n // ── Approver secondary decisions ────────────────────────────────\n // Send back for revision / request more info (ADR-0044). Both are approver\n // actions, so `visible` gates on `record.viewer.can_act` (a current pending\n // approver) — same as approve/reject. The service stays the authority.\n {\n name: 'approval_send_back',\n label: 'Send back',\n icon: 'corner-up-left',\n type: 'api',\n method: 'POST',\n target: '/api/v1/approvals/requests/{id}/revise',\n params: [\n { name: 'comment', label: 'Reason', type: 'textarea', required: false },\n ],\n visible: 'record.viewer.can_act',\n locations: ['record_section'],\n successMessage: 'Sent back for revision.',\n refreshAfter: true,\n },\n {\n name: 'approval_request_info',\n label: 'Request info',\n icon: 'help-circle',\n type: 'api',\n method: 'POST',\n target: '/api/v1/approvals/requests/{id}/request-info',\n params: [\n { name: 'comment', label: 'What do you need?', type: 'textarea', required: true },\n ],\n visible: 'record.viewer.can_act',\n locations: ['record_section'],\n successMessage: 'Information requested.',\n refreshAfter: true,\n },\n\n // ── Submitter continuity actions ────────────────────────────────\n // Remind / recall (pending) and resubmit / recall (returned). These are the\n // submitter's own levers, so `visible` gates on `record.viewer.is_submitter`\n // (server-computed on the current viewer). The service re-checks ownership;\n // the predicate keeps a non-submitter from ever seeing a button they cannot\n // use.\n {\n name: 'approval_remind',\n label: 'Send reminder',\n icon: 'bell-ring',\n type: 'api',\n method: 'POST',\n target: '/api/v1/approvals/requests/{id}/remind',\n params: [\n { name: 'comment', label: 'Note', type: 'textarea', required: false },\n ],\n visible: 'record.status == \"pending\" && record.viewer.is_submitter',\n locations: ['record_section'],\n successMessage: 'Reminder sent.',\n refreshAfter: true,\n },\n {\n name: 'approval_recall',\n label: 'Recall',\n icon: 'undo-2',\n type: 'api',\n method: 'POST',\n target: '/api/v1/approvals/requests/{id}/recall',\n params: [\n { name: 'comment', label: 'Comment', type: 'textarea', required: false },\n ],\n // Recall applies while the request is live for the submitter — pending\n // (withdraw) or returned (abandon the revision instead of resubmitting).\n visible: '(record.status == \"pending\" || record.status == \"returned\") && record.viewer.is_submitter',\n confirmText: 'Recall this request? Approvers can no longer act on it and the record is unlocked.',\n locations: ['record_section'],\n successMessage: 'Recalled.',\n refreshAfter: true,\n },\n {\n name: 'approval_resubmit',\n label: 'Resubmit',\n icon: 'refresh-cw',\n type: 'api',\n method: 'POST',\n target: '/api/v1/approvals/requests/{id}/resubmit',\n params: [\n { name: 'comment', label: 'What changed?', type: 'textarea', required: false },\n ],\n visible: 'record.status == \"returned\" && record.viewer.is_submitter',\n locations: ['record_section'],\n successMessage: 'Resubmitted.',\n refreshAfter: true,\n },\n ],\n\n enable: {\n // [ADR-0103] Engine-owned: the approval engine owns the request lifecycle\n // (SYSTEM_CTX); users act via domain actions (Submit/Approve/Recall), never\n // generic CRUD. Reads stay open.\n apiMethods: ['get', 'list'],\n },\n});\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { ObjectSchema, Field } from '@objectstack/spec/data';\n\n/**\n * sys_approval_action — Audit trail row per approval action.\n *\n * Append-only: every `submit`, `approve`, `reject`, `recall`, or\n * `escalate` event lands here. The engine reads back per-step approval\n * rows to evaluate `behavior: 'unanimous'` (all approvers must approve\n * before advancing) versus `first_response` (any single approval\n * advances the step).\n *\n * @namespace sys\n */\nexport const SysApprovalAction = ObjectSchema.create({\n name: 'sys_approval_action',\n label: 'Approval Action',\n pluralLabel: 'Approval Actions',\n icon: 'check-circle',\n isSystem: true,\n managedBy: 'append-only',\n description: 'Append-only audit trail for approval actions',\n displayNameField: 'id',\n nameField: 'id', // [ADR-0079] canonical primary-title pointer (mirrors deprecated displayNameField)\n titleFormat: '{action} · {step_name}',\n highlightFields: ['request_id', 'step_name', 'action', 'actor_id', 'created_at'],\n\n listViews: {\n recent: {\n type: 'grid',\n name: 'recent',\n label: 'Recent',\n data: { provider: 'object', object: 'sys_approval_action' },\n columns: ['created_at', 'request_id', 'step_name', 'action', 'actor_id', 'comment'],\n sort: [{ field: 'created_at', order: 'desc' }],\n pagination: { pageSize: 50 },\n emptyState: { title: 'No approval actions yet', message: 'Actions are logged automatically when approvals progress.' },\n },\n by_actor: {\n type: 'grid',\n name: 'by_actor',\n label: 'By Actor',\n data: { provider: 'object', object: 'sys_approval_action' },\n columns: ['actor_id', 'created_at', 'request_id', 'step_name', 'action'],\n sort: [{ field: 'actor_id', order: 'asc' }, { field: 'created_at', order: 'desc' }],\n grouping: { fields: [{ field: 'actor_id', order: 'asc', collapsed: false }] },\n pagination: { pageSize: 100 },\n },\n all_actions: {\n type: 'grid',\n name: 'all_actions',\n label: 'All',\n data: { provider: 'object', object: 'sys_approval_action' },\n columns: ['created_at', 'request_id', 'step_name', 'action', 'actor_id', 'comment'],\n sort: [{ field: 'created_at', order: 'desc' }],\n pagination: { pageSize: 100 },\n },\n },\n\n fields: {\n id: Field.text({ label: 'Action ID', required: true, readonly: true, group: 'System' }),\n\n organization_id: Field.lookup('sys_organization', {\n label: 'Organization',\n required: false,\n group: 'System',\n description: 'Tenant that owns this action (mirrors the parent request)',\n }),\n\n request_id: Field.lookup('sys_approval_request', {\n label: 'Request',\n required: true,\n group: 'Target',\n }),\n\n step_name: Field.text({\n label: 'Step',\n required: false,\n maxLength: 100,\n description: 'Machine name of the step at the time of the action',\n group: 'Target',\n }),\n\n step_index: Field.number({\n label: 'Step Index',\n required: false,\n group: 'Target',\n }),\n\n action: Field.select(\n // Keep in sync with `ApprovalActionKind` (spec/contracts). reassign /\n // remind / request_info / comment are thread interactions — they never\n // move the flow. revise / resubmit (ADR-0044) DO move it: send back for\n // revision and the later resubmission. ooo_substitute (#1322 M1) is a\n // system-recorded reroute of an out-of-office approver — no flow movement.\n ['submit', 'approve', 'reject', 'recall', 'escalate', 'reassign', 'remind', 'request_info', 'comment', 'revise', 'resubmit', 'ooo_substitute'],\n {\n label: 'Action',\n required: true,\n group: 'Action',\n },\n ),\n\n actor_id: Field.lookup('sys_user', {\n label: 'Actor',\n required: false,\n group: 'Action',\n }),\n\n comment: Field.textarea({ label: 'Comment', required: false, group: 'Action' }),\n\n attachments: Field.file({\n label: 'Attachments',\n required: false,\n multiple: true,\n group: 'Action',\n description: 'Files supporting this action — e.g. a signed contract or evidence (#3266).',\n }),\n\n created_at: Field.datetime({\n label: 'Created At',\n required: true,\n defaultValue: 'NOW()',\n readonly: true,\n group: 'System',\n }),\n },\n\n indexes: [\n { fields: ['request_id', 'created_at'] },\n { fields: ['request_id', 'step_index', 'action'] },\n ],\n\n enable: {\n // [ADR-0103] Engine-owned append-only decision log: appended by the approval\n // engine (SYSTEM_CTX). Reads stay open.\n apiMethods: ['get', 'list'],\n },\n});\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { ObjectSchema, Field } from '@objectstack/spec/data';\n\n/**\n * sys_approval_approver — Pending-approver index (issue #1745).\n *\n * One row per (request, approver identity) while the request is **pending**.\n * `sys_approval_request.pending_approvers` stays the human-readable source of\n * truth (a CSV column), but CSV substring matching can neither be indexed nor\n * pushed into an engine query — which made \"my pending\" a post-filter in\n * memory and broke pagination beyond the scan window.\n *\n * This table is that CSV, normalized: the service mirrors every change to\n * `pending_approvers` here (open / decide / recall / send-back / reassign /\n * escalate), and clears the rows when the request leaves `pending`. So the\n * table only ever holds the live work queue — its size tracks the number of\n * open approvals, not the append-only request history.\n *\n * `approver` holds one identity literal exactly as it appears in the CSV:\n * a user id, an email, or a `role:<name>` / `team:<name>` style literal.\n * Equality (or `$in`) on this column is the indexed replacement for the old\n * per-row substring match.\n *\n * @namespace sys\n */\nexport const SysApprovalApprover = ObjectSchema.create({\n name: 'sys_approval_approver',\n label: 'Approval Approver',\n pluralLabel: 'Approval Approvers',\n icon: 'users',\n isSystem: true,\n managedBy: 'engine-owned',\n description: 'Normalized pending-approver rows for indexed inbox queries',\n displayNameField: 'id',\n nameField: 'id', // [ADR-0079] canonical primary-title pointer (mirrors deprecated displayNameField)\n titleFormat: '{approver} · {request_id}',\n highlightFields: ['request_id', 'approver', 'created_at'],\n\n fields: {\n id: Field.text({ label: 'Row ID', required: true, readonly: true, group: 'System' }),\n\n organization_id: Field.lookup('sys_organization', {\n label: 'Organization',\n required: false,\n group: 'System',\n description: 'Tenant that owns this row (mirrors the parent request)',\n }),\n\n request_id: Field.lookup('sys_approval_request', {\n label: 'Request',\n required: true,\n group: 'Target',\n }),\n\n approver: Field.text({\n label: 'Approver',\n required: true,\n maxLength: 255,\n description: 'One pending-approver identity: user id, email, or role:/team: literal',\n group: 'Target',\n }),\n\n created_at: Field.datetime({\n label: 'Created At',\n required: true,\n defaultValue: 'NOW()',\n readonly: true,\n group: 'System',\n }),\n },\n\n indexes: [\n // \"My pending\" inbox: equality on the identity literal, scoped by tenant.\n { fields: ['approver', 'organization_id'] },\n // Sync path: rewrite all rows of one request on each approver-set change.\n { fields: ['request_id'] },\n ],\n\n enable: {\n // [ADR-0103] Engine-owned: approver rows are rewritten by the approval\n // engine (SYSTEM_CTX) on each approver-set change, never via generic CRUD.\n apiMethods: ['get', 'list'],\n },\n});\n","// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { ObjectSchema, Field } from '@objectstack/spec/data';\n\n/**\n * sys_approval_delegation — self-service out-of-office (OOO) delegation (#1322 M1).\n *\n * A standing, self-declared rule: \"while I (the delegator) am out between\n * `valid_from` and `valid_until`, route the approver slots that would resolve\n * to me onto my delegate instead.\" The approval service consults active rows\n * in `ApprovalService.expandApprovers` when resolving an approval node's\n * INDIVIDUALLY-routed approvers (`type: user` / `field` / `manager`) — the\n * delegate becomes a real pending approver and acts under their own identity,\n * so nothing is impersonated and the audit trail stays honest.\n *\n * Modelled as its own object (not a scalar on the better-auth-locked\n * `sys_user`), mirroring the `sys_user_position` delegation precedent\n * (ADR-0091): the validity window is enforced at RESOLUTION time via the\n * shared `isGrantActive` predicate — never by a background job (ADR-0049).\n * The window is half-open `[valid_from, valid_until)` in UTC.\n *\n * Scope note: this is the community-core OOO auto-skip only. Long-term proxy\n * \"act-as\" access (viewing/acting on another user's full queue under their\n * authority), delegation governance / segregation-of-duties, and org-wide\n * administration of others' delegations are enterprise concerns tracked\n * separately (objectstack-ai/cloud#855), not here.\n *\n * @namespace sys\n */\nexport const SysApprovalDelegation = ObjectSchema.create({\n name: 'sys_approval_delegation',\n label: 'Approval Delegation',\n pluralLabel: 'Approval Delegations',\n icon: 'user-clock',\n isSystem: true,\n managedBy: 'system',\n // [ADR-0103] Admin/user-writable DATA on a platform-defined schema: a user\n // authors their own out-of-office delegation. Affordance only (matches the\n // full-CRUD apiMethods below) — RLS/permission sets are the authz; opening it\n // keeps the system write guard from rejecting the self-service write.\n userActions: { create: true, edit: true, delete: true },\n description:\n 'Self-service out-of-office rule: route this user\\'s approver slots to a delegate within a time window (#1322 M1).',\n titleFormat: '{delegator_id} → {delegate_id}',\n highlightFields: ['delegator_id', 'delegate_id', 'valid_from', 'valid_until'],\n\n listViews: {\n active: {\n type: 'grid',\n name: 'active',\n label: 'Active',\n data: { provider: 'object', object: 'sys_approval_delegation' },\n columns: ['delegator_id', 'delegate_id', 'valid_from', 'valid_until', 'reason'],\n sort: [{ field: 'valid_until', order: 'asc' }],\n pagination: { pageSize: 50 },\n emptyState: {\n title: 'No delegations',\n message: 'Declare an out-of-office delegation so approvals route to a backup while you are away.',\n },\n },\n },\n\n fields: {\n id: Field.text({ label: 'Delegation ID', required: true, readonly: true, group: 'System' }),\n\n delegator_id: Field.lookup('sys_user', {\n label: 'Delegator',\n required: true,\n group: 'Delegation',\n description: 'The user going out of office; their individually-routed approver slots are rerouted while active.',\n }),\n\n delegate_id: Field.lookup('sys_user', {\n label: 'Delegate',\n required: true,\n group: 'Delegation',\n description: 'The backup who receives the delegator\\'s approvals while this rule is active. Acts under their own identity.',\n }),\n\n valid_from: Field.datetime({\n label: 'Valid From',\n required: false,\n group: 'Delegation',\n description:\n 'Rule is inactive before this instant. Null = active immediately. ' +\n 'Enforced at resolution time via isGrantActive (ADR-0091 D2 predicate) — never by a background job.',\n }),\n\n valid_until: Field.datetime({\n label: 'Valid Until',\n required: false,\n group: 'Delegation',\n description:\n 'Rule is inactive AT and AFTER this instant (half-open [from, until), UTC). Null = never expires.',\n }),\n\n reason: Field.text({\n label: 'Reason',\n required: false,\n maxLength: 500,\n group: 'Delegation',\n description: 'Why the delegation exists (e.g. \"Annual leave 5/26–5/30\"). Recorded on the substitution audit row.',\n }),\n\n organization_id: Field.lookup('sys_organization', {\n label: 'Organization',\n required: false,\n group: 'System',\n description: 'Tenant that owns this rule; null = applies across tenants for this delegator.',\n }),\n\n created_at: Field.datetime({\n label: 'Created At',\n defaultValue: 'NOW()',\n readonly: true,\n group: 'System',\n }),\n\n updated_at: Field.datetime({\n label: 'Updated At',\n defaultValue: 'NOW()',\n readonly: true,\n group: 'System',\n }),\n },\n\n indexes: [\n // Resolution-time lookup: \"active delegations for this delegator\".\n { fields: ['delegator_id', 'organization_id'] },\n { fields: ['delegate_id'] },\n { fields: ['valid_until'] },\n ],\n\n enable: {\n trackHistory: true,\n searchable: true,\n apiEnabled: true,\n apiMethods: ['get', 'list', 'create', 'update', 'delete'],\n trash: true,\n mru: false,\n },\n});\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { createHash, randomBytes } from 'node:crypto';\nimport {\n APPROVAL_BRANCH_LABELS,\n canonicalApproverType,\n type ApprovalNodeConfig,\n} from '@objectstack/spec/automation';\nimport type {\n IApprovalService,\n ApprovalRequestRow,\n ApprovalActionRow,\n ApprovalDecisionInput,\n ApprovalDecisionResult,\n ApprovalRecallInput,\n ApprovalRecallResult,\n ApprovalSendBackInput,\n ApprovalSendBackResult,\n ApprovalResubmitInput,\n ApprovalResubmitResult,\n ApprovalStatus,\n SharingExecutionContext,\n} from '@objectstack/spec/contracts';\nimport { isGrantActive } from '@objectstack/core';\n\n/**\n * Node-era approval runtime (ADR-0019).\n *\n * Approval is no longer a standalone engine — it is a **flow node**. A flow's\n * Approval node opens a request via {@link ApprovalService.openNodeRequest} and\n * the run suspends; a human decision via {@link ApprovalService.decide}\n * finalises the request and resumes the owning run down the matching\n * `approve` / `reject` edge.\n *\n * This service owns the durable approval *state* — `sys_approval_request` /\n * `sys_approval_action`, approver resolution (team / department / position /\n * role / manager graph), and the optional status-field mirror — plus the decision\n * API. It does not author processes, submit, or walk multi-step machinery\n * anymore; that orchestration lives on the one automation engine.\n */\nexport interface ApprovalEngine {\n find(object: string, options?: any): Promise<any[]>;\n insert(object: string, data: any, options?: any): Promise<any>;\n update(object: string, idOrData: any, dataOrOptions?: any, options?: any): Promise<any>;\n delete(object: string, options?: any): Promise<any>;\n}\n\nexport interface ApprovalClock { now(): Date }\n\n/**\n * Minimal automation surface the service uses to resume a suspended flow run\n * once a decision finalises a node-driven request. Optional — attached by the\n * plugin when an automation engine is present (see `approval-node.ts`).\n */\nexport interface ApprovalResumeSurface {\n resume?(runId: string, signal?: { output?: Record<string, unknown>; branchLabel?: string }): Promise<unknown>;\n /** Flow definition lookup, used to derive step-progress display data. */\n getFlow?(name: string): Promise<any | null>;\n /**\n * Terminally cancel a suspended run (ADR-0044). Used when a recall lands\n * during a revision window — the run is paused at the revise wait node,\n * which has no reject edge to resume down.\n */\n cancelRun?(runId: string, reason?: string): Promise<unknown>;\n}\n\n/**\n * Optional messaging surface (ADR-0012 `messaging` service). When attached,\n * thread interactions (reassign / remind / request-info / comment) notify the\n * affected users; without it they degrade to audit-only.\n */\nexport interface ApprovalMessagingSurface {\n emit(input: {\n topic: string;\n audience: string[];\n payload?: Record<string, unknown>;\n severity?: string;\n dedupKey?: string;\n source?: { object: string; id: string };\n actorId?: string;\n }): Promise<unknown>;\n}\n\n/** Minimum time between submitter reminders on one request. */\nexport const REMIND_COOLDOWN_MS = 4 * 60 * 60 * 1000;\n\n/** Named job under which the SLA escalation scan is registered (ADR-0042). */\nexport const ESCALATION_JOB_NAME = 'approvals-sla-escalation';\n/** Default interval between SLA escalation scans. */\nexport const ESCALATION_SCAN_INTERVAL_MS = 5 * 60 * 1000;\n/** Reserved actor id for machine decisions made by the SLA scanner. */\nexport const SLA_ACTOR_ID = 'system:sla';\n\n/** Default lifetime of an actionable-link token (ADR-0043). */\nexport const ACTION_TOKEN_TTL_MS = 72 * 60 * 60 * 1000;\n\n/** Outcome of redeeming (or peeking) an actionable-link token. */\nexport type ActionTokenOutcome =\n | { ok: true; action: 'approve' | 'reject'; request: ApprovalRequestRow; approverId: string }\n | { ok: false; reason: 'invalid' | 'expired' | 'consumed' | 'not_pending' | 'not_approver'; request?: ApprovalRequestRow };\n\nconst SYSTEM_CTX = { isSystem: true, positions: [], permissions: [] } as const;\n\n/**\n * Max hops when following an OOO delegation chain (#1322 M1): A out → B, B out\n * → C, … Bounds the walk so a mis-configured chain can't loop or resolve\n * unboundedly; a cycle or self-reference also stops it early.\n */\nconst OOO_MAX_CHAIN = 8;\n\n/** One OOO delegation hop applied while resolving an approver (#1322 M1/M4). */\ninterface OooSubstitution {\n /** The approver who was skipped (out of office). */\n from: string;\n /** The delegate the slot was routed to. */\n to: string;\n /** The delegator's declared reason, if any. */\n reason: string | null;\n}\n\nfunction uid(prefix: string): string {\n const g: any = globalThis as any;\n if (g.crypto?.randomUUID) return `${prefix}_${g.crypto.randomUUID()}`;\n return `${prefix}_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`;\n}\n\nfunction parseJson<T = any>(raw: unknown, fallback: T): T {\n if (raw == null || raw === '') return fallback;\n if (typeof raw === 'string') {\n try { return JSON.parse(raw) as T; } catch { return fallback; }\n }\n return raw as T;\n}\n\nfunction csvSplit(raw: unknown): string[] {\n if (!raw) return [];\n if (Array.isArray(raw)) return raw.map(String).filter(Boolean);\n return String(raw).split(',').map(s => s.trim()).filter(Boolean);\n}\n\n/**\n * Humanize a machine name for display fallback: strips a `flow:` prefix and\n * title-cases underscore/dash segments (`flow:manager_review` → \"Manager\n * Review\"). Used only when no authored label was snapshotted on the row.\n */\nfunction prettifyMachineName(raw: string | null | undefined): string | undefined {\n if (!raw) return undefined;\n const base = String(raw).replace(/^flow:/, '').trim();\n if (!base) return undefined;\n return base\n .split(/[_\\-\\s]+/)\n .filter(Boolean)\n .map(w => w.charAt(0).toUpperCase() + w.slice(1))\n .join(' ');\n}\n\nfunction rowFromRequest(row: any): ApprovalRequestRow {\n // Authored display labels ride the node-config snapshot (`__flowLabel` /\n // `__nodeLabel`) so they survive without a schema migration; fall back to a\n // prettified machine name for rows written before labels were captured.\n const cfg = parseJson<any>(row.node_config_json, undefined);\n return {\n id: String(row.id),\n organization_id: row.organization_id ?? undefined,\n process_name: String(row.process_name ?? ''),\n object_name: String(row.object_name ?? ''),\n record_id: String(row.record_id ?? ''),\n submitter_id: row.submitter_id ?? undefined,\n submitter_comment: row.submitter_comment ?? undefined,\n status: (row.status as ApprovalStatus) ?? 'pending',\n current_step: row.current_step ?? undefined,\n current_step_index: row.current_step_index ?? undefined,\n pending_approvers: csvSplit(row.pending_approvers),\n payload: parseJson(row.payload_json, undefined),\n flow_run_id: row.flow_run_id ?? undefined,\n flow_node_id: row.flow_node_id ?? undefined,\n completed_at: row.completed_at ?? undefined,\n created_at: row.created_at ?? undefined,\n updated_at: row.updated_at ?? undefined,\n // The row is created at submission time; expose the stable inbox-facing name.\n submitted_at: row.created_at ?? undefined,\n process_label: cfg?.__flowLabel ?? prettifyMachineName(row.process_name),\n step_label: cfg?.__nodeLabel ?? prettifyMachineName(row.current_step),\n sla_due_at: slaDueAt(row.created_at, cfg),\n // ADR-0044 revision round (rides the config snapshot; absent ⇒ round 1).\n round: typeof cfg?.__round === 'number' ? cfg.__round : undefined,\n } as any;\n}\n\n/** `created_at + escalation.timeoutHours`, when the node declares an SLA. */\nfunction slaDueAt(createdAt: unknown, cfg: any): string | undefined {\n const hours = cfg?.escalation?.timeoutHours;\n if (typeof hours !== 'number' || hours <= 0 || !createdAt) return undefined;\n const t = Date.parse(String(createdAt));\n if (Number.isNaN(t)) return undefined;\n return new Date(t + hours * 3600_000).toISOString();\n}\n\nfunction rowFromAction(row: any): ApprovalActionRow {\n return {\n id: String(row.id),\n request_id: String(row.request_id),\n step_name: row.step_name ?? undefined,\n step_index: row.step_index ?? undefined,\n action: row.action,\n actor_id: row.actor_id ?? undefined,\n comment: row.comment ?? undefined,\n // Decision attachments (#3266). The column shipped in #3268 but this\n // contract mapping didn't — the raw engine row carried the fileIds while\n // every consumer of listActions saw none (caught by browser verification).\n attachments: Array.isArray(row.attachments) && row.attachments.length ? row.attachments.map(String) : undefined,\n created_at: row.created_at ?? undefined,\n };\n}\n\nexport interface ApprovalServiceOptions {\n engine: ApprovalEngine;\n clock?: ApprovalClock;\n logger?: { info?: (msg: any, ...rest: any[]) => void; warn?: (msg: any, ...rest: any[]) => void; error?: (msg: any, ...rest: any[]) => void; debug?: (msg: any, ...rest: any[]) => void };\n /**\n * Optional automation surface used to resume a suspended flow run when a\n * decision finalises a request. Usually attached after construction via\n * {@link ApprovalService.attachAutomation} once the automation engine is\n * available.\n */\n automation?: ApprovalResumeSurface;\n /** Optional messaging service for thread notifications. */\n messaging?: ApprovalMessagingSurface;\n /**\n * Absolute origin prefixed onto actionable links (ADR-0043), e.g.\n * `https://app.example.com`. Defaults to relative URLs, which work inside\n * the Console and IM webviews; outbound email needs the absolute form.\n */\n publicBaseUrl?: string;\n}\n\nexport class ApprovalService implements IApprovalService {\n private readonly engine: ApprovalEngine;\n private readonly clock: ApprovalClock;\n private readonly logger?: ApprovalServiceOptions['logger'];\n private automation?: ApprovalResumeSurface;\n private messaging?: ApprovalMessagingSurface;\n private publicBaseUrl: string;\n\n constructor(opts: ApprovalServiceOptions) {\n this.engine = opts.engine;\n this.clock = opts.clock ?? { now: () => new Date() };\n this.logger = opts.logger;\n this.automation = opts.automation;\n this.messaging = opts.messaging;\n this.publicBaseUrl = (opts.publicBaseUrl ?? '').replace(/\\/$/, '');\n }\n\n /** Attach (or replace) the automation surface used to resume flow runs. */\n attachAutomation(automation: ApprovalResumeSurface): void {\n this.automation = automation;\n }\n\n /** Attach (or replace) the messaging surface used for thread notifications. */\n attachMessaging(messaging: ApprovalMessagingSurface): void {\n this.messaging = messaging;\n }\n\n /** Best-effort notification fan-out — failures only log. */\n private async notify(input: {\n topic: string;\n audience: string[];\n payload?: Record<string, unknown>;\n dedupKey?: string;\n source?: { object: string; id: string };\n actorId?: string;\n }): Promise<number> {\n const audience = input.audience.filter(a => a && !a.includes(':'));\n if (!this.messaging || !audience.length) return 0;\n // Deep-link the inbox (#2678 P1.5): a notification about one request should\n // land on that request, not the bare inbox. Rewritten centrally so every\n // call site — and any future one — inherits it; the query param is read by\n // the console inbox to auto-open the drawer.\n let payload = input.payload;\n if (\n payload?.actionUrl === '/system/approvals'\n && input.source?.object === 'sys_approval_request'\n && input.source.id\n ) {\n payload = { ...payload, actionUrl: `/system/approvals?request=${encodeURIComponent(input.source.id)}` };\n }\n try {\n await this.messaging.emit({ severity: 'info', ...input, payload, audience });\n return audience.length;\n } catch (err: any) {\n this.logger?.warn?.('[approvals] notification failed', {\n topic: input.topic, error: err?.message ?? String(err),\n });\n return 0;\n }\n }\n\n /** Load a request row and assert it is still pending. */\n private async loadPendingRow(requestId: string): Promise<any> {\n if (!requestId) throw new Error('VALIDATION_FAILED: requestId is required');\n const rows = await this.engine.find('sys_approval_request', {\n where: { id: requestId }, limit: 1, context: SYSTEM_CTX,\n });\n const raw: any = Array.isArray(rows) ? rows[0] : null;\n if (!raw) throw new Error(`REQUEST_NOT_FOUND: ${requestId}`);\n if (raw.status !== 'pending') throw new Error(`INVALID_STATE: request is ${raw.status}`);\n return raw;\n }\n\n /**\n * Expand the approvers on an Approval node into user IDs by querying the\n * graph tables for `team:` / `department:` / `position:` /\n * `org_membership_level:` / `manager:` approver types. Falls back to a\n * prefixed literal (`type:value`) when graph lookups produce nothing — so\n * existing fixtures and flows that rely on substring matching keep working.\n *\n * **Graph semantics:**\n * - `team` → flat members of `sys_team` (better-auth; no BFS)\n * - `department` → recursive BFS of `sys_business_unit.parent_business_unit_id`\n * → members of every descendant via `sys_business_unit_member`\n * - `position` → holders via `sys_user_position` ∪ `sys_member.role`\n * transition source (ADR-0090 D3 / ADR-0057 D4)\n * - `org_membership_level`\n * → users with `sys_member.role = value` in tenant — the\n * better-auth MEMBERSHIP TIER (owner/admin/member), not a\n * position; author `position` for org positions\n * - `manager` → `sys_user.manager_id` of `record[value] ?? record.owner_id`\n * - `field` → literal user id stored in `record[value]`\n * - `user` → literal value\n *\n * `role` is accepted as the deprecated spelling of `org_membership_level`\n * (ADR-0090 D3) for one window: it resolves identically and logs a warning.\n *\n * **Out-of-office (#1322 M1):** individually-routed approvers — the ones that\n * resolve to a specific person (`user` / `field` / `manager`) — are passed\n * through {@link ApprovalService.applyOooDelegation}, which reroutes them onto\n * an active delegate when the resolved user has declared OOO. Group/graph\n * approvers (`team` / `department` / `position` / `org_membership_level`) are\n * left untouched: a group still has its other members, and position-routed\n * leave is already covered by ADR-0091 job delegation. Pass an `opts.now` /\n * `opts.substitutions` collector to record the hops for audit + notification.\n */\n private async expandApprovers(\n step: any,\n record?: any,\n organizationId?: string | null,\n opts?: { now?: number; substitutions?: OooSubstitution[]; groups?: Record<string, string[]> },\n ): Promise<string[]> {\n if (!step || !Array.isArray(step.approvers)) return [];\n const now = opts?.now ?? this.clock.now().getTime();\n const out: string[] = [];\n const specs: any[] = step.approvers;\n for (let idx = 0; idx < specs.length; idx++) {\n const a = specs[idx];\n if (!a) continue;\n const ids = await this.resolveApproverSpec(a, record, organizationId, now, opts?.substitutions);\n // per_group (#3266): tag each resolved id with this spec's group. An\n // approver without an explicit `group` forms its own group keyed by\n // position, so a plain per-approver list still behaves predictably.\n const groupKey = a.group != null && String(a.group) !== '' ? String(a.group) : `#${idx}`;\n for (const u of ids) {\n if (!u) continue;\n out.push(u);\n if (opts?.groups) (opts.groups[u] ??= []).push(groupKey);\n }\n }\n return out.filter(Boolean);\n }\n\n /**\n * Resolve ONE approver spec to concrete approver identities, applying OOO\n * substitution (#1322) to individually-routed types. Extracted from\n * {@link ApprovalService.expandApprovers} so the caller can tag each spec's\n * resolved ids with a group (#3266) without duplicating the resolution logic.\n * Returns the `type:value` literal as a single-element fallback when a graph\n * lookup yields nothing — same behaviour as before the extraction.\n */\n private async resolveApproverSpec(\n a: any,\n record: any,\n organizationId: string | null | undefined,\n now: number,\n substitutions?: OooSubstitution[],\n ): Promise<string[]> {\n // ADR-0090 D3: `role` is the deprecated spelling of `org_membership_level`.\n // Resolve on the canonical type, but keep the AUTHORED spelling in the\n // `type:value` fallback below — stored `sys_approval_approver` rows and\n // `pending_approvers` slots from 15.x carry the old literal.\n const type = canonicalApproverType(String(a.type));\n if (type !== a.type) {\n this.logger?.warn?.(\n `[approvals] approver type '${a.type}' is deprecated (ADR-0090 D3) — author '${type}' instead`,\n { deprecated: a.type, canonical: type },\n );\n }\n if (type === 'user') {\n return this.applyOooDelegation(String(a.value), now, organizationId, substitutions);\n }\n if (type === 'field' && record) {\n return this.applyOooDelegation(String((record as any)[a.value] ?? ''), now, organizationId, substitutions);\n }\n try {\n if (type === 'team') {\n const users = await this.expandTeamUsers(String(a.value));\n if (users.length) return users;\n } else if (type === 'department' || type === 'business_unit' || type === 'bu') {\n const users = await this.expandBusinessUnitUsers(String(a.value), organizationId);\n if (users.length) return users;\n } else if (type === 'position') {\n const users = await this.expandPositionUsers(String(a.value), organizationId);\n if (users.length) return users;\n } else if (type === 'org_membership_level') {\n const users = await this.expandMembershipTierUsers(String(a.value), organizationId);\n if (users.length) return users;\n } else if (type === 'manager' && record) {\n const subject = (record as any)[a.value] ?? (record as any).owner_id;\n if (subject) {\n const mgr = await this.lookupManager(String(subject));\n if (mgr) return this.applyOooDelegation(mgr, now, organizationId, substitutions);\n }\n }\n } catch { /* fall through */ }\n return [`${a.type}:${a.value}`];\n }\n\n /** Flat team — `sys_team` is better-auth's collaboration grouping (no hierarchy). */\n private async expandTeamUsers(teamId: string): Promise<string[]> {\n if (!teamId) return [];\n let rows: any[] = [];\n try {\n rows = await this.engine.find('sys_team_member', {\n filter: { team_id: teamId },\n fields: ['user_id'],\n limit: 10000,\n context: SYSTEM_CTX,\n } as any);\n } catch { rows = []; }\n return Array.from(new Set((rows ?? []).map((r: any) => String(r.user_id ?? '')).filter(Boolean)));\n }\n\n /** Recursive department — walks `sys_business_unit.parent_business_unit_id`. */\n private async expandBusinessUnitUsers(businessUnitId: string, organizationId?: string | null): Promise<string[]> {\n if (!businessUnitId) return [];\n // Seed sanity check: skip if dept doesn't exist or is inactive within tenant.\n try {\n const seed = await this.engine.find('sys_business_unit', {\n filter: organizationId\n ? { id: businessUnitId, organization_id: organizationId }\n : { id: businessUnitId },\n fields: ['id', 'active'],\n limit: 1,\n context: SYSTEM_CTX,\n } as any);\n const seedRow: any = Array.isArray(seed) ? seed[0] : null;\n if (!seedRow || seedRow.active === false) return [];\n } catch { return []; }\n\n const seen = new Set<string>([businessUnitId]);\n const queue: string[] = [businessUnitId];\n while (queue.length) {\n const parent = queue.shift()!;\n let kids: any[] = [];\n try {\n const filter: any = { parent_business_unit_id: parent, active: { $ne: false } };\n if (organizationId) filter.organization_id = organizationId;\n kids = await this.engine.find('sys_business_unit', { filter, fields: ['id'], limit: 1000, context: SYSTEM_CTX } as any);\n } catch { kids = []; }\n for (const k of kids ?? []) {\n const kid = String((k as any).id ?? '');\n if (kid && !seen.has(kid)) { seen.add(kid); queue.push(kid); }\n }\n }\n let rows: any[] = [];\n try {\n rows = await this.engine.find('sys_business_unit_member', {\n filter: { business_unit_id: { $in: Array.from(seen) } },\n fields: ['user_id'],\n limit: 10000,\n context: SYSTEM_CTX,\n } as any);\n } catch { rows = []; }\n return Array.from(new Set((rows ?? []).map((r: any) => String(r.user_id ?? '')).filter(Boolean)));\n }\n\n /**\n * Position holders (ADR-0090 D3): `sys_user_position` is the platform-owned\n * assignment table, keyed by the position's machine name (ADR-0057 D4),\n * unioned with the better-auth membership string (`sys_member.role`) as a\n * transition source — the same semantics as `PositionGraphService` in\n * `plugin-sharing`, so an approval routes to exactly the users the sharing\n * engine would expand for the same position.\n */\n private async expandPositionUsers(positionName: string, organizationId?: string | null): Promise<string[]> {\n if (!positionName) return [];\n const users = new Set<string>();\n const filter: any = { position: positionName };\n if (organizationId) filter.organization_id = organizationId;\n try {\n const rows = await this.engine.find('sys_user_position', {\n filter, fields: ['user_id'], limit: 10000, context: SYSTEM_CTX,\n } as any);\n for (const r of (rows ?? []) as any[]) {\n const uid = String(r.user_id ?? '');\n if (uid) users.add(uid);\n }\n } catch { /* table may not exist on minimal stacks — union source below still applies */ }\n // ADR-0057 D4 transition source: pre-migration stacks still carry the\n // position name in better-auth's `sys_member.role` column, so the same\n // lookup serves a position name here and a membership tier for\n // `org_membership_level` — the column is one, the two concepts are not.\n for (const uid of await this.expandMembershipTierUsers(positionName, organizationId)) users.add(uid);\n return Array.from(users);\n }\n\n /**\n * better-auth org-membership tier (`sys_member.role`: owner/admin/member) —\n * NOT positions. Named for the projection (`org_membership_level`, ADR-0057\n * D7 / ADR-0090 D3), not for better-auth's column: the column name is theirs\n * and stays, the platform-facing word does not.\n */\n private async expandMembershipTierUsers(tier: string, organizationId?: string | null): Promise<string[]> {\n if (!tier) return [];\n const filter: any = { role: tier };\n if (organizationId) filter.organization_id = organizationId;\n let rows: any[] = [];\n try {\n rows = await this.engine.find('sys_member', { filter, fields: ['user_id'], limit: 10000, context: SYSTEM_CTX } as any);\n } catch { rows = []; }\n return Array.from(new Set((rows ?? []).map((r: any) => String(r.user_id ?? '')).filter(Boolean)));\n }\n\n private async lookupManager(userId: string): Promise<string | null> {\n try {\n const rows = await this.engine.find('sys_user', {\n filter: { id: userId }, fields: ['id', 'manager_id'], limit: 1, context: SYSTEM_CTX,\n } as any);\n const row: any = Array.isArray(rows) ? rows[0] : null;\n return row?.manager_id ? String(row.manager_id) : null;\n } catch { return null; }\n }\n\n /**\n * Out-of-office auto-skip (#1322 M1). Given an individually-routed approver\n * id, follow any active `sys_approval_delegation` chain and return the id the\n * slot should actually go to — the delegate acts under their own identity, so\n * no impersonation is involved. Returns `[userId]` unchanged when there is no\n * active delegation. Each hop is appended to `collector` (when supplied) so\n * the caller can audit + notify (M4).\n *\n * The chain (A out → B, B out → C, …) is bounded by {@link OOO_MAX_CHAIN} and\n * stops on a self-reference or a cycle, so a mis-declared loop degrades to the\n * last reachable delegate rather than hanging.\n */\n private async applyOooDelegation(\n userId: string,\n now: number,\n organizationId?: string | null,\n collector?: OooSubstitution[],\n ): Promise<string[]> {\n const start = String(userId ?? '').trim();\n if (!start) return [];\n let current = start;\n const visited = new Set<string>([current]);\n for (let hop = 0; hop < OOO_MAX_CHAIN; hop++) {\n const del = await this.lookupActiveDelegation(current, now, organizationId);\n if (!del) break;\n const to = String(del.delegate_id ?? '').trim();\n if (!to || to === current || visited.has(to)) break; // no-op / self / cycle\n collector?.push({ from: current, to, reason: del.reason != null ? String(del.reason) : null });\n visited.add(to);\n current = to;\n }\n return [current];\n }\n\n /**\n * The active OOO delegation for a delegator at `now`, or null. Validity is the\n * shared `isGrantActive` half-open window (ADR-0091 D2), enforced here at\n * resolution time — never by a background job. When several rows are active,\n * the one expiring soonest wins (the most specific coverage window).\n */\n private async lookupActiveDelegation(\n delegatorId: string,\n now: number,\n organizationId?: string | null,\n ): Promise<any | null> {\n if (!delegatorId) return null;\n let rows: any[] = [];\n try {\n rows = await this.engine.find('sys_approval_delegation', {\n filter: { delegator_id: delegatorId },\n fields: ['id', 'delegator_id', 'delegate_id', 'valid_from', 'valid_until', 'reason', 'organization_id'],\n limit: 50,\n context: SYSTEM_CTX,\n } as any);\n } catch { return null; } // table absent on minimal stacks — no OOO, resolve as-is\n const active = (rows ?? []).filter((r: any) =>\n isGrantActive(r, now)\n // A null-org rule applies across tenants; a scoped rule only within its tenant.\n && (organizationId == null || r.organization_id == null || String(r.organization_id) === String(organizationId)));\n if (!active.length) return null;\n active.sort((a: any, b: any) => {\n const au = a.valid_until ? Date.parse(String(a.valid_until)) : Number.POSITIVE_INFINITY;\n const bu = b.valid_until ? Date.parse(String(b.valid_until)) : Number.POSITIVE_INFINITY;\n return au - bu;\n });\n return active[0];\n }\n\n /** Mirror a request status onto a business-object field, if configured. */\n private async mirrorStatusField(object: string, recordId: string, field: string, status: string): Promise<void> {\n try {\n await this.engine.update(object, { id: recordId, [field]: status }, { context: SYSTEM_CTX });\n } catch (err: any) {\n this.logger?.warn?.(`[approvals] mirrorStatusField failed: ${err?.message ?? err}`);\n }\n }\n\n // ── ADR-0019: Approval-as-flow-node ──────────────────────────\n //\n // A flow's Approval node opens a request via `openNodeRequest` (carrying its\n // own approvers/behavior config and the suspended run id), then suspends. A\n // later `decide` finalizes it and resumes the flow run down the matching\n // `approve`/`reject` edge. The record lock is enforced by a beforeUpdate hook\n // keyed on a *pending* request, so finalizing auto-releases it.\n\n /**\n * Open a pending approval request on behalf of a flow's Approval node. The\n * node config (approvers / behavior / status field) is snapshotted on the row\n * so a decision can be made without any process to resolve against.\n */\n async openNodeRequest(\n input: {\n object: string;\n recordId: string;\n runId: string;\n nodeId: string;\n config: ApprovalNodeConfig;\n flowName?: string;\n /** Authored flow label, snapshotted for inbox display. */\n flowLabel?: string;\n /** Authored node label, snapshotted for inbox display. */\n nodeLabel?: string;\n submitterId?: string | null;\n record?: any;\n organizationId?: string | null;\n },\n context: SharingExecutionContext,\n ): Promise<ApprovalRequestRow> {\n if (!input.object) throw new Error('VALIDATION_FAILED: object is required');\n if (!input.recordId) throw new Error('VALIDATION_FAILED: recordId is required');\n if (!input.runId) throw new Error('VALIDATION_FAILED: runId is required');\n\n // One pending request per (object, record).\n const existing = await this.engine.find('sys_approval_request', {\n where: { object_name: input.object, record_id: input.recordId, status: 'pending' },\n limit: 1, context: SYSTEM_CTX,\n });\n if (Array.isArray(existing) && existing[0]) {\n throw new Error(`DUPLICATE_REQUEST: a pending approval already exists for ${input.object}/${input.recordId}`);\n }\n\n const ctxOrg = (context as any)?.organizationId ?? (context as any)?.tenantId ?? input.organizationId ?? null;\n const nowDate = this.clock.now();\n // OOO auto-skip (#1322 M1): reroute individually-routed approvers who are\n // out of office. Collected hops drive the audit + notification below (M4).\n const substitutions: OooSubstitution[] = [];\n // Group membership per resolved approver (#3266) — snapshotted so quorum /\n // per_group finalization is decided against the slate resolved at OPEN time\n // (OOO-substituted), not re-resolved live at each decision.\n const groups: Record<string, string[]> = {};\n const approvers = await this.expandApprovers(\n { approvers: input.config.approvers }, input.record, ctxOrg, { now: nowDate.getTime(), substitutions, groups },\n );\n\n const now = nowDate.toISOString();\n const id = uid('areq');\n const processName = `flow:${input.flowName ?? input.nodeId}`;\n // Display labels ride the config snapshot (no schema migration needed);\n // `rowFromRequest` surfaces them as `process_label` / `step_label`.\n const configSnapshot: any = { ...input.config };\n if (input.flowLabel) configSnapshot.__flowLabel = input.flowLabel;\n if (input.nodeLabel) configSnapshot.__nodeLabel = input.nodeLabel;\n // Snapshot the resolved approver→group map for quorum/per_group tallying.\n if (input.config.behavior === 'quorum' || input.config.behavior === 'per_group') {\n configSnapshot.__approverGroups = groups;\n }\n // ADR-0044 round numbering: rounds of a revise loop share the run — count\n // this (run, node)'s prior requests; the new one is round N+1. Stamped on\n // the snapshot (precedent: __flowLabel), so no schema migration.\n try {\n const prior = await this.engine.find('sys_approval_request', {\n where: { flow_run_id: input.runId, flow_node_id: input.nodeId }, limit: 500, context: SYSTEM_CTX,\n });\n const n = Array.isArray(prior) ? prior.length : 0;\n if (n > 0) configSnapshot.__round = n + 1;\n } catch { /* round display is best-effort */ }\n const row: any = {\n id,\n process_name: processName,\n object_name: input.object,\n record_id: input.recordId,\n submitter_id: input.submitterId ?? context.userId ?? null,\n status: 'pending',\n current_step: input.nodeId,\n current_step_index: 0,\n pending_approvers: approvers.join(','),\n payload_json: input.record != null ? JSON.stringify(input.record) : null,\n flow_run_id: input.runId,\n flow_node_id: input.nodeId,\n node_config_json: JSON.stringify(configSnapshot),\n organization_id: ctxOrg,\n created_at: now,\n updated_at: now,\n };\n await this.engine.insert('sys_approval_request', row, { context: SYSTEM_CTX });\n await this.syncApproverIndex(id, approvers, ctxOrg, now);\n await this.engine.insert('sys_approval_action', {\n id: uid('aact'), request_id: id, organization_id: ctxOrg,\n step_name: input.nodeId, step_index: 0, action: 'submit',\n actor_id: input.submitterId ?? context.userId ?? null, comment: null, created_at: now,\n }, { context: SYSTEM_CTX });\n\n // OOO substitution audit + notification (#1322 M4). Each hop that rerouted\n // an approver away from an out-of-office user is recorded on the request's\n // audit trail (a system action, no human actor) and notified to both the\n // delegate — who now owns the slot — and the skipped approver.\n for (const sub of substitutions) {\n await this.engine.insert('sys_approval_action', {\n id: uid('aact'), request_id: id, organization_id: ctxOrg,\n step_name: input.nodeId, step_index: 0, action: 'ooo_substitute',\n actor_id: null,\n comment: `${sub.from} → ${sub.to}${sub.reason ? ` — ${sub.reason}` : ''}`,\n created_at: now,\n }, { context: SYSTEM_CTX });\n await this.notify({\n topic: 'approval.ooo_substituted',\n audience: [sub.to],\n source: { object: 'sys_approval_request', id },\n dedupKey: `approval-ooo-${id}-${sub.to}`,\n payload: {\n title: 'Approval routed to you (out-of-office cover)',\n message: `You are covering an approval on ${input.object}/${input.recordId} while ${sub.from} is out of office.`,\n actionUrl: '/system/approvals',\n },\n });\n await this.notify({\n topic: 'approval.ooo_skipped',\n audience: [sub.from],\n source: { object: 'sys_approval_request', id },\n dedupKey: `approval-ooo-skip-${id}-${sub.from}`,\n payload: {\n title: 'Approval routed to your delegate',\n message: `An approval on ${input.object}/${input.recordId} was routed to ${sub.to} while you are out of office.`,\n actionUrl: '/system/approvals',\n },\n });\n }\n\n // Record lock (when `lockRecord !== false`) is enforced by the beforeUpdate\n // hook keyed on the now-pending request; no extra write needed here.\n if (input.config.approvalStatusField) {\n await this.mirrorStatusField(input.object, input.recordId, input.config.approvalStatusField, 'pending');\n }\n\n return rowFromRequest(row);\n }\n\n /**\n * True when the approve tally satisfies the node's `behavior` (#3266):\n * - `unanimous` — every resolved approver approved.\n * - `quorum` — at least `minApprovals` distinct approvals (default = all).\n * - `per_group` — every group reached `minApprovals` approvals (default 1).\n * Thresholds are clamped to the resolvable count / group size, so a mis-set\n * value can never deadlock a request.\n */\n private isApprovalSatisfied(\n behavior: string,\n config: ApprovalNodeConfig,\n original: string[],\n groupMap: Record<string, string[]>,\n approved: Set<string>,\n ): boolean {\n if (behavior === 'unanimous') {\n return original.length > 0 && original.every(a => approved.has(a));\n }\n if (behavior === 'quorum') {\n const n = original.length || 1;\n const need = Math.min(Math.max(1, config.minApprovals ?? n), n);\n // Count distinct approvals (robust to OOO/reassign changing who holds a slot).\n return approved.size >= need;\n }\n if (behavior === 'per_group') {\n const perGroupNeed = Math.max(1, config.minApprovals ?? 1);\n const size: Record<string, number> = {};\n for (const gs of Object.values(groupMap)) for (const g of gs) size[g] = (size[g] ?? 0) + 1;\n const groups = Object.keys(size);\n if (!groups.length) return true; // nothing to gate\n const got: Record<string, number> = {};\n for (const a of approved) for (const g of (groupMap[a] ?? [])) got[g] = (got[g] ?? 0) + 1;\n return groups.every(g => (got[g] ?? 0) >= Math.min(perGroupNeed, size[g]));\n }\n return true; // first_response and unknown → first approval finalizes\n }\n\n /**\n * Record a decision on a node-driven request. Honours the node's `behavior`\n * (#3266): `first_response` finalizes on the first approval; `unanimous`,\n * `quorum`, and `per_group` hold the request open until their tally is met\n * (see {@link ApprovalService.isApprovalSatisfied}). A rejection always\n * finalizes the node (one veto). When the request finalizes, returns the\n * suspended run id + node id so the caller (or {@link ApprovalService.decide})\n * can resume the flow down the matching branch.\n */\n async decideNode(\n requestId: string,\n input: { decision: 'approve' | 'reject'; actorId: string; comment?: string; attachments?: string[] },\n context: SharingExecutionContext,\n ): Promise<{ request: ApprovalRequestRow; runId: string | null; nodeId: string | null; finalized: boolean; decision: 'approve' | 'reject' }> {\n if (!requestId) throw new Error('VALIDATION_FAILED: requestId is required');\n if (!input?.actorId) throw new Error('VALIDATION_FAILED: actorId is required');\n if (input.decision !== 'approve' && input.decision !== 'reject') {\n throw new Error('VALIDATION_FAILED: decision must be approve|reject');\n }\n\n // Read the raw row to reach flow_* correlation + the node config snapshot.\n const rawRows = await this.engine.find('sys_approval_request', {\n where: { id: requestId }, limit: 1, context: SYSTEM_CTX,\n });\n const raw: any = Array.isArray(rawRows) ? rawRows[0] : null;\n if (!raw) throw new Error(`REQUEST_NOT_FOUND: ${requestId}`);\n if (raw.status !== 'pending') throw new Error(`INVALID_STATE: request is ${raw.status}`);\n\n const pendingApprovers = csvSplit(raw.pending_approvers);\n if (!context.isSystem && !pendingApprovers.includes(input.actorId)) {\n throw new Error(`FORBIDDEN: actor '${input.actorId}' is not a pending approver`);\n }\n\n const config = parseJson<ApprovalNodeConfig>(raw.node_config_json, { approvers: [], behavior: 'first_response' } as any);\n const org = raw.organization_id ?? null;\n const nodeId: string | null = raw.flow_node_id ?? raw.current_step ?? null;\n const runId: string | null = raw.flow_run_id ?? null;\n const now = this.clock.now().toISOString();\n\n // Audit the decision first so the quorum/per_group tally below sees it.\n await this.engine.insert('sys_approval_action', {\n id: uid('aact'), request_id: requestId, organization_id: org,\n step_name: nodeId, step_index: 0, action: input.decision,\n actor_id: input.actorId, comment: input.comment ?? null,\n attachments: input.attachments?.length ? input.attachments : null,\n created_at: now,\n }, { context: SYSTEM_CTX });\n\n // Multi-approver aggregation on approve (#3266). A rejection always\n // finalizes the node (one veto), so only the approve path can hold it open.\n // `first_response` finalizes on the first approval (falls straight through).\n const behavior = config.behavior ?? 'first_response';\n if (input.decision === 'approve' && behavior !== 'first_response') {\n const acts = await this.engine.find('sys_approval_action', {\n where: { request_id: requestId, step_index: 0, action: 'approve' }, limit: 1000, context: SYSTEM_CTX,\n });\n const approved = new Set<string>((acts ?? []).map((a: any) => String(a.actor_id ?? '')).filter(Boolean));\n\n // quorum / per_group tally against the OPEN-time snapshot (already\n // OOO-substituted). unanimous re-resolves for back-compat with requests\n // opened before the snapshot existed.\n const snapshotGroups = (config as any).__approverGroups as Record<string, string[]> | undefined;\n let original: string[];\n let groupMap: Record<string, string[]>;\n if (snapshotGroups && (behavior === 'quorum' || behavior === 'per_group')) {\n groupMap = snapshotGroups;\n original = Object.keys(snapshotGroups);\n } else {\n original = await this.expandApprovers(\n { approvers: config.approvers }, parseJson(raw.payload_json, undefined), org,\n );\n groupMap = {};\n }\n\n if (!this.isApprovalSatisfied(behavior, config, original, groupMap, approved)) {\n const stillPending = original.filter(a => !approved.has(a));\n await this.engine.update('sys_approval_request', {\n id: requestId, pending_approvers: stillPending.join(','), updated_at: now,\n }, { context: SYSTEM_CTX });\n await this.syncApproverIndex(requestId, stillPending, org, now);\n const fresh = await this.getRequest(requestId, context);\n return { request: fresh!, runId, nodeId, finalized: false, decision: input.decision };\n }\n }\n\n const finalStatus = input.decision === 'approve' ? 'approved' : 'rejected';\n await this.engine.update('sys_approval_request', {\n id: requestId, status: finalStatus, pending_approvers: null, completed_at: now, updated_at: now,\n }, { context: SYSTEM_CTX });\n await this.syncApproverIndex(requestId, [], org, now);\n if (config.approvalStatusField) {\n await this.mirrorStatusField(raw.object_name, raw.record_id, config.approvalStatusField, finalStatus);\n }\n const fresh = await this.getRequest(requestId, context);\n return { request: fresh!, runId, nodeId, finalized: true, decision: input.decision };\n }\n\n /**\n * Public contract entrypoint (ADR-0019). Records a decision on a node-driven\n * request via {@link ApprovalService.decideNode} and, when it finalizes,\n * resumes the owning flow run down the matching `approve` / `reject` edge.\n */\n async decide(\n requestId: string,\n input: ApprovalDecisionInput,\n context: SharingExecutionContext,\n ): Promise<ApprovalDecisionResult> {\n const result = await this.decideNode(requestId, input, context);\n\n let resumed = false;\n if (result.finalized && result.runId && typeof this.automation?.resume === 'function') {\n const branchLabel = result.decision === 'approve'\n ? APPROVAL_BRANCH_LABELS.approve\n : APPROVAL_BRANCH_LABELS.reject;\n try {\n await this.automation.resume(result.runId, {\n branchLabel,\n output: { decision: result.decision, requestId },\n });\n resumed = true;\n } catch (err: any) {\n this.logger?.warn?.('[approvals] resume after decision failed', {\n request: requestId, run: result.runId, error: err?.message ?? String(err),\n });\n }\n }\n\n return {\n request: result.request,\n finalized: result.finalized,\n decision: result.decision,\n runId: result.runId,\n resumed,\n };\n }\n\n /**\n * Withdraw a pending request (submitter only). Finalises the row as\n * `recalled`, releases the record lock (keyed on pending status), mirrors\n * the status field when configured, and resumes the owning flow run down\n * the `reject` branch with `output.decision = 'recall'` — leaving the run\n * suspended forever would leak it.\n *\n * ADR-0044: also valid on the LATEST `returned` request of its run — the\n * submitter abandons the revision window instead of resubmitting. The run\n * is then paused at the revise wait node (no reject edge), so it is\n * terminally cancelled via {@link ApprovalResumeSurface.cancelRun} rather\n * than resumed.\n */\n async recall(\n requestId: string,\n input: ApprovalRecallInput,\n context: SharingExecutionContext,\n ): Promise<ApprovalRecallResult> {\n if (!requestId) throw new Error('VALIDATION_FAILED: requestId is required');\n if (!input?.actorId) throw new Error('VALIDATION_FAILED: actorId is required');\n\n const rawRows = await this.engine.find('sys_approval_request', {\n where: { id: requestId }, limit: 1, context: SYSTEM_CTX,\n });\n const raw: any = Array.isArray(rawRows) ? rawRows[0] : null;\n if (!raw) throw new Error(`REQUEST_NOT_FOUND: ${requestId}`);\n const inReviseWindow = raw.status === 'returned';\n if (raw.status !== 'pending' && !inReviseWindow) {\n throw new Error(`INVALID_STATE: request is ${raw.status}`);\n }\n if (!context.isSystem && raw.submitter_id && String(raw.submitter_id) !== String(input.actorId)) {\n throw new Error(`FORBIDDEN: only the submitter may recall this request`);\n }\n // A returned request is only recallable while it is still the run's live\n // frontier — a resubmitted (or later-node) request supersedes it.\n if (inReviseWindow) await this.assertLatestForRun(raw);\n\n const config = parseJson<ApprovalNodeConfig>(raw.node_config_json, { approvers: [], behavior: 'first_response' } as any);\n const org = raw.organization_id ?? null;\n const nodeId: string | null = raw.flow_node_id ?? raw.current_step ?? null;\n const runId: string | null = raw.flow_run_id ?? null;\n const now = this.clock.now().toISOString();\n\n await this.engine.insert('sys_approval_action', {\n id: uid('aact'), request_id: requestId, organization_id: org,\n step_name: nodeId, step_index: 0, action: 'recall',\n actor_id: input.actorId, comment: input.comment ?? null, created_at: now,\n }, { context: SYSTEM_CTX });\n\n await this.engine.update('sys_approval_request', {\n id: requestId, status: 'recalled', pending_approvers: null, completed_at: now, updated_at: now,\n }, { context: SYSTEM_CTX });\n await this.syncApproverIndex(requestId, [], org, now);\n if (config.approvalStatusField) {\n await this.mirrorStatusField(raw.object_name, raw.record_id, config.approvalStatusField, 'recalled');\n }\n\n let resumed = false;\n if (inReviseWindow) {\n // ADR-0044: the run is paused at the revise wait node, which has no\n // reject out-edge to resume down — terminally cancel it instead.\n if (runId && typeof this.automation?.cancelRun === 'function') {\n try {\n await this.automation.cancelRun(runId, `approval request ${requestId} recalled during revision`);\n } catch (err: any) {\n this.logger?.warn?.('[approvals] cancelRun after revise-window recall failed', {\n request: requestId, run: runId, error: err?.message ?? String(err),\n });\n }\n }\n } else if (runId && typeof this.automation?.resume === 'function') {\n try {\n await this.automation.resume(runId, {\n branchLabel: APPROVAL_BRANCH_LABELS.reject,\n output: { decision: 'recall', requestId },\n });\n resumed = true;\n } catch (err: any) {\n this.logger?.warn?.('[approvals] resume after recall failed', {\n request: requestId, run: runId, error: err?.message ?? String(err),\n });\n }\n }\n\n const fresh = await this.getRequest(requestId, context);\n return { request: fresh!, runId, resumed };\n }\n\n // ── Send back for revision / resubmit (ADR-0044) ─────────────\n\n /**\n * ADR-0044 send back for revision. Finalises the pending request as\n * `returned` (a third terminal state — approver-initiated rework, distinct\n * from submitter-initiated `recalled`) and resumes the owning flow run down\n * its `revise` edge to a wait point: the record lock (keyed on `pending`)\n * releases, the submitter reworks the data, then {@link resubmit}s.\n *\n * Requires the approval node to declare a `revise` out-edge — validated\n * BEFORE any mutation, because resuming with an unmatched `branchLabel`\n * falls back to *all* out-edges. Past the node's `maxRevisions` budget the\n * request auto-rejects instead (resumes down `reject` with\n * `output.autoRejected = true`) so instances cannot orbit forever.\n */\n async sendBack(\n requestId: string,\n input: ApprovalSendBackInput,\n context: SharingExecutionContext,\n ): Promise<ApprovalSendBackResult> {\n if (!input?.actorId) throw new Error('VALIDATION_FAILED: actorId is required');\n const raw = await this.loadPendingRow(requestId);\n const pending = csvSplit(raw.pending_approvers);\n if (!context.isSystem && !pending.includes(input.actorId)) {\n throw new Error(`FORBIDDEN: actor '${input.actorId}' is not a pending approver`);\n }\n\n const config = parseJson<ApprovalNodeConfig>(raw.node_config_json, { approvers: [], behavior: 'first_response' } as any);\n const org = raw.organization_id ?? null;\n const nodeId: string | null = raw.flow_node_id ?? raw.current_step ?? null;\n const runId: string | null = raw.flow_run_id ?? null;\n\n await this.assertReviseEdge(raw, nodeId);\n\n const now = this.clock.now().toISOString();\n const maxRevisions = typeof (config as any).maxRevisions === 'number' ? (config as any).maxRevisions : 3;\n let priorSendBacks = 0;\n if (runId && nodeId) {\n const siblings = await this.engine.find('sys_approval_request', {\n where: { flow_run_id: runId, flow_node_id: nodeId, status: 'returned' }, limit: 500, context: SYSTEM_CTX,\n });\n priorSendBacks = Array.isArray(siblings) ? siblings.length : 0;\n }\n\n // Audit the revise intent first (audit-first, like decideNode) — on the\n // auto-reject path the trail then reads `revise → reject`, preserving\n // what the approver actually asked for.\n await this.engine.insert('sys_approval_action', {\n id: uid('aact'), request_id: requestId, organization_id: org,\n step_name: nodeId, step_index: 0, action: 'revise',\n actor_id: input.actorId, comment: input.comment ?? null, created_at: now,\n }, { context: SYSTEM_CTX });\n\n if (priorSendBacks >= maxRevisions) {\n // Revision budget exhausted — auto-reject (ADR-0044 loop guard).\n await this.engine.insert('sys_approval_action', {\n id: uid('aact'), request_id: requestId, organization_id: org,\n step_name: nodeId, step_index: 0, action: 'reject',\n actor_id: input.actorId,\n comment: `Auto-rejected: revision limit (${maxRevisions}) exceeded`, created_at: now,\n }, { context: SYSTEM_CTX });\n await this.engine.update('sys_approval_request', {\n id: requestId, status: 'rejected', pending_approvers: null, completed_at: now, updated_at: now,\n }, { context: SYSTEM_CTX });\n await this.syncApproverIndex(requestId, [], org, now);\n if (config.approvalStatusField) {\n await this.mirrorStatusField(raw.object_name, raw.record_id, config.approvalStatusField, 'rejected');\n }\n let resumed = false;\n if (runId && typeof this.automation?.resume === 'function') {\n try {\n await this.automation.resume(runId, {\n branchLabel: APPROVAL_BRANCH_LABELS.reject,\n output: { decision: 'reject', autoRejected: true, requestId },\n });\n resumed = true;\n } catch (err: any) {\n this.logger?.warn?.('[approvals] resume after auto-reject failed', {\n request: requestId, run: runId, error: err?.message ?? String(err),\n });\n }\n }\n if (raw.submitter_id) {\n await this.notify({\n topic: 'approval.returned',\n audience: [String(raw.submitter_id)],\n actorId: input.actorId,\n source: { object: 'sys_approval_request', id: requestId },\n payload: {\n title: 'Approval auto-rejected',\n message: `Your ${raw.object_name}/${raw.record_id} exceeded the revision limit (${maxRevisions}) and was rejected.`,\n actionUrl: '/system/approvals',\n },\n });\n }\n const fresh = await this.getRequest(requestId, context);\n return { request: fresh!, runId, resumed, autoRejected: true };\n }\n\n await this.engine.update('sys_approval_request', {\n id: requestId, status: 'returned', pending_approvers: null, completed_at: now, updated_at: now,\n }, { context: SYSTEM_CTX });\n await this.syncApproverIndex(requestId, [], org, now);\n if (config.approvalStatusField) {\n await this.mirrorStatusField(raw.object_name, raw.record_id, config.approvalStatusField, 'returned');\n }\n\n let resumed = false;\n if (runId && typeof this.automation?.resume === 'function') {\n try {\n await this.automation.resume(runId, {\n branchLabel: APPROVAL_BRANCH_LABELS.revise,\n output: { decision: 'revise', requestId },\n });\n resumed = true;\n } catch (err: any) {\n this.logger?.warn?.('[approvals] resume after send-back failed', {\n request: requestId, run: runId, error: err?.message ?? String(err),\n });\n }\n }\n\n if (raw.submitter_id) {\n await this.notify({\n topic: 'approval.returned',\n audience: [String(raw.submitter_id)],\n actorId: input.actorId,\n source: { object: 'sys_approval_request', id: requestId },\n payload: {\n title: 'Sent back for revision',\n message: input.comment?.trim() || `Your ${raw.object_name}/${raw.record_id} needs rework before it can be approved.`,\n actionUrl: '/system/approvals',\n },\n });\n }\n\n const fresh = await this.getRequest(requestId, context);\n return { request: fresh!, runId, resumed };\n }\n\n /**\n * ADR-0044 resubmit after rework. Valid on the LATEST `returned` request of\n * its run, submitter-only. Audits `resubmit` on the returned (round-N)\n * request and resumes the run from the revise wait node; traversal walks\n * the declared back-edge into the approval node, whose executor opens the\n * round-N+1 request — fresh approver slate, record re-locks.\n */\n async resubmit(\n requestId: string,\n input: ApprovalResubmitInput,\n context: SharingExecutionContext,\n ): Promise<ApprovalResubmitResult> {\n if (!input?.actorId) throw new Error('VALIDATION_FAILED: actorId is required');\n const rawRows = await this.engine.find('sys_approval_request', {\n where: { id: requestId }, limit: 1, context: SYSTEM_CTX,\n });\n const raw: any = Array.isArray(rawRows) ? rawRows[0] : null;\n if (!raw) throw new Error(`REQUEST_NOT_FOUND: ${requestId}`);\n if (raw.status !== 'returned') {\n throw new Error(`INVALID_STATE: request is ${raw.status} (resubmit applies to returned requests)`);\n }\n if (!context.isSystem && raw.submitter_id && String(raw.submitter_id) !== String(input.actorId)) {\n throw new Error('FORBIDDEN: only the submitter may resubmit');\n }\n await this.assertLatestForRun(raw);\n\n // A colliding pending request on the same record (e.g. a record-change\n // trigger re-fired off an edit made inside the revise window) would make\n // the approval node's re-entry fail AFTER the engine consumed the\n // suspension — permanently killing the run. Refuse up front instead; the\n // submitter resolves the collision (recall the other request) first.\n const colliding = await this.engine.find('sys_approval_request', {\n where: { object_name: raw.object_name, record_id: raw.record_id, status: 'pending' },\n limit: 1, context: SYSTEM_CTX,\n });\n if (Array.isArray(colliding) && colliding[0]) {\n throw new Error(\n `DUPLICATE_REQUEST: another approval request is already pending on ${raw.object_name}/${raw.record_id} — resolve it before resubmitting`,\n );\n }\n\n const org = raw.organization_id ?? null;\n const nodeId: string | null = raw.flow_node_id ?? raw.current_step ?? null;\n const runId: string | null = raw.flow_run_id ?? null;\n const now = this.clock.now().toISOString();\n\n await this.engine.insert('sys_approval_action', {\n id: uid('aact'), request_id: requestId, organization_id: org,\n step_name: nodeId, step_index: 0, action: 'resubmit',\n actor_id: input.actorId, comment: input.comment ?? null, created_at: now,\n }, { context: SYSTEM_CTX });\n\n // The next round only exists if this resume lands — surface `resumed`\n // honestly so a stuck run is visible instead of silently swallowed.\n let resumed = false;\n if (runId && typeof this.automation?.resume === 'function') {\n try {\n await this.automation.resume(runId, {\n branchLabel: APPROVAL_BRANCH_LABELS.resubmit,\n output: { resubmitted: true, requestId },\n });\n resumed = true;\n } catch (err: any) {\n this.logger?.warn?.('[approvals] resume after resubmit failed', {\n request: requestId, run: runId, error: err?.message ?? String(err),\n });\n }\n }\n\n const fresh = await this.getRequest(requestId, context);\n return { request: fresh!, runId, resumed };\n }\n\n /**\n * ADR-0044 guard: the flow's approval node must declare a `revise`\n * out-edge before send-back is allowed — the engine's branch-label fallback\n * (no matching label ⇒ ALL out-edges) must never be reachable from a user\n * action.\n */\n private async assertReviseEdge(raw: any, nodeId: string | null): Promise<void> {\n const processName = String(raw.process_name ?? '');\n const flowName = processName.startsWith('flow:') ? processName.slice('flow:'.length) : undefined;\n if (!flowName || !nodeId || typeof this.automation?.getFlow !== 'function') {\n throw new Error('VALIDATION_FAILED: send-back requires the owning flow definition (automation engine unavailable)');\n }\n const flow: any = await this.automation.getFlow(flowName);\n const hasRevise = Array.isArray(flow?.edges)\n && flow.edges.some((e: any) => e?.source === nodeId && e?.label === APPROVAL_BRANCH_LABELS.revise);\n if (!hasRevise) {\n throw new Error(\n `VALIDATION_FAILED: approval node '${nodeId}' has no '${APPROVAL_BRANCH_LABELS.revise}' out-edge — ` +\n 'the flow does not support send-back for revision',\n );\n }\n }\n\n /**\n * ADR-0044 guard: a `returned` request is only actionable (resubmit /\n * recall) while it is still the newest request on its run — a later round\n * or a later node's request supersedes it.\n */\n private async assertLatestForRun(raw: any): Promise<void> {\n const runId = raw.flow_run_id;\n if (!runId) return;\n // SortNode's key is `order` (spec/data/query.zod.ts) — `direction` would\n // silently default to ascending and return the OLDEST row.\n const rows = await this.engine.find('sys_approval_request', {\n where: { flow_run_id: runId },\n orderBy: [{ field: 'created_at', order: 'desc' }], limit: 1, context: SYSTEM_CTX,\n });\n const latest: any = Array.isArray(rows) ? rows[0] : null;\n if (latest && String(latest.id) !== String(raw.id)) {\n throw new Error('INVALID_STATE: a newer approval request supersedes this one');\n }\n }\n\n // ── Thread interactions (no flow movement) ───────────────────\n\n /**\n * Hand a pending-approver slot to someone else. `from` defaults to the\n * actor itself; the actor must hold the slot being handed over (or be a\n * system caller). Audits `reassign` and notifies the new approver.\n */\n async reassign(\n requestId: string,\n input: { actorId: string; to: string; from?: string; comment?: string },\n context: SharingExecutionContext,\n ): Promise<{ request: ApprovalRequestRow }> {\n if (!input?.actorId) throw new Error('VALIDATION_FAILED: actorId is required');\n const to = String(input?.to ?? '').trim();\n if (!to) throw new Error('VALIDATION_FAILED: `to` (new approver) is required');\n const raw = await this.loadPendingRow(requestId);\n\n const pending = csvSplit(raw.pending_approvers);\n const from = String(input.from ?? input.actorId).trim();\n if (!pending.includes(from)) {\n throw new Error(`FORBIDDEN: '${from}' is not a pending approver on this request`);\n }\n if (!context.isSystem && input.actorId !== from && !pending.includes(input.actorId)) {\n throw new Error(`FORBIDDEN: actor '${input.actorId}' is not a pending approver`);\n }\n if (pending.includes(to)) {\n throw new Error(`VALIDATION_FAILED: '${to}' is already a pending approver`);\n }\n\n const next = pending.map(a => (a === from ? to : a));\n const now = this.clock.now().toISOString();\n // Audit first, then mutate — mirrors decideNode(), so a failed audit\n // write can never leave a moved slot without a trail.\n await this.engine.insert('sys_approval_action', {\n id: uid('aact'), request_id: requestId, organization_id: raw.organization_id ?? null,\n step_name: raw.flow_node_id ?? raw.current_step ?? null, step_index: 0, action: 'reassign',\n actor_id: input.actorId, comment: input.comment ?? `${from} → ${to}`, created_at: now,\n }, { context: SYSTEM_CTX });\n // per_group / quorum (#3266): carry the delegated slot's group membership to\n // the new approver in the snapshot, so their approval still counts for the\n // original group.\n let configPatch: Record<string, unknown> = {};\n try {\n const cfg = parseJson<any>(raw.node_config_json, null);\n const groups = cfg?.__approverGroups as Record<string, string[]> | undefined;\n if (groups && groups[from] && !groups[to]) {\n groups[to] = groups[from];\n delete groups[from];\n configPatch = { node_config_json: JSON.stringify(cfg) };\n }\n } catch { /* snapshot left untouched on parse failure */ }\n await this.engine.update('sys_approval_request', {\n id: requestId, pending_approvers: next.join(','), updated_at: now, ...configPatch,\n }, { context: SYSTEM_CTX });\n await this.syncApproverIndex(requestId, next, raw.organization_id ?? null, now);\n\n await this.notify({\n topic: 'approval.reassigned',\n audience: [to],\n actorId: input.actorId,\n source: { object: 'sys_approval_request', id: requestId },\n dedupKey: `approval-reassign-${requestId}-${to}`,\n payload: {\n title: 'Approval handed to you',\n message: `You are now an approver on ${raw.object_name}/${raw.record_id}.`,\n actionUrl: '/system/approvals',\n },\n });\n\n const fresh = await this.getRequest(requestId, context);\n return { request: fresh! };\n }\n\n /**\n * Submitter nudge — notify every pending approver. Throttled to one\n * reminder per {@link REMIND_COOLDOWN_MS} per request.\n */\n async remind(\n requestId: string,\n input: { actorId: string; comment?: string },\n context: SharingExecutionContext,\n ): Promise<{ request: ApprovalRequestRow; notified: number }> {\n if (!input?.actorId) throw new Error('VALIDATION_FAILED: actorId is required');\n const raw = await this.loadPendingRow(requestId);\n if (!context.isSystem && raw.submitter_id && String(raw.submitter_id) !== String(input.actorId)) {\n throw new Error('FORBIDDEN: only the submitter may send reminders');\n }\n\n const acts = await this.engine.find('sys_approval_action', {\n where: { request_id: requestId, action: 'remind' },\n orderBy: [{ field: 'created_at', order: 'desc' }], limit: 1, context: SYSTEM_CTX,\n });\n const last: any = Array.isArray(acts) ? acts[0] : null;\n const now = this.clock.now();\n if (last?.created_at && now.getTime() - Date.parse(last.created_at) < REMIND_COOLDOWN_MS) {\n throw new Error('THROTTLED: a reminder was already sent recently');\n }\n\n const pending = csvSplit(raw.pending_approvers);\n const nowIso = now.toISOString();\n await this.engine.insert('sys_approval_action', {\n id: uid('aact'), request_id: requestId, organization_id: raw.organization_id ?? null,\n step_name: raw.flow_node_id ?? raw.current_step ?? null, step_index: 0, action: 'remind',\n actor_id: input.actorId, comment: input.comment ?? null, created_at: nowIso,\n }, { context: SYSTEM_CTX });\n\n // Per-approver fan-out: concrete identities (user ids / emails) each get\n // their OWN one-tap approve/reject links (ADR-0043); `role:*`-style\n // literals can't carry a personal token and fall back to a plain nudge.\n let notified = 0;\n const concrete = pending.filter(a => a && !a.includes(':'));\n const literals = pending.filter(a => a && a.includes(':'));\n for (const approver of concrete) {\n try {\n const tokens = await this.issueActionTokens(requestId, approver);\n notified += await this.notify({\n topic: 'approval.reminder',\n audience: [approver],\n actorId: input.actorId,\n source: { object: 'sys_approval_request', id: requestId },\n dedupKey: `approval-remind-${requestId}-${nowIso}-${approver}`,\n payload: {\n title: 'Approval reminder',\n message: `A decision on ${raw.object_name}/${raw.record_id} is still waiting on you.`,\n actionUrl: '/system/approvals',\n actions: [\n { label: 'Approve', url: this.actionLinkUrl(tokens.approve) },\n { label: 'Reject', url: this.actionLinkUrl(tokens.reject) },\n ],\n },\n });\n } catch (err: any) {\n this.logger?.warn?.('[approvals] reminder with action links failed', {\n request: requestId, approver, error: err?.message ?? String(err),\n });\n }\n }\n if (literals.length) {\n notified += await this.notify({\n topic: 'approval.reminder',\n audience: literals,\n actorId: input.actorId,\n source: { object: 'sys_approval_request', id: requestId },\n dedupKey: `approval-remind-${requestId}-${nowIso}`,\n payload: {\n title: 'Approval reminder',\n message: `A decision on ${raw.object_name}/${raw.record_id} is still waiting on you.`,\n actionUrl: '/system/approvals',\n },\n });\n }\n\n const fresh = await this.getRequest(requestId, context);\n return { request: fresh!, notified };\n }\n\n // ── Actionable links (ADR-0043) ──────────────────────────────\n\n /** Build the session-less confirm-page URL for a raw token. */\n actionLinkUrl(rawToken: string): string {\n return `${this.publicBaseUrl}/api/v1/approvals/act?token=${encodeURIComponent(rawToken)}`;\n }\n\n /**\n * Issue one-tap approve/reject tokens for one approver on one pending\n * request. Raw tokens are returned ONCE; only SHA-256 hashes are stored\n * (`sys_approval_token`), so a DB leak yields no usable links.\n */\n async issueActionTokens(\n requestId: string,\n approverId: string,\n opts?: { ttlMs?: number },\n ): Promise<{ approve: string; reject: string }> {\n if (!approverId?.trim()) throw new Error('VALIDATION_FAILED: approverId is required');\n const raw = await this.loadPendingRow(requestId);\n const pending = csvSplit(raw.pending_approvers);\n if (!pending.includes(approverId)) {\n throw new Error(`FORBIDDEN: '${approverId}' is not a pending approver on this request`);\n }\n const now = this.clock.now();\n const expires = new Date(now.getTime() + (opts?.ttlMs ?? ACTION_TOKEN_TTL_MS)).toISOString();\n const out = { approve: '', reject: '' };\n for (const action of ['approve', 'reject'] as const) {\n const rawToken = randomBytes(32).toString('base64url');\n await this.engine.insert('sys_approval_token', {\n id: uid('atok'),\n organization_id: raw.organization_id ?? null,\n token_hash: createHash('sha256').update(rawToken).digest('hex'),\n request_id: requestId,\n action,\n approver_id: approverId,\n expires_at: expires,\n consumed_at: null,\n created_at: now.toISOString(),\n }, { context: SYSTEM_CTX });\n out[action] = rawToken;\n }\n return out;\n }\n\n /** Shared validation chain for peek/redeem. Returns the token row when live. */\n private async resolveActionToken(rawToken: string): Promise<\n { ok: true; token: any; request: ApprovalRequestRow } | Extract<ActionTokenOutcome, { ok: false }>\n > {\n const trimmed = rawToken?.trim();\n if (!trimmed) return { ok: false, reason: 'invalid' };\n const hash = createHash('sha256').update(trimmed).digest('hex');\n const rows = await this.engine.find('sys_approval_token', {\n where: { token_hash: hash }, limit: 1, context: SYSTEM_CTX,\n });\n const token: any = Array.isArray(rows) ? rows[0] : null;\n if (!token) return { ok: false, reason: 'invalid' };\n if (token.consumed_at) return { ok: false, reason: 'consumed' };\n if (Date.parse(token.expires_at) < this.clock.now().getTime()) {\n return { ok: false, reason: 'expired' };\n }\n const request = await this.getRequest(token.request_id, SYSTEM_CTX as unknown as SharingExecutionContext);\n if (!request || request.status !== 'pending') {\n return { ok: false, reason: 'not_pending', request: request ?? undefined };\n }\n if (!(request.pending_approvers ?? []).includes(token.approver_id)) {\n // Reassigned away / slot consumed by a unanimous round — the link died\n // with the slot (ADR-0043 invalidation row).\n return { ok: false, reason: 'not_approver', request };\n }\n return { ok: true, token, request };\n }\n\n /** GET confirm page: validate WITHOUT consuming — never mutates. */\n async peekActionToken(rawToken: string): Promise<ActionTokenOutcome> {\n const res = await this.resolveActionToken(rawToken);\n if (!res.ok) return res;\n return { ok: true, action: res.token.action, request: res.request, approverId: res.token.approver_id };\n }\n\n /**\n * POST redemption: consume the token FIRST (a failed decide still burns\n * it — replay-safe), then decide as the bound approver.\n */\n async redeemActionToken(rawToken: string): Promise<ActionTokenOutcome> {\n const res = await this.resolveActionToken(rawToken);\n if (!res.ok) return res;\n await this.engine.update('sys_approval_token', {\n id: res.token.id, consumed_at: this.clock.now().toISOString(),\n }, { context: SYSTEM_CTX });\n const out = await this.decide(res.token.request_id, {\n decision: res.token.action,\n actorId: res.token.approver_id,\n comment: 'Via action link',\n }, SYSTEM_CTX as unknown as SharingExecutionContext);\n return { ok: true, action: res.token.action, request: out.request, approverId: res.token.approver_id };\n }\n\n /**\n * Approver asks the submitter for more information. The request stays\n * pending — a thread interaction, not a flow decision.\n */\n async requestInfo(\n requestId: string,\n input: { actorId: string; comment: string },\n context: SharingExecutionContext,\n ): Promise<{ request: ApprovalRequestRow }> {\n if (!input?.actorId) throw new Error('VALIDATION_FAILED: actorId is required');\n if (!input?.comment?.trim()) throw new Error('VALIDATION_FAILED: comment is required');\n const raw = await this.loadPendingRow(requestId);\n const pending = csvSplit(raw.pending_approvers);\n if (!context.isSystem && !pending.includes(input.actorId)) {\n throw new Error(`FORBIDDEN: actor '${input.actorId}' is not a pending approver`);\n }\n\n const now = this.clock.now().toISOString();\n await this.engine.insert('sys_approval_action', {\n id: uid('aact'), request_id: requestId, organization_id: raw.organization_id ?? null,\n step_name: raw.flow_node_id ?? raw.current_step ?? null, step_index: 0, action: 'request_info',\n actor_id: input.actorId, comment: input.comment.trim(), created_at: now,\n }, { context: SYSTEM_CTX });\n\n if (raw.submitter_id) {\n await this.notify({\n topic: 'approval.request_info',\n audience: [String(raw.submitter_id)],\n actorId: input.actorId,\n source: { object: 'sys_approval_request', id: requestId },\n payload: {\n title: 'More information requested',\n message: input.comment.trim(),\n actionUrl: '/system/approvals',\n },\n });\n }\n\n const fresh = await this.getRequest(requestId, context);\n return { request: fresh! };\n }\n\n /** Free-form reply on the thread (submitter or any pending approver). */\n async comment(\n requestId: string,\n input: { actorId: string; comment: string; attachments?: string[] },\n context: SharingExecutionContext,\n ): Promise<{ request: ApprovalRequestRow }> {\n if (!input?.actorId) throw new Error('VALIDATION_FAILED: actorId is required');\n if (!input?.comment?.trim()) throw new Error('VALIDATION_FAILED: comment is required');\n const raw = await this.loadPendingRow(requestId);\n const pending = csvSplit(raw.pending_approvers);\n const isSubmitter = raw.submitter_id && String(raw.submitter_id) === String(input.actorId);\n if (!context.isSystem && !isSubmitter && !pending.includes(input.actorId)) {\n throw new Error(`FORBIDDEN: actor '${input.actorId}' is not on this request`);\n }\n\n const now = this.clock.now().toISOString();\n await this.engine.insert('sys_approval_action', {\n id: uid('aact'), request_id: requestId, organization_id: raw.organization_id ?? null,\n step_name: raw.flow_node_id ?? raw.current_step ?? null, step_index: 0, action: 'comment',\n actor_id: input.actorId, comment: input.comment.trim(),\n attachments: input.attachments?.length ? input.attachments : null,\n created_at: now,\n }, { context: SYSTEM_CTX });\n\n // Notify the other side of the thread.\n const audience = isSubmitter ? pending : [String(raw.submitter_id ?? '')].filter(Boolean);\n await this.notify({\n topic: 'approval.comment',\n audience,\n actorId: input.actorId,\n source: { object: 'sys_approval_request', id: requestId },\n payload: {\n title: 'New comment on an approval',\n message: input.comment.trim(),\n actionUrl: '/system/approvals',\n },\n });\n\n const fresh = await this.getRequest(requestId, context);\n return { request: fresh! };\n }\n\n // ── SLA escalation (ADR-0042) ─────────────────────────────────\n\n /**\n * One escalation sweep: every *pending* request whose node config declares\n * `escalation.timeoutHours` and whose deadline has passed is escalated\n * **at most once, ever** — the `escalate` audit row is the idempotency\n * marker, written before any mutation (audit-first, like reassign). One\n * bad row never stops the sweep.\n */\n async runEscalations(): Promise<{ scanned: number; escalated: number }> {\n let rows: any[] = [];\n try {\n rows = await this.engine.find('sys_approval_request', {\n where: { status: 'pending' }, limit: 500, context: SYSTEM_CTX,\n }) ?? [];\n } catch (err: any) {\n this.logger?.warn?.('[approvals] escalation scan failed to list requests', {\n error: err?.message ?? String(err),\n });\n return { scanned: 0, escalated: 0 };\n }\n\n let escalated = 0;\n for (const raw of rows) {\n try {\n const cfg = parseJson<any>(raw.node_config_json, undefined);\n const esc = cfg?.escalation;\n if (!esc || typeof esc.timeoutHours !== 'number' || esc.timeoutHours <= 0) continue;\n const due = slaDueAt(raw.created_at, cfg);\n if (!due || Date.parse(due) > this.clock.now().getTime()) continue;\n\n // Single-shot: a prior 'escalate' action means this request is done.\n const prior = await this.engine.find('sys_approval_action', {\n where: { request_id: raw.id, action: 'escalate' }, limit: 1, context: SYSTEM_CTX,\n });\n if (Array.isArray(prior) && prior[0]) continue;\n\n await this.escalateRequest(raw, esc);\n escalated++;\n } catch (err: any) {\n this.logger?.warn?.('[approvals] escalation failed for request', {\n request: raw?.id, error: err?.message ?? String(err),\n });\n }\n }\n if (escalated > 0) {\n this.logger?.info?.('[approvals] SLA escalation sweep', { scanned: rows.length, escalated });\n }\n return { scanned: rows.length, escalated };\n }\n\n /** Execute the configured escalation action for one overdue request. */\n private async escalateRequest(raw: any, esc: any): Promise<void> {\n const action: string = esc.action ?? 'notify';\n const escalateTo: string | undefined =\n typeof esc.escalateTo === 'string' && esc.escalateTo.trim() ? esc.escalateTo.trim() : undefined;\n const now = this.clock.now().toISOString();\n const pending = csvSplit(raw.pending_approvers);\n\n // `escalateTo` is a position machine name or a user id (same contract as\n // the `position` ApproverType, ADR-0090 D3). Position holders win; an\n // empty expansion falls back to the literal, so a config naming a\n // specific user id keeps working unchanged.\n let escalatees: string[] = [];\n if (escalateTo) {\n try {\n escalatees = await this.expandPositionUsers(escalateTo, raw.organization_id ?? null);\n } catch { escalatees = []; }\n if (!escalatees.length) escalatees = [escalateTo];\n }\n\n // Audit first — this row IS the idempotency marker (ADR-0042 §1).\n await this.engine.insert('sys_approval_action', {\n id: uid('aact'), request_id: raw.id, organization_id: raw.organization_id ?? null,\n step_name: raw.flow_node_id ?? raw.current_step ?? null, step_index: 0, action: 'escalate',\n actor_id: SLA_ACTOR_ID,\n comment: `${action}${escalateTo ? ` → ${escalateTo}` : ''}`,\n created_at: now,\n }, { context: SYSTEM_CTX });\n\n if (action === 'reassign' && escalatees.length) {\n await this.engine.update('sys_approval_request', {\n id: raw.id, pending_approvers: escalatees.join(','), updated_at: now,\n }, { context: SYSTEM_CTX });\n await this.syncApproverIndex(raw.id, escalatees, raw.organization_id ?? null, now);\n await this.notify({\n topic: 'approval.escalated',\n audience: escalatees,\n actorId: SLA_ACTOR_ID,\n source: { object: 'sys_approval_request', id: raw.id },\n payload: {\n title: 'Approval escalated to you',\n message: `An overdue approval on ${raw.object_name}/${raw.record_id} was escalated to you.`,\n actionUrl: '/system/approvals',\n },\n });\n } else if (action === 'auto_approve' || action === 'auto_reject') {\n await this.decide(raw.id, {\n decision: action === 'auto_approve' ? 'approve' : 'reject',\n actorId: SLA_ACTOR_ID,\n comment: 'SLA escalation',\n }, SYSTEM_CTX as unknown as SharingExecutionContext);\n } else {\n // 'notify' (and the reassign-without-target fallback)\n await this.notify({\n topic: 'approval.sla_breached',\n audience: [...pending, ...escalatees],\n actorId: SLA_ACTOR_ID,\n source: { object: 'sys_approval_request', id: raw.id },\n payload: {\n title: 'Approval SLA breached',\n message: `A decision on ${raw.object_name}/${raw.record_id} is overdue.`,\n actionUrl: '/system/approvals',\n },\n });\n }\n\n if (esc.notifySubmitter !== false && raw.submitter_id) {\n await this.notify({\n topic: 'approval.sla_breached',\n audience: [String(raw.submitter_id)],\n actorId: SLA_ACTOR_ID,\n source: { object: 'sys_approval_request', id: raw.id },\n payload: {\n title: 'Your approval request breached its SLA',\n message: `${raw.object_name}/${raw.record_id}: escalation action '${action}' was taken.`,\n actionUrl: '/system/approvals',\n },\n });\n }\n }\n\n // ── Display enrichment ───────────────────────────────────────\n\n /**\n * Resolve the schema-declared display field for an object, when the engine\n * exposes schema metadata (`getSchema`). Falls back to common title-ish\n * field names so plain `ApprovalEngine` fakes still enrich sensibly.\n */\n private resolveDisplayField(object: string): string | undefined {\n try {\n const schema: any = (this.engine as any).getSchema?.(object);\n const fields = schema?.fields ?? {};\n // [ADR-0079] `nameField` is the canonical primary-title pointer;\n // `displayNameField` is the deprecated alias (still honored).\n const declared = schema?.nameField ?? schema?.displayNameField;\n if (declared && declared !== 'id' && fields[declared]) return declared;\n for (const cand of ['name', 'title', 'subject', 'label']) {\n if (fields[cand]) return cand;\n }\n } catch { /* schema unavailable — heuristics below still apply */ }\n return undefined;\n }\n\n private static pickTitle(rec: any, displayField?: string): string | undefined {\n const candidates = displayField\n ? [displayField, 'name', 'title', 'subject', 'label']\n : ['name', 'title', 'subject', 'label'];\n for (const f of candidates) {\n const v = rec?.[f];\n if (v != null && String(v).trim() && f !== 'id') return String(v);\n }\n return undefined;\n }\n\n /**\n * Batch-resolve `sys_user` display names for identifiers that may be user\n * ids or emails. Best-effort — failures leave entries unresolved.\n */\n private async resolveUserNames(identifiers: Array<string | null | undefined>): Promise<Map<string, string>> {\n const names = new Map<string, string>();\n const targets = Array.from(new Set(identifiers.filter(Boolean))) as string[];\n if (!targets.length) return names;\n try {\n const users = await this.engine.find('sys_user', {\n where: { id: { $in: targets } }, fields: ['id', 'name', 'email'],\n limit: targets.length, context: SYSTEM_CTX,\n });\n for (const u of (users ?? []) as any[]) {\n if (u?.id && (u.name || u.email)) names.set(String(u.id), String(u.name ?? u.email));\n }\n } catch { /* best-effort */ }\n const unresolvedEmails = targets.filter(t => !names.has(t) && t.includes('@'));\n if (unresolvedEmails.length) {\n try {\n const users = await this.engine.find('sys_user', {\n where: { email: { $in: unresolvedEmails } }, fields: ['email', 'name'],\n limit: unresolvedEmails.length, context: SYSTEM_CTX,\n });\n for (const u of (users ?? []) as any[]) {\n if (u?.email && u.name) names.set(String(u.email), String(u.name));\n }\n } catch { /* best-effort */ }\n }\n return names;\n }\n\n /** Lookup-typed fields (key + referenced object) of an object's schema. */\n private resolveLookupFields(object: string): Array<{ key: string; reference: string }> {\n try {\n const schema: any = (this.engine as any).getSchema?.(object);\n const fields = schema?.fields ?? {};\n const out: Array<{ key: string; reference: string }> = [];\n for (const [key, f] of Object.entries<any>(fields)) {\n if ((f?.type === 'lookup' || f?.type === 'master_detail' || f?.type === 'user') && f?.reference) {\n out.push({ key, reference: String(f.reference) });\n }\n }\n return out;\n } catch { return []; }\n }\n\n /**\n * Attach inbox display fields to rows so clients never render a raw\n * identifier: `record_title`, `submitter_name`, `object_label`,\n * `pending_approver_names` (user-id approvers), and `payload_display`\n * (lookup foreign keys in the snapshot → referenced record titles).\n * Batched: one query per distinct object (target + referenced) plus one\n * `sys_user` lookup. Best-effort — a deleted record falls back to the\n * payload snapshot, and any failure leaves the field unset rather than\n * failing the list.\n */\n private async enrichRows(rows: ApprovalRequestRow[]): Promise<void> {\n if (!rows.length) return;\n\n // Record titles + object labels, batched per object.\n const byObject = new Map<string, Set<string>>();\n for (const r of rows) {\n if (!r.object_name || !r.record_id) continue;\n let set = byObject.get(r.object_name);\n if (!set) { set = new Set(); byObject.set(r.object_name, set); }\n set.add(r.record_id);\n }\n const titles = new Map<string, string>();\n const objectLabels = new Map<string, string>();\n for (const [object, idSet] of byObject) {\n try {\n const schema: any = (this.engine as any).getSchema?.(object);\n if (schema?.label) objectLabels.set(object, String(schema.label));\n } catch { /* label optional */ }\n const ids = Array.from(idSet);\n const displayField = this.resolveDisplayField(object);\n try {\n const recs = await this.engine.find(object, {\n where: { id: { $in: ids } }, limit: ids.length, context: SYSTEM_CTX,\n });\n for (const rec of (recs ?? []) as any[]) {\n const title = ApprovalService.pickTitle(rec, displayField);\n if (rec?.id && title) titles.set(`${object} ${rec.id}`, title);\n }\n } catch { /* object may be unregistered — payload fallback below */ }\n }\n\n // Lookup foreign keys inside payload snapshots → referenced record titles.\n const lookupFieldsByObject = new Map<string, Array<{ key: string; reference: string }>>();\n for (const object of byObject.keys()) {\n const lookups = this.resolveLookupFields(object);\n if (lookups.length) lookupFieldsByObject.set(object, lookups);\n }\n const refIds = new Map<string, Set<string>>();\n for (const r of rows) {\n const lookups = lookupFieldsByObject.get(r.object_name);\n const payload: any = r.payload;\n if (!lookups || !payload || typeof payload !== 'object') continue;\n for (const { key, reference } of lookups) {\n const v = payload[key];\n if (v == null || typeof v === 'object' || !String(v).trim()) continue;\n let set = refIds.get(reference);\n if (!set) { set = new Set(); refIds.set(reference, set); }\n set.add(String(v));\n }\n }\n const refTitles = new Map<string, string>();\n for (const [object, idSet] of refIds) {\n const ids = Array.from(idSet);\n const displayField = this.resolveDisplayField(object);\n try {\n const recs = await this.engine.find(object, {\n where: { id: { $in: ids } }, limit: ids.length, context: SYSTEM_CTX,\n });\n for (const rec of (recs ?? []) as any[]) {\n const title = ApprovalService.pickTitle(rec, displayField);\n if (rec?.id && title) refTitles.set(`${object} ${rec.id}`, title);\n }\n } catch { /* referenced object unreadable — leave unresolved */ }\n }\n\n // Display names for submitters AND user-id approvers in one lookup.\n // `role:<r>` (and other `type:value` literals) are already readable.\n const userIdentifiers: Array<string | null | undefined> = [];\n for (const r of rows) {\n userIdentifiers.push(r.submitter_id);\n for (const a of r.pending_approvers ?? []) {\n if (a && !a.includes(':')) userIdentifiers.push(a);\n }\n }\n const names = await this.resolveUserNames(userIdentifiers);\n\n for (const r of rows as any[]) {\n const title = titles.get(`${r.object_name} ${r.record_id}`)\n ?? ApprovalService.pickTitle(r.payload, undefined);\n if (title) r.record_title = title;\n const name = r.submitter_id ? names.get(String(r.submitter_id)) : undefined;\n if (name) r.submitter_name = name;\n const label = objectLabels.get(r.object_name);\n if (label) r.object_label = label;\n\n const approverNames: Record<string, string> = {};\n for (const a of r.pending_approvers ?? []) {\n const n = names.get(String(a));\n if (n) approverNames[a] = n;\n }\n if (Object.keys(approverNames).length) r.pending_approver_names = approverNames;\n\n const lookups = lookupFieldsByObject.get(r.object_name);\n if (lookups && r.payload && typeof r.payload === 'object') {\n const display: Record<string, string> = {};\n for (const { key, reference } of lookups) {\n const v = (r.payload as any)[key];\n if (v == null) continue;\n const t = refTitles.get(`${reference} ${String(v)}`);\n if (t) display[key] = t;\n }\n if (Object.keys(display).length) r.payload_display = display;\n }\n }\n }\n\n // ── Pending-approver index (issue #1745) ─────────────────────\n\n /**\n * Mirror one request's `pending_approvers` CSV into the normalized\n * `sys_approval_approver` index. Called by every write path that changes\n * the approver set; an empty `approvers` clears the request's rows (the\n * request left `pending`). Diff-based so reassign/unanimous churn doesn't\n * rewrite untouched rows.\n */\n private async syncApproverIndex(\n requestId: string,\n approvers: string[],\n org: string | null,\n now: string,\n ): Promise<void> {\n const desired = new Set(approvers.map(a => String(a).trim()).filter(Boolean));\n const existing = await this.engine.find('sys_approval_approver', {\n where: { request_id: requestId }, limit: 500, context: SYSTEM_CTX,\n });\n const rows: any[] = Array.isArray(existing) ? existing : [];\n for (const row of rows) {\n if (desired.has(String(row.approver))) desired.delete(String(row.approver));\n else await this.engine.delete('sys_approval_approver', { where: { id: row.id }, context: SYSTEM_CTX });\n }\n for (const approver of desired) {\n await this.engine.insert('sys_approval_approver', {\n id: uid('aapr'), request_id: requestId, approver,\n organization_id: org, created_at: now,\n }, { context: SYSTEM_CTX });\n }\n }\n\n /**\n * Rebuild the whole `sys_approval_approver` index from the CSV source of\n * truth. Idempotent; run at plugin start so rows written before the index\n * existed (or drifted past a crashed sync) become queryable. Cost tracks\n * the number of *pending* requests, not the request history.\n */\n async rebuildApproverIndex(): Promise<{ requests: number; inserted: number; deleted: number }> {\n // Desired state: every pending request's CSV entries.\n const desired = new Map<string, { approvers: Set<string>; org: string | null }>();\n const PAGE = 500;\n for (let offset = 0; ; offset += PAGE) {\n const batch = await this.engine.find('sys_approval_request', {\n where: { status: 'pending' },\n fields: ['id', 'pending_approvers', 'organization_id'],\n limit: PAGE, offset, context: SYSTEM_CTX,\n });\n const rows: any[] = Array.isArray(batch) ? batch : [];\n for (const r of rows) {\n desired.set(String(r.id), {\n approvers: new Set(csvSplit(r.pending_approvers)),\n org: r.organization_id ?? null,\n });\n }\n if (rows.length < PAGE) break;\n }\n\n // Current state: read the whole index first (bounded by the live work\n // queue), THEN mutate — deleting while paginating would shift the cursor.\n const indexRows: any[] = [];\n for (let offset = 0; ; offset += PAGE) {\n const batch = await this.engine.find('sys_approval_approver', {\n orderBy: [{ field: 'created_at', order: 'asc' }],\n limit: PAGE, offset, context: SYSTEM_CTX,\n });\n const rows: any[] = Array.isArray(batch) ? batch : [];\n indexRows.push(...rows);\n if (rows.length < PAGE) break;\n }\n let inserted = 0; let deleted = 0;\n const seen = new Map<string, Set<string>>();\n for (const row of indexRows) {\n const reqId = String(row.request_id);\n const want = desired.get(reqId);\n const have = seen.get(reqId) ?? seen.set(reqId, new Set()).get(reqId)!;\n // Orphan (request no longer pending), stale entry, or duplicate → drop.\n if (!want || !want.approvers.has(String(row.approver)) || have.has(String(row.approver))) {\n await this.engine.delete('sys_approval_approver', { where: { id: row.id }, context: SYSTEM_CTX });\n deleted++;\n continue;\n }\n have.add(String(row.approver));\n }\n\n const now = this.clock.now().toISOString();\n for (const [reqId, want] of desired) {\n const have = seen.get(reqId);\n for (const approver of want.approvers) {\n if (have?.has(approver)) continue;\n await this.engine.insert('sys_approval_approver', {\n id: uid('aapr'), request_id: reqId, approver,\n organization_id: want.org, created_at: now,\n }, { context: SYSTEM_CTX });\n inserted++;\n }\n }\n return { requests: desired.size, inserted, deleted };\n }\n\n // ── Read API ─────────────────────────────────────────────────\n\n /** Filter type accepted by {@link listRequests} / {@link countRequests}. */\n private buildRequestWhere(\n filter: {\n object?: string;\n recordId?: string;\n status?: ApprovalStatus | ApprovalStatus[];\n submitterId?: string;\n q?: string;\n } | undefined,\n context: SharingExecutionContext,\n ): { where: any; tenantOrg: string | null } {\n const f: any = {};\n if (filter?.object) f.object_name = filter.object;\n if (filter?.recordId) f.record_id = filter.recordId;\n if (filter?.submitterId) f.submitter_id = filter.submitterId;\n // Tenant isolation: when a caller context carries a tenant identifier\n // (organizationId / tenantId), scope the query to that tenant. SYSTEM\n // callers (no tenant) see all rows. This prevents the bespoke endpoint\n // from leaking other-tenant rows since we deliberately query with\n // SYSTEM_CTX to bypass RLS on the engine (the approver-visibility rule\n // spans three identity forms, which RLS can't model cleanly).\n const tenantOrg = (context as any)?.organizationId ?? (context as any)?.tenantId ?? null;\n if (tenantOrg) f.organization_id = tenantOrg;\n // Free-text search, pushed down: `payload_json` carries the record\n // snapshot, so record titles match without any join. `$contains` is the\n // driver's escaped-LIKE operator.\n const q = filter?.q?.trim();\n if (q) {\n f.$or = [\n { process_name: { $contains: q } },\n { object_name: { $contains: q } },\n { record_id: { $contains: q } },\n { submitter_id: { $contains: q } },\n { payload_json: { $contains: q } },\n ];\n }\n // Status pushes down whole: `$in` for arrays (all bundled drivers\n // support it), equality for a single value.\n if (Array.isArray(filter?.status)) {\n const statuses = (filter!.status as ApprovalStatus[]).filter(Boolean);\n if (statuses.length === 1) f.status = statuses[0];\n else if (statuses.length > 1) f.status = { $in: statuses };\n } else if (filter?.status) {\n f.status = filter.status;\n }\n return { where: f, tenantOrg };\n }\n\n /** Window the approver-index probe — pending queues live far below this. */\n private static readonly APPROVER_INDEX_CAP = 10_000;\n\n /**\n * Resolve an approver filter to matching request ids via the normalized\n * `sys_approval_approver` index — the indexed replacement for the old\n * in-memory CSV scan, and what makes approver-filtered pagination correct\n * past any scan window (issue #1745). A request matches when ANY of the\n * caller's identities (user id / email / role:<r>) holds a pending slot.\n * Returns null when the filter is absent (callers skip the id constraint).\n */\n private async approverRequestIds(\n targets: string[],\n tenantOrg: string | null,\n ): Promise<string[] | null> {\n if (!targets.length) return null;\n const where: any = targets.length === 1\n ? { approver: targets[0] }\n : { approver: { $in: targets } };\n if (tenantOrg) where.organization_id = tenantOrg;\n const rows = await this.engine.find('sys_approval_approver', {\n where, fields: ['request_id'],\n limit: ApprovalService.APPROVER_INDEX_CAP, context: SYSTEM_CTX,\n });\n const list: any[] = Array.isArray(rows) ? rows : [];\n if (list.length >= ApprovalService.APPROVER_INDEX_CAP) {\n this.logger?.warn?.('[approvals] approver index probe hit its window — results may be truncated', {\n cap: ApprovalService.APPROVER_INDEX_CAP, targets: targets.length,\n });\n }\n return [...new Set<string>(list.map(r => String(r.request_id)))];\n }\n\n async listRequests(\n filter: {\n object?: string;\n recordId?: string;\n status?: ApprovalStatus | ApprovalStatus[];\n approverId?: string | string[];\n submitterId?: string;\n q?: string;\n limit?: number;\n offset?: number;\n } | undefined,\n context: SharingExecutionContext,\n ): Promise<ApprovalRequestRow[]> {\n const { where, tenantOrg } = this.buildRequestWhere(filter, context);\n const approverTargets = (Array.isArray(filter?.approverId) ? filter!.approverId : filter?.approverId ? [filter.approverId] : [])\n .map(t => String(t).trim())\n .filter(Boolean);\n\n // Every filter now pushes into the engine (issue #1745): approver via\n // the normalized index, status arrays via $in — so the page window is\n // always engine-side and correct at any table size.\n const ids = await this.approverRequestIds(approverTargets, tenantOrg);\n if (ids) {\n if (ids.length === 0) return [];\n where.id = ids.length === 1 ? ids[0] : { $in: ids };\n }\n\n const findOpts: any = {\n where,\n orderBy: [{ field: 'created_at', order: 'desc' }],\n context: SYSTEM_CTX,\n };\n if (filter?.limit != null || filter?.offset != null) {\n findOpts.limit = Math.min(Math.max(filter?.limit ?? 50, 1), 200);\n if (filter?.offset) findOpts.offset = Math.max(filter.offset, 0);\n } else {\n // Unpaginated callers keep the legacy bounded window.\n findOpts.limit = 500;\n }\n\n const rows = await this.engine.find('sys_approval_request', findOpts);\n const list = Array.isArray(rows) ? rows.map(rowFromRequest) : [];\n await this.enrichRows(list);\n this.attachViewers(list, context);\n return list;\n }\n\n async countRequests(\n filter: Parameters<IApprovalService['listRequests']>[0],\n context: SharingExecutionContext,\n ): Promise<number> {\n const { where, tenantOrg } = this.buildRequestWhere(filter, context);\n const approverTargets = (Array.isArray(filter?.approverId) ? filter!.approverId : filter?.approverId ? [filter.approverId] : [])\n .map(t => String(t).trim())\n .filter(Boolean);\n\n const ids = await this.approverRequestIds(approverTargets, tenantOrg);\n if (ids) {\n if (ids.length === 0) return 0;\n where.id = ids.length === 1 ? ids[0] : { $in: ids };\n }\n\n const countFn = (this.engine as any).count;\n if (typeof countFn === 'function') {\n try {\n const n = await countFn.call(this.engine, 'sys_approval_request', { where, context: SYSTEM_CTX });\n if (typeof n === 'number') return n;\n } catch { /* fall through to scan */ }\n }\n // Engine without count(): bounded scan. The approver-filtered case is\n // exact (the id set bounds it); the unfiltered case keeps the legacy\n // 500 window.\n const rows = await this.engine.find('sys_approval_request', {\n where, fields: ['id'], limit: ids ? Math.max(500, ids.length) : 500, context: SYSTEM_CTX,\n });\n return Array.isArray(rows) ? rows.length : 0;\n }\n\n async getRequest(requestId: string, context: SharingExecutionContext): Promise<ApprovalRequestRow | null> {\n if (!requestId) return null;\n const where: any = { id: requestId };\n const tenantOrg = (context as any)?.organizationId ?? (context as any)?.tenantId;\n if (tenantOrg) where.organization_id = tenantOrg;\n const rows = await this.engine.find('sys_approval_request', {\n where, limit: 1, context: SYSTEM_CTX,\n });\n if (!Array.isArray(rows) || !rows[0]) return null;\n const row = rowFromRequest(rows[0]);\n await this.enrichRows([row]);\n await this.attachFlowSteps(row);\n await this.attachDecisionProgress(row, rows[0]);\n this.attachViewers([row], context);\n return row;\n }\n\n /**\n * Server-computed decision aggregation progress (#3266 / objectui#2678 P1.5).\n * Single-read enrichment only (like {@link ApprovalService.attachFlowSteps}):\n * for a PENDING request whose behavior aggregates multiple approvals\n * (`unanimous` / `quorum` / `per_group`), expose\n * `decision_progress: { behavior, got, need, groups? }` so any client renders\n * \"2 of 3\" or per-group ticks without re-deriving the engine's tally rules.\n * `first_response` requests carry no progress (one approval finalizes).\n * Display-only and best-effort — errors leave the row untouched.\n */\n private async attachDecisionProgress(row: ApprovalRequestRow, raw: any): Promise<void> {\n try {\n if (row.status !== 'pending') return;\n const cfg = parseJson<any>(raw.node_config_json, undefined);\n const behavior = cfg?.behavior ?? 'first_response';\n if (behavior !== 'unanimous' && behavior !== 'quorum' && behavior !== 'per_group') return;\n\n const acts = await this.engine.find('sys_approval_action', {\n where: { request_id: row.id, step_index: 0, action: 'approve' }, limit: 1000, context: SYSTEM_CTX,\n });\n const approved = new Set<string>((acts ?? []).map((a: any) => String(a.actor_id ?? '')).filter(Boolean));\n\n const snapshot = cfg?.__approverGroups as Record<string, string[]> | undefined;\n const slate = snapshot ? Object.keys(snapshot) : [...approved, ...(row.pending_approvers ?? [])];\n const total = slate.length || 1;\n\n const progress: any = { behavior, got: approved.size, need: total };\n if (behavior === 'quorum') {\n progress.need = Math.min(Math.max(1, cfg?.minApprovals ?? total), total);\n } else if (behavior === 'per_group' && snapshot) {\n const perGroupNeed = Math.max(1, cfg?.minApprovals ?? 1);\n const size: Record<string, number> = {};\n for (const gs of Object.values(snapshot)) for (const g of gs) size[g] = (size[g] ?? 0) + 1;\n const got: Record<string, number> = {};\n for (const a of approved) for (const g of (snapshot[a] ?? [])) got[g] = (got[g] ?? 0) + 1;\n progress.groups = Object.keys(size).sort().map(g => {\n const need = Math.min(perGroupNeed, size[g]);\n return { group: g, got: Math.min(got[g] ?? 0, need), need, satisfied: (got[g] ?? 0) >= need };\n });\n progress.got = progress.groups.filter((g: any) => g.satisfied).length;\n progress.need = progress.groups.length;\n }\n (row as any).decision_progress = progress;\n } catch { /* display-only enrichment */ }\n }\n\n /**\n * Attach the per-viewer capability block (#3310) from the caller's context.\n * `can_act` mirrors the exact authorization the decision methods enforce — the\n * caller's user id is in the resolved `pending_approvers` while the request is\n * still `pending` (position/team/manager approvers are already resolved to\n * concrete user ids at open time, so a plain membership test is faithful).\n * `is_submitter` is a straight owner check. System/tokenless contexts get a\n * both-false block. Cheap + synchronous — safe on list reads.\n */\n private attachViewers(rows: ApprovalRequestRow[], context: SharingExecutionContext): void {\n const uid = (context as any)?.userId != null ? String((context as any).userId) : null;\n for (const row of rows) {\n const pending = row.pending_approvers ?? [];\n (row as any).viewer = {\n can_act: row.status === 'pending' && !!uid && pending.includes(uid),\n is_submitter: !!uid && row.submitter_id != null && String(row.submitter_id) === uid,\n };\n }\n }\n\n /**\n * Derive approval-step progress from the owning flow's graph (single-read\n * enrichment only — list reads skip it). Walks from the start node\n * preferring `approve`/`true` edges, so the result is the flow's main\n * approval trunk; conditional side-steps show as part of the potential\n * path. Display-only and best-effort.\n */\n private async attachFlowSteps(row: ApprovalRequestRow): Promise<void> {\n try {\n const flowName = row.process_name?.startsWith('flow:') ? row.process_name.slice(5) : undefined;\n if (!flowName || typeof this.automation?.getFlow !== 'function') return;\n const flow: any = await this.automation.getFlow(flowName);\n if (!flow?.nodes?.length) return;\n const nodesById = new Map<string, any>(flow.nodes.map((n: any) => [n.id, n]));\n const steps: Array<{ id: string; label: string }> = [];\n const seen = new Set<string>();\n let cur: any = flow.nodes.find((n: any) => n.type === 'start');\n while (cur && !seen.has(cur.id)) {\n seen.add(cur.id);\n if (cur.type === 'approval') steps.push({ id: cur.id, label: cur.label || cur.id });\n const out = (flow.edges ?? []).filter((e: any) => e.source === cur.id);\n if (!out.length) break;\n const pick = out.find((e: any) => e.label === 'approve')\n ?? out.find((e: any) => e.label === 'true')\n ?? out[0];\n cur = nodesById.get(pick.target);\n }\n if (steps.length === 0) return;\n const currentId = row.flow_node_id ?? row.current_step;\n const currentIdx = steps.findIndex(s => s.id === currentId);\n (row as any).flow_steps = steps.map((s, i) => ({\n ...s,\n state: currentIdx < 0 ? 'upcoming'\n : i < currentIdx ? 'done'\n : i === currentIdx ? (row.status === 'approved' ? 'done' : 'current')\n : 'upcoming',\n }));\n } catch { /* display-only — never fail the read */ }\n }\n\n async listActions(requestId: string, context: SharingExecutionContext): Promise<ApprovalActionRow[]> {\n if (!requestId) return [];\n // Tenant gate: ensure the caller can see the parent request before\n // returning its action history. Skipping this would leak history rows\n // across tenants the same way the unscoped list-requests path did.\n const req = await this.getRequest(requestId, context);\n if (!req) return [];\n const rows = await this.engine.find('sys_approval_action', {\n where: { request_id: requestId },\n limit: 500,\n orderBy: [{ field: 'created_at', order: 'asc' }],\n context: SYSTEM_CTX,\n });\n const actions = Array.isArray(rows) ? rows.map(rowFromAction) : [];\n // Timeline display: resolve actor ids to names so the audit trail never\n // shows a raw identifier. Role/team literals are already readable.\n const names = await this.resolveUserNames(\n actions.map(a => a.actor_id).filter(id => id && !id.includes(':')),\n );\n for (const a of actions as any[]) {\n const n = a.actor_id ? names.get(String(a.actor_id)) : undefined;\n if (n) a.actor_name = n;\n }\n return actions;\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { ObjectSchema, Field } from '@objectstack/spec/data';\n\n/**\n * sys_approval_token — single-use actionable-link tokens (ADR-0043).\n *\n * One row per issued approve/reject link. Only the SHA-256 **hash** of the\n * raw token is stored — a database leak yields no usable links. A token is\n * dead once any of these holds: `consumed_at` set, `expires_at` passed, the\n * request left `pending`, or the bound approver no longer holds a slot\n * (the last two are re-checked at redemption, not materialized here).\n *\n * @namespace sys\n */\nexport const SysApprovalToken = ObjectSchema.create({\n name: 'sys_approval_token',\n label: 'Approval Action Token',\n pluralLabel: 'Approval Action Tokens',\n icon: 'key',\n isSystem: true,\n managedBy: 'engine-owned',\n description: 'Single-use tokens behind actionable approval links',\n displayNameField: 'id',\n nameField: 'id', // [ADR-0079] canonical primary-title pointer (mirrors deprecated displayNameField)\n\n fields: {\n id: Field.text({ label: 'Token ID', required: true, readonly: true, group: 'System' }),\n\n organization_id: Field.lookup('sys_organization', {\n label: 'Organization',\n required: false,\n group: 'System',\n }),\n\n token_hash: Field.text({\n label: 'Token Hash',\n required: true,\n maxLength: 100,\n readonly: true,\n description: 'SHA-256 hex of the raw token — the raw value is never stored',\n group: 'Token',\n }),\n\n request_id: Field.text({\n label: 'Request',\n required: true,\n maxLength: 100,\n readonly: true,\n group: 'Token',\n }),\n\n action: Field.select(['approve', 'reject'], {\n label: 'Action',\n required: true,\n readonly: true,\n group: 'Token',\n }),\n\n approver_id: Field.text({\n label: 'Approver',\n required: true,\n maxLength: 200,\n readonly: true,\n description: 'Identity the token is bound to; the decision is audited as this approver',\n group: 'Token',\n }),\n\n expires_at: Field.datetime({\n label: 'Expires At',\n required: true,\n readonly: true,\n group: 'Lifecycle',\n }),\n\n consumed_at: Field.datetime({\n label: 'Consumed At',\n required: false,\n group: 'Lifecycle',\n }),\n\n created_at: Field.datetime({\n label: 'Created At',\n required: true,\n defaultValue: 'NOW()',\n readonly: true,\n group: 'System',\n }),\n },\n\n indexes: [\n { fields: ['token_hash'] },\n { fields: ['request_id'] },\n ],\n\n enable: {\n // [ADR-0103] Engine-owned: one-time email-approval tokens are minted and\n // consumed by the approval engine (SYSTEM_CTX), never via the data API.\n apiMethods: ['get', 'list'],\n },\n});\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * Session-less HTML for the actionable-link confirm/result pages (ADR-0043).\n *\n * Deliberately tiny and dependency-free: these pages are reached from an\n * email or IM message by a bearer with no session, so they must not assume\n * the Console bundle, auth state, or client-side i18n. Static bilingual\n * (EN / 中文) copy keeps them readable for the demo audience without a\n * locale negotiation step.\n *\n * The GET page NEVER mutates — the decision happens only on the POST form\n * submit (mail-gateway link prefetchers must not approve requests).\n */\n\nimport type { ApprovalRequestRow, ApprovalActionKind } from '@objectstack/spec/contracts';\n\nfunction esc(s: unknown): string {\n return String(s ?? '')\n .replaceAll('&', '&').replaceAll('<', '<').replaceAll('>', '>')\n .replaceAll('\"', '"').replaceAll(\"'\", ''');\n}\n\nfunction shell(title: string, body: string): string {\n return `<!doctype html>\n<html lang=\"en\"><head><meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n<meta name=\"robots\" content=\"noindex\">\n<title>${esc(title)}</title>\n<style>\n body{font:15px/1.6 -apple-system,BlinkMacSystemFont,\"Segoe UI\",Roboto,\"PingFang SC\",\"Microsoft YaHei\",sans-serif;\n background:#f6f7f9;color:#1a202c;margin:0;display:flex;min-height:100vh;align-items:center;justify-content:center}\n .card{background:#fff;border:1px solid #e2e8f0;border-radius:12px;max-width:440px;width:calc(100% - 32px);\n padding:28px 32px;box-shadow:0 1px 3px rgba(0,0,0,.06)}\n h1{font-size:18px;margin:0 0 4px}\n .sub{color:#64748b;font-size:13px;margin:0 0 20px}\n .row{display:flex;justify-content:space-between;gap:12px;padding:7px 0;border-bottom:1px solid #f1f5f9;font-size:14px}\n .row b{font-weight:600;text-align:right}\n .k{color:#64748b}\n .actions{margin-top:22px;display:flex;gap:10px}\n button{flex:1;padding:10px 16px;border-radius:8px;border:1px solid transparent;font-size:15px;font-weight:600;cursor:pointer}\n .approve{background:#059669;color:#fff}\n .reject{background:#fff;color:#dc2626;border-color:#fca5a5}\n .badge{display:inline-block;padding:2px 10px;border-radius:999px;font-size:12px;font-weight:600;margin-bottom:14px}\n .ok{background:#ecfdf5;color:#047857}.warn{background:#fffbeb;color:#b45309}.err{background:#fef2f2;color:#b91c1c}\n a{color:#2563eb;text-decoration:none}\n .foot{margin-top:18px;font-size:12px;color:#94a3b8}\n</style></head><body><div class=\"card\">${body}</div></body></html>`;\n}\n\nfunction summaryRows(req: ApprovalRequestRow): string {\n const rows: Array<[string, string]> = [\n ['Process · 流程', req.process_label || req.process_name],\n ['Step · 步骤', req.step_label || req.current_step || '—'],\n ['Record · 记录', req.record_title || req.record_id],\n ['Object · 对象', req.object_label || req.object_name],\n ['Requester · 申请人', req.submitter_name || req.submitter_id || '—'],\n ];\n return rows.map(([k, v]) => `<div class=\"row\"><span class=\"k\">${esc(k)}</span><b>${esc(v)}</b></div>`).join('');\n}\n\n/** GET page: summary + a POST form. Rendering only — no mutation. */\nexport function renderConfirmPage(input: {\n request: ApprovalRequestRow;\n action: Extract<ApprovalActionKind, 'approve' | 'reject'>;\n approverId: string;\n token: string;\n actPath: string;\n}): string {\n const approving = input.action === 'approve';\n const verb = approving ? 'Approve · 通过' : 'Reject · 拒绝';\n return shell(`${verb} — Approval`, `\n <h1>${approving ? '✅ Approve this request?' : '⛔ Reject this request?'}</h1>\n <p class=\"sub\">${approving ? '确认通过该审批请求?' : '确认拒绝该审批请求?'}\n Acting as · 操作身份:<b>${esc(input.approverId)}</b></p>\n ${summaryRows(input.request)}\n <form method=\"post\" action=\"${esc(input.actPath)}\" class=\"actions\">\n <input type=\"hidden\" name=\"token\" value=\"${esc(input.token)}\">\n <button type=\"submit\" class=\"${approving ? 'approve' : 'reject'}\">${verb}</button>\n </form>\n <p class=\"foot\">This link is single-use and expires automatically. · 此链接一次有效,过期自动失效。</p>`);\n}\n\nconst RESULT_COPY: Record<string, { cls: string; title: string; body: string }> = {\n approved: { cls: 'ok', title: '✅ Approved · 已通过', body: 'The decision was recorded. · 审批结果已记录。' },\n rejected: { cls: 'ok', title: '⛔ Rejected · 已拒绝', body: 'The decision was recorded. · 审批结果已记录。' },\n invalid: { cls: 'err', title: 'Invalid link · 链接无效', body: 'This link is not recognized. · 无法识别该链接。' },\n expired: { cls: 'warn', title: 'Link expired · 链接已过期', body: 'Ask the requester to send a new reminder. · 请让申请人重新发送催办。' },\n consumed: { cls: 'warn', title: 'Already used · 链接已使用', body: 'This link was already used once. · 该链接已被使用过。' },\n not_pending: { cls: 'warn', title: 'Already decided · 请求已处理', body: 'This request is no longer pending. · 该请求已不在待审批状态。' },\n not_approver: { cls: 'warn', title: 'No longer your approval · 已不在你名下', body: 'This approval was handed to someone else. · 该审批已转由他人处理。' },\n};\n\n/** Terminal page for every redemption outcome (and stale GETs). */\nexport function renderResultPage(kind: keyof typeof RESULT_COPY, request?: ApprovalRequestRow): string {\n const copy = RESULT_COPY[kind] ?? RESULT_COPY.invalid;\n return shell(copy.title, `\n <span class=\"badge ${copy.cls}\">${esc(copy.title)}</span>\n ${request ? summaryRows(request) : ''}\n <p>${esc(copy.body)}</p>\n <p class=\"foot\"><a href=\"/system/approvals\">Open the Approvals Inbox · 打开审批中心</a></p>`);\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * Lifecycle Hooks — node-era record lock (ADR-0019).\n *\n * Approval is now a flow node, so there is no per-object process registry to\n * bind auto-trigger hooks against — a flow decides *when* to open an approval.\n * What remains worth enforcing at the data layer is the **record lock**: while\n * a record has a pending `sys_approval_request`, block edits to it.\n *\n * A single global `beforeUpdate` hook handles every object (the target object\n * of an approval node is only known at flow-run time). For each update it:\n *\n * 1. Skips engine self-writes (status mirror) and `sys_approval_*` bookkeeping.\n * 2. Looks up a pending request for `(object, recordId)`.\n * 3. Reads the lock policy from that request's `node_config_json` snapshot:\n * - `lockRecord === false` → allow.\n * - otherwise block, EXCEPT when the only changed field is the configured\n * `approvalStatusField` (so the status mirror is never blocked) or the\n * caller is an `admin`.\n *\n * Registered under `packageId: 'plugin-approvals:lock'` so it can be cleanly\n * unbound on plugin stop.\n */\n\nexport const APPROVALS_HOOK_PACKAGE = 'plugin-approvals:lock';\n\ninterface MinimalEngine {\n registerHook(event: string, handler: (ctx: any) => any | Promise<any>, options?: {\n object?: string | string[];\n priority?: number;\n packageId?: string;\n }): void;\n unregisterHooksByPackage(packageId: string): number;\n find<T = any>(object: string, args: any, opts?: any): Promise<T[]>;\n}\n\ninterface MinimalLogger {\n debug?: (msg: any, ...rest: any[]) => void;\n info?: (msg: any, ...rest: any[]) => void;\n warn?: (msg: any, ...rest: any[]) => void;\n error?: (msg: any, ...rest: any[]) => void;\n}\n\nfunction parseJson<T = any>(raw: unknown, fallback: T): T {\n if (raw == null || raw === '') return fallback;\n if (typeof raw === 'string') {\n try { return JSON.parse(raw) as T; } catch { return fallback; }\n }\n return raw as T;\n}\n\n/** The pending request gating a record, plus its snapshotted node config. */\nasync function pendingRequestFor(\n engine: MinimalEngine,\n objectName: string,\n recordId: string,\n): Promise<any | null> {\n try {\n const rows = await engine.find('sys_approval_request', {\n where: { object_name: objectName, record_id: String(recordId), status: 'pending' },\n limit: 1,\n } as any);\n return Array.isArray(rows) && rows[0] ? rows[0] : null;\n } catch {\n return null;\n }\n}\n\n/**\n * Bind the global record-lock hook. Caller is responsible for calling\n * {@link unbindAllHooks} first if re-binding.\n */\nexport function bindApprovalLockHook(engine: MinimalEngine, logger?: MinimalLogger): void {\n engine.registerHook('beforeUpdate', async (ctx: any) => {\n const id = String((ctx?.input?.id ?? '') as string);\n if (!id) return;\n const object = (ctx?.object ?? ctx?.objectName) as string | undefined;\n // No object name (shouldn't happen) or our own bookkeeping objects → skip.\n if (!object || String(object).startsWith('sys_approval')) return;\n\n const data = (ctx?.input?.data ?? {}) as Record<string, unknown>;\n const changedFields = Object.keys(data).filter((k) => k !== 'id' && k !== 'updated_at');\n if (changedFields.length === 0) return;\n\n // Allow engine self-writes (status mirror from the approvals service, etc).\n if ((ctx?.session as any)?.isSystem) return;\n\n // Allow admin override.\n const roles = (ctx?.session?.roles ?? []) as string[];\n if (Array.isArray(roles) && roles.includes('admin')) return;\n\n const pending = await pendingRequestFor(engine, object, id);\n if (!pending) return;\n\n const config = parseJson<any>(pending.node_config_json, {});\n if (config?.lockRecord === false) return;\n\n // Allow when every changed field is the approval status mirror.\n const mirror = config?.approvalStatusField;\n if (typeof mirror === 'string' && mirror && changedFields.every((f) => f === mirror)) return;\n\n const err: any = new Error('RECORD_LOCKED: record is locked while an approval is in progress');\n err.code = 'RECORD_LOCKED';\n err.statusCode = 409;\n throw err;\n }, { packageId: APPROVALS_HOOK_PACKAGE, priority: 50 });\n\n logger?.info?.('[approvals] record-lock hook bound');\n}\n\n/** The self-service out-of-office delegation object (#1322). */\nexport const DELEGATION_OBJECT = 'sys_approval_delegation';\n\n/**\n * Self-service write guard for `sys_approval_delegation` (#1322 follow-up).\n *\n * The object is `apiEnabled` CRUD so a user can declare their own out-of-office\n * delegation. But it is a system object: it gets no auto `owner_id` anchor and\n * (with no `sharingModel`) defaults to a `public` sharing model, so an\n * unguarded member could **forge a delegation for someone else**\n * (`delegator_id = victim`) and reroute the victim's individually-routed\n * approvals to themselves. This guard forces a normal user's writes to name\n * themselves as the delegator:\n *\n * - **system** context (service / seed / import) → bypass;\n * - **admin** (`roles` includes `'admin'`) → may set `delegator_id` to anyone;\n * - otherwise `delegator_id` must equal the acting user — an absent delegator\n * on insert is stamped to the caller, a foreign delegator is rejected.\n *\n * Row-level ownership on update/delete (you can only touch a delegation you\n * created) is already enforced by `member_default`'s wildcard\n * `created_by == current_user.id` RLS; this guard adds the delegator-identity\n * check that RLS alone can't express. Mirrors the ADR-0092 identity write-guard\n * shape and the security plugin's `owner_id` anchor guard, scoped to this one\n * object.\n */\nexport function bindDelegationWriteGuard(engine: MinimalEngine, logger?: MinimalLogger): void {\n const makeGuard = (isInsert: boolean) => async (ctx: any) => {\n const session = (ctx?.session ?? {}) as any;\n if (session.isSystem) return; // service / seed / import\n const roles = (session.roles ?? []) as unknown[];\n if (Array.isArray(roles) && roles.includes('admin')) return; // admin may act for anyone\n const userId = session.userId != null ? String(session.userId) : '';\n const data = ctx?.input?.data;\n const rows = Array.isArray(data) ? data : (data && typeof data === 'object' ? [data] : []);\n const deny = (): never => {\n const err: any = new Error(\n 'FORBIDDEN: you may only manage out-of-office delegations where you are the delegator'\n + (userId ? ` ('${userId}')` : ''),\n );\n err.code = 'FORBIDDEN';\n err.statusCode = 403;\n throw err;\n };\n for (const row of rows) {\n if (!row || typeof row !== 'object' || Array.isArray(row)) continue;\n const has = Object.prototype.hasOwnProperty.call(row, 'delegator_id');\n const supplied = has ? String((row as any).delegator_id ?? '') : '';\n if (isInsert && (!has || supplied === '')) {\n // Self-service: stamp the caller as delegator when omitted (the schema's\n // `required` is the fallback if the engine doesn't persist the stamp).\n if (!userId) deny();\n (row as any).delegator_id = userId;\n continue;\n }\n // A foreign delegator on insert (forge) or update (relabel/hijack) → deny.\n if (has && supplied !== userId) deny();\n }\n };\n engine.registerHook('beforeInsert', makeGuard(true), { object: DELEGATION_OBJECT, packageId: APPROVALS_HOOK_PACKAGE, priority: 50 });\n engine.registerHook('beforeUpdate', makeGuard(false), { object: DELEGATION_OBJECT, packageId: APPROVALS_HOOK_PACKAGE, priority: 50 });\n logger?.info?.('[approvals] delegation write-guard bound');\n}\n\n/** Unregister every hook the lock module registered. */\nexport function unbindAllHooks(engine: MinimalEngine): number {\n return engine.unregisterHooksByPackage(APPROVALS_HOOK_PACKAGE);\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * Approval-as-flow-node provider (ADR-0019).\n *\n * Registers an `approval` node executor on the automation engine so an approval\n * rides the one flow engine as a durable-pause node:\n *\n * 1. On entry the node opens a `sys_approval_request` (reusing the mature\n * approver-resolution / audit / lock / status-mirror machinery) and returns\n * `{ suspend: true }` — the engine persists the run and stops traversal.\n * 2. A decision (`ApprovalService.decide`) finalizes the request and resumes\n * the run down the matching `approve` / `reject` out-edge.\n *\n * The approval *state* (request/action rows) stays first-class and owned by this\n * plugin — a flow-run log can't drive an inbox / recall / audit. Only the\n * orchestration (when to pause, which branch to take) moves onto the engine.\n */\n\nimport {\n defineActionDescriptor,\n ApprovalNodeConfigSchema,\n getApprovalNodeConfigJsonSchema,\n APPROVAL_NODE_TYPE,\n type ApprovalNodeConfig,\n} from '@objectstack/spec/automation';\nimport type { SharingExecutionContext } from '@objectstack/spec/contracts';\nimport type { ApprovalService } from './approval-service.js';\n\n/** Minimal surface of the automation engine this provider depends on. */\nexport interface ApprovalAutomationSurface {\n registerNodeExecutor(executor: {\n type: string;\n descriptor?: unknown;\n execute(node: any, variables: Map<string, unknown>, context: any): Promise<{\n success: boolean;\n output?: Record<string, unknown>;\n error?: string;\n suspend?: boolean;\n correlation?: string;\n }>;\n }): void;\n resume?(runId: string, signal?: { output?: Record<string, unknown>; branchLabel?: string }): Promise<unknown>;\n}\n\ninterface MinimalLogger {\n info?: (msg: any, ...rest: any[]) => void;\n warn?: (msg: any, ...rest: any[]) => void;\n}\n\nconst SYSTEM_CTX = { isSystem: true, positions: [], permissions: [] } as const;\n\n/**\n * Register the `approval` node executor on the automation engine. Idempotent at\n * the engine level (re-registering replaces). Safe to skip when no automation\n * service is present.\n */\nexport function registerApprovalNode(\n automation: ApprovalAutomationSurface,\n service: ApprovalService,\n logger?: MinimalLogger,\n): void {\n automation.registerNodeExecutor({\n type: APPROVAL_NODE_TYPE,\n descriptor: defineActionDescriptor({\n type: APPROVAL_NODE_TYPE,\n version: '1.0.0',\n name: 'Approval',\n description: 'Route a record for human approval; suspends the flow until a decision, '\n + 'then continues down the approve / reject branch.',\n icon: 'check-circle',\n category: 'human',\n paradigms: ['flow'],\n source: 'plugin',\n // Human decision: the run suspends here awaiting an external reply.\n supportsPause: true,\n isAsync: true,\n // Publish the node's config contract (ADR-0018 §configSchema) so the\n // Studio flow designer renders the Approval property form from the engine\n // rather than a hardcoded client form — the engine owns the shape.\n configSchema: getApprovalNodeConfigJsonSchema(),\n }),\n async execute(node, variables, context) {\n const parsed = ApprovalNodeConfigSchema.safeParse(node.config ?? {});\n if (!parsed.success) {\n const msg = parsed.error.issues.map(i => `${i.path.join('.')}: ${i.message}`).join('; ');\n return { success: false, error: `Approval node '${node.id}' has invalid config: ${msg}` };\n }\n const config = parsed.data as ApprovalNodeConfig;\n\n const runId = variables.get('$runId');\n const record = (variables.get('$record') ?? context?.record ?? {}) as Record<string, unknown>;\n const object = (context?.object ?? (record as any)?.object_name) as string | undefined;\n const recordId = (record as any)?.id as string | undefined;\n\n if (!runId) return { success: false, error: `Approval node '${node.id}': missing $runId` };\n if (!object) return { success: false, error: `Approval node '${node.id}': no target object in context` };\n if (!recordId) return { success: false, error: `Approval node '${node.id}': no record id in $record` };\n\n // Flow identity comes from engine-seeded variables (`$flowName` /\n // `$flowLabel`) so the request row can carry a human-readable origin;\n // `context.flowName` is a legacy fallback for direct callers.\n const flowName = (variables.get('$flowName') as string | undefined) ?? context?.flowName;\n const flowLabel = variables.get('$flowLabel') as string | undefined;\n\n try {\n const request = await service.openNodeRequest({\n object,\n recordId: String(recordId),\n runId: String(runId),\n nodeId: node.id,\n config,\n flowName,\n flowLabel,\n nodeLabel: typeof node.label === 'string' ? node.label : undefined,\n submitterId: context?.userId ?? null,\n record,\n organizationId: context?.organizationId ?? context?.tenantId ?? null,\n }, {\n ...SYSTEM_CTX,\n userId: context?.userId,\n organizationId: context?.organizationId,\n tenantId: context?.tenantId,\n } as unknown as SharingExecutionContext);\n\n logger?.info?.('[approvals] approval node suspended run', {\n node: node.id, request: request.id, run: String(runId),\n });\n // Suspend the run; the request id is the correlation key surfaced on\n // the suspended-run record for lookup.\n return { success: true, suspend: true, correlation: request.id };\n } catch (err: any) {\n return { success: false, error: `Approval node '${node.id}': ${err?.message ?? String(err)}` };\n }\n },\n });\n\n logger?.info?.('[approvals] approval node executor registered');\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { Plugin, PluginContext } from '@objectstack/core';\nimport { SysApprovalRequest } from './sys-approval-request.object.js';\nimport { SysApprovalAction } from './sys-approval-action.object.js';\nimport { SysApprovalApprover } from './sys-approval-approver.object.js';\nimport { SysApprovalToken } from './sys-approval-token.object.js';\nimport { SysApprovalDelegation } from './sys-approval-delegation.object.js';\nimport { renderConfirmPage, renderResultPage } from './action-link-pages.js';\nimport {\n ApprovalService,\n ESCALATION_JOB_NAME,\n ESCALATION_SCAN_INTERVAL_MS,\n type ApprovalEngine,\n} from './approval-service.js';\nimport { bindApprovalLockHook, bindDelegationWriteGuard, unbindAllHooks } from './lifecycle-hooks.js';\nimport { registerApprovalNode, type ApprovalAutomationSurface } from './approval-node.js';\n\nexport interface ApprovalsPluginOptions {\n /** Disable runtime registration (schemas still register). */\n disableService?: boolean;\n /**\n * Interval between SLA escalation scans (ADR-0042). Defaults to\n * {@link ESCALATION_SCAN_INTERVAL_MS} (5 min). Only takes effect when a\n * `job` service is installed; without one, SLA stays display-only.\n */\n escalationScanIntervalMs?: number;\n /**\n * Absolute origin for actionable links in outbound notifications\n * (ADR-0043), e.g. `https://app.example.com`. Relative by default.\n */\n publicBaseUrl?: string;\n /**\n * Disable the record-lock hook. Schema + service stay intact; only the\n * engine-level lock wiring is suppressed. Useful when a caller wants the\n * manual API only (e.g. tests).\n */\n disableAutoHooks?: boolean;\n}\n\n/**\n * ApprovalsServicePlugin — registers sys_approval_{request,action}, the\n * `approvals` service, the `approval` flow node executor (ADR-0019), and the\n * record-lock hook.\n *\n * ADR-0019: approval is no longer a standalone process engine. A flow's\n * Approval node opens a request and suspends the run; a decision via the\n * service resumes it down the matching branch.\n */\nexport class ApprovalsServicePlugin implements Plugin {\n name = 'com.objectstack.service.approvals';\n version = '1.0.0';\n type = 'standard';\n dependencies = ['com.objectstack.engine.objectql'];\n\n private readonly options: ApprovalsPluginOptions;\n private service?: ApprovalService;\n private engine?: any;\n private escalationJobScheduled = false;\n\n constructor(options: ApprovalsPluginOptions = {}) {\n this.options = options;\n }\n\n async init(ctx: PluginContext): Promise<void> {\n ctx.getService<{ register(m: any): void }>('manifest').register({\n id: 'com.objectstack.service.approvals',\n name: 'Approvals Service',\n version: '1.0.0',\n type: 'plugin',\n scope: 'system',\n defaultDatasource: 'cloud',\n namespace: 'sys',\n objects: [SysApprovalRequest, SysApprovalAction, SysApprovalApprover, SysApprovalToken, SysApprovalDelegation],\n // ADR-0029 D7 — contribute the Approvals entries into the Setup app's\n // `group_approvals` slot. This plugin owns these objects (K2.b), so it\n // ships their menu too; when the plugin isn't installed the slot is empty.\n navigationContributions: [\n {\n app: 'setup',\n group: 'group_approvals',\n priority: 100,\n items: [\n { id: 'nav_approval_requests', type: 'object', label: 'Requests', objectName: 'sys_approval_request', icon: 'inbox', requiresObject: 'sys_approval_request' },\n { id: 'nav_approval_actions', type: 'object', label: 'Action History', objectName: 'sys_approval_action', icon: 'history', requiresObject: 'sys_approval_action' },\n { id: 'nav_approval_delegations', type: 'object', label: 'Delegations (OOO)', objectName: 'sys_approval_delegation', icon: 'user-clock', requiresObject: 'sys_approval_delegation' },\n ],\n },\n ],\n });\n // ADR-0029 D8 — contribute this plugin's object translations to the i18n\n // service on kernel:ready (the i18n plugin may register after this one).\n if (typeof (ctx as any).hook === 'function') {\n (ctx as any).hook('kernel:ready', async () => {\n try {\n const i18n = ctx.getService<any>('i18n');\n if (i18n && typeof i18n.loadTranslations === 'function') {\n const { ApprovalsTranslations } = await import('./translations/index.js');\n for (const [locale, data] of Object.entries(ApprovalsTranslations)) {\n i18n.loadTranslations(locale, data as Record<string, unknown>);\n }\n }\n } catch { /* i18n optional */ }\n });\n }\n ctx.logger.info('ApprovalsServicePlugin: schemas registered');\n }\n\n async start(ctx: PluginContext): Promise<void> {\n if (this.options.disableService) return;\n let engine: any = null;\n try { engine = ctx.getService<any>('objectql'); }\n catch { try { engine = ctx.getService<any>('data'); } catch { /* ignore */ } }\n if (!engine) {\n ctx.logger.warn('ApprovalsServicePlugin: no ObjectQL engine — service NOT registered');\n return;\n }\n this.engine = engine;\n\n this.service = new ApprovalService({\n engine: engine as ApprovalEngine,\n logger: ctx.logger,\n publicBaseUrl: this.options.publicBaseUrl,\n });\n\n // Record lock: block edits to a record while it has a pending request.\n // Delegation write-guard: a self-service OOO delegation may only name the\n // acting user as delegator (#1322 follow-up). Both bind under the same\n // package id, so unbindAllHooks clears them together.\n if (!this.options.disableAutoHooks) {\n try {\n unbindAllHooks(engine);\n bindApprovalLockHook(engine, ctx.logger);\n bindDelegationWriteGuard(engine, ctx.logger);\n } catch (err: any) {\n ctx.logger.warn?.('[approvals] failed to bind approval hooks', { error: err?.message });\n }\n }\n\n ctx.registerService('approvals', this.service);\n ctx.logger.info('ApprovalsServicePlugin: service registered');\n\n // Optional messaging service (ADR-0012): thread interactions (reassign /\n // remind / request-info / comment) notify users when present; without it\n // they degrade to audit-only.\n try {\n const messaging = ctx.getService<any>('messaging');\n if (messaging && typeof messaging.emit === 'function') {\n this.service.attachMessaging(messaging);\n }\n } catch { /* messaging not installed */ }\n\n // SLA escalation clock (ADR-0042): a plugin-internal job, deliberately\n // NOT a flow trigger (ADR-0041 §1). Interval sweep + one catch-up scan at\n // boot so a restart doesn't extend a breach by a scan period. Wired on\n // kernel:ready — the job service may start after this plugin. No `job`\n // service → SLA stays display-only.\n const wireEscalationClock = async () => {\n try {\n const jobs = ctx.getService<any>('job');\n if (!jobs || typeof jobs.schedule !== 'function' || !this.service) return;\n const svc = this.service;\n const intervalMs = this.options.escalationScanIntervalMs ?? ESCALATION_SCAN_INTERVAL_MS;\n await jobs.schedule(ESCALATION_JOB_NAME, { type: 'interval', intervalMs }, async () => {\n await svc.runEscalations();\n });\n this.escalationJobScheduled = true;\n void svc.runEscalations().catch((err: any) => {\n ctx.logger.warn?.('[approvals] boot escalation sweep failed', { error: err?.message });\n });\n ctx.logger.info('ApprovalsServicePlugin: SLA escalation scan scheduled', { intervalMs });\n } catch { /* job service not installed */ }\n };\n // Actionable-link pages (ADR-0043): session-less confirm + redemption,\n // mounted straight on the host Hono app. GET only renders; the decision\n // happens exclusively on the POST (mail-gateway prefetch safe).\n const mountActionPages = async () => {\n try {\n const http = ctx.getService<any>('http-server');\n const rawApp = http && typeof http.getRawApp === 'function' ? http.getRawApp() : null;\n if (!rawApp || !this.service) return;\n const svc = this.service;\n const ACT_PATH = '/api/v1/approvals/act';\n const html = (c: any, body: string, status = 200) =>\n c.body(body, status, { 'Content-Type': 'text/html; charset=utf-8' });\n rawApp.get(ACT_PATH, async (c: any) => {\n const token = String(c.req.query('token') ?? '');\n const peek = await svc.peekActionToken(token);\n if (!peek.ok) return html(c, renderResultPage(peek.reason, peek.request), 200);\n return html(c, renderConfirmPage({\n request: peek.request, action: peek.action, approverId: peek.approverId,\n token, actPath: ACT_PATH,\n }));\n });\n rawApp.post(ACT_PATH, async (c: any) => {\n let token = '';\n try {\n const body = await c.req.parseBody();\n token = String(body?.token ?? '');\n } catch { /* fall through to invalid */ }\n const out = await svc.redeemActionToken(token);\n if (!out.ok) return html(c, renderResultPage(out.reason, out.request), 200);\n return html(c, renderResultPage(out.action === 'approve' ? 'approved' : 'rejected', out.request));\n });\n ctx.logger.info(`ApprovalsServicePlugin: actionable-link pages mounted at ${ACT_PATH}`);\n } catch { /* http server not installed */ }\n };\n\n // Pending-approver index backfill (issue #1745): rebuild the normalized\n // sys_approval_approver rows from the pending_approvers CSV so requests\n // written before the index existed (or drifted past a crashed sync) are\n // queryable. Idempotent; cost tracks the live pending queue.\n const backfillApproverIndex = async () => {\n try {\n const svc = this.service;\n if (!svc) return;\n const out = await svc.rebuildApproverIndex();\n if (out.inserted > 0 || out.deleted > 0) {\n ctx.logger.info('ApprovalsServicePlugin: approver index rebuilt', out);\n }\n } catch (err: any) {\n ctx.logger.warn?.('[approvals] approver index backfill failed', { error: err?.message });\n }\n };\n\n if (typeof (ctx as any).hook === 'function') {\n (ctx as any).hook('kernel:ready', wireEscalationClock);\n (ctx as any).hook('kernel:ready', mountActionPages);\n (ctx as any).hook('kernel:ready', backfillApproverIndex);\n } else {\n await wireEscalationClock();\n await mountActionPages();\n await backfillApproverIndex();\n }\n\n // ADR-0019: contribute the `approval` node to the flow engine when one is\n // present. The node lets a flow suspend on an approval and resume on\n // decision; the service is wired to the same engine so `decide()` can\n // resume the suspended run.\n try {\n const automation = ctx.getService<ApprovalAutomationSurface>('automation');\n if (automation && typeof automation.registerNodeExecutor === 'function') {\n this.service.attachAutomation(automation);\n registerApprovalNode(automation, this.service, ctx.logger);\n }\n } catch {\n ctx.logger.info('ApprovalsServicePlugin: no automation engine — approval node not registered');\n }\n }\n\n async stop(ctx: PluginContext): Promise<void> {\n if (this.escalationJobScheduled) {\n try {\n const jobs = ctx.getService<any>('job');\n await jobs?.cancel?.(ESCALATION_JOB_NAME);\n } catch { /* ignore */ }\n this.escalationJobScheduled = false;\n }\n if (this.engine) {\n try { unbindAllHooks(this.engine); } catch { /* ignore */ }\n }\n }\n}\n"],"mappings":"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","names":["import_data","import_data","import_data","uid","fresh","resumed","esc","import_data","parseJson","import_automation","SYSTEM_CTX","ApprovalsTranslations"]}
|