@xyo-network/event-kit-protocol 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +33 -0
- package/dist/neutral/admissionTypes.d.ts +110 -0
- package/dist/neutral/admissionTypes.d.ts.map +1 -0
- package/dist/neutral/admitAndEnqueue.d.ts +29 -0
- package/dist/neutral/admitAndEnqueue.d.ts.map +1 -0
- package/dist/neutral/index.d.ts +19 -0
- package/dist/neutral/index.d.ts.map +1 -0
- package/dist/neutral/index.mjs +802 -0
- package/dist/neutral/index.mjs.map +7 -0
- package/dist/neutral/memoryStatementGrantGraph.d.ts +34 -0
- package/dist/neutral/memoryStatementGrantGraph.d.ts.map +1 -0
- package/dist/neutral/memoryWakeInbox.d.ts +31 -0
- package/dist/neutral/memoryWakeInbox.d.ts.map +1 -0
- package/dist/neutral/memoryWakeQueue.d.ts +14 -0
- package/dist/neutral/memoryWakeQueue.d.ts.map +1 -0
- package/dist/neutral/statementGraphPorts.d.ts +42 -0
- package/dist/neutral/statementGraphPorts.d.ts.map +1 -0
- package/dist/neutral/statementGraphWakeGrantAuthorizer.d.ts +20 -0
- package/dist/neutral/statementGraphWakeGrantAuthorizer.d.ts.map +1 -0
- package/dist/neutral/types.d.ts +20 -0
- package/dist/neutral/types.d.ts.map +1 -0
- package/dist/neutral/verifyWakeRequest.d.ts +54 -0
- package/dist/neutral/verifyWakeRequest.d.ts.map +1 -0
- package/dist/neutral/wakeQueue.d.ts +49 -0
- package/dist/neutral/wakeQueue.d.ts.map +1 -0
- package/package.json +68 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/admissionTypes.ts", "../../src/admitAndEnqueue.ts", "../../src/memoryStatementGrantGraph.ts", "../../src/memoryWakeInbox.ts", "../../src/memoryWakeQueue.ts", "../../src/statementGraphWakeGrantAuthorizer.ts", "../../src/verifyWakeRequest.ts", "../../src/wakeQueue.ts"],
|
|
4
|
+
"sourcesContent": ["import type {\n DeploymentId,\n Hash,\n NormalizedAddress,\n WakeId,\n WakeJwtAudience,\n WakeJwtId,\n} from '@xyo-network/event-kit-schemas'\n\nimport type { AdmittedWake } from './types.ts'\n\n/** Replay records survive token expiry by this amount to cover receiver skew. */\nexport const EVENT_KIT_REPLAY_RETENTION_SKEW_SECONDS = 60\n\nexport interface WakeGrantAuthorizationRequest {\n readonly controller: NormalizedAddress\n readonly deploymentId: DeploymentId\n readonly expectedHead: number\n readonly publisher: NormalizedAddress\n readonly queueId?: string\n}\n\n/** Concrete grant evidence required for every enabled decision. */\nexport interface WakeGrantEvidence {\n readonly assertedAtBlock: number\n readonly controller: NormalizedAddress\n readonly deploymentId: DeploymentId\n readonly id: string\n readonly queueId?: string\n readonly target: NormalizedAddress\n}\n\nexport interface WakeGrantAuthorizationDisabled {\n readonly atBlock: number\n readonly enabled: false\n /** Optional diagnostics. The core rejects disagreement with its trusted input. */\n readonly expectedHead?: number\n /** Optional diagnostics. The core recomputes lag instead of trusting this value. */\n readonly lag?: number\n}\n\nexport interface WakeGrantAuthorizationEnabled {\n readonly atBlock: number\n readonly enabled: true\n /** Optional diagnostics. The core rejects disagreement with its trusted input. */\n readonly expectedHead?: number\n readonly grant: WakeGrantEvidence\n /** Optional diagnostics. The core recomputes lag instead of trusting this value. */\n readonly lag?: number\n}\n\nexport type WakeGrantAuthorizationDecision\n = | WakeGrantAuthorizationDisabled\n | WakeGrantAuthorizationEnabled\n\n/**\n * Stateful Statement Graph authorization port. Implementations must evaluate\n * the exact controller, scope, publisher, and expected finalized head supplied\n * for this request.\n */\nexport interface WakeGrantAuthorizer {\n authorizePublisher: (\n request: WakeGrantAuthorizationRequest,\n ) => Promise<WakeGrantAuthorizationDecision>\n}\n\n/** Normalized grant snapshot accepted by the protocol core. */\nexport interface AuthorizedWakeGrant {\n readonly atBlock: number\n readonly expectedHead: number\n readonly grant: WakeGrantEvidence\n readonly lag: number\n}\n\nexport interface WakeAdmissionAttempt {\n readonly audience: WakeJwtAudience\n readonly eventHash: Hash\n readonly jwtId: WakeJwtId\n readonly publisher: NormalizedAddress\n /** Token replay record retention deadline (`exp + 60`). */\n readonly retainJwtUntil: number\n readonly wakeId: WakeId\n}\n\n/** Stable receipt bound to both durable admission indexes. */\nexport interface WakeAdmissionReceipt {\n readonly audience: WakeJwtAudience\n readonly eventHash: Hash\n readonly id: string\n readonly publisher: NormalizedAddress\n readonly wakeId: WakeId\n}\n\nexport type WakeAttemptResolution\n = | { readonly kind: 'new' }\n | { readonly kind: 'duplicate'; readonly receipt: WakeAdmissionReceipt }\n | { readonly kind: 'jwt-id-collision' }\n | { readonly kind: 'wake-id-collision' }\n\nexport type WakeCommitResult\n = | { readonly kind: 'enqueued'; readonly receipt: WakeAdmissionReceipt }\n | { readonly kind: 'duplicate'; readonly receipt: WakeAdmissionReceipt }\n | { readonly kind: 'jwt-id-collision' }\n | { readonly kind: 'wake-id-collision' }\n\n/**\n * Durable linearizable admission boundary.\n *\n * `resolveAttempt` must atomically bind a fresh JWT id to an existing matching\n * wake receipt. It must not consume either identity when returning `new`.\n *\n * `commitAuthorized` must atomically recheck both identities, persist both\n * mappings and their stable receipt, and durably enqueue the wake (or write a\n * transactional outbox record). A separate fallible enqueue is nonconforming.\n */\nexport interface AtomicWakeInbox {\n commitAuthorized: (input: {\n readonly attempt: WakeAdmissionAttempt\n readonly grant: AuthorizedWakeGrant\n readonly wake: AdmittedWake\n }) => Promise<WakeCommitResult>\n resolveAttempt: (attempt: WakeAdmissionAttempt) => Promise<WakeAttemptResolution>\n}\n", "import type {\n AtomicWakeInbox,\n AuthorizedWakeGrant,\n WakeAdmissionAttempt,\n WakeAdmissionReceipt,\n WakeCommitResult,\n WakeGrantAuthorizationDecision,\n WakeGrantAuthorizer,\n WakeGrantEvidence,\n} from './admissionTypes.ts'\nimport { EVENT_KIT_REPLAY_RETENTION_SKEW_SECONDS } from './admissionTypes.ts'\nimport type { AdmittedWake } from './types.ts'\nimport type { VerifiedWakeRequest } from './verifyWakeRequest.ts'\n\nexport interface AdmitAndEnqueueInput {\n /** Independently trusted finalized XL1 head for this admission attempt. */\n readonly expectedHead: number\n readonly grants: WakeGrantAuthorizer\n readonly inbox: AtomicWakeInbox\n readonly verified: VerifiedWakeRequest\n}\n\nexport type AdmitAndEnqueueFailureReason\n = | 'grant-missing'\n | 'grant-unavailable'\n | 'grant-view-invalid'\n | 'grant-view-stale'\n | 'inbox-unavailable'\n | 'jwt-id-collision'\n | 'wake-id-collision'\n\nexport interface AdmitAndEnqueueFailure {\n readonly details?: readonly string[]\n readonly ok: false\n readonly reason: AdmitAndEnqueueFailureReason\n}\n\nexport interface AdmitAndEnqueueSuccess {\n readonly disposition: 'duplicate' | 'enqueued'\n readonly ok: true\n readonly receipt: WakeAdmissionReceipt\n readonly wake: AdmittedWake\n}\n\nexport type AdmitAndEnqueueResult = AdmitAndEnqueueFailure | AdmitAndEnqueueSuccess\n\n/**\n * Performs D-002 durable replay/idempotency resolution, live grant\n * authorization, and atomic enqueue after pure request verification.\n */\nexport async function admitAndEnqueue(input: AdmitAndEnqueueInput): Promise<AdmitAndEnqueueResult> {\n const attemptResult = createAttempt(input.verified)\n if (!attemptResult.ok) return attemptResult.failure\n const { attempt } = attemptResult\n const wake = toAdmittedWake(input.verified)\n\n const prior = await resolvePriorAttempt(input.inbox, attempt, wake)\n if (!prior.pending) return prior.result\n\n if (!isNonnegativeSafeInteger(input.expectedHead)) {\n return reject('grant-view-invalid', ['expectedHead must be a nonnegative safe integer'])\n }\n\n const authorization = await authorize(input)\n if (!authorization.ok) return authorization.failure\n return await commitAuthorizedWake(input.inbox, attempt, authorization.grant, wake)\n}\n\ntype PriorAttemptResult = {\n readonly pending: true\n} | {\n readonly pending: false\n readonly result: AdmitAndEnqueueResult\n}\n\nasync function resolvePriorAttempt(\n inbox: AtomicWakeInbox,\n attempt: WakeAdmissionAttempt,\n wake: AdmittedWake,\n): Promise<PriorAttemptResult> {\n let resolution\n try {\n resolution = await inbox.resolveAttempt(attempt)\n } catch (error) {\n return completed(reject('inbox-unavailable', [errorMessage(error)]))\n }\n\n if (!isRecord(resolution) || typeof resolution.kind !== 'string') {\n return completed(reject('inbox-unavailable', ['inbox returned an invalid attempt resolution']))\n }\n if (resolution.kind === 'jwt-id-collision' || resolution.kind === 'wake-id-collision') {\n return completed(reject(resolution.kind))\n }\n if (resolution.kind === 'duplicate') {\n const receiptFailure = validateReceipt(resolution.receipt, attempt)\n return completed(receiptFailure\n ?? success('duplicate', snapshotReceipt(resolution.receipt), wake))\n }\n if (resolution.kind !== 'new') {\n return completed(reject('inbox-unavailable', ['inbox returned an unknown attempt resolution']))\n }\n return Object.freeze({ pending: true })\n}\n\nasync function commitAuthorizedWake(\n inbox: AtomicWakeInbox,\n attempt: WakeAdmissionAttempt,\n grant: AuthorizedWakeGrant,\n wake: AdmittedWake,\n): Promise<AdmitAndEnqueueResult> {\n let committed: WakeCommitResult\n try {\n committed = await inbox.commitAuthorized({\n attempt,\n grant,\n wake,\n })\n } catch (error) {\n return reject('inbox-unavailable', [errorMessage(error)])\n }\n\n if (!isRecord(committed) || typeof committed.kind !== 'string') {\n return reject('inbox-unavailable', ['inbox returned an invalid commit result'])\n }\n if (committed.kind === 'jwt-id-collision' || committed.kind === 'wake-id-collision') {\n return reject(committed.kind)\n }\n if (committed.kind !== 'duplicate' && committed.kind !== 'enqueued') {\n return reject('inbox-unavailable', ['inbox returned an unknown commit result'])\n }\n\n const receiptFailure = validateReceipt(committed.receipt, attempt)\n if (receiptFailure !== undefined) return receiptFailure\n return success(committed.kind, snapshotReceipt(committed.receipt), wake)\n}\n\nfunction completed(result: AdmitAndEnqueueResult): PriorAttemptResult {\n return Object.freeze({ pending: false, result })\n}\n\ntype AttemptResult = {\n readonly attempt: WakeAdmissionAttempt\n readonly ok: true\n} | {\n readonly failure: AdmitAndEnqueueFailure\n readonly ok: false\n}\n\nfunction createAttempt(verified: VerifiedWakeRequest): AttemptResult {\n if (verified.expiresAt > Number.MAX_SAFE_INTEGER - EVENT_KIT_REPLAY_RETENTION_SKEW_SECONDS) {\n return {\n failure: reject('inbox-unavailable', ['JWT expiry cannot be represented through the replay-retention window']),\n ok: false,\n }\n }\n\n return {\n attempt: Object.freeze({\n audience: verified.audience,\n eventHash: verified.eventHash,\n jwtId: verified.jwtId,\n publisher: verified.publisher,\n retainJwtUntil: verified.expiresAt + EVENT_KIT_REPLAY_RETENTION_SKEW_SECONDS,\n wakeId: verified.wakeId,\n }),\n ok: true,\n }\n}\n\ntype AuthorizationResult = {\n readonly grant: AuthorizedWakeGrant\n readonly ok: true\n} | {\n readonly failure: AdmitAndEnqueueFailure\n readonly ok: false\n}\n\nasync function authorize(\n input: AdmitAndEnqueueInput,\n): Promise<AuthorizationResult> {\n const { route } = input.verified\n let decision: WakeGrantAuthorizationDecision\n try {\n decision = await input.grants.authorizePublisher({\n controller: route.controller,\n deploymentId: route.deploymentId,\n expectedHead: input.expectedHead,\n publisher: input.verified.publisher,\n ...(route.queueId === undefined ? {} : { queueId: route.queueId }),\n })\n } catch (error) {\n return { failure: reject('grant-unavailable', [errorMessage(error)]), ok: false }\n }\n\n const viewFailure = validateGrantView(decision, input.expectedHead, route.maxGrantLagBlocks)\n if (viewFailure !== undefined) return { failure: viewFailure, ok: false }\n if (!decision.enabled) return { failure: reject('grant-missing'), ok: false }\n\n const evidenceFailure = validateGrantEvidence(decision.grant, input.verified, decision.atBlock)\n if (evidenceFailure !== undefined) return { failure: evidenceFailure, ok: false }\n\n const grant: AuthorizedWakeGrant = Object.freeze({\n atBlock: decision.atBlock,\n expectedHead: input.expectedHead,\n grant: snapshotGrantEvidence(decision.grant),\n lag: input.expectedHead - decision.atBlock,\n })\n return { grant, ok: true }\n}\n\nfunction validateGrantView(\n decision: WakeGrantAuthorizationDecision,\n expectedHead: number,\n maxGrantLagBlocks: number,\n): AdmitAndEnqueueFailure | undefined {\n if (!isRecord(decision)\n || !Object.hasOwn(decision, 'enabled')\n || typeof decision.enabled !== 'boolean'\n || !Object.hasOwn(decision, 'atBlock')) {\n return reject('grant-view-invalid', ['grant authorizer returned an invalid decision'])\n }\n if (!isNonnegativeSafeInteger(decision.atBlock)) {\n return reject('grant-view-invalid', ['grant atBlock must be a nonnegative safe integer'])\n }\n if (decision.atBlock > expectedHead) {\n return reject('grant-view-invalid', ['grant view is ahead of the trusted finalized head'])\n }\n\n const lag = expectedHead - decision.atBlock\n if (decision.expectedHead !== undefined && decision.expectedHead !== expectedHead) {\n return reject('grant-view-invalid', ['grant diagnostic expectedHead disagrees with the trusted head'])\n }\n if (decision.lag !== undefined && decision.lag !== lag) {\n return reject('grant-view-invalid', ['grant diagnostic lag disagrees with the recomputed lag'])\n }\n if (lag > maxGrantLagBlocks) {\n return reject('grant-view-stale', [`grantLag=${lag} max=${maxGrantLagBlocks}`])\n }\n return undefined\n}\n\nfunction validateGrantEvidence(\n evidence: WakeGrantEvidence,\n verified: VerifiedWakeRequest,\n atBlock: number,\n): AdmitAndEnqueueFailure | undefined {\n if (!isRecord(evidence)) return reject('grant-view-invalid', ['enabled grant decision omitted evidence'])\n const requiredFields = [\n 'assertedAtBlock',\n 'controller',\n 'deploymentId',\n 'id',\n 'target',\n ] as const\n if (requiredFields.some(field => !Object.hasOwn(evidence, field))) {\n return reject('grant-view-invalid', ['enabled grant evidence requires own canonical fields'])\n }\n if (typeof evidence.id !== 'string' || evidence.id.length === 0) {\n return reject('grant-view-invalid', ['enabled grant evidence requires a non-empty id'])\n }\n if (!isNonnegativeSafeInteger(evidence.assertedAtBlock) || evidence.assertedAtBlock > atBlock) {\n return reject('grant-view-invalid', ['grant assertion block must be at or before the evaluated snapshot'])\n }\n if (evidence.controller !== verified.route.controller) {\n return reject('grant-view-invalid', ['grant controller does not match the configured controller'])\n }\n if (evidence.target !== verified.publisher) {\n return reject('grant-view-invalid', ['grant target does not match the verified publisher'])\n }\n const evidenceHasQueue = Object.hasOwn(evidence, 'queueId')\n const routeHasQueue = Object.hasOwn(verified.route, 'queueId')\n if (evidence.deploymentId !== verified.route.deploymentId\n || evidenceHasQueue !== routeHasQueue\n || evidence.queueId !== verified.route.queueId) {\n return reject('grant-view-invalid', ['grant scope does not exactly match the configured route'])\n }\n return undefined\n}\n\nfunction validateReceipt(\n receipt: WakeAdmissionReceipt,\n attempt: WakeAdmissionAttempt,\n): AdmitAndEnqueueFailure | undefined {\n const requiredFields = [\n 'audience',\n 'eventHash',\n 'id',\n 'publisher',\n 'wakeId',\n ] as const\n if (!isRecord(receipt)\n || requiredFields.some(field => !Object.hasOwn(receipt, field))\n || typeof receipt.id !== 'string'\n || receipt.id.length === 0) {\n return reject('inbox-unavailable', ['inbox returned an invalid receipt'])\n }\n if (receipt.audience !== attempt.audience\n || receipt.publisher !== attempt.publisher\n || receipt.eventHash !== attempt.eventHash\n || receipt.wakeId !== attempt.wakeId) {\n return reject('inbox-unavailable', ['inbox receipt is not bound to the verified attempt'])\n }\n return undefined\n}\n\nfunction snapshotGrantEvidence(evidence: WakeGrantEvidence): WakeGrantEvidence {\n return Object.freeze({\n assertedAtBlock: evidence.assertedAtBlock,\n controller: evidence.controller,\n deploymentId: evidence.deploymentId,\n id: evidence.id,\n ...(evidence.queueId === undefined ? {} : { queueId: evidence.queueId }),\n target: evidence.target,\n })\n}\n\nfunction snapshotReceipt(receipt: WakeAdmissionReceipt): WakeAdmissionReceipt {\n return Object.freeze({\n audience: receipt.audience,\n eventHash: receipt.eventHash,\n id: receipt.id,\n publisher: receipt.publisher,\n wakeId: receipt.wakeId,\n })\n}\n\nfunction toAdmittedWake(verified: VerifiedWakeRequest): AdmittedWake {\n return Object.freeze({\n audience: verified.audience,\n deploymentId: verified.deploymentId,\n event: verified.event,\n eventHash: verified.eventHash,\n fromBlock: verified.fromBlock,\n jti: verified.jwtId,\n publisher: verified.publisher,\n ...(verified.queueId === undefined ? {} : { queueId: verified.queueId }),\n toBlock: verified.toBlock,\n wakeId: verified.wakeId,\n })\n}\n\nfunction success(\n disposition: AdmitAndEnqueueSuccess['disposition'],\n receipt: WakeAdmissionReceipt,\n wake: AdmittedWake,\n): AdmitAndEnqueueSuccess {\n return Object.freeze({\n disposition, ok: true, receipt, wake,\n })\n}\n\nfunction reject(\n reason: AdmitAndEnqueueFailureReason,\n details?: readonly string[],\n): AdmitAndEnqueueFailure {\n if (details === undefined) return Object.freeze({ ok: false, reason })\n return Object.freeze({\n details: Object.freeze([...details]), ok: false, reason,\n })\n}\n\nfunction isNonnegativeSafeInteger(value: unknown): value is number {\n return typeof value === 'number' && Number.isSafeInteger(value) && value >= 0\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n\nfunction errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error)\n}\n", "import type { WakeGrantObject, WakeGrantRevocation } from '@xyo-network/event-kit-schemas'\nimport {\n normalizeAddress,\n WakeGrantObjectSchema,\n WakeGrantRevocationSchema,\n} from '@xyo-network/event-kit-schemas'\n\nimport type {\n StatementGrantClaim,\n StatementGrantObject,\n StatementGraphGrantReadModel,\n} from './statementGraphPorts.ts'\n\nexport interface MemoryStatementGrantGraph extends StatementGraphGrantReadModel {\n /**\n * Claim a grant object. Statement Graph v2 is append-only, so a repeat claim\n * is redundant: it advances `lastBlock` and leaves `firstBlock` frozen.\n */\n claim: (input: {\n block: number\n /** Claim event hash; must be 64 lowercase hex. */\n eventHash: string\n grant: WakeGrantObject\n objectHash: string\n source: string\n }) => void\n /**\n * Claim a revocation object negating `grant`. There is no revoke verb in v2 \u2014\n * negation is another claim, and Event Kit reads it as the disabling signal.\n */\n revoke: (input: {\n block: number\n eventHash: string\n grantObjectHash: string\n objectHash: string\n source: string\n }) => void\n setHead: (block: number) => void\n}\n\n/**\n * In-memory Statement Graph v2 stand-in for grant/negation tests.\n * Not a full fold \u2014 enough to exercise the Event Kit allowlist adapter.\n */\nexport function createMemoryStatementGrantGraph(initialHead = 0): MemoryStatementGrantGraph {\n let head = initialHead\n const claims = new Map<string, StatementGrantClaim>()\n const objects = new Map<string, StatementGrantObject>()\n\n function claimKey(source: string, objectHash: string): string {\n return `${normalizeAddress(source)}|${objectHash}`\n }\n\n function materialize(input: {\n block: number\n declaredSchema: string\n eventHash: string\n objectHash: string\n params: Readonly<Record<string, unknown>>\n source: string\n }): void {\n const source = normalizeAddress(input.source)\n objects.set(input.objectHash, Object.freeze({\n assurance: 'resolved',\n declaredSchema: input.declaredSchema,\n objectHash: input.objectHash,\n params: Object.freeze({ ...input.params }),\n }))\n\n const key = claimKey(source, input.objectHash)\n const existing = claims.get(key)\n claims.set(key, Object.freeze(existing === undefined\n ? {\n declaredObjectSchema: input.declaredSchema,\n firstBlock: input.block,\n firstEventHash: input.eventHash,\n lastBlock: input.block,\n objectHash: input.objectHash,\n source,\n }\n // Redundant claim: first-wins on identity, only the moving clock advances.\n : { ...existing, lastBlock: Math.max(existing.lastBlock, input.block) }))\n if (input.block > head) head = input.block\n }\n\n return {\n async head(): Promise<number> {\n return head\n },\n\n setHead(block: number): void {\n head = block\n },\n\n async claims(source, query): Promise<readonly StatementGrantClaim[]> {\n const normalizedSource = normalizeAddress(source)\n const records: StatementGrantClaim[] = []\n for (const record of claims.values()) {\n if (record.source !== normalizedSource) continue\n if (query?.objectHash !== undefined && record.objectHash !== query.objectHash) continue\n if (query?.declaredObjectSchemaPrefix !== undefined\n && !record.declaredObjectSchema.startsWith(query.declaredObjectSchemaPrefix)) {\n continue\n }\n records.push(record)\n }\n return records\n },\n\n async object(objectHash): Promise<StatementGrantObject | undefined> {\n return objects.get(objectHash)\n },\n\n claim(input): void {\n if (input.grant.schema !== WakeGrantObjectSchema) {\n throw new Error(`expected ${WakeGrantObjectSchema}`)\n }\n const { schema: _schema, ...params } = input.grant\n materialize({\n block: input.block,\n declaredSchema: WakeGrantObjectSchema,\n eventHash: input.eventHash,\n objectHash: input.objectHash,\n params: {\n ...params,\n permissions: Object.freeze([...params.permissions]),\n },\n source: input.source,\n })\n },\n\n revoke(input): void {\n const revocation: Omit<WakeGrantRevocation, 'schema'> = { grant: input.grantObjectHash }\n materialize({\n block: input.block,\n declaredSchema: WakeGrantRevocationSchema,\n eventHash: input.eventHash,\n objectHash: input.objectHash,\n params: revocation,\n source: input.source,\n })\n },\n }\n}\n", "import type { Hash, WakeId } from '@xyo-network/event-kit-schemas'\n\nimport type {\n AtomicWakeInbox,\n WakeAdmissionAttempt,\n WakeAdmissionReceipt,\n WakeAttemptResolution,\n WakeCommitResult,\n} from './admissionTypes.ts'\nimport type { AdmittedWake } from './types.ts'\n\nexport interface MemoryWakeInboxOptions {\n /**\n * Durable-sink stand-in invoked inside the atomic commit. A throw leaves both\n * identities unconsumed, so the publisher may retry the same `wakeId` with a\n * fresh `jti` instead of losing the wake to a burned replay key.\n */\n readonly enqueue?: (wake: AdmittedWake) => Promise<void> | void\n /** Trusted clock in Unix seconds, used to drop expired token records. */\n readonly nowSeconds?: () => number\n}\n\nexport interface MemoryWakeInbox extends AtomicWakeInbox {\n /** Wakes handed to `enqueue`, in commit order. */\n readonly queued: readonly AdmittedWake[]\n /** Live `(aud, iss, jti)` replay records. */\n readonly tokenRecordCount: number\n /** Live `(aud, iss, wakeId)` logical records. */\n readonly wakeRecordCount: number\n}\n\ninterface ReceiptBinding {\n readonly eventHash: Hash\n readonly receipt: WakeAdmissionReceipt\n readonly wakeId: WakeId\n}\n\ninterface TokenBinding extends ReceiptBinding {\n readonly retainJwtUntil: number\n}\n\n/** The already-recorded outcomes, common to both the resolve and commit unions. */\ntype RecordedResolution = Exclude<WakeAttemptResolution, { readonly kind: 'new' }>\n\n/**\n * Single-process linearizable `AtomicWakeInbox` for structural tests and local\n * rehearsal.\n *\n * Writes are ordered so a failing sink cannot consume `jti` or `wakeId` without\n * a recoverable receipt. It is **not** durable: process death between enqueue\n * and record commit redelivers the wake, and no state survives restart. Gate 5\n * requires a durable adapter; this is local evidence only.\n */\nexport function createMemoryWakeInbox(options: MemoryWakeInboxOptions = {}): MemoryWakeInbox {\n const tokenRecords = new Map<string, TokenBinding>()\n const wakeRecords = new Map<string, ReceiptBinding>()\n const queued: AdmittedWake[] = []\n let receiptSequence = 0\n let tail: Promise<unknown> = Promise.resolve()\n\n /**\n * Serializes the critical section. Both entry points read, decide, and write\n * across an `await`, so without this a concurrent commit could pass its\n * recheck before the winning commit records either identity.\n */\n function exclusive<T>(work: () => Promise<T>): Promise<T> {\n const run = tail.then(work, work)\n // allSettled never rejects, so a failed section still releases the lock.\n tail = Promise.allSettled([run])\n return run\n }\n\n function pruneExpiredTokens(): void {\n const { nowSeconds } = options\n if (nowSeconds === undefined) return\n const now = nowSeconds()\n for (const [key, binding] of tokenRecords) {\n if (binding.retainJwtUntil <= now) tokenRecords.delete(key)\n }\n }\n\n /** Resolves an attempt against both indexes, binding a fresh `jti` to a known wake. */\n function matchRecorded(attempt: WakeAdmissionAttempt): RecordedResolution | undefined {\n const tokenBinding = tokenRecords.get(tokenKey(attempt))\n if (tokenBinding !== undefined) {\n return tokenBinding.eventHash === attempt.eventHash && tokenBinding.wakeId === attempt.wakeId\n ? { kind: 'duplicate', receipt: tokenBinding.receipt }\n : { kind: 'jwt-id-collision' }\n }\n\n const wakeBinding = wakeRecords.get(wakeKey(attempt))\n if (wakeBinding === undefined) return undefined\n if (wakeBinding.eventHash !== attempt.eventHash) return { kind: 'wake-id-collision' }\n tokenRecords.set(tokenKey(attempt), { ...wakeBinding, retainJwtUntil: attempt.retainJwtUntil })\n return { kind: 'duplicate', receipt: wakeBinding.receipt }\n }\n\n return {\n get queued(): readonly AdmittedWake[] {\n return queued\n },\n\n get tokenRecordCount(): number {\n return tokenRecords.size\n },\n\n get wakeRecordCount(): number {\n return wakeRecords.size\n },\n\n async resolveAttempt(attempt: WakeAdmissionAttempt): Promise<WakeAttemptResolution> {\n return await exclusive(async () => {\n pruneExpiredTokens()\n return matchRecorded(attempt) ?? { kind: 'new' }\n })\n },\n\n async commitAuthorized({ attempt, wake }: {\n readonly attempt: WakeAdmissionAttempt\n readonly wake: AdmittedWake\n }): Promise<WakeCommitResult> {\n return await exclusive(async () => {\n pruneExpiredTokens()\n const recorded = matchRecorded(attempt)\n if (recorded !== undefined) return recorded\n\n const receipt: WakeAdmissionReceipt = Object.freeze({\n audience: attempt.audience,\n eventHash: attempt.eventHash,\n id: `receipt-${receiptSequence += 1}`,\n publisher: attempt.publisher,\n wakeId: attempt.wakeId,\n })\n\n // Hand the wake to the sink before consuming either identity. A throw here\n // must leave the attempt retryable rather than strand it without a receipt.\n await options.enqueue?.(wake)\n queued.push(wake)\n\n const binding: ReceiptBinding = {\n eventHash: attempt.eventHash,\n receipt,\n wakeId: attempt.wakeId,\n }\n tokenRecords.set(tokenKey(attempt), { ...binding, retainJwtUntil: attempt.retainJwtUntil })\n wakeRecords.set(wakeKey(attempt), binding)\n return { kind: 'enqueued', receipt }\n })\n },\n }\n}\n\n/** Opaque audiences may contain any character, so keys are JSON-encoded rather than joined. */\nfunction tokenKey(attempt: WakeAdmissionAttempt): string {\n return JSON.stringify([attempt.audience, attempt.publisher, attempt.jwtId])\n}\n\nfunction wakeKey(attempt: WakeAdmissionAttempt): string {\n return JSON.stringify([attempt.audience, attempt.publisher, attempt.wakeId])\n}\n", "import type { AdmittedWake } from './types.ts'\nimport type { LeasedWake, WakeQueue } from './wakeQueue.ts'\n\nexport interface MemoryWakeQueue extends WakeQueue {\n /** Entries currently leased and not yet acked or released. */\n inflightCount: () => Promise<number>\n}\n\ninterface Entry {\n readonly sequence: number\n readonly wake: AdmittedWake\n}\n\n/**\n * In-process `WakeQueue`.\n *\n * Structural evidence only: nothing survives process death, so `recoverInflight`\n * can reclaim a lease abandoned within this process but cannot help after a\n * restart. Use the filesystem or SQLite provider where durability matters.\n */\nexport function createMemoryWakeQueue(): MemoryWakeQueue {\n const pending: Entry[] = []\n const inflight = new Map<number, Entry>()\n let sequence = 0\n\n return {\n async append(wake: AdmittedWake): Promise<void> {\n pending.push({ sequence: sequence += 1, wake })\n },\n\n async claim(): Promise<LeasedWake | undefined> {\n const entry = pending.shift()\n if (entry === undefined) return undefined\n inflight.set(entry.sequence, entry)\n\n return {\n wake: entry.wake,\n async ack(): Promise<void> {\n inflight.delete(entry.sequence)\n },\n async release(): Promise<void> {\n if (!inflight.delete(entry.sequence)) return\n // Restore arrival order rather than appending to the tail.\n pending.push(entry)\n pending.sort((left, right) => left.sequence - right.sequence)\n },\n }\n },\n\n async inflightCount(): Promise<number> {\n return inflight.size\n },\n\n async pendingCount(): Promise<number> {\n return pending.length\n },\n\n async recoverInflight(): Promise<number> {\n const recovered = inflight.size\n for (const entry of inflight.values()) pending.push(entry)\n inflight.clear()\n pending.sort((left, right) => left.sequence - right.sequence)\n return recovered\n },\n }\n}\n", "import type { WakeGrantObject } from '@xyo-network/event-kit-schemas'\nimport {\n asWakeGrantObject,\n asWakeGrantRevocation,\n DeploymentIdZod,\n HashZod,\n NormalizedAddressZod,\n WakeGrantObjectSchema,\n WakeGrantRevocationSchema,\n} from '@xyo-network/event-kit-schemas'\n\nimport type {\n WakeGrantAuthorizationDecision,\n WakeGrantAuthorizationRequest,\n WakeGrantAuthorizer,\n WakeGrantEvidence,\n} from './admissionTypes.ts'\nimport type {\n StatementGrantClaim,\n StatementGraphGrantReadModel,\n} from './statementGraphPorts.ts'\n\nexport interface StatementGraphWakeGrantAuthorizerOptions {\n readonly viewer: StatementGraphGrantReadModel\n}\n\n/**\n * Adapts a canonical Statement Graph v2 read model to the evidence-bearing\n * D-002 grant authorization port. Each decision is bound to one stable head.\n *\n * v2 is append-only with no `target` and no lifecycle `state`, so this layer\n * owns two things the protocol used to:\n *\n * - **Aboutness.** The publisher a grant enables is read from the grant\n * object's `publisher` param, not from a claim edge.\n * - **Negation.** A grant is disabled by a further claim, by the *same pinned\n * controller*, of a revocation object referencing that grant's hash.\n * Revocations from any other source are ignored.\n */\nexport function createStatementGraphWakeGrantAuthorizer(\n options: StatementGraphWakeGrantAuthorizerOptions,\n): WakeGrantAuthorizer {\n const { viewer } = options\n\n return Object.freeze({\n async authorizePublisher(request: WakeGrantAuthorizationRequest): Promise<WakeGrantAuthorizationDecision> {\n assertValidRequest(request)\n\n const atBlock = await readHead(viewer)\n if (atBlock > request.expectedHead) {\n throw new Error(`Statement Graph head ${atBlock} is ahead of expected head ${request.expectedHead}`)\n }\n\n const claims = await viewer.claims(request.controller, { declaredObjectSchemaPrefix: WakeGrantObjectSchema })\n const revokedGrantHashes = await readRevocations(viewer, request.controller, atBlock)\n\n let evidence: WakeGrantEvidence | undefined\n for (const claim of claims) {\n evidence = await resolveEvidence(viewer, claim, request, atBlock, revokedGrantHashes)\n if (evidence !== undefined) break\n }\n\n const completedAtBlock = await readHead(viewer)\n if (completedAtBlock !== atBlock) {\n throw new Error(`Statement Graph head changed during authorization [${atBlock} -> ${completedAtBlock}]`)\n }\n\n const lag = request.expectedHead - atBlock\n if (evidence === undefined) {\n return Object.freeze({\n atBlock,\n enabled: false,\n expectedHead: request.expectedHead,\n lag,\n })\n }\n return Object.freeze({\n atBlock,\n enabled: true,\n expectedHead: request.expectedHead,\n grant: evidence,\n lag,\n })\n },\n })\n}\n\n/**\n * Collects the grant hashes the pinned controller has negated at or before\n * `atBlock`. A revocation claimed after the evaluated snapshot is not yet in\n * effect, matching how a grant claimed after the snapshot does not yet enable.\n */\nasync function readRevocations(\n viewer: StatementGraphGrantReadModel,\n controller: string,\n atBlock: number,\n): Promise<ReadonlySet<string>> {\n const revoked = new Set<string>()\n const claims = await viewer.claims(controller, { declaredObjectSchemaPrefix: WakeGrantRevocationSchema })\n\n for (const claim of claims) {\n if (!isLiveClaim(claim, controller, WakeGrantRevocationSchema, atBlock)) continue\n const object = await viewer.object(claim.objectHash)\n if (object?.assurance !== 'resolved') continue\n if (object.declaredSchema !== WakeGrantRevocationSchema || object.objectHash !== claim.objectHash) continue\n if (!isRecord(object.params) || Object.hasOwn(object.params, 'schema')) continue\n const revocation = asWakeGrantRevocation({ ...object.params, schema: object.declaredSchema })\n if (revocation !== undefined) revoked.add(revocation.grant)\n }\n return revoked\n}\n\nasync function resolveEvidence(\n viewer: StatementGraphGrantReadModel,\n claim: StatementGrantClaim,\n request: WakeGrantAuthorizationRequest,\n atBlock: number,\n revokedGrantHashes: ReadonlySet<string>,\n): Promise<WakeGrantEvidence | undefined> {\n if (!isLiveClaim(claim, request.controller, WakeGrantObjectSchema, atBlock)) return undefined\n if (revokedGrantHashes.has(claim.objectHash)) return undefined\n\n const object = await viewer.object(claim.objectHash)\n const grant = parseExactGrantObject(object, claim.objectHash)\n if (grant === undefined) return undefined\n if (grant.publisher !== request.publisher) return undefined\n if (grant.deploymentId !== request.deploymentId) return undefined\n if (grant.queueId !== request.queueId) return undefined\n if (!grant.permissions.includes('enqueue')) return undefined\n\n return Object.freeze({\n assertedAtBlock: claim.firstBlock,\n controller: request.controller,\n deploymentId: grant.deploymentId,\n id: claim.firstEventHash,\n ...(grant.queueId === undefined ? {} : { queueId: grant.queueId }),\n target: grant.publisher,\n })\n}\n\nfunction isLiveClaim(\n claim: StatementGrantClaim,\n controller: string,\n declaredObjectSchema: string,\n atBlock: number,\n): boolean {\n if (claim.source !== controller) return false\n if (claim.declaredObjectSchema !== declaredObjectSchema) return false\n if (!isNonnegativeSafeInteger(claim.firstBlock) || claim.firstBlock > atBlock) return false\n if (!isNonnegativeSafeInteger(claim.lastBlock) || claim.lastBlock < claim.firstBlock) return false\n if (!HashZod.safeParse(claim.firstEventHash).success) return false\n return HashZod.safeParse(claim.objectHash).success\n}\n\nfunction parseExactGrantObject(\n object: Awaited<ReturnType<StatementGraphGrantReadModel['object']>>,\n expectedObjectHash: string,\n): WakeGrantObject | undefined {\n if (object?.assurance !== 'resolved') return undefined\n if (object.declaredSchema !== WakeGrantObjectSchema || object.objectHash !== expectedObjectHash) return undefined\n if (!isRecord(object.params) || Object.hasOwn(object.params, 'schema')) return undefined\n return asWakeGrantObject({\n ...object.params,\n schema: object.declaredSchema,\n })\n}\n\nfunction assertValidRequest(request: WakeGrantAuthorizationRequest): void {\n if (!NormalizedAddressZod.safeParse(request.controller).success) {\n throw new TypeError('Grant controller must be a normalized address')\n }\n if (!NormalizedAddressZod.safeParse(request.publisher).success) {\n throw new TypeError('Grant publisher must be a normalized address')\n }\n if (!DeploymentIdZod.safeParse(request.deploymentId).success) {\n throw new TypeError('Grant deploymentId must contain 1 to 255 characters')\n }\n if (request.queueId !== undefined && (request.queueId.length === 0 || request.queueId.length > 255)) {\n throw new TypeError('Grant queueId must contain 1 to 255 characters when configured')\n }\n if (!isNonnegativeSafeInteger(request.expectedHead)) {\n throw new RangeError('Grant expectedHead must be a nonnegative safe integer')\n }\n}\n\nasync function readHead(viewer: StatementGraphGrantReadModel): Promise<number> {\n const head = await viewer.head()\n if (!isNonnegativeSafeInteger(head)) {\n throw new RangeError('Statement Graph head must be a nonnegative safe integer')\n }\n return head\n}\n\nfunction isNonnegativeSafeInteger(value: unknown): value is number {\n return typeof value === 'number' && Number.isSafeInteger(value) && value >= 0\n}\n\nfunction isRecord(value: unknown): value is Readonly<Record<string, unknown>> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n", "import type {\n DeploymentId,\n Hash,\n NormalizedAddress,\n WakeEnvelope,\n WakeId,\n WakeJwtAudience,\n WakeJwtHeader,\n WakeJwtId,\n WakeJwtPayload,\n} from '@xyo-network/event-kit-schemas'\nimport {\n DeploymentIdZod,\n NormalizedAddressZod,\n WakeEnvelopeZod,\n WakeIdRegExp,\n WakeJwtAudienceZod,\n WakeJwtHeaderZod,\n WakeJwtPayloadZod,\n WakeJwtSchema,\n} from '@xyo-network/event-kit-schemas'\nimport type { JwtHeader, JwtPayload } from '@xyo-network/sdk'\nimport { Account, PayloadBuilder } from '@xyo-network/sdk'\n\n/** D-002 maximum accepted JWT lifetime. */\nexport const EVENT_KIT_MAX_JWT_LIFETIME_SECONDS = 300\n\n/** D-002 maximum accepted publisher clock lead. */\nexport const EVENT_KIT_MAX_FUTURE_IAT_SECONDS = 60\n\nexport interface WakeAdmissionRoute {\n readonly audience: WakeJwtAudience\n readonly controller: NormalizedAddress\n readonly deploymentId: DeploymentId\n readonly maxBlocksPerWake: number\n readonly maxGrantLagBlocks: number\n readonly queueId?: string\n}\n\nexport interface VerifyWakeRequestInput {\n /** Already JSON-decoded request body. Wrappers and companion credential fields are rejected. */\n readonly body: unknown\n readonly jwt: string\n /** Trusted request-receive clock, supplied explicitly to keep verification deterministic. */\n readonly nowSeconds: number\n readonly route: WakeAdmissionRoute\n}\n\nexport type VerifyWakeRequestRejectionReason\n = | 'configuration-invalid'\n | 'event-hash-failed'\n | 'event-hash-mismatch'\n | 'event-malformed'\n | 'event-target-mismatch'\n | 'range-invalid'\n | 'range-too-large'\n | 'wake-id-invalid'\n | 'jwt-audience-mismatch'\n | 'jwt-claims-invalid'\n | 'jwt-expired'\n | 'jwt-future-iat'\n | 'jwt-header-invalid'\n | 'jwt-identity-invalid'\n | 'jwt-invalid'\n | 'jwt-lifetime-invalid'\n | 'jwt-malformed'\n | 'jwt-nbf-not-allowed'\n | 'jwt-schema-mismatch'\n\nexport interface VerifiedWakeRequest {\n readonly audience: WakeJwtAudience\n readonly deploymentId: DeploymentId\n readonly event: Readonly<WakeEnvelope>\n readonly eventHash: Hash\n readonly expiresAt: number\n readonly fromBlock: number\n readonly issuedAt: number\n readonly jwtId: WakeJwtId\n readonly publisher: NormalizedAddress\n readonly queueId?: string\n readonly route: WakeAdmissionRoute\n readonly toBlock: number\n readonly tokenIssuedAt: number\n readonly wakeId: WakeId\n}\n\nexport interface VerifyWakeRequestSuccess {\n readonly ok: true\n readonly verified: VerifiedWakeRequest\n}\n\nexport interface VerifyWakeRequestFailure {\n readonly details?: readonly string[]\n readonly ok: false\n readonly reason: VerifyWakeRequestRejectionReason\n}\n\nexport type VerifyWakeRequestResult = VerifyWakeRequestFailure | VerifyWakeRequestSuccess\n\ninterface VerifiedJwtProfile {\n readonly eventHash: Hash\n readonly expiresAt: number\n readonly issuedAt: number\n readonly jwtId: WakeJwtId\n readonly publisher: NormalizedAddress\n}\n\ntype JwtProfileResult = VerifyWakeRequestFailure | {\n readonly jwt: VerifiedJwtProfile\n readonly ok: true\n}\n\ntype StrictJwtWireResult = VerifyWakeRequestFailure | {\n readonly header: WakeJwtHeader\n readonly ok: true\n readonly payload: WakeJwtPayload\n}\n\n/**\n * Verifies the cryptographic and request-shape portion of D-002 without grant,\n * replay, queue, reducer, or XL1 I/O.\n */\nexport async function verifyWakeRequest(input: VerifyWakeRequestInput): Promise<VerifyWakeRequestResult> {\n const { nowSeconds } = input\n const route = snapshotRoute(input.route)\n const configurationFailure = validateConfiguration(route, nowSeconds)\n if (configurationFailure !== undefined) return configurationFailure\n\n const parsed = WakeEnvelopeZod.safeParse(input.body)\n if (!parsed.success) {\n const details = parsed.error.issues.map(issue => `${issue.path.join('.') || '<root>'}: ${issue.message}`)\n if (hasInvertedSafeRange(input.body)) return reject('range-invalid', details)\n if (isRecord(input.body)\n && Object.hasOwn(input.body, 'wakeId')\n && parsed.error.issues.some(issue => issue.path[0] === 'wakeId')) {\n return reject('wake-id-invalid', details)\n }\n return reject(\n 'event-malformed',\n details,\n )\n }\n\n const event = parsed.data\n if (!WakeIdRegExp.test(event.wakeId)) return reject('wake-id-invalid')\n if (!hasSafeEventNumbers(event)) return reject('event-malformed', ['wake numeric fields must be nonnegative safe integers'])\n if (event.deploymentId !== route.deploymentId || event.queueId !== route.queueId) {\n return reject('event-target-mismatch')\n }\n if (event.fromBlock > event.toBlock) return reject('range-invalid')\n\n if (event.toBlock - event.fromBlock >= route.maxBlocksPerWake) {\n return reject('range-too-large', [`maxBlocksPerWake=${route.maxBlocksPerWake}`])\n }\n\n const jwtResult = await verifyJwtProfile(input.jwt, route.audience, nowSeconds)\n if (!jwtResult.ok) return jwtResult\n\n let eventHash: Hash\n try {\n eventHash = await PayloadBuilder.dataHash(event)\n } catch (error) {\n return reject('event-hash-failed', [errorMessage(error)])\n }\n if (eventHash !== jwtResult.jwt.eventHash) return reject('event-hash-mismatch')\n\n const frozenEvent: Readonly<WakeEnvelope> = Object.freeze({ ...event })\n const verified: VerifiedWakeRequest = Object.freeze({\n audience: route.audience,\n deploymentId: event.deploymentId,\n event: frozenEvent,\n eventHash,\n expiresAt: jwtResult.jwt.expiresAt,\n fromBlock: event.fromBlock,\n issuedAt: event.issuedAt,\n jwtId: jwtResult.jwt.jwtId,\n publisher: jwtResult.jwt.publisher,\n ...(event.queueId === undefined ? {} : { queueId: event.queueId }),\n route,\n toBlock: event.toBlock,\n tokenIssuedAt: jwtResult.jwt.issuedAt,\n wakeId: event.wakeId,\n })\n return Object.freeze({ ok: true, verified })\n}\n\nfunction validateConfiguration(route: WakeAdmissionRoute, nowSeconds: number): VerifyWakeRequestFailure | undefined {\n if (!WakeJwtAudienceZod.safeParse(route.audience).success) {\n return reject('configuration-invalid', ['audience must not be empty'])\n }\n if (!DeploymentIdZod.safeParse(route.deploymentId).success) {\n return reject('configuration-invalid', ['deploymentId must contain 1 to 255 characters'])\n }\n if (route.queueId !== undefined && (route.queueId.length === 0 || route.queueId.length > 255)) {\n return reject('configuration-invalid', ['queueId must contain 1 to 255 characters when configured'])\n }\n if (!NormalizedAddressZod.safeParse(route.controller).success) {\n return reject('configuration-invalid', ['controller must be a normalized 40-character lowercase-hex address'])\n }\n if (!isNonnegativeSafeInteger(nowSeconds)) {\n return reject('configuration-invalid', ['nowSeconds must be a nonnegative safe integer'])\n }\n if (!Number.isSafeInteger(route.maxBlocksPerWake) || route.maxBlocksPerWake < 1) {\n return reject('configuration-invalid', ['maxBlocksPerWake must be a positive safe integer'])\n }\n if (!isNonnegativeSafeInteger(route.maxGrantLagBlocks)) {\n return reject('configuration-invalid', ['maxGrantLagBlocks must be a nonnegative safe integer'])\n }\n return undefined\n}\n\nasync function verifyJwtProfile(token: string, audience: string, nowSeconds: number): Promise<JwtProfileResult> {\n let verified: Awaited<ReturnType<typeof Account.verifyJwt>>\n try {\n verified = await Account.verifyJwt(token, { audience, now: nowSeconds })\n } catch (error) {\n return reject('jwt-malformed', [errorMessage(error)])\n }\n\n if (!verified.ok) {\n if (Object.hasOwn(verified.payload ?? {}, 'nbf')) return reject('jwt-nbf-not-allowed')\n return reject(classifySdkJwtFailure(verified.reasons), verified.reasons)\n }\n\n const wireResult = parseStrictJwtWire(verified.header, verified.payload, audience)\n if (!wireResult.ok) return wireResult\n\n const { header: strictHeader, payload: strictPayload } = wireResult\n if (strictHeader.kid !== strictPayload.iss) return reject('jwt-identity-invalid')\n if (strictPayload.exp <= nowSeconds) return reject('jwt-expired')\n if (strictPayload.exp - strictPayload.iat > EVENT_KIT_MAX_JWT_LIFETIME_SECONDS) return reject('jwt-lifetime-invalid')\n if (strictPayload.iat - nowSeconds > EVENT_KIT_MAX_FUTURE_IAT_SECONDS) return reject('jwt-future-iat')\n\n const jwt: VerifiedJwtProfile = Object.freeze({\n eventHash: strictPayload.eventHash,\n expiresAt: strictPayload.exp,\n issuedAt: strictPayload.iat,\n jwtId: strictPayload.jti,\n publisher: strictPayload.iss,\n })\n return Object.freeze({ jwt, ok: true })\n}\n\nfunction parseStrictJwtWire(header: JwtHeader, payload: JwtPayload, audience: string): StrictJwtWireResult {\n const headerResult = WakeJwtHeaderZod.safeParse(header)\n if (!headerResult.success) {\n if (!NormalizedAddressZod.safeParse(header.kid).success) return reject('jwt-identity-invalid')\n return reject('jwt-header-invalid', zodDetails(headerResult.error.issues))\n }\n if (Object.hasOwn(payload, 'nbf')) return reject('jwt-nbf-not-allowed')\n if (!NormalizedAddressZod.safeParse(payload.iss).success) return reject('jwt-identity-invalid')\n if (payload.schema !== WakeJwtSchema) return reject('jwt-schema-mismatch')\n if (payload.aud !== audience) return reject('jwt-audience-mismatch')\n if (!isNonnegativeSafeInteger(payload.iat) || !isNonnegativeSafeInteger(payload.exp) || payload.exp <= payload.iat) {\n return reject('jwt-lifetime-invalid')\n }\n\n const payloadResult = WakeJwtPayloadZod.safeParse(payload)\n if (!payloadResult.success) return reject('jwt-claims-invalid', zodDetails(payloadResult.error.issues))\n return Object.freeze({\n header: headerResult.data,\n ok: true,\n payload: payloadResult.data,\n })\n}\n\nfunction classifySdkJwtFailure(reasons: readonly string[]): VerifyWakeRequestRejectionReason {\n if (reasons.some(reason => reason.startsWith('audience mismatch:'))) return 'jwt-audience-mismatch'\n if (reasons.some(reason => reason.startsWith('expired:'))) return 'jwt-expired'\n if (reasons.some(reason => reason.startsWith('unsupported alg:') || reason.startsWith('unsupported typ:'))) {\n return 'jwt-header-invalid'\n }\n if (reasons.some(reason => (\n reason.startsWith('invalid public key:')\n || reason.startsWith('public key does not derive to kid:')\n || reason === 'header.kid does not match payload.iss'\n ))) {\n return 'jwt-identity-invalid'\n }\n return 'jwt-invalid'\n}\n\nfunction hasSafeEventNumbers(event: WakeEnvelope): boolean {\n return isNonnegativeSafeInteger(event.fromBlock)\n && isNonnegativeSafeInteger(event.toBlock)\n && isNonnegativeSafeInteger(event.issuedAt)\n}\n\nfunction hasInvertedSafeRange(value: unknown): boolean {\n if (!isRecord(value)) return false\n const { fromBlock, toBlock } = value\n return typeof fromBlock === 'number'\n && typeof toBlock === 'number'\n && isNonnegativeSafeInteger(fromBlock)\n && isNonnegativeSafeInteger(toBlock)\n && fromBlock > toBlock\n}\n\nfunction isNonnegativeSafeInteger(value: number): boolean {\n return Number.isSafeInteger(value) && value >= 0\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n\nfunction snapshotRoute(route: WakeAdmissionRoute): WakeAdmissionRoute {\n return Object.freeze({\n audience: route.audience,\n controller: route.controller,\n deploymentId: route.deploymentId,\n maxBlocksPerWake: route.maxBlocksPerWake,\n maxGrantLagBlocks: route.maxGrantLagBlocks,\n ...(route.queueId === undefined ? {} : { queueId: route.queueId }),\n })\n}\n\nfunction zodDetails(issues: readonly { readonly message: string; readonly path: readonly PropertyKey[] }[]): readonly string[] {\n return issues.map((issue) => {\n const path = issue.path.map(String).join('.') || '<root>'\n return `${path}: ${issue.message}`\n })\n}\n\nfunction reject(\n reason: VerifyWakeRequestRejectionReason,\n details?: readonly string[],\n): VerifyWakeRequestFailure {\n if (details === undefined) return Object.freeze({ ok: false, reason })\n return Object.freeze({\n details: Object.freeze([...details]),\n ok: false,\n reason,\n })\n}\n\nfunction errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error)\n}\n", "import type { AdmittedWake } from './types.ts'\n\n/**\n * One wake leased to exactly one consumer.\n *\n * The lease is held until `ack` or `release`. A consumer that dies holding it\n * leaves the entry recoverable rather than lost, which is why the queue port is\n * lease-based rather than push-based: a fire-and-forget handoff has no way to\n * reclaim work whose consumer never finished.\n */\nexport interface LeasedWake {\n /** Removes the entry permanently. Call only once the handler committed. */\n readonly ack: () => Promise<void>\n /** Returns the entry for another attempt. */\n readonly release: () => Promise<void>\n readonly wake: AdmittedWake\n}\n\n/**\n * Provider-agnostic durable wake queue.\n *\n * Implementations back this with a filesystem directory, SQLite, Postgres, or a\n * cloud queue. Delivery is at-least-once: a consumer MUST be idempotent, since\n * a lease that is never acked is redelivered.\n *\n * Every implementation must satisfy the shared conformance suite in\n * `@xyo-network/event-kit-testing`.\n */\nexport interface WakeQueue {\n /** Durably appends a wake. Resolves only once the entry survives a crash. */\n append: (wake: AdmittedWake) => Promise<void>\n /** Leases the next pending entry, or `undefined` when none remain. */\n claim: () => Promise<LeasedWake | undefined>\n /** Entries waiting to be claimed. Excludes leases already held. */\n pendingCount: () => Promise<number>\n /**\n * Returns every in-flight entry to pending and reports how many moved.\n * Run at startup: entries held by a process that died are otherwise stranded.\n */\n recoverInflight: () => Promise<number>\n}\n\nexport type WakeHandler = (wake: AdmittedWake) => Promise<void> | void\n\n/**\n * Drains the queue serially until empty, acking each wake the handler accepts.\n *\n * A handler that throws releases its lease, so the wake is retried rather than\n * dropped, and the error propagates. Push-style consumption composes over the\n * lease port; the reverse does not.\n */\nexport async function drainQueue(queue: WakeQueue, handler: WakeHandler): Promise<number> {\n let handled = 0\n for (;;) {\n const leased = await queue.claim()\n if (leased === undefined) return handled\n\n try {\n await handler(leased.wake)\n } catch (error) {\n await leased.release()\n throw error\n }\n await leased.ack()\n handled += 1\n }\n}\n"],
|
|
5
|
+
"mappings": ";AAYO,IAAM,0CAA0C;;;ACsCvD,eAAsB,gBAAgB,OAA6D;AACjG,QAAM,gBAAgB,cAAc,MAAM,QAAQ;AAClD,MAAI,CAAC,cAAc,GAAI,QAAO,cAAc;AAC5C,QAAM,EAAE,QAAQ,IAAI;AACpB,QAAM,OAAO,eAAe,MAAM,QAAQ;AAE1C,QAAM,QAAQ,MAAM,oBAAoB,MAAM,OAAO,SAAS,IAAI;AAClE,MAAI,CAAC,MAAM,QAAS,QAAO,MAAM;AAEjC,MAAI,CAAC,yBAAyB,MAAM,YAAY,GAAG;AACjD,WAAO,OAAO,sBAAsB,CAAC,iDAAiD,CAAC;AAAA,EACzF;AAEA,QAAM,gBAAgB,MAAM,UAAU,KAAK;AAC3C,MAAI,CAAC,cAAc,GAAI,QAAO,cAAc;AAC5C,SAAO,MAAM,qBAAqB,MAAM,OAAO,SAAS,cAAc,OAAO,IAAI;AACnF;AASA,eAAe,oBACb,OACA,SACA,MAC6B;AAC7B,MAAI;AACJ,MAAI;AACF,iBAAa,MAAM,MAAM,eAAe,OAAO;AAAA,EACjD,SAAS,OAAO;AACd,WAAO,UAAU,OAAO,qBAAqB,CAAC,aAAa,KAAK,CAAC,CAAC,CAAC;AAAA,EACrE;AAEA,MAAI,CAAC,SAAS,UAAU,KAAK,OAAO,WAAW,SAAS,UAAU;AAChE,WAAO,UAAU,OAAO,qBAAqB,CAAC,8CAA8C,CAAC,CAAC;AAAA,EAChG;AACA,MAAI,WAAW,SAAS,sBAAsB,WAAW,SAAS,qBAAqB;AACrF,WAAO,UAAU,OAAO,WAAW,IAAI,CAAC;AAAA,EAC1C;AACA,MAAI,WAAW,SAAS,aAAa;AACnC,UAAM,iBAAiB,gBAAgB,WAAW,SAAS,OAAO;AAClE,WAAO,UAAU,kBACZ,QAAQ,aAAa,gBAAgB,WAAW,OAAO,GAAG,IAAI,CAAC;AAAA,EACtE;AACA,MAAI,WAAW,SAAS,OAAO;AAC7B,WAAO,UAAU,OAAO,qBAAqB,CAAC,8CAA8C,CAAC,CAAC;AAAA,EAChG;AACA,SAAO,OAAO,OAAO,EAAE,SAAS,KAAK,CAAC;AACxC;AAEA,eAAe,qBACb,OACA,SACA,OACA,MACgC;AAChC,MAAI;AACJ,MAAI;AACF,gBAAY,MAAM,MAAM,iBAAiB;AAAA,MACvC;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAAA,EACH,SAAS,OAAO;AACd,WAAO,OAAO,qBAAqB,CAAC,aAAa,KAAK,CAAC,CAAC;AAAA,EAC1D;AAEA,MAAI,CAAC,SAAS,SAAS,KAAK,OAAO,UAAU,SAAS,UAAU;AAC9D,WAAO,OAAO,qBAAqB,CAAC,yCAAyC,CAAC;AAAA,EAChF;AACA,MAAI,UAAU,SAAS,sBAAsB,UAAU,SAAS,qBAAqB;AACnF,WAAO,OAAO,UAAU,IAAI;AAAA,EAC9B;AACA,MAAI,UAAU,SAAS,eAAe,UAAU,SAAS,YAAY;AACnE,WAAO,OAAO,qBAAqB,CAAC,yCAAyC,CAAC;AAAA,EAChF;AAEA,QAAM,iBAAiB,gBAAgB,UAAU,SAAS,OAAO;AACjE,MAAI,mBAAmB,OAAW,QAAO;AACzC,SAAO,QAAQ,UAAU,MAAM,gBAAgB,UAAU,OAAO,GAAG,IAAI;AACzE;AAEA,SAAS,UAAU,QAAmD;AACpE,SAAO,OAAO,OAAO,EAAE,SAAS,OAAO,OAAO,CAAC;AACjD;AAUA,SAAS,cAAc,UAA8C;AACnE,MAAI,SAAS,YAAY,OAAO,mBAAmB,yCAAyC;AAC1F,WAAO;AAAA,MACL,SAAS,OAAO,qBAAqB,CAAC,sEAAsE,CAAC;AAAA,MAC7G,IAAI;AAAA,IACN;AAAA,EACF;AAEA,SAAO;AAAA,IACL,SAAS,OAAO,OAAO;AAAA,MACrB,UAAU,SAAS;AAAA,MACnB,WAAW,SAAS;AAAA,MACpB,OAAO,SAAS;AAAA,MAChB,WAAW,SAAS;AAAA,MACpB,gBAAgB,SAAS,YAAY;AAAA,MACrC,QAAQ,SAAS;AAAA,IACnB,CAAC;AAAA,IACD,IAAI;AAAA,EACN;AACF;AAUA,eAAe,UACb,OAC8B;AAC9B,QAAM,EAAE,MAAM,IAAI,MAAM;AACxB,MAAI;AACJ,MAAI;AACF,eAAW,MAAM,MAAM,OAAO,mBAAmB;AAAA,MAC/C,YAAY,MAAM;AAAA,MAClB,cAAc,MAAM;AAAA,MACpB,cAAc,MAAM;AAAA,MACpB,WAAW,MAAM,SAAS;AAAA,MAC1B,GAAI,MAAM,YAAY,SAAY,CAAC,IAAI,EAAE,SAAS,MAAM,QAAQ;AAAA,IAClE,CAAC;AAAA,EACH,SAAS,OAAO;AACd,WAAO,EAAE,SAAS,OAAO,qBAAqB,CAAC,aAAa,KAAK,CAAC,CAAC,GAAG,IAAI,MAAM;AAAA,EAClF;AAEA,QAAM,cAAc,kBAAkB,UAAU,MAAM,cAAc,MAAM,iBAAiB;AAC3F,MAAI,gBAAgB,OAAW,QAAO,EAAE,SAAS,aAAa,IAAI,MAAM;AACxE,MAAI,CAAC,SAAS,QAAS,QAAO,EAAE,SAAS,OAAO,eAAe,GAAG,IAAI,MAAM;AAE5E,QAAM,kBAAkB,sBAAsB,SAAS,OAAO,MAAM,UAAU,SAAS,OAAO;AAC9F,MAAI,oBAAoB,OAAW,QAAO,EAAE,SAAS,iBAAiB,IAAI,MAAM;AAEhF,QAAM,QAA6B,OAAO,OAAO;AAAA,IAC/C,SAAS,SAAS;AAAA,IAClB,cAAc,MAAM;AAAA,IACpB,OAAO,sBAAsB,SAAS,KAAK;AAAA,IAC3C,KAAK,MAAM,eAAe,SAAS;AAAA,EACrC,CAAC;AACD,SAAO,EAAE,OAAO,IAAI,KAAK;AAC3B;AAEA,SAAS,kBACP,UACA,cACA,mBACoC;AACpC,MAAI,CAAC,SAAS,QAAQ,KACjB,CAAC,OAAO,OAAO,UAAU,SAAS,KAClC,OAAO,SAAS,YAAY,aAC5B,CAAC,OAAO,OAAO,UAAU,SAAS,GAAG;AACxC,WAAO,OAAO,sBAAsB,CAAC,+CAA+C,CAAC;AAAA,EACvF;AACA,MAAI,CAAC,yBAAyB,SAAS,OAAO,GAAG;AAC/C,WAAO,OAAO,sBAAsB,CAAC,kDAAkD,CAAC;AAAA,EAC1F;AACA,MAAI,SAAS,UAAU,cAAc;AACnC,WAAO,OAAO,sBAAsB,CAAC,mDAAmD,CAAC;AAAA,EAC3F;AAEA,QAAM,MAAM,eAAe,SAAS;AACpC,MAAI,SAAS,iBAAiB,UAAa,SAAS,iBAAiB,cAAc;AACjF,WAAO,OAAO,sBAAsB,CAAC,+DAA+D,CAAC;AAAA,EACvG;AACA,MAAI,SAAS,QAAQ,UAAa,SAAS,QAAQ,KAAK;AACtD,WAAO,OAAO,sBAAsB,CAAC,wDAAwD,CAAC;AAAA,EAChG;AACA,MAAI,MAAM,mBAAmB;AAC3B,WAAO,OAAO,oBAAoB,CAAC,YAAY,GAAG,QAAQ,iBAAiB,EAAE,CAAC;AAAA,EAChF;AACA,SAAO;AACT;AAEA,SAAS,sBACP,UACA,UACA,SACoC;AACpC,MAAI,CAAC,SAAS,QAAQ,EAAG,QAAO,OAAO,sBAAsB,CAAC,yCAAyC,CAAC;AACxG,QAAM,iBAAiB;AAAA,IACrB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACA,MAAI,eAAe,KAAK,WAAS,CAAC,OAAO,OAAO,UAAU,KAAK,CAAC,GAAG;AACjE,WAAO,OAAO,sBAAsB,CAAC,sDAAsD,CAAC;AAAA,EAC9F;AACA,MAAI,OAAO,SAAS,OAAO,YAAY,SAAS,GAAG,WAAW,GAAG;AAC/D,WAAO,OAAO,sBAAsB,CAAC,gDAAgD,CAAC;AAAA,EACxF;AACA,MAAI,CAAC,yBAAyB,SAAS,eAAe,KAAK,SAAS,kBAAkB,SAAS;AAC7F,WAAO,OAAO,sBAAsB,CAAC,mEAAmE,CAAC;AAAA,EAC3G;AACA,MAAI,SAAS,eAAe,SAAS,MAAM,YAAY;AACrD,WAAO,OAAO,sBAAsB,CAAC,2DAA2D,CAAC;AAAA,EACnG;AACA,MAAI,SAAS,WAAW,SAAS,WAAW;AAC1C,WAAO,OAAO,sBAAsB,CAAC,oDAAoD,CAAC;AAAA,EAC5F;AACA,QAAM,mBAAmB,OAAO,OAAO,UAAU,SAAS;AAC1D,QAAM,gBAAgB,OAAO,OAAO,SAAS,OAAO,SAAS;AAC7D,MAAI,SAAS,iBAAiB,SAAS,MAAM,gBACxC,qBAAqB,iBACrB,SAAS,YAAY,SAAS,MAAM,SAAS;AAChD,WAAO,OAAO,sBAAsB,CAAC,yDAAyD,CAAC;AAAA,EACjG;AACA,SAAO;AACT;AAEA,SAAS,gBACP,SACA,SACoC;AACpC,QAAM,iBAAiB;AAAA,IACrB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACA,MAAI,CAAC,SAAS,OAAO,KAChB,eAAe,KAAK,WAAS,CAAC,OAAO,OAAO,SAAS,KAAK,CAAC,KAC3D,OAAO,QAAQ,OAAO,YACtB,QAAQ,GAAG,WAAW,GAAG;AAC5B,WAAO,OAAO,qBAAqB,CAAC,mCAAmC,CAAC;AAAA,EAC1E;AACA,MAAI,QAAQ,aAAa,QAAQ,YAC5B,QAAQ,cAAc,QAAQ,aAC9B,QAAQ,cAAc,QAAQ,aAC9B,QAAQ,WAAW,QAAQ,QAAQ;AACtC,WAAO,OAAO,qBAAqB,CAAC,oDAAoD,CAAC;AAAA,EAC3F;AACA,SAAO;AACT;AAEA,SAAS,sBAAsB,UAAgD;AAC7E,SAAO,OAAO,OAAO;AAAA,IACnB,iBAAiB,SAAS;AAAA,IAC1B,YAAY,SAAS;AAAA,IACrB,cAAc,SAAS;AAAA,IACvB,IAAI,SAAS;AAAA,IACb,GAAI,SAAS,YAAY,SAAY,CAAC,IAAI,EAAE,SAAS,SAAS,QAAQ;AAAA,IACtE,QAAQ,SAAS;AAAA,EACnB,CAAC;AACH;AAEA,SAAS,gBAAgB,SAAqD;AAC5E,SAAO,OAAO,OAAO;AAAA,IACnB,UAAU,QAAQ;AAAA,IAClB,WAAW,QAAQ;AAAA,IACnB,IAAI,QAAQ;AAAA,IACZ,WAAW,QAAQ;AAAA,IACnB,QAAQ,QAAQ;AAAA,EAClB,CAAC;AACH;AAEA,SAAS,eAAe,UAA6C;AACnE,SAAO,OAAO,OAAO;AAAA,IACnB,UAAU,SAAS;AAAA,IACnB,cAAc,SAAS;AAAA,IACvB,OAAO,SAAS;AAAA,IAChB,WAAW,SAAS;AAAA,IACpB,WAAW,SAAS;AAAA,IACpB,KAAK,SAAS;AAAA,IACd,WAAW,SAAS;AAAA,IACpB,GAAI,SAAS,YAAY,SAAY,CAAC,IAAI,EAAE,SAAS,SAAS,QAAQ;AAAA,IACtE,SAAS,SAAS;AAAA,IAClB,QAAQ,SAAS;AAAA,EACnB,CAAC;AACH;AAEA,SAAS,QACP,aACA,SACA,MACwB;AACxB,SAAO,OAAO,OAAO;AAAA,IACnB;AAAA,IAAa,IAAI;AAAA,IAAM;AAAA,IAAS;AAAA,EAClC,CAAC;AACH;AAEA,SAAS,OACP,QACA,SACwB;AACxB,MAAI,YAAY,OAAW,QAAO,OAAO,OAAO,EAAE,IAAI,OAAO,OAAO,CAAC;AACrE,SAAO,OAAO,OAAO;AAAA,IACnB,SAAS,OAAO,OAAO,CAAC,GAAG,OAAO,CAAC;AAAA,IAAG,IAAI;AAAA,IAAO;AAAA,EACnD,CAAC;AACH;AAEA,SAAS,yBAAyB,OAAiC;AACjE,SAAO,OAAO,UAAU,YAAY,OAAO,cAAc,KAAK,KAAK,SAAS;AAC9E;AAEA,SAAS,SAAS,OAAkD;AAClE,SAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAC5E;AAEA,SAAS,aAAa,OAAwB;AAC5C,SAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAC9D;;;AClXA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAuCA,SAAS,gCAAgC,cAAc,GAA8B;AAC1F,MAAI,OAAO;AACX,QAAM,SAAS,oBAAI,IAAiC;AACpD,QAAM,UAAU,oBAAI,IAAkC;AAEtD,WAAS,SAAS,QAAgB,YAA4B;AAC5D,WAAO,GAAG,iBAAiB,MAAM,CAAC,IAAI,UAAU;AAAA,EAClD;AAEA,WAAS,YAAY,OAOZ;AACP,UAAM,SAAS,iBAAiB,MAAM,MAAM;AAC5C,YAAQ,IAAI,MAAM,YAAY,OAAO,OAAO;AAAA,MAC1C,WAAW;AAAA,MACX,gBAAgB,MAAM;AAAA,MACtB,YAAY,MAAM;AAAA,MAClB,QAAQ,OAAO,OAAO,EAAE,GAAG,MAAM,OAAO,CAAC;AAAA,IAC3C,CAAC,CAAC;AAEF,UAAM,MAAM,SAAS,QAAQ,MAAM,UAAU;AAC7C,UAAM,WAAW,OAAO,IAAI,GAAG;AAC/B,WAAO,IAAI,KAAK,OAAO,OAAO,aAAa,SACvC;AAAA,MACE,sBAAsB,MAAM;AAAA,MAC5B,YAAY,MAAM;AAAA,MAClB,gBAAgB,MAAM;AAAA,MACtB,WAAW,MAAM;AAAA,MACjB,YAAY,MAAM;AAAA,MAClB;AAAA,IACF,IAEA,EAAE,GAAG,UAAU,WAAW,KAAK,IAAI,SAAS,WAAW,MAAM,KAAK,EAAE,CAAC,CAAC;AAC1E,QAAI,MAAM,QAAQ,KAAM,QAAO,MAAM;AAAA,EACvC;AAEA,SAAO;AAAA,IACL,MAAM,OAAwB;AAC5B,aAAO;AAAA,IACT;AAAA,IAEA,QAAQ,OAAqB;AAC3B,aAAO;AAAA,IACT;AAAA,IAEA,MAAM,OAAO,QAAQ,OAAgD;AACnE,YAAM,mBAAmB,iBAAiB,MAAM;AAChD,YAAM,UAAiC,CAAC;AACxC,iBAAW,UAAU,OAAO,OAAO,GAAG;AACpC,YAAI,OAAO,WAAW,iBAAkB;AACxC,YAAI,OAAO,eAAe,UAAa,OAAO,eAAe,MAAM,WAAY;AAC/E,YAAI,OAAO,+BAA+B,UACrC,CAAC,OAAO,qBAAqB,WAAW,MAAM,0BAA0B,GAAG;AAC9E;AAAA,QACF;AACA,gBAAQ,KAAK,MAAM;AAAA,MACrB;AACA,aAAO;AAAA,IACT;AAAA,IAEA,MAAM,OAAO,YAAuD;AAClE,aAAO,QAAQ,IAAI,UAAU;AAAA,IAC/B;AAAA,IAEA,MAAM,OAAa;AACjB,UAAI,MAAM,MAAM,WAAW,uBAAuB;AAChD,cAAM,IAAI,MAAM,YAAY,qBAAqB,EAAE;AAAA,MACrD;AACA,YAAM,EAAE,QAAQ,SAAS,GAAG,OAAO,IAAI,MAAM;AAC7C,kBAAY;AAAA,QACV,OAAO,MAAM;AAAA,QACb,gBAAgB;AAAA,QAChB,WAAW,MAAM;AAAA,QACjB,YAAY,MAAM;AAAA,QAClB,QAAQ;AAAA,UACN,GAAG;AAAA,UACH,aAAa,OAAO,OAAO,CAAC,GAAG,OAAO,WAAW,CAAC;AAAA,QACpD;AAAA,QACA,QAAQ,MAAM;AAAA,MAChB,CAAC;AAAA,IACH;AAAA,IAEA,OAAO,OAAa;AAClB,YAAM,aAAkD,EAAE,OAAO,MAAM,gBAAgB;AACvF,kBAAY;AAAA,QACV,OAAO,MAAM;AAAA,QACb,gBAAgB;AAAA,QAChB,WAAW,MAAM;AAAA,QACjB,YAAY,MAAM;AAAA,QAClB,QAAQ;AAAA,QACR,QAAQ,MAAM;AAAA,MAChB,CAAC;AAAA,IACH;AAAA,EACF;AACF;;;AC1FO,SAAS,sBAAsB,UAAkC,CAAC,GAAoB;AAC3F,QAAM,eAAe,oBAAI,IAA0B;AACnD,QAAM,cAAc,oBAAI,IAA4B;AACpD,QAAM,SAAyB,CAAC;AAChC,MAAI,kBAAkB;AACtB,MAAI,OAAyB,QAAQ,QAAQ;AAO7C,WAAS,UAAa,MAAoC;AACxD,UAAM,MAAM,KAAK,KAAK,MAAM,IAAI;AAEhC,WAAO,QAAQ,WAAW,CAAC,GAAG,CAAC;AAC/B,WAAO;AAAA,EACT;AAEA,WAAS,qBAA2B;AAClC,UAAM,EAAE,WAAW,IAAI;AACvB,QAAI,eAAe,OAAW;AAC9B,UAAM,MAAM,WAAW;AACvB,eAAW,CAAC,KAAK,OAAO,KAAK,cAAc;AACzC,UAAI,QAAQ,kBAAkB,IAAK,cAAa,OAAO,GAAG;AAAA,IAC5D;AAAA,EACF;AAGA,WAAS,cAAc,SAA+D;AACpF,UAAM,eAAe,aAAa,IAAI,SAAS,OAAO,CAAC;AACvD,QAAI,iBAAiB,QAAW;AAC9B,aAAO,aAAa,cAAc,QAAQ,aAAa,aAAa,WAAW,QAAQ,SACnF,EAAE,MAAM,aAAa,SAAS,aAAa,QAAQ,IACnD,EAAE,MAAM,mBAAmB;AAAA,IACjC;AAEA,UAAM,cAAc,YAAY,IAAI,QAAQ,OAAO,CAAC;AACpD,QAAI,gBAAgB,OAAW,QAAO;AACtC,QAAI,YAAY,cAAc,QAAQ,UAAW,QAAO,EAAE,MAAM,oBAAoB;AACpF,iBAAa,IAAI,SAAS,OAAO,GAAG,EAAE,GAAG,aAAa,gBAAgB,QAAQ,eAAe,CAAC;AAC9F,WAAO,EAAE,MAAM,aAAa,SAAS,YAAY,QAAQ;AAAA,EAC3D;AAEA,SAAO;AAAA,IACL,IAAI,SAAkC;AACpC,aAAO;AAAA,IACT;AAAA,IAEA,IAAI,mBAA2B;AAC7B,aAAO,aAAa;AAAA,IACtB;AAAA,IAEA,IAAI,kBAA0B;AAC5B,aAAO,YAAY;AAAA,IACrB;AAAA,IAEA,MAAM,eAAe,SAA+D;AAClF,aAAO,MAAM,UAAU,YAAY;AACjC,2BAAmB;AACnB,eAAO,cAAc,OAAO,KAAK,EAAE,MAAM,MAAM;AAAA,MACjD,CAAC;AAAA,IACH;AAAA,IAEA,MAAM,iBAAiB,EAAE,SAAS,KAAK,GAGT;AAC5B,aAAO,MAAM,UAAU,YAAY;AACjC,2BAAmB;AACnB,cAAM,WAAW,cAAc,OAAO;AACtC,YAAI,aAAa,OAAW,QAAO;AAEnC,cAAM,UAAgC,OAAO,OAAO;AAAA,UAClD,UAAU,QAAQ;AAAA,UAClB,WAAW,QAAQ;AAAA,UACnB,IAAI,WAAW,mBAAmB,CAAC;AAAA,UACnC,WAAW,QAAQ;AAAA,UACnB,QAAQ,QAAQ;AAAA,QAClB,CAAC;AAID,cAAM,QAAQ,UAAU,IAAI;AAC5B,eAAO,KAAK,IAAI;AAEhB,cAAM,UAA0B;AAAA,UAC9B,WAAW,QAAQ;AAAA,UACnB;AAAA,UACA,QAAQ,QAAQ;AAAA,QAClB;AACA,qBAAa,IAAI,SAAS,OAAO,GAAG,EAAE,GAAG,SAAS,gBAAgB,QAAQ,eAAe,CAAC;AAC1F,oBAAY,IAAI,QAAQ,OAAO,GAAG,OAAO;AACzC,eAAO,EAAE,MAAM,YAAY,QAAQ;AAAA,MACrC,CAAC;AAAA,IACH;AAAA,EACF;AACF;AAGA,SAAS,SAAS,SAAuC;AACvD,SAAO,KAAK,UAAU,CAAC,QAAQ,UAAU,QAAQ,WAAW,QAAQ,KAAK,CAAC;AAC5E;AAEA,SAAS,QAAQ,SAAuC;AACtD,SAAO,KAAK,UAAU,CAAC,QAAQ,UAAU,QAAQ,WAAW,QAAQ,MAAM,CAAC;AAC7E;;;AC3IO,SAAS,wBAAyC;AACvD,QAAM,UAAmB,CAAC;AAC1B,QAAM,WAAW,oBAAI,IAAmB;AACxC,MAAI,WAAW;AAEf,SAAO;AAAA,IACL,MAAM,OAAO,MAAmC;AAC9C,cAAQ,KAAK,EAAE,UAAU,YAAY,GAAG,KAAK,CAAC;AAAA,IAChD;AAAA,IAEA,MAAM,QAAyC;AAC7C,YAAM,QAAQ,QAAQ,MAAM;AAC5B,UAAI,UAAU,OAAW,QAAO;AAChC,eAAS,IAAI,MAAM,UAAU,KAAK;AAElC,aAAO;AAAA,QACL,MAAM,MAAM;AAAA,QACZ,MAAM,MAAqB;AACzB,mBAAS,OAAO,MAAM,QAAQ;AAAA,QAChC;AAAA,QACA,MAAM,UAAyB;AAC7B,cAAI,CAAC,SAAS,OAAO,MAAM,QAAQ,EAAG;AAEtC,kBAAQ,KAAK,KAAK;AAClB,kBAAQ,KAAK,CAAC,MAAM,UAAU,KAAK,WAAW,MAAM,QAAQ;AAAA,QAC9D;AAAA,MACF;AAAA,IACF;AAAA,IAEA,MAAM,gBAAiC;AACrC,aAAO,SAAS;AAAA,IAClB;AAAA,IAEA,MAAM,eAAgC;AACpC,aAAO,QAAQ;AAAA,IACjB;AAAA,IAEA,MAAM,kBAAmC;AACvC,YAAM,YAAY,SAAS;AAC3B,iBAAW,SAAS,SAAS,OAAO,EAAG,SAAQ,KAAK,KAAK;AACzD,eAAS,MAAM;AACf,cAAQ,KAAK,CAAC,MAAM,UAAU,KAAK,WAAW,MAAM,QAAQ;AAC5D,aAAO;AAAA,IACT;AAAA,EACF;AACF;;;AChEA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,yBAAAA;AAAA,EACA,6BAAAC;AAAA,OACK;AA8BA,SAAS,wCACd,SACqB;AACrB,QAAM,EAAE,OAAO,IAAI;AAEnB,SAAO,OAAO,OAAO;AAAA,IACnB,MAAM,mBAAmB,SAAiF;AACxG,yBAAmB,OAAO;AAE1B,YAAM,UAAU,MAAM,SAAS,MAAM;AACrC,UAAI,UAAU,QAAQ,cAAc;AAClC,cAAM,IAAI,MAAM,wBAAwB,OAAO,8BAA8B,QAAQ,YAAY,EAAE;AAAA,MACrG;AAEA,YAAM,SAAS,MAAM,OAAO,OAAO,QAAQ,YAAY,EAAE,4BAA4BD,uBAAsB,CAAC;AAC5G,YAAM,qBAAqB,MAAM,gBAAgB,QAAQ,QAAQ,YAAY,OAAO;AAEpF,UAAI;AACJ,iBAAW,SAAS,QAAQ;AAC1B,mBAAW,MAAM,gBAAgB,QAAQ,OAAO,SAAS,SAAS,kBAAkB;AACpF,YAAI,aAAa,OAAW;AAAA,MAC9B;AAEA,YAAM,mBAAmB,MAAM,SAAS,MAAM;AAC9C,UAAI,qBAAqB,SAAS;AAChC,cAAM,IAAI,MAAM,sDAAsD,OAAO,OAAO,gBAAgB,GAAG;AAAA,MACzG;AAEA,YAAM,MAAM,QAAQ,eAAe;AACnC,UAAI,aAAa,QAAW;AAC1B,eAAO,OAAO,OAAO;AAAA,UACnB;AAAA,UACA,SAAS;AAAA,UACT,cAAc,QAAQ;AAAA,UACtB;AAAA,QACF,CAAC;AAAA,MACH;AACA,aAAO,OAAO,OAAO;AAAA,QACnB;AAAA,QACA,SAAS;AAAA,QACT,cAAc,QAAQ;AAAA,QACtB,OAAO;AAAA,QACP;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF,CAAC;AACH;AAOA,eAAe,gBACb,QACA,YACA,SAC8B;AAC9B,QAAM,UAAU,oBAAI,IAAY;AAChC,QAAM,SAAS,MAAM,OAAO,OAAO,YAAY,EAAE,4BAA4BC,2BAA0B,CAAC;AAExG,aAAW,SAAS,QAAQ;AAC1B,QAAI,CAAC,YAAY,OAAO,YAAYA,4BAA2B,OAAO,EAAG;AACzE,UAAM,SAAS,MAAM,OAAO,OAAO,MAAM,UAAU;AACnD,QAAI,QAAQ,cAAc,WAAY;AACtC,QAAI,OAAO,mBAAmBA,8BAA6B,OAAO,eAAe,MAAM,WAAY;AACnG,QAAI,CAACC,UAAS,OAAO,MAAM,KAAK,OAAO,OAAO,OAAO,QAAQ,QAAQ,EAAG;AACxE,UAAM,aAAa,sBAAsB,EAAE,GAAG,OAAO,QAAQ,QAAQ,OAAO,eAAe,CAAC;AAC5F,QAAI,eAAe,OAAW,SAAQ,IAAI,WAAW,KAAK;AAAA,EAC5D;AACA,SAAO;AACT;AAEA,eAAe,gBACb,QACA,OACA,SACA,SACA,oBACwC;AACxC,MAAI,CAAC,YAAY,OAAO,QAAQ,YAAYF,wBAAuB,OAAO,EAAG,QAAO;AACpF,MAAI,mBAAmB,IAAI,MAAM,UAAU,EAAG,QAAO;AAErD,QAAM,SAAS,MAAM,OAAO,OAAO,MAAM,UAAU;AACnD,QAAM,QAAQ,sBAAsB,QAAQ,MAAM,UAAU;AAC5D,MAAI,UAAU,OAAW,QAAO;AAChC,MAAI,MAAM,cAAc,QAAQ,UAAW,QAAO;AAClD,MAAI,MAAM,iBAAiB,QAAQ,aAAc,QAAO;AACxD,MAAI,MAAM,YAAY,QAAQ,QAAS,QAAO;AAC9C,MAAI,CAAC,MAAM,YAAY,SAAS,SAAS,EAAG,QAAO;AAEnD,SAAO,OAAO,OAAO;AAAA,IACnB,iBAAiB,MAAM;AAAA,IACvB,YAAY,QAAQ;AAAA,IACpB,cAAc,MAAM;AAAA,IACpB,IAAI,MAAM;AAAA,IACV,GAAI,MAAM,YAAY,SAAY,CAAC,IAAI,EAAE,SAAS,MAAM,QAAQ;AAAA,IAChE,QAAQ,MAAM;AAAA,EAChB,CAAC;AACH;AAEA,SAAS,YACP,OACA,YACA,sBACA,SACS;AACT,MAAI,MAAM,WAAW,WAAY,QAAO;AACxC,MAAI,MAAM,yBAAyB,qBAAsB,QAAO;AAChE,MAAI,CAACG,0BAAyB,MAAM,UAAU,KAAK,MAAM,aAAa,QAAS,QAAO;AACtF,MAAI,CAACA,0BAAyB,MAAM,SAAS,KAAK,MAAM,YAAY,MAAM,WAAY,QAAO;AAC7F,MAAI,CAAC,QAAQ,UAAU,MAAM,cAAc,EAAE,QAAS,QAAO;AAC7D,SAAO,QAAQ,UAAU,MAAM,UAAU,EAAE;AAC7C;AAEA,SAAS,sBACP,QACA,oBAC6B;AAC7B,MAAI,QAAQ,cAAc,WAAY,QAAO;AAC7C,MAAI,OAAO,mBAAmBH,0BAAyB,OAAO,eAAe,mBAAoB,QAAO;AACxG,MAAI,CAACE,UAAS,OAAO,MAAM,KAAK,OAAO,OAAO,OAAO,QAAQ,QAAQ,EAAG,QAAO;AAC/E,SAAO,kBAAkB;AAAA,IACvB,GAAG,OAAO;AAAA,IACV,QAAQ,OAAO;AAAA,EACjB,CAAC;AACH;AAEA,SAAS,mBAAmB,SAA8C;AACxE,MAAI,CAAC,qBAAqB,UAAU,QAAQ,UAAU,EAAE,SAAS;AAC/D,UAAM,IAAI,UAAU,+CAA+C;AAAA,EACrE;AACA,MAAI,CAAC,qBAAqB,UAAU,QAAQ,SAAS,EAAE,SAAS;AAC9D,UAAM,IAAI,UAAU,8CAA8C;AAAA,EACpE;AACA,MAAI,CAAC,gBAAgB,UAAU,QAAQ,YAAY,EAAE,SAAS;AAC5D,UAAM,IAAI,UAAU,qDAAqD;AAAA,EAC3E;AACA,MAAI,QAAQ,YAAY,WAAc,QAAQ,QAAQ,WAAW,KAAK,QAAQ,QAAQ,SAAS,MAAM;AACnG,UAAM,IAAI,UAAU,gEAAgE;AAAA,EACtF;AACA,MAAI,CAACC,0BAAyB,QAAQ,YAAY,GAAG;AACnD,UAAM,IAAI,WAAW,uDAAuD;AAAA,EAC9E;AACF;AAEA,eAAe,SAAS,QAAuD;AAC7E,QAAM,OAAO,MAAM,OAAO,KAAK;AAC/B,MAAI,CAACA,0BAAyB,IAAI,GAAG;AACnC,UAAM,IAAI,WAAW,yDAAyD;AAAA,EAChF;AACA,SAAO;AACT;AAEA,SAASA,0BAAyB,OAAiC;AACjE,SAAO,OAAO,UAAU,YAAY,OAAO,cAAc,KAAK,KAAK,SAAS;AAC9E;AAEA,SAASD,UAAS,OAA4D;AAC5E,SAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAC5E;;;AC5LA;AAAA,EACE,mBAAAE;AAAA,EACA,wBAAAC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAEP,SAAS,SAAS,sBAAsB;AAGjC,IAAM,qCAAqC;AAG3C,IAAM,mCAAmC;AA8FhD,eAAsB,kBAAkB,OAAiE;AACvG,QAAM,EAAE,WAAW,IAAI;AACvB,QAAM,QAAQ,cAAc,MAAM,KAAK;AACvC,QAAM,uBAAuB,sBAAsB,OAAO,UAAU;AACpE,MAAI,yBAAyB,OAAW,QAAO;AAE/C,QAAM,SAAS,gBAAgB,UAAU,MAAM,IAAI;AACnD,MAAI,CAAC,OAAO,SAAS;AACnB,UAAM,UAAU,OAAO,MAAM,OAAO,IAAI,WAAS,GAAG,MAAM,KAAK,KAAK,GAAG,KAAK,QAAQ,KAAK,MAAM,OAAO,EAAE;AACxG,QAAI,qBAAqB,MAAM,IAAI,EAAG,QAAOC,QAAO,iBAAiB,OAAO;AAC5E,QAAIC,UAAS,MAAM,IAAI,KAClB,OAAO,OAAO,MAAM,MAAM,QAAQ,KAClC,OAAO,MAAM,OAAO,KAAK,WAAS,MAAM,KAAK,CAAC,MAAM,QAAQ,GAAG;AAClE,aAAOD,QAAO,mBAAmB,OAAO;AAAA,IAC1C;AACA,WAAOA;AAAA,MACL;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAEA,QAAM,QAAQ,OAAO;AACrB,MAAI,CAAC,aAAa,KAAK,MAAM,MAAM,EAAG,QAAOA,QAAO,iBAAiB;AACrE,MAAI,CAAC,oBAAoB,KAAK,EAAG,QAAOA,QAAO,mBAAmB,CAAC,uDAAuD,CAAC;AAC3H,MAAI,MAAM,iBAAiB,MAAM,gBAAgB,MAAM,YAAY,MAAM,SAAS;AAChF,WAAOA,QAAO,uBAAuB;AAAA,EACvC;AACA,MAAI,MAAM,YAAY,MAAM,QAAS,QAAOA,QAAO,eAAe;AAElE,MAAI,MAAM,UAAU,MAAM,aAAa,MAAM,kBAAkB;AAC7D,WAAOA,QAAO,mBAAmB,CAAC,oBAAoB,MAAM,gBAAgB,EAAE,CAAC;AAAA,EACjF;AAEA,QAAM,YAAY,MAAM,iBAAiB,MAAM,KAAK,MAAM,UAAU,UAAU;AAC9E,MAAI,CAAC,UAAU,GAAI,QAAO;AAE1B,MAAI;AACJ,MAAI;AACF,gBAAY,MAAM,eAAe,SAAS,KAAK;AAAA,EACjD,SAAS,OAAO;AACd,WAAOA,QAAO,qBAAqB,CAACE,cAAa,KAAK,CAAC,CAAC;AAAA,EAC1D;AACA,MAAI,cAAc,UAAU,IAAI,UAAW,QAAOF,QAAO,qBAAqB;AAE9E,QAAM,cAAsC,OAAO,OAAO,EAAE,GAAG,MAAM,CAAC;AACtE,QAAM,WAAgC,OAAO,OAAO;AAAA,IAClD,UAAU,MAAM;AAAA,IAChB,cAAc,MAAM;AAAA,IACpB,OAAO;AAAA,IACP;AAAA,IACA,WAAW,UAAU,IAAI;AAAA,IACzB,WAAW,MAAM;AAAA,IACjB,UAAU,MAAM;AAAA,IAChB,OAAO,UAAU,IAAI;AAAA,IACrB,WAAW,UAAU,IAAI;AAAA,IACzB,GAAI,MAAM,YAAY,SAAY,CAAC,IAAI,EAAE,SAAS,MAAM,QAAQ;AAAA,IAChE;AAAA,IACA,SAAS,MAAM;AAAA,IACf,eAAe,UAAU,IAAI;AAAA,IAC7B,QAAQ,MAAM;AAAA,EAChB,CAAC;AACD,SAAO,OAAO,OAAO,EAAE,IAAI,MAAM,SAAS,CAAC;AAC7C;AAEA,SAAS,sBAAsB,OAA2B,YAA0D;AAClH,MAAI,CAAC,mBAAmB,UAAU,MAAM,QAAQ,EAAE,SAAS;AACzD,WAAOA,QAAO,yBAAyB,CAAC,4BAA4B,CAAC;AAAA,EACvE;AACA,MAAI,CAACF,iBAAgB,UAAU,MAAM,YAAY,EAAE,SAAS;AAC1D,WAAOE,QAAO,yBAAyB,CAAC,+CAA+C,CAAC;AAAA,EAC1F;AACA,MAAI,MAAM,YAAY,WAAc,MAAM,QAAQ,WAAW,KAAK,MAAM,QAAQ,SAAS,MAAM;AAC7F,WAAOA,QAAO,yBAAyB,CAAC,0DAA0D,CAAC;AAAA,EACrG;AACA,MAAI,CAACD,sBAAqB,UAAU,MAAM,UAAU,EAAE,SAAS;AAC7D,WAAOC,QAAO,yBAAyB,CAAC,oEAAoE,CAAC;AAAA,EAC/G;AACA,MAAI,CAACG,0BAAyB,UAAU,GAAG;AACzC,WAAOH,QAAO,yBAAyB,CAAC,+CAA+C,CAAC;AAAA,EAC1F;AACA,MAAI,CAAC,OAAO,cAAc,MAAM,gBAAgB,KAAK,MAAM,mBAAmB,GAAG;AAC/E,WAAOA,QAAO,yBAAyB,CAAC,kDAAkD,CAAC;AAAA,EAC7F;AACA,MAAI,CAACG,0BAAyB,MAAM,iBAAiB,GAAG;AACtD,WAAOH,QAAO,yBAAyB,CAAC,sDAAsD,CAAC;AAAA,EACjG;AACA,SAAO;AACT;AAEA,eAAe,iBAAiB,OAAe,UAAkB,YAA+C;AAC9G,MAAI;AACJ,MAAI;AACF,eAAW,MAAM,QAAQ,UAAU,OAAO,EAAE,UAAU,KAAK,WAAW,CAAC;AAAA,EACzE,SAAS,OAAO;AACd,WAAOA,QAAO,iBAAiB,CAACE,cAAa,KAAK,CAAC,CAAC;AAAA,EACtD;AAEA,MAAI,CAAC,SAAS,IAAI;AAChB,QAAI,OAAO,OAAO,SAAS,WAAW,CAAC,GAAG,KAAK,EAAG,QAAOF,QAAO,qBAAqB;AACrF,WAAOA,QAAO,sBAAsB,SAAS,OAAO,GAAG,SAAS,OAAO;AAAA,EACzE;AAEA,QAAM,aAAa,mBAAmB,SAAS,QAAQ,SAAS,SAAS,QAAQ;AACjF,MAAI,CAAC,WAAW,GAAI,QAAO;AAE3B,QAAM,EAAE,QAAQ,cAAc,SAAS,cAAc,IAAI;AACzD,MAAI,aAAa,QAAQ,cAAc,IAAK,QAAOA,QAAO,sBAAsB;AAChF,MAAI,cAAc,OAAO,WAAY,QAAOA,QAAO,aAAa;AAChE,MAAI,cAAc,MAAM,cAAc,MAAM,mCAAoC,QAAOA,QAAO,sBAAsB;AACpH,MAAI,cAAc,MAAM,aAAa,iCAAkC,QAAOA,QAAO,gBAAgB;AAErG,QAAM,MAA0B,OAAO,OAAO;AAAA,IAC5C,WAAW,cAAc;AAAA,IACzB,WAAW,cAAc;AAAA,IACzB,UAAU,cAAc;AAAA,IACxB,OAAO,cAAc;AAAA,IACrB,WAAW,cAAc;AAAA,EAC3B,CAAC;AACD,SAAO,OAAO,OAAO,EAAE,KAAK,IAAI,KAAK,CAAC;AACxC;AAEA,SAAS,mBAAmB,QAAmB,SAAqB,UAAuC;AACzG,QAAM,eAAe,iBAAiB,UAAU,MAAM;AACtD,MAAI,CAAC,aAAa,SAAS;AACzB,QAAI,CAACD,sBAAqB,UAAU,OAAO,GAAG,EAAE,QAAS,QAAOC,QAAO,sBAAsB;AAC7F,WAAOA,QAAO,sBAAsB,WAAW,aAAa,MAAM,MAAM,CAAC;AAAA,EAC3E;AACA,MAAI,OAAO,OAAO,SAAS,KAAK,EAAG,QAAOA,QAAO,qBAAqB;AACtE,MAAI,CAACD,sBAAqB,UAAU,QAAQ,GAAG,EAAE,QAAS,QAAOC,QAAO,sBAAsB;AAC9F,MAAI,QAAQ,WAAW,cAAe,QAAOA,QAAO,qBAAqB;AACzE,MAAI,QAAQ,QAAQ,SAAU,QAAOA,QAAO,uBAAuB;AACnE,MAAI,CAACG,0BAAyB,QAAQ,GAAG,KAAK,CAACA,0BAAyB,QAAQ,GAAG,KAAK,QAAQ,OAAO,QAAQ,KAAK;AAClH,WAAOH,QAAO,sBAAsB;AAAA,EACtC;AAEA,QAAM,gBAAgB,kBAAkB,UAAU,OAAO;AACzD,MAAI,CAAC,cAAc,QAAS,QAAOA,QAAO,sBAAsB,WAAW,cAAc,MAAM,MAAM,CAAC;AACtG,SAAO,OAAO,OAAO;AAAA,IACnB,QAAQ,aAAa;AAAA,IACrB,IAAI;AAAA,IACJ,SAAS,cAAc;AAAA,EACzB,CAAC;AACH;AAEA,SAAS,sBAAsB,SAA8D;AAC3F,MAAI,QAAQ,KAAK,YAAU,OAAO,WAAW,oBAAoB,CAAC,EAAG,QAAO;AAC5E,MAAI,QAAQ,KAAK,YAAU,OAAO,WAAW,UAAU,CAAC,EAAG,QAAO;AAClE,MAAI,QAAQ,KAAK,YAAU,OAAO,WAAW,kBAAkB,KAAK,OAAO,WAAW,kBAAkB,CAAC,GAAG;AAC1G,WAAO;AAAA,EACT;AACA,MAAI,QAAQ,KAAK,YACf,OAAO,WAAW,qBAAqB,KACpC,OAAO,WAAW,oCAAoC,KACtD,WAAW,uCACf,GAAG;AACF,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAEA,SAAS,oBAAoB,OAA8B;AACzD,SAAOG,0BAAyB,MAAM,SAAS,KAC1CA,0BAAyB,MAAM,OAAO,KACtCA,0BAAyB,MAAM,QAAQ;AAC9C;AAEA,SAAS,qBAAqB,OAAyB;AACrD,MAAI,CAACF,UAAS,KAAK,EAAG,QAAO;AAC7B,QAAM,EAAE,WAAW,QAAQ,IAAI;AAC/B,SAAO,OAAO,cAAc,YACvB,OAAO,YAAY,YACnBE,0BAAyB,SAAS,KAClCA,0BAAyB,OAAO,KAChC,YAAY;AACnB;AAEA,SAASA,0BAAyB,OAAwB;AACxD,SAAO,OAAO,cAAc,KAAK,KAAK,SAAS;AACjD;AAEA,SAASF,UAAS,OAAkD;AAClE,SAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAC5E;AAEA,SAAS,cAAc,OAA+C;AACpE,SAAO,OAAO,OAAO;AAAA,IACnB,UAAU,MAAM;AAAA,IAChB,YAAY,MAAM;AAAA,IAClB,cAAc,MAAM;AAAA,IACpB,kBAAkB,MAAM;AAAA,IACxB,mBAAmB,MAAM;AAAA,IACzB,GAAI,MAAM,YAAY,SAAY,CAAC,IAAI,EAAE,SAAS,MAAM,QAAQ;AAAA,EAClE,CAAC;AACH;AAEA,SAAS,WAAW,QAA2G;AAC7H,SAAO,OAAO,IAAI,CAAC,UAAU;AAC3B,UAAM,OAAO,MAAM,KAAK,IAAI,MAAM,EAAE,KAAK,GAAG,KAAK;AACjD,WAAO,GAAG,IAAI,KAAK,MAAM,OAAO;AAAA,EAClC,CAAC;AACH;AAEA,SAASD,QACP,QACA,SAC0B;AAC1B,MAAI,YAAY,OAAW,QAAO,OAAO,OAAO,EAAE,IAAI,OAAO,OAAO,CAAC;AACrE,SAAO,OAAO,OAAO;AAAA,IACnB,SAAS,OAAO,OAAO,CAAC,GAAG,OAAO,CAAC;AAAA,IACnC,IAAI;AAAA,IACJ;AAAA,EACF,CAAC;AACH;AAEA,SAASE,cAAa,OAAwB;AAC5C,SAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAC9D;;;AC/RA,eAAsB,WAAW,OAAkB,SAAuC;AACxF,MAAI,UAAU;AACd,aAAS;AACP,UAAM,SAAS,MAAM,MAAM,MAAM;AACjC,QAAI,WAAW,OAAW,QAAO;AAEjC,QAAI;AACF,YAAM,QAAQ,OAAO,IAAI;AAAA,IAC3B,SAAS,OAAO;AACd,YAAM,OAAO,QAAQ;AACrB,YAAM;AAAA,IACR;AACA,UAAM,OAAO,IAAI;AACjB,eAAW;AAAA,EACb;AACF;",
|
|
6
|
+
"names": ["WakeGrantObjectSchema", "WakeGrantRevocationSchema", "isRecord", "isNonnegativeSafeInteger", "DeploymentIdZod", "NormalizedAddressZod", "reject", "isRecord", "errorMessage", "isNonnegativeSafeInteger"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { WakeGrantObject } from '@xyo-network/event-kit-schemas';
|
|
2
|
+
import type { StatementGraphGrantReadModel } from './statementGraphPorts.ts';
|
|
3
|
+
export interface MemoryStatementGrantGraph extends StatementGraphGrantReadModel {
|
|
4
|
+
/**
|
|
5
|
+
* Claim a grant object. Statement Graph v2 is append-only, so a repeat claim
|
|
6
|
+
* is redundant: it advances `lastBlock` and leaves `firstBlock` frozen.
|
|
7
|
+
*/
|
|
8
|
+
claim: (input: {
|
|
9
|
+
block: number;
|
|
10
|
+
/** Claim event hash; must be 64 lowercase hex. */
|
|
11
|
+
eventHash: string;
|
|
12
|
+
grant: WakeGrantObject;
|
|
13
|
+
objectHash: string;
|
|
14
|
+
source: string;
|
|
15
|
+
}) => void;
|
|
16
|
+
/**
|
|
17
|
+
* Claim a revocation object negating `grant`. There is no revoke verb in v2 —
|
|
18
|
+
* negation is another claim, and Event Kit reads it as the disabling signal.
|
|
19
|
+
*/
|
|
20
|
+
revoke: (input: {
|
|
21
|
+
block: number;
|
|
22
|
+
eventHash: string;
|
|
23
|
+
grantObjectHash: string;
|
|
24
|
+
objectHash: string;
|
|
25
|
+
source: string;
|
|
26
|
+
}) => void;
|
|
27
|
+
setHead: (block: number) => void;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* In-memory Statement Graph v2 stand-in for grant/negation tests.
|
|
31
|
+
* Not a full fold — enough to exercise the Event Kit allowlist adapter.
|
|
32
|
+
*/
|
|
33
|
+
export declare function createMemoryStatementGrantGraph(initialHead?: number): MemoryStatementGrantGraph;
|
|
34
|
+
//# sourceMappingURL=memoryStatementGrantGraph.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memoryStatementGrantGraph.d.ts","sourceRoot":"","sources":["../../src/memoryStatementGrantGraph.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAuB,MAAM,gCAAgC,CAAA;AAO1F,OAAO,KAAK,EAGV,4BAA4B,EAC7B,MAAM,0BAA0B,CAAA;AAEjC,MAAM,WAAW,yBAA0B,SAAQ,4BAA4B;IAC7E;;;OAGG;IACH,KAAK,EAAE,CAAC,KAAK,EAAE;QACb,KAAK,EAAE,MAAM,CAAA;QACb,kDAAkD;QAClD,SAAS,EAAE,MAAM,CAAA;QACjB,KAAK,EAAE,eAAe,CAAA;QACtB,UAAU,EAAE,MAAM,CAAA;QAClB,MAAM,EAAE,MAAM,CAAA;KACf,KAAK,IAAI,CAAA;IACV;;;OAGG;IACH,MAAM,EAAE,CAAC,KAAK,EAAE;QACd,KAAK,EAAE,MAAM,CAAA;QACb,SAAS,EAAE,MAAM,CAAA;QACjB,eAAe,EAAE,MAAM,CAAA;QACvB,UAAU,EAAE,MAAM,CAAA;QAClB,MAAM,EAAE,MAAM,CAAA;KACf,KAAK,IAAI,CAAA;IACV,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;CACjC;AAED;;;GAGG;AACH,wBAAgB,+BAA+B,CAAC,WAAW,SAAI,GAAG,yBAAyB,CAmG1F"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { AtomicWakeInbox } from './admissionTypes.ts';
|
|
2
|
+
import type { AdmittedWake } from './types.ts';
|
|
3
|
+
export interface MemoryWakeInboxOptions {
|
|
4
|
+
/**
|
|
5
|
+
* Durable-sink stand-in invoked inside the atomic commit. A throw leaves both
|
|
6
|
+
* identities unconsumed, so the publisher may retry the same `wakeId` with a
|
|
7
|
+
* fresh `jti` instead of losing the wake to a burned replay key.
|
|
8
|
+
*/
|
|
9
|
+
readonly enqueue?: (wake: AdmittedWake) => Promise<void> | void;
|
|
10
|
+
/** Trusted clock in Unix seconds, used to drop expired token records. */
|
|
11
|
+
readonly nowSeconds?: () => number;
|
|
12
|
+
}
|
|
13
|
+
export interface MemoryWakeInbox extends AtomicWakeInbox {
|
|
14
|
+
/** Wakes handed to `enqueue`, in commit order. */
|
|
15
|
+
readonly queued: readonly AdmittedWake[];
|
|
16
|
+
/** Live `(aud, iss, jti)` replay records. */
|
|
17
|
+
readonly tokenRecordCount: number;
|
|
18
|
+
/** Live `(aud, iss, wakeId)` logical records. */
|
|
19
|
+
readonly wakeRecordCount: number;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Single-process linearizable `AtomicWakeInbox` for structural tests and local
|
|
23
|
+
* rehearsal.
|
|
24
|
+
*
|
|
25
|
+
* Writes are ordered so a failing sink cannot consume `jti` or `wakeId` without
|
|
26
|
+
* a recoverable receipt. It is **not** durable: process death between enqueue
|
|
27
|
+
* and record commit redelivers the wake, and no state survives restart. Gate 5
|
|
28
|
+
* requires a durable adapter; this is local evidence only.
|
|
29
|
+
*/
|
|
30
|
+
export declare function createMemoryWakeInbox(options?: MemoryWakeInboxOptions): MemoryWakeInbox;
|
|
31
|
+
//# sourceMappingURL=memoryWakeInbox.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memoryWakeInbox.d.ts","sourceRoot":"","sources":["../../src/memoryWakeInbox.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,eAAe,EAKhB,MAAM,qBAAqB,CAAA;AAC5B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAE9C,MAAM,WAAW,sBAAsB;IACrC;;;;OAIG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;IAC/D,yEAAyE;IACzE,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,MAAM,CAAA;CACnC;AAED,MAAM,WAAW,eAAgB,SAAQ,eAAe;IACtD,kDAAkD;IAClD,QAAQ,CAAC,MAAM,EAAE,SAAS,YAAY,EAAE,CAAA;IACxC,6CAA6C;IAC7C,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAA;IACjC,iDAAiD;IACjD,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAA;CACjC;AAeD;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,GAAE,sBAA2B,GAAG,eAAe,CAiG3F"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { WakeQueue } from './wakeQueue.ts';
|
|
2
|
+
export interface MemoryWakeQueue extends WakeQueue {
|
|
3
|
+
/** Entries currently leased and not yet acked or released. */
|
|
4
|
+
inflightCount: () => Promise<number>;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* In-process `WakeQueue`.
|
|
8
|
+
*
|
|
9
|
+
* Structural evidence only: nothing survives process death, so `recoverInflight`
|
|
10
|
+
* can reclaim a lease abandoned within this process but cannot help after a
|
|
11
|
+
* restart. Use the filesystem or SQLite provider where durability matters.
|
|
12
|
+
*/
|
|
13
|
+
export declare function createMemoryWakeQueue(): MemoryWakeQueue;
|
|
14
|
+
//# sourceMappingURL=memoryWakeQueue.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memoryWakeQueue.d.ts","sourceRoot":"","sources":["../../src/memoryWakeQueue.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAc,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAE3D,MAAM,WAAW,eAAgB,SAAQ,SAAS;IAChD,8DAA8D;IAC9D,aAAa,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAA;CACrC;AAOD;;;;;;GAMG;AACH,wBAAgB,qBAAqB,IAAI,eAAe,CA6CvD"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal unbranded read surface needed to evaluate wake grants.
|
|
3
|
+
*
|
|
4
|
+
* Tracks Statement Graph v2: one append-only `claim` verb, no `target`, and no
|
|
5
|
+
* per-record lifecycle `state`. Canonical viewers use branded source/hash
|
|
6
|
+
* types, so live wiring requires a thin adapter that translates those types and
|
|
7
|
+
* preserves the fields below. Do not claim direct structural assignment.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* One materialized `(source, objectHash)` claim.
|
|
11
|
+
*
|
|
12
|
+
* `firstBlock`/`firstEventHash` are frozen at materialization; a redundant
|
|
13
|
+
* claim advances only `lastBlock`. Authorization reads `firstBlock`, so
|
|
14
|
+
* re-claiming cannot backdate or refresh a grant's asserted height.
|
|
15
|
+
*/
|
|
16
|
+
export interface StatementGrantClaim {
|
|
17
|
+
/** First-wins on redundant claims; never re-declared by a later claim. */
|
|
18
|
+
readonly declaredObjectSchema: string;
|
|
19
|
+
readonly firstBlock: number;
|
|
20
|
+
readonly firstEventHash: string;
|
|
21
|
+
readonly lastBlock: number;
|
|
22
|
+
readonly objectHash: string;
|
|
23
|
+
readonly source: string;
|
|
24
|
+
}
|
|
25
|
+
export interface StatementGrantObject {
|
|
26
|
+
readonly assurance: string;
|
|
27
|
+
readonly declaredSchema: string;
|
|
28
|
+
readonly objectHash: string;
|
|
29
|
+
/** Object body fields excluding `schema` (statement-graph ObjectRecord.params). */
|
|
30
|
+
readonly params: Readonly<Record<string, unknown>> | null;
|
|
31
|
+
}
|
|
32
|
+
export interface StatementGrantClaimQuery {
|
|
33
|
+
readonly declaredObjectSchemaPrefix?: string;
|
|
34
|
+
readonly objectHash?: string;
|
|
35
|
+
}
|
|
36
|
+
export interface StatementGraphGrantReadModel {
|
|
37
|
+
/** Claims made **by** `source`. v2 has no `target`, so there is no incoming direction. */
|
|
38
|
+
claims: (source: string, query?: StatementGrantClaimQuery) => Promise<readonly StatementGrantClaim[]>;
|
|
39
|
+
head: () => Promise<number>;
|
|
40
|
+
object: (objectHash: string) => Promise<StatementGrantObject | undefined>;
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=statementGraphPorts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"statementGraphPorts.d.ts","sourceRoot":"","sources":["../../src/statementGraphPorts.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;;;;;;GAMG;AACH,MAAM,WAAW,mBAAmB;IAClC,0EAA0E;IAC1E,QAAQ,CAAC,oBAAoB,EAAE,MAAM,CAAA;IACrC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAA;IAC/B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CACxB;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAA;IAC/B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,mFAAmF;IACnF,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,IAAI,CAAA;CAC1D;AAED,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,0BAA0B,CAAC,EAAE,MAAM,CAAA;IAC5C,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAC7B;AAED,MAAM,WAAW,4BAA4B;IAC3C,0FAA0F;IAC1F,MAAM,EAAE,CACN,MAAM,EAAE,MAAM,EACd,KAAK,CAAC,EAAE,wBAAwB,KAC7B,OAAO,CAAC,SAAS,mBAAmB,EAAE,CAAC,CAAA;IAC5C,IAAI,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAA;IAC3B,MAAM,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,oBAAoB,GAAG,SAAS,CAAC,CAAA;CAC1E"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { WakeGrantAuthorizer } from './admissionTypes.ts';
|
|
2
|
+
import type { StatementGraphGrantReadModel } from './statementGraphPorts.ts';
|
|
3
|
+
export interface StatementGraphWakeGrantAuthorizerOptions {
|
|
4
|
+
readonly viewer: StatementGraphGrantReadModel;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Adapts a canonical Statement Graph v2 read model to the evidence-bearing
|
|
8
|
+
* D-002 grant authorization port. Each decision is bound to one stable head.
|
|
9
|
+
*
|
|
10
|
+
* v2 is append-only with no `target` and no lifecycle `state`, so this layer
|
|
11
|
+
* owns two things the protocol used to:
|
|
12
|
+
*
|
|
13
|
+
* - **Aboutness.** The publisher a grant enables is read from the grant
|
|
14
|
+
* object's `publisher` param, not from a claim edge.
|
|
15
|
+
* - **Negation.** A grant is disabled by a further claim, by the *same pinned
|
|
16
|
+
* controller*, of a revocation object referencing that grant's hash.
|
|
17
|
+
* Revocations from any other source are ignored.
|
|
18
|
+
*/
|
|
19
|
+
export declare function createStatementGraphWakeGrantAuthorizer(options: StatementGraphWakeGrantAuthorizerOptions): WakeGrantAuthorizer;
|
|
20
|
+
//# sourceMappingURL=statementGraphWakeGrantAuthorizer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"statementGraphWakeGrantAuthorizer.d.ts","sourceRoot":"","sources":["../../src/statementGraphWakeGrantAuthorizer.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAGV,mBAAmB,EAEpB,MAAM,qBAAqB,CAAA;AAC5B,OAAO,KAAK,EAEV,4BAA4B,EAC7B,MAAM,0BAA0B,CAAA;AAEjC,MAAM,WAAW,wCAAwC;IACvD,QAAQ,CAAC,MAAM,EAAE,4BAA4B,CAAA;CAC9C;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,uCAAuC,CACrD,OAAO,EAAE,wCAAwC,GAChD,mBAAmB,CA4CrB"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { DeploymentId, Hash, WakeEnvelope, WakeId } from '@xyo-network/event-kit-schemas';
|
|
2
|
+
/**
|
|
3
|
+
* A wake that passed D-002 verification and live grant authorization.
|
|
4
|
+
*
|
|
5
|
+
* `jti` records the token attempt that first admitted it; retries of the same
|
|
6
|
+
* logical wake carry a different `jti` but resolve to the same receipt.
|
|
7
|
+
*/
|
|
8
|
+
export interface AdmittedWake {
|
|
9
|
+
audience: string;
|
|
10
|
+
deploymentId: DeploymentId;
|
|
11
|
+
event: WakeEnvelope;
|
|
12
|
+
eventHash: Hash;
|
|
13
|
+
fromBlock: number;
|
|
14
|
+
jti: string;
|
|
15
|
+
publisher: string;
|
|
16
|
+
queueId?: string;
|
|
17
|
+
toBlock: number;
|
|
18
|
+
wakeId: WakeId;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,YAAY,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,EACzC,MAAM,gCAAgC,CAAA;AAEvC;;;;;GAKG;AACH,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAA;IAChB,YAAY,EAAE,YAAY,CAAA;IAC1B,KAAK,EAAE,YAAY,CAAA;IACnB,SAAS,EAAE,IAAI,CAAA;IACf,SAAS,EAAE,MAAM,CAAA;IACjB,GAAG,EAAE,MAAM,CAAA;IACX,SAAS,EAAE,MAAM,CAAA;IACjB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,MAAM,CAAA;CACf"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { DeploymentId, Hash, NormalizedAddress, WakeEnvelope, WakeId, WakeJwtAudience, WakeJwtId } from '@xyo-network/event-kit-schemas';
|
|
2
|
+
/** D-002 maximum accepted JWT lifetime. */
|
|
3
|
+
export declare const EVENT_KIT_MAX_JWT_LIFETIME_SECONDS = 300;
|
|
4
|
+
/** D-002 maximum accepted publisher clock lead. */
|
|
5
|
+
export declare const EVENT_KIT_MAX_FUTURE_IAT_SECONDS = 60;
|
|
6
|
+
export interface WakeAdmissionRoute {
|
|
7
|
+
readonly audience: WakeJwtAudience;
|
|
8
|
+
readonly controller: NormalizedAddress;
|
|
9
|
+
readonly deploymentId: DeploymentId;
|
|
10
|
+
readonly maxBlocksPerWake: number;
|
|
11
|
+
readonly maxGrantLagBlocks: number;
|
|
12
|
+
readonly queueId?: string;
|
|
13
|
+
}
|
|
14
|
+
export interface VerifyWakeRequestInput {
|
|
15
|
+
/** Already JSON-decoded request body. Wrappers and companion credential fields are rejected. */
|
|
16
|
+
readonly body: unknown;
|
|
17
|
+
readonly jwt: string;
|
|
18
|
+
/** Trusted request-receive clock, supplied explicitly to keep verification deterministic. */
|
|
19
|
+
readonly nowSeconds: number;
|
|
20
|
+
readonly route: WakeAdmissionRoute;
|
|
21
|
+
}
|
|
22
|
+
export type VerifyWakeRequestRejectionReason = 'configuration-invalid' | 'event-hash-failed' | 'event-hash-mismatch' | 'event-malformed' | 'event-target-mismatch' | 'range-invalid' | 'range-too-large' | 'wake-id-invalid' | 'jwt-audience-mismatch' | 'jwt-claims-invalid' | 'jwt-expired' | 'jwt-future-iat' | 'jwt-header-invalid' | 'jwt-identity-invalid' | 'jwt-invalid' | 'jwt-lifetime-invalid' | 'jwt-malformed' | 'jwt-nbf-not-allowed' | 'jwt-schema-mismatch';
|
|
23
|
+
export interface VerifiedWakeRequest {
|
|
24
|
+
readonly audience: WakeJwtAudience;
|
|
25
|
+
readonly deploymentId: DeploymentId;
|
|
26
|
+
readonly event: Readonly<WakeEnvelope>;
|
|
27
|
+
readonly eventHash: Hash;
|
|
28
|
+
readonly expiresAt: number;
|
|
29
|
+
readonly fromBlock: number;
|
|
30
|
+
readonly issuedAt: number;
|
|
31
|
+
readonly jwtId: WakeJwtId;
|
|
32
|
+
readonly publisher: NormalizedAddress;
|
|
33
|
+
readonly queueId?: string;
|
|
34
|
+
readonly route: WakeAdmissionRoute;
|
|
35
|
+
readonly toBlock: number;
|
|
36
|
+
readonly tokenIssuedAt: number;
|
|
37
|
+
readonly wakeId: WakeId;
|
|
38
|
+
}
|
|
39
|
+
export interface VerifyWakeRequestSuccess {
|
|
40
|
+
readonly ok: true;
|
|
41
|
+
readonly verified: VerifiedWakeRequest;
|
|
42
|
+
}
|
|
43
|
+
export interface VerifyWakeRequestFailure {
|
|
44
|
+
readonly details?: readonly string[];
|
|
45
|
+
readonly ok: false;
|
|
46
|
+
readonly reason: VerifyWakeRequestRejectionReason;
|
|
47
|
+
}
|
|
48
|
+
export type VerifyWakeRequestResult = VerifyWakeRequestFailure | VerifyWakeRequestSuccess;
|
|
49
|
+
/**
|
|
50
|
+
* Verifies the cryptographic and request-shape portion of D-002 without grant,
|
|
51
|
+
* replay, queue, reducer, or XL1 I/O.
|
|
52
|
+
*/
|
|
53
|
+
export declare function verifyWakeRequest(input: VerifyWakeRequestInput): Promise<VerifyWakeRequestResult>;
|
|
54
|
+
//# sourceMappingURL=verifyWakeRequest.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verifyWakeRequest.d.ts","sourceRoot":"","sources":["../../src/verifyWakeRequest.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,YAAY,EACZ,IAAI,EACJ,iBAAiB,EACjB,YAAY,EACZ,MAAM,EACN,eAAe,EAEf,SAAS,EAEV,MAAM,gCAAgC,CAAA;AAcvC,2CAA2C;AAC3C,eAAO,MAAM,kCAAkC,MAAM,CAAA;AAErD,mDAAmD;AACnD,eAAO,MAAM,gCAAgC,KAAK,CAAA;AAElD,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAA;IAClC,QAAQ,CAAC,UAAU,EAAE,iBAAiB,CAAA;IACtC,QAAQ,CAAC,YAAY,EAAE,YAAY,CAAA;IACnC,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAA;IACjC,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAA;IAClC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAC1B;AAED,MAAM,WAAW,sBAAsB;IACrC,gGAAgG;IAChG,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAA;IACtB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,6FAA6F;IAC7F,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,KAAK,EAAE,kBAAkB,CAAA;CACnC;AAED,MAAM,MAAM,gCAAgC,GACtC,uBAAuB,GACvB,mBAAmB,GACnB,qBAAqB,GACrB,iBAAiB,GACjB,uBAAuB,GACvB,eAAe,GACf,iBAAiB,GACjB,iBAAiB,GACjB,uBAAuB,GACvB,oBAAoB,GACpB,aAAa,GACb,gBAAgB,GAChB,oBAAoB,GACpB,sBAAsB,GACtB,aAAa,GACb,sBAAsB,GACtB,eAAe,GACf,qBAAqB,GACrB,qBAAqB,CAAA;AAE3B,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAA;IAClC,QAAQ,CAAC,YAAY,EAAE,YAAY,CAAA;IACnC,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,YAAY,CAAC,CAAA;IACtC,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAA;IACxB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAA;IACzB,QAAQ,CAAC,SAAS,EAAE,iBAAiB,CAAA;IACrC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,KAAK,EAAE,kBAAkB,CAAA;IAClC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAA;IAC9B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CACxB;AAED,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAA;IACjB,QAAQ,CAAC,QAAQ,EAAE,mBAAmB,CAAA;CACvC;AAED,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IACpC,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAA;IAClB,QAAQ,CAAC,MAAM,EAAE,gCAAgC,CAAA;CAClD;AAED,MAAM,MAAM,uBAAuB,GAAG,wBAAwB,GAAG,wBAAwB,CAAA;AAqBzF;;;GAGG;AACH,wBAAsB,iBAAiB,CAAC,KAAK,EAAE,sBAAsB,GAAG,OAAO,CAAC,uBAAuB,CAAC,CA8DvG"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { AdmittedWake } from './types.ts';
|
|
2
|
+
/**
|
|
3
|
+
* One wake leased to exactly one consumer.
|
|
4
|
+
*
|
|
5
|
+
* The lease is held until `ack` or `release`. A consumer that dies holding it
|
|
6
|
+
* leaves the entry recoverable rather than lost, which is why the queue port is
|
|
7
|
+
* lease-based rather than push-based: a fire-and-forget handoff has no way to
|
|
8
|
+
* reclaim work whose consumer never finished.
|
|
9
|
+
*/
|
|
10
|
+
export interface LeasedWake {
|
|
11
|
+
/** Removes the entry permanently. Call only once the handler committed. */
|
|
12
|
+
readonly ack: () => Promise<void>;
|
|
13
|
+
/** Returns the entry for another attempt. */
|
|
14
|
+
readonly release: () => Promise<void>;
|
|
15
|
+
readonly wake: AdmittedWake;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Provider-agnostic durable wake queue.
|
|
19
|
+
*
|
|
20
|
+
* Implementations back this with a filesystem directory, SQLite, Postgres, or a
|
|
21
|
+
* cloud queue. Delivery is at-least-once: a consumer MUST be idempotent, since
|
|
22
|
+
* a lease that is never acked is redelivered.
|
|
23
|
+
*
|
|
24
|
+
* Every implementation must satisfy the shared conformance suite in
|
|
25
|
+
* `@xyo-network/event-kit-testing`.
|
|
26
|
+
*/
|
|
27
|
+
export interface WakeQueue {
|
|
28
|
+
/** Durably appends a wake. Resolves only once the entry survives a crash. */
|
|
29
|
+
append: (wake: AdmittedWake) => Promise<void>;
|
|
30
|
+
/** Leases the next pending entry, or `undefined` when none remain. */
|
|
31
|
+
claim: () => Promise<LeasedWake | undefined>;
|
|
32
|
+
/** Entries waiting to be claimed. Excludes leases already held. */
|
|
33
|
+
pendingCount: () => Promise<number>;
|
|
34
|
+
/**
|
|
35
|
+
* Returns every in-flight entry to pending and reports how many moved.
|
|
36
|
+
* Run at startup: entries held by a process that died are otherwise stranded.
|
|
37
|
+
*/
|
|
38
|
+
recoverInflight: () => Promise<number>;
|
|
39
|
+
}
|
|
40
|
+
export type WakeHandler = (wake: AdmittedWake) => Promise<void> | void;
|
|
41
|
+
/**
|
|
42
|
+
* Drains the queue serially until empty, acking each wake the handler accepts.
|
|
43
|
+
*
|
|
44
|
+
* A handler that throws releases its lease, so the wake is retried rather than
|
|
45
|
+
* dropped, and the error propagates. Push-style consumption composes over the
|
|
46
|
+
* lease port; the reverse does not.
|
|
47
|
+
*/
|
|
48
|
+
export declare function drainQueue(queue: WakeQueue, handler: WakeHandler): Promise<number>;
|
|
49
|
+
//# sourceMappingURL=wakeQueue.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wakeQueue.d.ts","sourceRoot":"","sources":["../../src/wakeQueue.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAE9C;;;;;;;GAOG;AACH,MAAM,WAAW,UAAU;IACzB,2EAA2E;IAC3E,QAAQ,CAAC,GAAG,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IACjC,6CAA6C;IAC7C,QAAQ,CAAC,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IACrC,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAA;CAC5B;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,SAAS;IACxB,6EAA6E;IAC7E,MAAM,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAC7C,sEAAsE;IACtE,KAAK,EAAE,MAAM,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,CAAA;IAC5C,mEAAmE;IACnE,YAAY,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAA;IACnC;;;OAGG;IACH,eAAe,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAA;CACvC;AAED,MAAM,MAAM,WAAW,GAAG,CAAC,IAAI,EAAE,YAAY,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;AAEtE;;;;;;GAMG;AACH,wBAAsB,UAAU,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAexF"}
|
package/package.json
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@xyo-network/event-kit-protocol",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Wallet-JWT Payload verification and admission contracts for XL1 Event Kit",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"xyo",
|
|
7
|
+
"xl1",
|
|
8
|
+
"event-kit",
|
|
9
|
+
"protocol",
|
|
10
|
+
"typescript"
|
|
11
|
+
],
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/XYOracleNetwork/event-kit/issues"
|
|
14
|
+
},
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "git+https://github.com/XYOracleNetwork/event-kit.git",
|
|
18
|
+
"directory": "packages/protocol"
|
|
19
|
+
},
|
|
20
|
+
"license": "UNLICENSED",
|
|
21
|
+
"sideEffects": false,
|
|
22
|
+
"type": "module",
|
|
23
|
+
"exports": {
|
|
24
|
+
".": {
|
|
25
|
+
"types": "./dist/neutral/index.d.ts",
|
|
26
|
+
"default": "./dist/neutral/index.mjs"
|
|
27
|
+
},
|
|
28
|
+
"./package.json": "./package.json",
|
|
29
|
+
"./README.md": "./README.md"
|
|
30
|
+
},
|
|
31
|
+
"files": [
|
|
32
|
+
"dist",
|
|
33
|
+
"README.md"
|
|
34
|
+
],
|
|
35
|
+
"dependencies": {
|
|
36
|
+
"@xyo-network/event-kit-schemas": "~0.0.1"
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@ariestools/sdk": "~8.1.9",
|
|
40
|
+
"@ariestools/toolchain": "~9.1.0",
|
|
41
|
+
"@ariestools/tsconfig": "~9.1.0",
|
|
42
|
+
"@opentelemetry/api": "~1.9.1",
|
|
43
|
+
"@xyo-network/sdk": "~7.2.3",
|
|
44
|
+
"@xyo-network/sdk-protocol": "~7.2.4",
|
|
45
|
+
"eslint": "~10.8.1",
|
|
46
|
+
"eslint-import-resolver-typescript": "~4.4.5",
|
|
47
|
+
"typescript": "~6.0.3",
|
|
48
|
+
"vite": "~8.2.1",
|
|
49
|
+
"vitest": "~4.1.11",
|
|
50
|
+
"zod": "~4.4.3"
|
|
51
|
+
},
|
|
52
|
+
"peerDependencies": {
|
|
53
|
+
"@ariestools/sdk": "^8.1",
|
|
54
|
+
"@opentelemetry/api": "^1.9",
|
|
55
|
+
"@xyo-network/sdk": "^7.2",
|
|
56
|
+
"@xyo-network/sdk-protocol": "^7.2",
|
|
57
|
+
"zod": "^4.4"
|
|
58
|
+
},
|
|
59
|
+
"engines": {
|
|
60
|
+
"node": ">=22"
|
|
61
|
+
},
|
|
62
|
+
"publishConfig": {
|
|
63
|
+
"access": "restricted"
|
|
64
|
+
},
|
|
65
|
+
"scripts": {
|
|
66
|
+
"test": "vitest run"
|
|
67
|
+
}
|
|
68
|
+
}
|