@eventsdk/sdk 0.0.0-stage → 0.4.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/LICENSE +201 -0
- package/NOTICE +9 -0
- package/dist/compatibility-http/bridge/receive.d.ts +3 -0
- package/dist/compatibility-http/bridge/types.d.ts +44 -0
- package/dist/compatibility-http/index.d.ts +4 -0
- package/dist/compatibility-http/index.js +1 -0
- package/dist/compatibility-http/policy/validate-policy.d.ts +3 -0
- package/dist/conformance/admission/harness.d.ts +20 -0
- package/dist/conformance/admission/run-suite.d.ts +2 -0
- package/dist/conformance/consumer/harness.d.ts +24 -0
- package/dist/conformance/consumer/run-apply-suite.d.ts +2 -0
- package/dist/conformance/consumer/run-worker-suite.d.ts +2 -0
- package/dist/conformance/event-link/harness.d.ts +13 -0
- package/dist/conformance/event-link/run-suite.d.ts +2 -0
- package/dist/conformance/fanout/harness.d.ts +39 -0
- package/dist/conformance/fanout/run-suite.d.ts +2 -0
- package/dist/conformance/gap/harness.d.ts +19 -0
- package/dist/conformance/gap/run-suite.d.ts +2 -0
- package/dist/conformance/index.d.ts +22 -0
- package/dist/conformance/index.js +1 -0
- package/dist/conformance/producer/harness.d.ts +21 -0
- package/dist/conformance/producer/run-suite.d.ts +2 -0
- package/dist/conformance/receipt/harness.d.ts +12 -0
- package/dist/conformance/receipt/projection-harness.d.ts +9 -0
- package/dist/conformance/receipt/run-projection-suite.d.ts +2 -0
- package/dist/conformance/receipt/run-suite.d.ts +2 -0
- package/dist/conformance/reliability/checks.d.ts +4 -0
- package/dist/conformance/result/harness.d.ts +15 -0
- package/dist/conformance/result/run-suite.d.ts +2 -0
- package/dist/conformance/version/compatibility.d.ts +13 -0
- package/dist/contracts/canonical/canonical-json.d.ts +1 -0
- package/dist/contracts/contract-types.d.ts +34 -0
- package/dist/contracts/generated/business-receipt.d.ts +21 -0
- package/dist/contracts/generated/cloud-event-context.d.ts +32 -0
- package/dist/contracts/generated/cloud-event-fanout.d.ts +33 -0
- package/dist/contracts/generated/cloud-event.d.ts +24 -0
- package/dist/contracts/generated/event-link-authorization-request.d.ts +22 -0
- package/dist/contracts/generated/event-link-proposal.d.ts +27 -0
- package/dist/contracts/generated/event-link-token-request.d.ts +7 -0
- package/dist/contracts/generated/event-origin-claims.d.ts +13 -0
- package/dist/contracts/generated/exchange-grant.d.ts +11 -0
- package/dist/contracts/generated/exchange-registration.d.ts +24 -0
- package/dist/contracts/generated/fanout-event-draft.d.ts +28 -0
- package/dist/contracts/generated/gap-baseline.d.ts +18 -0
- package/dist/contracts/generated/gap-recovery-command.d.ts +7 -0
- package/dist/contracts/generated/identity-context.d.ts +15 -0
- package/dist/contracts/generated/namespaced-reference.d.ts +4 -0
- package/dist/contracts/generated/native-event-catalog.d.ts +19 -0
- package/dist/contracts/generated/node-connection-profile.d.ts +217 -0
- package/dist/contracts/generated/node-worker-observation.d.ts +7 -0
- package/dist/contracts/generated/outbox-recovery-command.d.ts +8 -0
- package/dist/contracts/generated/portable-event-link-authorization-request.d.ts +98 -0
- package/dist/contracts/generated/portable-event-link-proposal.d.ts +121 -0
- package/dist/contracts/generated/portable-event-link-token-request.d.ts +34 -0
- package/dist/contracts/generated/portable-exchange-registration.d.ts +109 -0
- package/dist/contracts/generated/portable-gap-baseline.d.ts +93 -0
- package/dist/contracts/generated/portable-gap-recovery-command.d.ts +35 -0
- package/dist/contracts/generated/portable-outbox-recovery-command.d.ts +37 -0
- package/dist/contracts/generated/public-jwks-snapshot.d.ts +141 -0
- package/dist/contracts/generated/result-ref.d.ts +8 -0
- package/dist/contracts/generated/supported-profiles.d.ts +3 -0
- package/dist/contracts/generated/tenant-connection.d.ts +13 -0
- package/dist/contracts/generated/tenant-context.d.ts +4 -0
- package/dist/contracts/index.d.ts +31 -0
- package/dist/contracts/index.js +1 -0
- package/dist/contracts/validation/contract-error.d.ts +16 -0
- package/dist/contracts/validation/contracts.d.ts +316 -0
- package/dist/contracts/validation/decode-cloud-event.d.ts +2 -0
- package/dist/contracts/validation/event-link.d.ts +9 -0
- package/dist/contracts/validation/identity-context.d.ts +3 -0
- package/dist/contracts/validation/origin-proof-wire.d.ts +3 -0
- package/dist/contracts/validation/strict-json.d.ts +1 -0
- package/dist/core/inbox/accept-delivery.d.ts +26 -0
- package/dist/core/inbox/apply-delivery.d.ts +29 -0
- package/dist/core/inbox/domain-apply-result.d.ts +13 -0
- package/dist/core/inbox/inbox-worker.d.ts +2 -0
- package/dist/core/inbox/read-result.d.ts +12 -0
- package/dist/core/inbox/worker-types.d.ts +21 -0
- package/dist/core/index.d.ts +50 -0
- package/dist/core/index.js +1 -0
- package/dist/core/outbox/authorize-recovery.d.ts +75 -0
- package/dist/core/outbox/outbox-relay.d.ts +26 -0
- package/dist/core/outbox/record-event.d.ts +10 -0
- package/dist/core/outbox/record-fanout.d.ts +16 -0
- package/dist/core/ports/dead-letter.d.ts +29 -0
- package/dist/core/ports/inbox.d.ts +43 -0
- package/dist/core/ports/observability.d.ts +21 -0
- package/dist/core/ports/origin-refresh.d.ts +5 -0
- package/dist/core/ports/outbox.d.ts +46 -0
- package/dist/core/ports/result-reader.d.ts +14 -0
- package/dist/core/ports/transport.d.ts +13 -0
- package/dist/core/receipt/receipt-state.d.ts +3 -0
- package/dist/core/recovery/event-log.d.ts +28 -0
- package/dist/core/recovery/gap-baseline-binding.d.ts +2 -0
- package/dist/core/recovery/gap-recovery.d.ts +15 -0
- package/dist/core/recovery/receipt-identity-recovery.d.ts +8 -0
- package/dist/core/recovery/receipt-recovery.d.ts +14 -0
- package/dist/core/recovery/replay-dead-letter.d.ts +4 -0
- package/dist/core/runtime/dependencies.d.ts +19 -0
- package/dist/core/runtime/errors.d.ts +6 -0
- package/dist/core/runtime/event-identity.d.ts +14 -0
- package/dist/core/runtime/exchange-connection.d.ts +7 -0
- package/dist/core/runtime/fanout-identity.d.ts +6 -0
- package/dist/core/runtime/lease.d.ts +6 -0
- package/dist/core/runtime/observe-health.d.ts +3 -0
- package/dist/core/runtime/operation.d.ts +2 -0
- package/dist/core/runtime/retry.d.ts +14 -0
- package/dist/event-link/errors.d.ts +5 -0
- package/dist/event-link/exchange.d.ts +9 -0
- package/dist/event-link/index.d.ts +12 -0
- package/dist/event-link/index.js +1 -0
- package/dist/event-link/primitives.d.ts +10 -0
- package/dist/event-link/protocol.d.ts +21 -0
- package/dist/event-link/receiver-ports.d.ts +42 -0
- package/dist/event-link/receiver.d.ts +18 -0
- package/dist/event-link/registration.d.ts +21 -0
- package/dist/event-link/sender.d.ts +22 -0
- package/dist/identity-contracts/authorization/authorization-port.d.ts +35 -0
- package/dist/identity-contracts/index.d.ts +2 -0
- package/dist/identity-contracts/index.js +0 -0
- package/dist/identity-contracts/origin/verified-origin.d.ts +28 -0
- package/dist/identity-verifier/index.d.ts +6 -0
- package/dist/identity-verifier/index.js +1 -0
- package/dist/identity-verifier/jwt/service-token-verifier.d.ts +15 -0
- package/dist/identity-verifier/origin/event-origin-policy.d.ts +36 -0
- package/dist/identity-verifier/origin/event-origin-signer.d.ts +6 -0
- package/dist/identity-verifier/origin/event-origin-verifier.d.ts +6 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.js +22 -0
- package/dist/node-config/configuration-error.d.ts +4 -0
- package/dist/node-config/diagnostics/check-configuration.d.ts +40 -0
- package/dist/node-config/identity/load-identity.d.ts +14 -0
- package/dist/node-config/identity/local-recovery-origin.d.ts +3 -0
- package/dist/node-config/identity/public-identity.d.ts +87 -0
- package/dist/node-config/identity/public-snapshot.d.ts +2 -0
- package/dist/node-config/identity/signing-identity.d.ts +5 -0
- package/dist/node-config/index.d.ts +12 -0
- package/dist/node-config/index.js +1 -0
- package/dist/node-config/main.js +3 -0
- package/dist/node-config/operations/export-own-public.d.ts +8 -0
- package/dist/node-config/operations/refresh-trust.d.ts +10 -0
- package/dist/node-config/profile/load-profile.d.ts +6 -0
- package/dist/node-config/profile/validate-profile.d.ts +2 -0
- package/dist/node-worker/index.d.ts +3 -0
- package/dist/node-worker/index.js +1 -0
- package/dist/node-worker/lifecycle.d.ts +19 -0
- package/dist/node-worker/route-scheduler.d.ts +17 -0
- package/dist/node-worker/session.d.ts +15 -0
- package/dist/provisioner/application/apply.d.ts +11 -0
- package/dist/provisioner/application/ports.d.ts +44 -0
- package/dist/provisioner/application/verify.d.ts +7 -0
- package/dist/provisioner/cli/arguments.d.ts +9 -0
- package/dist/provisioner/cli/live-command.d.ts +7 -0
- package/dist/provisioner/cli/main.js +2 -0
- package/dist/provisioner/cli/run.d.ts +2 -0
- package/dist/provisioner/cli/session-types.d.ts +26 -0
- package/dist/provisioner/conformance/policy.d.ts +9 -0
- package/dist/provisioner/index.d.ts +17 -0
- package/dist/provisioner/index.js +1 -0
- package/dist/provisioner/manifest/types.d.ts +55 -0
- package/dist/provisioner/manifest/validate.d.ts +3 -0
- package/dist/provisioner/nats/inspector.d.ts +13 -0
- package/dist/provisioner/nats/types.d.ts +38 -0
- package/dist/provisioner/nats/writer-types.d.ts +11 -0
- package/dist/provisioner/nats/writer.d.ts +18 -0
- package/dist/provisioner/planning/digest.d.ts +1 -0
- package/dist/provisioner/planning/plan.d.ts +18 -0
- package/dist/transport-nats/connection/delivery-session.d.ts +10 -0
- package/dist/transport-nats/connection/verified-connection.d.ts +12 -0
- package/dist/transport-nats/consume/delivery-handler.d.ts +34 -0
- package/dist/transport-nats/consume/nats-consumer.d.ts +18 -0
- package/dist/transport-nats/index.d.ts +12 -0
- package/dist/transport-nats/index.js +3 -0
- package/dist/transport-nats/publish/nats-publisher.d.ts +24 -0
- package/dist/transport-nats/transport-error.d.ts +5 -0
- package/licenses/NATS-LICENSE +201 -0
- package/package.json +79 -3
- package/README.md +0 -3
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var CoreError=class extends Error{constructor(code){super(code);this.code=code;this.name="CoreError"}code};function assertNotAborted(signal){if(signal?.aborted)throw new CoreError("ABORTED")}async function boundedOperation(options,operation){assertNotAborted(options.signal);if(!Number.isSafeInteger(options.timeoutMs)||options.timeoutMs<1||options.timeoutMs>2147483647){throw new CoreError("INVALID_CONFIGURATION")}const controller=new AbortController;let rejectAbort;const stopped=new Promise((_resolve,reject)=>{rejectAbort=reject});const stop=code=>{controller.abort();rejectAbort?.(new CoreError(code))};const onAbort=()=>stop("ABORTED");options.signal?.addEventListener("abort",onAbort,{once:true});const timer=setTimeout(()=>stop("TIMEOUT"),options.timeoutMs);try{return await Promise.race([Promise.resolve().then(()=>{assertNotAborted(controller.signal);return operation(controller.signal)}),stopped])}finally{clearTimeout(timer);options.signal?.removeEventListener("abort",onAbort)}}function assertLiveLease(lease,now){if(!Number.isFinite(now)||!lease.token||!Number.isSafeInteger(lease.generation)||lease.generation<1||!Number.isFinite(lease.expiresAt)||lease.expiresAt<=now){throw new CoreError("STALE_LEASE")}}function decideRetry(attempt,now,policy,random){if(!Number.isSafeInteger(attempt)||attempt<1||!Number.isSafeInteger(now)||now<0||!Number.isSafeInteger(policy.maxAttempts)||policy.maxAttempts<1||!Number.isSafeInteger(policy.baseDelayMs)||policy.baseDelayMs<0||!Number.isSafeInteger(policy.maxDelayMs)||policy.maxDelayMs<policy.baseDelayMs||policy.jitterRatio<0||policy.jitterRatio>1||!Number.isFinite(policy.jitterRatio)){throw new CoreError("INVALID_CONFIGURATION")}if(attempt>=policy.maxAttempts)return{kind:"EXHAUSTED"};const sample=random.next();if(!Number.isFinite(sample)||sample<0||sample>=1)throw new CoreError("INVALID_CONFIGURATION");const base=Math.min(policy.maxDelayMs,policy.baseDelayMs*2**Math.min(attempt-1,52));const delay=Math.min(policy.maxDelayMs,base*(1-policy.jitterRatio+sample*policy.jitterRatio));const nextAttemptAt=now+Math.floor(delay);if(!Number.isSafeInteger(nextAttemptAt))throw new CoreError("INVALID_CONFIGURATION");return{kind:"RETRY",nextAttemptAt}}import{canonicalJson}from"@eventsdk/sdk/contracts";function eventMessageId(event,digest){return digest.sha256(event.deliveryid===void 0?`${event.source}\0${event.id}`:canonicalJson(["eventsdk-delivery-message/1",event.source,event.id,event.deliveryid]))}function eventDigest(event,digest){return digest.sha256(canonicalJson(event))}function inboxKey(key){return[key.consumerRef,key.targetScope,key.source,key.id].map(value=>`${value.length}:${value}`).join("")}import{parseCloudEvent}from"@eventsdk/sdk/contracts";function assertOrigin(event,origin,now){if(!Number.isFinite(now)||!origin.issuer||!origin.subject||!Array.isArray(origin.audience)||event.serviceorigin!==origin.serviceRef||!origin.audience.includes(event.audience)||!Number.isFinite(Date.parse(origin.expiresAt))||Date.parse(origin.expiresAt)<=now||!Number.isFinite(Date.parse(origin.verifiedAt))||Date.parse(origin.verifiedAt)>now){throw new CoreError("ORIGIN_MISMATCH")}}function authorizedScope(event,decision){if(decision.decision!=="ALLOW"){throw new CoreError(decision.decision==="DENY"?"AUTHORIZATION_DENIED":"AUTHORIZATION_UNKNOWN")}if(!decision.targetScope||decision.source!==event.source||decision.connectionRef!==event.connectionref||decision.grantRef!==event.grantref||decision.grantVersion!==event.grantversion){throw new CoreError("AUTHORIZATION_DENIED")}return decision.targetScope}import{canonicalJson as canonicalJson2,parseFanoutEventDraft}from"@eventsdk/sdk/contracts";function fanoutLogicalEvent(event){const{audience:_audience,connectionref:_connection,grantref:_grant,grantversion:_version,deliveryid:_delivery,...logical}=event;return parseFanoutEventDraft(logical)}function logicalEventDigest(event,digest){return digest.sha256(canonicalJson2(event.profile==="eventsdk/1.2"?fanoutLogicalEvent(event):event))}function deriveDeliveryId(event,digest){return digest.sha256(canonicalJson2(["eventsdk-delivery/1",event.source,event.id,event.audience,event.connectionref]))}async function assertDeliveryIdentity(event,digest){if(event.profile==="eventsdk/1.2"&&event.deliveryid!==await deriveDeliveryId(event,digest))throw new CoreError("EVENT_ID_CONFLICT")}function immutableSnapshot(value){return freezeDeep(structuredClone(value))}function freezeDeep(value){if(value!==null&&typeof value==="object"&&!Object.isFrozen(value)){Object.freeze(value);for(const nested of Object.values(value))freezeDeep(nested)}return value}async function recordEvent(tx,input,origin,dependencies,options){const event=immutableSnapshot(parseCloudEvent(input));origin=immutableSnapshot(origin);await boundedOperation(options,async signal=>{assertOrigin(event,origin,dependencies.clock.now());await assertDeliveryIdentity(event,dependencies.digest);if(event.profile==="eventsdk/1.2"&&!dependencies.outbox.recordFanoutInTransaction)throw new CoreError("ADAPTER_CAPABILITY_REQUIRED");const decision=await dependencies.authorization.authorize({phase:"OUTBOUND",event,origin,signal});if(authorizedScope(event,decision)!==event.sourcetenant)throw new CoreError("AUTHORIZATION_DENIED");const digest=await eventDigest(event,dependencies.digest);assertOrigin(event,origin,dependencies.clock.now());const record={event,origin,digest};if(event.profile==="eventsdk/1.2"){if(!dependencies.outbox.recordFanoutInTransaction)throw new CoreError("ADAPTER_CAPABILITY_REQUIRED");await dependencies.outbox.recordFanoutInTransaction(tx,{...record,logicalDigest:await logicalEventDigest(event,dependencies.digest),deliveryId:event.deliveryid},signal)}else await dependencies.outbox.recordInTransaction(tx,record,signal)})}async function refreshOrigin(event,previous,clock,signal,port){const verified=port?immutableSnapshot(await port.refresh(event,previous,signal)):previous;assertOrigin(event,verified,clock.now());return verified}async function publishClaim(claim,deps,options){try{return await boundedOperation(options,async signal=>{assertLiveLease(claim.lease,deps.clock.now());await assertDeliveryIdentity(claim.event,deps.digest);if(await eventDigest(claim.event,deps.digest)!==claim.digest)throw new CoreError("EVENT_ID_CONFLICT");const origin=await refreshOrigin(claim.event,claim.origin,deps.clock,signal,deps.originRefresh);const decision=await deps.authorization.authorize({phase:"OUTBOUND",event:claim.event,origin,signal});if(authorizedScope(claim.event,decision)!==claim.event.sourcetenant)throw new CoreError("AUTHORIZATION_DENIED");const messageId=await eventMessageId(claim.event,deps.digest);assertOrigin(claim.event,origin,deps.clock.now());assertLiveLease(claim.lease,deps.clock.now());const ack=await deps.publisher.publish(claim.event,{messageId,signal});return{status:"PUBLISHED",ack}})}catch(error){if(error instanceof CoreError&&["AUTHORIZATION_DENIED","AUTHORIZATION_UNKNOWN","ORIGIN_MISMATCH","EVENT_ID_CONFLICT"].includes(error.code)){return{status:"HOLD",reasonCode:error.code}}const retry=decideRetry(claim.attempt,deps.clock.now(),options.retry,deps.random);return retry.kind==="RETRY"?{status:"UNKNOWN",nextAttemptAt:retry.nextAttemptAt}:{status:"HOLD",reasonCode:"PUBLISH_UNKNOWN_RETRY_EXHAUSTED"}}}async function relayOutbox(deps,options){if(!Number.isSafeInteger(options.batchSize)||options.batchSize<1||options.batchSize>1e3||!Number.isFinite(options.leaseMs)||options.leaseMs<=options.timeoutMs)throw new CoreError("INVALID_CONFIGURATION");const claims=await boundedOperation(options,signal=>deps.outbox.claimReady({limit:options.batchSize,now:deps.clock.now(),leaseMs:options.leaseMs,signal}));if(claims.length>options.batchSize)throw new CoreError("INVALID_CONFIGURATION");const summary={published:0,unknown:0,held:0};const immutableClaims=immutableSnapshot(claims);for(const raw of immutableClaims){const claim=immutableSnapshot(raw);assertNotAborted(options.signal);assertLiveLease(claim.lease,deps.clock.now());if(claim.event.profile==="eventsdk/1.2"&&!deps.outbox.settleFanoutPublish)throw new CoreError("ADAPTER_CAPABILITY_REQUIRED");const outcome=await publishClaim(claim,deps,options);await boundedOperation({timeoutMs:options.timeoutMs},signal=>{assertLiveLease(claim.lease,deps.clock.now());if(claim.event.profile==="eventsdk/1.2"){if(!deps.outbox.settleFanoutPublish)throw new CoreError("ADAPTER_CAPABILITY_REQUIRED");return deps.outbox.settleFanoutPublish(claim.event,claim.lease,outcome,signal)}return deps.outbox.settlePublish(claim.event,claim.lease,outcome,signal)});if(outcome.status==="PUBLISHED")summary.published+=1;else if(outcome.status==="UNKNOWN")summary.unknown+=1;else summary.held+=1}return summary}import{parseCloudEvent as parseCloudEvent2}from"@eventsdk/sdk/contracts";import{parseBusinessReceipt}from"@eventsdk/sdk/contracts";function receivedReceipt(event,deliveryRef,consumerRef,targetScope,clock,ids){return parseBusinessReceipt({receiptRef:ids.next(),originSource:event.source,originEventId:event.id,deliveryRef,consumerRef,targetScope,disposition:"RECEIVED",recordedAt:new Date(clock.now()).toISOString(),revision:1})}async function persistAdmission(record,inbox,digest,signal){if(record.event.profile!=="eventsdk/1.2")return inbox.persistAccepted(record,signal);if(!inbox.persistFanoutAccepted)throw new CoreError("ADAPTER_CAPABILITY_REQUIRED");return inbox.persistFanoutAccepted({...record,logicalDigest:await logicalEventDigest(record.event,digest),deliveryId:record.event.deliveryid},signal)}async function quarantine(input,deps,reasonCode,signal){await deps.inbox.persistQuarantine({deliveryRef:input.deliveryRef,consumerRef:input.consumerRef,reasonCode,recordedAt:new Date(deps.clock.now()).toISOString()},signal);if(reasonCode==="AUTHORIZATION_UNKNOWN")throw new CoreError("AUTHORIZATION_UNKNOWN");return{kind:"REJECTED",reasonCode}}async function admitVerified(event,input,deps,signal){let targetScope;try{if(event.audience!==deps.audience)throw new CoreError("ORIGIN_MISMATCH");assertOrigin(event,input.origin,deps.clock.now());await assertDeliveryIdentity(event,deps.digest);const decision=await deps.authorization.authorize({phase:"RECEIVE",event,origin:input.origin,consumerRef:input.consumerRef,signal});targetScope=authorizedScope(event,decision);assertOrigin(event,input.origin,deps.clock.now())}catch(error){if(!(error instanceof CoreError))throw error;return quarantine(input,deps,error.code,signal)}const receipt=receivedReceipt(event,input.deliveryRef,input.consumerRef,targetScope,deps.clock,deps.ids);const result=await persistAdmission({key:{source:event.source,id:event.id,consumerRef:input.consumerRef,targetScope},event,origin:input.origin,digest:await eventDigest(event,deps.digest),deliveryRef:input.deliveryRef,receipt},deps.inbox,deps.digest,signal);if(result.kind==="CONFLICT")return quarantine(input,deps,"EVENT_ID_CONFLICT",signal);return result}async function acceptDelivery(input,deps,options){input=immutableSnapshot(input);if(!input.consumerRef||!input.deliveryRef)throw new CoreError("INVALID_CONFIGURATION");return boundedOperation(options,async signal=>{let event;try{event=parseCloudEvent2(input.event)}catch{return quarantine(input,deps,"INVALID_CONTRACT",signal)}return admitVerified(event,input,deps,signal)})}import{parseBusinessReceipt as parseBusinessReceipt4}from"@eventsdk/sdk/contracts";import{canonicalJson as canonicalJson3,parseBusinessReceipt as parseBusinessReceipt2}from"@eventsdk/sdk/contracts";var transitions={RECEIVED:["APPLIED","REJECTED","HOLD","UNKNOWN"],HOLD:["APPLIED","REJECTED","HOLD","UNKNOWN"],UNKNOWN:["APPLIED","REJECTED","HOLD"],APPLIED:[],REJECTED:[]};function assertReceiptTransition(previous,next){const identity=["receiptRef","originSource","originEventId","deliveryRef","consumerRef","targetScope"];if(identity.some(field=>previous[field]!==next[field]))throw new CoreError("RECEIPT_MISMATCH");if(next.revision!==previous.revision+1||!transitions[previous.disposition].includes(next.disposition)){throw new CoreError("INVALID_TRANSITION")}}function classifyReceiptCommit(previous,next){parseBusinessReceipt2(previous);parseBusinessReceipt2(next);if(previous.disposition==="HOLD"&&canonicalJson3(previous)===canonicalJson3(next)){return"UNCHANGED"}assertReceiptTransition(previous,next);return"TRANSITION"}import{parseBusinessReceipt as parseBusinessReceipt3,parseCloudEvent as parseCloudEvent3}from"@eventsdk/sdk/contracts";async function validateClaim(claim,digest){parseCloudEvent3(claim.event);await assertDeliveryIdentity(claim.event,digest);parseBusinessReceipt3(claim.receipt);if(claim.key.source!==claim.event.source||claim.key.id!==claim.event.id||claim.receipt.originSource!==claim.event.source||claim.receipt.originEventId!==claim.event.id||claim.receipt.consumerRef!==claim.key.consumerRef||claim.receipt.targetScope!==claim.key.targetScope||claim.receipt.deliveryRef!==claim.deliveryRef)throw new CoreError("RECEIPT_MISMATCH");if(claim.receipt.disposition==="UNKNOWN")throw new CoreError("RECOVERY_REQUIRED");if(claim.receipt.disposition==="APPLIED"||claim.receipt.disposition==="REJECTED"){throw new CoreError("INVALID_TRANSITION")}if(await eventDigest(claim.event,digest)!==claim.digest)throw new CoreError("EVENT_ID_CONFLICT")}import{canonicalJson as canonicalJson4,parseResultRef}from"@eventsdk/sdk/contracts";async function readAuthorizedResult(request,reader,authorization,digest,signal,clock){request=immutableSnapshot(request);assertNotAborted(signal);assertOrigin(request.event,request.origin,clock.now());const reference=parseResultRef(request.reference);if(reference.sourceSystem!==request.event.serviceorigin)throw new CoreError("RESULT_MISMATCH");const decision=await authorization.authorize({phase:"RESULT_READ",event:request.event,origin:request.origin,consumerRef:request.consumerRef,targetScope:request.targetScope,resultRef:reference,signal});if(authorizedScope(request.event,decision)!==request.targetScope)throw new CoreError("TARGET_SCOPE_CHANGED");assertNotAborted(signal);assertOrigin(request.event,request.origin,clock.now());const raw=await reader.read(request.reference,{event:request.event,origin:request.origin,targetScope:request.targetScope,signal});if(!raw)throw new CoreError("RECOVERY_REQUIRED");const snapshot=immutableSnapshot(raw);parseResultRef(snapshot.reference);const fields=["sourceSystem","resourceType","resourceId","revision","digest","evidenceRef"];if(fields.some(field=>snapshot.reference[field]!==request.reference[field])||`sha256:${await digest.sha256(canonicalJson4(snapshot.value))}`!==request.reference.digest){throw new CoreError("RESULT_MISMATCH")}assertNotAborted(signal);assertOrigin(request.event,request.origin,clock.now());return snapshot}import{canonicalJson as canonicalJson6}from"@eventsdk/sdk/contracts";import{canonicalJson as canonicalJson5,parseResultRef as parseResultRef2}from"@eventsdk/sdk/contracts";function resultObject(value){if(value===null||typeof value!=="object"||Array.isArray(value))throw new CoreError("INVALID_DOMAIN_RESULT");const prototype=Object.getPrototypeOf(value);if(prototype!==Object.prototype&&prototype!==null)throw new CoreError("INVALID_DOMAIN_RESULT");for(const key of Reflect.ownKeys(value)){const descriptor=Object.getOwnPropertyDescriptor(value,key);if(typeof key!=="string"||!descriptor?.enumerable||!("value"in descriptor)){throw new CoreError("INVALID_DOMAIN_RESULT")}}return value}function appliedResult(value){if(Object.keys(value).some(key=>key!=="disposition"&&key!=="resultRef"))throw new CoreError("INVALID_DOMAIN_RESULT");if(!Object.hasOwn(value,"resultRef"))return Object.freeze({disposition:"APPLIED"});resultObject(value.resultRef);canonicalJson5(value.resultRef);const reference=parseResultRef2(value.resultRef);return immutableSnapshot({disposition:"APPLIED",resultRef:reference})}function normalizeDomainApplyResult(value){if(value===void 0)return Object.freeze({disposition:"APPLIED"});try{const result=resultObject(value);if(!Object.hasOwn(result,"disposition")||result.disposition==="APPLIED")return appliedResult(result);if(result.disposition!=="REJECTED"&&result.disposition!=="HOLD")throw new CoreError("INVALID_DOMAIN_RESULT");if(Object.keys(result).some(key=>key!=="disposition"&&key!=="reasonCode")||typeof result.reasonCode!=="string"||!/^[A-Z][A-Z0-9_]{0,63}$/.test(result.reasonCode)){throw new CoreError("INVALID_DOMAIN_RESULT")}return Object.freeze({disposition:result.disposition,reasonCode:result.reasonCode})}catch{throw new CoreError("INVALID_DOMAIN_RESULT")}}async function runDomainApply(tx,claim,deps,snapshot,signal){let invoked=false;let observed;const operation=async()=>{if(invoked)throw new CoreError("INVALID_DOMAIN_RESULT");invoked=true;observed=normalizeDomainApplyResult(await deps.domain.apply(tx,claim,snapshot,signal));return observed};if(!deps.inbox.withDomainSavepoint){const outcome2=await operation();if(outcome2.disposition!=="APPLIED")throw new CoreError("ADAPTER_CAPABILITY_REQUIRED");return outcome2}const outcome=normalizeDomainApplyResult(await deps.inbox.withDomainSavepoint(tx,operation,signal));if(!invoked||!observed||canonicalJson6(outcome)!==canonicalJson6(observed))throw new CoreError("INVALID_DOMAIN_RESULT");return outcome}function dispositionReceipt(claim,disposition,clock,reasonCode,resultRef){const{reasonCode:_previousReason,resultRef:_previousResult,...previous}=claim.receipt;const next={...previous,...reasonCode?{reasonCode}:{},...resultRef?{resultRef}:{},disposition,revision:claim.receipt.revision+1,recordedAt:new Date(clock.now()).toISOString()};assertReceiptTransition(claim.receipt,next);return parseBusinessReceipt4(next)}async function applyAuthorizedDomain(tx,claim,deps,snapshot,signal){assertNotAborted(signal);assertOrigin(claim.event,claim.origin,deps.clock.now());assertLiveLease(claim.lease,deps.clock.now());const outcome=await runDomainApply(tx,claim,deps,snapshot,signal);assertNotAborted(signal);assertOrigin(claim.event,claim.origin,deps.clock.now());assertLiveLease(claim.lease,deps.clock.now());if(outcome.disposition==="APPLIED"&&outcome.resultRef&&outcome.resultRef.sourceSystem!==claim.event.audience){throw new CoreError("RESULT_MISMATCH")}if(outcome.disposition==="HOLD"&&claim.receipt.disposition==="HOLD"&&claim.receipt.reasonCode===outcome.reasonCode)return claim.receipt;const receipt=outcome.disposition==="APPLIED"?dispositionReceipt(claim,"APPLIED",deps.clock,void 0,outcome.resultRef):dispositionReceipt(claim,outcome.disposition,deps.clock,outcome.reasonCode);await deps.inbox.completeInTransaction(tx,claim,receipt,signal);return receipt}async function applyTransaction(claim,deps,snapshot,signal){return deps.inbox.transact(claim,async tx=>{assertLiveLease(claim.lease,deps.clock.now());const decision=await deps.authorization.authorizeInTransaction(tx,{phase:"APPLY",event:claim.event,origin:claim.origin,consumerRef:claim.key.consumerRef,targetScope:claim.key.targetScope,signal});if(decision.decision!=="ALLOW"){if(decision.decision==="UNKNOWN"&&claim.receipt.disposition==="HOLD")return claim.receipt;const receipt=dispositionReceipt(claim,decision.decision==="DENY"?"REJECTED":"HOLD",deps.clock,/^[A-Z][A-Z0-9_]{0,63}$/.test(decision.reasonCode)?decision.reasonCode:"AUTHORIZATION_UNAVAILABLE");await deps.inbox.completeInTransaction(tx,claim,receipt,signal);return receipt}if(authorizedScope(claim.event,decision)!==claim.key.targetScope)throw new CoreError("TARGET_SCOPE_CHANGED");return applyAuthorizedDomain(tx,claim,deps,snapshot,signal)},signal)}async function applyDelivery(claim,deps,options,readback){claim=immutableSnapshot(claim);return boundedOperation(options,async signal=>{await validateClaim(claim,deps.digest);assertLiveLease(claim.lease,deps.clock.now());const origin=await refreshOrigin(claim.event,claim.origin,deps.clock,signal,deps.originRefresh);claim=immutableSnapshot({...claim,origin});let snapshot;if(readback)snapshot=await readAuthorizedResult({reference:readback.reference,event:claim.event,origin:claim.origin,consumerRef:claim.key.consumerRef,targetScope:claim.key.targetScope},readback.reader,readback.authorization,readback.digest,signal,deps.clock);return applyTransaction(claim,deps,snapshot,signal)})}import{parseBusinessReceipt as parseBusinessReceipt5}from"@eventsdk/sdk/contracts";async function recoverReceipt(key,deliveryRef,reader,options){key=immutableSnapshot({source:key.source,id:key.id,consumerRef:key.consumerRef,targetScope:key.targetScope});return boundedOperation(options,async signal=>{const raw=await reader.read(key,deliveryRef,signal);assertNotAborted(signal);if(!raw)return{status:"WAIT",receipt:null};const receipt=immutableSnapshot(parseBusinessReceipt5(raw));if(receipt.originSource!==key.source||receipt.originEventId!==key.id||receipt.consumerRef!==key.consumerRef||receipt.targetScope!==key.targetScope||receipt.deliveryRef!==deliveryRef)throw new CoreError("RECEIPT_MISMATCH");return{status:["APPLIED","REJECTED"].includes(receipt.disposition)?"RESOLVED":"WAIT",receipt}})}import{parseBusinessReceipt as parseBusinessReceipt6}from"@eventsdk/sdk/contracts";async function recoverReceiptByIdentity(key,reader,options){key=immutableSnapshot({source:key.source,id:key.id,consumerRef:key.consumerRef,targetScope:key.targetScope});if(Object.values(key).some(part=>typeof part!=="string"||part.length===0)){throw new CoreError("INVALID_CONFIGURATION")}return boundedOperation(options,async signal=>{const raw=await reader.readByIdentity(key,signal);assertNotAborted(signal);if(!raw)return{status:"WAIT",receipt:null};const receipt=immutableSnapshot(parseBusinessReceipt6(raw));if(receipt.originSource!==key.source||receipt.originEventId!==key.id||receipt.consumerRef!==key.consumerRef||receipt.targetScope!==key.targetScope){throw new CoreError("RECEIPT_MISMATCH")}return{status:receipt.disposition==="APPLIED"||receipt.disposition==="REJECTED"?"RESOLVED":"WAIT",receipt}})}async function stageEventLogPage(cursor,limit,source,checkpoint,options){if(!Number.isSafeInteger(limit)||limit<1||limit>1e3)throw new CoreError("INVALID_CONFIGURATION");return boundedOperation(options,async signal=>{const page=immutableSnapshot(await source.readAfter(cursor,limit,signal));if(page.kind==="GAP"){await checkpoint.recordGap(cursor,page.oldestAvailableCursor,signal);return"GAP"}if(page.items.length>limit||page.items.length>0&&page.nextCursor===cursor||page.items.some(item=>!item.revision||!item.commitEvidenceRef||!item.cursor)){throw new CoreError("INVALID_CONFIGURATION")}await checkpoint.stageAndAdvance(cursor,page,signal);return"PAGE"})}import{canonicalJson as canonicalJson7}from"@eventsdk/sdk/contracts";async function recoverGap(source,scope,expectedWatermark,port,options){return boundedOperation(options,async signal=>{const raw=await port.readAuthorized(source,scope,signal);assertNotAborted(signal);const snapshot=immutableSnapshot(raw);if(!snapshot)throw new CoreError("RECOVERY_REQUIRED");if(snapshot.source!==source||snapshot.scope!==scope||[snapshot.source,snapshot.scope,snapshot.revision,snapshot.watermark,snapshot.evidenceRef].some(reference=>typeof reference!=="string"||reference.length===0))throw new CoreError("RESULT_MISMATCH");canonicalJson7(snapshot.value);assertNotAborted(signal);await port.applyAndCheckpoint(expectedWatermark,snapshot,signal);assertNotAborted(signal);return snapshot})}async function replayDeadLetter(entry,port,authorization,options){entry=immutableSnapshot(entry);return boundedOperation(options,signal=>port.transactReplay(entry,async(tx,claim)=>{if(inboxKey(entry.key)!==inboxKey(claim.key)||entry.originalDeliveryRef!==claim.deliveryRef){throw new CoreError("RECEIPT_MISMATCH")}if(claim.receipt.disposition==="UNKNOWN")throw new CoreError("RECOVERY_REQUIRED");if(claim.receipt.disposition==="APPLIED"||claim.receipt.disposition==="REJECTED"){throw new CoreError("INVALID_TRANSITION")}const decision=await authorization.authorizeInTransaction(tx,{phase:"APPLY",event:claim.event,origin:claim.origin,consumerRef:claim.key.consumerRef,targetScope:claim.key.targetScope,signal});if(authorizedScope(claim.event,decision)!==claim.key.targetScope)throw new CoreError("TARGET_SCOPE_CHANGED");await port.requeueInTransaction(tx,claim,signal)},signal))}async function observeDeliveryHealth(port,sink,options){const health=await boundedOperation(options,signal=>port.read(signal));if(!Number.isFinite(health.observedAt)||health.oldestPendingAt!==null&&!Number.isFinite(health.oldestPendingAt)){throw new CoreError("INVALID_CONFIGURATION")}const gauges={outbox_pending:health.outboxPending,outbox_oldest_age_ms:health.oldestPendingAt===null?0:Math.max(0,health.observedAt-health.oldestPendingAt),consumer_lag:health.consumerLag,retry_pending:health.retryPending,quarantined:health.quarantined,unresolved_receipts:health.unresolvedReceipts,gaps:health.gaps,authorization_denials:health.authorizationDenials};if(health.brokerStoredBytes!==void 0)gauges.broker_stored_bytes=health.brokerStoredBytes;if(health.brokerQuotaBytes!==void 0)gauges.broker_quota_bytes=health.brokerQuotaBytes;if(health.bridgeUnconfirmed!==void 0)gauges.bridge_unconfirmed=health.bridgeUnconfirmed;if(Object.values(gauges).some(value=>!Number.isFinite(value)||value<0))throw new CoreError("INVALID_CONFIGURATION");for(const[name,value]of Object.entries(gauges))sink.gauge(`eventsdk_${name}`,value);return health}import{parseBusinessReceipt as parseBusinessReceipt7}from"@eventsdk/sdk/contracts";function assertCorrelated(claim,receipt){if(receipt.receiptRef!==claim.receipt.receiptRef||receipt.revision<claim.receipt.revision||(claim.receipt.disposition==="APPLIED"||claim.receipt.disposition==="REJECTED")&&receipt.disposition!==claim.receipt.disposition||receipt.originSource!==claim.key.source||receipt.originEventId!==claim.key.id||receipt.consumerRef!==claim.key.consumerRef||receipt.targetScope!==claim.key.targetScope||receipt.deliveryRef!==claim.deliveryRef)throw new CoreError("RECEIPT_MISMATCH")}async function quarantineWork(claim,deps,reasonCode,signal){await deps.deadLetters.quarantine(claim,{ref:deps.ids.next(),key:claim.key,originalDeliveryRef:claim.deliveryRef,reasonCode,attempts:claim.attempt,recordedAt:new Date(deps.clock.now()).toISOString()},signal);return"QUARANTINED"}async function reconcileWork(claim,deps,options){return boundedOperation({timeoutMs:options.timeoutMs},async signal=>{const raw=await deps.receipts.readReceipt(claim.key,signal);if(!raw)throw new CoreError("RECOVERY_REQUIRED");const receipt=immutableSnapshot(parseBusinessReceipt7(raw));assertCorrelated(claim,receipt);if(receipt.disposition==="APPLIED"||receipt.disposition==="REJECTED")return receipt.disposition;const current={...claim,receipt};if(receipt.disposition==="UNKNOWN")return quarantineWork(current,deps,"OUTCOME_UNKNOWN_READBACK_REQUIRED",signal);const retry=decideRetry(claim.attempt,deps.clock.now(),options.retry,deps.random);if(retry.kind==="EXHAUSTED")return quarantineWork(current,deps,"RETRY_EXHAUSTED",signal);await deps.work.defer(claim.key,claim.lease,receipt,retry.nextAttemptAt,"APPLY_NOT_TERMINAL",signal);return"RETRY"})}async function runClaim(claim,deps,options){try{assertLiveLease(claim.lease,deps.clock.now());if(claim.receipt.disposition==="RECEIVED"||claim.receipt.disposition==="HOLD"){try{await boundedOperation(options,signal=>deps.process(claim,{timeoutMs:options.timeoutMs,signal}))}catch{}}return await reconcileWork(claim,deps,options)}catch{return"UNRESOLVED"}}async function runInboxWorker(deps,options){if(!Number.isSafeInteger(options.batchSize)||options.batchSize<1||options.batchSize>1e3||!Number.isFinite(options.leaseMs)||options.leaseMs<=options.timeoutMs)throw new CoreError("INVALID_CONFIGURATION");const claims=immutableSnapshot(await boundedOperation(options,signal=>deps.work.claimReady({limit:options.batchSize,now:deps.clock.now(),leaseMs:options.leaseMs,signal})));if(claims.length>options.batchSize)throw new CoreError("INVALID_CONFIGURATION");const summary={APPLIED:0,REJECTED:0,RETRY:0,QUARANTINED:0,UNRESOLVED:0};for(const claim of claims){assertNotAborted(options.signal);if(!Number.isSafeInteger(claim.attempt)||claim.attempt<1)throw new CoreError("INVALID_CONFIGURATION");summary[await runClaim(claim,deps,options)]+=1}return summary}import{parseCloudEvent as parseCloudEvent4,parseFanoutEventDraft as parseFanoutEventDraft2}from"@eventsdk/sdk/contracts";async function prepareFanoutDelivery(input,route,digest){const fact=immutableSnapshot(parseFanoutEventDraft2(input));const keys=Object.keys(route);if(keys.length!==4||keys.some(k=>!["audience","connectionref","grantref","grantversion"].includes(k)))throw new CoreError("INVALID_CONFIGURATION");const draft={...fact,...immutableSnapshot(route)};const event=parseCloudEvent4({...draft,deliveryid:await deriveDeliveryId(draft,digest)});if(event.profile!=="eventsdk/1.2")throw new CoreError("INVALID_CONFIGURATION");return event}async function recordFanoutEvent(tx,draft,recipients,deps,options){const fact=immutableSnapshot(parseFanoutEventDraft2(draft));const targets=immutableSnapshot(recipients);if(targets.length<1||targets.length>1e3)throw new CoreError("INVALID_CONFIGURATION");if(!deps.outbox.recordFanoutInTransaction)throw new CoreError("ADAPTER_CAPABILITY_REQUIRED");return boundedOperation(options,async signal=>{const events=[];const deliveryIds=new Set;for(const target of targets){signal.throwIfAborted();const event=await prepareFanoutDelivery(fact,target.route,deps.digest);if(deliveryIds.has(event.deliveryid))throw new CoreError("INVALID_CONFIGURATION");deliveryIds.add(event.deliveryid);events.push(event)}for(const[index,target]of targets.entries()){const event=events[index];if(!event)throw new CoreError("INVALID_CONFIGURATION");await recordEvent(tx,event,target.origin,deps,{...options,signal})}return events})}import{canonicalJson as canonicalJson8,parseTenantContext}from"@eventsdk/sdk/contracts";async function deriveExchangeConnectionRef(input,digest){const from=parseTenantContext(input.from),to=parseTenantContext(input.to);try{if(new URL(input.source).href.length>2048)throw new Error("source")}catch{throw new CoreError("INVALID_CONFIGURATION")}return`urn:eventsdk:connection:${await digest.sha256(canonicalJson8(["eventsdk-native-connection/1",input.source,from,to]))}`}import{parseOutboxRecoveryCommand}from"@eventsdk/sdk/contracts";async function authorizeOutboxRecovery(command,stored,deps,options){const record=immutableSnapshot(stored),input=immutableSnapshot(parseOutboxRecoveryCommand(command));return boundedOperation(options,async signal=>{const event=record.event;if(event.source!==input.source||event.id!==input.id||event.deliveryid!==input.deliveryid||record.status!=="HOLD"||record.generation!==input.expectedGeneration)throw new CoreError("RECOVERY_REQUIRED");await assertDeliveryIdentity(event,deps.digest);if(await eventDigest(event,deps.digest)!==record.digest)throw new CoreError("EVENT_ID_CONFLICT");const origin=await refreshOrigin(event,record.origin,deps.clock,signal,deps.originRefresh);const scope=authorizedScope(event,await deps.authorization.authorize({phase:"OUTBOUND",event,origin,signal}));if(scope!==event.sourcetenant)throw new CoreError("TARGET_SCOPE_CHANGED");return immutableSnapshot({event,digest:record.digest,generation:record.generation,origin,targetScope:scope})})}import{parseGapBaseline}from"@eventsdk/sdk/contracts";function assertGapBaselineBinding(event,value,targetScope){const baseline=parseGapBaseline(value);if(event.profile!=="eventsdk/1.2"||event.kind!=="EVENT"||baseline.source!==event.source||baseline.sourceTenant!==event.sourcetenant||baseline.targetService!==event.audience||baseline.connectionRef!==event.connectionref||baseline.grantRef!==event.grantref||baseline.grantVersion!==event.grantversion||baseline.createdAt!==event.time||targetScope!==void 0&&baseline.targetTenant!==targetScope)throw new CoreError("RESULT_MISMATCH")}export{CoreError,acceptDelivery,applyDelivery,assertDeliveryIdentity,assertGapBaselineBinding,assertLiveLease,assertNotAborted,assertReceiptTransition,authorizeOutboxRecovery,boundedOperation,classifyReceiptCommit,decideRetry,deriveDeliveryId,deriveExchangeConnectionRef,eventDigest,eventMessageId,fanoutLogicalEvent,inboxKey,logicalEventDigest,observeDeliveryHealth,prepareFanoutDelivery,readAuthorizedResult,recordEvent,recordFanoutEvent,recoverGap,recoverReceipt,recoverReceiptByIdentity,relayOutbox,replayDeadLetter,runInboxWorker,stageEventLogPage};
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { type CloudEventV12, type OutboxRecoveryCommand } from '@eventsdk/sdk/contracts';
|
|
2
|
+
import type { AuthorizationPort } from '@eventsdk/sdk/identity-contracts';
|
|
3
|
+
import type { OutboxRecord } from '../ports/outbox.js';
|
|
4
|
+
import type { OriginRefreshPort } from '../ports/origin-refresh.js';
|
|
5
|
+
import type { Clock, Digest, OperationOptions } from '../runtime/dependencies.js';
|
|
6
|
+
export interface HeldOutboxRecord extends OutboxRecord {
|
|
7
|
+
readonly event: CloudEventV12;
|
|
8
|
+
readonly status: string;
|
|
9
|
+
readonly generation: number;
|
|
10
|
+
}
|
|
11
|
+
export declare function authorizeOutboxRecovery(command: OutboxRecoveryCommand, stored: HeldOutboxRecord, deps: {
|
|
12
|
+
authorization: AuthorizationPort;
|
|
13
|
+
originRefresh: OriginRefreshPort;
|
|
14
|
+
clock: Clock;
|
|
15
|
+
digest: Digest;
|
|
16
|
+
}, options: OperationOptions): Promise<{
|
|
17
|
+
event: {
|
|
18
|
+
readonly specversion: "1.0";
|
|
19
|
+
readonly id: string;
|
|
20
|
+
readonly source: string;
|
|
21
|
+
readonly type: string;
|
|
22
|
+
readonly time: string;
|
|
23
|
+
readonly dataschema: string;
|
|
24
|
+
readonly datacontenttype: "application/json";
|
|
25
|
+
readonly profile: "eventsdk/1.2";
|
|
26
|
+
readonly kind: "EVENT";
|
|
27
|
+
readonly serviceorigin: string;
|
|
28
|
+
readonly sourcetenant: string;
|
|
29
|
+
readonly audience: string;
|
|
30
|
+
readonly connectionref: string;
|
|
31
|
+
readonly grantref: string;
|
|
32
|
+
readonly grantversion: number;
|
|
33
|
+
readonly correlationid: string;
|
|
34
|
+
readonly causationid?: string;
|
|
35
|
+
readonly subject?: string;
|
|
36
|
+
readonly data: string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | any | {
|
|
37
|
+
readonly [x: string]: string | number | boolean | any | any | null;
|
|
38
|
+
} | null)[] | {
|
|
39
|
+
readonly [x: string]: string | number | boolean | readonly (string | number | boolean | any | any | null)[] | any | null;
|
|
40
|
+
} | null)[] | {
|
|
41
|
+
readonly [x: string]: string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | any | any | null)[] | any | null)[] | any | null;
|
|
42
|
+
} | null)[] | {
|
|
43
|
+
readonly [x: string]: string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | any | any | null)[] | any | null)[] | any | null)[] | any | null;
|
|
44
|
+
} | null)[] | {
|
|
45
|
+
readonly [x: string]: string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | any | any | null)[] | any | null)[] | any | null)[] | any | null)[] | any | null;
|
|
46
|
+
} | null)[] | {
|
|
47
|
+
readonly [x: string]: string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | any | any | null)[] | any | null)[] | any | null)[] | any | null)[] | any | null)[] | any | null;
|
|
48
|
+
} | null)[] | {
|
|
49
|
+
readonly [x: string]: string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | any | any | null)[] | any | null)[] | any | null)[] | any | null)[] | any | null)[] | any | null)[] | any | null;
|
|
50
|
+
} | null)[] | {
|
|
51
|
+
readonly [x: string]: string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | any | any | null)[] | any | null)[] | any | null)[] | any | null)[] | any | null)[] | any | null)[] | any | null)[] | any | null;
|
|
52
|
+
} | null)[] | {
|
|
53
|
+
readonly [x: string]: string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | any | any | null)[] | any | null)[] | any | null)[] | any | null)[] | any | null)[] | any | null)[] | any | null)[] | any | null)[] | any | null;
|
|
54
|
+
} | null)[] | {
|
|
55
|
+
readonly [x: string]: string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | any | any | null)[] | any | null)[] | any | null)[] | any | null)[] | any | null)[] | any | null)[] | any | null)[] | any | null)[] | any | null)[] | any | null;
|
|
56
|
+
} | null)[] | {
|
|
57
|
+
readonly [x: string]: string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | any | any | null)[] | any | null)[] | any | null)[] | any | null)[] | any | null)[] | any | null)[] | any | null)[] | any | null)[] | any | null)[] | any | null)[] | any | null;
|
|
58
|
+
} | null)[] | {
|
|
59
|
+
readonly [x: string]: string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | readonly (string | number | boolean | any | any | null)[] | any | null)[] | any | null)[] | any | null)[] | any | null)[] | any | null)[] | any | null)[] | any | null)[] | any | null)[] | any | null)[] | any | null)[] | any | null;
|
|
60
|
+
} | null;
|
|
61
|
+
readonly orgnamespace?: string;
|
|
62
|
+
readonly orgref?: string;
|
|
63
|
+
readonly projectnamespace?: string;
|
|
64
|
+
readonly projectref?: string;
|
|
65
|
+
readonly principalnamespace?: string;
|
|
66
|
+
readonly principalref?: string;
|
|
67
|
+
readonly resourcenamespace?: string;
|
|
68
|
+
readonly resourceref?: string;
|
|
69
|
+
readonly deliveryid: string;
|
|
70
|
+
};
|
|
71
|
+
digest: string;
|
|
72
|
+
generation: number;
|
|
73
|
+
origin: import("@eventsdk/sdk/identity-contracts").VerifiedOrigin;
|
|
74
|
+
targetScope: string;
|
|
75
|
+
}>;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { AuthorizationPort } from '@eventsdk/sdk/identity-contracts';
|
|
2
|
+
import type { OutboxRelayPort } from '../ports/outbox.js';
|
|
3
|
+
import type { PublishPort } from '../ports/transport.js';
|
|
4
|
+
import type { Clock, Digest, OperationOptions, Random } from '../runtime/dependencies.js';
|
|
5
|
+
import type { OriginRefreshPort } from '../ports/origin-refresh.js';
|
|
6
|
+
import { type RetryPolicy } from '../runtime/retry.js';
|
|
7
|
+
export interface RelayDependencies {
|
|
8
|
+
readonly outbox: OutboxRelayPort;
|
|
9
|
+
readonly publisher: PublishPort;
|
|
10
|
+
readonly authorization: AuthorizationPort;
|
|
11
|
+
readonly clock: Clock;
|
|
12
|
+
readonly digest: Digest;
|
|
13
|
+
readonly random: Random;
|
|
14
|
+
readonly originRefresh?: OriginRefreshPort;
|
|
15
|
+
}
|
|
16
|
+
export interface RelayOptions extends OperationOptions {
|
|
17
|
+
readonly batchSize: number;
|
|
18
|
+
readonly leaseMs: number;
|
|
19
|
+
readonly retry: RetryPolicy;
|
|
20
|
+
}
|
|
21
|
+
export interface RelaySummary {
|
|
22
|
+
readonly published: number;
|
|
23
|
+
readonly unknown: number;
|
|
24
|
+
readonly held: number;
|
|
25
|
+
}
|
|
26
|
+
export declare function relayOutbox(deps: RelayDependencies, options: RelayOptions): Promise<RelaySummary>;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { AuthorizationPort, VerifiedOrigin } from '@eventsdk/sdk/identity-contracts';
|
|
2
|
+
import type { OutboxRecordPort } from '../ports/outbox.js';
|
|
3
|
+
import type { Clock, Digest, OperationOptions } from '../runtime/dependencies.js';
|
|
4
|
+
export interface RecordDependencies<TTransaction> {
|
|
5
|
+
readonly outbox: OutboxRecordPort<TTransaction>;
|
|
6
|
+
readonly authorization: AuthorizationPort;
|
|
7
|
+
readonly digest: Digest;
|
|
8
|
+
readonly clock: Clock;
|
|
9
|
+
}
|
|
10
|
+
export declare function recordEvent<TTransaction>(tx: TTransaction, input: unknown, origin: VerifiedOrigin, dependencies: RecordDependencies<TTransaction>, options: OperationOptions): Promise<void>;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type CloudEventV12 } from '@eventsdk/sdk/contracts';
|
|
2
|
+
import type { VerifiedOrigin } from '@eventsdk/sdk/identity-contracts';
|
|
3
|
+
import type { Digest, OperationOptions } from '../runtime/dependencies.js';
|
|
4
|
+
import { type RecordDependencies } from './record-event.js';
|
|
5
|
+
export interface FanoutRoute {
|
|
6
|
+
readonly audience: string;
|
|
7
|
+
readonly connectionref: string;
|
|
8
|
+
readonly grantref: string;
|
|
9
|
+
readonly grantversion: number;
|
|
10
|
+
}
|
|
11
|
+
export interface FanoutRecipient {
|
|
12
|
+
readonly route: FanoutRoute;
|
|
13
|
+
readonly origin: VerifiedOrigin;
|
|
14
|
+
}
|
|
15
|
+
export declare function prepareFanoutDelivery(input: unknown, route: FanoutRoute, digest: Digest): Promise<CloudEventV12>;
|
|
16
|
+
export declare function recordFanoutEvent<T>(tx: T, draft: unknown, recipients: readonly FanoutRecipient[], deps: RecordDependencies<T>, options: OperationOptions): Promise<readonly CloudEventV12[]>;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { BusinessReceipt } from '@eventsdk/sdk/contracts';
|
|
2
|
+
import type { ClaimedInbox } from './inbox.js';
|
|
3
|
+
import type { InboxKey } from '../runtime/event-identity.js';
|
|
4
|
+
import type { Lease } from '../runtime/lease.js';
|
|
5
|
+
export interface DeadLetterEntry {
|
|
6
|
+
readonly ref: string;
|
|
7
|
+
readonly key: InboxKey;
|
|
8
|
+
readonly originalDeliveryRef: string;
|
|
9
|
+
readonly reasonCode: string;
|
|
10
|
+
readonly attempts: number;
|
|
11
|
+
readonly recordedAt: string;
|
|
12
|
+
}
|
|
13
|
+
export interface DeadLetterPort<TTransaction> {
|
|
14
|
+
quarantine(claim: ClaimedInbox, entry: DeadLetterEntry, signal: AbortSignal): Promise<void>;
|
|
15
|
+
transactReplay(entry: DeadLetterEntry, operation: (tx: TTransaction, claim: ClaimedInbox) => Promise<void>, signal: AbortSignal): Promise<void>;
|
|
16
|
+
requeueInTransaction(tx: TTransaction, claim: ClaimedInbox, signal: AbortSignal): Promise<void>;
|
|
17
|
+
}
|
|
18
|
+
export interface InboxWorkClaim extends ClaimedInbox {
|
|
19
|
+
readonly attempt: number;
|
|
20
|
+
}
|
|
21
|
+
export interface InboxWorkPort {
|
|
22
|
+
claimReady(input: {
|
|
23
|
+
limit: number;
|
|
24
|
+
now: number;
|
|
25
|
+
leaseMs: number;
|
|
26
|
+
signal: AbortSignal;
|
|
27
|
+
}): Promise<readonly InboxWorkClaim[]>;
|
|
28
|
+
defer(key: InboxKey, lease: Lease, expectedReceipt: Pick<BusinessReceipt, 'receiptRef' | 'revision' | 'disposition'>, nextAttemptAt: number, reasonCode: string, signal: AbortSignal): Promise<void>;
|
|
29
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { BusinessReceipt, CloudEvent } from '@eventsdk/sdk/contracts';
|
|
2
|
+
import type { VerifiedOrigin } from '@eventsdk/sdk/identity-contracts';
|
|
3
|
+
import type { InboxKey } from '../runtime/event-identity.js';
|
|
4
|
+
import type { Lease } from '../runtime/lease.js';
|
|
5
|
+
import type { DomainApplyOutcome } from '../inbox/domain-apply-result.js';
|
|
6
|
+
export interface AcceptedEvent {
|
|
7
|
+
readonly key: InboxKey;
|
|
8
|
+
readonly event: CloudEvent;
|
|
9
|
+
readonly origin: VerifiedOrigin;
|
|
10
|
+
readonly digest: string;
|
|
11
|
+
readonly deliveryRef: string;
|
|
12
|
+
readonly receipt: BusinessReceipt;
|
|
13
|
+
}
|
|
14
|
+
export type PersistResult = {
|
|
15
|
+
readonly kind: 'RECEIVED' | 'DUPLICATE';
|
|
16
|
+
readonly receipt: BusinessReceipt;
|
|
17
|
+
} | {
|
|
18
|
+
readonly kind: 'CONFLICT';
|
|
19
|
+
};
|
|
20
|
+
export interface QuarantineRecord {
|
|
21
|
+
readonly deliveryRef: string;
|
|
22
|
+
readonly consumerRef: string;
|
|
23
|
+
readonly reasonCode: string;
|
|
24
|
+
readonly recordedAt: string;
|
|
25
|
+
}
|
|
26
|
+
export interface FanoutAcceptedEvent extends AcceptedEvent {
|
|
27
|
+
readonly logicalDigest: string;
|
|
28
|
+
readonly deliveryId: string;
|
|
29
|
+
}
|
|
30
|
+
export interface InboxAdmissionPort {
|
|
31
|
+
persistFanoutAccepted?(record: FanoutAcceptedEvent, signal: AbortSignal): Promise<PersistResult>;
|
|
32
|
+
persistAccepted(record: AcceptedEvent, signal: AbortSignal): Promise<PersistResult>;
|
|
33
|
+
persistQuarantine(record: QuarantineRecord, signal: AbortSignal): Promise<void>;
|
|
34
|
+
}
|
|
35
|
+
export interface ClaimedInbox extends AcceptedEvent {
|
|
36
|
+
readonly lease: Lease;
|
|
37
|
+
}
|
|
38
|
+
export interface InboxApplyPort<TTransaction> {
|
|
39
|
+
transact(claim: ClaimedInbox, operation: (tx: TTransaction) => Promise<BusinessReceipt>, signal: AbortSignal): Promise<BusinessReceipt>;
|
|
40
|
+
withDomainSavepoint?(tx: TTransaction, operation: () => Promise<DomainApplyOutcome>, signal: AbortSignal): Promise<DomainApplyOutcome>;
|
|
41
|
+
completeInTransaction(tx: TTransaction, claim: ClaimedInbox, receipt: BusinessReceipt, signal: AbortSignal): Promise<void>;
|
|
42
|
+
readReceipt(key: InboxKey, signal: AbortSignal): Promise<BusinessReceipt | null>;
|
|
43
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export interface DeliveryHealth {
|
|
2
|
+
readonly observedAt: number;
|
|
3
|
+
readonly outboxPending: number;
|
|
4
|
+
readonly oldestPendingAt: number | null;
|
|
5
|
+
readonly consumerLag: number;
|
|
6
|
+
readonly retryPending: number;
|
|
7
|
+
readonly quarantined: number;
|
|
8
|
+
readonly unresolvedReceipts: number;
|
|
9
|
+
readonly gaps: number;
|
|
10
|
+
readonly authorizationDenials: number;
|
|
11
|
+
readonly watermark: string;
|
|
12
|
+
readonly brokerStoredBytes?: number;
|
|
13
|
+
readonly brokerQuotaBytes?: number;
|
|
14
|
+
readonly bridgeUnconfirmed?: number;
|
|
15
|
+
}
|
|
16
|
+
export interface DeliveryHealthPort {
|
|
17
|
+
read(signal: AbortSignal): Promise<DeliveryHealth>;
|
|
18
|
+
}
|
|
19
|
+
export interface HealthMetricSink {
|
|
20
|
+
gauge(name: string, value: number): void;
|
|
21
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { CloudEvent } from '@eventsdk/sdk/contracts';
|
|
2
|
+
import type { VerifiedOrigin } from '@eventsdk/sdk/identity-contracts';
|
|
3
|
+
export interface OriginRefreshPort {
|
|
4
|
+
refresh(event: CloudEvent, previous: VerifiedOrigin, signal: AbortSignal): Promise<VerifiedOrigin>;
|
|
5
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { CloudEvent } from '@eventsdk/sdk/contracts';
|
|
2
|
+
import type { VerifiedOrigin } from '@eventsdk/sdk/identity-contracts';
|
|
3
|
+
import type { EventIdentity } from '../runtime/event-identity.js';
|
|
4
|
+
import type { Lease } from '../runtime/lease.js';
|
|
5
|
+
import type { PublishAck } from './transport.js';
|
|
6
|
+
export interface OutboxRecord {
|
|
7
|
+
readonly event: CloudEvent;
|
|
8
|
+
readonly digest: string;
|
|
9
|
+
readonly origin: VerifiedOrigin;
|
|
10
|
+
}
|
|
11
|
+
export interface ClaimedEvent extends OutboxRecord {
|
|
12
|
+
readonly lease: Lease;
|
|
13
|
+
readonly attempt: number;
|
|
14
|
+
}
|
|
15
|
+
export type PublishOutcome = {
|
|
16
|
+
readonly status: 'PUBLISHED';
|
|
17
|
+
readonly ack: PublishAck;
|
|
18
|
+
} | {
|
|
19
|
+
readonly status: 'UNKNOWN';
|
|
20
|
+
readonly nextAttemptAt: number;
|
|
21
|
+
} | {
|
|
22
|
+
readonly status: 'HOLD';
|
|
23
|
+
readonly reasonCode: string;
|
|
24
|
+
};
|
|
25
|
+
export interface FanoutOutboxRecord extends OutboxRecord {
|
|
26
|
+
readonly logicalDigest: string;
|
|
27
|
+
readonly deliveryId: string;
|
|
28
|
+
}
|
|
29
|
+
export interface OutboxRecordPort<TTransaction> {
|
|
30
|
+
recordFanoutInTransaction?(tx: TTransaction, record: FanoutOutboxRecord, signal: AbortSignal): Promise<void>;
|
|
31
|
+
recordInTransaction(tx: TTransaction, record: OutboxRecord, signal: AbortSignal): Promise<void>;
|
|
32
|
+
}
|
|
33
|
+
export interface OutboxRelayPort {
|
|
34
|
+
settleFanoutPublish?(identity: EventIdentity & {
|
|
35
|
+
readonly deliveryid: string;
|
|
36
|
+
}, lease: Lease, outcome: PublishOutcome, signal: AbortSignal): Promise<void>;
|
|
37
|
+
claimReady(input: {
|
|
38
|
+
limit: number;
|
|
39
|
+
now: number;
|
|
40
|
+
leaseMs: number;
|
|
41
|
+
signal: AbortSignal;
|
|
42
|
+
}): Promise<readonly ClaimedEvent[]>;
|
|
43
|
+
settlePublish(identity: EventIdentity, lease: Lease, outcome: PublishOutcome, signal: AbortSignal): Promise<void>;
|
|
44
|
+
}
|
|
45
|
+
export interface OutboxPort<TTransaction> extends OutboxRecordPort<TTransaction>, OutboxRelayPort {
|
|
46
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { CloudEvent, JsonValue, ResultRef } from '@eventsdk/sdk/contracts';
|
|
2
|
+
import type { VerifiedOrigin } from '@eventsdk/sdk/identity-contracts';
|
|
3
|
+
export interface ResultSnapshot {
|
|
4
|
+
readonly reference: ResultRef;
|
|
5
|
+
readonly value: JsonValue;
|
|
6
|
+
}
|
|
7
|
+
export interface ResultReadPort {
|
|
8
|
+
read(reference: ResultRef, context: {
|
|
9
|
+
event: CloudEvent;
|
|
10
|
+
origin: VerifiedOrigin;
|
|
11
|
+
targetScope: string;
|
|
12
|
+
signal: AbortSignal;
|
|
13
|
+
}): Promise<ResultSnapshot | null>;
|
|
14
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { CloudEvent } from '@eventsdk/sdk/contracts';
|
|
2
|
+
export interface PublishAck {
|
|
3
|
+
readonly stream: string;
|
|
4
|
+
readonly sequence: number;
|
|
5
|
+
readonly duplicate: boolean;
|
|
6
|
+
}
|
|
7
|
+
export interface PublishContext {
|
|
8
|
+
readonly messageId: string;
|
|
9
|
+
readonly signal: AbortSignal;
|
|
10
|
+
}
|
|
11
|
+
export interface PublishPort {
|
|
12
|
+
publish(event: CloudEvent, context: PublishContext): Promise<PublishAck>;
|
|
13
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { type BusinessReceipt } from '@eventsdk/sdk/contracts';
|
|
2
|
+
export declare function assertReceiptTransition(previous: BusinessReceipt, next: BusinessReceipt): void;
|
|
3
|
+
export declare function classifyReceiptCommit(previous: BusinessReceipt, next: BusinessReceipt): 'UNCHANGED' | 'TRANSITION';
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { CloudEvent } from '@eventsdk/sdk/contracts';
|
|
2
|
+
import type { VerifiedOrigin } from '@eventsdk/sdk/identity-contracts';
|
|
3
|
+
import type { OperationOptions } from '../runtime/dependencies.js';
|
|
4
|
+
export interface EventLogItem {
|
|
5
|
+
readonly cursor: string;
|
|
6
|
+
readonly revision: string;
|
|
7
|
+
readonly commitEvidenceRef: string;
|
|
8
|
+
readonly event: CloudEvent;
|
|
9
|
+
readonly origin: VerifiedOrigin;
|
|
10
|
+
}
|
|
11
|
+
export type EventLogPage = {
|
|
12
|
+
readonly kind: 'PAGE';
|
|
13
|
+
readonly items: readonly EventLogItem[];
|
|
14
|
+
readonly nextCursor: string;
|
|
15
|
+
} | {
|
|
16
|
+
readonly kind: 'GAP';
|
|
17
|
+
readonly oldestAvailableCursor: string;
|
|
18
|
+
};
|
|
19
|
+
export interface NativeEventLogPort {
|
|
20
|
+
readAfter(cursor: string, limit: number, signal: AbortSignal): Promise<EventLogPage>;
|
|
21
|
+
}
|
|
22
|
+
export interface EventLogCheckpointPort {
|
|
23
|
+
stageAndAdvance(expectedCursor: string, page: Extract<EventLogPage, {
|
|
24
|
+
kind: 'PAGE';
|
|
25
|
+
}>, signal: AbortSignal): Promise<void>;
|
|
26
|
+
recordGap(expectedCursor: string, oldestAvailableCursor: string, signal: AbortSignal): Promise<void>;
|
|
27
|
+
}
|
|
28
|
+
export declare function stageEventLogPage(cursor: string, limit: number, source: NativeEventLogPort, checkpoint: EventLogCheckpointPort, options: OperationOptions): Promise<EventLogPage['kind']>;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type JsonValue } from '@eventsdk/sdk/contracts';
|
|
2
|
+
import type { OperationOptions } from '../runtime/dependencies.js';
|
|
3
|
+
export interface AuthorizedSnapshot {
|
|
4
|
+
readonly source: string;
|
|
5
|
+
readonly scope: string;
|
|
6
|
+
readonly revision: string;
|
|
7
|
+
readonly watermark: string;
|
|
8
|
+
readonly evidenceRef: string;
|
|
9
|
+
readonly value: JsonValue;
|
|
10
|
+
}
|
|
11
|
+
export interface SnapshotRecoveryPort {
|
|
12
|
+
readAuthorized(source: string, scope: string, signal: AbortSignal): Promise<AuthorizedSnapshot | null>;
|
|
13
|
+
applyAndCheckpoint(expectedWatermark: string, snapshot: AuthorizedSnapshot, signal: AbortSignal): Promise<void>;
|
|
14
|
+
}
|
|
15
|
+
export declare function recoverGap(source: string, scope: string, expectedWatermark: string, port: SnapshotRecoveryPort, options: OperationOptions): Promise<AuthorizedSnapshot>;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type BusinessReceipt } from '@eventsdk/sdk/contracts';
|
|
2
|
+
import type { InboxKey } from '../runtime/event-identity.js';
|
|
3
|
+
import type { OperationOptions } from '../runtime/dependencies.js';
|
|
4
|
+
import type { RecoveryObservation } from './receipt-recovery.js';
|
|
5
|
+
export interface ReceiptIdentityLookupPort {
|
|
6
|
+
readByIdentity(key: InboxKey, signal: AbortSignal): Promise<BusinessReceipt | null>;
|
|
7
|
+
}
|
|
8
|
+
export declare function recoverReceiptByIdentity(key: InboxKey, reader: ReceiptIdentityLookupPort, options: OperationOptions): Promise<RecoveryObservation>;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type BusinessReceipt } from '@eventsdk/sdk/contracts';
|
|
2
|
+
import type { InboxKey } from '../runtime/event-identity.js';
|
|
3
|
+
import type { OperationOptions } from '../runtime/dependencies.js';
|
|
4
|
+
export interface ReceiptLookupPort {
|
|
5
|
+
read(key: InboxKey, deliveryRef: string, signal: AbortSignal): Promise<BusinessReceipt | null>;
|
|
6
|
+
}
|
|
7
|
+
export type RecoveryObservation = {
|
|
8
|
+
readonly status: 'RESOLVED';
|
|
9
|
+
readonly receipt: BusinessReceipt;
|
|
10
|
+
} | {
|
|
11
|
+
readonly status: 'WAIT';
|
|
12
|
+
readonly receipt: BusinessReceipt | null;
|
|
13
|
+
};
|
|
14
|
+
export declare function recoverReceipt(key: InboxKey, deliveryRef: string, reader: ReceiptLookupPort, options: OperationOptions): Promise<RecoveryObservation>;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { DeadLetterEntry, DeadLetterPort } from '../ports/dead-letter.js';
|
|
2
|
+
import type { ApplyAuthorizationPort } from '../inbox/apply-delivery.js';
|
|
3
|
+
import type { OperationOptions } from '../runtime/dependencies.js';
|
|
4
|
+
export declare function replayDeadLetter<T>(entry: DeadLetterEntry, port: DeadLetterPort<T>, authorization: ApplyAuthorizationPort<T>, options: OperationOptions): Promise<void>;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export interface Clock {
|
|
2
|
+
now(): number;
|
|
3
|
+
}
|
|
4
|
+
export interface IdGenerator {
|
|
5
|
+
next(): string;
|
|
6
|
+
}
|
|
7
|
+
export interface Digest {
|
|
8
|
+
sha256(value: string): Promise<string>;
|
|
9
|
+
}
|
|
10
|
+
export interface Random {
|
|
11
|
+
next(): number;
|
|
12
|
+
}
|
|
13
|
+
export interface OperationOptions {
|
|
14
|
+
signal?: AbortSignal;
|
|
15
|
+
timeoutMs: number;
|
|
16
|
+
}
|
|
17
|
+
export interface MetricSink {
|
|
18
|
+
increment(name: string, labels: Readonly<Record<string, string>>): void;
|
|
19
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export type CoreErrorCode = 'ABORTED' | 'TIMEOUT' | 'INVALID_CONFIGURATION' | 'INVALID_DOMAIN_RESULT' | 'ADAPTER_CAPABILITY_REQUIRED' | 'STALE_LEASE' | 'EVENT_ID_CONFLICT' | 'AUTHORIZATION_DENIED' | 'AUTHORIZATION_UNKNOWN' | 'ORIGIN_MISMATCH' | 'TARGET_SCOPE_CHANGED' | 'RESULT_MISMATCH' | 'RECEIPT_MISMATCH' | 'RECOVERY_REQUIRED' | 'GAP' | 'INVALID_TRANSITION';
|
|
2
|
+
export declare class CoreError extends Error {
|
|
3
|
+
readonly code: CoreErrorCode;
|
|
4
|
+
constructor(code: CoreErrorCode);
|
|
5
|
+
}
|
|
6
|
+
export declare function assertNotAborted(signal?: AbortSignal): void;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type CloudEvent } from '@eventsdk/sdk/contracts';
|
|
2
|
+
import type { Digest } from './dependencies.js';
|
|
3
|
+
export interface EventIdentity {
|
|
4
|
+
readonly source: string;
|
|
5
|
+
readonly id: string;
|
|
6
|
+
readonly deliveryid?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface InboxKey extends EventIdentity {
|
|
9
|
+
readonly consumerRef: string;
|
|
10
|
+
readonly targetScope: string;
|
|
11
|
+
}
|
|
12
|
+
export declare function eventMessageId(event: EventIdentity, digest: Digest): Promise<string>;
|
|
13
|
+
export declare function eventDigest(event: CloudEvent, digest: Digest): Promise<string>;
|
|
14
|
+
export declare function inboxKey(key: InboxKey): string;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type TenantContext } from '@eventsdk/sdk/contracts';
|
|
2
|
+
import type { Digest } from './dependencies.js';
|
|
3
|
+
export declare function deriveExchangeConnectionRef(input: {
|
|
4
|
+
source: string;
|
|
5
|
+
from: TenantContext;
|
|
6
|
+
to: TenantContext;
|
|
7
|
+
}, digest: Digest): Promise<string>;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type CloudEvent, type CloudEventV12, type FanoutEventDraft } from '@eventsdk/sdk/contracts';
|
|
2
|
+
import type { Digest } from './dependencies.js';
|
|
3
|
+
export declare function fanoutLogicalEvent(event: CloudEventV12): FanoutEventDraft;
|
|
4
|
+
export declare function logicalEventDigest(event: CloudEvent, digest: Digest): Promise<string>;
|
|
5
|
+
export declare function deriveDeliveryId(event: Pick<CloudEventV12, 'source' | 'id' | 'audience' | 'connectionref'>, digest: Digest): Promise<string>;
|
|
6
|
+
export declare function assertDeliveryIdentity(event: CloudEvent, digest: Digest): Promise<void>;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { DeliveryHealth, DeliveryHealthPort, HealthMetricSink } from '../ports/observability.js';
|
|
2
|
+
import type { OperationOptions } from './dependencies.js';
|
|
3
|
+
export declare function observeDeliveryHealth(port: DeliveryHealthPort, sink: HealthMetricSink, options: OperationOptions): Promise<DeliveryHealth>;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Random } from './dependencies.js';
|
|
2
|
+
export interface RetryPolicy {
|
|
3
|
+
readonly maxAttempts: number;
|
|
4
|
+
readonly baseDelayMs: number;
|
|
5
|
+
readonly maxDelayMs: number;
|
|
6
|
+
readonly jitterRatio: number;
|
|
7
|
+
}
|
|
8
|
+
export type RetryDecision = {
|
|
9
|
+
readonly kind: 'RETRY';
|
|
10
|
+
readonly nextAttemptAt: number;
|
|
11
|
+
} | {
|
|
12
|
+
readonly kind: 'EXHAUSTED';
|
|
13
|
+
};
|
|
14
|
+
export declare function decideRetry(attempt: number, now: number, policy: RetryPolicy, random: Random): RetryDecision;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare class EventLinkProtocolError extends Error {
|
|
2
|
+
readonly code: 'INVALID' | 'FORBIDDEN' | 'EXPIRED' | 'CHANGED' | 'CONFLICT' | 'CODE_INVALID' | 'UNKNOWN';
|
|
3
|
+
constructor(code: 'INVALID' | 'FORBIDDEN' | 'EXPIRED' | 'CHANGED' | 'CONFLICT' | 'CODE_INVALID' | 'UNKNOWN');
|
|
4
|
+
}
|
|
5
|
+
export declare function eventLinkInput<T>(parse: () => T): T;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type EventLinkProposal } from '@eventsdk/sdk/contracts';
|
|
2
|
+
import { type EventLinkSenderBinding } from './protocol.js';
|
|
3
|
+
export interface EventLinkExchangeOptions {
|
|
4
|
+
readonly fetch?: typeof fetch;
|
|
5
|
+
readonly now?: () => number;
|
|
6
|
+
readonly signal?: AbortSignal;
|
|
7
|
+
readonly timeoutMs?: number;
|
|
8
|
+
}
|
|
9
|
+
export declare function exchangeEventLinkCode(binding: EventLinkSenderBinding, code: string, options?: EventLinkExchangeOptions): Promise<EventLinkProposal>;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export { EventLinkProtocolError } from './errors.js';
|
|
2
|
+
export { EVENT_LINK_MAX_BYTES, createEventLinkVerifier, createEventLinkState, eventLinkChallenge, eventLinkHash, } from './primitives.js';
|
|
3
|
+
export { assertEventLinkRegistration, eventLinkRegistrationRevision } from './registration.js';
|
|
4
|
+
export type { EventLinkClientRegistration, EventLinkReceiverRegistration } from './registration.js';
|
|
5
|
+
export { buildEventLinkAuthorizationUrl, parseEventLinkAuthorization, parseEventLinkToken, validateEventLinkCallback, validateEventLinkProposalBinding, } from './protocol.js';
|
|
6
|
+
export type { EventLinkSenderBinding } from './protocol.js';
|
|
7
|
+
export { exchangeEventLinkCode } from './exchange.js';
|
|
8
|
+
export type { EventLinkExchangeOptions } from './exchange.js';
|
|
9
|
+
export { planEventLinkCallback, continueEventLinkAuthorization } from './sender.js';
|
|
10
|
+
export type { EventLinkSenderSnapshot, EventLinkSenderClaim, EventLinkSenderPort, } from './sender.js';
|
|
11
|
+
export { EventLinkReceiver } from './receiver.js';
|
|
12
|
+
export type { EventLinkConsent, EventLinkReceiverActor, EventLinkReceiverState, EventLinkReceiverRecord, EventLinkReceiverTransaction, EventLinkReceiverPort, } from './receiver-ports.js';
|