@openlup/platform 0.26.0 → 0.28.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +305 -327
- package/README.md +332 -16
- package/dist/account-support/accountReadFacade.d.ts +8 -0
- package/dist/account-support/accountReadFacade.js +10 -0
- package/dist/account-support/accountReadModels.d.ts +69 -0
- package/dist/account-support/accountReadModels.js +272 -0
- package/dist/account-support/bindings.d.ts +23 -0
- package/dist/account-support/bindings.js +16 -0
- package/dist/account-support/contracts/account.d.ts +281 -0
- package/dist/account-support/contracts/account.js +1 -0
- package/dist/account-support/contracts/capabilities.d.ts +44 -0
- package/dist/account-support/contracts/capabilities.js +1 -0
- package/dist/account-support/contracts/commands.d.ts +307 -0
- package/dist/account-support/contracts/commands.js +1 -0
- package/dist/account-support/contracts/customer360.d.ts +154 -0
- package/dist/account-support/contracts/customer360.js +1 -0
- package/dist/account-support/contracts/index.d.ts +10 -0
- package/dist/account-support/contracts/index.js +1 -0
- package/dist/account-support/contracts/invoice.d.ts +79 -0
- package/dist/account-support/contracts/invoice.js +1 -0
- package/dist/account-support/contracts/operator.d.ts +289 -0
- package/dist/account-support/contracts/operator.js +1 -0
- package/dist/account-support/contribution.d.ts +24 -0
- package/dist/account-support/contribution.js +22 -0
- package/dist/account-support/customer360.d.ts +106 -0
- package/dist/account-support/customer360.js +163 -0
- package/dist/account-support/customerAccountReadDiagnostics.d.ts +11 -0
- package/dist/account-support/customerAccountReadDiagnostics.js +71 -0
- package/dist/account-support/index.d.ts +26 -0
- package/dist/account-support/index.js +15 -0
- package/dist/account-support/invoiceAccess.d.ts +57 -0
- package/dist/account-support/invoiceAccess.js +40 -0
- package/dist/account-support/migrations.d.ts +14 -0
- package/dist/account-support/migrations.js +7 -0
- package/dist/account-support/operatorAuthority.d.ts +67 -0
- package/dist/account-support/operatorAuthority.js +379 -0
- package/dist/account-support/operatorRecovery.d.ts +66 -0
- package/dist/account-support/operatorRecovery.js +129 -0
- package/dist/account-support/orderHistory.d.ts +50 -0
- package/dist/account-support/orderHistory.js +188 -0
- package/dist/account-support/paymentMethodComposition.d.ts +5 -0
- package/dist/account-support/paymentMethodComposition.js +4 -0
- package/dist/account-support/postgresOperatorAuthority.d.ts +16 -0
- package/dist/account-support/postgresOperatorAuthority.js +93 -0
- package/dist/account-support/selfService.d.ts +6 -0
- package/dist/account-support/selfService.js +81 -0
- package/dist/account-support/subscriptionCommandCodec.d.ts +10 -0
- package/dist/account-support/subscriptionCommandCodec.js +38 -0
- package/dist/catalog/draftSchemas.d.ts +1 -1
- package/dist/catalog/foundationSchemas.d.ts +3 -3
- package/dist/catalog/resolvedSkuProjection.d.ts +2 -2
- package/dist/catalog/sellableSchemas.d.ts +2 -2
- package/dist/commerce/adapters/managed/commerceOmsControlPlane.d.ts +3 -0
- package/dist/commerce/adapters/managed/commerceOmsControlPlane.js +71 -0
- package/dist/commerce/adapters/managed/commerceOmsMutations.d.ts +10 -0
- package/dist/commerce/adapters/managed/commerceOmsMutations.js +119 -0
- package/dist/commerce/adapters/managed/commerceOmsPort.d.ts +28 -0
- package/dist/commerce/adapters/managed/commerceOmsPort.js +101 -0
- package/dist/commerce/adapters/managed/oms/accounting.d.ts +3 -0
- package/dist/commerce/adapters/managed/oms/accounting.js +13 -0
- package/dist/commerce/adapters/managed/oms/fulfillmentReads.d.ts +17 -0
- package/dist/commerce/adapters/managed/oms/fulfillmentReads.js +81 -0
- package/dist/commerce/adapters/managed/oms/inboundEvents.d.ts +9 -0
- package/dist/commerce/adapters/managed/oms/inboundEvents.js +40 -0
- package/dist/commerce/adapters/managed/oms/outboxEvents.d.ts +2 -0
- package/dist/commerce/adapters/managed/oms/outboxEvents.js +23 -0
- package/dist/commerce/adapters/managed/oms/paymentAttempts.d.ts +3 -0
- package/dist/commerce/adapters/managed/oms/paymentAttempts.js +15 -0
- package/dist/commerce/adapters/managed/oms/queueSelection.d.ts +12 -0
- package/dist/commerce/adapters/managed/oms/queueSelection.js +109 -0
- package/dist/commerce/adapters/managed/oms/readProjections.d.ts +18 -0
- package/dist/commerce/adapters/managed/oms/readProjections.js +13 -0
- package/dist/commerce/adapters/managed/oms/readQueries.d.ts +16 -0
- package/dist/commerce/adapters/managed/oms/readQueries.js +276 -0
- package/dist/commerce/adapters/managed/oms/types.d.ts +2 -0
- package/dist/commerce/adapters/managed/oms/types.js +7 -0
- package/dist/commerce/checkoutCommandSchemas.d.ts +89 -0
- package/dist/commerce/checkoutCommandSchemas.js +70 -0
- package/dist/commerce/checkoutHelpers.d.ts +21 -0
- package/dist/commerce/checkoutHelpers.js +29 -0
- package/dist/commerce/checkoutResumeSchemas.d.ts +158 -0
- package/dist/commerce/checkoutResumeSchemas.js +145 -0
- package/dist/commerce/checkoutSchemas.d.ts +158 -0
- package/dist/commerce/checkoutSchemas.js +161 -0
- package/dist/commerce/commerceReturnsPort.d.ts +97 -0
- package/dist/commerce/commerceReturnsPort.js +39 -0
- package/dist/commerce/configuratorIntentPersistenceSchemas.d.ts +20 -0
- package/dist/commerce/configuratorIntentPersistenceSchemas.js +21 -0
- package/dist/commerce/configuratorIntentSchemas.d.ts +63 -0
- package/dist/commerce/configuratorIntentSchemas.js +43 -0
- package/dist/commerce/contractPrimitives.d.ts +50 -0
- package/dist/commerce/contractPrimitives.js +25 -0
- package/dist/commerce/contracts/availability.d.ts +23 -0
- package/dist/commerce/contracts/availability.js +1 -0
- package/dist/commerce/contracts/fulfillmentRecovery.d.ts +25 -0
- package/dist/commerce/contracts/fulfillmentRecovery.js +1 -0
- package/dist/commerce/contracts/index.d.ts +13 -0
- package/dist/commerce/contracts/index.js +1 -0
- package/dist/commerce/contracts/intent.d.ts +86 -0
- package/dist/commerce/contracts/intent.js +1 -0
- package/dist/commerce/contracts/omsTypes.d.ts +1216 -0
- package/dist/commerce/contracts/omsTypes.js +1 -0
- package/dist/commerce/contracts/order.d.ts +39 -0
- package/dist/commerce/contracts/order.js +1 -0
- package/dist/commerce/contracts/orderMoney.d.ts +52 -0
- package/dist/commerce/contracts/orderMoney.js +1 -0
- package/dist/commerce/contracts/ports.d.ts +113 -0
- package/dist/commerce/contracts/ports.js +1 -0
- package/dist/commerce/contracts/recovery.d.ts +11 -0
- package/dist/commerce/contracts/recovery.js +1 -0
- package/dist/commerce/contracts/runtimePorts.d.ts +196 -0
- package/dist/commerce/contracts/runtimePorts.js +1 -0
- package/dist/commerce/contracts/state.d.ts +26 -0
- package/dist/commerce/contracts/state.js +43 -0
- package/dist/commerce/customerDefaultsSnapshotSchemas.d.ts +51 -0
- package/dist/commerce/customerDefaultsSnapshotSchemas.js +106 -0
- package/dist/commerce/errors.d.ts +18 -0
- package/dist/commerce/errors.js +36 -0
- package/dist/commerce/fulfillmentEligibility.d.ts +6 -0
- package/dist/commerce/fulfillmentEligibility.js +31 -0
- package/dist/commerce/index.d.ts +72 -0
- package/dist/commerce/index.js +67 -0
- package/dist/commerce/model/customerFulfillmentRecovery.d.ts +40 -0
- package/dist/commerce/model/customerFulfillmentRecovery.js +144 -0
- package/dist/commerce/model/fulfillmentCancellationEligibility.d.ts +7 -0
- package/dist/commerce/model/fulfillmentCancellationEligibility.js +9 -0
- package/dist/commerce/model/omsAccountingVisibility.d.ts +12 -0
- package/dist/commerce/model/omsAccountingVisibility.js +118 -0
- package/dist/commerce/model/omsBillingInvoiceBuyer.d.ts +2 -0
- package/dist/commerce/model/omsBillingInvoiceBuyer.js +15 -0
- package/dist/commerce/model/omsCurrency.d.ts +4 -0
- package/dist/commerce/model/omsCurrency.js +5 -0
- package/dist/commerce/model/omsFulfillmentDebug.d.ts +20 -0
- package/dist/commerce/model/omsFulfillmentDebug.js +122 -0
- package/dist/commerce/model/omsFulfillmentSummary.d.ts +16 -0
- package/dist/commerce/model/omsFulfillmentSummary.js +189 -0
- package/dist/commerce/model/omsListTotals.d.ts +13 -0
- package/dist/commerce/model/omsListTotals.js +32 -0
- package/dist/commerce/model/omsOperationalLadder.d.ts +51 -0
- package/dist/commerce/model/omsOperationalLadder.js +158 -0
- package/dist/commerce/model/omsOrderLineMoney.d.ts +4 -0
- package/dist/commerce/model/omsOrderLineMoney.js +25 -0
- package/dist/commerce/model/omsPaymentMethodSummary.d.ts +5 -0
- package/dist/commerce/model/omsPaymentMethodSummary.js +11 -0
- package/dist/commerce/model/omsReadModel.d.ts +43 -0
- package/dist/commerce/model/omsReadModel.js +211 -0
- package/dist/commerce/model/omsReadModelCommunication.d.ts +3 -0
- package/dist/commerce/model/omsReadModelCommunication.js +29 -0
- package/dist/commerce/model/omsReadModelHelpers.d.ts +125 -0
- package/dist/commerce/model/omsReadModelHelpers.js +212 -0
- package/dist/commerce/model/omsReadModelList.d.ts +33 -0
- package/dist/commerce/model/omsReadModelList.js +50 -0
- package/dist/commerce/model/omsReadModelListSummary.d.ts +3 -0
- package/dist/commerce/model/omsReadModelListSummary.js +13 -0
- package/dist/commerce/model/omsReadModelPricing.d.ts +5 -0
- package/dist/commerce/model/omsReadModelPricing.js +36 -0
- package/dist/commerce/model/omsReadModelProjections.d.ts +1 -0
- package/dist/commerce/model/omsReadModelProjections.js +1 -0
- package/dist/commerce/model/omsReadModelRowCore.d.ts +79 -0
- package/dist/commerce/model/omsReadModelRowCore.js +149 -0
- package/dist/commerce/model/omsReadModelRows.d.ts +1 -0
- package/dist/commerce/model/omsReadModelRows.js +6 -0
- package/dist/commerce/offerAvailability.d.ts +18 -0
- package/dist/commerce/offerAvailability.js +53 -0
- package/dist/commerce/offerAvailabilitySchemas.d.ts +43 -0
- package/dist/commerce/offerAvailabilitySchemas.js +42 -0
- package/dist/commerce/offerEvidenceSchemas.d.ts +7 -0
- package/dist/commerce/offerEvidenceSchemas.js +13 -0
- package/dist/commerce/oms/omsContractBase.d.ts +130 -0
- package/dist/commerce/oms/omsContractBase.js +86 -0
- package/dist/commerce/oms/omsContractReadAuxSchemas.d.ts +222 -0
- package/dist/commerce/oms/omsContractReadAuxSchemas.js +123 -0
- package/dist/commerce/oms/omsContractReadSchemas.d.ts +2266 -0
- package/dist/commerce/oms/omsContractReadSchemas.js +277 -0
- package/dist/commerce/oms/omsContractRequests.d.ts +196 -0
- package/dist/commerce/oms/omsContractRequests.js +118 -0
- package/dist/commerce/oms/omsContracts.d.ts +5 -0
- package/dist/commerce/oms/omsContracts.js +4 -0
- package/dist/commerce/oms/omsControlPlane.d.ts +275 -0
- package/dist/commerce/oms/omsControlPlane.js +72 -0
- package/dist/commerce/oms/omsFulfillmentContractSchemas.d.ts +203 -0
- package/dist/commerce/oms/omsFulfillmentContractSchemas.js +94 -0
- package/dist/commerce/oms/omsFulfillmentDebugSchemas.d.ts +69 -0
- package/dist/commerce/oms/omsFulfillmentDebugSchemas.js +33 -0
- package/dist/commerce/oms/omsFulfillmentHealthSchemas.d.ts +67 -0
- package/dist/commerce/oms/omsFulfillmentHealthSchemas.js +44 -0
- package/dist/commerce/oms/omsPorts.d.ts +84 -0
- package/dist/commerce/oms/omsPorts.js +148 -0
- package/dist/commerce/oms/omsPrimitives.d.ts +5 -0
- package/dist/commerce/oms/omsPrimitives.js +3 -0
- package/dist/commerce/oms/omsProviderEvidenceSchemas.d.ts +15 -0
- package/dist/commerce/oms/omsProviderEvidenceSchemas.js +12 -0
- package/dist/commerce/orderDraftErrors.d.ts +13 -0
- package/dist/commerce/orderDraftErrors.js +20 -0
- package/dist/commerce/orderEmailEligibility.d.ts +54 -0
- package/dist/commerce/orderEmailEligibility.js +123 -0
- package/dist/commerce/orderEmailLines.d.ts +12 -0
- package/dist/commerce/orderEmailLines.js +8 -0
- package/dist/commerce/orderFeedbackContracts.d.ts +41 -0
- package/dist/commerce/orderFeedbackContracts.js +33 -0
- package/dist/commerce/orderMoney.d.ts +6 -0
- package/dist/commerce/orderMoney.js +168 -0
- package/dist/commerce/orderReviewContracts.d.ts +475 -0
- package/dist/commerce/orderReviewContracts.js +94 -0
- package/dist/commerce/orderReviewPorts.d.ts +140 -0
- package/dist/commerce/orderReviewPorts.js +1 -0
- package/dist/commerce/outboxDispatchContracts.d.ts +30 -0
- package/dist/commerce/outboxDispatchContracts.js +1 -0
- package/dist/commerce/outboxEventSchemas.d.ts +162 -0
- package/dist/commerce/outboxEventSchemas.js +164 -0
- package/dist/commerce/outboxOrderDraftEmailPorts.d.ts +207 -0
- package/dist/commerce/outboxOrderDraftEmailPorts.js +12 -0
- package/dist/commerce/paymentContinuation.d.ts +4 -0
- package/dist/commerce/paymentContinuation.js +4 -0
- package/dist/commerce/ports.d.ts +8 -0
- package/dist/commerce/ports.js +1 -0
- package/dist/commerce/recoveryDestination.d.ts +3 -0
- package/dist/commerce/recoveryDestination.js +17 -0
- package/dist/commerce/runtimeErrors.d.ts +8 -0
- package/dist/commerce/runtimeErrors.js +16 -0
- package/dist/commerce/salesChannelEnvelope.d.ts +20 -0
- package/dist/commerce/salesChannelEnvelope.js +7 -0
- package/dist/commerce/schemas.d.ts +174 -0
- package/dist/commerce/schemas.js +84 -0
- package/dist/commerce/server/checkoutCompensation.d.ts +21 -0
- package/dist/commerce/server/checkoutCompensation.js +32 -0
- package/dist/commerce/server/checkoutConflictClassifiers.d.ts +17 -0
- package/dist/commerce/server/checkoutConflictClassifiers.js +38 -0
- package/dist/commerce/server/checkoutExpiredRecoveryPolicy.d.ts +38 -0
- package/dist/commerce/server/checkoutExpiredRecoveryPolicy.js +85 -0
- package/dist/commerce/server/checkoutInvoiceBuyerSnapshot.d.ts +22 -0
- package/dist/commerce/server/checkoutInvoiceBuyerSnapshot.js +30 -0
- package/dist/commerce/server/checkoutOfferPolicyPort.d.ts +33 -0
- package/dist/commerce/server/checkoutOfferPolicyPort.js +49 -0
- package/dist/commerce/server/checkoutPaymentContinuationCredential.d.ts +58 -0
- package/dist/commerce/server/checkoutPaymentContinuationCredential.js +154 -0
- package/dist/commerce/server/checkoutQuoteTypes.d.ts +19 -0
- package/dist/commerce/server/checkoutQuoteTypes.js +1 -0
- package/dist/commerce/server/checkoutRecoveryOrderPort.d.ts +42 -0
- package/dist/commerce/server/checkoutRecoveryOrderPort.js +1 -0
- package/dist/commerce/server/checkoutRecoveryToken.d.ts +40 -0
- package/dist/commerce/server/checkoutRecoveryToken.js +26 -0
- package/dist/commerce/server/checkoutRefusalContinuation.d.ts +24 -0
- package/dist/commerce/server/checkoutRefusalContinuation.js +18 -0
- package/dist/commerce/server/checkoutRuntimeTypes.d.ts +81 -0
- package/dist/commerce/server/checkoutRuntimeTypes.js +1 -0
- package/dist/commerce/server/commerceCheckoutCommandExecution.d.ts +60 -0
- package/dist/commerce/server/commerceCheckoutCommandExecution.js +136 -0
- package/dist/commerce/server/commerceCheckoutCompensation.d.ts +26 -0
- package/dist/commerce/server/commerceCheckoutCompensation.js +46 -0
- package/dist/commerce/server/commerceCheckoutContinuationTerms.d.ts +50 -0
- package/dist/commerce/server/commerceCheckoutContinuationTerms.js +66 -0
- package/dist/commerce/server/commerceCheckoutCustomerDefaults.d.ts +18 -0
- package/dist/commerce/server/commerceCheckoutCustomerDefaults.js +17 -0
- package/dist/commerce/server/commerceCheckoutFailureHandler.d.ts +51 -0
- package/dist/commerce/server/commerceCheckoutFailureHandler.js +90 -0
- package/dist/commerce/server/commerceCheckoutHandler.d.ts +213 -0
- package/dist/commerce/server/commerceCheckoutHandler.js +196 -0
- package/dist/commerce/server/commerceCheckoutHandlerAdmission.d.ts +58 -0
- package/dist/commerce/server/commerceCheckoutHandlerAdmission.js +94 -0
- package/dist/commerce/server/commerceCheckoutHandlerHelpers.d.ts +67 -0
- package/dist/commerce/server/commerceCheckoutHandlerHelpers.js +155 -0
- package/dist/commerce/server/commerceCheckoutOrchestrationError.d.ts +9 -0
- package/dist/commerce/server/commerceCheckoutOrchestrationError.js +14 -0
- package/dist/commerce/server/commerceCheckoutPromotionPriceChange.d.ts +47 -0
- package/dist/commerce/server/commerceCheckoutPromotionPriceChange.js +43 -0
- package/dist/commerce/server/commerceCheckoutProviderPayment.d.ts +34 -0
- package/dist/commerce/server/commerceCheckoutProviderPayment.js +37 -0
- package/dist/commerce/server/commerceCheckoutQuoteGuard.d.ts +62 -0
- package/dist/commerce/server/commerceCheckoutQuoteGuard.js +106 -0
- package/dist/commerce/server/commerceCheckoutResume.d.ts +29 -0
- package/dist/commerce/server/commerceCheckoutResume.js +81 -0
- package/dist/commerce/server/commerceCheckoutResumeGuard.d.ts +54 -0
- package/dist/commerce/server/commerceCheckoutResumeGuard.js +138 -0
- package/dist/commerce/server/commerceCheckoutSavedPaymentMethod.d.ts +39 -0
- package/dist/commerce/server/commerceCheckoutSavedPaymentMethod.js +44 -0
- package/dist/commerce/server/commerceCheckoutStartRuntimeFailure.d.ts +7 -0
- package/dist/commerce/server/commerceCheckoutStartRuntimeFailure.js +39 -0
- package/dist/commerce/server/commerceCheckoutTiming.d.ts +8 -0
- package/dist/commerce/server/commerceCheckoutTiming.js +31 -0
- package/dist/commerce/server/commerceDiagnostics.d.ts +6 -0
- package/dist/commerce/server/commerceDiagnostics.js +31 -0
- package/dist/commerce/server/commerceOmsCancelOrderHandler.d.ts +7 -0
- package/dist/commerce/server/commerceOmsCancelOrderHandler.js +22 -0
- package/dist/commerce/server/commerceOmsControlPlaneHandlers.d.ts +18 -0
- package/dist/commerce/server/commerceOmsControlPlaneHandlers.js +60 -0
- package/dist/commerce/server/commerceOmsHandlers.d.ts +47 -0
- package/dist/commerce/server/commerceOmsHandlers.js +176 -0
- package/dist/commerce/server/commerceOmsMarkRefundedHandler.d.ts +7 -0
- package/dist/commerce/server/commerceOmsMarkRefundedHandler.js +19 -0
- package/dist/commerce/server/commerceOrderDraft.d.ts +24 -0
- package/dist/commerce/server/commerceOrderDraft.js +92 -0
- package/dist/commerce/server/commercePaidOrderOrchestration.d.ts +131 -0
- package/dist/commerce/server/commercePaidOrderOrchestration.js +140 -0
- package/dist/commerce/server/commerceProviderAttemptFailure.d.ts +133 -0
- package/dist/commerce/server/commerceProviderAttemptFailure.js +175 -0
- package/dist/commerce/server/commerceReturnsHandlers.d.ts +41 -0
- package/dist/commerce/server/commerceReturnsHandlers.js +100 -0
- package/dist/commerce/server/commerceRuntimePort.d.ts +16 -0
- package/dist/commerce/server/commerceRuntimePort.js +57 -0
- package/dist/commerce/server/commerceRuntimeService.d.ts +98 -0
- package/dist/commerce/server/commerceRuntimeService.js +186 -0
- package/dist/commerce/server/commerceRuntimeStartResponse.d.ts +37 -0
- package/dist/commerce/server/commerceRuntimeStartResponse.js +56 -0
- package/dist/commerce/server/commerceStarterOfferGuard.d.ts +55 -0
- package/dist/commerce/server/commerceStarterOfferGuard.js +128 -0
- package/dist/commerce/server/configuratorIntentPersistence.d.ts +47 -0
- package/dist/commerce/server/configuratorIntentPersistence.js +85 -0
- package/dist/commerce/server/configuratorIntentPersistenceHandler.d.ts +14 -0
- package/dist/commerce/server/configuratorIntentPersistenceHandler.js +42 -0
- package/dist/commerce/server/emailRuntime.d.ts +47 -0
- package/dist/commerce/server/emailRuntime.js +1 -0
- package/dist/commerce/server/handlerSupport.d.ts +68 -0
- package/dist/commerce/server/handlerSupport.js +1 -0
- package/dist/commerce/server/index.d.ts +178 -0
- package/dist/commerce/server/index.js +127 -0
- package/dist/commerce/server/offerAvailability.d.ts +21 -0
- package/dist/commerce/server/offerAvailability.js +163 -0
- package/dist/commerce/server/orderDraftRpcPayload.d.ts +20 -0
- package/dist/commerce/server/orderDraftRpcPayload.js +21 -0
- package/dist/commerce/server/orderFeedbackSubmit.d.ts +20 -0
- package/dist/commerce/server/orderFeedbackSubmit.js +16 -0
- package/dist/commerce/server/orderFeedbackTokenCheck.d.ts +17 -0
- package/dist/commerce/server/orderFeedbackTokenCheck.js +14 -0
- package/dist/commerce/server/orderReviewAdminHandlers.d.ts +47 -0
- package/dist/commerce/server/orderReviewAdminHandlers.js +41 -0
- package/dist/commerce/server/orderReviewHandlers.d.ts +114 -0
- package/dist/commerce/server/orderReviewHandlers.js +42 -0
- package/dist/commerce/server/orderReviewLifecycle.d.ts +10 -0
- package/dist/commerce/server/orderReviewLifecycle.js +121 -0
- package/dist/commerce/server/orderReviewMedia.d.ts +11 -0
- package/dist/commerce/server/orderReviewMedia.js +172 -0
- package/dist/commerce/server/orderReviewRawUploadHandler.d.ts +40 -0
- package/dist/commerce/server/orderReviewRawUploadHandler.js +316 -0
- package/dist/commerce/server/outboxCheckoutExpiredEmailHandler.d.ts +14 -0
- package/dist/commerce/server/outboxCheckoutExpiredEmailHandler.js +57 -0
- package/dist/commerce/server/outboxCheckoutRecoveryEmailHandler.d.ts +13 -0
- package/dist/commerce/server/outboxCheckoutRecoveryEmailHandler.js +150 -0
- package/dist/commerce/server/outboxDispatchRegistry.d.ts +46 -0
- package/dist/commerce/server/outboxDispatchRegistry.js +184 -0
- package/dist/commerce/server/outboxDispatchRegistryComposition.d.ts +6 -0
- package/dist/commerce/server/outboxDispatchRegistryComposition.js +23 -0
- package/dist/commerce/server/outboxOrderDraftEmailHandler.d.ts +14 -0
- package/dist/commerce/server/outboxOrderDraftEmailHandler.js +130 -0
- package/dist/commerce/server/outboxOrderPaidEmailHandler.d.ts +21 -0
- package/dist/commerce/server/outboxOrderPaidEmailHandler.js +93 -0
- package/dist/commerce/server/outboxOrderPaidFulfillmentHandler.d.ts +3 -0
- package/dist/commerce/server/outboxOrderPaidFulfillmentHandler.js +1 -0
- package/dist/commerce/server/outboxOrderPaidFulfillmentPorts.d.ts +3 -0
- package/dist/commerce/server/outboxOrderPaidFulfillmentPorts.js +1 -0
- package/dist/commerce/server/outboxOrderRefundedEmailHandler.d.ts +13 -0
- package/dist/commerce/server/outboxOrderRefundedEmailHandler.js +42 -0
- package/dist/commerce/server/outboxPaymentFailedEmailHandler.d.ts +14 -0
- package/dist/commerce/server/outboxPaymentFailedEmailHandler.js +65 -0
- package/dist/commerce/server/outboxReturnEmailHandlers.d.ts +26 -0
- package/dist/commerce/server/outboxReturnEmailHandlers.js +53 -0
- package/dist/commerce/server/outboxShipmentDeliveredEmailHandler.d.ts +17 -0
- package/dist/commerce/server/outboxShipmentDeliveredEmailHandler.js +52 -0
- package/dist/commerce/server/outboxShipmentDispatchedEmailHandler.d.ts +13 -0
- package/dist/commerce/server/outboxShipmentDispatchedEmailHandler.js +87 -0
- package/dist/commerce/server/outboxShipmentExceptionEmailHandler.d.ts +13 -0
- package/dist/commerce/server/outboxShipmentExceptionEmailHandler.js +46 -0
- package/dist/commerce/server/referenceCheckoutHandler.d.ts +48 -0
- package/dist/commerce/server/referenceCheckoutHandler.js +68 -0
- package/dist/commerce/server/reservationSweepPort.d.ts +31 -0
- package/dist/commerce/server/reservationSweepPort.js +45 -0
- package/dist/commerce/server/starterTermsPort.d.ts +22 -0
- package/dist/commerce/server/starterTermsPort.js +1 -0
- package/dist/commerce/server/supabaseCommerceReturnsPort.d.ts +13 -0
- package/dist/commerce/server/supabaseCommerceReturnsPort.js +56 -0
- package/dist/communications/consentPurposeRegistry.d.ts +1 -1
- package/dist/communications/newsletterIntegrationContracts.d.ts +10 -10
- package/dist/composition/accountSupportContribution.d.ts +18 -0
- package/dist/composition/accountSupportContribution.js +21 -0
- package/dist/composition/commerceContribution.d.ts +21 -0
- package/dist/composition/commerceContribution.js +27 -0
- package/dist/composition/index.d.ts +2 -0
- package/dist/composition/index.js +2 -0
- package/dist/fulfillment/handlerSchemas.d.ts +69 -69
- package/dist/fulfillment/index.d.ts +1 -1
- package/dist/fulfillment/index.js +1 -1
- package/dist/fulfillment/paidHandoff.d.ts +12 -1
- package/dist/fulfillment/paidHandoff.js +2 -2
- package/dist/fulfillment/providerDispatchWorker.d.ts +4 -4
- package/dist/identity/customerContracts.d.ts +4 -4
- package/dist/inventory/bindings.d.ts +3 -0
- package/dist/inventory/bindings.js +10 -4
- package/dist/inventory/index.d.ts +1 -0
- package/dist/inventory/index.js +1 -0
- package/dist/inventory/managedStockAvailability.d.ts +15 -0
- package/dist/inventory/managedStockAvailability.js +16 -0
- package/dist/inventory/postgresStockAvailability.js +2 -25
- package/dist/inventory/schemas.d.ts +1 -1
- package/dist/inventory/stockReadResponse.d.ts +4 -0
- package/dist/inventory/stockReadResponse.js +27 -0
- package/dist/invoicing/snapshot.d.ts +1 -1
- package/dist/pricing/acquisitionQuoteBinding.d.ts +1 -1
- package/dist/pricing/browser/index.d.ts +6 -0
- package/dist/pricing/browser/index.js +6 -0
- package/dist/pricing/catalogFactsSchemas.d.ts +1 -1
- package/dist/pricing/quotePromotionEvidence.d.ts +1 -1
- package/dist/pricing/quoteSchemas.d.ts +56 -56
- package/dist/promotions/adminPromotionCodesContracts.d.ts +30 -30
- package/dist/promotions/adminPromotionsContracts.d.ts +16 -16
- package/dist/subscriptions/index.d.ts +3 -2
- package/dist/subscriptions/index.js +3 -2
- package/package.json +32 -2
- package/release-gates.json +90 -8
- package/sql/20261026120000_account_support_operator_authority.sql +693 -0
- package/src/account-support/accountReadFacade.ts +15 -0
- package/src/account-support/accountReadModels.ts +371 -0
- package/src/account-support/bindings.ts +28 -0
- package/src/account-support/contracts/account.ts +306 -0
- package/src/account-support/contracts/capabilities.ts +30 -0
- package/src/account-support/contracts/commands.ts +243 -0
- package/src/account-support/contracts/customer360.ts +150 -0
- package/src/account-support/contracts/index.ts +141 -0
- package/src/account-support/contracts/invoice.ts +44 -0
- package/src/account-support/contracts/operator.ts +123 -0
- package/src/account-support/contribution.ts +35 -0
- package/src/account-support/customer360.ts +268 -0
- package/src/account-support/customerAccountReadDiagnostics.ts +83 -0
- package/src/account-support/index.ts +72 -0
- package/src/account-support/invoiceAccess.ts +63 -0
- package/src/account-support/migrations.ts +7 -0
- package/src/account-support/operatorAuthority.ts +393 -0
- package/src/account-support/operatorRecovery.ts +136 -0
- package/src/account-support/orderHistory.ts +309 -0
- package/src/account-support/paymentMethodComposition.ts +8 -0
- package/src/account-support/postgresOperatorAuthority.ts +92 -0
- package/src/account-support/selfService.ts +83 -0
- package/src/account-support/subscriptionCommandCodec.ts +48 -0
- package/src/commerce/adapters/managed/commerceOmsControlPlane.ts +80 -0
- package/src/commerce/adapters/managed/commerceOmsMutations.ts +145 -0
- package/src/commerce/adapters/managed/commerceOmsPort.ts +158 -0
- package/src/commerce/adapters/managed/oms/accounting.ts +18 -0
- package/src/commerce/adapters/managed/oms/fulfillmentReads.ts +82 -0
- package/src/commerce/adapters/managed/oms/inboundEvents.ts +45 -0
- package/src/commerce/adapters/managed/oms/outboxEvents.ts +30 -0
- package/src/commerce/adapters/managed/oms/paymentAttempts.ts +19 -0
- package/src/commerce/adapters/managed/oms/queueSelection.ts +132 -0
- package/src/commerce/adapters/managed/oms/readProjections.ts +22 -0
- package/src/commerce/adapters/managed/oms/readQueries.ts +292 -0
- package/src/commerce/adapters/managed/oms/types.ts +9 -0
- package/src/commerce/checkoutCommandSchemas.ts +93 -0
- package/src/commerce/checkoutHelpers.ts +47 -0
- package/src/commerce/checkoutResumeSchemas.ts +164 -0
- package/src/commerce/checkoutSchemas.ts +182 -0
- package/src/commerce/commerceReturnsPort.ts +67 -0
- package/src/commerce/configuratorIntentPersistenceSchemas.ts +26 -0
- package/src/commerce/configuratorIntentSchemas.ts +47 -0
- package/src/commerce/contractPrimitives.ts +30 -0
- package/src/commerce/contracts/availability.ts +21 -0
- package/src/commerce/contracts/fulfillmentRecovery.ts +26 -0
- package/src/commerce/contracts/index.ts +17 -0
- package/src/commerce/contracts/intent.ts +58 -0
- package/src/commerce/contracts/omsTypes.ts +1217 -0
- package/src/commerce/contracts/order.ts +44 -0
- package/src/commerce/contracts/orderMoney.ts +75 -0
- package/src/commerce/contracts/ports.ts +124 -0
- package/src/commerce/contracts/recovery.ts +24 -0
- package/src/commerce/contracts/runtimePorts.ts +201 -0
- package/src/commerce/contracts/state.ts +64 -0
- package/src/commerce/customerDefaultsSnapshotSchemas.ts +117 -0
- package/src/commerce/errors.ts +53 -0
- package/src/commerce/fulfillmentEligibility.ts +32 -0
- package/src/commerce/index.ts +82 -0
- package/src/commerce/model/customerFulfillmentRecovery.ts +185 -0
- package/src/commerce/model/fulfillmentCancellationEligibility.ts +18 -0
- package/src/commerce/model/omsAccountingVisibility.ts +135 -0
- package/src/commerce/model/omsBillingInvoiceBuyer.ts +20 -0
- package/src/commerce/model/omsCurrency.ts +8 -0
- package/src/commerce/model/omsFulfillmentDebug.ts +157 -0
- package/src/commerce/model/omsFulfillmentSummary.ts +225 -0
- package/src/commerce/model/omsListTotals.ts +38 -0
- package/src/commerce/model/omsOperationalLadder.ts +181 -0
- package/src/commerce/model/omsOrderLineMoney.ts +34 -0
- package/src/commerce/model/omsPaymentMethodSummary.ts +19 -0
- package/src/commerce/model/omsReadModel.ts +302 -0
- package/src/commerce/model/omsReadModelCommunication.ts +32 -0
- package/src/commerce/model/omsReadModelHelpers.ts +279 -0
- package/src/commerce/model/omsReadModelList.ts +90 -0
- package/src/commerce/model/omsReadModelListSummary.ts +19 -0
- package/src/commerce/model/omsReadModelPricing.ts +57 -0
- package/src/commerce/model/omsReadModelProjections.ts +1 -0
- package/src/commerce/model/omsReadModelRowCore.ts +193 -0
- package/src/commerce/model/omsReadModelRows.ts +7 -0
- package/src/commerce/offerAvailability.ts +75 -0
- package/src/commerce/offerAvailabilitySchemas.ts +56 -0
- package/src/commerce/offerEvidenceSchemas.ts +17 -0
- package/src/commerce/oms/omsContractBase.ts +92 -0
- package/src/commerce/oms/omsContractReadAuxSchemas.ts +130 -0
- package/src/commerce/oms/omsContractReadSchemas.ts +303 -0
- package/src/commerce/oms/omsContractRequests.ts +143 -0
- package/src/commerce/oms/omsContracts.ts +6 -0
- package/src/commerce/oms/omsControlPlane.ts +85 -0
- package/src/commerce/oms/omsFulfillmentContractSchemas.ts +113 -0
- package/src/commerce/oms/omsFulfillmentDebugSchemas.ts +38 -0
- package/src/commerce/oms/omsFulfillmentHealthSchemas.ts +46 -0
- package/src/commerce/oms/omsPorts.ts +165 -0
- package/src/commerce/oms/omsPrimitives.ts +3 -0
- package/src/commerce/oms/omsProviderEvidenceSchemas.ts +13 -0
- package/src/commerce/orderDraftErrors.ts +28 -0
- package/src/commerce/orderEmailEligibility.ts +131 -0
- package/src/commerce/orderEmailLines.ts +22 -0
- package/src/commerce/orderFeedbackContracts.ts +47 -0
- package/src/commerce/orderMoney.ts +207 -0
- package/src/commerce/orderReviewContracts.ts +124 -0
- package/src/commerce/orderReviewPorts.ts +94 -0
- package/src/commerce/outboxDispatchContracts.ts +30 -0
- package/src/commerce/outboxEventSchemas.ts +230 -0
- package/src/commerce/outboxOrderDraftEmailPorts.ts +241 -0
- package/src/commerce/paymentContinuation.ts +5 -0
- package/src/commerce/ports.ts +7 -0
- package/src/commerce/recoveryDestination.ts +23 -0
- package/src/commerce/runtimeErrors.ts +19 -0
- package/src/commerce/salesChannelEnvelope.ts +28 -0
- package/src/commerce/schemas.ts +104 -0
- package/src/commerce/server/checkoutCompensation.ts +49 -0
- package/src/commerce/server/checkoutConflictClassifiers.ts +53 -0
- package/src/commerce/server/checkoutExpiredRecoveryPolicy.ts +107 -0
- package/src/commerce/server/checkoutInvoiceBuyerSnapshot.ts +36 -0
- package/src/commerce/server/checkoutOfferPolicyPort.ts +60 -0
- package/src/commerce/server/checkoutPaymentContinuationCredential.ts +222 -0
- package/src/commerce/server/checkoutQuoteTypes.ts +9 -0
- package/src/commerce/server/checkoutRecoveryOrderPort.ts +40 -0
- package/src/commerce/server/checkoutRecoveryToken.ts +63 -0
- package/src/commerce/server/checkoutRefusalContinuation.ts +29 -0
- package/src/commerce/server/checkoutRuntimeTypes.ts +26 -0
- package/src/commerce/server/commerceCheckoutCommandExecution.ts +188 -0
- package/src/commerce/server/commerceCheckoutCompensation.ts +66 -0
- package/src/commerce/server/commerceCheckoutContinuationTerms.ts +87 -0
- package/src/commerce/server/commerceCheckoutCustomerDefaults.ts +24 -0
- package/src/commerce/server/commerceCheckoutFailureHandler.ts +144 -0
- package/src/commerce/server/commerceCheckoutHandler.ts +269 -0
- package/src/commerce/server/commerceCheckoutHandlerAdmission.ts +157 -0
- package/src/commerce/server/commerceCheckoutHandlerHelpers.ts +223 -0
- package/src/commerce/server/commerceCheckoutOrchestrationError.ts +15 -0
- package/src/commerce/server/commerceCheckoutPromotionPriceChange.ts +83 -0
- package/src/commerce/server/commerceCheckoutProviderPayment.ts +45 -0
- package/src/commerce/server/commerceCheckoutQuoteGuard.ts +172 -0
- package/src/commerce/server/commerceCheckoutResume.ts +132 -0
- package/src/commerce/server/commerceCheckoutResumeGuard.ts +195 -0
- package/src/commerce/server/commerceCheckoutSavedPaymentMethod.ts +85 -0
- package/src/commerce/server/commerceCheckoutStartRuntimeFailure.ts +59 -0
- package/src/commerce/server/commerceCheckoutTiming.ts +53 -0
- package/src/commerce/server/commerceDiagnostics.ts +37 -0
- package/src/commerce/server/commerceOmsCancelOrderHandler.ts +43 -0
- package/src/commerce/server/commerceOmsControlPlaneHandlers.ts +71 -0
- package/src/commerce/server/commerceOmsHandlers.ts +275 -0
- package/src/commerce/server/commerceOmsMarkRefundedHandler.ts +39 -0
- package/src/commerce/server/commerceOrderDraft.ts +131 -0
- package/src/commerce/server/commercePaidOrderOrchestration.ts +275 -0
- package/src/commerce/server/commerceProviderAttemptFailure.ts +257 -0
- package/src/commerce/server/commerceReturnsHandlers.ts +143 -0
- package/src/commerce/server/commerceRuntimePort.ts +75 -0
- package/src/commerce/server/commerceRuntimeService.ts +229 -0
- package/src/commerce/server/commerceRuntimeStartResponse.ts +76 -0
- package/src/commerce/server/commerceStarterOfferGuard.ts +200 -0
- package/src/commerce/server/configuratorIntentPersistence.ts +161 -0
- package/src/commerce/server/configuratorIntentPersistenceHandler.ts +54 -0
- package/src/commerce/server/emailRuntime.ts +30 -0
- package/src/commerce/server/handlerSupport.ts +22 -0
- package/src/commerce/server/index.ts +181 -0
- package/src/commerce/server/offerAvailability.ts +275 -0
- package/src/commerce/server/orderDraftRpcPayload.ts +39 -0
- package/src/commerce/server/orderFeedbackSubmit.ts +40 -0
- package/src/commerce/server/orderFeedbackTokenCheck.ts +28 -0
- package/src/commerce/server/orderReviewAdminHandlers.ts +43 -0
- package/src/commerce/server/orderReviewHandlers.ts +57 -0
- package/src/commerce/server/orderReviewLifecycle.ts +129 -0
- package/src/commerce/server/orderReviewMedia.ts +170 -0
- package/src/commerce/server/orderReviewRawUploadHandler.ts +300 -0
- package/src/commerce/server/outboxCheckoutExpiredEmailHandler.ts +86 -0
- package/src/commerce/server/outboxCheckoutRecoveryEmailHandler.ts +188 -0
- package/src/commerce/server/outboxDispatchRegistry.ts +269 -0
- package/src/commerce/server/outboxDispatchRegistryComposition.ts +31 -0
- package/src/commerce/server/outboxOrderDraftEmailHandler.ts +162 -0
- package/src/commerce/server/outboxOrderPaidEmailHandler.ts +147 -0
- package/src/commerce/server/outboxOrderPaidFulfillmentHandler.ts +4 -0
- package/src/commerce/server/outboxOrderPaidFulfillmentPorts.ts +3 -0
- package/src/commerce/server/outboxOrderRefundedEmailHandler.ts +58 -0
- package/src/commerce/server/outboxPaymentFailedEmailHandler.ts +99 -0
- package/src/commerce/server/outboxReturnEmailHandlers.ts +92 -0
- package/src/commerce/server/outboxShipmentDeliveredEmailHandler.ts +94 -0
- package/src/commerce/server/outboxShipmentDispatchedEmailHandler.ts +112 -0
- package/src/commerce/server/outboxShipmentExceptionEmailHandler.ts +73 -0
- package/src/commerce/server/referenceCheckoutHandler.ts +87 -0
- package/src/commerce/server/reservationSweepPort.ts +67 -0
- package/src/commerce/server/starterTermsPort.ts +22 -0
- package/src/commerce/server/supabaseCommerceReturnsPort.ts +81 -0
- package/src/composition/accountSupportContribution.ts +28 -0
- package/src/composition/commerceContribution.ts +35 -0
- package/src/composition/index.ts +2 -0
- package/src/fulfillment/index.ts +1 -1
- package/src/fulfillment/paidHandoff.ts +2 -2
- package/src/inventory/bindings.ts +12 -4
- package/src/inventory/index.ts +1 -0
- package/src/inventory/managedStockAvailability.ts +23 -0
- package/src/inventory/postgresStockAvailability.ts +2 -21
- package/src/inventory/stockReadResponse.ts +25 -0
- package/src/pricing/browser/index.ts +6 -0
- package/src/subscriptions/index.ts +3 -2
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import {
|
|
2
|
+
orderReviewMediaSchema,
|
|
3
|
+
type OrderReviewMedia,
|
|
4
|
+
} from "../orderReviewContracts.js";
|
|
5
|
+
import type {
|
|
6
|
+
OrderReviewMediaCleanup,
|
|
7
|
+
OrderReviewMediaObject,
|
|
8
|
+
OrderReviewMediaPort,
|
|
9
|
+
OrderReviewMediaReconcileTask,
|
|
10
|
+
OrderReviewUploadReservation,
|
|
11
|
+
} from "../orderReviewPorts.js";
|
|
12
|
+
// Structural equivalent of the host query executor; declarations need no optional pg peer.
|
|
13
|
+
type PgQueryExecutor = { query(text: string, values?: unknown[]): Promise<{ rows: Record<string, unknown>[] }> };
|
|
14
|
+
|
|
15
|
+
const READ = "SELECT public.order_review_read_media($1::text,$2::text,now()) AS response";
|
|
16
|
+
const ADMIT = "SELECT public.order_review_admit_media_upload($1::text,$2::text,$3::integer,$4::text,now()) AS response";
|
|
17
|
+
const LOCK_FINALIZE = "SELECT public.order_review_lock_media_finalize($1::text,$2::text,$3::bigint,now()) AS response";
|
|
18
|
+
const STORED = "SELECT public.order_review_record_media_stored($1::text,$2::text,$3::bigint,$4::text,$5::integer,now()) AS response";
|
|
19
|
+
const ABORT = "SELECT public.order_review_abort_media_upload($1::text,$2::text,$3::bigint,$4::text,now()) AS response";
|
|
20
|
+
const ADMIN_READ = "SELECT public.order_review_admin_read_media($1::text,$2::text) AS response";
|
|
21
|
+
const ADMIN_DELETE_PREPARE = "SELECT public.order_review_admin_prepare_media_delete($1::text,$2::text,$3::text,now()) AS response";
|
|
22
|
+
const ADMIN_DELETE_COMPLETE = "SELECT public.order_review_admin_complete_media_delete($1::text,$2::text,now()) AS response";
|
|
23
|
+
const CLAIM_RECONCILE = "SELECT public.order_review_claim_media_reconcile($1::integer,now()) AS response";
|
|
24
|
+
const COMPLETE_RECONCILE = "SELECT public.order_review_complete_media_reconcile($1::text,$2::text,$3::text,$4::integer,$5::text,$6::text,now()) AS response";
|
|
25
|
+
|
|
26
|
+
export interface OrderReviewMediaTransactionLane {
|
|
27
|
+
run<T>(work: (executor: PgQueryExecutor) => Promise<T>): Promise<T>;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function createPostgresOrderReviewMediaPort(
|
|
31
|
+
executor: PgQueryExecutor,
|
|
32
|
+
transactionLane?: OrderReviewMediaTransactionLane,
|
|
33
|
+
): OrderReviewMediaPort {
|
|
34
|
+
return {
|
|
35
|
+
async readAuthorized(grant, mediaRef) { return mediaObjectOrNull(await call(executor, READ, [grant, mediaRef])); },
|
|
36
|
+
async admitUpload(input) {
|
|
37
|
+
let value: Record<string, unknown> | null;
|
|
38
|
+
try {
|
|
39
|
+
value = object(await call(executor, ADMIT, [
|
|
40
|
+
input.capabilityDigest, input.declaredContentType, input.declaredByteLength, input.writerRef,
|
|
41
|
+
]));
|
|
42
|
+
} catch (error) {
|
|
43
|
+
const code = error && typeof error === "object" && "code" in error ? String(error.code) : "";
|
|
44
|
+
if (code === "23505" || code === "order_review_conflict") return { kind: "conflict" };
|
|
45
|
+
throw error;
|
|
46
|
+
}
|
|
47
|
+
if (!value) return { kind: "unavailable" };
|
|
48
|
+
if (value.kind === "complete") return { kind: "complete", media: media(value.media) };
|
|
49
|
+
if (value.kind !== undefined && value.kind !== "lease") throw invalid();
|
|
50
|
+
const parsed = media(value.media);
|
|
51
|
+
const leaseVersion = value.leaseVersion;
|
|
52
|
+
const leaseExpiresAt = value.leaseExpiresAt;
|
|
53
|
+
const objectKey = value.objectKey;
|
|
54
|
+
const declaredContentType = value.declaredContentType;
|
|
55
|
+
const declaredByteLength = value.declaredByteLength;
|
|
56
|
+
if (!Number.isInteger(leaseVersion) || typeof leaseExpiresAt !== "string" || typeof objectKey !== "string"
|
|
57
|
+
|| (declaredContentType !== "image/jpeg" && declaredContentType !== "image/png" && declaredContentType !== "image/webp")
|
|
58
|
+
|| !Number.isInteger(declaredByteLength)) throw invalid();
|
|
59
|
+
return { kind: "lease", reservation: { media: parsed, leaseVersion: leaseVersion as number, leaseExpiresAt, objectKey,
|
|
60
|
+
declaredContentType, declaredByteLength: declaredByteLength as number } satisfies OrderReviewUploadReservation };
|
|
61
|
+
},
|
|
62
|
+
async finalizeUpload(input) {
|
|
63
|
+
if (!transactionLane) throw Object.assign(new Error("order_review_finalize_lane_required"), { code: "order_review_invalid" });
|
|
64
|
+
let leased = false;
|
|
65
|
+
try {
|
|
66
|
+
return await transactionLane.run(async (transaction) => {
|
|
67
|
+
const locked = await call(transaction, LOCK_FINALIZE, [input.capabilityDigest, input.writerRef, input.leaseVersion]);
|
|
68
|
+
if (locked === null) return null;
|
|
69
|
+
const lockedRow = object(locked);
|
|
70
|
+
if (!lockedRow || !lockedRow.media) throw invalid();
|
|
71
|
+
media(lockedRow.media);
|
|
72
|
+
leased = true;
|
|
73
|
+
await input.promote();
|
|
74
|
+
const stored = mediaOrNull(await call(transaction, STORED, [
|
|
75
|
+
input.capabilityDigest, input.writerRef, input.leaseVersion, input.digest, input.byteLength,
|
|
76
|
+
]));
|
|
77
|
+
if (!stored) throw invalid();
|
|
78
|
+
return stored;
|
|
79
|
+
});
|
|
80
|
+
} catch (error) {
|
|
81
|
+
// The transaction has rolled back: persist cleanup_pending outside it.
|
|
82
|
+
if (leased) await call(executor, ABORT, [input.capabilityDigest, input.writerRef, input.leaseVersion, "finalize_failed"]);
|
|
83
|
+
throw error;
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
async abortUpload(input) { await call(executor, ABORT, [input.capabilityDigest, input.writerRef, input.leaseVersion, input.reason]); },
|
|
87
|
+
async readAdmin(input) { return mediaObjectOrNull(await call(executor, ADMIN_READ, [input.actorRef, input.mediaRef])); },
|
|
88
|
+
async prepareAdminDelete(input) {
|
|
89
|
+
const value = object(await call(executor, ADMIN_DELETE_PREPARE, [input.actorRef, input.mediaRef, input.idempotencyKey]));
|
|
90
|
+
if (!value) return null;
|
|
91
|
+
return cleanup(value);
|
|
92
|
+
},
|
|
93
|
+
async completeAdminDelete(input) {
|
|
94
|
+
const value = object(await call(executor, ADMIN_DELETE_COMPLETE, [input.actorRef, input.cleanupReceipt]));
|
|
95
|
+
if (!value) throw invalid();
|
|
96
|
+
return { replayed: value.replayed === true };
|
|
97
|
+
},
|
|
98
|
+
async claimReconcile(limit) {
|
|
99
|
+
if (!Number.isInteger(limit) || limit < 1 || limit > 100) throw invalid();
|
|
100
|
+
const value = object(await call(executor, CLAIM_RECONCILE, [limit]));
|
|
101
|
+
if (!value || !Array.isArray(value.tasks)) throw invalid();
|
|
102
|
+
return value.tasks.map(reconcileTask);
|
|
103
|
+
},
|
|
104
|
+
async completeReconcile(input) {
|
|
105
|
+
const outcome = input.outcome;
|
|
106
|
+
if (!/^[-A-Za-z0-9_:]{1,512}$/.test(input.receipt)) throw invalid();
|
|
107
|
+
if (outcome.kind === "stored" && (!Number.isInteger(outcome.observedByteLength)
|
|
108
|
+
|| outcome.observedByteLength < 1 || outcome.observedByteLength > 20 * 1024 * 1024
|
|
109
|
+
|| !/^[a-f0-9]{64}$/.test(outcome.observedDigest))) throw invalid();
|
|
110
|
+
if (outcome.kind === "retry" && (outcome.reason.length < 1 || outcome.reason.length > 128)) throw invalid();
|
|
111
|
+
await call(executor, COMPLETE_RECONCILE, [
|
|
112
|
+
input.receipt,
|
|
113
|
+
outcome.kind,
|
|
114
|
+
outcome.kind === "stored" ? outcome.observedContentType : null,
|
|
115
|
+
outcome.kind === "stored" ? outcome.observedByteLength : null,
|
|
116
|
+
outcome.kind === "stored" ? outcome.observedDigest : null,
|
|
117
|
+
outcome.kind === "retry" ? outcome.reason : null,
|
|
118
|
+
]);
|
|
119
|
+
},
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
async function call(executor: PgQueryExecutor, sql: string, values: unknown[]): Promise<unknown> {
|
|
124
|
+
const result = await executor.query(sql, values);
|
|
125
|
+
return object(result.rows[0])?.response ?? null;
|
|
126
|
+
}
|
|
127
|
+
function mediaOrNull(value: unknown): OrderReviewMedia | null {
|
|
128
|
+
return value === null ? null : media(value);
|
|
129
|
+
}
|
|
130
|
+
function media(value: unknown): OrderReviewMedia { return orderReviewMediaSchema.parse(value); }
|
|
131
|
+
function mediaObjectOrNull(value: unknown): OrderReviewMediaObject | null {
|
|
132
|
+
if (value === null) return null;
|
|
133
|
+
const row = object(value);
|
|
134
|
+
if (!row || typeof row.objectKey !== "string") throw invalid();
|
|
135
|
+
return { media: media(row.media), objectKey: row.objectKey };
|
|
136
|
+
}
|
|
137
|
+
function cleanup(value: Record<string, unknown>): OrderReviewMediaCleanup {
|
|
138
|
+
if (typeof value.objectKey !== "string" || typeof value.cleanupReceipt !== "string" || typeof value.replayed !== "boolean") throw invalid();
|
|
139
|
+
if (value.tempKey !== undefined && value.tempKey !== null && typeof value.tempKey !== "string") throw invalid();
|
|
140
|
+
return { media: media(value.media), objectKey: value.objectKey,
|
|
141
|
+
...(typeof value.tempKey === "string" ? { tempKey: value.tempKey } : {}),
|
|
142
|
+
cleanupReceipt: value.cleanupReceipt, replayed: value.replayed };
|
|
143
|
+
}
|
|
144
|
+
function reconcileTask(value: unknown): OrderReviewMediaReconcileTask {
|
|
145
|
+
const row = object(value);
|
|
146
|
+
const expectedDeclaredByteLength = row?.expectedDeclaredByteLength;
|
|
147
|
+
const tempKey = row?.tempKey;
|
|
148
|
+
if (!row
|
|
149
|
+
|| typeof row.receipt !== "string"
|
|
150
|
+
|| (row.kind !== "finalize" && row.kind !== "delete")
|
|
151
|
+
|| typeof row.objectKey !== "string"
|
|
152
|
+
|| (tempKey !== undefined && typeof tempKey !== "string")
|
|
153
|
+
|| (row.expectedDeclaredContentType !== "image/jpeg" && row.expectedDeclaredContentType !== "image/png" && row.expectedDeclaredContentType !== "image/webp")
|
|
154
|
+
|| !Number.isInteger(expectedDeclaredByteLength)
|
|
155
|
+
|| typeof expectedDeclaredByteLength !== "number"
|
|
156
|
+
|| expectedDeclaredByteLength < 1
|
|
157
|
+
|| expectedDeclaredByteLength > 20 * 1024 * 1024) throw invalid();
|
|
158
|
+
return {
|
|
159
|
+
receipt: row.receipt,
|
|
160
|
+
kind: row.kind,
|
|
161
|
+
objectKey: row.objectKey,
|
|
162
|
+
...(tempKey === undefined ? {} : { tempKey: tempKey as string }),
|
|
163
|
+
expectedDeclaredContentType: row.expectedDeclaredContentType,
|
|
164
|
+
expectedDeclaredByteLength,
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
function object(value: unknown): Record<string, unknown> | null {
|
|
168
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value as Record<string, unknown> : null;
|
|
169
|
+
}
|
|
170
|
+
function invalid() { return Object.assign(new Error("order_review_media_response_invalid"), { code: "order_review_invalid" }); }
|
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { crc32 } from "node:zlib";
|
|
3
|
+
import type { HttpRequest, HttpResponse } from "../../http/index.js";
|
|
4
|
+
|
|
5
|
+
const MAX_UPLOAD_BYTES = 20 * 1024 * 1024;
|
|
6
|
+
const MAX_IMAGE_HEADER_BYTES = 64 * 1024;
|
|
7
|
+
const MAX_DIMENSION = 8192;
|
|
8
|
+
const MAX_PIXELS = 40_000_000;
|
|
9
|
+
const CAPABILITY_HEADER = "authorization";
|
|
10
|
+
const ALLOWED_MIME = new Set(["image/jpeg", "image/png", "image/webp"] as const);
|
|
11
|
+
|
|
12
|
+
export type OrderReviewMediaMime = "image/jpeg" | "image/png" | "image/webp";
|
|
13
|
+
|
|
14
|
+
export interface OrderReviewRawUploadSession {
|
|
15
|
+
upload(input: { body: AsyncIterable<Uint8Array>; signal: AbortSignal }): Promise<OrderReviewRawUploadResult>;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface OrderReviewRawUploadBinding {
|
|
19
|
+
admit(input: { capabilityDigest: string; declaredMime: OrderReviewMediaMime; declaredBytes: number }):
|
|
20
|
+
Promise<OrderReviewRawUploadSession | OrderReviewRawUploadResult>;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export type OrderReviewRawUploadResult =
|
|
24
|
+
| { kind: "complete"; status: 200 | 201; mediaRef: string }
|
|
25
|
+
| { kind: "refused"; status: 404 | 409 | 413 | 415 | 503; code: string };
|
|
26
|
+
|
|
27
|
+
export type OrderReviewRawUploadBindingState =
|
|
28
|
+
| { kind: "direct"; binding: OrderReviewRawUploadBinding }
|
|
29
|
+
| { kind: "hosted" }
|
|
30
|
+
| { kind: "unbound" };
|
|
31
|
+
|
|
32
|
+
export function createOrderReviewRawUploadHandler(options: { resolveBinding: () => OrderReviewRawUploadBindingState
|
|
33
|
+
| Promise<OrderReviewRawUploadBindingState>; timeoutMs?: number }) {
|
|
34
|
+
return async function orderReviewRawUpload(req: HttpRequest, res: HttpResponse): Promise<void> {
|
|
35
|
+
if (req.method !== "PUT") return sendError(res, 405, "METHOD_NOT_ALLOWED");
|
|
36
|
+
let state: OrderReviewRawUploadBindingState;
|
|
37
|
+
try {
|
|
38
|
+
state = await options.resolveBinding();
|
|
39
|
+
} catch {
|
|
40
|
+
return sendError(res, 503, "ORDER_REVIEW_MEDIA_UNAVAILABLE");
|
|
41
|
+
}
|
|
42
|
+
if (state.kind === "hosted") return sendError(res, 405, "METHOD_NOT_ALLOWED");
|
|
43
|
+
if (state.kind === "unbound") return sendError(res, 503, "ORDER_REVIEW_MEDIA_UNAVAILABLE");
|
|
44
|
+
let headers: ValidatedHeaders;
|
|
45
|
+
try {
|
|
46
|
+
headers = validateHeaders(req);
|
|
47
|
+
} catch (error) {
|
|
48
|
+
const input = asInputError(error);
|
|
49
|
+
return sendError(res, input.status, input.code);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
let admission: OrderReviewRawUploadSession | OrderReviewRawUploadResult;
|
|
53
|
+
try {
|
|
54
|
+
admission = await state.binding.admit({
|
|
55
|
+
capabilityDigest: headers.capabilityDigest,
|
|
56
|
+
declaredMime: headers.mime,
|
|
57
|
+
declaredBytes: headers.bytes,
|
|
58
|
+
});
|
|
59
|
+
} catch {
|
|
60
|
+
return sendError(res, 503, "ORDER_REVIEW_MEDIA_UNAVAILABLE");
|
|
61
|
+
}
|
|
62
|
+
if (isResult(admission)) { if (admission.kind === "refused") req.resume(); return sendResult(res, admission); }
|
|
63
|
+
|
|
64
|
+
const abort = new AbortController();
|
|
65
|
+
const timeout = setTimeout(() => {
|
|
66
|
+
abort.abort(new Error("raw upload deadline exceeded"));
|
|
67
|
+
req.destroy();
|
|
68
|
+
}, options.timeoutMs ?? 30_000);
|
|
69
|
+
timeout.unref?.();
|
|
70
|
+
const onAborted = () => abort.abort(new Error("raw upload aborted"));
|
|
71
|
+
req.once("aborted", onAborted);
|
|
72
|
+
try {
|
|
73
|
+
const result = await admission.upload({
|
|
74
|
+
body: validatedImageBody(req, headers.mime, headers.bytes, abort.signal),
|
|
75
|
+
signal: abort.signal,
|
|
76
|
+
});
|
|
77
|
+
return sendResult(res, result);
|
|
78
|
+
} catch (error) {
|
|
79
|
+
if (error instanceof InputError) return sendError(res, error.status, error.code);
|
|
80
|
+
if (abort.signal.aborted) return sendError(res, 400, "UPLOAD_ABORTED");
|
|
81
|
+
return sendError(res, 503, "ORDER_REVIEW_MEDIA_UNAVAILABLE");
|
|
82
|
+
} finally {
|
|
83
|
+
clearTimeout(timeout);
|
|
84
|
+
req.off("aborted", onAborted);
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
interface ValidatedHeaders {
|
|
90
|
+
capabilityDigest: string;
|
|
91
|
+
mime: OrderReviewMediaMime;
|
|
92
|
+
bytes: number;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function validateHeaders(req: HttpRequest): ValidatedHeaders {
|
|
96
|
+
if (headerValues(req, "transfer-encoding").length > 0) fail(400, "TRANSFER_ENCODING_REFUSED");
|
|
97
|
+
if (headerValues(req, "content-encoding").length > 0) fail(400, "CONTENT_ENCODING_REFUSED");
|
|
98
|
+
if (headerValues(req, "range").length > 0) fail(400, "RANGE_REFUSED");
|
|
99
|
+
|
|
100
|
+
const lengths = headerValues(req, "content-length");
|
|
101
|
+
if (lengths.length !== 1 || !/^[1-9][0-9]*$/.test(lengths[0]!) || lengths[0]!.includes(",")) {
|
|
102
|
+
fail(400, "INVALID_CONTENT_LENGTH");
|
|
103
|
+
}
|
|
104
|
+
const bytes = Number(lengths[0]);
|
|
105
|
+
if (!Number.isSafeInteger(bytes)) fail(400, "INVALID_CONTENT_LENGTH");
|
|
106
|
+
if (bytes > MAX_UPLOAD_BYTES) fail(413, "UPLOAD_TOO_LARGE");
|
|
107
|
+
|
|
108
|
+
const contentTypes = headerValues(req, "content-type");
|
|
109
|
+
if (contentTypes.length !== 1 || contentTypes[0]!.includes(";") || contentTypes[0]!.includes(",")) {
|
|
110
|
+
fail(415, "UNSUPPORTED_MEDIA_TYPE");
|
|
111
|
+
}
|
|
112
|
+
const mime = contentTypes[0]!.trim().toLowerCase();
|
|
113
|
+
if (!ALLOWED_MIME.has(mime as OrderReviewMediaMime)) fail(415, "UNSUPPORTED_MEDIA_TYPE");
|
|
114
|
+
|
|
115
|
+
const authorizations = headerValues(req, CAPABILITY_HEADER);
|
|
116
|
+
if (authorizations.length !== 1) fail(404, "ORDER_REVIEW_MEDIA_NOT_FOUND");
|
|
117
|
+
const match = /^Bearer (order-review-upload:[a-f0-9-]{36})$/.exec(authorizations[0]!);
|
|
118
|
+
if (!match) fail(404, "ORDER_REVIEW_MEDIA_NOT_FOUND");
|
|
119
|
+
const capabilityDigest = createHash("sha256").update(match[1]!, "utf8").digest("hex");
|
|
120
|
+
return { capabilityDigest, mime: mime as OrderReviewMediaMime, bytes };
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function headerValues(req: HttpRequest, name: string): string[] {
|
|
124
|
+
const values: string[] = [];
|
|
125
|
+
const raw = req.rawHeaders ?? [];
|
|
126
|
+
for (let index = 0; index < raw.length; index += 2) {
|
|
127
|
+
if (raw[index]?.toLowerCase() === name) values.push(raw[index + 1] ?? "");
|
|
128
|
+
}
|
|
129
|
+
if (values.length > 0) return values;
|
|
130
|
+
const fallback = req.headers[name];
|
|
131
|
+
if (fallback === undefined) return [];
|
|
132
|
+
return Array.isArray(fallback) ? fallback : [String(fallback)];
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
async function* validatedImageBody(
|
|
136
|
+
source: AsyncIterable<unknown>,
|
|
137
|
+
mime: OrderReviewMediaMime,
|
|
138
|
+
declaredBytes: number,
|
|
139
|
+
signal: AbortSignal,
|
|
140
|
+
): AsyncIterable<Uint8Array> {
|
|
141
|
+
const header = Buffer.alloc(MAX_IMAGE_HEADER_BYTES);
|
|
142
|
+
const pending: Uint8Array[] = [];
|
|
143
|
+
let headerBytes = 0;
|
|
144
|
+
let seen = 0;
|
|
145
|
+
let accepted = false;
|
|
146
|
+
for await (const value of source) {
|
|
147
|
+
if (signal.aborted) fail(400, "UPLOAD_ABORTED");
|
|
148
|
+
const chunk = toBytes(value);
|
|
149
|
+
seen += chunk.byteLength;
|
|
150
|
+
if (seen > declaredBytes || seen > MAX_UPLOAD_BYTES) fail(413, "UPLOAD_TOO_LARGE");
|
|
151
|
+
if (!accepted) {
|
|
152
|
+
pending.push(chunk);
|
|
153
|
+
const copyBytes = Math.min(chunk.byteLength, header.byteLength - headerBytes);
|
|
154
|
+
if (copyBytes > 0) {
|
|
155
|
+
header.set(chunk.subarray(0, copyBytes), headerBytes);
|
|
156
|
+
headerBytes += copyBytes;
|
|
157
|
+
}
|
|
158
|
+
const dimensions = inspectImageHeader(mime, header.subarray(0, headerBytes), declaredBytes);
|
|
159
|
+
if (dimensions) {
|
|
160
|
+
assertDimensions(dimensions.width, dimensions.height);
|
|
161
|
+
accepted = true;
|
|
162
|
+
for (const buffered of pending) yield buffered;
|
|
163
|
+
pending.length = 0;
|
|
164
|
+
} else if (headerBytes === MAX_IMAGE_HEADER_BYTES) {
|
|
165
|
+
fail(415, "INVALID_IMAGE");
|
|
166
|
+
}
|
|
167
|
+
} else {
|
|
168
|
+
yield chunk;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
if (signal.aborted) fail(400, "UPLOAD_ABORTED");
|
|
172
|
+
if (seen !== declaredBytes) fail(400, "CONTENT_LENGTH_MISMATCH");
|
|
173
|
+
if (!accepted) fail(415, "INVALID_IMAGE");
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
export function inspectImageHeader(mime: OrderReviewMediaMime, bytes: Uint8Array, declaredBytes: number):
|
|
177
|
+
{ width: number; height: number } | null {
|
|
178
|
+
if (mime === "image/png") {
|
|
179
|
+
if (bytes.length < 33) {
|
|
180
|
+
if (bytes.length === declaredBytes) fail(415, "INVALID_IMAGE");
|
|
181
|
+
return null;
|
|
182
|
+
}
|
|
183
|
+
if (!matches(bytes, 0, [137, 80, 78, 71, 13, 10, 26, 10]) || readU32BE(bytes, 8) !== 13
|
|
184
|
+
|| ascii(bytes, 12, 4) !== "IHDR" || declaredBytes < 57 || crc32(bytes.subarray(12, 29)) !== readU32BE(bytes, 29)) {
|
|
185
|
+
fail(415, "INVALID_IMAGE");
|
|
186
|
+
}
|
|
187
|
+
const depths: Record<number, number[]> = { 0: [1, 2, 4, 8, 16], 2: [8, 16], 3: [1, 2, 4, 8], 4: [8, 16], 6: [8, 16] };
|
|
188
|
+
if (!depths[bytes[25]!]?.includes(bytes[24]!) || bytes[26] !== 0 || bytes[27] !== 0 || bytes[28]! > 1) fail(415, "INVALID_IMAGE");
|
|
189
|
+
return { width: readU32BE(bytes, 16), height: readU32BE(bytes, 20) };
|
|
190
|
+
}
|
|
191
|
+
if (mime === "image/webp") return inspectWebp(bytes, declaredBytes);
|
|
192
|
+
return inspectJpeg(bytes);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
function inspectWebp(bytes: Uint8Array, declaredBytes: number) {
|
|
196
|
+
if (bytes.length < 16) return null;
|
|
197
|
+
if (ascii(bytes, 0, 4) !== "RIFF" || ascii(bytes, 8, 4) !== "WEBP") fail(415, "INVALID_IMAGE");
|
|
198
|
+
if (readU32LE(bytes, 4) + 8 !== declaredBytes) fail(415, "INVALID_IMAGE");
|
|
199
|
+
const kind = ascii(bytes, 12, 4);
|
|
200
|
+
const chunkBytes = readU32LE(bytes, 16);
|
|
201
|
+
if (kind === "VP8X") {
|
|
202
|
+
if (bytes.length < 38) {
|
|
203
|
+
if (bytes.length === declaredBytes) fail(415, "INVALID_IMAGE");
|
|
204
|
+
return null;
|
|
205
|
+
}
|
|
206
|
+
if (chunkBytes !== 10 || !["VP8 ", "VP8L", "ALPH"].includes(ascii(bytes, 30, 4))) fail(415, "INVALID_IMAGE");
|
|
207
|
+
return { width: 1 + readU24LE(bytes, 24), height: 1 + readU24LE(bytes, 27) };
|
|
208
|
+
}
|
|
209
|
+
if (kind === "VP8L") {
|
|
210
|
+
if (bytes.length < 25) return null;
|
|
211
|
+
if (bytes[20] !== 0x2f || chunkBytes < 6 || 20 + chunkBytes + (chunkBytes & 1) !== declaredBytes) fail(415, "INVALID_IMAGE");
|
|
212
|
+
return {
|
|
213
|
+
width: 1 + (((bytes[22]! & 0x3f) << 8) | bytes[21]!),
|
|
214
|
+
height: 1 + (((bytes[24]! & 0x0f) << 10) | (bytes[23]! << 2) | ((bytes[22]! & 0xc0) >> 6)),
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
if (kind === "VP8 ") {
|
|
218
|
+
if (bytes.length < 30) return null;
|
|
219
|
+
if (!matches(bytes, 23, [0x9d, 0x01, 0x2a]) || chunkBytes < 10
|
|
220
|
+
|| 20 + chunkBytes + (chunkBytes & 1) !== declaredBytes) fail(415, "INVALID_IMAGE");
|
|
221
|
+
return { width: readU16LE(bytes, 26) & 0x3fff, height: readU16LE(bytes, 28) & 0x3fff };
|
|
222
|
+
}
|
|
223
|
+
fail(415, "INVALID_IMAGE");
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
function inspectJpeg(bytes: Uint8Array) {
|
|
227
|
+
if (bytes.length < 4) return null;
|
|
228
|
+
if (bytes[0] !== 0xff || bytes[1] !== 0xd8) fail(415, "INVALID_IMAGE");
|
|
229
|
+
let offset = 2;
|
|
230
|
+
while (offset + 3 < bytes.length) {
|
|
231
|
+
if (bytes[offset] !== 0xff) fail(415, "INVALID_IMAGE");
|
|
232
|
+
while (bytes[offset] === 0xff) offset += 1;
|
|
233
|
+
if (offset >= bytes.length) return null;
|
|
234
|
+
const marker = bytes[offset++]!;
|
|
235
|
+
if (marker === 0xd9 || marker === 0xda) fail(415, "INVALID_IMAGE");
|
|
236
|
+
if (marker === 0x01 || (marker >= 0xd0 && marker <= 0xd7)) continue;
|
|
237
|
+
if (offset + 1 >= bytes.length) return null;
|
|
238
|
+
const length = (bytes[offset]! << 8) | bytes[offset + 1]!;
|
|
239
|
+
if (length < 2) fail(415, "INVALID_IMAGE");
|
|
240
|
+
if (isStartOfFrame(marker)) {
|
|
241
|
+
if (length < 11) fail(415, "INVALID_IMAGE");
|
|
242
|
+
if (offset + length > bytes.length) return null;
|
|
243
|
+
const components = bytes[offset + 7]!;
|
|
244
|
+
if (bytes[offset + 2] !== 8 || components < 1 || components > 4 || length !== 8 + 3 * components) fail(415, "INVALID_IMAGE");
|
|
245
|
+
return {
|
|
246
|
+
height: (bytes[offset + 3]! << 8) | bytes[offset + 4]!,
|
|
247
|
+
width: (bytes[offset + 5]! << 8) | bytes[offset + 6]!,
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
if (offset + length > bytes.length) return null;
|
|
251
|
+
offset += length;
|
|
252
|
+
}
|
|
253
|
+
return null;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
function isStartOfFrame(marker: number): boolean {
|
|
257
|
+
return marker >= 0xc0 && marker <= 0xcf && ![0xc4, 0xc8, 0xcc].includes(marker);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
function assertDimensions(width: number, height: number): void {
|
|
261
|
+
if (width < 1 || height < 1 || width > MAX_DIMENSION || height > MAX_DIMENSION || width * height > MAX_PIXELS) {
|
|
262
|
+
fail(415, "INVALID_IMAGE_DIMENSIONS");
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
function toBytes(value: unknown): Uint8Array {
|
|
267
|
+
if (typeof value === "string") return Buffer.from(value);
|
|
268
|
+
if (value instanceof Uint8Array) return value;
|
|
269
|
+
fail(400, "INVALID_BODY_CHUNK");
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
class InputError extends Error {
|
|
273
|
+
constructor(readonly status: 400 | 404 | 413 | 415, readonly code: string) { super(code); }
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
function fail(status: 400 | 404 | 413 | 415, code: string): never { throw new InputError(status, code); }
|
|
277
|
+
function asInputError(error: unknown): InputError {
|
|
278
|
+
return error instanceof InputError ? error : new InputError(400, "INVALID_UPLOAD_BODY");
|
|
279
|
+
}
|
|
280
|
+
function isResult(value: OrderReviewRawUploadSession | OrderReviewRawUploadResult): value is OrderReviewRawUploadResult {
|
|
281
|
+
return "kind" in value;
|
|
282
|
+
}
|
|
283
|
+
function sendResult(res: HttpResponse, result: OrderReviewRawUploadResult): void {
|
|
284
|
+
if (result.kind === "complete") {
|
|
285
|
+
res.status(result.status).json({ data: { mediaRef: result.mediaRef } });
|
|
286
|
+
} else sendError(res, result.status, result.code);
|
|
287
|
+
}
|
|
288
|
+
function sendError(res: HttpResponse, status: number, code: string): void {
|
|
289
|
+
res.status(status).json({ error: { code, message: "Order review media request refused" } });
|
|
290
|
+
}
|
|
291
|
+
function matches(bytes: Uint8Array, offset: number, expected: number[]): boolean {
|
|
292
|
+
return expected.every((value, index) => bytes[offset + index] === value);
|
|
293
|
+
}
|
|
294
|
+
function ascii(bytes: Uint8Array, offset: number, length: number): string {
|
|
295
|
+
return String.fromCharCode(...bytes.subarray(offset, offset + length));
|
|
296
|
+
}
|
|
297
|
+
function readU16LE(bytes: Uint8Array, offset: number): number { return bytes[offset]! | (bytes[offset + 1]! << 8); }
|
|
298
|
+
function readU24LE(bytes: Uint8Array, offset: number): number { return readU16LE(bytes, offset) | (bytes[offset + 2]! << 16); }
|
|
299
|
+
function readU32LE(bytes: Uint8Array, offset: number): number { return (readU16LE(bytes, offset) | (readU16LE(bytes, offset + 2) << 16)) >>> 0; }
|
|
300
|
+
function readU32BE(bytes: Uint8Array, offset: number): number { return ((bytes[offset]! << 24) | (bytes[offset + 1]! << 16) | (bytes[offset + 2]! << 8) | bytes[offset + 3]!) >>> 0; }
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import type { CommerceEmailRuntime } from "./emailRuntime.js";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { COMMERCE_CHECKOUT_EXPIRED_EVENT_TYPE } from "../outboxEventSchemas.js";
|
|
4
|
+
import type {
|
|
5
|
+
OutboxEventRow,
|
|
6
|
+
OutboxHandler,
|
|
7
|
+
OutboxHandlerOutcome,
|
|
8
|
+
} from "../outboxDispatchContracts.js";
|
|
9
|
+
import {
|
|
10
|
+
OUTBOX_CHECKOUT_EXPIRED_TEMPLATE_SLUG,
|
|
11
|
+
type OrderPaymentLifecyclePort,
|
|
12
|
+
type OrderRecipientPort,
|
|
13
|
+
type TransactionalEmailPort,
|
|
14
|
+
} from "../outboxOrderDraftEmailPorts.js";
|
|
15
|
+
import { shouldSkipCheckoutExpired } from "../orderEmailEligibility.js";
|
|
16
|
+
|
|
17
|
+
export { OUTBOX_CHECKOUT_EXPIRED_TEMPLATE_SLUG };
|
|
18
|
+
|
|
19
|
+
const HANDLER_TIMEOUT_MS = 10_000;
|
|
20
|
+
|
|
21
|
+
export const outboxCheckoutExpiredEmailDescriptor = Object.freeze({
|
|
22
|
+
eventType: COMMERCE_CHECKOUT_EXPIRED_EVENT_TYPE, timeoutMs: HANDLER_TIMEOUT_MS,
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
const payloadSubsetSchema = z
|
|
26
|
+
.object({
|
|
27
|
+
orderUuid: z.guid(),
|
|
28
|
+
orderId: z.string().min(1),
|
|
29
|
+
totalCents: z.number().int().nonnegative().optional(),
|
|
30
|
+
currency: z.string().trim().min(1).optional(),
|
|
31
|
+
recoveryToken: z.string().trim().min(1).optional(),
|
|
32
|
+
})
|
|
33
|
+
.passthrough();
|
|
34
|
+
|
|
35
|
+
export function createOutboxCheckoutExpiredEmailHandler<Locale extends string>(deps: {
|
|
36
|
+
runtime: Pick<CommerceEmailRuntime<Locale>, "formatMoney" | "mapSendOutcome" | "parseOutboxPayload" | "resolveLocale">;
|
|
37
|
+
emailPort: TransactionalEmailPort<Locale>;
|
|
38
|
+
recipientPort: OrderRecipientPort;
|
|
39
|
+
lifecyclePort: OrderPaymentLifecyclePort;
|
|
40
|
+
}): OutboxHandler {
|
|
41
|
+
return {
|
|
42
|
+
...outboxCheckoutExpiredEmailDescriptor,
|
|
43
|
+
async handle(row: OutboxEventRow, signal: AbortSignal): Promise<OutboxHandlerOutcome> {
|
|
44
|
+
const parsed = deps.runtime.parseOutboxPayload(payloadSubsetSchema, row.payload);
|
|
45
|
+
if (parsed.ok === false) {
|
|
46
|
+
return parsed.outcome;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const lifecycle = await deps.lifecyclePort.read(parsed.data.orderUuid, signal);
|
|
50
|
+
const skipReason = shouldSkipCheckoutExpired(lifecycle);
|
|
51
|
+
if (skipReason) {
|
|
52
|
+
return { kind: "processed", detail: { skipped: skipReason } };
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const recipient = await deps.recipientPort.resolve(parsed.data.orderUuid, signal);
|
|
56
|
+
if (recipient === null) {
|
|
57
|
+
return { kind: "processed", detail: { skipped: "recipient_unresolved" } };
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const alreadySent = await deps.emailPort.findExistingSend(
|
|
61
|
+
OUTBOX_CHECKOUT_EXPIRED_TEMPLATE_SLUG,
|
|
62
|
+
row.id,
|
|
63
|
+
);
|
|
64
|
+
if (alreadySent) {
|
|
65
|
+
return { kind: "processed", detail: { dedupe: "email_already_sent" } };
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const payload = parsed.data;
|
|
69
|
+
const amountLabel =
|
|
70
|
+
payload.totalCents !== undefined && payload.currency !== undefined
|
|
71
|
+
? deps.runtime.formatMoney(payload.totalCents, payload.currency)
|
|
72
|
+
: null;
|
|
73
|
+
const outcome = await deps.emailPort.sendCheckoutExpiredNotice({
|
|
74
|
+
to: recipient.email,
|
|
75
|
+
firstName: recipient.firstName,
|
|
76
|
+
orderId: payload.orderId,
|
|
77
|
+
amountLabel,
|
|
78
|
+
recoveryToken: payload.recoveryToken ?? null,
|
|
79
|
+
outboxEventId: row.id,
|
|
80
|
+
locale: deps.runtime.resolveLocale(recipient.country ?? null),
|
|
81
|
+
signal,
|
|
82
|
+
});
|
|
83
|
+
return deps.runtime.mapSendOutcome(outcome);
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
}
|