UNPKG

@beignet/core

Version:

Core framework primitives for Beignet

224 lines (209 loc) 6.58 kB
import type { EventPublishOptions } from "./index.js"; import type { EventTransportValue } from "./transport.js"; const PARSED_EVENT_PAYLOAD = Symbol.for("beignet.eventPayload.parsed"); const TRANSPORT_STABLE_EVENT_PAYLOAD = Symbol.for( "beignet.eventPayload.transportStable", ); type ParsedEventPublishOptions = EventPublishOptions & { [PARSED_EVENT_PAYLOAD]?: object; [TRANSPORT_STABLE_EVENT_PAYLOAD]?: object; }; interface ParsedPayloadState { readonly eventName: string; readonly payloadSchema: object; readonly validate: unknown; readonly payload: unknown; } type PayloadSnapshot = | { readonly kind: "primitive"; readonly value: unknown } | { readonly kind: "array"; readonly value: object; readonly prototype: object | null; readonly items: readonly PayloadSnapshot[]; } | { readonly kind: "object"; readonly value: object; readonly prototype: object | null; readonly entries: readonly (readonly [string, PayloadSnapshot])[]; }; interface TransportStablePayloadState { readonly eventName: string; readonly payloadSchema: object; readonly validate: unknown; readonly payload: PayloadSnapshot; readonly fingerprint: string; } interface EventPayloadIdentity { readonly name: string; readonly payload: { readonly "~standard": { readonly validate: unknown; }; }; } const transportStablePayloadStates = new WeakMap< object, TransportStablePayloadState >(); const parsedPayloadStates = new WeakMap<object, ParsedPayloadState>(); function transportFingerprint(value: EventTransportValue): string { return JSON.stringify(value); } function capturePayloadSnapshot(value: unknown): PayloadSnapshot { if (value === null || typeof value !== "object") { return { kind: "primitive", value }; } if (Array.isArray(value)) { const items: PayloadSnapshot[] = []; for (let index = 0; index < value.length; index += 1) { const descriptor = Object.getOwnPropertyDescriptor(value, String(index)); if (!descriptor || !("value" in descriptor)) { throw new TypeError( "Transport-stable array state must contain data properties.", ); } items.push(capturePayloadSnapshot(descriptor.value)); } return { kind: "array", value, prototype: Object.getPrototypeOf(value), items, }; } return { kind: "object", value, prototype: Object.getPrototypeOf(value), entries: Reflect.ownKeys(value).map((key) => { const descriptor = Object.getOwnPropertyDescriptor(value, key); if (typeof key !== "string" || !descriptor || !("value" in descriptor)) { throw new TypeError( "Transport-stable payload state must contain data properties.", ); } return [key, capturePayloadSnapshot(descriptor.value)] as const; }), }; } function matchesPayloadSnapshot( snapshot: PayloadSnapshot, value: unknown, ): boolean { if (snapshot.kind === "primitive") return Object.is(snapshot.value, value); if (snapshot.value !== value || value === null || typeof value !== "object") { return false; } if (Object.getPrototypeOf(value) !== snapshot.prototype) return false; if (snapshot.kind === "array") { return ( Array.isArray(value) && value.length === snapshot.items.length && snapshot.items.every((item, index) => { const descriptor = Object.getOwnPropertyDescriptor( value, String(index), ); return ( descriptor !== undefined && "value" in descriptor && matchesPayloadSnapshot(item, descriptor.value) ); }) ); } if (Array.isArray(value)) return false; const keys = Reflect.ownKeys(value); return ( keys.length === snapshot.entries.length && snapshot.entries.every(([key, item], index) => { const descriptor = Object.getOwnPropertyDescriptor(value, key); return ( keys[index] === key && descriptor !== undefined && "value" in descriptor && matchesPayloadSnapshot(item, descriptor.value) ); }) ); } export function markEventPayloadParsed( event: EventPayloadIdentity, payload: unknown, options?: EventPublishOptions, ): EventPublishOptions { const token = {}; parsedPayloadStates.set(token, { eventName: event.name, payloadSchema: event.payload, validate: event.payload["~standard"].validate, payload, }); return { ...options, [PARSED_EVENT_PAYLOAD]: token, } as ParsedEventPublishOptions; } export function isEventPayloadParsed( event: EventPayloadIdentity, payload: unknown, options?: EventPublishOptions, ): boolean { const token = (options as ParsedEventPublishOptions | undefined)?.[ PARSED_EVENT_PAYLOAD ]; const state = token ? parsedPayloadStates.get(token) : undefined; return ( state?.eventName === event.name && state.payloadSchema === event.payload && state.validate === event.payload["~standard"].validate && Object.is(state.payload, payload) ); } export function markEventPayloadTransportStable( event: EventPayloadIdentity, payload: unknown, transportValue: EventTransportValue, options?: EventPublishOptions, ): EventPublishOptions { const parsedToken = {}; parsedPayloadStates.set(parsedToken, { eventName: event.name, payloadSchema: event.payload, validate: event.payload["~standard"].validate, payload, }); const stableToken = {}; transportStablePayloadStates.set(stableToken, { eventName: event.name, payloadSchema: event.payload, validate: event.payload["~standard"].validate, payload: capturePayloadSnapshot(payload), fingerprint: transportFingerprint(transportValue), }); return { ...options, [PARSED_EVENT_PAYLOAD]: parsedToken, [TRANSPORT_STABLE_EVENT_PAYLOAD]: stableToken, } as ParsedEventPublishOptions; } export function isEventPayloadTransportStable( event: EventPayloadIdentity, payload: unknown, transportValue: EventTransportValue, options?: EventPublishOptions, ): boolean { const token = (options as ParsedEventPublishOptions | undefined)?.[ TRANSPORT_STABLE_EVENT_PAYLOAD ]; const state = token ? transportStablePayloadStates.get(token) : undefined; return ( state?.eventName === event.name && state.payloadSchema === event.payload && state.validate === event.payload["~standard"].validate && matchesPayloadSnapshot(state.payload, payload) && state.fingerprint === transportFingerprint(transportValue) ); }