@sguild/dispatcher 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +354 -0
- package/contracts/credit-reservation-funding-state/schema/payloads/reservation.funded-v1.json +59 -0
- package/contracts/credit-reservation-funding-state/schema/payloads/reservation.refunded-v1.json +80 -0
- package/contracts/credit-reservation-funding-state/schema/payloads/reservation.refunding-v1.json +74 -0
- package/contracts/credit-reservation-lock/schema/payloads/credit.consumed-v1.json +33 -0
- package/contracts/credit-reservation-lock/schema/payloads/credit.forfeited-v1.json +41 -0
- package/contracts/credit-reservation-lock/schema/payloads/credit.funded-v1.json +31 -0
- package/contracts/credit-reservation-lock/schema/payloads/credit.locked-v1.json +42 -0
- package/contracts/credit-reservation-lock/schema/payloads/credit.purchased-v1.json +39 -0
- package/contracts/credit-reservation-lock/schema/payloads/credit.released-v1.json +61 -0
- package/contracts/credit-reservation-lock/schema/payloads/credit.released-v2.json +77 -0
- package/contracts/credit-reservation-lock/schema/payloads/credit.reserved-v1.json +60 -0
- package/contracts/credit-reservation-lock/schema/payloads/customer.handoff-v1.json +35 -0
- package/contracts/event-envelope/schema/envelope-v1.json +79 -0
- package/contracts/event-types-registry.json +541 -0
- package/contracts/identity/schema/payloads/intake.amended-v1.json +124 -0
- package/contracts/identity/schema/payloads/intake.captured-v2.json +114 -0
- package/contracts/identity/schema/payloads/person.updated-v1.json +99 -0
- package/contracts/lead-lifecycle/schema/payloads/lead.attempt.exhausted-v1.json +36 -0
- package/contracts/lead-lifecycle/schema/payloads/lead.callback.scheduled-v1.json +39 -0
- package/contracts/lead-lifecycle/schema/payloads/lead.created-v1.json +50 -0
- package/contracts/lead-lifecycle/schema/payloads/lead.reached-v1.json +39 -0
- package/contracts/lead-lifecycle/schema/payloads/lead.stage.changed-v1.json +44 -0
- package/contracts/payment-flow/schema/payloads/payment.failed-v1.json +88 -0
- package/contracts/payment-flow/schema/payloads/payment.received-v1.json +69 -0
- package/contracts/refund-flow/schema/payloads/refund.completed-v1.json +75 -0
- package/contracts/refund-flow/schema/payloads/refund.initiated-v1.json +69 -0
- package/dist/config.d.ts +67 -0
- package/dist/config.js +81 -0
- package/dist/dispatcher-errors.d.ts +20 -0
- package/dist/dispatcher-errors.js +42 -0
- package/dist/dispatcher.d.ts +123 -0
- package/dist/dispatcher.js +171 -0
- package/dist/dlq.d.ts +173 -0
- package/dist/dlq.js +391 -0
- package/dist/fanout-drain.d.ts +11 -0
- package/dist/fanout-drain.js +31 -0
- package/dist/fanout.d.ts +144 -0
- package/dist/fanout.js +321 -0
- package/dist/inbox.d.ts +125 -0
- package/dist/inbox.js +120 -0
- package/dist/index.d.ts +36 -0
- package/dist/index.js +70 -0
- package/dist/internal/id.d.ts +38 -0
- package/dist/internal/id.js +78 -0
- package/dist/internal/pg-search-path.d.ts +34 -0
- package/dist/internal/pg-search-path.js +55 -0
- package/dist/internal/resolve-contract-path.d.ts +41 -0
- package/dist/internal/resolve-contract-path.js +65 -0
- package/dist/observability.d.ts +24 -0
- package/dist/observability.js +37 -0
- package/dist/postgres-consumer.d.ts +175 -0
- package/dist/postgres-consumer.js +561 -0
- package/dist/postgres-transport.d.ts +70 -0
- package/dist/postgres-transport.js +144 -0
- package/dist/producer-db.d.ts +80 -0
- package/dist/producer-db.js +115 -0
- package/dist/registry.d.ts +94 -0
- package/dist/registry.js +99 -0
- package/dist/signature.d.ts +44 -0
- package/dist/signature.js +79 -0
- package/dist/types.d.ts +107 -0
- package/dist/types.js +13 -0
- package/dist/validator.d.ts +60 -0
- package/dist/validator.js +171 -0
- package/package.json +48 -0
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dispatcher SDK envelope types.
|
|
3
|
+
*
|
|
4
|
+
* Mirrors the Sguild Event Envelope JSON Schema at
|
|
5
|
+
* coordination/contracts/event-envelope/schema/envelope-v1.json
|
|
6
|
+
* (sourced from contracts/event-envelope/README.md v1.0.2).
|
|
7
|
+
*
|
|
8
|
+
* Per §8.2 of the envelope contract, payload schema versioning is per-event-type
|
|
9
|
+
* and independent of envelope versioning. The generic `TPayload` parameter on
|
|
10
|
+
* `EventEnvelope` lets callers narrow the payload type at the call site.
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Closed set of producer domains per the closed-domain rule in
|
|
14
|
+
* coordination/CONVENTIONS.md and coordination/domains/README.md.
|
|
15
|
+
*
|
|
16
|
+
* Coaching was added on 2026-05-01 by ADR-0008. `operations` was the legacy
|
|
17
|
+
* value during the 2026-04-27 to 2026-05-11 deprecation window per the v1.0.1
|
|
18
|
+
* changelog of contracts/event-envelope/README.md and is included here so the
|
|
19
|
+
* type accepts events emitted under the legacy name; consumers MUST treat
|
|
20
|
+
* `operations` and `delivery` as the same producer per §4.1.
|
|
21
|
+
*/
|
|
22
|
+
export type ProducerDomain = "platform" | "growth" | "sales" | "delivery" | "revenue" | "coaching" | "operations";
|
|
23
|
+
/**
|
|
24
|
+
* Live producer domains. Excludes the `operations` deprecation alias. New code
|
|
25
|
+
* SHOULD constrain to this type rather than the broader `ProducerDomain` to
|
|
26
|
+
* avoid emitting the deprecated value.
|
|
27
|
+
*/
|
|
28
|
+
export type LiveProducerDomain = Exclude<ProducerDomain, "operations">;
|
|
29
|
+
/**
|
|
30
|
+
* Actor reference per §4.2 of the envelope contract. Either a Person ID
|
|
31
|
+
* (human-triggered) or `system:<domain>` (automated).
|
|
32
|
+
*/
|
|
33
|
+
export type ActorRef = `per_${string}` | `system:${LiveProducerDomain}`;
|
|
34
|
+
/**
|
|
35
|
+
* Canonical entity ID prefix-and-UUID-v7 shape per ADR-0002. Used for the
|
|
36
|
+
* `subject` field. Specific role-record prefixes (per_, lead_, par_, coa_,
|
|
37
|
+
* crr_, crd_acct_, les_, etc.) are validated by the JSON Schema's regex; the
|
|
38
|
+
* TS type stays loose because the closed-set of prefixes is broader than the
|
|
39
|
+
* type system can usefully express here.
|
|
40
|
+
*/
|
|
41
|
+
export type CanonicalEntityId = `${string}_${string}`;
|
|
42
|
+
/**
|
|
43
|
+
* The envelope every cross-domain event rides on. Required and optional fields
|
|
44
|
+
* per §4.1 and §4.2 of the contract.
|
|
45
|
+
*
|
|
46
|
+
* @typeParam TPayload - the event-specific payload shape, narrowed per
|
|
47
|
+
* (event_type, schema_version) by the consumer at the call site.
|
|
48
|
+
*/
|
|
49
|
+
export type EventEnvelope<TPayload = unknown> = {
|
|
50
|
+
/** evt_<UUID v7 canonical>. Globally unique per ADR-0002. */
|
|
51
|
+
event_id: string;
|
|
52
|
+
/** Dotted lowercase noun.verb. Must be registered in the event-type registry. */
|
|
53
|
+
event_type: string;
|
|
54
|
+
/** ISO 8601 UTC, producer wall-clock at the moment the event happened. */
|
|
55
|
+
occurred_at: string;
|
|
56
|
+
/** Tenant scoping per ADR-0001. */
|
|
57
|
+
tenant_id: string;
|
|
58
|
+
/** Which domain emitted the event. */
|
|
59
|
+
producer: ProducerDomain;
|
|
60
|
+
/** Per-event-type schema version. Independent of envelope version per §8.2. */
|
|
61
|
+
schema_version: number;
|
|
62
|
+
/** Event-specific data; shape determined by (event_type, schema_version). */
|
|
63
|
+
payload: TPayload;
|
|
64
|
+
/** Optional. The primary entity the event is about. Usually a person_id. */
|
|
65
|
+
subject?: CanonicalEntityId;
|
|
66
|
+
/** Optional. The human or system that caused the event. */
|
|
67
|
+
actor?: ActorRef;
|
|
68
|
+
/** Optional. The originating event in a chain. */
|
|
69
|
+
correlation_id?: string;
|
|
70
|
+
};
|
|
71
|
+
/**
|
|
72
|
+
* The minimum a producer supplies to `dispatcher.publish`. The SDK fills in
|
|
73
|
+
* `event_id`, `occurred_at`, `tenant_id`, `producer`, and `schema_version`
|
|
74
|
+
* automatically per §10.2 of the envelope contract; producers populate
|
|
75
|
+
* `event_type`, `payload`, and the optional fields.
|
|
76
|
+
*
|
|
77
|
+
* Note: `schema_version` defaults to the active version registered in the
|
|
78
|
+
* event-type registry for `event_type`. Producers emitting at a non-default
|
|
79
|
+
* version (during a transition window) supply it explicitly via `EventEmit`.
|
|
80
|
+
*/
|
|
81
|
+
export type EventEmit<TPayload = unknown> = {
|
|
82
|
+
event_type: string;
|
|
83
|
+
payload: TPayload;
|
|
84
|
+
schema_version?: number;
|
|
85
|
+
subject?: CanonicalEntityId;
|
|
86
|
+
actor?: ActorRef;
|
|
87
|
+
correlation_id?: string;
|
|
88
|
+
};
|
|
89
|
+
/**
|
|
90
|
+
* Subscriber handler signature. Per §9.2 of the envelope contract, the SDK
|
|
91
|
+
* dedupes over `(consumer, event_id)` so handlers are invoked at-most-once
|
|
92
|
+
* per (consumer, event_id) pair (when the SDK ships; today the SDK is in
|
|
93
|
+
* Phase 0 per memos/2026/2026-05-01-platform-dispatcher-sdk-build-plan).
|
|
94
|
+
*
|
|
95
|
+
* Handlers MUST throw on processing failure to invoke the SDK's retry path.
|
|
96
|
+
* Swallowing exceptions silently bypasses the dead-letter machinery.
|
|
97
|
+
*/
|
|
98
|
+
export type SubscribeHandler<TPayload = unknown> = (envelope: EventEnvelope<TPayload>) => Promise<void>;
|
|
99
|
+
/**
|
|
100
|
+
* Result of a successful `dispatcher.publish` call. Returns the canonical
|
|
101
|
+
* `event_id` so the producer can correlate retries (per §10.6 of the envelope
|
|
102
|
+
* contract: producers SHALL reuse the same event_id on retry so consumer dedup
|
|
103
|
+
* works).
|
|
104
|
+
*/
|
|
105
|
+
export type PublishResult = {
|
|
106
|
+
event_id: string;
|
|
107
|
+
};
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Dispatcher SDK envelope types.
|
|
4
|
+
*
|
|
5
|
+
* Mirrors the Sguild Event Envelope JSON Schema at
|
|
6
|
+
* coordination/contracts/event-envelope/schema/envelope-v1.json
|
|
7
|
+
* (sourced from contracts/event-envelope/README.md v1.0.2).
|
|
8
|
+
*
|
|
9
|
+
* Per §8.2 of the envelope contract, payload schema versioning is per-event-type
|
|
10
|
+
* and independent of envelope versioning. The generic `TPayload` parameter on
|
|
11
|
+
* `EventEnvelope` lets callers narrow the payload type at the call site.
|
|
12
|
+
*/
|
|
13
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dispatcher payload and envelope validation.
|
|
3
|
+
*
|
|
4
|
+
* ADR-0009 action item 8: every emit validates payload against the
|
|
5
|
+
* registered JSON Schema for `(event_type, schema_version)` before the
|
|
6
|
+
* row hits dispatcher_event. The validator runs producer-side at publish
|
|
7
|
+
* time so unschema'd payloads never reach consumers; consumers also
|
|
8
|
+
* re-validate at subscribe time per envelope contract §5.
|
|
9
|
+
*
|
|
10
|
+
* Schemas live in two places per the event-envelope contract:
|
|
11
|
+
*
|
|
12
|
+
* - The envelope schema at
|
|
13
|
+
* `coordination/contracts/event-envelope/schema/envelope-v1.json`
|
|
14
|
+
* applies to every envelope the SDK builds. Validated once per
|
|
15
|
+
* publish; cached after first compile.
|
|
16
|
+
*
|
|
17
|
+
* - Per-event-type payload schemas at
|
|
18
|
+
* `coordination/contracts/<contract>/schema/payloads/<event_type>-v<schema_version>.json`
|
|
19
|
+
* (path resolved from the registry's `payload_schema` field). One
|
|
20
|
+
* compiled validator per (event_type, schema_version), cached on
|
|
21
|
+
* first use.
|
|
22
|
+
*
|
|
23
|
+
* Validation failures throw `PayloadValidationError` or
|
|
24
|
+
* `EnvelopeValidationError` with the ajv-shaped error list attached so
|
|
25
|
+
* callers can surface useful messages.
|
|
26
|
+
*/
|
|
27
|
+
import type { ErrorObject } from "ajv";
|
|
28
|
+
export declare class EnvelopeValidationError extends Error {
|
|
29
|
+
readonly errors: ErrorObject[];
|
|
30
|
+
constructor(errors: ErrorObject[]);
|
|
31
|
+
}
|
|
32
|
+
export declare class PayloadValidationError extends Error {
|
|
33
|
+
readonly eventType: string;
|
|
34
|
+
readonly schemaVersion: number;
|
|
35
|
+
readonly errors: ErrorObject[];
|
|
36
|
+
constructor(eventType: string, schemaVersion: number, errors: ErrorObject[]);
|
|
37
|
+
}
|
|
38
|
+
export declare class PayloadSchemaUnavailableError extends Error {
|
|
39
|
+
readonly eventType: string;
|
|
40
|
+
readonly schemaVersion: number;
|
|
41
|
+
constructor(eventType: string, schemaVersion: number);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Validate an envelope against the published JSON Schema. Throws
|
|
45
|
+
* EnvelopeValidationError on failure with the ajv error list attached.
|
|
46
|
+
* Idempotent: the compiled validator caches across calls.
|
|
47
|
+
*/
|
|
48
|
+
export declare function validateEnvelope(envelope: unknown): void;
|
|
49
|
+
/**
|
|
50
|
+
* Validate a payload against the registered JSON Schema for
|
|
51
|
+
* (event_type, schema_version). Throws PayloadValidationError on
|
|
52
|
+
* validation failure or PayloadSchemaUnavailableError when the registry
|
|
53
|
+
* has no `payload_schema` recorded for the version (which is itself a
|
|
54
|
+
* registry-hygiene problem the producer should fix before emitting).
|
|
55
|
+
*/
|
|
56
|
+
export declare function validatePayload(eventType: string, schemaVersion: number, payload: unknown): void;
|
|
57
|
+
/**
|
|
58
|
+
* Reset the compiled-validator caches. Test-only.
|
|
59
|
+
*/
|
|
60
|
+
export declare function __resetValidatorCachesForTests(): void;
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Dispatcher payload and envelope validation.
|
|
4
|
+
*
|
|
5
|
+
* ADR-0009 action item 8: every emit validates payload against the
|
|
6
|
+
* registered JSON Schema for `(event_type, schema_version)` before the
|
|
7
|
+
* row hits dispatcher_event. The validator runs producer-side at publish
|
|
8
|
+
* time so unschema'd payloads never reach consumers; consumers also
|
|
9
|
+
* re-validate at subscribe time per envelope contract §5.
|
|
10
|
+
*
|
|
11
|
+
* Schemas live in two places per the event-envelope contract:
|
|
12
|
+
*
|
|
13
|
+
* - The envelope schema at
|
|
14
|
+
* `coordination/contracts/event-envelope/schema/envelope-v1.json`
|
|
15
|
+
* applies to every envelope the SDK builds. Validated once per
|
|
16
|
+
* publish; cached after first compile.
|
|
17
|
+
*
|
|
18
|
+
* - Per-event-type payload schemas at
|
|
19
|
+
* `coordination/contracts/<contract>/schema/payloads/<event_type>-v<schema_version>.json`
|
|
20
|
+
* (path resolved from the registry's `payload_schema` field). One
|
|
21
|
+
* compiled validator per (event_type, schema_version), cached on
|
|
22
|
+
* first use.
|
|
23
|
+
*
|
|
24
|
+
* Validation failures throw `PayloadValidationError` or
|
|
25
|
+
* `EnvelopeValidationError` with the ajv-shaped error list attached so
|
|
26
|
+
* callers can surface useful messages.
|
|
27
|
+
*/
|
|
28
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
29
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
30
|
+
};
|
|
31
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
32
|
+
exports.PayloadSchemaUnavailableError = exports.PayloadValidationError = exports.EnvelopeValidationError = void 0;
|
|
33
|
+
exports.validateEnvelope = validateEnvelope;
|
|
34
|
+
exports.validatePayload = validatePayload;
|
|
35
|
+
exports.__resetValidatorCachesForTests = __resetValidatorCachesForTests;
|
|
36
|
+
const node_fs_1 = require("node:fs");
|
|
37
|
+
const _2020_1 = __importDefault(require("ajv/dist/2020"));
|
|
38
|
+
const ajv_formats_1 = __importDefault(require("ajv-formats"));
|
|
39
|
+
const registry_1 = require("./registry");
|
|
40
|
+
const resolve_contract_path_1 = require("./internal/resolve-contract-path");
|
|
41
|
+
// =============================================================================
|
|
42
|
+
// ajv setup. Single instance, shared across the process. `strict: false`
|
|
43
|
+
// because the contract schemas use a few patterns ajv's strict mode
|
|
44
|
+
// rejects (notably draft-2020-12 features used loosely); the contracts
|
|
45
|
+
// pass schema linting separately so loose validation here is acceptable.
|
|
46
|
+
// addFormats wires up ISO 8601 date-time, uri, etc. for schema fields
|
|
47
|
+
// that use `format`.
|
|
48
|
+
// =============================================================================
|
|
49
|
+
const ajv = new _2020_1.default({ allErrors: true, strict: false });
|
|
50
|
+
(0, ajv_formats_1.default)(ajv);
|
|
51
|
+
let cachedEnvelopeValidator = null;
|
|
52
|
+
const payloadValidatorCache = new Map();
|
|
53
|
+
// The envelope schema ships bundled inside the package's contracts tree
|
|
54
|
+
// (rooted at `contracts/` exactly as the coordination repo stores it).
|
|
55
|
+
// `resolveContractPath` handles the module-relative and cwd-relative
|
|
56
|
+
// layouts, including the sibling coordination repo fallback.
|
|
57
|
+
const ENVELOPE_SCHEMA_REL_PATH = "contracts/event-envelope/schema/envelope-v1.json";
|
|
58
|
+
// =============================================================================
|
|
59
|
+
// Errors
|
|
60
|
+
// =============================================================================
|
|
61
|
+
class EnvelopeValidationError extends Error {
|
|
62
|
+
errors;
|
|
63
|
+
constructor(errors) {
|
|
64
|
+
super(`Envelope failed JSON Schema validation: ${errors
|
|
65
|
+
.map((e) => `${e.instancePath || "/"} ${e.message}`)
|
|
66
|
+
.join("; ")}`);
|
|
67
|
+
this.errors = errors;
|
|
68
|
+
this.name = "EnvelopeValidationError";
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
exports.EnvelopeValidationError = EnvelopeValidationError;
|
|
72
|
+
class PayloadValidationError extends Error {
|
|
73
|
+
eventType;
|
|
74
|
+
schemaVersion;
|
|
75
|
+
errors;
|
|
76
|
+
constructor(eventType, schemaVersion, errors) {
|
|
77
|
+
super(`Payload for event_type='${eventType}' schema_version=${schemaVersion} failed JSON Schema validation: ${errors
|
|
78
|
+
.map((e) => `${e.instancePath || "/"} ${e.message}`)
|
|
79
|
+
.join("; ")}`);
|
|
80
|
+
this.eventType = eventType;
|
|
81
|
+
this.schemaVersion = schemaVersion;
|
|
82
|
+
this.errors = errors;
|
|
83
|
+
this.name = "PayloadValidationError";
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
exports.PayloadValidationError = PayloadValidationError;
|
|
87
|
+
class PayloadSchemaUnavailableError extends Error {
|
|
88
|
+
eventType;
|
|
89
|
+
schemaVersion;
|
|
90
|
+
constructor(eventType, schemaVersion) {
|
|
91
|
+
super(`No payload schema registered for event_type='${eventType}' schema_version=${schemaVersion}. ` +
|
|
92
|
+
`Author the schema at coordination/contracts/<contract>/schema/payloads/<event_type>-v<schema_version>.json ` +
|
|
93
|
+
`and update the registry's payload_schema field before emitting.`);
|
|
94
|
+
this.eventType = eventType;
|
|
95
|
+
this.schemaVersion = schemaVersion;
|
|
96
|
+
this.name = "PayloadSchemaUnavailableError";
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
exports.PayloadSchemaUnavailableError = PayloadSchemaUnavailableError;
|
|
100
|
+
// =============================================================================
|
|
101
|
+
// Public API
|
|
102
|
+
// =============================================================================
|
|
103
|
+
/**
|
|
104
|
+
* Validate an envelope against the published JSON Schema. Throws
|
|
105
|
+
* EnvelopeValidationError on failure with the ajv error list attached.
|
|
106
|
+
* Idempotent: the compiled validator caches across calls.
|
|
107
|
+
*/
|
|
108
|
+
function validateEnvelope(envelope) {
|
|
109
|
+
const validator = getEnvelopeValidator();
|
|
110
|
+
const ok = validator(envelope);
|
|
111
|
+
if (!ok) {
|
|
112
|
+
throw new EnvelopeValidationError(validator.errors ?? []);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Validate a payload against the registered JSON Schema for
|
|
117
|
+
* (event_type, schema_version). Throws PayloadValidationError on
|
|
118
|
+
* validation failure or PayloadSchemaUnavailableError when the registry
|
|
119
|
+
* has no `payload_schema` recorded for the version (which is itself a
|
|
120
|
+
* registry-hygiene problem the producer should fix before emitting).
|
|
121
|
+
*/
|
|
122
|
+
function validatePayload(eventType, schemaVersion, payload) {
|
|
123
|
+
const validator = getPayloadValidator(eventType, schemaVersion);
|
|
124
|
+
const ok = validator(payload);
|
|
125
|
+
if (!ok) {
|
|
126
|
+
throw new PayloadValidationError(eventType, schemaVersion, validator.errors ?? []);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Reset the compiled-validator caches. Test-only.
|
|
131
|
+
*/
|
|
132
|
+
function __resetValidatorCachesForTests() {
|
|
133
|
+
cachedEnvelopeValidator = null;
|
|
134
|
+
payloadValidatorCache.clear();
|
|
135
|
+
}
|
|
136
|
+
// =============================================================================
|
|
137
|
+
// Internal
|
|
138
|
+
// =============================================================================
|
|
139
|
+
function getEnvelopeValidator() {
|
|
140
|
+
if (cachedEnvelopeValidator)
|
|
141
|
+
return cachedEnvelopeValidator;
|
|
142
|
+
const schemaPath = (0, resolve_contract_path_1.resolveContractPath)(__dirname, ENVELOPE_SCHEMA_REL_PATH);
|
|
143
|
+
const raw = (0, node_fs_1.readFileSync)(schemaPath, "utf8");
|
|
144
|
+
const schema = JSON.parse(raw);
|
|
145
|
+
cachedEnvelopeValidator = ajv.compile(schema);
|
|
146
|
+
return cachedEnvelopeValidator;
|
|
147
|
+
}
|
|
148
|
+
function getPayloadValidator(eventType, schemaVersion) {
|
|
149
|
+
const cacheKey = `${eventType}@${schemaVersion}`;
|
|
150
|
+
const cached = payloadValidatorCache.get(cacheKey);
|
|
151
|
+
if (cached)
|
|
152
|
+
return cached;
|
|
153
|
+
const registration = (0, registry_1.getEventTypeRegistration)(eventType, (0, registry_1.loadRegistry)());
|
|
154
|
+
if (!registration) {
|
|
155
|
+
throw new PayloadSchemaUnavailableError(eventType, schemaVersion);
|
|
156
|
+
}
|
|
157
|
+
const versionEntry = registration.schema_versions.find((v) => v.version === schemaVersion);
|
|
158
|
+
if (!versionEntry || !versionEntry.payload_schema) {
|
|
159
|
+
throw new PayloadSchemaUnavailableError(eventType, schemaVersion);
|
|
160
|
+
}
|
|
161
|
+
// The registry stores the payload-schema path rooted at `contracts/`
|
|
162
|
+
// exactly as the coordination repo does. The dispatcher reads it from the
|
|
163
|
+
// bundled contracts tree (resolveContractPath handles the layout
|
|
164
|
+
// waterfall, including the sibling coordination repo fallback).
|
|
165
|
+
const schemaPath = (0, resolve_contract_path_1.resolveContractPath)(__dirname, versionEntry.payload_schema);
|
|
166
|
+
const raw = (0, node_fs_1.readFileSync)(schemaPath, "utf8");
|
|
167
|
+
const schema = JSON.parse(raw);
|
|
168
|
+
const validator = ajv.compile(schema);
|
|
169
|
+
payloadValidatorCache.set(cacheKey, validator);
|
|
170
|
+
return validator;
|
|
171
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@sguild/dispatcher",
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"description": "Cross-domain event dispatcher SDK for Sguild domains, per the Sguild Event Envelope contract and ADR-0009. Producer-side transactional emit, consumer-side polling worker with dedup/retry/dead-letter, envelope and payload validation against the bundled contracts tree.",
|
|
5
|
+
"license": "UNLICENSED",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/sguild-admin/platform.git",
|
|
9
|
+
"directory": "lib/dispatcher"
|
|
10
|
+
},
|
|
11
|
+
"main": "dist/index.js",
|
|
12
|
+
"types": "dist/index.d.ts",
|
|
13
|
+
"exports": {
|
|
14
|
+
".": {
|
|
15
|
+
"types": "./dist/index.d.ts",
|
|
16
|
+
"default": "./dist/index.js"
|
|
17
|
+
},
|
|
18
|
+
"./package.json": "./package.json"
|
|
19
|
+
},
|
|
20
|
+
"files": [
|
|
21
|
+
"dist",
|
|
22
|
+
"contracts",
|
|
23
|
+
"README.md"
|
|
24
|
+
],
|
|
25
|
+
"scripts": {
|
|
26
|
+
"build": "tsc -p tsconfig.json",
|
|
27
|
+
"prepublishOnly": "npm run build"
|
|
28
|
+
},
|
|
29
|
+
"engines": {
|
|
30
|
+
"node": ">=20"
|
|
31
|
+
},
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"ajv": "^8.17.1",
|
|
34
|
+
"ajv-formats": "^3.0.1",
|
|
35
|
+
"pg": "^8.17.2"
|
|
36
|
+
},
|
|
37
|
+
"peerDependencies": {
|
|
38
|
+
"@prisma/client": ">=7"
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"@types/node": "^20",
|
|
42
|
+
"@types/pg": "^8.16.0",
|
|
43
|
+
"typescript": "^5.2.2"
|
|
44
|
+
},
|
|
45
|
+
"publishConfig": {
|
|
46
|
+
"access": "public"
|
|
47
|
+
}
|
|
48
|
+
}
|