@webwaka/core 1.3.0 → 1.3.2
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.
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Canonical event contracts for the entire WebWaka OS v4 platform.
|
|
6
6
|
* Every domain emits typed DomainEvents; consumers subscribe by event type.
|
|
7
7
|
*
|
|
8
|
-
* This module defines shapes and
|
|
8
|
+
* This module defines shapes, constants, and the emitEvent utility.
|
|
9
9
|
* Actual queue/bus wiring (Cloudflare Queues) is a separate concern.
|
|
10
10
|
*/
|
|
11
11
|
/**
|
|
@@ -61,4 +61,30 @@ export interface DomainEvent<T = unknown> {
|
|
|
61
61
|
* @param payload Domain-specific payload.
|
|
62
62
|
*/
|
|
63
63
|
export declare function createEvent<T>(type: WebWakaEventType, tenantId: string, payload: T): DomainEvent<T>;
|
|
64
|
+
/**
|
|
65
|
+
* KV-backed event bus environment interface.
|
|
66
|
+
* Any Worker that needs to emit events must include these bindings.
|
|
67
|
+
*/
|
|
68
|
+
export interface EventBusEnv {
|
|
69
|
+
/** KV namespace for outbound event queue (write-only from emitter side) */
|
|
70
|
+
EVENTS?: KVNamespace;
|
|
71
|
+
/** Optional HTTP endpoint to forward events to a central event router */
|
|
72
|
+
EVENT_BUS_URL?: string;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* emitEvent — Publish a domain event to the platform event bus.
|
|
76
|
+
*
|
|
77
|
+
* Strategy:
|
|
78
|
+
* 1. Write to EVENTS KV namespace as an outbox entry (TTL 24h)
|
|
79
|
+
* 2. If EVENT_BUS_URL is set, also forward via HTTP POST (fire-and-forget)
|
|
80
|
+
*
|
|
81
|
+
* This function NEVER throws — failures are logged and swallowed so that
|
|
82
|
+
* the calling business logic is never blocked by event bus unavailability.
|
|
83
|
+
*
|
|
84
|
+
* @param env Worker environment bindings (must include EVENTS KV)
|
|
85
|
+
* @param eventType Canonical event type string (e.g. "civic.member.created")
|
|
86
|
+
* @param tenantId Tenant that owns this event
|
|
87
|
+
* @param payload Domain-specific payload (must be JSON-serialisable)
|
|
88
|
+
*/
|
|
89
|
+
export declare function emitEvent(env: EventBusEnv, eventType: string, tenantId: string, payload: unknown): Promise<void>;
|
|
64
90
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/events/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH;;;;;GAKG;AACH,oBAAY,gBAAgB;IAE1B,eAAe,oBAAoB;IACnC,gBAAgB,qBAAqB;IACrC,oBAAoB,yBAAyB;IAG7C,aAAa,kBAAkB;IAC/B,YAAY,iBAAiB;IAC7B,YAAY,iBAAiB;IAG7B,iBAAiB,sBAAsB;IACvC,iBAAiB,sBAAsB;IAGvC,iBAAiB,sBAAsB;IACvC,oBAAoB,yBAAyB;IAG7C,gBAAgB,qBAAqB;IACrC,eAAe,oBAAoB;IAGnC,sBAAsB,2BAA2B;IACjD,uBAAuB,4BAA4B;IAGnD,iBAAiB,sBAAsB;IACvC,mBAAmB,wBAAwB;CAC5C;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,WAAW,CAAC,CAAC,GAAG,OAAO;IACtC,yCAAyC;IACzC,EAAE,EAAE,MAAM,CAAC;IACX,kEAAkE;IAClE,IAAI,EAAE,gBAAgB,CAAC;IACvB,uCAAuC;IACvC,QAAQ,EAAE,MAAM,CAAC;IACjB,6CAA6C;IAC7C,UAAU,EAAE,IAAI,CAAC;IACjB,+BAA+B;IAC/B,OAAO,EAAE,CAAC,CAAC;CACZ;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAC3B,IAAI,EAAE,gBAAgB,EACtB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,CAAC,GACT,WAAW,CAAC,CAAC,CAAC,CAQhB"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/events/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH;;;;;GAKG;AACH,oBAAY,gBAAgB;IAE1B,eAAe,oBAAoB;IACnC,gBAAgB,qBAAqB;IACrC,oBAAoB,yBAAyB;IAG7C,aAAa,kBAAkB;IAC/B,YAAY,iBAAiB;IAC7B,YAAY,iBAAiB;IAG7B,iBAAiB,sBAAsB;IACvC,iBAAiB,sBAAsB;IAGvC,iBAAiB,sBAAsB;IACvC,oBAAoB,yBAAyB;IAG7C,gBAAgB,qBAAqB;IACrC,eAAe,oBAAoB;IAGnC,sBAAsB,2BAA2B;IACjD,uBAAuB,4BAA4B;IAGnD,iBAAiB,sBAAsB;IACvC,mBAAmB,wBAAwB;CAC5C;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,WAAW,CAAC,CAAC,GAAG,OAAO;IACtC,yCAAyC;IACzC,EAAE,EAAE,MAAM,CAAC;IACX,kEAAkE;IAClE,IAAI,EAAE,gBAAgB,CAAC;IACvB,uCAAuC;IACvC,QAAQ,EAAE,MAAM,CAAC;IACjB,6CAA6C;IAC7C,UAAU,EAAE,IAAI,CAAC;IACjB,+BAA+B;IAC/B,OAAO,EAAE,CAAC,CAAC;CACZ;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAC3B,IAAI,EAAE,gBAAgB,EACtB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,CAAC,GACT,WAAW,CAAC,CAAC,CAAC,CAQhB;AAED;;;GAGG;AACH,MAAM,WAAW,WAAW;IAC1B,2EAA2E;IAC3E,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,yEAAyE;IACzE,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,SAAS,CAC7B,GAAG,EAAE,WAAW,EAChB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,OAAO,GACf,OAAO,CAAC,IAAI,CAAC,CAiCf"}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Canonical event contracts for the entire WebWaka OS v4 platform.
|
|
6
6
|
* Every domain emits typed DomainEvents; consumers subscribe by event type.
|
|
7
7
|
*
|
|
8
|
-
* This module defines shapes and
|
|
8
|
+
* This module defines shapes, constants, and the emitEvent utility.
|
|
9
9
|
* Actual queue/bus wiring (Cloudflare Queues) is a separate concern.
|
|
10
10
|
*/
|
|
11
11
|
/**
|
|
@@ -57,4 +57,53 @@ export function createEvent(type, tenantId, payload) {
|
|
|
57
57
|
payload,
|
|
58
58
|
};
|
|
59
59
|
}
|
|
60
|
+
/**
|
|
61
|
+
* emitEvent — Publish a domain event to the platform event bus.
|
|
62
|
+
*
|
|
63
|
+
* Strategy:
|
|
64
|
+
* 1. Write to EVENTS KV namespace as an outbox entry (TTL 24h)
|
|
65
|
+
* 2. If EVENT_BUS_URL is set, also forward via HTTP POST (fire-and-forget)
|
|
66
|
+
*
|
|
67
|
+
* This function NEVER throws — failures are logged and swallowed so that
|
|
68
|
+
* the calling business logic is never blocked by event bus unavailability.
|
|
69
|
+
*
|
|
70
|
+
* @param env Worker environment bindings (must include EVENTS KV)
|
|
71
|
+
* @param eventType Canonical event type string (e.g. "civic.member.created")
|
|
72
|
+
* @param tenantId Tenant that owns this event
|
|
73
|
+
* @param payload Domain-specific payload (must be JSON-serialisable)
|
|
74
|
+
*/
|
|
75
|
+
export async function emitEvent(env, eventType, tenantId, payload) {
|
|
76
|
+
const event = {
|
|
77
|
+
id: crypto.randomUUID(),
|
|
78
|
+
type: eventType,
|
|
79
|
+
tenantId,
|
|
80
|
+
occurredAt: new Date().toISOString(),
|
|
81
|
+
payload,
|
|
82
|
+
};
|
|
83
|
+
const key = `event:${Date.now()}:${crypto.randomUUID()}`;
|
|
84
|
+
const body = JSON.stringify(event);
|
|
85
|
+
// 1. Write to KV outbox
|
|
86
|
+
if (env.EVENTS) {
|
|
87
|
+
try {
|
|
88
|
+
await env.EVENTS.put(key, body, { expirationTtl: 86400 });
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
// Non-fatal — continue to HTTP delivery
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
// 2. HTTP delivery (fire-and-forget)
|
|
95
|
+
if (env.EVENT_BUS_URL) {
|
|
96
|
+
try {
|
|
97
|
+
await fetch(env.EVENT_BUS_URL, {
|
|
98
|
+
method: 'POST',
|
|
99
|
+
headers: { 'Content-Type': 'application/json' },
|
|
100
|
+
body,
|
|
101
|
+
signal: AbortSignal.timeout(5000),
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
// Non-fatal — event is already in KV outbox
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
60
109
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/core/events/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH;;;;;GAKG;AACH,MAAM,CAAN,IAAY,gBA8BX;AA9BD,WAAY,gBAAgB;IAC1B,8EAA8E;IAC9E,uDAAmC,CAAA;IACnC,yDAAqC,CAAA;IACrC,iEAA6C,CAAA;IAE7C,8EAA8E;IAC9E,mDAA+B,CAAA;IAC/B,iDAA6B,CAAA;IAC7B,iDAA6B,CAAA;IAE7B,8EAA8E;IAC9E,2DAAuC,CAAA;IACvC,2DAAuC,CAAA;IAEvC,8EAA8E;IAC9E,2DAAuC,CAAA;IACvC,iEAA6C,CAAA;IAE7C,8EAA8E;IAC9E,yDAAqC,CAAA;IACrC,uDAAmC,CAAA;IAEnC,8EAA8E;IAC9E,qEAAiD,CAAA;IACjD,uEAAmD,CAAA;IAEnD,8EAA8E;IAC9E,2DAAuC,CAAA;IACvC,+DAA2C,CAAA;AAC7C,CAAC,EA9BW,gBAAgB,KAAhB,gBAAgB,QA8B3B;AAuBD;;;;;;;GAOG;AACH,MAAM,UAAU,WAAW,CACzB,IAAsB,EACtB,QAAgB,EAChB,OAAU;IAEV,OAAO;QACL,EAAE,EAAE,MAAM,CAAC,UAAU,EAAE;QACvB,IAAI;QACJ,QAAQ;QACR,UAAU,EAAE,IAAI,IAAI,EAAE;QACtB,OAAO;KACR,CAAC;AACJ,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/core/events/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH;;;;;GAKG;AACH,MAAM,CAAN,IAAY,gBA8BX;AA9BD,WAAY,gBAAgB;IAC1B,8EAA8E;IAC9E,uDAAmC,CAAA;IACnC,yDAAqC,CAAA;IACrC,iEAA6C,CAAA;IAE7C,8EAA8E;IAC9E,mDAA+B,CAAA;IAC/B,iDAA6B,CAAA;IAC7B,iDAA6B,CAAA;IAE7B,8EAA8E;IAC9E,2DAAuC,CAAA;IACvC,2DAAuC,CAAA;IAEvC,8EAA8E;IAC9E,2DAAuC,CAAA;IACvC,iEAA6C,CAAA;IAE7C,8EAA8E;IAC9E,yDAAqC,CAAA;IACrC,uDAAmC,CAAA;IAEnC,8EAA8E;IAC9E,qEAAiD,CAAA;IACjD,uEAAmD,CAAA;IAEnD,8EAA8E;IAC9E,2DAAuC,CAAA;IACvC,+DAA2C,CAAA;AAC7C,CAAC,EA9BW,gBAAgB,KAAhB,gBAAgB,QA8B3B;AAuBD;;;;;;;GAOG;AACH,MAAM,UAAU,WAAW,CACzB,IAAsB,EACtB,QAAgB,EAChB,OAAU;IAEV,OAAO;QACL,EAAE,EAAE,MAAM,CAAC,UAAU,EAAE;QACvB,IAAI;QACJ,QAAQ;QACR,UAAU,EAAE,IAAI,IAAI,EAAE;QACtB,OAAO;KACR,CAAC;AACJ,CAAC;AAaD;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAC7B,GAAgB,EAChB,SAAiB,EACjB,QAAgB,EAChB,OAAgB;IAEhB,MAAM,KAAK,GAAG;QACZ,EAAE,EAAE,MAAM,CAAC,UAAU,EAAE;QACvB,IAAI,EAAE,SAAS;QACf,QAAQ;QACR,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACpC,OAAO;KACR,CAAC;IACF,MAAM,GAAG,GAAG,SAAS,IAAI,CAAC,GAAG,EAAE,IAAI,MAAM,CAAC,UAAU,EAAE,EAAE,CAAC;IACzD,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IAEnC,wBAAwB;IACxB,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC;QACf,IAAI,CAAC;YACH,MAAM,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,aAAa,EAAE,KAAK,EAAE,CAAC,CAAC;QAC5D,CAAC;QAAC,MAAM,CAAC;YACP,wCAAwC;QAC1C,CAAC;IACH,CAAC;IAED,qCAAqC;IACrC,IAAI,GAAG,CAAC,aAAa,EAAE,CAAC;QACtB,IAAI,CAAC;YACH,MAAM,KAAK,CAAC,GAAG,CAAC,aAAa,EAAE;gBAC7B,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;gBAC/C,IAAI;gBACJ,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC;aAClC,CAAC,CAAC;QACL,CAAC;QAAC,MAAM,CAAC;YACP,4CAA4C;QAC9C,CAAC;IACH,CAAC;AACH,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webwaka/core",
|
|
3
|
-
"version": "1.3.
|
|
4
|
-
"description": "WebWaka OS v4
|
|
3
|
+
"version": "1.3.2",
|
|
4
|
+
"description": "WebWaka OS v4 \u2014 Shared platform primitives: auth, RBAC, CORS, rate-limiting, event bus types, and billing utilities.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
7
7
|
"types": "./dist/index.d.ts",
|
|
@@ -59,6 +59,14 @@
|
|
|
59
59
|
"types": "./dist/core/booking/index.d.ts"
|
|
60
60
|
}
|
|
61
61
|
},
|
|
62
|
+
"scripts": {
|
|
63
|
+
"build": "tsc",
|
|
64
|
+
"prepare": "tsc",
|
|
65
|
+
"test": "vitest run",
|
|
66
|
+
"test:watch": "vitest",
|
|
67
|
+
"lint": "tsc --noEmit",
|
|
68
|
+
"prepublishOnly": "pnpm run build"
|
|
69
|
+
},
|
|
62
70
|
"peerDependencies": {
|
|
63
71
|
"hono": ">=4.0.0"
|
|
64
72
|
},
|
|
@@ -89,11 +97,5 @@
|
|
|
89
97
|
"repository": {
|
|
90
98
|
"type": "git",
|
|
91
99
|
"url": "https://github.com/WebWakaDOS/webwaka-core.git"
|
|
92
|
-
},
|
|
93
|
-
"scripts": {
|
|
94
|
-
"build": "tsc",
|
|
95
|
-
"test": "vitest run",
|
|
96
|
-
"test:watch": "vitest",
|
|
97
|
-
"lint": "tsc --noEmit"
|
|
98
100
|
}
|
|
99
101
|
}
|
package/src/core/events/index.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Canonical event contracts for the entire WebWaka OS v4 platform.
|
|
6
6
|
* Every domain emits typed DomainEvents; consumers subscribe by event type.
|
|
7
7
|
*
|
|
8
|
-
* This module defines shapes and
|
|
8
|
+
* This module defines shapes, constants, and the emitEvent utility.
|
|
9
9
|
* Actual queue/bus wiring (Cloudflare Queues) is a separate concern.
|
|
10
10
|
*/
|
|
11
11
|
|
|
@@ -89,3 +89,69 @@ export function createEvent<T>(
|
|
|
89
89
|
payload,
|
|
90
90
|
};
|
|
91
91
|
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* KV-backed event bus environment interface.
|
|
95
|
+
* Any Worker that needs to emit events must include these bindings.
|
|
96
|
+
*/
|
|
97
|
+
export interface EventBusEnv {
|
|
98
|
+
/** KV namespace for outbound event queue (write-only from emitter side) */
|
|
99
|
+
EVENTS?: KVNamespace;
|
|
100
|
+
/** Optional HTTP endpoint to forward events to a central event router */
|
|
101
|
+
EVENT_BUS_URL?: string;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* emitEvent — Publish a domain event to the platform event bus.
|
|
106
|
+
*
|
|
107
|
+
* Strategy:
|
|
108
|
+
* 1. Write to EVENTS KV namespace as an outbox entry (TTL 24h)
|
|
109
|
+
* 2. If EVENT_BUS_URL is set, also forward via HTTP POST (fire-and-forget)
|
|
110
|
+
*
|
|
111
|
+
* This function NEVER throws — failures are logged and swallowed so that
|
|
112
|
+
* the calling business logic is never blocked by event bus unavailability.
|
|
113
|
+
*
|
|
114
|
+
* @param env Worker environment bindings (must include EVENTS KV)
|
|
115
|
+
* @param eventType Canonical event type string (e.g. "civic.member.created")
|
|
116
|
+
* @param tenantId Tenant that owns this event
|
|
117
|
+
* @param payload Domain-specific payload (must be JSON-serialisable)
|
|
118
|
+
*/
|
|
119
|
+
export async function emitEvent(
|
|
120
|
+
env: EventBusEnv,
|
|
121
|
+
eventType: string,
|
|
122
|
+
tenantId: string,
|
|
123
|
+
payload: unknown,
|
|
124
|
+
): Promise<void> {
|
|
125
|
+
const event = {
|
|
126
|
+
id: crypto.randomUUID(),
|
|
127
|
+
type: eventType,
|
|
128
|
+
tenantId,
|
|
129
|
+
occurredAt: new Date().toISOString(),
|
|
130
|
+
payload,
|
|
131
|
+
};
|
|
132
|
+
const key = `event:${Date.now()}:${crypto.randomUUID()}`;
|
|
133
|
+
const body = JSON.stringify(event);
|
|
134
|
+
|
|
135
|
+
// 1. Write to KV outbox
|
|
136
|
+
if (env.EVENTS) {
|
|
137
|
+
try {
|
|
138
|
+
await env.EVENTS.put(key, body, { expirationTtl: 86400 });
|
|
139
|
+
} catch {
|
|
140
|
+
// Non-fatal — continue to HTTP delivery
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// 2. HTTP delivery (fire-and-forget)
|
|
145
|
+
if (env.EVENT_BUS_URL) {
|
|
146
|
+
try {
|
|
147
|
+
await fetch(env.EVENT_BUS_URL, {
|
|
148
|
+
method: 'POST',
|
|
149
|
+
headers: { 'Content-Type': 'application/json' },
|
|
150
|
+
body,
|
|
151
|
+
signal: AbortSignal.timeout(5000),
|
|
152
|
+
});
|
|
153
|
+
} catch {
|
|
154
|
+
// Non-fatal — event is already in KV outbox
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|