@wildo-ai/saas-backend-lib 1.1.12 → 1.1.13
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/dist/esm/base-classes/models/manual-controllers.backend.definition.d.ts.map +1 -1
- package/dist/esm/base-classes/models/manual-controllers.backend.definition.js +2 -0
- package/dist/esm/base-classes/models/manual-controllers.backend.definition.js.map +1 -1
- package/dist/esm/base-classes/services/repositories/stored-field-omission.backend.d.ts +4 -0
- package/dist/esm/base-classes/services/repositories/stored-field-omission.backend.d.ts.map +1 -1
- package/dist/esm/base-classes/services/repositories/stored-field-omission.backend.js +20 -5
- package/dist/esm/base-classes/services/repositories/stored-field-omission.backend.js.map +1 -1
- package/dist/esm/base-classes/services/services/resource-operation-custom-implementation-registry.backend.service.d.ts +3 -0
- package/dist/esm/base-classes/services/services/resource-operation-custom-implementation-registry.backend.service.d.ts.map +1 -1
- package/dist/esm/base-classes/services/services/resource-operation-custom-implementation-registry.backend.service.js +10 -1
- package/dist/esm/base-classes/services/services/resource-operation-custom-implementation-registry.backend.service.js.map +1 -1
- package/dist/esm/base-classes/services/services/resource-operation-custom-implementation.factory.backend.d.ts +22 -0
- package/dist/esm/base-classes/services/services/resource-operation-custom-implementation.factory.backend.d.ts.map +1 -1
- package/dist/esm/base-classes/services/services/resource-operation-custom-implementation.factory.backend.js +25 -1
- package/dist/esm/base-classes/services/services/resource-operation-custom-implementation.factory.backend.js.map +1 -1
- package/dist/esm/base-classes/services/services/resource-operation-transaction-persistence.backend.utils.d.ts +38 -3
- package/dist/esm/base-classes/services/services/resource-operation-transaction-persistence.backend.utils.d.ts.map +1 -1
- package/dist/esm/base-classes/services/services/resource-operation-transaction-persistence.backend.utils.js +68 -5
- package/dist/esm/base-classes/services/services/resource-operation-transaction-persistence.backend.utils.js.map +1 -1
- package/dist/esm/base-classes/services/services/resource-status-transition.custom-impl.backend.service.d.ts +2 -2
- package/dist/esm/base-classes/services/services/resource-status-transition.custom-impl.backend.service.d.ts.map +1 -1
- package/dist/esm/base-classes/services/services/resource-status-transition.custom-impl.backend.service.js +6 -3
- package/dist/esm/base-classes/services/services/resource-status-transition.custom-impl.backend.service.js.map +1 -1
- package/dist/esm/base-classes/services/services/services-registry-handler.backend.service.d.ts +83 -0
- package/dist/esm/base-classes/services/services/services-registry-handler.backend.service.d.ts.map +1 -1
- package/dist/esm/base-classes/services/services/services-registry-handler.backend.service.js +217 -14
- package/dist/esm/base-classes/services/services/services-registry-handler.backend.service.js.map +1 -1
- package/dist/esm/compliance/approval-seals/approval-seal-currency.backend.d.ts +32 -0
- package/dist/esm/compliance/approval-seals/approval-seal-currency.backend.d.ts.map +1 -0
- package/dist/esm/compliance/approval-seals/approval-seal-currency.backend.js +36 -0
- package/dist/esm/compliance/approval-seals/approval-seal-currency.backend.js.map +1 -0
- package/dist/esm/compliance/approval-seals/approval-seal-on-record.backend.d.ts +38 -0
- package/dist/esm/compliance/approval-seals/approval-seal-on-record.backend.d.ts.map +1 -0
- package/dist/esm/compliance/approval-seals/approval-seal-on-record.backend.js +83 -0
- package/dist/esm/compliance/approval-seals/approval-seal-on-record.backend.js.map +1 -0
- package/dist/esm/compliance/approval-seals/approval-seal-presentation-read.backend.d.ts +36 -0
- package/dist/esm/compliance/approval-seals/approval-seal-presentation-read.backend.d.ts.map +1 -0
- package/dist/esm/compliance/approval-seals/approval-seal-presentation-read.backend.js +51 -0
- package/dist/esm/compliance/approval-seals/approval-seal-presentation-read.backend.js.map +1 -0
- package/dist/esm/compliance/approval-seals/approval-seal-relay-store.backend.d.ts +46 -0
- package/dist/esm/compliance/approval-seals/approval-seal-relay-store.backend.d.ts.map +1 -1
- package/dist/esm/compliance/approval-seals/approval-seal-relay-store.backend.js +68 -0
- package/dist/esm/compliance/approval-seals/approval-seal-relay-store.backend.js.map +1 -1
- package/dist/esm/compliance/approval-seals/approval-seal-store.backend.d.ts +27 -0
- package/dist/esm/compliance/approval-seals/approval-seal-store.backend.d.ts.map +1 -1
- package/dist/esm/compliance/approval-seals/approval-seal-store.backend.js +42 -3
- package/dist/esm/compliance/approval-seals/approval-seal-store.backend.js.map +1 -1
- package/dist/esm/compliance/approval-seals/approval-seals-admin.backend.contracts.d.ts +26 -1
- package/dist/esm/compliance/approval-seals/approval-seals-admin.backend.contracts.d.ts.map +1 -1
- package/dist/esm/compliance/approval-seals/approval-seals-admin.backend.contracts.js +10 -0
- package/dist/esm/compliance/approval-seals/approval-seals-admin.backend.contracts.js.map +1 -1
- package/dist/esm/compliance/approval-seals/approval-seals-admin.backend.controller.d.ts +10 -1
- package/dist/esm/compliance/approval-seals/approval-seals-admin.backend.controller.d.ts.map +1 -1
- package/dist/esm/compliance/approval-seals/approval-seals-admin.backend.controller.js +60 -28
- package/dist/esm/compliance/approval-seals/approval-seals-admin.backend.controller.js.map +1 -1
- package/dist/esm/compliance/approval-seals/approval-seals-on-record.backend.controller.d.ts +90 -0
- package/dist/esm/compliance/approval-seals/approval-seals-on-record.backend.controller.d.ts.map +1 -0
- package/dist/esm/compliance/approval-seals/approval-seals-on-record.backend.controller.js +373 -0
- package/dist/esm/compliance/approval-seals/approval-seals-on-record.backend.controller.js.map +1 -0
- package/dist/esm/compliance/approval-seals/decision-presentation.backend.d.ts +29 -2
- package/dist/esm/compliance/approval-seals/decision-presentation.backend.d.ts.map +1 -1
- package/dist/esm/compliance/approval-seals/decision-presentation.backend.js +40 -3
- package/dist/esm/compliance/approval-seals/decision-presentation.backend.js.map +1 -1
- package/dist/esm/compliance/electronic-signatures/pdf-signature-structure.backend.d.ts.map +1 -1
- package/dist/esm/compliance/electronic-signatures/pdf-signature-structure.backend.js +34 -6
- package/dist/esm/compliance/electronic-signatures/pdf-signature-structure.backend.js.map +1 -1
- package/dist/esm/compliance/electronic-signatures/signature-request-evidence-files.backend.d.ts +30 -6
- package/dist/esm/compliance/electronic-signatures/signature-request-evidence-files.backend.d.ts.map +1 -1
- package/dist/esm/compliance/electronic-signatures/signature-request-evidence-files.backend.js +67 -22
- package/dist/esm/compliance/electronic-signatures/signature-request-evidence-files.backend.js.map +1 -1
- package/dist/esm/compliance/electronic-signatures/signature-request-poll.batch.backend.service.d.ts.map +1 -1
- package/dist/esm/compliance/electronic-signatures/signature-request-poll.batch.backend.service.js +18 -1
- package/dist/esm/compliance/electronic-signatures/signature-request-poll.batch.backend.service.js.map +1 -1
- package/dist/esm/compliance/electronic-signatures/signature-requests.backend.service.d.ts +66 -1
- package/dist/esm/compliance/electronic-signatures/signature-requests.backend.service.d.ts.map +1 -1
- package/dist/esm/compliance/electronic-signatures/signature-requests.backend.service.js +161 -14
- package/dist/esm/compliance/electronic-signatures/signature-requests.backend.service.js.map +1 -1
- package/dist/esm/compliance/electronic-signatures/signed-document-validation.backend.d.ts +47 -0
- package/dist/esm/compliance/electronic-signatures/signed-document-validation.backend.d.ts.map +1 -1
- package/dist/esm/compliance/electronic-signatures/signed-document-validation.backend.js.map +1 -1
- package/dist/esm/external-providers/services/content-safety.backend.service.d.ts +27 -2
- package/dist/esm/external-providers/services/content-safety.backend.service.d.ts.map +1 -1
- package/dist/esm/external-providers/services/content-safety.backend.service.js +46 -1
- package/dist/esm/external-providers/services/content-safety.backend.service.js.map +1 -1
- package/dist/esm/external-providers/services/embeddings.backend.service.d.ts.map +1 -1
- package/dist/esm/external-providers/services/embeddings.backend.service.js +2 -0
- package/dist/esm/external-providers/services/embeddings.backend.service.js.map +1 -1
- package/dist/esm/external-providers/services/external-providers-registry.backend.service.d.ts +11 -0
- package/dist/esm/external-providers/services/external-providers-registry.backend.service.d.ts.map +1 -1
- package/dist/esm/external-providers/services/external-providers-registry.backend.service.js +23 -0
- package/dist/esm/external-providers/services/external-providers-registry.backend.service.js.map +1 -1
- package/dist/esm/external-providers/services/provider-service-account-token.backend.d.ts +19 -1
- package/dist/esm/external-providers/services/provider-service-account-token.backend.d.ts.map +1 -1
- package/dist/esm/external-providers/services/provider-service-account-token.backend.js +41 -1
- package/dist/esm/external-providers/services/provider-service-account-token.backend.js.map +1 -1
- package/dist/esm/files/utils/file-parent-read-context.backend.d.ts +27 -2
- package/dist/esm/files/utils/file-parent-read-context.backend.d.ts.map +1 -1
- package/dist/esm/files/utils/file-parent-read-context.backend.js +23 -4
- package/dist/esm/files/utils/file-parent-read-context.backend.js.map +1 -1
- package/dist/esm/flows-actors/content-guardrails/classifier-availability.backend.utils.d.ts +26 -0
- package/dist/esm/flows-actors/content-guardrails/classifier-availability.backend.utils.d.ts.map +1 -1
- package/dist/esm/flows-actors/content-guardrails/classifier-availability.backend.utils.js +100 -8
- package/dist/esm/flows-actors/content-guardrails/classifier-availability.backend.utils.js.map +1 -1
- package/dist/esm/flows-actors/content-guardrails/record-owner-policy.backend.d.ts +3 -1
- package/dist/esm/flows-actors/content-guardrails/record-owner-policy.backend.d.ts.map +1 -1
- package/dist/esm/flows-actors/content-guardrails/record-owner-policy.backend.js +8 -2
- package/dist/esm/flows-actors/content-guardrails/record-owner-policy.backend.js.map +1 -1
- package/dist/esm/flows-actors/models/function-tools.backend.definitions.d.ts +43 -0
- package/dist/esm/flows-actors/models/function-tools.backend.definitions.d.ts.map +1 -1
- package/dist/esm/flows-actors/models/function-tools.backend.definitions.js +37 -0
- package/dist/esm/flows-actors/models/function-tools.backend.definitions.js.map +1 -1
- package/dist/esm/flows-actors/services/agent-work-decisions.backend.service.d.ts +7 -0
- package/dist/esm/flows-actors/services/agent-work-decisions.backend.service.d.ts.map +1 -1
- package/dist/esm/flows-actors/services/agent-work-decisions.backend.service.js +8 -3
- package/dist/esm/flows-actors/services/agent-work-decisions.backend.service.js.map +1 -1
- package/dist/esm/flows-actors/services/agents.backend.service.d.ts +31 -6
- package/dist/esm/flows-actors/services/agents.backend.service.d.ts.map +1 -1
- package/dist/esm/flows-actors/services/agents.backend.service.js +78 -30
- package/dist/esm/flows-actors/services/agents.backend.service.js.map +1 -1
- package/dist/esm/flows-actors/services/autonomous-agent-turn.backend.service.d.ts.map +1 -1
- package/dist/esm/flows-actors/services/autonomous-agent-turn.backend.service.js +4 -0
- package/dist/esm/flows-actors/services/autonomous-agent-turn.backend.service.js.map +1 -1
- package/dist/esm/flows-actors/services/conversational-execution.backend.service.d.ts +28 -2
- package/dist/esm/flows-actors/services/conversational-execution.backend.service.d.ts.map +1 -1
- package/dist/esm/flows-actors/services/conversational-execution.backend.service.js +132 -22
- package/dist/esm/flows-actors/services/conversational-execution.backend.service.js.map +1 -1
- package/dist/esm/flows-actors/services/flow-actor-executions.custom-impl.backend.service.d.ts.map +1 -1
- package/dist/esm/flows-actors/services/flow-actor-executions.custom-impl.backend.service.js +12 -8
- package/dist/esm/flows-actors/services/flow-actor-executions.custom-impl.backend.service.js.map +1 -1
- package/dist/esm/flows-actors/services/flows-actors-registry.service.d.ts +5 -0
- package/dist/esm/flows-actors/services/flows-actors-registry.service.d.ts.map +1 -1
- package/dist/esm/flows-actors/services/flows-actors-registry.service.js +18 -2
- package/dist/esm/flows-actors/services/flows-actors-registry.service.js.map +1 -1
- package/dist/esm/flows-actors/utils/acp-session-runner.backend.utils.d.ts +33 -0
- package/dist/esm/flows-actors/utils/acp-session-runner.backend.utils.d.ts.map +1 -1
- package/dist/esm/flows-actors/utils/acp-session-runner.backend.utils.js +58 -0
- package/dist/esm/flows-actors/utils/acp-session-runner.backend.utils.js.map +1 -1
- package/dist/esm/inbound/services/inbound-delivery-dispatch.backend.service.d.ts +12 -1
- package/dist/esm/inbound/services/inbound-delivery-dispatch.backend.service.d.ts.map +1 -1
- package/dist/esm/inbound/services/inbound-delivery-dispatch.backend.service.js +23 -4
- package/dist/esm/inbound/services/inbound-delivery-dispatch.backend.service.js.map +1 -1
- package/dist/esm/inbound/services/inbound-delivery-receiver.backend.service.d.ts +12 -1
- package/dist/esm/inbound/services/inbound-delivery-receiver.backend.service.d.ts.map +1 -1
- package/dist/esm/inbound/services/inbound-delivery-receiver.backend.service.js +55 -17
- package/dist/esm/inbound/services/inbound-delivery-receiver.backend.service.js.map +1 -1
- package/dist/esm/inbound/services/inbound-delivery-store.backend.service.d.ts +22 -1
- package/dist/esm/inbound/services/inbound-delivery-store.backend.service.d.ts.map +1 -1
- package/dist/esm/inbound/services/inbound-delivery-store.backend.service.js +52 -9
- package/dist/esm/inbound/services/inbound-delivery-store.backend.service.js.map +1 -1
- package/dist/esm/inbound/services/inbound-delivery-stored-body.backend.service.d.ts +79 -0
- package/dist/esm/inbound/services/inbound-delivery-stored-body.backend.service.d.ts.map +1 -0
- package/dist/esm/inbound/services/inbound-delivery-stored-body.backend.service.js +211 -0
- package/dist/esm/inbound/services/inbound-delivery-stored-body.backend.service.js.map +1 -0
- package/dist/esm/inbound/services/inbound-delivery-subject-erasure-severance.backend.d.ts +2 -2
- package/dist/esm/inbound/services/inbound-delivery-subject-erasure-severance.backend.d.ts.map +1 -1
- package/dist/esm/inbound/services/inbound-delivery-subject-erasure-severance.backend.js +9 -1
- package/dist/esm/inbound/services/inbound-delivery-subject-erasure-severance.backend.js.map +1 -1
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +1 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/inject/models/container.d.ts.map +1 -1
- package/dist/esm/inject/models/container.js +6 -0
- package/dist/esm/inject/models/container.js.map +1 -1
- package/dist/esm/inject/models/service-types.d.ts +5 -0
- package/dist/esm/inject/models/service-types.d.ts.map +1 -1
- package/dist/esm/inject/models/service-types.js +3 -0
- package/dist/esm/inject/models/service-types.js.map +1 -1
- package/dist/esm/monitoring/observability/models/observability.backend.schemas.d.ts +5 -0
- package/dist/esm/monitoring/observability/models/observability.backend.schemas.d.ts.map +1 -1
- package/dist/esm/monitoring/observability/models/observability.backend.schemas.js.map +1 -1
- package/dist/esm/monitoring/observability/services/metrics.service.d.ts +34 -1
- package/dist/esm/monitoring/observability/services/metrics.service.d.ts.map +1 -1
- package/dist/esm/monitoring/observability/services/metrics.service.js +49 -0
- package/dist/esm/monitoring/observability/services/metrics.service.js.map +1 -1
- package/dist/esm/notifications/webhooks/controllers/webhook-auto-controller.backend.service.d.ts +6 -1
- package/dist/esm/notifications/webhooks/controllers/webhook-auto-controller.backend.service.d.ts.map +1 -1
- package/dist/esm/notifications/webhooks/controllers/webhook-auto-controller.backend.service.js +15 -4
- package/dist/esm/notifications/webhooks/controllers/webhook-auto-controller.backend.service.js.map +1 -1
- package/dist/esm/notifications/webhooks/outbound/services/m2m-webhook-delivery-log.custom-impl.backend.service.d.ts.map +1 -1
- package/dist/esm/notifications/webhooks/outbound/services/m2m-webhook-delivery-log.custom-impl.backend.service.js +3 -1
- package/dist/esm/notifications/webhooks/outbound/services/m2m-webhook-delivery-log.custom-impl.backend.service.js.map +1 -1
- package/dist/esm/runtime/services/http-server.backend.service.d.ts +3 -1
- package/dist/esm/runtime/services/http-server.backend.service.d.ts.map +1 -1
- package/dist/esm/runtime/services/http-server.backend.service.js +11 -3
- package/dist/esm/runtime/services/http-server.backend.service.js.map +1 -1
- package/dist/esm/runtime/services/utils/inbound-endpoint-raw-body.backend.utils.d.ts +22 -0
- package/dist/esm/runtime/services/utils/inbound-endpoint-raw-body.backend.utils.d.ts.map +1 -1
- package/dist/esm/runtime/services/utils/inbound-endpoint-raw-body.backend.utils.js +54 -0
- package/dist/esm/runtime/services/utils/inbound-endpoint-raw-body.backend.utils.js.map +1 -1
- package/dist/esm/security/authentications/services/auth-methods/auth-password-reset.backend.service.d.ts +51 -0
- package/dist/esm/security/authentications/services/auth-methods/auth-password-reset.backend.service.d.ts.map +1 -1
- package/dist/esm/security/authentications/services/auth-methods/auth-password-reset.backend.service.js +87 -15
- package/dist/esm/security/authentications/services/auth-methods/auth-password-reset.backend.service.js.map +1 -1
- package/dist/esm/security/authentications/services/custom-impls/siem-delivery-dlq.custom-impl.backend.service.d.ts.map +1 -1
- package/dist/esm/security/authentications/services/custom-impls/siem-delivery-dlq.custom-impl.backend.service.js +5 -2
- package/dist/esm/security/authentications/services/custom-impls/siem-delivery-dlq.custom-impl.backend.service.js.map +1 -1
- package/dist/esm/security/authentications/services/custom-impls/sso-config-domain-verification.custom-impl.backend.service.d.ts.map +1 -1
- package/dist/esm/security/authentications/services/custom-impls/sso-config-domain-verification.custom-impl.backend.service.js +65 -24
- package/dist/esm/security/authentications/services/custom-impls/sso-config-domain-verification.custom-impl.backend.service.js.map +1 -1
- package/dist/esm/security/authorizations/super-admin-floor.backend.utils.d.ts +64 -1
- package/dist/esm/security/authorizations/super-admin-floor.backend.utils.d.ts.map +1 -1
- package/dist/esm/security/authorizations/super-admin-floor.backend.utils.js +84 -2
- package/dist/esm/security/authorizations/super-admin-floor.backend.utils.js.map +1 -1
- package/dist/esm/security/oauth-clients/oauth-clients.custom-impl.backend.service.d.ts +14 -0
- package/dist/esm/security/oauth-clients/oauth-clients.custom-impl.backend.service.d.ts.map +1 -1
- package/dist/esm/security/oauth-clients/oauth-clients.custom-impl.backend.service.js +13 -5
- package/dist/esm/security/oauth-clients/oauth-clients.custom-impl.backend.service.js.map +1 -1
- package/dist/esm/users/services/anonymous-consent.custom-impl.backend.service.d.ts.map +1 -1
- package/dist/esm/users/services/anonymous-consent.custom-impl.backend.service.js +6 -2
- package/dist/esm/users/services/anonymous-consent.custom-impl.backend.service.js.map +1 -1
- package/dist/esm/users/services/user-force-password-reset.custom-impl.backend.service.d.ts +7 -0
- package/dist/esm/users/services/user-force-password-reset.custom-impl.backend.service.d.ts.map +1 -1
- package/dist/esm/users/services/user-force-password-reset.custom-impl.backend.service.js +65 -20
- package/dist/esm/users/services/user-force-password-reset.custom-impl.backend.service.js.map +1 -1
- package/dist/esm/users/services/user-role-administration.custom-impl.backend.service.d.ts.map +1 -1
- package/dist/esm/users/services/user-role-administration.custom-impl.backend.service.js +11 -4
- package/dist/esm/users/services/user-role-administration.custom-impl.backend.service.js.map +1 -1
- package/dist/esm/users/services/user-self-custom-implementations.backend.d.ts.map +1 -1
- package/dist/esm/users/services/user-self-custom-implementations.backend.js +4 -2
- package/dist/esm/users/services/user-self-custom-implementations.backend.js.map +1 -1
- package/dist/esm/users/services/user-super-admin-floor.custom-impl.backend.service.d.ts.map +1 -1
- package/dist/esm/users/services/user-super-admin-floor.custom-impl.backend.service.js +16 -0
- package/dist/esm/users/services/user-super-admin-floor.custom-impl.backend.service.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +10 -10
|
@@ -85,6 +85,29 @@ export function assertValidResourceCustomImplementationHookTransactionPosture(pa
|
|
|
85
85
|
throw new Error(`[CustomImpl] Invalid hookTransactionPosture for registration "${label}" (${params.operationPathKey}): an OVERRIDE_ALL implementation runs no framework pipeline, so no framework transaction`);
|
|
86
86
|
}
|
|
87
87
|
}
|
|
88
|
+
/**
|
|
89
|
+
* `maximumRowsWrittenPerAttempt` (#2297 wave 4): on a multi-row verb (`UPDATE_MANY` / `DELETE_MANY`) whose REPLACE handler
|
|
90
|
+
* performs the write itself, the most rows of the operation's resource one attempt writes. The framework cannot chunk a
|
|
91
|
+
* selection a hook makes, so this declaration is what bounds such a write's transaction: declared within
|
|
92
|
+
* `MULTI_ROW_WRITE_ROWS_PER_TRANSACTION`, beside `hookTransactionPosture: RUNS_INSIDE_TRANSACTION`, the write is made
|
|
93
|
+
* transactional and its audit row is kept through a crash. Declare it only when the handler cannot write more by
|
|
94
|
+
* construction (a single-row update by a unique key, a page it bounds itself), and say why at the declaration.
|
|
95
|
+
*
|
|
96
|
+
* Refused unless it is a positive integer within the bound, and on a registration that does not REPLACE the core write
|
|
97
|
+
* (the framework's own write is bounded by chunking instead, and a bound on a hook that does not write would bound nothing).
|
|
98
|
+
*/
|
|
99
|
+
export function assertValidResourceCustomImplementationMaximumRowsWrittenPerAttempt(params) {
|
|
100
|
+
if (params.maximumRowsWrittenPerAttempt === undefined)
|
|
101
|
+
return;
|
|
102
|
+
const label = params.debugLabel ?? params.operationPathKey;
|
|
103
|
+
const value = params.maximumRowsWrittenPerAttempt;
|
|
104
|
+
if (typeof value !== 'number' || !Number.isInteger(value) || value < 1 || value > params.rowsPerTransactionBound) {
|
|
105
|
+
throw new Error(`[CustomImpl] Invalid maximumRowsWrittenPerAttempt for registration "${label}" (${params.operationPathKey}): ${String(value)} is not a positive integer within ${params.rowsPerTransactionBound}`);
|
|
106
|
+
}
|
|
107
|
+
if (!params.modes.includes(ResourceOperation_CustomServiceImplementationMode.REPLACE_CORE_OPERARTIONS)) {
|
|
108
|
+
throw new Error(`[CustomImpl] Invalid maximumRowsWrittenPerAttempt for registration "${label}" (${params.operationPathKey}): only a REPLACE handler performs the write it would bound`);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
88
111
|
/**
|
|
89
112
|
* Fails before registration when `ownsOperationAuditRecord` cannot mean anything: a value other than `true`, or a
|
|
90
113
|
* registration with no `overrideAll` handler (the framework pipeline records the row for every other mode).
|
|
@@ -233,7 +256,7 @@ export function assertValidResourceCustomImplementationTransactionalCoreConfigur
|
|
|
233
256
|
}
|
|
234
257
|
}
|
|
235
258
|
export function createResourceCustomServiceImplementation(params) {
|
|
236
|
-
const { reconcileScheduled, authorizeTarget, operationPath, requestDtoSchema, responseDtoSchema, handlers = {}, priority, modeOverrides, debugLabel, authoritativeFields, postCommitEffectOwnership, ownsOperationAuditRecord, coreWritePrecondition, coreWritePinsRowVersion, hookTransactionPosture, transactionalCore, transactionParticipants, transactionalCoreConflictResolver, transactionalCoreCommitOutcomeResolver, } = params;
|
|
259
|
+
const { reconcileScheduled, authorizeTarget, operationPath, requestDtoSchema, responseDtoSchema, handlers = {}, priority, modeOverrides, debugLabel, authoritativeFields, postCommitEffectOwnership, ownsOperationAuditRecord, coreWritePrecondition, coreWritePinsRowVersion, hookTransactionPosture, maximumRowsWrittenPerAttempt, transactionalCore, transactionParticipants, transactionalCoreConflictResolver, transactionalCoreCommitOutcomeResolver, } = params;
|
|
237
260
|
const getModeSchema = (mode, inputOrOutput) => {
|
|
238
261
|
if (inputOrOutput === 'input') {
|
|
239
262
|
if (!requestDtoSchema) {
|
|
@@ -407,6 +430,7 @@ export function createResourceCustomServiceImplementation(params) {
|
|
|
407
430
|
...(coreWritePrecondition ? { coreWritePrecondition: freezeCoreWritePrecondition(coreWritePrecondition, key, normalizedDebugLabel, implementation.getPlaceholders()) } : {}),
|
|
408
431
|
...(coreWritePinsRowVersion ? { coreWritePinsRowVersion: assertCoreWriteRuns(key, normalizedDebugLabel, implementation.getPlaceholders()) } : {}),
|
|
409
432
|
...(hookTransactionPosture !== undefined ? { hookTransactionPosture } : {}),
|
|
433
|
+
...(maximumRowsWrittenPerAttempt !== undefined ? { maximumRowsWrittenPerAttempt } : {}),
|
|
410
434
|
...transactionalCoreConfiguration,
|
|
411
435
|
};
|
|
412
436
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resource-operation-custom-implementation.factory.backend.js","sourceRoot":"","sources":["../../../../../src/base-classes/services/services/resource-operation-custom-implementation.factory.backend.ts"],"names":[],"mappings":"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","sourcesContent":["import { DataMode, ErrorCustomMessageReference, ErrorType, type ResourceConfiguration_Operation, ResourceConfiguration_OperationPath, ResourceOperation_CustomServiceImplementationMode, ResourceOperation_PostCommitEffectOwnership, ResourcesConfig_OperationPathUtils, ResourcesConfigOperationsDtosBuilderUtils, jsonParsingSchemaOf } from '@wildo-ai/saas-models';\nimport { z } from 'zod';\nimport type { Container } from 'inversify';\nimport type { AdmissionWritePrecondition } from '~wildo-backend-lib/base-classes/utils/admission-write-precondition.backend.utils';\nimport type { ExecutionContext } from '~wildo-backend-lib/runtime/models/execution-context.backend.schemas';\nimport { parseResourceOperation_CustomServiceImplementationSchema, ResourceOperation_CustomImplementation_Utils, ResourceOperationBeforeTransactionalCoreResult, ResourceOperationCustomImplementation_InputTypeOf, ResourceOperationCustomImplementation_OutputTypeOf, ResourceOperationCustomImplementationBase } from './resource-operation-custom-implementation-base.backend.service';\nimport { ResourcesRegistryBackendService } from '~wildo-backend-lib/resources/services/resources-registry.backend.service';\nimport type { ModeOverrideConfig } from './resource-operation-custom-implementation-registry.backend.service';\nimport type { ScheduledAttemptContext, ScheduledReconciliationResult } from '@wildo-ai/saas-models';\n\n/**\n * Reconciles the effects of the entire scheduled operation after an unknown outcome.\n * Declare once per exact operation path. Capture application dependencies in the\n * enclosing implementation factory, just as for its normal execution handlers.\n * This callback must inspect durable evidence; it must not execute the operation again.\n */\nexport type ResourceScheduledReconciler = (\n input: unknown,\n executionContext: ExecutionContext<any>,\n scheduledAttempt: ScheduledAttemptContext,\n) => Promise<ScheduledReconciliationResult>;\n\n\n\ntype AnyHandlerType<\n TMode extends ResourceOperation_CustomServiceImplementationMode,\n TInput extends z.ZodSchema | undefined = z.ZodAny | undefined,\n TOutput extends z.ZodSchema = z.ZodAny,\n TAugment extends object|undefined = undefined\n> =\n (\n _id: string | undefined,\n input: ResourceOperationCustomImplementation_InputTypeOf<TMode, TInput, TOutput, TAugment>,\n executionContext: ExecutionContext<any>,\n operationPath: ResourceConfiguration_OperationPath<any, any>,\n utils: ResourceOperation_CustomImplementation_Utils\n ) =>\n Promise<ResourceOperationCustomImplementation_OutputTypeOf<TMode, TInput, TOutput, TAugment>>;\n\ntype AllHandlersType<\n TInput extends z.ZodSchema | undefined = z.ZodAny | undefined,\n TOutput extends z.ZodSchema = z.ZodAny,\n> = Partial<{\n overrideAll :\n (\n _id: string | undefined,\n input: ResourceOperationCustomImplementation_InputTypeOf<ResourceOperation_CustomServiceImplementationMode.OVERRIDE_ALL, TInput, TOutput>,\n executionContext: ExecutionContext<any>,\n operationPath: ResourceConfiguration_OperationPath<any, any>,\n utils: ResourceOperation_CustomImplementation_Utils\n ) =>\n Promise<ResourceOperationCustomImplementation_OutputTypeOf<ResourceOperation_CustomServiceImplementationMode.OVERRIDE_ALL, TInput, TOutput>>;\n\n /** @wildo_source:part:start saas.backend.custom-operation.transactional-core facet:layer:backend facet:family:resource-operation */\n /**\n * Runs OUTSIDE any database transaction, after preflight and before the transactional core (#535). The phase for an\n * external effect whose outcome feeds the core write. Requires `transactionalCore: true`; exactly one registration\n * may declare it. Handler signature: `(id, input, executionContext, operationPath, utils)`, where `input` is parsed\n * by the operation's request DTO and the answer is a `ResourceOperationBeforeTransactionalCoreResult`.\n */\n beforeTransactionalCore :\n (\n _id: string | undefined,\n input: ResourceOperationCustomImplementation_InputTypeOf<ResourceOperation_CustomServiceImplementationMode.BEFORE_TRANSACTIONAL_CORE, TInput, TOutput>,\n executionContext: ExecutionContext<any>,\n operationPath: ResourceConfiguration_OperationPath<any, any>,\n utils: ResourceOperation_CustomImplementation_Utils\n ) =>\n Promise<ResourceOperationBeforeTransactionalCoreResult>;\n /** @wildo_source:part:end saas.backend.custom-operation.transactional-core */\n\n prefixCoreOperations :\n <TAugment extends object|undefined = undefined>\n (\n _id: string | undefined,\n input: ResourceOperationCustomImplementation_InputTypeOf<ResourceOperation_CustomServiceImplementationMode.PREFIX_CORE_OPERARTIONS, TInput, TOutput, TAugment>,\n executionContext: ExecutionContext<any>,\n operationPath: ResourceConfiguration_OperationPath<any, any>,\n utils: ResourceOperation_CustomImplementation_Utils\n ) =>\n Promise<ResourceOperationCustomImplementation_OutputTypeOf<ResourceOperation_CustomServiceImplementationMode.PREFIX_CORE_OPERARTIONS, TInput, TOutput, TAugment>>;\n\n replaceCoreOperations :\n <TAugment extends object|undefined = undefined>(\n _id: string | undefined,\n input: ResourceOperationCustomImplementation_InputTypeOf<ResourceOperation_CustomServiceImplementationMode.REPLACE_CORE_OPERARTIONS, TInput, TOutput, TAugment>,\n executionContext: ExecutionContext<any>,\n operationPath: ResourceConfiguration_OperationPath<any, any>,\n utils: ResourceOperation_CustomImplementation_Utils\n ) => Promise<ResourceOperationCustomImplementation_OutputTypeOf<ResourceOperation_CustomServiceImplementationMode.REPLACE_CORE_OPERARTIONS, TInput, TOutput, TAugment>>;\n\n postfixCoreOperations :\n (\n _id: string | undefined,\n input: ResourceOperationCustomImplementation_InputTypeOf<ResourceOperation_CustomServiceImplementationMode.POSTFIX_CORE_OPERARTIONS, TInput, TOutput>,\n executionContext: ExecutionContext<any>,\n operationPath: ResourceConfiguration_OperationPath<any, any>,\n utils: ResourceOperation_CustomImplementation_Utils\n ) =>\n Promise<ResourceOperationCustomImplementation_OutputTypeOf<ResourceOperation_CustomServiceImplementationMode.POSTFIX_CORE_OPERARTIONS, TInput, TOutput>>;\n\n afterUserNotifications :\n (\n _id: string | undefined,\n input: ResourceOperationCustomImplementation_InputTypeOf<ResourceOperation_CustomServiceImplementationMode.AFTER_USER_NOTIFICATIONS, TInput, TOutput>,\n executionContext: ExecutionContext<any>,\n operationPath: ResourceConfiguration_OperationPath<any, any>,\n utils: ResourceOperation_CustomImplementation_Utils\n ) =>\n Promise<ResourceOperationCustomImplementation_OutputTypeOf<ResourceOperation_CustomServiceImplementationMode.AFTER_USER_NOTIFICATIONS, TInput, TOutput>>;\n\n atTheEnd :\n (\n _id: string | undefined,\n input: ResourceOperationCustomImplementation_InputTypeOf<ResourceOperation_CustomServiceImplementationMode.AT_THE_END, TInput, TOutput>,\n executionContext: ExecutionContext<any>,\n operationPath: ResourceConfiguration_OperationPath<any, any>,\n utils: ResourceOperation_CustomImplementation_Utils\n ) =>\n Promise<ResourceOperationCustomImplementation_OutputTypeOf<ResourceOperation_CustomServiceImplementationMode.AT_THE_END, TInput, TOutput>>;\n}>\n\n/** @wildo_source:part:start saas.backend.custom-operation.transactional-core facet:layer:backend facet:family:resource-operation */\n\n/**\n * Explicit outcome of a conflict resolver invoked after the owned transaction\n * has aborted.\n *\n * `RECONCILED` returns an already-committed semantic winner.\n * `RETRY_TRANSACTION` requests the framework's single bounded retry of the\n * complete transaction boundary.\n * `UNHANDLED` preserves the original conflict without spending that retry.\n */\nexport enum ResourceCustomServiceImplementationTransactionalCoreConflictAction {\n RECONCILED = 'reconciled',\n RETRY_TRANSACTION = 'retry_transaction',\n UNHANDLED = 'unhandled',\n}\n\nexport type ResourceCustomServiceImplementationTransactionalCoreConflictResolution =\n | {\n action: ResourceCustomServiceImplementationTransactionalCoreConflictAction.RECONCILED;\n /** Already-committed operation result that is equivalent to this request. */\n value: unknown;\n }\n | {\n action: ResourceCustomServiceImplementationTransactionalCoreConflictAction.RETRY_TRANSACTION;\n }\n | {\n action: ResourceCustomServiceImplementationTransactionalCoreConflictAction.UNHANDLED;\n };\n\nexport type ResourceCustomServiceImplementationTransactionalCoreConflictResolver = (\n error: unknown,\n input: unknown,\n executionContext: ExecutionContext<any>,\n utils: ResourceOperation_CustomImplementation_Utils,\n) => Promise<ResourceCustomServiceImplementationTransactionalCoreConflictResolution>;\n\n/**\n * What reading back an owned transaction whose COMMIT threw found (#2820). The attempt's work all resolved and the\n * transaction then failed: the commit may have landed and lost its reply, so the error alone says nothing about whether\n * the operation happened.\n */\nexport enum ResourceCustomServiceImplementationTransactionalCoreCommitOutcome {\n /** The operation's writes are in the store: the request succeeded, and its caller is answered with `value`. */\n LANDED = 'landed',\n /** The read found the writes absent: the transaction did not commit, and the caller gets the commit's error. */\n NOT_LANDED = 'not_landed',\n /** Nothing could be read: the caller gets `refusal`, which must not say the operation failed (it may have happened). */\n UNKNOWN = 'unknown',\n /**\n * This resolver does not judge this attempt (it reads back only some of the shapes its operation writes). The next\n * resolver is asked; when none settles it, the caller gets the commit's error, as without a resolver.\n */\n UNHANDLED = 'unhandled',\n}\n\nexport type ResourceCustomServiceImplementationTransactionalCoreCommitOutcomeResolution =\n | {\n outcome: ResourceCustomServiceImplementationTransactionalCoreCommitOutcome.LANDED;\n /** The committed core state as read back: what the operation answers, as if its commit had answered. */\n value: unknown;\n /**\n * Keys of post-commit effects THIS implementation registered whose premise the read-back disproved (an approval\n * announced as waiting that was answered before the read-back): the framework drops them instead of running them.\n * Every other effect the attempt registered runs. Omit it when the stored state still bears out every effect.\n */\n withheldPostCommitEffectKeys?: readonly string[];\n }\n | {\n outcome: ResourceCustomServiceImplementationTransactionalCoreCommitOutcome.NOT_LANDED;\n }\n | {\n outcome: ResourceCustomServiceImplementationTransactionalCoreCommitOutcome.UNKNOWN;\n /** The error thrown to the caller instead of the commit's: a stable, client-branchable refusal saying it may have happened. */\n refusal: unknown;\n }\n | {\n outcome: ResourceCustomServiceImplementationTransactionalCoreCommitOutcome.UNHANDLED;\n };\n\n/**\n * The commit receipt the framework wrote inside an attempt's transaction (#2870): a row whose id only that attempt holds,\n * so it is stored if and only if the attempt committed. Present only for an operation whose commit-outcome resolver reads\n * one (its resolver was built with `createTransactionalCoreDeleteReadBack`).\n */\nexport interface ResourceCustomServiceImplementationTransactionalCoreCommitReceipt {\n /** The id the framework minted for this attempt. For the log; the receipt is read through {@link isStored}. */\n readonly id: string;\n /**\n * Whether the receipt is stored, read outside the failed transaction. `true` proves the attempt committed. Throws when\n * the store cannot answer, and only then is the read worth retrying.\n */\n readonly isStored: () => Promise<boolean>;\n}\n\n/** The attempt whose work resolved before its commit threw (#2820): what the resolver reads back by. */\nexport interface ResourceCustomServiceImplementationTransactionalCoreCommittedAttempt {\n /** The input after PREFIX: what the attempt minted (an id, a decision ref) is here. */\n readonly input: unknown;\n /** The core state the attempt produced, as its writes returned it inside the transaction. */\n readonly state: unknown;\n /** The attempt's commit receipt (#2870), when its operation's resolver reads one. */\n readonly commitReceipt?: ResourceCustomServiceImplementationTransactionalCoreCommitReceipt;\n}\n\n/**\n * Invoked when an owned transaction's work resolved and its commit then threw (#2820), so the operation may have happened\n * with its caller about to be told it failed. The resolver reads the store back (outside the failed transaction) by\n * something only this attempt wrote (an id it minted, a timestamp it stamped), never by a guess, and answers LANDED,\n * NOT_LANDED or UNKNOWN.\n *\n * On LANDED the framework answers the caller with `value` and runs, once, every post-commit effect the attempt\n * registered on the transaction whose commit threw (#2825): the operation's framework work (audit row, notifications),\n * the implementation's own effects, and those of every nested operation it called. The resolver records nothing itself;\n * it only withholds an effect of its own whose premise the read-back disproved (`withheldPostCommitEffectKeys`).\n *\n * On UNKNOWN its `refusal` is thrown: a 409 with a stable, client-branchable `code` saying the operation may have taken\n * effect. `ResourceOperationOutcomeErrorCode.OUTCOME_UNKNOWN` is the general one; a request that RAISES a human decision\n * uses `HumanDecisionRequestErrorCode.REQUEST_OUTCOME_UNKNOWN`. The attempt's registered effects are then dropped for\n * good (nothing knows whether their writes exist), and a retry is usually refused as already done when the commit did\n * land: the caller is meant to look at the record, not to repeat the act. Only a repair the operation owns (the decision\n * planes' request repairs) records them later.\n *\n * Most operations write one row they can be read back by, and build the resolver with\n * `createTransactionalCoreCommitReadBack` (from `@wildo-ai/saas-backend-lib`): `carriesAttemptCreatedRow` for a CREATE (the\n * id the attempt's write produced), `carriesAttemptUpdateStamp` for an UPDATE (the `updatedAt` its write stamped). It\n * reads up to four times over about 4 s and refuses UNKNOWN with the general code. `readBackTransactionalCoreCommit` is the\n * lower-level loop for a read-back of another shape.\n *\n * A DELETE leaves nothing only it wrote: the row's absence is also what another remover leaves. Build its resolver with\n * `createTransactionalCoreDeleteReadBack` (#2870). The framework then writes a commit receipt inside each attempt's\n * transaction, under an id only that attempt holds, and the read-back answers LANDED only when that receipt is stored.\n * When it is not, a row still stored is NOT_LANDED, and a row that is gone is UNKNOWN: never taken for this attempt's work.\n *\n * @example\n * createResourceCustomServiceImplementation({\n * operationPath,\n * transactionalCore: true,\n * transactionParticipants: {},\n * handlers: { prefixCoreOperations, postfixCoreOperations },\n * // A repeat of this verb is refused once it has happened, so a lost commit reply is read back by the row's stamp.\n * transactionalCoreCommitOutcomeResolver: createTransactionalCoreCommitReadBack({\n * reason: 'invoice_approval_outcome_unknown',\n * read: (prepared, _executionContext, utils) => utils.systemAccessService!.readAsSystem(INVOICES, { _id: String(prepared._id) }),\n * carriesThisAttempt: carriesAttemptUpdateStamp,\n * }),\n * });\n */\nexport type ResourceCustomServiceImplementationTransactionalCoreCommitOutcomeResolver = (\n error: unknown,\n attempt: ResourceCustomServiceImplementationTransactionalCoreCommittedAttempt,\n executionContext: ExecutionContext<any>,\n utils: ResourceOperation_CustomImplementation_Utils,\n) => Promise<ResourceCustomServiceImplementationTransactionalCoreCommitOutcomeResolution>;\n\n/**\n * Transaction ownership options for one custom-implementation registration.\n *\n * Import this surface from `@wildo-ai/saas-backend-lib` through\n * `createResourceCustomServiceImplementation`. When `transactionalCore` is\n * enabled, PREFIX, core persistence, REPLACE, and POSTFIX execute atomically.\n * The framework includes the operation resource automatically; authors must\n * name every additional resource touched by those phases and forward\n * `utils.serviceOptions` to every nested resource call. Startup validates the\n * declared participant set; it cannot discover an omitted call or make a call\n * that drops `serviceOptions` join the transaction. Use an explicit empty\n * object only for a genuinely single-resource transaction.\n *\n * @example\n * createResourceCustomServiceImplementation({\n * operationPath,\n * transactionalCore: true,\n * transactionParticipants: {\n * owner: CoreResourceType.USERS,\n * organization: CoreResourceType.ORGANIZATIONS,\n * },\n * handlers: { prefixCoreOperations },\n * });\n *\n * The discriminated shape prevents authored TypeScript registrations from\n * attaching a conflict resolver to a pipeline that does not own the core\n * transaction. The registry repeats this check at runtime because factories\n * may arrive through JavaScript, stale compiled output, or type erasure.\n */\nexport type ResourceCustomServiceImplementationTransactionalCoreConfiguration =\n | {\n /**\n * Runs PREFIX → core repository mutation → REPLACE → POSTFIX in one\n * declared resource persistence transaction. The operation resource is\n * included automatically; every additional resource accessed by these\n * phases must be named in `transactionParticipants`, and every nested\n * resource call must receive `utils.serviceOptions`.\n *\n * This is an explicit authoring contract, not dynamic access discovery:\n * startup proves adapter compatibility for the declared set, but cannot\n * detect an omitted participant or a call that discards the transaction.\n *\n * `OVERRIDE_ALL` is incompatible because it replaces and exits the\n * pipeline before this boundary.\n */\n transactionalCore: true;\n /**\n * Additional resource participants touched inside the atomic core phase,\n * keyed by their semantic role at this boundary.\n *\n * An explicit empty object is required for a true single-resource\n * transaction. This makes the absence of extra participants an authored\n * decision instead of an accidental omission hidden behind a boolean.\n * Calls to these resources must forward `utils.serviceOptions`; naming a\n * participant alone does not implicitly propagate the transaction.\n */\n transactionParticipants: Readonly<Record<string, string>>;\n /**\n * Optional idempotency resolver invoked outside an aborted transaction\n * after a transactional-core conflict. The resolver must explicitly\n * reconcile a committed winner, request the one bounded full-transaction\n * retry, or leave the original conflict unhandled.\n */\n transactionalCoreConflictResolver?: ResourceCustomServiceImplementationTransactionalCoreConflictResolver;\n /**\n * Optional read-back invoked when the transaction's work resolved and its COMMIT then threw (#2820): it decides\n * whether the caller is told the operation succeeded, failed, or may have happened. See\n * {@link ResourceCustomServiceImplementationTransactionalCoreCommitOutcomeResolver}.\n */\n transactionalCoreCommitOutcomeResolver?: ResourceCustomServiceImplementationTransactionalCoreCommitOutcomeResolver;\n }\n | {\n /** Default non-transactional custom-implementation behavior. */\n transactionalCore?: false;\n /** Participant declarations only have meaning for an owned transaction. */\n transactionParticipants?: never;\n /** A conflict resolver has no valid invocation boundary without the transaction. */\n transactionalCoreConflictResolver?: never;\n /** Nor has a commit-outcome resolver: without an owned transaction there is no commit of its own to read back. */\n transactionalCoreCommitOutcomeResolver?: never;\n };\n/** @wildo_source:part:end saas.backend.custom-operation.transactional-core */\n\n/**\n * @wildo_source:part:start saas.backend.custom-operation.authoritative-fields facet:layer:backend facet:family:custom-implementation\n *\n * Fields whose value this implementation's `prefixCoreOperations` hook OWNS.\n *\n * ## Why this exists\n *\n * A prefix that authors a server-owned field (one marked `.excludeFromCreate()` /\n * `.excludeFromUpdate()`) relies on `preserveServerInjectedFields` to carry that value past the\n * repository's strict `requestDto` re-parse. So does a prefix that sets a value BELOW a field: the\n * request contract strips an `.isBackendOnly()` field at every depth, so the re-parse of the\n * containing field drops what the prefix put there. Declare the TOP-LEVEL field that contains it\n * (an SSO connection's prefix parses `saml.x509Certificates` from a PEM, and declares `saml`). That allow-list is normally derived by diffing the\n * prefix output against a snapshot of the payload keys taken BEFORE the prefix ran, so only keys\n * the hook *introduced* are preserved — which is what stops a client smuggling a value into a\n * field it may not write.\n *\n * That inference has a hole: the snapshot is taken at the SERVICE tier, after a LOOSE parse\n * (`z.looseObject`) that passes unknown keys through. A caller that reaches the service tier with\n * the field already present — MCP `callTool` forwards its arguments with no strict parse — puts\n * the key into the snapshot. The prefix's own value is then not classified as introduced, the\n * repository strips it, and the operation answers success having written nothing.\n *\n * Declaring the field here makes the authorship EXPLICIT instead of inferred: the value is always\n * preserved, and it is always the POST-prefix value, so a caller-supplied value is overwritten\n * rather than honored. Reachability of the field by a client is unchanged — that remains governed\n * by the operation's `requestDto` and the schema decorators.\n *\n * ## Why not \"preserve any field whose value the prefix changed\"\n *\n * Rejected as unsafe. `preserveServerInjectedFields` copies the post-prefix value, and a\n * pass-through prefix (`return input` — the idiom used by guard hooks that only validate) which\n * rebuilt an object-valued field would produce a reference change with identical content. That\n * would allow-list a field the caller supplied and the hook never intended to endorse. Primitives\n * compare safely by value, object graphs do not, and making the guarantee depend on how each hook\n * happens to construct its return value is exactly the implicit rule this contract removes.\n *\n * @example\n * createResourceCustomServiceImplementation({\n * operationPath: { resourceIdentifier: CoreResourceType.ORGANIZATIONS, operationIdentifier: 'suspend', ... },\n * // `status` is `.excludeFromUpdate()`; this operation is the authority that sets it.\n * authoritativeFields: ['status'],\n * handlers: { prefixCoreOperations: async () => ({ status: OrganizationStatus.SUSPENDED }) },\n * });\n */\nexport type ResourceCustomServiceImplementationAuthoritativeFields = readonly string[];\n/** @wildo_source:part:end saas.backend.custom-operation.authoritative-fields */\n\n/** @wildo_source:part:start saas.backend.custom-operation.target-authority facet:layer:backend facet:family:custom-implementation */\n/**\n * WHO may act on THIS row: a read-only check that refuses (AUTHORIZATION, 403) when the caller may not act on the\n * operation's single target. The pipeline runs it with the other gates that depend on who is asking, after the target is\n * read and before every refusal that reads the row's state (a RESTRICT dependent, a legal hold) and before every hook.\n *\n * Why it is not a hook: every gate that depends on who is asking runs before a refusal that reads state, so a caller who\n * may not act on a row is told that, never what state the row is in. A check about the ROW's relation to the caller is\n * such a gate, and no hook runs early enough for it. Since a DELETE refuses on its target before any hook (#2582 review\n * F2), a held row answered a caller outside its authority with 409 and the hold's legal grounds before the hook that\n * would have answered 403 (#2582 review R2).\n *\n * Only an operation addressed to ONE row has a target to judge. Declared on an operation called any other way (a bulk\n * selection of several rows, a filter, a create), the call is refused (AUTHORIZATION): a check that cannot run would\n * otherwise admit everyone it exists to refuse. A bulk selection of exactly one row is judged on that row. It must not\n * write: it runs outside any transaction, and a refusal after it must leave nothing behind.\n */\nexport type ResourceCustomServiceImplementationTargetAuthority = (\n target: Record<string, unknown>,\n executionContext: ExecutionContext<any>,\n utils: ResourceOperation_CustomImplementation_Utils,\n) => Promise<void>;\n/** @wildo_source:part:end saas.backend.custom-operation.target-authority */\n\ntype ResourceCustomServiceImplementationFactoryResultBase = {\n reconcileScheduled?: ResourceScheduledReconciler;\n /** Who may act on the operation's single target. See {@link ResourceCustomServiceImplementationTargetAuthority}. */\n authorizeTarget?: ResourceCustomServiceImplementationTargetAuthority;\n operationPathKey: string;\n implementation: ResourceOperationCustomImplementationBase;\n /** Lower number = higher priority. Default: 100. */\n priority?: number;\n /** Per-mode override configuration. Default: all modes are chainable. */\n modeOverrides?: ModeOverrideConfig;\n /** Human-readable label for debug logging. Fallback: `{operationPathKey}@{priority}`. */\n debugLabel?: string;\n /** Fields whose value this implementation's PREFIX hook owns. See the type's documentation. */\n authoritativeFields?: ResourceCustomServiceImplementationAuthoritativeFields;\n /** Who delivers the occurrence's audit row and notifications. Default `FRAMEWORK`. See {@link ResourceOperation_PostCommitEffectOwnership}. */\n postCommitEffectOwnership?: ResourceOperation_PostCommitEffectOwnership;\n /** This `overrideAll` writes its own `RESOURCE_OPERATION_PERFORMED` row. See {@link ResourceCustomServiceImplementationOwnsOperationAuditRecord}. */\n ownsOperationAuditRecord?: ResourceCustomServiceImplementationOwnsOperationAuditRecord;\n /** @wildo_source:part:start saas.backend.custom-operation.core-write-precondition facet:layer:backend facet:family:custom-implementation facet:audience:app-developer */\n /**\n * What the row must still hold for the CORE write to land, per field (`{ status: ['ACTIVE'] }`). Folded into the single\n * statement that writes, beside what the operation's `enabledCondition` read, so a concurrent writer that moved the row\n * since the prefix judged it makes this write match nothing, and the caller gets 409 `version_conflict`.\n * Declare it when the PREFIX judges the row's state (a status transition's starting states): it holds on every path the\n * registration runs on, including one no `enabledCondition` guards. On a bulk variant it holds for every selected row,\n * and one row that no longer does refuses the whole selection.\n *\n * It holds for every caller of the registration, and `updateAsSystem` resolves the operation's default. So when the system\n * must still write a row a person may not (bookkeeping on a closed record), declare an `INTERNAL_CALL` default beside the\n * `API_CALL` one and register this on the route: the service tier prefers an internal default, so the system door reaches\n * neither the hook nor the fence, while a route, an MCP tool, a function tool and a chat command dispatch by path. What the\n * route declares (`referenceConstraints`, its request) stays the route's: the internal variant declares none of it.\n * The doors that resolve the default reach the internal variant whoever's context they carry, so on such a resource none of\n * them may run a person's write: an in-process `servicesRegistry.update()` (use `doByOperationPath`), a declared flow's\n * `update` step, and a nested `childOperations` mutation. An inbound channel's `ctx.resources.update` is refused there.\n */\n coreWritePrecondition?: AdmissionWritePrecondition;\n /**\n * The core write lands only on the row at the version the hooks read. Declare it when the PREFIX computes the write from\n * the row and no field states what it judged: it rewrites a whole array (`domains[]`), which a field pin cannot guard.\n * A concurrent writer of ANY field then refuses this write with 409 `version_conflict`, so prefer\n * `coreWritePrecondition` wherever a field does state it. Beside it, not instead: a guarded mutation moves a field without\n * advancing the version. Refused on an OVERRIDE_ALL implementation, which runs no core write.\n */\n coreWritePinsRowVersion?: true;\n /** @wildo_source:part:end saas.backend.custom-operation.core-write-precondition */\n /** Whether this registration's hooks may run inside the transaction that keeps the operation's audit row. See {@link ResourceCustomServiceImplementationHookTransactionPosture}. */\n hookTransactionPosture?: ResourceCustomServiceImplementationHookTransactionPosture;\n};\n\n/** @wildo_source:part:start saas.backend.custom-operation.hook-transaction-posture facet:layer:backend facet:family:custom-implementation facet:audience:app-developer */\n/**\n * Whether a registration's hooks (PREFIX, REPLACE, POSTFIX) may run inside a database transaction the framework opens\n * around the operation, so that the operation's audit row is kept through a crash (#2297).\n *\n * An audited write whose operation is not transactional for another reason writes its `RESOURCE_OPERATION_PERFORMED` row\n * after the commit, best effort: a process that dies in between loses it. The framework closes that gap by running the\n * write in a transaction whose post-commit effects are captured, so the row is kept in the outbox and written later.\n * Running a write in a transaction runs its hooks there too, and that changes what a hook may do, so the framework does it\n * only for a registration that says its hooks were reviewed for it. Undeclared, the write stays best effort.\n *\n * Inside the transaction a hook runs before the commit, possibly twice (the store may retry the transaction once), and on\n * PostgreSQL the operation's own row is locked from the start. So a hook that RUNS_INSIDE_TRANSACTION:\n * - reads and writes the operation's own row, and any row the core write creates or changes, only with\n * `utils.serviceOptions` (another connection would wait on the row lock, or not see the uncommitted row);\n * - makes no effect outside the database before the commit: a provider call, an email, a queue publish, a cache or Redis\n * write, an audit row. Such an effect is registered as a post-commit effect instead\n * (`registerTransactionPostCommitEffect(utils.serviceOptions.transaction, …)`, or `emitAuthorityChangeAuditWhenDurable`\n * for an authority-change audit row), where it runs once, after the commit, and never for a rolled-back attempt. A\n * refusal's own audit row (written just before the hook throws) may stay where it is: nothing commits after it.\n *\n * STAYS_OUTSIDE_TRANSACTION records the opposite review: a hook must run outside any transaction (its answer depends on a\n * provider call, or on an audit row that has to exist before the operation answers), so the write stays best effort,\n * reported under its own reason rather than as unreviewed. Say why at the declaration.\n *\n * A registration with `transactionalCore: true` already runs its hooks in a transaction and needs neither. Refused beside an\n * `overrideAll` handler, which replaces the pipeline whose transaction this is about.\n */\nexport enum ResourceCustomServiceImplementationHookTransactionPosture {\n RUNS_INSIDE_TRANSACTION = 'runs_inside_transaction',\n STAYS_OUTSIDE_TRANSACTION = 'stays_outside_transaction',\n}\n/** @wildo_source:part:end saas.backend.custom-operation.hook-transaction-posture */\n\n/**\n * Fails before registration when `hookTransactionPosture` cannot mean anything (#2297): a value outside the vocabulary, or\n * one declared beside an `overrideAll` handler, which runs no framework pipeline and so no framework transaction.\n */\nexport function assertValidResourceCustomImplementationHookTransactionPosture(params: {\n operationPathKey: string;\n debugLabel?: string;\n modes: readonly ResourceOperation_CustomServiceImplementationMode[];\n hookTransactionPosture: unknown;\n}): void {\n if (params.hookTransactionPosture === undefined) return;\n const label = params.debugLabel ?? params.operationPathKey;\n if (!(Object.values(ResourceCustomServiceImplementationHookTransactionPosture) as unknown[]).includes(params.hookTransactionPosture)) {\n throw new Error(`[CustomImpl] Invalid hookTransactionPosture for registration \"${label}\" (${params.operationPathKey}): ${String(params.hookTransactionPosture)}`);\n }\n if (params.modes.includes(ResourceOperation_CustomServiceImplementationMode.OVERRIDE_ALL)) {\n throw new Error(`[CustomImpl] Invalid hookTransactionPosture for registration \"${label}\" (${params.operationPathKey}): an OVERRIDE_ALL implementation runs no framework pipeline, so no framework transaction`);\n }\n}\n\n/**\n * Declares that an `overrideAll` handler records the operation's `RESOURCE_OPERATION_PERFORMED` row itself, so the\n * framework does not record a second one (#3151).\n *\n * An `overrideAll` replaces the framework pipeline, but not its audit duty: once the handler returns, the framework\n * records the row from the operation's declared risk (the same decision every other write takes), with the pre-image it\n * read, the request input, and the handler's response as the post-state. Before #3151 nothing did, so every HIGH or\n * CRITICAL verb written `overrideAll` left no row unless its author remembered to write one, which the risk floor exists\n * to make unnecessary (Wonder Ledger's close lifecycle verbs left none).\n *\n * Declare it only when the handler records a row the framework could not: the feature-administration writers record the\n * persisted overrides before and after, which the framework never sees, and a MEDIUM `enable` below the floor. Only\n * `true` is meaningful, and only beside an `overrideAll` handler: every other mode runs inside the framework pipeline,\n * whose row cannot be declined this way.\n */\nexport type ResourceCustomServiceImplementationOwnsOperationAuditRecord = true;\n\n/**\n * Fails before registration when `ownsOperationAuditRecord` cannot mean anything: a value other than `true`, or a\n * registration with no `overrideAll` handler (the framework pipeline records the row for every other mode).\n */\nexport function assertValidResourceCustomImplementationOperationAuditOwnership(params: {\n operationPathKey: string;\n debugLabel: string;\n modes: readonly ResourceOperation_CustomServiceImplementationMode[];\n ownsOperationAuditRecord: unknown;\n}): void {\n if (params.ownsOperationAuditRecord === undefined) return;\n if (params.ownsOperationAuditRecord !== true) {\n throw new Error(\n `[CustomImpl] Invalid ownsOperationAuditRecord for registration \"${params.debugLabel}\" `\n + `on operation \"${params.operationPathKey}\": only \\`true\\` may be declared.`,\n );\n }\n if (!params.modes.includes(ResourceOperation_CustomServiceImplementationMode.OVERRIDE_ALL)) {\n throw new Error(\n `[CustomImpl] Invalid ownsOperationAuditRecord for registration \"${params.debugLabel}\" `\n + `on operation \"${params.operationPathKey}\": only an overrideAll handler records its own operation audit row; `\n + 'every other mode runs inside the framework pipeline, which records it.',\n );\n }\n}\n\n/**\n * Fails before registration when a `postCommitEffectOwnership` declaration cannot be honoured.\n *\n * `IMPLEMENTATION_OUTBOX` tells the framework NOT to deliver the occurrence's audit row and notifications, on the\n * promise that the implementation enqueued them with the change. That promise is only true inside the operation's\n * transaction, so a registration that does not own the transactional core would suppress the effects with nothing\n * durable behind the suppression: a silent loss, which is the one outcome ownership exists to prevent.\n */\nexport function assertValidResourceCustomImplementationPostCommitEffectOwnership(params: {\n operationPathKey: string;\n debugLabel: string;\n transactionalCore: unknown;\n postCommitEffectOwnership: unknown;\n}): void {\n if (params.postCommitEffectOwnership === undefined) return;\n\n if (!Object.values(ResourceOperation_PostCommitEffectOwnership).includes(params.postCommitEffectOwnership as ResourceOperation_PostCommitEffectOwnership)) {\n throw new Error(\n `[CustomImpl] Invalid postCommitEffectOwnership for registration \"${params.debugLabel}\" `\n + `on operation \"${params.operationPathKey}\": must be a ResourceOperation_PostCommitEffectOwnership member.`,\n );\n }\n\n if (params.postCommitEffectOwnership === ResourceOperation_PostCommitEffectOwnership.IMPLEMENTATION_OUTBOX && params.transactionalCore !== true) {\n throw new Error(\n `[CustomImpl] Invalid postCommitEffectOwnership for registration \"${params.debugLabel}\" `\n + `on operation \"${params.operationPathKey}\": IMPLEMENTATION_OUTBOX requires transactionalCore=true, `\n + 'because the effects are only durable when they are enqueued in the transaction that commits the change.',\n );\n }\n}\n\n/**\n * Fails before registration when `authoritativeFields` cannot mean anything.\n *\n * The declaration only has an effect inside the PREFIX phase, so declaring it on an\n * implementation with no `prefixCoreOperations` handler is an authoring error that would\n * otherwise be silent — and silence is the exact failure mode this contract exists to remove.\n */\nexport function assertValidResourceCustomImplementationAuthoritativeFields(params: {\n operationPathKey: string;\n debugLabel: string;\n modes: readonly ResourceOperation_CustomServiceImplementationMode[];\n authoritativeFields: unknown;\n}): void {\n if (params.authoritativeFields === undefined) return;\n\n if (\n !Array.isArray(params.authoritativeFields)\n || params.authoritativeFields.length === 0\n || params.authoritativeFields.some((field) => typeof field !== 'string' || field.length === 0)\n ) {\n throw new Error(\n `[CustomImpl] Invalid authoritativeFields for registration \"${params.debugLabel}\" `\n + `on operation \"${params.operationPathKey}\": must be a non-empty array of non-empty field names.`,\n );\n }\n\n if (!params.modes.includes(ResourceOperation_CustomServiceImplementationMode.PREFIX_CORE_OPERARTIONS)) {\n throw new Error(\n `[CustomImpl] Invalid authoritativeFields for registration \"${params.debugLabel}\" `\n + `on operation \"${params.operationPathKey}\": the declaration only takes effect in the `\n + `PREFIX_CORE_OPERARTIONS phase, but this implementation declares no prefixCoreOperations handler.`,\n );\n }\n}\n\nexport type ResourceCustomServiceImplementationFactoryResult =\n ResourceCustomServiceImplementationFactoryResultBase\n & ResourceCustomServiceImplementationTransactionalCoreConfiguration;\n\n/**\n * Fails before registration/execution when transactional-core settings cannot\n * be honored by the custom implementation's declared modes.\n *\n * `OVERRIDE_ALL` replaces the whole operation pipeline and returns before the\n * framework reaches its core transaction. Treating that registration as\n * transactional would advertise an atomicity guarantee that can never exist.\n */\nexport function assertValidResourceCustomImplementationTransactionalCoreConfiguration(params: {\n operationPathKey: string;\n debugLabel: string;\n modes: readonly ResourceOperation_CustomServiceImplementationMode[];\n transactionalCore: unknown;\n transactionParticipants?: unknown;\n transactionalCoreConflictResolver?: unknown;\n transactionalCoreCommitOutcomeResolver?: unknown;\n}): void {\n if (typeof params.transactionalCore !== 'boolean') {\n throw new Error(\n `[CustomImpl] Invalid transactional-core configuration for registration \"${params.debugLabel}\" `\n + `on operation \"${params.operationPathKey}\": transactionalCore must be a boolean.`,\n );\n }\n\n const isPlainParticipantsRecord = (() => {\n if (\n params.transactionParticipants === null\n || typeof params.transactionParticipants !== 'object'\n || Array.isArray(params.transactionParticipants)\n ) {\n return false;\n }\n\n try {\n const prototype = Object.getPrototypeOf(params.transactionParticipants);\n return prototype === Object.prototype || prototype === null;\n } catch {\n return false;\n }\n })();\n\n if (\n params.transactionalCore\n && !isPlainParticipantsRecord\n ) {\n throw new Error(\n `[CustomImpl] Invalid transactional-core configuration for registration \"${params.debugLabel}\" `\n + `on operation \"${params.operationPathKey}\": transactionalCore=true requires an explicit `\n + 'plain-object transactionParticipants declaration (use {} for a single-resource transaction).',\n );\n }\n\n if (\n !params.transactionalCore\n && params.transactionParticipants !== undefined\n ) {\n throw new Error(\n `[CustomImpl] Invalid transactional-core configuration for registration \"${params.debugLabel}\" `\n + `on operation \"${params.operationPathKey}\": transactionParticipants requires `\n + 'transactionalCore=true.',\n );\n }\n\n if (\n isPlainParticipantsRecord\n && Object.entries(\n params.transactionParticipants as Readonly<Record<string, unknown>>,\n ).some(\n ([participantName, resourceType]) =>\n participantName.trim().length === 0\n || typeof resourceType !== 'string'\n || resourceType.trim().length === 0,\n )\n ) {\n throw new Error(\n `[CustomImpl] Invalid transactional-core configuration for registration \"${params.debugLabel}\" `\n + `on operation \"${params.operationPathKey}\": transactionParticipants must use `\n + 'non-empty semantic names and resource identifiers.',\n );\n }\n\n if (\n params.transactionalCoreConflictResolver !== undefined\n && typeof params.transactionalCoreConflictResolver !== 'function'\n ) {\n throw new Error(\n `[CustomImpl] Invalid transactional-core configuration for registration \"${params.debugLabel}\" `\n + `on operation \"${params.operationPathKey}\": transactionalCoreConflictResolver must be a function.`,\n );\n }\n\n if (\n params.transactionalCoreConflictResolver !== undefined\n && !params.transactionalCore\n ) {\n throw new Error(\n `[CustomImpl] Invalid transactional-core configuration for registration \"${params.debugLabel}\" `\n + `on operation \"${params.operationPathKey}\": transactionalCoreConflictResolver requires `\n + 'transactionalCore=true.',\n );\n }\n\n if (\n params.transactionalCoreCommitOutcomeResolver !== undefined\n && typeof params.transactionalCoreCommitOutcomeResolver !== 'function'\n ) {\n throw new Error(\n `[CustomImpl] Invalid transactional-core configuration for registration \"${params.debugLabel}\" `\n + `on operation \"${params.operationPathKey}\": transactionalCoreCommitOutcomeResolver must be a function.`,\n );\n }\n\n if (\n params.transactionalCoreCommitOutcomeResolver !== undefined\n && !params.transactionalCore\n ) {\n throw new Error(\n `[CustomImpl] Invalid transactional-core configuration for registration \"${params.debugLabel}\" `\n + `on operation \"${params.operationPathKey}\": transactionalCoreCommitOutcomeResolver requires `\n + 'transactionalCore=true.',\n );\n }\n\n if (\n params.transactionalCore\n && params.modes.includes(ResourceOperation_CustomServiceImplementationMode.OVERRIDE_ALL)\n ) {\n throw new Error(\n `[CustomImpl] Invalid transactional-core configuration for registration \"${params.debugLabel}\" `\n + `on operation \"${params.operationPathKey}\": transactionalCore=true cannot be combined with `\n + 'OVERRIDE_ALL because OVERRIDE_ALL returns before the framework core transaction.',\n );\n }\n\n /*\n * BEFORE_TRANSACTIONAL_CORE exists to keep an external effect OUT of a retryable transaction while its outcome still\n * feeds one (#535). Without an owned transactional core there is nothing for it to stand before, and the phase would\n * be a PREFIX with a misleading name — so its absence of a transaction is refused rather than tolerated.\n */\n if (\n params.modes.includes(ResourceOperation_CustomServiceImplementationMode.BEFORE_TRANSACTIONAL_CORE)\n && !params.transactionalCore\n ) {\n throw new Error(\n `[CustomImpl] Invalid transactional-core configuration for registration \"${params.debugLabel}\" `\n + `on operation \"${params.operationPathKey}\": beforeTransactionalCore requires transactionalCore=true, `\n + 'because the phase exists to run outside the transaction that the core then owns.',\n );\n }\n}\n\nexport type ResourceCustomServiceImplementationFactory = (\n resourcesRegistryService: ResourcesRegistryBackendService,\n container: Container,\n) => ResourceCustomServiceImplementationFactoryResult;\n\n\n\n\n\nexport function createResourceCustomServiceImplementation<\n TInput extends z.ZodSchema | undefined = (z.ZodAny | undefined),\n TOutput extends z.ZodSchema = z.ZodAny,\n>(params: {\n reconcileScheduled?: ResourceScheduledReconciler;\n /** Who may act on the operation's single target. See {@link ResourceCustomServiceImplementationTargetAuthority}. */\n authorizeTarget?: ResourceCustomServiceImplementationTargetAuthority;\n operationPath: ResourceConfiguration_OperationPath<any, any>;\n requestDtoSchema?: TInput;\n responseDtoSchema?: TOutput;\n handlers: AllHandlersType;\n /** Lower number = higher priority. Default: 100. */\n priority?: number;\n /** Per-mode override configuration. Default: all modes are chainable. */\n modeOverrides?: ModeOverrideConfig;\n /** Human-readable label for debug logging. Fallback: `{operationPathKey}@{priority}`. */\n debugLabel?: string;\n /** Fields whose value this implementation's PREFIX hook owns. See {@link ResourceCustomServiceImplementationAuthoritativeFields}. */\n authoritativeFields?: ResourceCustomServiceImplementationAuthoritativeFields;\n /** Who delivers the occurrence's audit row and notifications. See {@link ResourceOperation_PostCommitEffectOwnership}. */\n postCommitEffectOwnership?: ResourceOperation_PostCommitEffectOwnership;\n /** This `overrideAll` writes its own operation audit row. See {@link ResourceCustomServiceImplementationOwnsOperationAuditRecord}. */\n ownsOperationAuditRecord?: ResourceCustomServiceImplementationOwnsOperationAuditRecord;\n /** #2543: what the row must still hold for the core write to land. See the factory result's `coreWritePrecondition`. */\n coreWritePrecondition?: AdmissionWritePrecondition;\n /** #3279: the core write lands only on the row at the version the hooks read. See the factory result's field. */\n coreWritePinsRowVersion?: true;\n /** #2297: whether the hooks may run inside the transaction that keeps the audit row. See {@link ResourceCustomServiceImplementationHookTransactionPosture}. */\n hookTransactionPosture?: ResourceCustomServiceImplementationHookTransactionPosture;\n} & ResourceCustomServiceImplementationTransactionalCoreConfiguration): ResourceCustomServiceImplementationFactoryResult & { implementation: ResourceOperationCustomImplementationBase<TInput, TOutput> } {\n const {\n reconcileScheduled,\n authorizeTarget,\n operationPath,\n requestDtoSchema,\n responseDtoSchema,\n handlers = {},\n priority,\n modeOverrides,\n debugLabel,\n authoritativeFields,\n postCommitEffectOwnership,\n ownsOperationAuditRecord,\n coreWritePrecondition,\n coreWritePinsRowVersion,\n hookTransactionPosture,\n transactionalCore,\n transactionParticipants,\n transactionalCoreConflictResolver,\n transactionalCoreCommitOutcomeResolver,\n } = params;\n\n const getModeSchema = (mode: ResourceOperation_CustomServiceImplementationMode, inputOrOutput: 'input' | 'output') : z.ZodSchema | undefined => {\n\n if(inputOrOutput === 'input') {\n if(!requestDtoSchema) {\n if(mode === ResourceOperation_CustomServiceImplementationMode.REPLACE_CORE_OPERARTIONS) {\n return z.any();\n }\n return undefined;\n }\n if([\n ResourceOperation_CustomServiceImplementationMode.OVERRIDE_ALL,\n ResourceOperation_CustomServiceImplementationMode.BEFORE_TRANSACTIONAL_CORE,\n ResourceOperation_CustomServiceImplementationMode.PREFIX_CORE_OPERARTIONS,\n ResourceOperation_CustomServiceImplementationMode.REPLACE_CORE_OPERARTIONS,\n ].includes(mode)) {\n return requestDtoSchema;\n }\n return responseDtoSchema;\n } else {\n // A BEFORE_TRANSACTIONAL_CORE result is a framework disposition, not a DTO: the service tier validates its shape.\n if(!responseDtoSchema || mode === ResourceOperation_CustomServiceImplementationMode.BEFORE_TRANSACTIONAL_CORE) {\n return undefined;\n }\n if([\n ResourceOperation_CustomServiceImplementationMode.PREFIX_CORE_OPERARTIONS,\n ].includes(mode)) {\n return requestDtoSchema;\n }\n return responseDtoSchema;\n }\n }\n\n /**\n * The schema an `overrideAll` result is held to in a SUMMARY or CONTEXT read (#3177): that mode's response DTO, when\n * the operation answers its data modes itself (a LIST-like or a named read-like operation).\n *\n * An override that reads the core operation as a sub-call carries the caller's `dataMode` into it, as a nested read\n * does by default, so in SUMMARY mode it returns summary rows. An override's result never reaches the service tier's\n * `transformOutput`, so this parse is its only service-side check, and the controller then serializes it with\n * `selectResponseDto(operation, dataMode)`. This parse held it to the RAW `responseDtoSchema` instead, whose coerced\n * `createdAt` turned a summary row's absent date into an Invalid Date: Wonder\n * Procurement's \"Awaiting Your Decision\" queue answered 400 to the home page that lists it in summary mode.\n * `undefined` keeps the RAW parse: in RAW mode, and for an operation whose response is its own in every mode.\n */\n const dataModeOutputSchema = (\n mode: ResourceOperation_CustomServiceImplementationMode,\n executionContext: ExecutionContext<any>,\n utils: ResourceOperation_CustomImplementation_Utils,\n ): z.ZodSchema | undefined => {\n if (mode !== ResourceOperation_CustomServiceImplementationMode.OVERRIDE_ALL || !responseDtoSchema) return undefined;\n const dataMode = utils.serviceOptions?.dataMode;\n if (dataMode !== DataMode.SUMMARY && dataMode !== DataMode.CONTEXT) return undefined;\n // The execution context types its operation as a readonly view; the DTO utilities read it, never write it.\n const operation = executionContext.operation as ResourceConfiguration_Operation<any, any, any> | undefined;\n if (!operation || !ResourcesConfigOperationsDtosBuilderUtils.answersDataModesItself(operation)) return undefined;\n return ResourcesConfigOperationsDtosBuilderUtils.selectResponseDto(operation, dataMode) ?? undefined;\n };\n\n const key = ResourcesConfig_OperationPathUtils.createOperationPathKey(operationPath);\n\n const executeHandler = async <\n TMode extends ResourceOperation_CustomServiceImplementationMode,\n TInput extends z.ZodSchema | undefined = z.ZodAny | undefined,\n TOutput extends z.ZodSchema = z.ZodAny,\n TAugment extends object|undefined = undefined\n>(\n handler: AnyHandlerType<TMode, TInput, TOutput, TAugment> | undefined,\n handlerName : string,\n mode: ResourceOperation_CustomServiceImplementationMode,\n _id: string | undefined,\n input: ResourceOperationCustomImplementation_InputTypeOf<TMode, TInput, TOutput, TAugment>,\n executionContext: ExecutionContext<any>,\n utils : ResourceOperation_CustomImplementation_Utils,\n\n) : Promise<ResourceOperationCustomImplementation_OutputTypeOf<TMode, TInput, TOutput, TAugment>> => {\n\n\n if (!handler)\n throw utils.errorBuilder.buildError(ErrorType.CONFIGURATION, executionContext, {\n customMessageReference : ErrorCustomMessageReference.RESOURCE_OPERATION_CUSTOM_IMPLEMENTATION_NOT_IMPLEMENTED,\n context : {\n message: `${handlerName} has not been defined in handlers`,\n }\n });\n\n // The JSON form of the authored schema (#3478): over HTTP the controller has already read the body's dates, but an\n // operation run again from the queue (`job-executor`) hands this the job's JSON, whose dates are RFC 3339 strings.\n const authoredInputSchema = getModeSchema(mode, 'input');\n const inputSchema = authoredInputSchema ? jsonParsingSchemaOf(authoredInputSchema) : authoredInputSchema;\n const inputParsed = parseResourceOperation_CustomServiceImplementationSchema(\n mode, 'input',\n inputSchema,\n input,\n utils.errorBuilder,\n ) as ResourceOperationCustomImplementation_InputTypeOf<TMode, TInput, TOutput, TAugment>;\n\n\n const output = await (handler as AnyHandlerType<TMode, TInput, TOutput, TAugment>)(_id, inputParsed, executionContext, operationPath, utils);\n\n const outputSchema = dataModeOutputSchema(mode, executionContext, utils) ?? getModeSchema(mode, 'output');\n return parseResourceOperation_CustomServiceImplementationSchema(\n mode, 'output',\n outputSchema,\n output,\n utils.errorBuilder,\n ) as ResourceOperationCustomImplementation_OutputTypeOf<TMode, TInput, TOutput, TAugment>;\n }\n\n\n class Impl extends ResourceOperationCustomImplementationBase<TInput, TOutput> {\n\n public getPlaceholders(): ResourceOperation_CustomServiceImplementationMode[] {\n const modes: ResourceOperation_CustomServiceImplementationMode[] = [];\n if (handlers.overrideAll) modes.push(ResourceOperation_CustomServiceImplementationMode.OVERRIDE_ALL);\n if (handlers.beforeTransactionalCore) modes.push(ResourceOperation_CustomServiceImplementationMode.BEFORE_TRANSACTIONAL_CORE);\n if (handlers.prefixCoreOperations) modes.push(ResourceOperation_CustomServiceImplementationMode.PREFIX_CORE_OPERARTIONS);\n if (handlers.replaceCoreOperations) modes.push(ResourceOperation_CustomServiceImplementationMode.REPLACE_CORE_OPERARTIONS);\n if (handlers.postfixCoreOperations) modes.push(ResourceOperation_CustomServiceImplementationMode.POSTFIX_CORE_OPERARTIONS);\n if (handlers.afterUserNotifications) modes.push(ResourceOperation_CustomServiceImplementationMode.AFTER_USER_NOTIFICATIONS);\n if (handlers.atTheEnd) modes.push(ResourceOperation_CustomServiceImplementationMode.AT_THE_END);\n return modes;\n }\n\n public async overrideAll(\n _id: string | undefined,\n input: ResourceOperationCustomImplementation_InputTypeOf<ResourceOperation_CustomServiceImplementationMode.OVERRIDE_ALL, TInput, TOutput>,\n executionContext: ExecutionContext<any>,\n utils: ResourceOperation_CustomImplementation_Utils\n ): Promise<ResourceOperationCustomImplementation_OutputTypeOf<\n ResourceOperation_CustomServiceImplementationMode.OVERRIDE_ALL,\n TInput, TOutput\n >> {\n\n return executeHandler<ResourceOperation_CustomServiceImplementationMode.OVERRIDE_ALL, TInput, TOutput>(\n handlers.overrideAll,\n 'overrideAll',\n ResourceOperation_CustomServiceImplementationMode.OVERRIDE_ALL,\n _id, input, executionContext, utils);\n }\n\n public async beforeTransactionalCore(\n _id: string | undefined,\n input: ResourceOperationCustomImplementation_InputTypeOf<ResourceOperation_CustomServiceImplementationMode.BEFORE_TRANSACTIONAL_CORE, TInput, TOutput>,\n executionContext: ExecutionContext<any>,\n utils: ResourceOperation_CustomImplementation_Utils\n ): Promise<ResourceOperationBeforeTransactionalCoreResult> {\n\n return executeHandler<ResourceOperation_CustomServiceImplementationMode.BEFORE_TRANSACTIONAL_CORE, TInput, TOutput>(\n handlers.beforeTransactionalCore,\n 'beforeTransactionalCore',\n ResourceOperation_CustomServiceImplementationMode.BEFORE_TRANSACTIONAL_CORE,\n _id, input, executionContext, utils);\n }\n\n public async prefixCoreOperations<TAugment extends object|undefined = undefined>(\n _id: string | undefined,\n input: ResourceOperationCustomImplementation_InputTypeOf<ResourceOperation_CustomServiceImplementationMode.PREFIX_CORE_OPERARTIONS, TInput, TOutput, TAugment>,\n executionContext: ExecutionContext<any>,\n utils: ResourceOperation_CustomImplementation_Utils\n ): Promise<ResourceOperationCustomImplementation_OutputTypeOf<\n ResourceOperation_CustomServiceImplementationMode.PREFIX_CORE_OPERARTIONS,\n TInput, TOutput, TAugment\n >> {\n\n return executeHandler<ResourceOperation_CustomServiceImplementationMode.PREFIX_CORE_OPERARTIONS, TInput, TOutput, TAugment>(\n handlers.prefixCoreOperations as AnyHandlerType<ResourceOperation_CustomServiceImplementationMode.PREFIX_CORE_OPERARTIONS, TInput, TOutput, TAugment> | undefined,\n 'prefixCoreOperations',\n ResourceOperation_CustomServiceImplementationMode.PREFIX_CORE_OPERARTIONS,\n _id, input, executionContext, utils);\n }\n\n public async replaceCoreOperations<TAugment extends object|undefined = undefined>(\n _id: string | undefined,\n input: ResourceOperationCustomImplementation_InputTypeOf<ResourceOperation_CustomServiceImplementationMode.REPLACE_CORE_OPERARTIONS, TInput, TOutput, TAugment>,\n executionContext: ExecutionContext<any>,\n utils: ResourceOperation_CustomImplementation_Utils\n ): Promise<ResourceOperationCustomImplementation_OutputTypeOf<\n ResourceOperation_CustomServiceImplementationMode.REPLACE_CORE_OPERARTIONS,\n TInput, TOutput, TAugment\n >> {\n\n return executeHandler<ResourceOperation_CustomServiceImplementationMode.REPLACE_CORE_OPERARTIONS, TInput, TOutput, TAugment>(\n handlers.replaceCoreOperations as AnyHandlerType<ResourceOperation_CustomServiceImplementationMode.REPLACE_CORE_OPERARTIONS, TInput, TOutput, TAugment> | undefined,\n 'replaceCoreOperations',\n ResourceOperation_CustomServiceImplementationMode.REPLACE_CORE_OPERARTIONS,\n _id, input, executionContext, utils);\n }\n\n public async postfixCoreOperations(\n _id: string | undefined,\n input: ResourceOperationCustomImplementation_InputTypeOf<ResourceOperation_CustomServiceImplementationMode.POSTFIX_CORE_OPERARTIONS, TInput, TOutput>,\n executionContext: ExecutionContext<any>,\n utils: ResourceOperation_CustomImplementation_Utils\n ): Promise<ResourceOperationCustomImplementation_OutputTypeOf<\n ResourceOperation_CustomServiceImplementationMode.POSTFIX_CORE_OPERARTIONS,\n TInput, TOutput\n >> {\n\n return executeHandler<ResourceOperation_CustomServiceImplementationMode.POSTFIX_CORE_OPERARTIONS, TInput, TOutput>(\n handlers.postfixCoreOperations,\n 'postfixCoreOperations',\n ResourceOperation_CustomServiceImplementationMode.POSTFIX_CORE_OPERARTIONS,\n _id, input, executionContext, utils);\n }\n\n public async afterUserNotifications(\n _id: string | undefined,\n input: ResourceOperationCustomImplementation_InputTypeOf<ResourceOperation_CustomServiceImplementationMode.AFTER_USER_NOTIFICATIONS, TInput, TOutput>,\n executionContext: ExecutionContext<any>,\n utils: ResourceOperation_CustomImplementation_Utils\n ): Promise<ResourceOperationCustomImplementation_OutputTypeOf<\n ResourceOperation_CustomServiceImplementationMode.AFTER_USER_NOTIFICATIONS,\n TInput, TOutput\n >> {\n\n return executeHandler<ResourceOperation_CustomServiceImplementationMode.AFTER_USER_NOTIFICATIONS, TInput, TOutput>(\n handlers.afterUserNotifications,\n 'afterUserNotifications',\n ResourceOperation_CustomServiceImplementationMode.AFTER_USER_NOTIFICATIONS,\n _id, input, executionContext, utils);\n }\n\n public async atTheEnd(\n _id: string | undefined,\n input: ResourceOperationCustomImplementation_InputTypeOf<ResourceOperation_CustomServiceImplementationMode.AT_THE_END, TInput, TOutput>,\n executionContext: ExecutionContext<any>,\n utils: ResourceOperation_CustomImplementation_Utils\n ): Promise<ResourceOperationCustomImplementation_OutputTypeOf<\n ResourceOperation_CustomServiceImplementationMode.AT_THE_END,\n TInput, TOutput\n >> {\n\n return executeHandler<ResourceOperation_CustomServiceImplementationMode.AT_THE_END, TInput, TOutput>(\n handlers.atTheEnd,\n 'atTheEnd',\n ResourceOperation_CustomServiceImplementationMode.AT_THE_END,\n _id, input, executionContext, utils);\n }\n }\n\n const implementation = new Impl();\n const authoredTransactionalCore: unknown =\n transactionalCore === undefined ? false : transactionalCore;\n const normalizedTransactionalCore = authoredTransactionalCore === true;\n const normalizedDebugLabel = debugLabel ?? `${key}@${priority ?? 100}`;\n\n assertValidResourceCustomImplementationTransactionalCoreConfiguration({\n operationPathKey: key,\n debugLabel: normalizedDebugLabel,\n modes: implementation.getPlaceholders(),\n transactionalCore: authoredTransactionalCore,\n transactionParticipants,\n transactionalCoreConflictResolver,\n transactionalCoreCommitOutcomeResolver,\n });\n\n assertValidResourceCustomImplementationAuthoritativeFields({\n operationPathKey: key,\n debugLabel: normalizedDebugLabel,\n modes: implementation.getPlaceholders(),\n authoritativeFields,\n });\n\n assertValidResourceCustomImplementationPostCommitEffectOwnership({\n operationPathKey: key,\n debugLabel: normalizedDebugLabel,\n transactionalCore: authoredTransactionalCore,\n postCommitEffectOwnership,\n });\n\n assertValidResourceCustomImplementationOperationAuditOwnership({\n operationPathKey: key,\n debugLabel: normalizedDebugLabel,\n modes: implementation.getPlaceholders(),\n ownsOperationAuditRecord,\n });\n\n const transactionalCoreConfiguration: ResourceCustomServiceImplementationTransactionalCoreConfiguration =\n transactionalCore === true\n ? {\n transactionalCore: true,\n transactionParticipants: Object.freeze({\n ...transactionParticipants,\n }),\n transactionalCoreConflictResolver,\n transactionalCoreCommitOutcomeResolver,\n }\n : {\n transactionalCore,\n };\n\n return {\n operationPathKey: key,\n reconcileScheduled,\n ...(authorizeTarget ? { authorizeTarget } : {}),\n implementation,\n priority,\n modeOverrides,\n debugLabel,\n // Frozen: the allow-list is consulted on every write through this operation, and a mutable\n // shared array would let one call site widen what another may persist.\n ...(authoritativeFields ? { authoritativeFields: Object.freeze([...authoritativeFields]) } : {}),\n ...(postCommitEffectOwnership ? { postCommitEffectOwnership } : {}),\n ...(ownsOperationAuditRecord ? { ownsOperationAuditRecord } : {}),\n ...(coreWritePrecondition ? { coreWritePrecondition: freezeCoreWritePrecondition(coreWritePrecondition, key, normalizedDebugLabel, implementation.getPlaceholders()) } : {}),\n ...(coreWritePinsRowVersion ? { coreWritePinsRowVersion: assertCoreWriteRuns(key, normalizedDebugLabel, implementation.getPlaceholders()) } : {}),\n ...(hookTransactionPosture !== undefined ? { hookTransactionPosture } : {}),\n ...transactionalCoreConfiguration,\n };\n}\n\n/** An OVERRIDE_ALL implementation runs no core write, so a pin declared on one would read as protection that is not there. */\nexport function assertCoreWriteRuns(\n operationPathKey: string,\n debugLabel: string | undefined,\n modes: readonly ResourceOperation_CustomServiceImplementationMode[],\n): true {\n if (modes.includes(ResourceOperation_CustomServiceImplementationMode.OVERRIDE_ALL)) {\n throw new Error(`[CustomImpl] Invalid coreWritePinsRowVersion for registration \"${debugLabel ?? operationPathKey}\" (${operationPathKey}): an OVERRIDE_ALL implementation runs no core write for it to fence`);\n }\n return true;\n}\n\n/**\n * Validates and freezes a registration's `coreWritePrecondition` (#2543). Refused when it cannot mean anything: an empty\n * map, a field with no admitted value (no row could ever satisfy it, so the operation could never land), a value that\n * is not a string, number, boolean or null (an equality only those compile to identically on every adapter), or an\n * OVERRIDE_ALL registration (it replaces the pipeline, so no core write exists to carry it, and the declaration would read\n * as protection that is not there).\n */\nexport function freezeCoreWritePrecondition(\n precondition: AdmissionWritePrecondition,\n operationPathKey: string,\n debugLabel: string | undefined,\n modes: readonly ResourceOperation_CustomServiceImplementationMode[],\n): AdmissionWritePrecondition {\n const refuse = (why: string): never => {\n throw new Error(`[CustomImpl] Invalid coreWritePrecondition for registration \"${debugLabel ?? operationPathKey}\" (${operationPathKey}): ${why}`);\n };\n if (modes.includes(ResourceOperation_CustomServiceImplementationMode.OVERRIDE_ALL)) {\n refuse('an OVERRIDE_ALL implementation runs no core write for it to fence');\n }\n if (!precondition || typeof precondition !== 'object' || Array.isArray(precondition)) refuse('it must be a map of field to admitted values');\n const entries = Object.entries(precondition);\n if (entries.length === 0) refuse('it constrains no field');\n for (const [field, values] of entries) {\n if (!Array.isArray(values) || values.length === 0) refuse(`field \"${field}\" admits no value, so the write could never land`);\n for (const value of values) {\n if (value !== null && typeof value !== 'string' && typeof value !== 'boolean' && !(typeof value === 'number' && Number.isFinite(value))) {\n refuse(`field \"${field}\" admits a value that is not a string, number, boolean or null`);\n }\n }\n }\n return Object.freeze(Object.fromEntries(entries.map(([field, values]) => [field, Object.freeze([...values])])));\n}\n"]}
|
|
1
|
+
{"version":3,"file":"resource-operation-custom-implementation.factory.backend.js","sourceRoot":"","sources":["../../../../../src/base-classes/services/services/resource-operation-custom-implementation.factory.backend.ts"],"names":[],"mappings":"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","sourcesContent":["import { DataMode, ErrorCustomMessageReference, ErrorType, type ResourceConfiguration_Operation, ResourceConfiguration_OperationPath, ResourceOperation_CustomServiceImplementationMode, ResourceOperation_PostCommitEffectOwnership, ResourcesConfig_OperationPathUtils, ResourcesConfigOperationsDtosBuilderUtils, jsonParsingSchemaOf } from '@wildo-ai/saas-models';\nimport { z } from 'zod';\nimport type { Container } from 'inversify';\nimport type { AdmissionWritePrecondition } from '~wildo-backend-lib/base-classes/utils/admission-write-precondition.backend.utils';\nimport type { ExecutionContext } from '~wildo-backend-lib/runtime/models/execution-context.backend.schemas';\nimport { parseResourceOperation_CustomServiceImplementationSchema, ResourceOperation_CustomImplementation_Utils, ResourceOperationBeforeTransactionalCoreResult, ResourceOperationCustomImplementation_InputTypeOf, ResourceOperationCustomImplementation_OutputTypeOf, ResourceOperationCustomImplementationBase } from './resource-operation-custom-implementation-base.backend.service';\nimport { ResourcesRegistryBackendService } from '~wildo-backend-lib/resources/services/resources-registry.backend.service';\nimport type { ModeOverrideConfig } from './resource-operation-custom-implementation-registry.backend.service';\nimport type { ScheduledAttemptContext, ScheduledReconciliationResult } from '@wildo-ai/saas-models';\n\n/**\n * Reconciles the effects of the entire scheduled operation after an unknown outcome.\n * Declare once per exact operation path. Capture application dependencies in the\n * enclosing implementation factory, just as for its normal execution handlers.\n * This callback must inspect durable evidence; it must not execute the operation again.\n */\nexport type ResourceScheduledReconciler = (\n input: unknown,\n executionContext: ExecutionContext<any>,\n scheduledAttempt: ScheduledAttemptContext,\n) => Promise<ScheduledReconciliationResult>;\n\n\n\ntype AnyHandlerType<\n TMode extends ResourceOperation_CustomServiceImplementationMode,\n TInput extends z.ZodSchema | undefined = z.ZodAny | undefined,\n TOutput extends z.ZodSchema = z.ZodAny,\n TAugment extends object|undefined = undefined\n> =\n (\n _id: string | undefined,\n input: ResourceOperationCustomImplementation_InputTypeOf<TMode, TInput, TOutput, TAugment>,\n executionContext: ExecutionContext<any>,\n operationPath: ResourceConfiguration_OperationPath<any, any>,\n utils: ResourceOperation_CustomImplementation_Utils\n ) =>\n Promise<ResourceOperationCustomImplementation_OutputTypeOf<TMode, TInput, TOutput, TAugment>>;\n\ntype AllHandlersType<\n TInput extends z.ZodSchema | undefined = z.ZodAny | undefined,\n TOutput extends z.ZodSchema = z.ZodAny,\n> = Partial<{\n overrideAll :\n (\n _id: string | undefined,\n input: ResourceOperationCustomImplementation_InputTypeOf<ResourceOperation_CustomServiceImplementationMode.OVERRIDE_ALL, TInput, TOutput>,\n executionContext: ExecutionContext<any>,\n operationPath: ResourceConfiguration_OperationPath<any, any>,\n utils: ResourceOperation_CustomImplementation_Utils\n ) =>\n Promise<ResourceOperationCustomImplementation_OutputTypeOf<ResourceOperation_CustomServiceImplementationMode.OVERRIDE_ALL, TInput, TOutput>>;\n\n /** @wildo_source:part:start saas.backend.custom-operation.transactional-core facet:layer:backend facet:family:resource-operation */\n /**\n * Runs OUTSIDE any database transaction, after preflight and before the transactional core (#535). The phase for an\n * external effect whose outcome feeds the core write. Requires `transactionalCore: true`; exactly one registration\n * may declare it. Handler signature: `(id, input, executionContext, operationPath, utils)`, where `input` is parsed\n * by the operation's request DTO and the answer is a `ResourceOperationBeforeTransactionalCoreResult`.\n */\n beforeTransactionalCore :\n (\n _id: string | undefined,\n input: ResourceOperationCustomImplementation_InputTypeOf<ResourceOperation_CustomServiceImplementationMode.BEFORE_TRANSACTIONAL_CORE, TInput, TOutput>,\n executionContext: ExecutionContext<any>,\n operationPath: ResourceConfiguration_OperationPath<any, any>,\n utils: ResourceOperation_CustomImplementation_Utils\n ) =>\n Promise<ResourceOperationBeforeTransactionalCoreResult>;\n /** @wildo_source:part:end saas.backend.custom-operation.transactional-core */\n\n prefixCoreOperations :\n <TAugment extends object|undefined = undefined>\n (\n _id: string | undefined,\n input: ResourceOperationCustomImplementation_InputTypeOf<ResourceOperation_CustomServiceImplementationMode.PREFIX_CORE_OPERARTIONS, TInput, TOutput, TAugment>,\n executionContext: ExecutionContext<any>,\n operationPath: ResourceConfiguration_OperationPath<any, any>,\n utils: ResourceOperation_CustomImplementation_Utils\n ) =>\n Promise<ResourceOperationCustomImplementation_OutputTypeOf<ResourceOperation_CustomServiceImplementationMode.PREFIX_CORE_OPERARTIONS, TInput, TOutput, TAugment>>;\n\n replaceCoreOperations :\n <TAugment extends object|undefined = undefined>(\n _id: string | undefined,\n input: ResourceOperationCustomImplementation_InputTypeOf<ResourceOperation_CustomServiceImplementationMode.REPLACE_CORE_OPERARTIONS, TInput, TOutput, TAugment>,\n executionContext: ExecutionContext<any>,\n operationPath: ResourceConfiguration_OperationPath<any, any>,\n utils: ResourceOperation_CustomImplementation_Utils\n ) => Promise<ResourceOperationCustomImplementation_OutputTypeOf<ResourceOperation_CustomServiceImplementationMode.REPLACE_CORE_OPERARTIONS, TInput, TOutput, TAugment>>;\n\n postfixCoreOperations :\n (\n _id: string | undefined,\n input: ResourceOperationCustomImplementation_InputTypeOf<ResourceOperation_CustomServiceImplementationMode.POSTFIX_CORE_OPERARTIONS, TInput, TOutput>,\n executionContext: ExecutionContext<any>,\n operationPath: ResourceConfiguration_OperationPath<any, any>,\n utils: ResourceOperation_CustomImplementation_Utils\n ) =>\n Promise<ResourceOperationCustomImplementation_OutputTypeOf<ResourceOperation_CustomServiceImplementationMode.POSTFIX_CORE_OPERARTIONS, TInput, TOutput>>;\n\n afterUserNotifications :\n (\n _id: string | undefined,\n input: ResourceOperationCustomImplementation_InputTypeOf<ResourceOperation_CustomServiceImplementationMode.AFTER_USER_NOTIFICATIONS, TInput, TOutput>,\n executionContext: ExecutionContext<any>,\n operationPath: ResourceConfiguration_OperationPath<any, any>,\n utils: ResourceOperation_CustomImplementation_Utils\n ) =>\n Promise<ResourceOperationCustomImplementation_OutputTypeOf<ResourceOperation_CustomServiceImplementationMode.AFTER_USER_NOTIFICATIONS, TInput, TOutput>>;\n\n atTheEnd :\n (\n _id: string | undefined,\n input: ResourceOperationCustomImplementation_InputTypeOf<ResourceOperation_CustomServiceImplementationMode.AT_THE_END, TInput, TOutput>,\n executionContext: ExecutionContext<any>,\n operationPath: ResourceConfiguration_OperationPath<any, any>,\n utils: ResourceOperation_CustomImplementation_Utils\n ) =>\n Promise<ResourceOperationCustomImplementation_OutputTypeOf<ResourceOperation_CustomServiceImplementationMode.AT_THE_END, TInput, TOutput>>;\n}>\n\n/** @wildo_source:part:start saas.backend.custom-operation.transactional-core facet:layer:backend facet:family:resource-operation */\n\n/**\n * Explicit outcome of a conflict resolver invoked after the owned transaction\n * has aborted.\n *\n * `RECONCILED` returns an already-committed semantic winner.\n * `RETRY_TRANSACTION` requests the framework's single bounded retry of the\n * complete transaction boundary.\n * `UNHANDLED` preserves the original conflict without spending that retry.\n */\nexport enum ResourceCustomServiceImplementationTransactionalCoreConflictAction {\n RECONCILED = 'reconciled',\n RETRY_TRANSACTION = 'retry_transaction',\n UNHANDLED = 'unhandled',\n}\n\nexport type ResourceCustomServiceImplementationTransactionalCoreConflictResolution =\n | {\n action: ResourceCustomServiceImplementationTransactionalCoreConflictAction.RECONCILED;\n /** Already-committed operation result that is equivalent to this request. */\n value: unknown;\n }\n | {\n action: ResourceCustomServiceImplementationTransactionalCoreConflictAction.RETRY_TRANSACTION;\n }\n | {\n action: ResourceCustomServiceImplementationTransactionalCoreConflictAction.UNHANDLED;\n };\n\nexport type ResourceCustomServiceImplementationTransactionalCoreConflictResolver = (\n error: unknown,\n input: unknown,\n executionContext: ExecutionContext<any>,\n utils: ResourceOperation_CustomImplementation_Utils,\n) => Promise<ResourceCustomServiceImplementationTransactionalCoreConflictResolution>;\n\n/**\n * What reading back an owned transaction whose COMMIT threw found (#2820). The attempt's work all resolved and the\n * transaction then failed: the commit may have landed and lost its reply, so the error alone says nothing about whether\n * the operation happened.\n */\nexport enum ResourceCustomServiceImplementationTransactionalCoreCommitOutcome {\n /** The operation's writes are in the store: the request succeeded, and its caller is answered with `value`. */\n LANDED = 'landed',\n /** The read found the writes absent: the transaction did not commit, and the caller gets the commit's error. */\n NOT_LANDED = 'not_landed',\n /** Nothing could be read: the caller gets `refusal`, which must not say the operation failed (it may have happened). */\n UNKNOWN = 'unknown',\n /**\n * This resolver does not judge this attempt (it reads back only some of the shapes its operation writes). The next\n * resolver is asked; when none settles it, the caller gets the commit's error, as without a resolver.\n */\n UNHANDLED = 'unhandled',\n}\n\nexport type ResourceCustomServiceImplementationTransactionalCoreCommitOutcomeResolution =\n | {\n outcome: ResourceCustomServiceImplementationTransactionalCoreCommitOutcome.LANDED;\n /** The committed core state as read back: what the operation answers, as if its commit had answered. */\n value: unknown;\n /**\n * Keys of post-commit effects THIS implementation registered whose premise the read-back disproved (an approval\n * announced as waiting that was answered before the read-back): the framework drops them instead of running them.\n * Every other effect the attempt registered runs. Omit it when the stored state still bears out every effect.\n */\n withheldPostCommitEffectKeys?: readonly string[];\n }\n | {\n outcome: ResourceCustomServiceImplementationTransactionalCoreCommitOutcome.NOT_LANDED;\n }\n | {\n outcome: ResourceCustomServiceImplementationTransactionalCoreCommitOutcome.UNKNOWN;\n /** The error thrown to the caller instead of the commit's: a stable, client-branchable refusal saying it may have happened. */\n refusal: unknown;\n }\n | {\n outcome: ResourceCustomServiceImplementationTransactionalCoreCommitOutcome.UNHANDLED;\n };\n\n/**\n * The commit receipt the framework wrote inside an attempt's transaction (#2870): a row whose id only that attempt holds,\n * so it is stored if and only if the attempt committed. Present only for an operation whose commit-outcome resolver reads\n * one (its resolver was built with `createTransactionalCoreDeleteReadBack`).\n */\nexport interface ResourceCustomServiceImplementationTransactionalCoreCommitReceipt {\n /** The id the framework minted for this attempt. For the log; the receipt is read through {@link isStored}. */\n readonly id: string;\n /**\n * Whether the receipt is stored, read outside the failed transaction. `true` proves the attempt committed. Throws when\n * the store cannot answer, and only then is the read worth retrying.\n */\n readonly isStored: () => Promise<boolean>;\n}\n\n/** The attempt whose work resolved before its commit threw (#2820): what the resolver reads back by. */\nexport interface ResourceCustomServiceImplementationTransactionalCoreCommittedAttempt {\n /** The input after PREFIX: what the attempt minted (an id, a decision ref) is here. */\n readonly input: unknown;\n /** The core state the attempt produced, as its writes returned it inside the transaction. */\n readonly state: unknown;\n /** The attempt's commit receipt (#2870), when its operation's resolver reads one. */\n readonly commitReceipt?: ResourceCustomServiceImplementationTransactionalCoreCommitReceipt;\n}\n\n/**\n * Invoked when an owned transaction's work resolved and its commit then threw (#2820), so the operation may have happened\n * with its caller about to be told it failed. The resolver reads the store back (outside the failed transaction) by\n * something only this attempt wrote (an id it minted, a timestamp it stamped), never by a guess, and answers LANDED,\n * NOT_LANDED or UNKNOWN.\n *\n * On LANDED the framework answers the caller with `value` and runs, once, every post-commit effect the attempt\n * registered on the transaction whose commit threw (#2825): the operation's framework work (audit row, notifications),\n * the implementation's own effects, and those of every nested operation it called. The resolver records nothing itself;\n * it only withholds an effect of its own whose premise the read-back disproved (`withheldPostCommitEffectKeys`).\n *\n * On UNKNOWN its `refusal` is thrown: a 409 with a stable, client-branchable `code` saying the operation may have taken\n * effect. `ResourceOperationOutcomeErrorCode.OUTCOME_UNKNOWN` is the general one; a request that RAISES a human decision\n * uses `HumanDecisionRequestErrorCode.REQUEST_OUTCOME_UNKNOWN`. The attempt's registered effects are then dropped for\n * good (nothing knows whether their writes exist), and a retry is usually refused as already done when the commit did\n * land: the caller is meant to look at the record, not to repeat the act. Only a repair the operation owns (the decision\n * planes' request repairs) records them later.\n *\n * Most operations write one row they can be read back by, and build the resolver with\n * `createTransactionalCoreCommitReadBack` (from `@wildo-ai/saas-backend-lib`): `carriesAttemptCreatedRow` for a CREATE (the\n * id the attempt's write produced), `carriesAttemptUpdateStamp` for an UPDATE (the `updatedAt` its write stamped). It\n * reads up to four times over about 4 s and refuses UNKNOWN with the general code. `readBackTransactionalCoreCommit` is the\n * lower-level loop for a read-back of another shape.\n *\n * A DELETE leaves nothing only it wrote: the row's absence is also what another remover leaves. Build its resolver with\n * `createTransactionalCoreDeleteReadBack` (#2870). The framework then writes a commit receipt inside each attempt's\n * transaction, under an id only that attempt holds, and the read-back answers LANDED only when that receipt is stored.\n * When it is not, a row still stored is NOT_LANDED, and a row that is gone is UNKNOWN: never taken for this attempt's work.\n *\n * @example\n * createResourceCustomServiceImplementation({\n * operationPath,\n * transactionalCore: true,\n * transactionParticipants: {},\n * handlers: { prefixCoreOperations, postfixCoreOperations },\n * // A repeat of this verb is refused once it has happened, so a lost commit reply is read back by the row's stamp.\n * transactionalCoreCommitOutcomeResolver: createTransactionalCoreCommitReadBack({\n * reason: 'invoice_approval_outcome_unknown',\n * read: (prepared, _executionContext, utils) => utils.systemAccessService!.readAsSystem(INVOICES, { _id: String(prepared._id) }),\n * carriesThisAttempt: carriesAttemptUpdateStamp,\n * }),\n * });\n */\nexport type ResourceCustomServiceImplementationTransactionalCoreCommitOutcomeResolver = (\n error: unknown,\n attempt: ResourceCustomServiceImplementationTransactionalCoreCommittedAttempt,\n executionContext: ExecutionContext<any>,\n utils: ResourceOperation_CustomImplementation_Utils,\n) => Promise<ResourceCustomServiceImplementationTransactionalCoreCommitOutcomeResolution>;\n\n/**\n * Transaction ownership options for one custom-implementation registration.\n *\n * Import this surface from `@wildo-ai/saas-backend-lib` through\n * `createResourceCustomServiceImplementation`. When `transactionalCore` is\n * enabled, PREFIX, core persistence, REPLACE, and POSTFIX execute atomically.\n * The framework includes the operation resource automatically; authors must\n * name every additional resource touched by those phases and forward\n * `utils.serviceOptions` to every nested resource call. Startup validates the\n * declared participant set; it cannot discover an omitted call or make a call\n * that drops `serviceOptions` join the transaction. Use an explicit empty\n * object only for a genuinely single-resource transaction.\n *\n * @example\n * createResourceCustomServiceImplementation({\n * operationPath,\n * transactionalCore: true,\n * transactionParticipants: {\n * owner: CoreResourceType.USERS,\n * organization: CoreResourceType.ORGANIZATIONS,\n * },\n * handlers: { prefixCoreOperations },\n * });\n *\n * The discriminated shape prevents authored TypeScript registrations from\n * attaching a conflict resolver to a pipeline that does not own the core\n * transaction. The registry repeats this check at runtime because factories\n * may arrive through JavaScript, stale compiled output, or type erasure.\n */\nexport type ResourceCustomServiceImplementationTransactionalCoreConfiguration =\n | {\n /**\n * Runs PREFIX → core repository mutation → REPLACE → POSTFIX in one\n * declared resource persistence transaction. The operation resource is\n * included automatically; every additional resource accessed by these\n * phases must be named in `transactionParticipants`, and every nested\n * resource call must receive `utils.serviceOptions`.\n *\n * This is an explicit authoring contract, not dynamic access discovery:\n * startup proves adapter compatibility for the declared set, but cannot\n * detect an omitted participant or a call that discards the transaction.\n *\n * `OVERRIDE_ALL` is incompatible because it replaces and exits the\n * pipeline before this boundary.\n */\n transactionalCore: true;\n /**\n * Additional resource participants touched inside the atomic core phase,\n * keyed by their semantic role at this boundary.\n *\n * An explicit empty object is required for a true single-resource\n * transaction. This makes the absence of extra participants an authored\n * decision instead of an accidental omission hidden behind a boolean.\n * Calls to these resources must forward `utils.serviceOptions`; naming a\n * participant alone does not implicitly propagate the transaction.\n */\n transactionParticipants: Readonly<Record<string, string>>;\n /**\n * Optional idempotency resolver invoked outside an aborted transaction\n * after a transactional-core conflict. The resolver must explicitly\n * reconcile a committed winner, request the one bounded full-transaction\n * retry, or leave the original conflict unhandled.\n */\n transactionalCoreConflictResolver?: ResourceCustomServiceImplementationTransactionalCoreConflictResolver;\n /**\n * Optional read-back invoked when the transaction's work resolved and its COMMIT then threw (#2820): it decides\n * whether the caller is told the operation succeeded, failed, or may have happened. See\n * {@link ResourceCustomServiceImplementationTransactionalCoreCommitOutcomeResolver}.\n */\n transactionalCoreCommitOutcomeResolver?: ResourceCustomServiceImplementationTransactionalCoreCommitOutcomeResolver;\n }\n | {\n /** Default non-transactional custom-implementation behavior. */\n transactionalCore?: false;\n /** Participant declarations only have meaning for an owned transaction. */\n transactionParticipants?: never;\n /** A conflict resolver has no valid invocation boundary without the transaction. */\n transactionalCoreConflictResolver?: never;\n /** Nor has a commit-outcome resolver: without an owned transaction there is no commit of its own to read back. */\n transactionalCoreCommitOutcomeResolver?: never;\n };\n/** @wildo_source:part:end saas.backend.custom-operation.transactional-core */\n\n/**\n * @wildo_source:part:start saas.backend.custom-operation.authoritative-fields facet:layer:backend facet:family:custom-implementation\n *\n * Fields whose value this implementation's `prefixCoreOperations` hook OWNS.\n *\n * ## Why this exists\n *\n * A prefix that authors a server-owned field (one marked `.excludeFromCreate()` /\n * `.excludeFromUpdate()`) relies on `preserveServerInjectedFields` to carry that value past the\n * repository's strict `requestDto` re-parse. So does a prefix that sets a value BELOW a field: the\n * request contract strips an `.isBackendOnly()` field at every depth, so the re-parse of the\n * containing field drops what the prefix put there. Declare the TOP-LEVEL field that contains it\n * (an SSO connection's prefix parses `saml.x509Certificates` from a PEM, and declares `saml`). That allow-list is normally derived by diffing the\n * prefix output against a snapshot of the payload keys taken BEFORE the prefix ran, so only keys\n * the hook *introduced* are preserved — which is what stops a client smuggling a value into a\n * field it may not write.\n *\n * That inference has a hole: the snapshot is taken at the SERVICE tier, after a LOOSE parse\n * (`z.looseObject`) that passes unknown keys through. A caller that reaches the service tier with\n * the field already present — MCP `callTool` forwards its arguments with no strict parse — puts\n * the key into the snapshot. The prefix's own value is then not classified as introduced, the\n * repository strips it, and the operation answers success having written nothing.\n *\n * Declaring the field here makes the authorship EXPLICIT instead of inferred: the value is always\n * preserved, and it is always the POST-prefix value, so a caller-supplied value is overwritten\n * rather than honored. Reachability of the field by a client is unchanged — that remains governed\n * by the operation's `requestDto` and the schema decorators.\n *\n * ## Why not \"preserve any field whose value the prefix changed\"\n *\n * Rejected as unsafe. `preserveServerInjectedFields` copies the post-prefix value, and a\n * pass-through prefix (`return input` — the idiom used by guard hooks that only validate) which\n * rebuilt an object-valued field would produce a reference change with identical content. That\n * would allow-list a field the caller supplied and the hook never intended to endorse. Primitives\n * compare safely by value, object graphs do not, and making the guarantee depend on how each hook\n * happens to construct its return value is exactly the implicit rule this contract removes.\n *\n * @example\n * createResourceCustomServiceImplementation({\n * operationPath: { resourceIdentifier: CoreResourceType.ORGANIZATIONS, operationIdentifier: 'suspend', ... },\n * // `status` is `.excludeFromUpdate()`; this operation is the authority that sets it.\n * authoritativeFields: ['status'],\n * handlers: { prefixCoreOperations: async () => ({ status: OrganizationStatus.SUSPENDED }) },\n * });\n */\nexport type ResourceCustomServiceImplementationAuthoritativeFields = readonly string[];\n/** @wildo_source:part:end saas.backend.custom-operation.authoritative-fields */\n\n/** @wildo_source:part:start saas.backend.custom-operation.target-authority facet:layer:backend facet:family:custom-implementation */\n/**\n * WHO may act on THIS row: a read-only check that refuses (AUTHORIZATION, 403) when the caller may not act on the\n * operation's single target. The pipeline runs it with the other gates that depend on who is asking, after the target is\n * read and before every refusal that reads the row's state (a RESTRICT dependent, a legal hold) and before every hook.\n *\n * Why it is not a hook: every gate that depends on who is asking runs before a refusal that reads state, so a caller who\n * may not act on a row is told that, never what state the row is in. A check about the ROW's relation to the caller is\n * such a gate, and no hook runs early enough for it. Since a DELETE refuses on its target before any hook (#2582 review\n * F2), a held row answered a caller outside its authority with 409 and the hold's legal grounds before the hook that\n * would have answered 403 (#2582 review R2).\n *\n * Only an operation addressed to ONE row has a target to judge. Declared on an operation called any other way (a bulk\n * selection of several rows, a filter, a create), the call is refused (AUTHORIZATION): a check that cannot run would\n * otherwise admit everyone it exists to refuse. A bulk selection of exactly one row is judged on that row. It must not\n * write: it runs outside any transaction, and a refusal after it must leave nothing behind.\n */\nexport type ResourceCustomServiceImplementationTargetAuthority = (\n target: Record<string, unknown>,\n executionContext: ExecutionContext<any>,\n utils: ResourceOperation_CustomImplementation_Utils,\n) => Promise<void>;\n/** @wildo_source:part:end saas.backend.custom-operation.target-authority */\n\ntype ResourceCustomServiceImplementationFactoryResultBase = {\n reconcileScheduled?: ResourceScheduledReconciler;\n /** Who may act on the operation's single target. See {@link ResourceCustomServiceImplementationTargetAuthority}. */\n authorizeTarget?: ResourceCustomServiceImplementationTargetAuthority;\n operationPathKey: string;\n implementation: ResourceOperationCustomImplementationBase;\n /** Lower number = higher priority. Default: 100. */\n priority?: number;\n /** Per-mode override configuration. Default: all modes are chainable. */\n modeOverrides?: ModeOverrideConfig;\n /** Human-readable label for debug logging. Fallback: `{operationPathKey}@{priority}`. */\n debugLabel?: string;\n /** Fields whose value this implementation's PREFIX hook owns. See the type's documentation. */\n authoritativeFields?: ResourceCustomServiceImplementationAuthoritativeFields;\n /** Who delivers the occurrence's audit row and notifications. Default `FRAMEWORK`. See {@link ResourceOperation_PostCommitEffectOwnership}. */\n postCommitEffectOwnership?: ResourceOperation_PostCommitEffectOwnership;\n /** This `overrideAll` writes its own `RESOURCE_OPERATION_PERFORMED` row. See {@link ResourceCustomServiceImplementationOwnsOperationAuditRecord}. */\n ownsOperationAuditRecord?: ResourceCustomServiceImplementationOwnsOperationAuditRecord;\n /** @wildo_source:part:start saas.backend.custom-operation.core-write-precondition facet:layer:backend facet:family:custom-implementation facet:audience:app-developer */\n /**\n * What the row must still hold for the CORE write to land, per field (`{ status: ['ACTIVE'] }`). Folded into the single\n * statement that writes, beside what the operation's `enabledCondition` read, so a concurrent writer that moved the row\n * since the prefix judged it makes this write match nothing, and the caller gets 409 `version_conflict`.\n * Declare it when the PREFIX judges the row's state (a status transition's starting states): it holds on every path the\n * registration runs on, including one no `enabledCondition` guards. On a bulk variant it holds for every selected row,\n * and one row that no longer does refuses the whole selection.\n *\n * It holds for every caller of the registration, and `updateAsSystem` resolves the operation's default. So when the system\n * must still write a row a person may not (bookkeeping on a closed record), declare an `INTERNAL_CALL` default beside the\n * `API_CALL` one and register this on the route: the service tier prefers an internal default, so the system door reaches\n * neither the hook nor the fence, while a route, an MCP tool, a function tool and a chat command dispatch by path. What the\n * route declares (`referenceConstraints`, its request) stays the route's: the internal variant declares none of it.\n * The doors that resolve the default reach the internal variant whoever's context they carry, so on such a resource none of\n * them may run a person's write: an in-process `servicesRegistry.update()` (use `doByOperationPath`), a declared flow's\n * `update` step, and a nested `childOperations` mutation. An inbound channel's `ctx.resources.update` is refused there.\n */\n coreWritePrecondition?: AdmissionWritePrecondition;\n /**\n * The core write lands only on the row at the version the hooks read. Declare it when the PREFIX computes the write from\n * the row and no field states what it judged: it rewrites a whole array (`domains[]`), which a field pin cannot guard.\n * A concurrent writer of ANY field then refuses this write with 409 `version_conflict`, so prefer\n * `coreWritePrecondition` wherever a field does state it. Beside it, not instead: a guarded mutation moves a field without\n * advancing the version. Refused on an OVERRIDE_ALL implementation, which runs no core write.\n */\n coreWritePinsRowVersion?: true;\n /** @wildo_source:part:end saas.backend.custom-operation.core-write-precondition */\n /** Whether this registration's hooks may run inside the transaction that keeps the operation's audit row. See {@link ResourceCustomServiceImplementationHookTransactionPosture}. */\n hookTransactionPosture?: ResourceCustomServiceImplementationHookTransactionPosture;\n /** The most rows of its resource one attempt of this REPLACE writes on a multi-row verb. See {@link assertValidResourceCustomImplementationMaximumRowsWrittenPerAttempt}. */\n maximumRowsWrittenPerAttempt?: number;\n};\n\n/** @wildo_source:part:start saas.backend.custom-operation.hook-transaction-posture facet:layer:backend facet:family:custom-implementation facet:audience:app-developer */\n/**\n * Whether a registration's hooks (PREFIX, REPLACE, POSTFIX) may run inside a database transaction the framework opens\n * around the operation, so that the operation's audit row is kept through a crash (#2297).\n *\n * An audited write whose operation is not transactional for another reason writes its `RESOURCE_OPERATION_PERFORMED` row\n * after the commit, best effort: a process that dies in between loses it. The framework closes that gap by running the\n * write in a transaction whose post-commit effects are captured, so the row is kept in the outbox and written later.\n * Running a write in a transaction runs its hooks there too, and that changes what a hook may do, so the framework does it\n * only for a registration that says its hooks were reviewed for it. Undeclared, the write stays best effort.\n *\n * Inside the transaction a hook runs before the commit, possibly twice (the store may retry the transaction once), and on\n * PostgreSQL the operation's own row is locked from the start. So a hook that RUNS_INSIDE_TRANSACTION:\n * - reads and writes the operation's own row, and any row the core write creates or changes, only with\n * `utils.serviceOptions` (another connection would wait on the row lock, or not see the uncommitted row);\n * - makes no effect outside the database before the commit: a provider call, an email, a queue publish, a cache or Redis\n * write, an audit row. Such an effect is registered as a post-commit effect instead\n * (`registerTransactionPostCommitEffect(utils.serviceOptions.transaction, …)`, or `emitAuthorityChangeAuditWhenDurable`\n * for an authority-change audit row), where it runs once, after the commit, and never for a rolled-back attempt. A\n * refusal's own audit row (written just before the hook throws) may stay where it is: nothing commits after it.\n *\n * STAYS_OUTSIDE_TRANSACTION records the opposite review: a hook must run outside any transaction (its answer depends on a\n * provider call, or on an audit row that has to exist before the operation answers), so the write stays best effort,\n * reported under its own reason rather than as unreviewed. Say why at the declaration.\n *\n * A registration with `transactionalCore: true` already runs its hooks in a transaction and needs neither. Refused beside an\n * `overrideAll` handler, which replaces the pipeline whose transaction this is about.\n */\nexport enum ResourceCustomServiceImplementationHookTransactionPosture {\n RUNS_INSIDE_TRANSACTION = 'runs_inside_transaction',\n STAYS_OUTSIDE_TRANSACTION = 'stays_outside_transaction',\n}\n/** @wildo_source:part:end saas.backend.custom-operation.hook-transaction-posture */\n\n/**\n * Fails before registration when `hookTransactionPosture` cannot mean anything (#2297): a value outside the vocabulary, or\n * one declared beside an `overrideAll` handler, which runs no framework pipeline and so no framework transaction.\n */\nexport function assertValidResourceCustomImplementationHookTransactionPosture(params: {\n operationPathKey: string;\n debugLabel?: string;\n modes: readonly ResourceOperation_CustomServiceImplementationMode[];\n hookTransactionPosture: unknown;\n}): void {\n if (params.hookTransactionPosture === undefined) return;\n const label = params.debugLabel ?? params.operationPathKey;\n if (!(Object.values(ResourceCustomServiceImplementationHookTransactionPosture) as unknown[]).includes(params.hookTransactionPosture)) {\n throw new Error(`[CustomImpl] Invalid hookTransactionPosture for registration \"${label}\" (${params.operationPathKey}): ${String(params.hookTransactionPosture)}`);\n }\n if (params.modes.includes(ResourceOperation_CustomServiceImplementationMode.OVERRIDE_ALL)) {\n throw new Error(`[CustomImpl] Invalid hookTransactionPosture for registration \"${label}\" (${params.operationPathKey}): an OVERRIDE_ALL implementation runs no framework pipeline, so no framework transaction`);\n }\n}\n\n/**\n * `maximumRowsWrittenPerAttempt` (#2297 wave 4): on a multi-row verb (`UPDATE_MANY` / `DELETE_MANY`) whose REPLACE handler\n * performs the write itself, the most rows of the operation's resource one attempt writes. The framework cannot chunk a\n * selection a hook makes, so this declaration is what bounds such a write's transaction: declared within\n * `MULTI_ROW_WRITE_ROWS_PER_TRANSACTION`, beside `hookTransactionPosture: RUNS_INSIDE_TRANSACTION`, the write is made\n * transactional and its audit row is kept through a crash. Declare it only when the handler cannot write more by\n * construction (a single-row update by a unique key, a page it bounds itself), and say why at the declaration.\n *\n * Refused unless it is a positive integer within the bound, and on a registration that does not REPLACE the core write\n * (the framework's own write is bounded by chunking instead, and a bound on a hook that does not write would bound nothing).\n */\nexport function assertValidResourceCustomImplementationMaximumRowsWrittenPerAttempt(params: {\n operationPathKey: string;\n debugLabel?: string;\n modes: readonly ResourceOperation_CustomServiceImplementationMode[];\n maximumRowsWrittenPerAttempt: unknown;\n rowsPerTransactionBound: number;\n}): void {\n if (params.maximumRowsWrittenPerAttempt === undefined) return;\n const label = params.debugLabel ?? params.operationPathKey;\n const value = params.maximumRowsWrittenPerAttempt;\n if (typeof value !== 'number' || !Number.isInteger(value) || value < 1 || value > params.rowsPerTransactionBound) {\n throw new Error(`[CustomImpl] Invalid maximumRowsWrittenPerAttempt for registration \"${label}\" (${params.operationPathKey}): ${String(value)} is not a positive integer within ${params.rowsPerTransactionBound}`);\n }\n if (!params.modes.includes(ResourceOperation_CustomServiceImplementationMode.REPLACE_CORE_OPERARTIONS)) {\n throw new Error(`[CustomImpl] Invalid maximumRowsWrittenPerAttempt for registration \"${label}\" (${params.operationPathKey}): only a REPLACE handler performs the write it would bound`);\n }\n}\n\n/**\n * Declares that an `overrideAll` handler records the operation's `RESOURCE_OPERATION_PERFORMED` row itself, so the\n * framework does not record a second one (#3151).\n *\n * An `overrideAll` replaces the framework pipeline, but not its audit duty: once the handler returns, the framework\n * records the row from the operation's declared risk (the same decision every other write takes), with the pre-image it\n * read, the request input, and the handler's response as the post-state. Before #3151 nothing did, so every HIGH or\n * CRITICAL verb written `overrideAll` left no row unless its author remembered to write one, which the risk floor exists\n * to make unnecessary (Wonder Ledger's close lifecycle verbs left none).\n *\n * Declare it only when the handler records a row the framework could not: the feature-administration writers record the\n * persisted overrides before and after, which the framework never sees, and a MEDIUM `enable` below the floor. Only\n * `true` is meaningful, and only beside an `overrideAll` handler: every other mode runs inside the framework pipeline,\n * whose row cannot be declined this way.\n */\nexport type ResourceCustomServiceImplementationOwnsOperationAuditRecord = true;\n\n/**\n * Fails before registration when `ownsOperationAuditRecord` cannot mean anything: a value other than `true`, or a\n * registration with no `overrideAll` handler (the framework pipeline records the row for every other mode).\n */\nexport function assertValidResourceCustomImplementationOperationAuditOwnership(params: {\n operationPathKey: string;\n debugLabel: string;\n modes: readonly ResourceOperation_CustomServiceImplementationMode[];\n ownsOperationAuditRecord: unknown;\n}): void {\n if (params.ownsOperationAuditRecord === undefined) return;\n if (params.ownsOperationAuditRecord !== true) {\n throw new Error(\n `[CustomImpl] Invalid ownsOperationAuditRecord for registration \"${params.debugLabel}\" `\n + `on operation \"${params.operationPathKey}\": only \\`true\\` may be declared.`,\n );\n }\n if (!params.modes.includes(ResourceOperation_CustomServiceImplementationMode.OVERRIDE_ALL)) {\n throw new Error(\n `[CustomImpl] Invalid ownsOperationAuditRecord for registration \"${params.debugLabel}\" `\n + `on operation \"${params.operationPathKey}\": only an overrideAll handler records its own operation audit row; `\n + 'every other mode runs inside the framework pipeline, which records it.',\n );\n }\n}\n\n/**\n * Fails before registration when a `postCommitEffectOwnership` declaration cannot be honoured.\n *\n * `IMPLEMENTATION_OUTBOX` tells the framework NOT to deliver the occurrence's audit row and notifications, on the\n * promise that the implementation enqueued them with the change. That promise is only true inside the operation's\n * transaction, so a registration that does not own the transactional core would suppress the effects with nothing\n * durable behind the suppression: a silent loss, which is the one outcome ownership exists to prevent.\n */\nexport function assertValidResourceCustomImplementationPostCommitEffectOwnership(params: {\n operationPathKey: string;\n debugLabel: string;\n transactionalCore: unknown;\n postCommitEffectOwnership: unknown;\n}): void {\n if (params.postCommitEffectOwnership === undefined) return;\n\n if (!Object.values(ResourceOperation_PostCommitEffectOwnership).includes(params.postCommitEffectOwnership as ResourceOperation_PostCommitEffectOwnership)) {\n throw new Error(\n `[CustomImpl] Invalid postCommitEffectOwnership for registration \"${params.debugLabel}\" `\n + `on operation \"${params.operationPathKey}\": must be a ResourceOperation_PostCommitEffectOwnership member.`,\n );\n }\n\n if (params.postCommitEffectOwnership === ResourceOperation_PostCommitEffectOwnership.IMPLEMENTATION_OUTBOX && params.transactionalCore !== true) {\n throw new Error(\n `[CustomImpl] Invalid postCommitEffectOwnership for registration \"${params.debugLabel}\" `\n + `on operation \"${params.operationPathKey}\": IMPLEMENTATION_OUTBOX requires transactionalCore=true, `\n + 'because the effects are only durable when they are enqueued in the transaction that commits the change.',\n );\n }\n}\n\n/**\n * Fails before registration when `authoritativeFields` cannot mean anything.\n *\n * The declaration only has an effect inside the PREFIX phase, so declaring it on an\n * implementation with no `prefixCoreOperations` handler is an authoring error that would\n * otherwise be silent — and silence is the exact failure mode this contract exists to remove.\n */\nexport function assertValidResourceCustomImplementationAuthoritativeFields(params: {\n operationPathKey: string;\n debugLabel: string;\n modes: readonly ResourceOperation_CustomServiceImplementationMode[];\n authoritativeFields: unknown;\n}): void {\n if (params.authoritativeFields === undefined) return;\n\n if (\n !Array.isArray(params.authoritativeFields)\n || params.authoritativeFields.length === 0\n || params.authoritativeFields.some((field) => typeof field !== 'string' || field.length === 0)\n ) {\n throw new Error(\n `[CustomImpl] Invalid authoritativeFields for registration \"${params.debugLabel}\" `\n + `on operation \"${params.operationPathKey}\": must be a non-empty array of non-empty field names.`,\n );\n }\n\n if (!params.modes.includes(ResourceOperation_CustomServiceImplementationMode.PREFIX_CORE_OPERARTIONS)) {\n throw new Error(\n `[CustomImpl] Invalid authoritativeFields for registration \"${params.debugLabel}\" `\n + `on operation \"${params.operationPathKey}\": the declaration only takes effect in the `\n + `PREFIX_CORE_OPERARTIONS phase, but this implementation declares no prefixCoreOperations handler.`,\n );\n }\n}\n\nexport type ResourceCustomServiceImplementationFactoryResult =\n ResourceCustomServiceImplementationFactoryResultBase\n & ResourceCustomServiceImplementationTransactionalCoreConfiguration;\n\n/**\n * Fails before registration/execution when transactional-core settings cannot\n * be honored by the custom implementation's declared modes.\n *\n * `OVERRIDE_ALL` replaces the whole operation pipeline and returns before the\n * framework reaches its core transaction. Treating that registration as\n * transactional would advertise an atomicity guarantee that can never exist.\n */\nexport function assertValidResourceCustomImplementationTransactionalCoreConfiguration(params: {\n operationPathKey: string;\n debugLabel: string;\n modes: readonly ResourceOperation_CustomServiceImplementationMode[];\n transactionalCore: unknown;\n transactionParticipants?: unknown;\n transactionalCoreConflictResolver?: unknown;\n transactionalCoreCommitOutcomeResolver?: unknown;\n}): void {\n if (typeof params.transactionalCore !== 'boolean') {\n throw new Error(\n `[CustomImpl] Invalid transactional-core configuration for registration \"${params.debugLabel}\" `\n + `on operation \"${params.operationPathKey}\": transactionalCore must be a boolean.`,\n );\n }\n\n const isPlainParticipantsRecord = (() => {\n if (\n params.transactionParticipants === null\n || typeof params.transactionParticipants !== 'object'\n || Array.isArray(params.transactionParticipants)\n ) {\n return false;\n }\n\n try {\n const prototype = Object.getPrototypeOf(params.transactionParticipants);\n return prototype === Object.prototype || prototype === null;\n } catch {\n return false;\n }\n })();\n\n if (\n params.transactionalCore\n && !isPlainParticipantsRecord\n ) {\n throw new Error(\n `[CustomImpl] Invalid transactional-core configuration for registration \"${params.debugLabel}\" `\n + `on operation \"${params.operationPathKey}\": transactionalCore=true requires an explicit `\n + 'plain-object transactionParticipants declaration (use {} for a single-resource transaction).',\n );\n }\n\n if (\n !params.transactionalCore\n && params.transactionParticipants !== undefined\n ) {\n throw new Error(\n `[CustomImpl] Invalid transactional-core configuration for registration \"${params.debugLabel}\" `\n + `on operation \"${params.operationPathKey}\": transactionParticipants requires `\n + 'transactionalCore=true.',\n );\n }\n\n if (\n isPlainParticipantsRecord\n && Object.entries(\n params.transactionParticipants as Readonly<Record<string, unknown>>,\n ).some(\n ([participantName, resourceType]) =>\n participantName.trim().length === 0\n || typeof resourceType !== 'string'\n || resourceType.trim().length === 0,\n )\n ) {\n throw new Error(\n `[CustomImpl] Invalid transactional-core configuration for registration \"${params.debugLabel}\" `\n + `on operation \"${params.operationPathKey}\": transactionParticipants must use `\n + 'non-empty semantic names and resource identifiers.',\n );\n }\n\n if (\n params.transactionalCoreConflictResolver !== undefined\n && typeof params.transactionalCoreConflictResolver !== 'function'\n ) {\n throw new Error(\n `[CustomImpl] Invalid transactional-core configuration for registration \"${params.debugLabel}\" `\n + `on operation \"${params.operationPathKey}\": transactionalCoreConflictResolver must be a function.`,\n );\n }\n\n if (\n params.transactionalCoreConflictResolver !== undefined\n && !params.transactionalCore\n ) {\n throw new Error(\n `[CustomImpl] Invalid transactional-core configuration for registration \"${params.debugLabel}\" `\n + `on operation \"${params.operationPathKey}\": transactionalCoreConflictResolver requires `\n + 'transactionalCore=true.',\n );\n }\n\n if (\n params.transactionalCoreCommitOutcomeResolver !== undefined\n && typeof params.transactionalCoreCommitOutcomeResolver !== 'function'\n ) {\n throw new Error(\n `[CustomImpl] Invalid transactional-core configuration for registration \"${params.debugLabel}\" `\n + `on operation \"${params.operationPathKey}\": transactionalCoreCommitOutcomeResolver must be a function.`,\n );\n }\n\n if (\n params.transactionalCoreCommitOutcomeResolver !== undefined\n && !params.transactionalCore\n ) {\n throw new Error(\n `[CustomImpl] Invalid transactional-core configuration for registration \"${params.debugLabel}\" `\n + `on operation \"${params.operationPathKey}\": transactionalCoreCommitOutcomeResolver requires `\n + 'transactionalCore=true.',\n );\n }\n\n if (\n params.transactionalCore\n && params.modes.includes(ResourceOperation_CustomServiceImplementationMode.OVERRIDE_ALL)\n ) {\n throw new Error(\n `[CustomImpl] Invalid transactional-core configuration for registration \"${params.debugLabel}\" `\n + `on operation \"${params.operationPathKey}\": transactionalCore=true cannot be combined with `\n + 'OVERRIDE_ALL because OVERRIDE_ALL returns before the framework core transaction.',\n );\n }\n\n /*\n * BEFORE_TRANSACTIONAL_CORE exists to keep an external effect OUT of a retryable transaction while its outcome still\n * feeds one (#535). Without an owned transactional core there is nothing for it to stand before, and the phase would\n * be a PREFIX with a misleading name — so its absence of a transaction is refused rather than tolerated.\n */\n if (\n params.modes.includes(ResourceOperation_CustomServiceImplementationMode.BEFORE_TRANSACTIONAL_CORE)\n && !params.transactionalCore\n ) {\n throw new Error(\n `[CustomImpl] Invalid transactional-core configuration for registration \"${params.debugLabel}\" `\n + `on operation \"${params.operationPathKey}\": beforeTransactionalCore requires transactionalCore=true, `\n + 'because the phase exists to run outside the transaction that the core then owns.',\n );\n }\n}\n\nexport type ResourceCustomServiceImplementationFactory = (\n resourcesRegistryService: ResourcesRegistryBackendService,\n container: Container,\n) => ResourceCustomServiceImplementationFactoryResult;\n\n\n\n\n\nexport function createResourceCustomServiceImplementation<\n TInput extends z.ZodSchema | undefined = (z.ZodAny | undefined),\n TOutput extends z.ZodSchema = z.ZodAny,\n>(params: {\n reconcileScheduled?: ResourceScheduledReconciler;\n /** Who may act on the operation's single target. See {@link ResourceCustomServiceImplementationTargetAuthority}. */\n authorizeTarget?: ResourceCustomServiceImplementationTargetAuthority;\n operationPath: ResourceConfiguration_OperationPath<any, any>;\n requestDtoSchema?: TInput;\n responseDtoSchema?: TOutput;\n handlers: AllHandlersType;\n /** Lower number = higher priority. Default: 100. */\n priority?: number;\n /** Per-mode override configuration. Default: all modes are chainable. */\n modeOverrides?: ModeOverrideConfig;\n /** Human-readable label for debug logging. Fallback: `{operationPathKey}@{priority}`. */\n debugLabel?: string;\n /** Fields whose value this implementation's PREFIX hook owns. See {@link ResourceCustomServiceImplementationAuthoritativeFields}. */\n authoritativeFields?: ResourceCustomServiceImplementationAuthoritativeFields;\n /** Who delivers the occurrence's audit row and notifications. See {@link ResourceOperation_PostCommitEffectOwnership}. */\n postCommitEffectOwnership?: ResourceOperation_PostCommitEffectOwnership;\n /** This `overrideAll` writes its own operation audit row. See {@link ResourceCustomServiceImplementationOwnsOperationAuditRecord}. */\n ownsOperationAuditRecord?: ResourceCustomServiceImplementationOwnsOperationAuditRecord;\n /** #2543: what the row must still hold for the core write to land. See the factory result's `coreWritePrecondition`. */\n coreWritePrecondition?: AdmissionWritePrecondition;\n /** #3279: the core write lands only on the row at the version the hooks read. See the factory result's field. */\n coreWritePinsRowVersion?: true;\n /** #2297: whether the hooks may run inside the transaction that keeps the audit row. See {@link ResourceCustomServiceImplementationHookTransactionPosture}. */\n hookTransactionPosture?: ResourceCustomServiceImplementationHookTransactionPosture;\n /** #2297 wave 4: the most rows one attempt of this REPLACE writes on a multi-row verb. See {@link assertValidResourceCustomImplementationMaximumRowsWrittenPerAttempt}. */\n maximumRowsWrittenPerAttempt?: number;\n} & ResourceCustomServiceImplementationTransactionalCoreConfiguration): ResourceCustomServiceImplementationFactoryResult & { implementation: ResourceOperationCustomImplementationBase<TInput, TOutput> } {\n const {\n reconcileScheduled,\n authorizeTarget,\n operationPath,\n requestDtoSchema,\n responseDtoSchema,\n handlers = {},\n priority,\n modeOverrides,\n debugLabel,\n authoritativeFields,\n postCommitEffectOwnership,\n ownsOperationAuditRecord,\n coreWritePrecondition,\n coreWritePinsRowVersion,\n hookTransactionPosture,\n maximumRowsWrittenPerAttempt,\n transactionalCore,\n transactionParticipants,\n transactionalCoreConflictResolver,\n transactionalCoreCommitOutcomeResolver,\n } = params;\n\n const getModeSchema = (mode: ResourceOperation_CustomServiceImplementationMode, inputOrOutput: 'input' | 'output') : z.ZodSchema | undefined => {\n\n if(inputOrOutput === 'input') {\n if(!requestDtoSchema) {\n if(mode === ResourceOperation_CustomServiceImplementationMode.REPLACE_CORE_OPERARTIONS) {\n return z.any();\n }\n return undefined;\n }\n if([\n ResourceOperation_CustomServiceImplementationMode.OVERRIDE_ALL,\n ResourceOperation_CustomServiceImplementationMode.BEFORE_TRANSACTIONAL_CORE,\n ResourceOperation_CustomServiceImplementationMode.PREFIX_CORE_OPERARTIONS,\n ResourceOperation_CustomServiceImplementationMode.REPLACE_CORE_OPERARTIONS,\n ].includes(mode)) {\n return requestDtoSchema;\n }\n return responseDtoSchema;\n } else {\n // A BEFORE_TRANSACTIONAL_CORE result is a framework disposition, not a DTO: the service tier validates its shape.\n if(!responseDtoSchema || mode === ResourceOperation_CustomServiceImplementationMode.BEFORE_TRANSACTIONAL_CORE) {\n return undefined;\n }\n if([\n ResourceOperation_CustomServiceImplementationMode.PREFIX_CORE_OPERARTIONS,\n ].includes(mode)) {\n return requestDtoSchema;\n }\n return responseDtoSchema;\n }\n }\n\n /**\n * The schema an `overrideAll` result is held to in a SUMMARY or CONTEXT read (#3177): that mode's response DTO, when\n * the operation answers its data modes itself (a LIST-like or a named read-like operation).\n *\n * An override that reads the core operation as a sub-call carries the caller's `dataMode` into it, as a nested read\n * does by default, so in SUMMARY mode it returns summary rows. An override's result never reaches the service tier's\n * `transformOutput`, so this parse is its only service-side check, and the controller then serializes it with\n * `selectResponseDto(operation, dataMode)`. This parse held it to the RAW `responseDtoSchema` instead, whose coerced\n * `createdAt` turned a summary row's absent date into an Invalid Date: Wonder\n * Procurement's \"Awaiting Your Decision\" queue answered 400 to the home page that lists it in summary mode.\n * `undefined` keeps the RAW parse: in RAW mode, and for an operation whose response is its own in every mode.\n */\n const dataModeOutputSchema = (\n mode: ResourceOperation_CustomServiceImplementationMode,\n executionContext: ExecutionContext<any>,\n utils: ResourceOperation_CustomImplementation_Utils,\n ): z.ZodSchema | undefined => {\n if (mode !== ResourceOperation_CustomServiceImplementationMode.OVERRIDE_ALL || !responseDtoSchema) return undefined;\n const dataMode = utils.serviceOptions?.dataMode;\n if (dataMode !== DataMode.SUMMARY && dataMode !== DataMode.CONTEXT) return undefined;\n // The execution context types its operation as a readonly view; the DTO utilities read it, never write it.\n const operation = executionContext.operation as ResourceConfiguration_Operation<any, any, any> | undefined;\n if (!operation || !ResourcesConfigOperationsDtosBuilderUtils.answersDataModesItself(operation)) return undefined;\n return ResourcesConfigOperationsDtosBuilderUtils.selectResponseDto(operation, dataMode) ?? undefined;\n };\n\n const key = ResourcesConfig_OperationPathUtils.createOperationPathKey(operationPath);\n\n const executeHandler = async <\n TMode extends ResourceOperation_CustomServiceImplementationMode,\n TInput extends z.ZodSchema | undefined = z.ZodAny | undefined,\n TOutput extends z.ZodSchema = z.ZodAny,\n TAugment extends object|undefined = undefined\n>(\n handler: AnyHandlerType<TMode, TInput, TOutput, TAugment> | undefined,\n handlerName : string,\n mode: ResourceOperation_CustomServiceImplementationMode,\n _id: string | undefined,\n input: ResourceOperationCustomImplementation_InputTypeOf<TMode, TInput, TOutput, TAugment>,\n executionContext: ExecutionContext<any>,\n utils : ResourceOperation_CustomImplementation_Utils,\n\n) : Promise<ResourceOperationCustomImplementation_OutputTypeOf<TMode, TInput, TOutput, TAugment>> => {\n\n\n if (!handler)\n throw utils.errorBuilder.buildError(ErrorType.CONFIGURATION, executionContext, {\n customMessageReference : ErrorCustomMessageReference.RESOURCE_OPERATION_CUSTOM_IMPLEMENTATION_NOT_IMPLEMENTED,\n context : {\n message: `${handlerName} has not been defined in handlers`,\n }\n });\n\n // The JSON form of the authored schema (#3478): over HTTP the controller has already read the body's dates, but an\n // operation run again from the queue (`job-executor`) hands this the job's JSON, whose dates are RFC 3339 strings.\n const authoredInputSchema = getModeSchema(mode, 'input');\n const inputSchema = authoredInputSchema ? jsonParsingSchemaOf(authoredInputSchema) : authoredInputSchema;\n const inputParsed = parseResourceOperation_CustomServiceImplementationSchema(\n mode, 'input',\n inputSchema,\n input,\n utils.errorBuilder,\n ) as ResourceOperationCustomImplementation_InputTypeOf<TMode, TInput, TOutput, TAugment>;\n\n\n const output = await (handler as AnyHandlerType<TMode, TInput, TOutput, TAugment>)(_id, inputParsed, executionContext, operationPath, utils);\n\n const outputSchema = dataModeOutputSchema(mode, executionContext, utils) ?? getModeSchema(mode, 'output');\n return parseResourceOperation_CustomServiceImplementationSchema(\n mode, 'output',\n outputSchema,\n output,\n utils.errorBuilder,\n ) as ResourceOperationCustomImplementation_OutputTypeOf<TMode, TInput, TOutput, TAugment>;\n }\n\n\n class Impl extends ResourceOperationCustomImplementationBase<TInput, TOutput> {\n\n public getPlaceholders(): ResourceOperation_CustomServiceImplementationMode[] {\n const modes: ResourceOperation_CustomServiceImplementationMode[] = [];\n if (handlers.overrideAll) modes.push(ResourceOperation_CustomServiceImplementationMode.OVERRIDE_ALL);\n if (handlers.beforeTransactionalCore) modes.push(ResourceOperation_CustomServiceImplementationMode.BEFORE_TRANSACTIONAL_CORE);\n if (handlers.prefixCoreOperations) modes.push(ResourceOperation_CustomServiceImplementationMode.PREFIX_CORE_OPERARTIONS);\n if (handlers.replaceCoreOperations) modes.push(ResourceOperation_CustomServiceImplementationMode.REPLACE_CORE_OPERARTIONS);\n if (handlers.postfixCoreOperations) modes.push(ResourceOperation_CustomServiceImplementationMode.POSTFIX_CORE_OPERARTIONS);\n if (handlers.afterUserNotifications) modes.push(ResourceOperation_CustomServiceImplementationMode.AFTER_USER_NOTIFICATIONS);\n if (handlers.atTheEnd) modes.push(ResourceOperation_CustomServiceImplementationMode.AT_THE_END);\n return modes;\n }\n\n public async overrideAll(\n _id: string | undefined,\n input: ResourceOperationCustomImplementation_InputTypeOf<ResourceOperation_CustomServiceImplementationMode.OVERRIDE_ALL, TInput, TOutput>,\n executionContext: ExecutionContext<any>,\n utils: ResourceOperation_CustomImplementation_Utils\n ): Promise<ResourceOperationCustomImplementation_OutputTypeOf<\n ResourceOperation_CustomServiceImplementationMode.OVERRIDE_ALL,\n TInput, TOutput\n >> {\n\n return executeHandler<ResourceOperation_CustomServiceImplementationMode.OVERRIDE_ALL, TInput, TOutput>(\n handlers.overrideAll,\n 'overrideAll',\n ResourceOperation_CustomServiceImplementationMode.OVERRIDE_ALL,\n _id, input, executionContext, utils);\n }\n\n public async beforeTransactionalCore(\n _id: string | undefined,\n input: ResourceOperationCustomImplementation_InputTypeOf<ResourceOperation_CustomServiceImplementationMode.BEFORE_TRANSACTIONAL_CORE, TInput, TOutput>,\n executionContext: ExecutionContext<any>,\n utils: ResourceOperation_CustomImplementation_Utils\n ): Promise<ResourceOperationBeforeTransactionalCoreResult> {\n\n return executeHandler<ResourceOperation_CustomServiceImplementationMode.BEFORE_TRANSACTIONAL_CORE, TInput, TOutput>(\n handlers.beforeTransactionalCore,\n 'beforeTransactionalCore',\n ResourceOperation_CustomServiceImplementationMode.BEFORE_TRANSACTIONAL_CORE,\n _id, input, executionContext, utils);\n }\n\n public async prefixCoreOperations<TAugment extends object|undefined = undefined>(\n _id: string | undefined,\n input: ResourceOperationCustomImplementation_InputTypeOf<ResourceOperation_CustomServiceImplementationMode.PREFIX_CORE_OPERARTIONS, TInput, TOutput, TAugment>,\n executionContext: ExecutionContext<any>,\n utils: ResourceOperation_CustomImplementation_Utils\n ): Promise<ResourceOperationCustomImplementation_OutputTypeOf<\n ResourceOperation_CustomServiceImplementationMode.PREFIX_CORE_OPERARTIONS,\n TInput, TOutput, TAugment\n >> {\n\n return executeHandler<ResourceOperation_CustomServiceImplementationMode.PREFIX_CORE_OPERARTIONS, TInput, TOutput, TAugment>(\n handlers.prefixCoreOperations as AnyHandlerType<ResourceOperation_CustomServiceImplementationMode.PREFIX_CORE_OPERARTIONS, TInput, TOutput, TAugment> | undefined,\n 'prefixCoreOperations',\n ResourceOperation_CustomServiceImplementationMode.PREFIX_CORE_OPERARTIONS,\n _id, input, executionContext, utils);\n }\n\n public async replaceCoreOperations<TAugment extends object|undefined = undefined>(\n _id: string | undefined,\n input: ResourceOperationCustomImplementation_InputTypeOf<ResourceOperation_CustomServiceImplementationMode.REPLACE_CORE_OPERARTIONS, TInput, TOutput, TAugment>,\n executionContext: ExecutionContext<any>,\n utils: ResourceOperation_CustomImplementation_Utils\n ): Promise<ResourceOperationCustomImplementation_OutputTypeOf<\n ResourceOperation_CustomServiceImplementationMode.REPLACE_CORE_OPERARTIONS,\n TInput, TOutput, TAugment\n >> {\n\n return executeHandler<ResourceOperation_CustomServiceImplementationMode.REPLACE_CORE_OPERARTIONS, TInput, TOutput, TAugment>(\n handlers.replaceCoreOperations as AnyHandlerType<ResourceOperation_CustomServiceImplementationMode.REPLACE_CORE_OPERARTIONS, TInput, TOutput, TAugment> | undefined,\n 'replaceCoreOperations',\n ResourceOperation_CustomServiceImplementationMode.REPLACE_CORE_OPERARTIONS,\n _id, input, executionContext, utils);\n }\n\n public async postfixCoreOperations(\n _id: string | undefined,\n input: ResourceOperationCustomImplementation_InputTypeOf<ResourceOperation_CustomServiceImplementationMode.POSTFIX_CORE_OPERARTIONS, TInput, TOutput>,\n executionContext: ExecutionContext<any>,\n utils: ResourceOperation_CustomImplementation_Utils\n ): Promise<ResourceOperationCustomImplementation_OutputTypeOf<\n ResourceOperation_CustomServiceImplementationMode.POSTFIX_CORE_OPERARTIONS,\n TInput, TOutput\n >> {\n\n return executeHandler<ResourceOperation_CustomServiceImplementationMode.POSTFIX_CORE_OPERARTIONS, TInput, TOutput>(\n handlers.postfixCoreOperations,\n 'postfixCoreOperations',\n ResourceOperation_CustomServiceImplementationMode.POSTFIX_CORE_OPERARTIONS,\n _id, input, executionContext, utils);\n }\n\n public async afterUserNotifications(\n _id: string | undefined,\n input: ResourceOperationCustomImplementation_InputTypeOf<ResourceOperation_CustomServiceImplementationMode.AFTER_USER_NOTIFICATIONS, TInput, TOutput>,\n executionContext: ExecutionContext<any>,\n utils: ResourceOperation_CustomImplementation_Utils\n ): Promise<ResourceOperationCustomImplementation_OutputTypeOf<\n ResourceOperation_CustomServiceImplementationMode.AFTER_USER_NOTIFICATIONS,\n TInput, TOutput\n >> {\n\n return executeHandler<ResourceOperation_CustomServiceImplementationMode.AFTER_USER_NOTIFICATIONS, TInput, TOutput>(\n handlers.afterUserNotifications,\n 'afterUserNotifications',\n ResourceOperation_CustomServiceImplementationMode.AFTER_USER_NOTIFICATIONS,\n _id, input, executionContext, utils);\n }\n\n public async atTheEnd(\n _id: string | undefined,\n input: ResourceOperationCustomImplementation_InputTypeOf<ResourceOperation_CustomServiceImplementationMode.AT_THE_END, TInput, TOutput>,\n executionContext: ExecutionContext<any>,\n utils: ResourceOperation_CustomImplementation_Utils\n ): Promise<ResourceOperationCustomImplementation_OutputTypeOf<\n ResourceOperation_CustomServiceImplementationMode.AT_THE_END,\n TInput, TOutput\n >> {\n\n return executeHandler<ResourceOperation_CustomServiceImplementationMode.AT_THE_END, TInput, TOutput>(\n handlers.atTheEnd,\n 'atTheEnd',\n ResourceOperation_CustomServiceImplementationMode.AT_THE_END,\n _id, input, executionContext, utils);\n }\n }\n\n const implementation = new Impl();\n const authoredTransactionalCore: unknown =\n transactionalCore === undefined ? false : transactionalCore;\n const normalizedTransactionalCore = authoredTransactionalCore === true;\n const normalizedDebugLabel = debugLabel ?? `${key}@${priority ?? 100}`;\n\n assertValidResourceCustomImplementationTransactionalCoreConfiguration({\n operationPathKey: key,\n debugLabel: normalizedDebugLabel,\n modes: implementation.getPlaceholders(),\n transactionalCore: authoredTransactionalCore,\n transactionParticipants,\n transactionalCoreConflictResolver,\n transactionalCoreCommitOutcomeResolver,\n });\n\n assertValidResourceCustomImplementationAuthoritativeFields({\n operationPathKey: key,\n debugLabel: normalizedDebugLabel,\n modes: implementation.getPlaceholders(),\n authoritativeFields,\n });\n\n assertValidResourceCustomImplementationPostCommitEffectOwnership({\n operationPathKey: key,\n debugLabel: normalizedDebugLabel,\n transactionalCore: authoredTransactionalCore,\n postCommitEffectOwnership,\n });\n\n assertValidResourceCustomImplementationOperationAuditOwnership({\n operationPathKey: key,\n debugLabel: normalizedDebugLabel,\n modes: implementation.getPlaceholders(),\n ownsOperationAuditRecord,\n });\n\n const transactionalCoreConfiguration: ResourceCustomServiceImplementationTransactionalCoreConfiguration =\n transactionalCore === true\n ? {\n transactionalCore: true,\n transactionParticipants: Object.freeze({\n ...transactionParticipants,\n }),\n transactionalCoreConflictResolver,\n transactionalCoreCommitOutcomeResolver,\n }\n : {\n transactionalCore,\n };\n\n return {\n operationPathKey: key,\n reconcileScheduled,\n ...(authorizeTarget ? { authorizeTarget } : {}),\n implementation,\n priority,\n modeOverrides,\n debugLabel,\n // Frozen: the allow-list is consulted on every write through this operation, and a mutable\n // shared array would let one call site widen what another may persist.\n ...(authoritativeFields ? { authoritativeFields: Object.freeze([...authoritativeFields]) } : {}),\n ...(postCommitEffectOwnership ? { postCommitEffectOwnership } : {}),\n ...(ownsOperationAuditRecord ? { ownsOperationAuditRecord } : {}),\n ...(coreWritePrecondition ? { coreWritePrecondition: freezeCoreWritePrecondition(coreWritePrecondition, key, normalizedDebugLabel, implementation.getPlaceholders()) } : {}),\n ...(coreWritePinsRowVersion ? { coreWritePinsRowVersion: assertCoreWriteRuns(key, normalizedDebugLabel, implementation.getPlaceholders()) } : {}),\n ...(hookTransactionPosture !== undefined ? { hookTransactionPosture } : {}),\n ...(maximumRowsWrittenPerAttempt !== undefined ? { maximumRowsWrittenPerAttempt } : {}),\n ...transactionalCoreConfiguration,\n };\n}\n\n/** An OVERRIDE_ALL implementation runs no core write, so a pin declared on one would read as protection that is not there. */\nexport function assertCoreWriteRuns(\n operationPathKey: string,\n debugLabel: string | undefined,\n modes: readonly ResourceOperation_CustomServiceImplementationMode[],\n): true {\n if (modes.includes(ResourceOperation_CustomServiceImplementationMode.OVERRIDE_ALL)) {\n throw new Error(`[CustomImpl] Invalid coreWritePinsRowVersion for registration \"${debugLabel ?? operationPathKey}\" (${operationPathKey}): an OVERRIDE_ALL implementation runs no core write for it to fence`);\n }\n return true;\n}\n\n/**\n * Validates and freezes a registration's `coreWritePrecondition` (#2543). Refused when it cannot mean anything: an empty\n * map, a field with no admitted value (no row could ever satisfy it, so the operation could never land), a value that\n * is not a string, number, boolean or null (an equality only those compile to identically on every adapter), or an\n * OVERRIDE_ALL registration (it replaces the pipeline, so no core write exists to carry it, and the declaration would read\n * as protection that is not there).\n */\nexport function freezeCoreWritePrecondition(\n precondition: AdmissionWritePrecondition,\n operationPathKey: string,\n debugLabel: string | undefined,\n modes: readonly ResourceOperation_CustomServiceImplementationMode[],\n): AdmissionWritePrecondition {\n const refuse = (why: string): never => {\n throw new Error(`[CustomImpl] Invalid coreWritePrecondition for registration \"${debugLabel ?? operationPathKey}\" (${operationPathKey}): ${why}`);\n };\n if (modes.includes(ResourceOperation_CustomServiceImplementationMode.OVERRIDE_ALL)) {\n refuse('an OVERRIDE_ALL implementation runs no core write for it to fence');\n }\n if (!precondition || typeof precondition !== 'object' || Array.isArray(precondition)) refuse('it must be a map of field to admitted values');\n const entries = Object.entries(precondition);\n if (entries.length === 0) refuse('it constrains no field');\n for (const [field, values] of entries) {\n if (!Array.isArray(values) || values.length === 0) refuse(`field \"${field}\" admits no value, so the write could never land`);\n for (const value of values) {\n if (value !== null && typeof value !== 'string' && typeof value !== 'boolean' && !(typeof value === 'number' && Number.isFinite(value))) {\n refuse(`field \"${field}\" admits a value that is not a string, number, boolean or null`);\n }\n }\n }\n return Object.freeze(Object.fromEntries(entries.map(([field, values]) => [field, Object.freeze([...values])])));\n}\n"]}
|
|
@@ -126,6 +126,12 @@ export declare enum PlainAuditedWriteDurability {
|
|
|
126
126
|
* A write with custom implementations is included when EVERY registration declares its hooks
|
|
127
127
|
* `RUNS_INSIDE_TRANSACTION` (wave 3): each was read, and does nothing outside the database before the commit
|
|
128
128
|
* (`ResourceCustomServiceImplementationHookTransactionPosture`).
|
|
129
|
+
*
|
|
130
|
+
* A multi-row UPDATE_MANY / DELETE_MANY is included once its rows per transaction are BOUNDED by
|
|
131
|
+
* {@link MULTI_ROW_WRITE_ROWS_PER_TRANSACTION} (wave 4): the framework performs a hook-less core one in chunks of at most
|
|
132
|
+
* that many rows, each chunk its own transactional attempt with its own audit row
|
|
133
|
+
* ({@link isFrameworkChunkedMultiRowWrite}); a registration that performs the write itself is included when it declares
|
|
134
|
+
* how many rows one attempt writes (`maximumRowsWrittenPerAttempt`), within the same bound.
|
|
129
135
|
*/
|
|
130
136
|
TRANSACTION_FOR_AUDIT_ROW = "transaction_for_audit_row",
|
|
131
137
|
/**
|
|
@@ -148,9 +154,12 @@ export declare enum PlainAuditedWriteDurability {
|
|
|
148
154
|
*/
|
|
149
155
|
BEST_EFFORT_OVERRIDE_ALL = "best_effort_override_all",
|
|
150
156
|
/**
|
|
151
|
-
* A multi-row write (`CREATE_MANY`, `UPDATE_MANY`, `DELETE_MANY`)
|
|
152
|
-
*
|
|
153
|
-
*
|
|
157
|
+
* A multi-row write (`CREATE_MANY`, `UPDATE_MANY`, `DELETE_MANY`) whose rows per transaction nothing bounds: not a
|
|
158
|
+
* synchronous bulk operation (bounded by its request, and already transactional), not a hook-less core UPDATE_MANY /
|
|
159
|
+
* DELETE_MANY the framework chunks, and not a registration that declares how many rows it writes. One transaction could
|
|
160
|
+
* hold an unbounded number of rows and outlive the store's transaction limits (MongoDB aborts a transaction after 60
|
|
161
|
+
* seconds by default). Since wave 4 its members are the writes whose selection a HOOK decides (a purge selecting its own
|
|
162
|
+
* population), which a framework bound cannot reach, and `CREATE_MANY`.
|
|
154
163
|
*/
|
|
155
164
|
BEST_EFFORT_UNBOUNDED_MULTI_ROW = "best_effort_unbounded_multi_row",
|
|
156
165
|
/**
|
|
@@ -175,6 +184,32 @@ export declare enum PlainAuditedWriteDurability {
|
|
|
175
184
|
* makes transactional.
|
|
176
185
|
*/
|
|
177
186
|
export declare function classifyPlainAuditedWriteDurability(operation: ResourceConfiguration_Operation<any, any, any>, registrations: readonly ResourceOperationCustomImplementationRegistration[]): PlainAuditedWriteDurability | undefined;
|
|
187
|
+
/**
|
|
188
|
+
* The most rows one transactional attempt of a multi-row write may hold (#2297 wave 4): 100, the bound a synchronous bulk
|
|
189
|
+
* operation already enforces on its request (`BULK_OPERATION_DEFAULT_MAX_SELECTION`), and so the one bound the framework
|
|
190
|
+
* already holds a synchronous multi-row transaction to. Decided by this repository's own principle (one bound for one
|
|
191
|
+
* concern) rather than by a new number:
|
|
192
|
+
* - MongoDB aborts a transaction that runs a minute; spec-cite: MongoDB Manual, "Production Considerations", Runtime Limit
|
|
193
|
+
* (https://www.mongodb.com/docs/manual/core/transactions-production-consideration/, quoted: "By default, a transaction
|
|
194
|
+
* must have a runtime of less than one minute."). Removing 10,000 rows' targets was measured at 19 s (MongoDB) and 37 s
|
|
195
|
+
* (PostgreSQL) in one transaction (#2864), so 100 rows is two orders of magnitude inside the limit.
|
|
196
|
+
* - it is NOT what makes a bulk write's guards complete, and must not be read as such: the RESTRICT and legal-hold refusals
|
|
197
|
+
* and the pre-hook snapshots read EVERY target (`loadBulkTargetResources`, a listing with no paging options, which both
|
|
198
|
+
* adapters answer whole), whatever the chunk size, including a nested write the chunking never splits (#3698).
|
|
199
|
+
* Above it, the write is performed in CHUNKS, each its own transaction and its own audit row naming its rows, which is how
|
|
200
|
+
* the framework's own sweeps already delete (`resource-retention-sweep`, `retention-class-sweep`); rejected: refusing a
|
|
201
|
+
* selection above the bound, which would break every internal caller that removes a population (a transposition, a
|
|
202
|
+
* cascade of a large tenant) for a limit that only exists to keep one transaction short.
|
|
203
|
+
*/
|
|
204
|
+
export declare const MULTI_ROW_WRITE_ROWS_PER_TRANSACTION: number;
|
|
205
|
+
/**
|
|
206
|
+
* Whether the FRAMEWORK performs this multi-row write itself and can therefore chunk it (#2297 wave 4): the core
|
|
207
|
+
* `UPDATE_MANY` / `DELETE_MANY` operation itself (not a custom verb borrowing it), answering the core response (no
|
|
208
|
+
* `customResponseDto`, so chunk answers merge: rows concatenate, deleted ids concatenate and their counts add), with no
|
|
209
|
+
* custom registration (nothing but the framework reads the selection it rewrites per chunk), and not a synchronous bulk
|
|
210
|
+
* operation (bounded by its request already). `ServiceResourceBackendService.doOperation` chunks exactly these.
|
|
211
|
+
*/
|
|
212
|
+
export declare function isFrameworkChunkedMultiRowWrite(operation: ResourceConfiguration_Operation<any, any, any>, registrations: readonly ResourceOperationCustomImplementationRegistration[]): boolean;
|
|
178
213
|
/**
|
|
179
214
|
* What the process can do for a resource's writes, asked by both callers of
|
|
180
215
|
* {@link resolveResourceOperationTransactionPersistenceContract} (startup validation and `doOperation`) through the same
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resource-operation-transaction-persistence.backend.utils.d.ts","sourceRoot":"","sources":["../../../../../src/base-classes/services/services/resource-operation-transaction-persistence.backend.utils.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"resource-operation-transaction-persistence.backend.utils.d.ts","sourceRoot":"","sources":["../../../../../src/base-classes/services/services/resource-operation-transaction-persistence.backend.utils.ts"],"names":[],"mappings":"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"}
|