@objectstack/plugin-approvals 7.8.0 → 8.0.0
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 +30 -0
- package/dist/index.d.mts +1117 -32
- package/dist/index.d.ts +1117 -32
- package/dist/index.js +7 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +7 -2
- package/dist/index.mjs.map +1 -1
- package/package.json +7 -7
- package/src/approval-service.test.ts +16 -0
- package/src/approval-service.ts +15 -3
package/dist/index.mjs.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/sys-approval-request.object.ts","../src/sys-approval-action.object.ts","../src/approval-service.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};\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};\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};\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};\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\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 titleFormat: '{process_name} · {record_id}',\n compactLayout: ['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 ['pending', 'approved', 'rejected', 'recalled'],\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 // \"My approvals\" inbox — pending_approvers is a CSV string so this\n // index only helps with status pre-filtering; the engine does a\n // post-filter substring match per row.\n { fields: ['status', 'updated_at'] },\n { fields: ['submitter_id', 'status'] },\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 titleFormat: '{action} · {step_name}',\n compactLayout: ['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 ['submit', 'approve', 'reject', 'recall', 'escalate'],\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 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","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport {\n APPROVAL_BRANCH_LABELS,\n type ApprovalNodeConfig,\n} from '@objectstack/spec/automation';\nimport type {\n IApprovalService,\n ApprovalRequestRow,\n ApprovalActionRow,\n ApprovalDecisionInput,\n ApprovalDecisionResult,\n ApprovalStatus,\n SharingExecutionContext,\n} from '@objectstack/spec/contracts';\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 / role /\n * 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}\n\nconst SYSTEM_CTX = { isSystem: true, roles: [], permissions: [] } as const;\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\nfunction rowFromRequest(row: any): ApprovalRequestRow {\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 } as any;\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 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}\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\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 }\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 /**\n * Expand the approvers on an Approval node into user IDs by querying the\n * graph tables for `team:` / `department:` / `role:` / `manager:` approver\n * types. Falls back to a prefixed literal (`type:value`) when graph lookups\n * produce nothing — so existing fixtures and flows that rely on substring\n * matching keep working.\n *\n * **Graph semantics:**\n * - `team` → flat members of `sys_team` (better-auth; no BFS)\n * - `department` → recursive BFS of `sys_department.parent_department_id`\n * → members of every descendant via `sys_department_member`\n * - `role` → users with `sys_member.role = value` in tenant\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 private async expandApprovers(step: any, record?: any, organizationId?: string | null): Promise<string[]> {\n if (!step || !Array.isArray(step.approvers)) return [];\n const out: string[] = [];\n for (const a of step.approvers) {\n if (!a) continue;\n if (a.type === 'user') { out.push(String(a.value)); continue; }\n if (a.type === 'field' && record) { out.push(String((record as any)[a.value] ?? '')); continue; }\n try {\n if (a.type === 'team') {\n const users = await this.expandTeamUsers(String(a.value));\n if (users.length) { for (const u of users) out.push(u); continue; }\n } else if (a.type === 'department' || a.type === 'dept') {\n const users = await this.expandDepartmentUsers(String(a.value), organizationId);\n if (users.length) { for (const u of users) out.push(u); continue; }\n } else if (a.type === 'role') {\n const users = await this.expandRoleUsers(String(a.value), organizationId);\n if (users.length) { for (const u of users) out.push(u); continue; }\n } else if (a.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) { out.push(mgr); continue; }\n }\n }\n } catch { /* fall through */ }\n out.push(`${a.type}:${a.value}`);\n }\n return out.filter(Boolean);\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_department.parent_department_id`. */\n private async expandDepartmentUsers(departmentId: string, organizationId?: string | null): Promise<string[]> {\n if (!departmentId) 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_department', {\n filter: organizationId\n ? { id: departmentId, organization_id: organizationId }\n : { id: departmentId },\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>([departmentId]);\n const queue: string[] = [departmentId];\n while (queue.length) {\n const parent = queue.shift()!;\n let kids: any[] = [];\n try {\n const filter: any = { parent_department_id: parent, active: { $ne: false } };\n if (organizationId) filter.organization_id = organizationId;\n kids = await this.engine.find('sys_department', { 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_department_member', {\n filter: { department_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 private async expandRoleUsers(roleName: string, organizationId?: string | null): Promise<string[]> {\n if (!roleName) return [];\n const filter: any = { role: roleName };\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 /** 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 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 approvers = await this.expandApprovers({ approvers: input.config.approvers }, input.record, ctxOrg);\n\n const now = this.clock.now().toISOString();\n const id = uid('areq');\n const processName = `flow:${input.flowName ?? input.nodeId}`;\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(input.config),\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.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 // 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 * Record a decision on a node-driven request. Honours the node's `unanimous`\n * behavior (holds until every approver has approved). When the request\n * finalizes, returns the suspended run id + node id so the caller (or\n * {@link ApprovalService.decide}) can resume the flow down the matching\n * branch.\n */\n async decideNode(\n requestId: string,\n input: { decision: 'approve' | 'reject'; actorId: string; comment?: 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 unanimous 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, created_at: now,\n }, { context: SYSTEM_CTX });\n\n // Unanimous approve: advance only once every approver has approved.\n if (input.decision === 'approve' && config.behavior === 'unanimous') {\n const original = await this.expandApprovers(\n { approvers: config.approvers }, parseJson(raw.payload_json, undefined), org,\n );\n const acts = await this.engine.find('sys_approval_action', {\n where: { request_id: requestId, step_index: 0, action: 'approve' }, limit: 500, context: SYSTEM_CTX,\n });\n const approved = new Set<string>((acts ?? []).map((a: any) => String(a.actor_id ?? '')).filter(Boolean));\n const stillPending = original.filter(a => !approved.has(a));\n if (stillPending.length > 0) {\n await this.engine.update('sys_approval_request', {\n id: requestId, pending_approvers: stillPending.join(','), updated_at: now,\n }, { context: SYSTEM_CTX });\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 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 // ── Read API ─────────────────────────────────────────────────\n\n async listRequests(\n filter: {\n object?: string;\n recordId?: string;\n status?: ApprovalStatus | ApprovalStatus[];\n approverId?: string;\n submitterId?: string;\n } | undefined,\n context: SharingExecutionContext,\n ): Promise<ApprovalRequestRow[]> {\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 (we need CSV substring match\n // on pending_approvers which RLS can't model cleanly).\n const tenantOrg = (context as any)?.organizationId ?? (context as any)?.tenantId;\n if (tenantOrg) f.organization_id = tenantOrg;\n // Status: when array, post-filter; when single, push into engine filter.\n let statusFilter: ApprovalStatus[] | undefined;\n if (Array.isArray(filter?.status)) statusFilter = filter!.status as ApprovalStatus[];\n else if (filter?.status) f.status = filter.status;\n\n const rows = await this.engine.find('sys_approval_request', {\n where: f, limit: 500, orderBy: [{ field: 'updated_at', direction: 'desc' }], context: SYSTEM_CTX,\n });\n let list = Array.isArray(rows) ? rows.map(rowFromRequest) : [];\n if (statusFilter) list = list.filter(r => statusFilter!.includes(r.status));\n if (filter?.approverId) {\n const target = filter.approverId;\n list = list.filter(r => (r.pending_approvers ?? []).includes(target));\n }\n return list;\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 return Array.isArray(rows) && rows[0] ? rowFromRequest(rows[0]) : null;\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', direction: 'asc' }],\n context: SYSTEM_CTX,\n });\n return Array.isArray(rows) ? rows.map(rowFromAction) : [];\n }\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/** 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, roles: [], 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 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: context?.flowName,\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 { ApprovalService, type ApprovalEngine } from './approval-service.js';\nimport { bindApprovalLockHook, 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 * 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\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],\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 ],\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 });\n\n // Record lock: block edits to a record while it has a pending request.\n if (!this.options.disableAutoHooks) {\n try {\n unbindAllHooks(engine);\n bindApprovalLockHook(engine, ctx.logger);\n } catch (err: any) {\n ctx.logger.warn?.('[approvals] failed to bind record-lock hook', { error: err?.message });\n }\n }\n\n ctx.registerService('approvals', this.service);\n ctx.logger.info('ApprovalsServicePlugin: service registered');\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.engine) {\n try { unbindAllHooks(this.engine); } catch { /* ignore */ }\n }\n }\n}\n"],"mappings":"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","names":["ObjectSchema","Field","fresh","parseJson","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/sys-approval-request.object.ts","../src/sys-approval-action.object.ts","../src/approval-service.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};\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};\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};\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};\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\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 titleFormat: '{process_name} · {record_id}',\n compactLayout: ['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 ['pending', 'approved', 'rejected', 'recalled'],\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 // \"My approvals\" inbox — pending_approvers is a CSV string so this\n // index only helps with status pre-filtering; the engine does a\n // post-filter substring match per row.\n { fields: ['status', 'updated_at'] },\n { fields: ['submitter_id', 'status'] },\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 titleFormat: '{action} · {step_name}',\n compactLayout: ['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 ['submit', 'approve', 'reject', 'recall', 'escalate'],\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 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","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport {\n APPROVAL_BRANCH_LABELS,\n type ApprovalNodeConfig,\n} from '@objectstack/spec/automation';\nimport type {\n IApprovalService,\n ApprovalRequestRow,\n ApprovalActionRow,\n ApprovalDecisionInput,\n ApprovalDecisionResult,\n ApprovalStatus,\n SharingExecutionContext,\n} from '@objectstack/spec/contracts';\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 / role /\n * 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}\n\nconst SYSTEM_CTX = { isSystem: true, roles: [], permissions: [] } as const;\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\nfunction rowFromRequest(row: any): ApprovalRequestRow {\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 } as any;\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 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}\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\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 }\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 /**\n * Expand the approvers on an Approval node into user IDs by querying the\n * graph tables for `team:` / `department:` / `role:` / `manager:` approver\n * types. Falls back to a prefixed literal (`type:value`) when graph lookups\n * produce nothing — so existing fixtures and flows that rely on substring\n * matching keep working.\n *\n * **Graph semantics:**\n * - `team` → flat members of `sys_team` (better-auth; no BFS)\n * - `department` → recursive BFS of `sys_department.parent_department_id`\n * → members of every descendant via `sys_department_member`\n * - `role` → users with `sys_member.role = value` in tenant\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 private async expandApprovers(step: any, record?: any, organizationId?: string | null): Promise<string[]> {\n if (!step || !Array.isArray(step.approvers)) return [];\n const out: string[] = [];\n for (const a of step.approvers) {\n if (!a) continue;\n if (a.type === 'user') { out.push(String(a.value)); continue; }\n if (a.type === 'field' && record) { out.push(String((record as any)[a.value] ?? '')); continue; }\n try {\n if (a.type === 'team') {\n const users = await this.expandTeamUsers(String(a.value));\n if (users.length) { for (const u of users) out.push(u); continue; }\n } else if (a.type === 'department' || a.type === 'dept') {\n const users = await this.expandDepartmentUsers(String(a.value), organizationId);\n if (users.length) { for (const u of users) out.push(u); continue; }\n } else if (a.type === 'role') {\n const users = await this.expandRoleUsers(String(a.value), organizationId);\n if (users.length) { for (const u of users) out.push(u); continue; }\n } else if (a.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) { out.push(mgr); continue; }\n }\n }\n } catch { /* fall through */ }\n out.push(`${a.type}:${a.value}`);\n }\n return out.filter(Boolean);\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_department.parent_department_id`. */\n private async expandDepartmentUsers(departmentId: string, organizationId?: string | null): Promise<string[]> {\n if (!departmentId) 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_department', {\n filter: organizationId\n ? { id: departmentId, organization_id: organizationId }\n : { id: departmentId },\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>([departmentId]);\n const queue: string[] = [departmentId];\n while (queue.length) {\n const parent = queue.shift()!;\n let kids: any[] = [];\n try {\n const filter: any = { parent_department_id: parent, active: { $ne: false } };\n if (organizationId) filter.organization_id = organizationId;\n kids = await this.engine.find('sys_department', { 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_department_member', {\n filter: { department_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 private async expandRoleUsers(roleName: string, organizationId?: string | null): Promise<string[]> {\n if (!roleName) return [];\n const filter: any = { role: roleName };\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 /** 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 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 approvers = await this.expandApprovers({ approvers: input.config.approvers }, input.record, ctxOrg);\n\n const now = this.clock.now().toISOString();\n const id = uid('areq');\n const processName = `flow:${input.flowName ?? input.nodeId}`;\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(input.config),\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.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 // 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 * Record a decision on a node-driven request. Honours the node's `unanimous`\n * behavior (holds until every approver has approved). When the request\n * finalizes, returns the suspended run id + node id so the caller (or\n * {@link ApprovalService.decide}) can resume the flow down the matching\n * branch.\n */\n async decideNode(\n requestId: string,\n input: { decision: 'approve' | 'reject'; actorId: string; comment?: 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 unanimous 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, created_at: now,\n }, { context: SYSTEM_CTX });\n\n // Unanimous approve: advance only once every approver has approved.\n if (input.decision === 'approve' && config.behavior === 'unanimous') {\n const original = await this.expandApprovers(\n { approvers: config.approvers }, parseJson(raw.payload_json, undefined), org,\n );\n const acts = await this.engine.find('sys_approval_action', {\n where: { request_id: requestId, step_index: 0, action: 'approve' }, limit: 500, context: SYSTEM_CTX,\n });\n const approved = new Set<string>((acts ?? []).map((a: any) => String(a.actor_id ?? '')).filter(Boolean));\n const stillPending = original.filter(a => !approved.has(a));\n if (stillPending.length > 0) {\n await this.engine.update('sys_approval_request', {\n id: requestId, pending_approvers: stillPending.join(','), updated_at: now,\n }, { context: SYSTEM_CTX });\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 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 // ── Read API ─────────────────────────────────────────────────\n\n async listRequests(\n filter: {\n object?: string;\n recordId?: string;\n status?: ApprovalStatus | ApprovalStatus[];\n approverId?: string | string[];\n submitterId?: string;\n } | undefined,\n context: SharingExecutionContext,\n ): Promise<ApprovalRequestRow[]> {\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 (we need CSV substring match\n // on pending_approvers which RLS can't model cleanly).\n const tenantOrg = (context as any)?.organizationId ?? (context as any)?.tenantId;\n if (tenantOrg) f.organization_id = tenantOrg;\n // Status: when array, post-filter; when single, push into engine filter.\n let statusFilter: ApprovalStatus[] | undefined;\n if (Array.isArray(filter?.status)) statusFilter = filter!.status as ApprovalStatus[];\n else if (filter?.status) f.status = filter.status;\n\n const rows = await this.engine.find('sys_approval_request', {\n where: f, limit: 500, orderBy: [{ field: 'updated_at', direction: 'desc' }], context: SYSTEM_CTX,\n });\n let list = Array.isArray(rows) ? rows.map(rowFromRequest) : [];\n if (statusFilter) list = list.filter(r => statusFilter!.includes(r.status));\n if (filter?.approverId) {\n // Accept one identity or a list: a request matches when ANY of the\n // caller's identities (user id / email / role:<r>) is a pending\n // approver. This lets the Console badge fetch \"my pending approvals\"\n // in a single request instead of one-per-identity (previously the\n // client looped, firing N near-simultaneous calls per poll).\n const targets = (Array.isArray(filter.approverId) ? filter.approverId : [filter.approverId])\n .map(t => String(t).trim())\n .filter(Boolean);\n if (targets.length) {\n list = list.filter(r => {\n const pending = r.pending_approvers ?? [];\n return targets.some(t => pending.includes(t));\n });\n }\n }\n return list;\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 return Array.isArray(rows) && rows[0] ? rowFromRequest(rows[0]) : null;\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', direction: 'asc' }],\n context: SYSTEM_CTX,\n });\n return Array.isArray(rows) ? rows.map(rowFromAction) : [];\n }\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/** 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, roles: [], 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 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: context?.flowName,\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 { ApprovalService, type ApprovalEngine } from './approval-service.js';\nimport { bindApprovalLockHook, 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 * 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\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],\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 ],\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 });\n\n // Record lock: block edits to a record while it has a pending request.\n if (!this.options.disableAutoHooks) {\n try {\n unbindAllHooks(engine);\n bindApprovalLockHook(engine, ctx.logger);\n } catch (err: any) {\n ctx.logger.warn?.('[approvals] failed to bind record-lock hook', { error: err?.message });\n }\n }\n\n ctx.registerService('approvals', this.service);\n ctx.logger.info('ApprovalsServicePlugin: service registered');\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.engine) {\n try { unbindAllHooks(this.engine); } catch { /* ignore */ }\n }\n }\n}\n"],"mappings":"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","names":["ObjectSchema","Field","fresh","parseJson","SYSTEM_CTX","ApprovalsTranslations"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@objectstack/plugin-approvals",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "8.0.0",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"description": "Multi-step approval engine for ObjectStack — sys_approval_process + sys_approval_request + sys_approval_action + IApprovalService.",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -13,17 +13,17 @@
|
|
|
13
13
|
}
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
|
-
"@objectstack/core": "
|
|
17
|
-
"@objectstack/formula": "
|
|
18
|
-
"@objectstack/metadata-core": "
|
|
19
|
-
"@objectstack/platform-objects": "
|
|
20
|
-
"@objectstack/spec": "
|
|
16
|
+
"@objectstack/core": "8.0.0",
|
|
17
|
+
"@objectstack/formula": "8.0.0",
|
|
18
|
+
"@objectstack/metadata-core": "8.0.0",
|
|
19
|
+
"@objectstack/platform-objects": "8.0.0",
|
|
20
|
+
"@objectstack/spec": "8.0.0"
|
|
21
21
|
},
|
|
22
22
|
"devDependencies": {
|
|
23
23
|
"@types/node": "^25.9.1",
|
|
24
24
|
"typescript": "^6.0.3",
|
|
25
25
|
"vitest": "^4.1.8",
|
|
26
|
-
"@objectstack/service-automation": "
|
|
26
|
+
"@objectstack/service-automation": "8.0.0"
|
|
27
27
|
},
|
|
28
28
|
"keywords": [
|
|
29
29
|
"objectstack",
|
|
@@ -264,6 +264,22 @@ describe('ApprovalService (node era)', () => {
|
|
|
264
264
|
expect(none).toHaveLength(0);
|
|
265
265
|
});
|
|
266
266
|
|
|
267
|
+
it('listRequests: approverId accepts a list and matches ANY identity', async () => {
|
|
268
|
+
await svc.openNodeRequest(openInput(['u9']), CTX);
|
|
269
|
+
// None of these identities individually except the last is the approver.
|
|
270
|
+
const hit = await svc.listRequests(
|
|
271
|
+
{ status: 'pending', approverId: ['someone-else', 'user@example.com', 'u9'] },
|
|
272
|
+
SYS,
|
|
273
|
+
);
|
|
274
|
+
expect(hit).toHaveLength(1);
|
|
275
|
+
// A list with no matching identity returns nothing.
|
|
276
|
+
const miss = await svc.listRequests({ approverId: ['a', 'b', 'role:viewer'] }, SYS);
|
|
277
|
+
expect(miss).toHaveLength(0);
|
|
278
|
+
// Empty / whitespace-only ids are ignored, not treated as a match-all.
|
|
279
|
+
const ignored = await svc.listRequests({ approverId: ['', ' '] }, SYS);
|
|
280
|
+
expect(ignored).toHaveLength(1);
|
|
281
|
+
});
|
|
282
|
+
|
|
267
283
|
it('listActions: returns the audit trail for a request', async () => {
|
|
268
284
|
const req = await svc.openNodeRequest(openInput(['u9']), CTX);
|
|
269
285
|
await svc.decideNode(req.id, { decision: 'approve', actorId: 'u9' }, SYS);
|
package/src/approval-service.ts
CHANGED
|
@@ -470,7 +470,7 @@ export class ApprovalService implements IApprovalService {
|
|
|
470
470
|
object?: string;
|
|
471
471
|
recordId?: string;
|
|
472
472
|
status?: ApprovalStatus | ApprovalStatus[];
|
|
473
|
-
approverId?: string;
|
|
473
|
+
approverId?: string | string[];
|
|
474
474
|
submitterId?: string;
|
|
475
475
|
} | undefined,
|
|
476
476
|
context: SharingExecutionContext,
|
|
@@ -498,8 +498,20 @@ export class ApprovalService implements IApprovalService {
|
|
|
498
498
|
let list = Array.isArray(rows) ? rows.map(rowFromRequest) : [];
|
|
499
499
|
if (statusFilter) list = list.filter(r => statusFilter!.includes(r.status));
|
|
500
500
|
if (filter?.approverId) {
|
|
501
|
-
|
|
502
|
-
|
|
501
|
+
// Accept one identity or a list: a request matches when ANY of the
|
|
502
|
+
// caller's identities (user id / email / role:<r>) is a pending
|
|
503
|
+
// approver. This lets the Console badge fetch "my pending approvals"
|
|
504
|
+
// in a single request instead of one-per-identity (previously the
|
|
505
|
+
// client looped, firing N near-simultaneous calls per poll).
|
|
506
|
+
const targets = (Array.isArray(filter.approverId) ? filter.approverId : [filter.approverId])
|
|
507
|
+
.map(t => String(t).trim())
|
|
508
|
+
.filter(Boolean);
|
|
509
|
+
if (targets.length) {
|
|
510
|
+
list = list.filter(r => {
|
|
511
|
+
const pending = r.pending_approvers ?? [];
|
|
512
|
+
return targets.some(t => pending.includes(t));
|
|
513
|
+
});
|
|
514
|
+
}
|
|
503
515
|
}
|
|
504
516
|
return list;
|
|
505
517
|
}
|