equipped 5.0.32 → 5.0.34
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/CHANGELOG.md +9 -0
- package/dist/cjs/audit/events.cjs +28 -27
- package/dist/cjs/audit/events.cjs.map +1 -1
- package/dist/cjs/audit/events.min.cjs +1 -1
- package/dist/cjs/audit/events.min.cjs.map +1 -1
- package/dist/cjs/instance/index.cjs +4 -0
- package/dist/cjs/instance/index.cjs.map +1 -1
- package/dist/cjs/instance/index.min.cjs +2 -2
- package/dist/cjs/instance/index.min.cjs.map +1 -1
- package/dist/esm/audit/events.min.mjs +1 -1
- package/dist/esm/audit/events.min.mjs.map +1 -1
- package/dist/esm/audit/events.mjs +27 -26
- package/dist/esm/audit/events.mjs.map +1 -1
- package/dist/esm/instance/index.min.mjs +2 -2
- package/dist/esm/instance/index.min.mjs.map +1 -1
- package/dist/esm/instance/index.mjs +4 -0
- package/dist/esm/instance/index.mjs.map +1 -1
- package/dist/types/audit/events.js +27 -26
- package/dist/types/audit/index.d.ts +18 -21
- package/dist/types/instance/index.d.ts +1 -0
- package/dist/types/instance/index.js +4 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
|
4
4
|
|
|
5
|
+
### [5.0.34](https://github.com/kevinand11/equipped/compare/v5.0.33...v5.0.34) (2025-10-03)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
* audit context with userId ([d5ecd16](https://github.com/kevinand11/equipped/commit/d5ecd167d7d794cef4c9f994f6c90bd950b9aba6))
|
|
11
|
+
|
|
12
|
+
### [5.0.33](https://github.com/kevinand11/equipped/compare/v5.0.32...v5.0.33) (2025-10-02)
|
|
13
|
+
|
|
5
14
|
### [5.0.32](https://github.com/kevinand11/equipped/compare/v5.0.31...v5.0.32) (2025-10-02)
|
|
6
15
|
|
|
7
16
|
|
|
@@ -1,27 +1,26 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports, "__esModule", {value: true});var
|
|
2
|
-
var _valleyed = require('valleyed');
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } }var _valleyed = require('valleyed');
|
|
3
2
|
var _indexcjs = require('../dbs/index.cjs');
|
|
4
3
|
var _indexcjs3 = require('../errors/index.cjs');
|
|
4
|
+
var _indexcjs5 = require('../instance/index.cjs');
|
|
5
5
|
class EventAudit {
|
|
6
|
-
constructor(db, dbName
|
|
6
|
+
constructor(db, dbName) {;EventAudit.prototype.__init.call(this);
|
|
7
7
|
this.db = db;
|
|
8
|
-
this.handlers = handlers;
|
|
9
8
|
this.table = db.use({
|
|
10
9
|
db: dbName,
|
|
11
10
|
col: "__audits",
|
|
12
11
|
mapper: (model) => ({ ...model, toJSON: () => model }),
|
|
13
12
|
options: { skipAudit: true }
|
|
14
13
|
});
|
|
15
|
-
for (const key in handlers) _valleyed.v.compile(handlers[key].pipe);
|
|
16
14
|
}
|
|
17
15
|
|
|
18
|
-
|
|
19
|
-
|
|
16
|
+
__init() {this.handles = {}}
|
|
17
|
+
async #createEvent(type, payload, mode, context) {
|
|
18
|
+
const handler = this.handles[type];
|
|
20
19
|
if (!handler) throw new (0, _indexcjs3.EquippedError)("audit handler not found", { type, payload, mode });
|
|
21
20
|
const validPayload = _valleyed.v.assert(handler.pipe, payload);
|
|
22
|
-
const key =
|
|
21
|
+
const key = _indexcjs5.Instance.createId();
|
|
23
22
|
const now = /* @__PURE__ */ new Date();
|
|
24
|
-
|
|
23
|
+
return await this.table.insertOne(
|
|
25
24
|
{
|
|
26
25
|
key,
|
|
27
26
|
type,
|
|
@@ -29,17 +28,17 @@ class EventAudit {
|
|
|
29
28
|
ts: now.getTime(),
|
|
30
29
|
payload: validPayload,
|
|
31
30
|
status: "pending",
|
|
31
|
+
userId: _nullishCoalesce(context.userId, () => ( null)),
|
|
32
32
|
error: null,
|
|
33
33
|
startedAt: null,
|
|
34
34
|
completedAt: null
|
|
35
35
|
},
|
|
36
36
|
{ getTime: () => now, makeId: () => key }
|
|
37
37
|
);
|
|
38
|
-
return audit;
|
|
39
38
|
}
|
|
40
39
|
async #processEvent(event) {
|
|
41
40
|
return this.db.session(async () => {
|
|
42
|
-
const handler = this.
|
|
41
|
+
const handler = this.handles[event.type];
|
|
43
42
|
if (!handler) throw new (0, _indexcjs3.EquippedError)("audit handler not found", { event });
|
|
44
43
|
try {
|
|
45
44
|
await this.table.updateOne(
|
|
@@ -47,8 +46,9 @@ class EventAudit {
|
|
|
47
46
|
{ $set: { status: "processing", startedAt: Date.now(), completedAt: null, error: null } }
|
|
48
47
|
);
|
|
49
48
|
const result = await handler.handle(event.payload, {
|
|
50
|
-
|
|
51
|
-
|
|
49
|
+
key: event.key,
|
|
50
|
+
userId: event.userId,
|
|
51
|
+
date: new Date(event.ts)
|
|
52
52
|
});
|
|
53
53
|
await this.table.updateOne({ key: event.key }, { $set: { status: "done", completedAt: Date.now() } });
|
|
54
54
|
return result;
|
|
@@ -59,15 +59,6 @@ class EventAudit {
|
|
|
59
59
|
}
|
|
60
60
|
});
|
|
61
61
|
}
|
|
62
|
-
async createSync(type, payload) {
|
|
63
|
-
const event = await this.#createEvent(type, payload, "sync");
|
|
64
|
-
return this.#processEvent(event);
|
|
65
|
-
}
|
|
66
|
-
async createAsync(type, payload) {
|
|
67
|
-
const event = await this.#createEvent(type, payload, "async");
|
|
68
|
-
this.#processEvent(event).catch(() => {
|
|
69
|
-
});
|
|
70
|
-
}
|
|
71
62
|
async replay(from) {
|
|
72
63
|
const { results: events } = await this.table.query(
|
|
73
64
|
_indexcjs.wrapQueryParams.call(void 0, {
|
|
@@ -83,11 +74,21 @@ class EventAudit {
|
|
|
83
74
|
if (!event) throw new (0, _indexcjs3.EquippedError)("audit event not found", { key });
|
|
84
75
|
await this.#processEvent(event);
|
|
85
76
|
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
return {
|
|
77
|
+
register(type, handle) {
|
|
78
|
+
if (this.handles[type]) throw new (0, _indexcjs3.EquippedError)(`${type} already has a registered handler`, {});
|
|
79
|
+
this.handles[type] = handle;
|
|
80
|
+
_valleyed.v.compile(handle.pipe);
|
|
81
|
+
return {
|
|
82
|
+
sync: async (payload, context) => {
|
|
83
|
+
const event = await this.#createEvent(type, payload, "sync", context);
|
|
84
|
+
return this.#processEvent(event);
|
|
85
|
+
},
|
|
86
|
+
async: async (payload, context) => {
|
|
87
|
+
const event = await this.#createEvent(type, payload, "async", context);
|
|
88
|
+
this.#processEvent(event).catch(() => {
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
};
|
|
91
92
|
}
|
|
92
93
|
}
|
|
93
94
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/audit/events.ts","/home/runner/work/equipped/equipped/dist/cjs/audit/events.cjs"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"sources":["../../../src/audit/events.ts","/home/runner/work/equipped/equipped/dist/cjs/audit/events.cjs"],"names":[],"mappings":"AAAA,iNAA+C;AAE/C,4CAAuD;AACvD,gDAA8B;AAC9B,kDAAyB;AA2BlB,MAAM,WAAW;AAAA,EAIvB,WAAA,CACS,EAAA,EACR,MAAA,EACC;AAFO,IAAA,IAAA,CAAA,GAAA,EAAA,EAAA;AAGR,IAAA,IAAA,CAAK,MAAA,EAAQ,EAAA,CAAG,GAAA,CAAI;AAAA,MACnB,EAAA,EAAI,MAAA;AAAA,MACJ,GAAA,EAAK,UAAA;AAAA,MACL,MAAA,EAAQ,CAAC,KAAA,EAAA,GAAA,CAAW,EAAE,GAAG,KAAA,EAAO,MAAA,EAAQ,CAAA,EAAA,GAAM,MAAiC,CAAA,CAAA;AAAA,MAC/E,OAAA,EAAS,EAAE,SAAA,EAAW,KAAK;AAAA,IAC5B,CAAC,CAAA;AAAA,EACF;AAAA,EAbQ;AAAA,iBACA,QAAA,EAAqD,CAAC,EAAA;AAAA,EAc9D,MAAM,CAAA,WAAA,CAAa,IAAA,EAAc,OAAA,EAAkB,IAAA,EAAwB,OAAA,EAAkB;AAC5F,IAAA,MAAM,QAAA,EAAU,IAAA,CAAK,OAAA,CAAQ,IAAI,CAAA;AACjC,IAAA,GAAA,CAAI,CAAC,OAAA,EAAS,MAAM,IAAI,6BAAA,CAAc,yBAAA,EAA2B,EAAE,IAAA,EAAM,OAAA,EAAS,KAAK,CAAC,CAAA;AAExF,IAAA,MAAM,aAAA,EAAe,WAAA,CAAE,MAAA,CAAO,OAAA,CAAQ,IAAA,EAAM,OAAO,CAAA;AACnD,IAAA,MAAM,IAAA,EAAM,mBAAA,CAAS,QAAA,CAAS,CAAA;AAC9B,IAAA,MAAM,IAAA,kBAAM,IAAI,IAAA,CAAK,CAAA;AAErB,IAAA,OAAO,MAAM,IAAA,CAAK,KAAA,CAAM,SAAA;AAAA,MACvB;AAAA,QACC,GAAA;AAAA,QACA,IAAA;AAAA,QACA,IAAA;AAAA,QACA,EAAA,EAAI,GAAA,CAAI,OAAA,CAAQ,CAAA;AAAA,QAChB,OAAA,EAAS,YAAA;AAAA,QACT,MAAA,EAAQ,SAAA;AAAA,QACR,MAAA,mBAAQ,OAAA,CAAQ,MAAA,UAAU,MAAA;AAAA,QAC1B,KAAA,EAAO,IAAA;AAAA,QACP,SAAA,EAAW,IAAA;AAAA,QACX,WAAA,EAAa;AAAA,MACd,CAAA;AAAA,MACA,EAAE,OAAA,EAAS,CAAA,EAAA,GAAM,GAAA,EAAK,MAAA,EAAQ,CAAA,EAAA,GAAM,IAAI;AAAA,IACzC,CAAA;AAAA,EACD;AAAA,EAEA,MAAM,CAAA,YAAA,CAAiB,KAAA,EAAiB;AACvC,IAAA,OAAO,IAAA,CAAK,EAAA,CAAG,OAAA,CAAQ,MAAA,CAAA,EAAA,GAAY;AAClC,MAAA,MAAM,QAAA,EAAU,IAAA,CAAK,OAAA,CAAQ,KAAA,CAAM,IAAI,CAAA;AACvC,MAAA,GAAA,CAAI,CAAC,OAAA,EAAS,MAAM,IAAI,6BAAA,CAAc,yBAAA,EAA2B,EAAE,MAAM,CAAC,CAAA;AAC1E,MAAA,IAAI;AACH,QAAA,MAAM,IAAA,CAAK,KAAA,CAAM,SAAA;AAAA,UAChB,EAAE,GAAA,EAAK,KAAA,CAAM,IAAI,CAAA;AAAA,UACjB,EAAE,IAAA,EAAM,EAAE,MAAA,EAAQ,YAAA,EAAc,SAAA,EAAW,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,WAAA,EAAa,IAAA,EAAM,KAAA,EAAO,KAAK,EAAE;AAAA,QACzF,CAAA;AACA,QAAA,MAAM,OAAA,EAAS,MAAM,OAAA,CAAQ,MAAA,CAAO,KAAA,CAAM,OAAA,EAAS;AAAA,UAClD,GAAA,EAAK,KAAA,CAAM,GAAA;AAAA,UACX,MAAA,EAAQ,KAAA,CAAM,MAAA;AAAA,UACd,IAAA,EAAM,IAAI,IAAA,CAAK,KAAA,CAAM,EAAE;AAAA,QACxB,CAAC,CAAA;AACD,QAAA,MAAM,IAAA,CAAK,KAAA,CAAM,SAAA,CAAU,EAAE,GAAA,EAAK,KAAA,CAAM,IAAI,CAAA,EAAG,EAAE,IAAA,EAAM,EAAE,MAAA,EAAQ,MAAA,EAAQ,WAAA,EAAa,IAAA,CAAK,GAAA,CAAI,EAAE,EAAE,CAAC,CAAA;AACpG,QAAA,OAAO,MAAA;AAAA,MACR,EAAA,MAAA,CAAS,GAAA,EAAK;AACb,QAAA,MAAM,QAAA,EAAU,IAAA,WAAe,MAAA,EAAQ,GAAA,CAAI,QAAA,EAAU,MAAA,CAAO,GAAG,CAAA;AAC/D,QAAA,MAAM,IAAA,CAAK,KAAA,CAAM,SAAA,CAAU,EAAE,GAAA,EAAK,KAAA,CAAM,IAAI,CAAA,EAAG,EAAE,IAAA,EAAM,EAAE,MAAA,EAAQ,QAAA,EAAU,KAAA,EAAO,OAAA,EAAS,WAAA,EAAa,IAAA,CAAK,GAAA,CAAI,EAAE,EAAE,CAAC,CAAA;AACtH,QAAA,MAAM,GAAA;AAAA,MACP;AAAA,IACD,CAAC,CAAA;AAAA,EACF;AAAA,EAEA,MAAM,MAAA,CAAO,IAAA,EAAa;AACzB,IAAA,MAAM,EAAE,OAAA,EAAS,OAAO,EAAA,EAAI,MAAM,IAAA,CAAK,KAAA,CAAM,KAAA;AAAA,MAC5C,uCAAA;AAAgB,QACf,KAAA,EAAO,CAAC,GAAI,KAAA,EAAO,CAAC,EAAE,KAAA,EAAO,IAAA,EAAM,KAAA,EAAO,IAAA,CAAK,OAAA,CAAQ,CAAA,EAAG,SAAA,EAAW,oBAAA,CAAW,IAAI,CAAC,EAAA,EAAI,CAAC,CAAE,CAAA;AAAA,QAC5F,IAAA,EAAM,CAAC,EAAE,KAAA,EAAO,IAAA,EAAM,IAAA,EAAM,MAAM,CAAC,CAAA;AAAA,QACnC,GAAA,EAAK;AAAA,MACN,CAAC;AAAA,IACF,CAAA;AACA,IAAA,IAAA,CAAA,MAAW,MAAA,GAAS,MAAA,EAAQ,MAAM,IAAA,CAAK,CAAA,YAAA,CAAc,KAAK,CAAA;AAAA,EAC3D;AAAA,EAEA,MAAM,KAAA,CAAM,GAAA,EAAa;AACxB,IAAA,MAAM,MAAA,EAAQ,MAAM,IAAA,CAAK,KAAA,CAAM,OAAA,CAAQ,EAAE,IAAI,CAAC,CAAA;AAC9C,IAAA,GAAA,CAAI,CAAC,KAAA,EAAO,MAAM,IAAI,6BAAA,CAAc,uBAAA,EAAyB,EAAE,IAAI,CAAC,CAAA;AACpE,IAAA,MAAM,IAAA,CAAK,CAAA,YAAA,CAAc,KAAK,CAAA;AAAA,EAC/B;AAAA,EAEA,QAAA,CAAsC,IAAA,EAAc,MAAA,EAA+B;AAClF,IAAA,GAAA,CAAI,IAAA,CAAK,OAAA,CAAQ,IAAI,CAAA,EAAG,MAAM,IAAI,6BAAA,CAAc,CAAA,EAAA;AAC3B,IAAA;AACA,IAAA;AACd,IAAA;AACmD,MAAA;AACZ,QAAA;AACV,QAAA;AACnC,MAAA;AAC0D,MAAA;AACb,QAAA;AACH,QAAA;AAAE,QAAA;AAC5C,MAAA;AACD,IAAA;AACD,EAAA;AACD;ACnCqD;AACA;AACA","file":"/home/runner/work/equipped/equipped/dist/cjs/audit/events.cjs","sourcesContent":["import { Pipe, PipeInput, PipeOutput, v } from 'valleyed'\n\nimport { Conditions, Db, Table, wrapQueryParams } from '../dbs'\nimport { EquippedError } from '../errors'\nimport { Instance } from '../instance'\n\nexport type EventDefinition<P extends Pipe<any, any>, R> = {\n\tpipe: P\n\thandle: (payload: PipeOutput<P>, context: EventContext) => R | Promise<R>\n}\n\nexport type EventContext = {\n\tkey: string\n\tuserId: string | null\n\tdate: Date\n}\n\nexport type EventDoc = {\n\tkey: string\n\ttype: string\n\tts: number\n\tpayload: unknown\n\tmode: 'sync' | 'async'\n\tstatus: 'pending' | 'processing' | 'done' | 'failed'\n\tuserId: string | null\n\terror: string | null\n\tstartedAt: number | null\n\tcompletedAt: number | null\n}\ntype Context = { userId?: string }\n\nexport class EventAudit {\n\tprivate table: Table<any, EventDoc, EventDoc & { toJSON: () => Record<string, unknown> }, any>\n\tprivate handles: Record<string, EventDefinition<any, any>> = {}\n\n\tconstructor(\n\t\tprivate db: Db<any>,\n\t\tdbName: string,\n\t) {\n\t\tthis.table = db.use({\n\t\t\tdb: dbName,\n\t\t\tcol: '__audits',\n\t\t\tmapper: (model) => ({ ...model, toJSON: () => model as Record<string, unknown> }),\n\t\t\toptions: { skipAudit: true },\n\t\t})\n\t}\n\n\tasync #createEvent(type: string, payload: unknown, mode: 'sync' | 'async', context: Context) {\n\t\tconst handler = this.handles[type]\n\t\tif (!handler) throw new EquippedError('audit handler not found', { type, payload, mode })\n\n\t\tconst validPayload = v.assert(handler.pipe, payload)\n\t\tconst key = Instance.createId()\n\t\tconst now = new Date()\n\n\t\treturn await this.table.insertOne(\n\t\t\t{\n\t\t\t\tkey,\n\t\t\t\ttype,\n\t\t\t\tmode,\n\t\t\t\tts: now.getTime(),\n\t\t\t\tpayload: validPayload,\n\t\t\t\tstatus: 'pending',\n\t\t\t\tuserId: context.userId ?? null,\n\t\t\t\terror: null,\n\t\t\t\tstartedAt: null,\n\t\t\t\tcompletedAt: null,\n\t\t\t},\n\t\t\t{ getTime: () => now, makeId: () => key },\n\t\t)\n\t}\n\n\tasync #processEvent<R>(event: EventDoc) {\n\t\treturn this.db.session(async () => {\n\t\t\tconst handler = this.handles[event.type]\n\t\t\tif (!handler) throw new EquippedError('audit handler not found', { event })\n\t\t\ttry {\n\t\t\t\tawait this.table.updateOne(\n\t\t\t\t\t{ key: event.key },\n\t\t\t\t\t{ $set: { status: 'processing', startedAt: Date.now(), completedAt: null, error: null } },\n\t\t\t\t)\n\t\t\t\tconst result = await handler.handle(event.payload, {\n\t\t\t\t\tkey: event.key,\n\t\t\t\t\tuserId: event.userId,\n\t\t\t\t\tdate: new Date(event.ts),\n\t\t\t\t})\n\t\t\t\tawait this.table.updateOne({ key: event.key }, { $set: { status: 'done', completedAt: Date.now() } })\n\t\t\t\treturn result as R\n\t\t\t} catch (err) {\n\t\t\t\tconst message = err instanceof Error ? err.message : String(err)\n\t\t\t\tawait this.table.updateOne({ key: event.key }, { $set: { status: 'failed', error: message, completedAt: Date.now() } })\n\t\t\t\tthrow err\n\t\t\t}\n\t\t})\n\t}\n\n\tasync replay(from?: Date) {\n\t\tconst { results: events } = await this.table.query(\n\t\t\twrapQueryParams({\n\t\t\t\twhere: [...(from ? [{ field: 'ts', value: from.getTime(), condition: Conditions.gte }] : [])],\n\t\t\t\tsort: [{ field: 'ts', desc: false }],\n\t\t\t\tall: true,\n\t\t\t}),\n\t\t)\n\t\tfor (const event of events) await this.#processEvent(event)\n\t}\n\n\tasync rerun(key: string) {\n\t\tconst event = await this.table.findOne({ key })\n\t\tif (!event) throw new EquippedError('audit event not found', { key })\n\t\tawait this.#processEvent(event)\n\t}\n\n\tregister<P extends Pipe<any, any>, R>(type: string, handle: EventDefinition<P, R>) {\n\t\tif (this.handles[type]) throw new EquippedError(`${type} already has a registered handler`, {})\n\t\tthis.handles[type] = handle\n\t\tv.compile(handle.pipe)\n\t\treturn {\n\t\t\tsync: async (payload: PipeInput<P>, context: Context) => {\n\t\t\t\tconst event = await this.#createEvent(type, payload, 'sync', context)\n\t\t\t\treturn this.#processEvent<R>(event)\n\t\t\t},\n\t\t\tasync: async (payload: PipeInput<P>, context: Context) => {\n\t\t\t\tconst event = await this.#createEvent(type, payload, 'async', context)\n\t\t\t\tthis.#processEvent<R>(event).catch(() => {})\n\t\t\t},\n\t\t}\n\t}\n}\n",null]}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports, "__esModule", {value: true});
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } }var _valleyed = require('valleyed');var _indexmincjs = require('../dbs/index.min.cjs');var _indexmincjs3 = require('../errors/index.min.cjs');var _indexmincjs5 = require('../instance/index.min.cjs');class D{constructor(t,n){;D.prototype.__init.call(this);this.db=t;this.table=t.use({db:n,col:"__audits",mapper:e=>({...e,toJSON:()=>e}),options:{skipAudit:!0}})}__init() {this.handles={}}async#e(t,n,e,s){const a=this.handles[t];if(!a)throw new (0, _indexmincjs3.EquippedError)("audit handler not found",{type:t,payload:n,mode:e});const l=_valleyed.v.assert(a.pipe,n),i=_indexmincjs5.Instance.createId(),o=new Date;return await this.table.insertOne({key:i,type:t,mode:e,ts:o.getTime(),payload:l,status:"pending",userId:_nullishCoalesce(s.userId, () => (null)),error:null,startedAt:null,completedAt:null},{getTime:()=>o,makeId:()=>i})}async#t(t){return this.db.session(async()=>{const n=this.handles[t.type];if(!n)throw new (0, _indexmincjs3.EquippedError)("audit handler not found",{event:t});try{await this.table.updateOne({key:t.key},{$set:{status:"processing",startedAt:Date.now(),completedAt:null,error:null}});const e=await n.handle(t.payload,{key:t.key,userId:t.userId,date:new Date(t.ts)});return await this.table.updateOne({key:t.key},{$set:{status:"done",completedAt:Date.now()}}),e}catch(e){const s=e instanceof Error?e.message:String(e);throw await this.table.updateOne({key:t.key},{$set:{status:"failed",error:s,completedAt:Date.now()}}),e}})}async replay(t){const{results:n}=await this.table.query(_indexmincjs.wrapQueryParams.call(void 0, {where:[...t?[{field:"ts",value:t.getTime(),condition:_indexmincjs.Conditions.gte}]:[]],sort:[{field:"ts",desc:!1}],all:!0}));for(const e of n)await this.#t(e)}async rerun(t){const n=await this.table.findOne({key:t});if(!n)throw new (0, _indexmincjs3.EquippedError)("audit event not found",{key:t});await this.#t(n)}register(t,n){if(this.handles[t])throw new (0, _indexmincjs3.EquippedError)(`${t} already has a registered handler`,{});return this.handles[t]=n,_valleyed.v.compile(n.pipe),{sync:async(e,s)=>{const a=await this.#e(t,e,"sync",s);return this.#t(a)},async:async(e,s)=>{const a=await this.#e(t,e,"async",s);this.#t(a).catch(()=>{})}}}}exports.EventAudit = D;
|
|
2
2
|
//# sourceMappingURL=events.min.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/audit/events.ts"],"names":["
|
|
1
|
+
{"version":3,"sources":["../../../src/audit/events.ts"],"names":["model","payload","mode","handler","EquippedError","type","now","key","validPayload","context","event","result","message","err","from","events","wrapQueryParams","#processEvent"],"mappings":"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","file":"/home/runner/work/equipped/equipped/dist/cjs/audit/events.min.cjs","sourcesContent":["import { Pipe, PipeInput, PipeOutput, v } from 'valleyed'\n\nimport { Conditions, Db, Table, wrapQueryParams } from '../dbs'\nimport { EquippedError } from '../errors'\nimport { Instance } from '../instance'\n\nexport type EventDefinition<P extends Pipe<any, any>, R> = {\n\tpipe: P\n\thandle: (payload: PipeOutput<P>, context: EventContext) => R | Promise<R>\n}\n\nexport type EventContext = {\n\tkey: string\n\tuserId: string | null\n\tdate: Date\n}\n\nexport type EventDoc = {\n\tkey: string\n\ttype: string\n\tts: number\n\tpayload: unknown\n\tmode: 'sync' | 'async'\n\tstatus: 'pending' | 'processing' | 'done' | 'failed'\n\tuserId: string | null\n\terror: string | null\n\tstartedAt: number | null\n\tcompletedAt: number | null\n}\ntype Context = { userId?: string }\n\nexport class EventAudit {\n\tprivate table: Table<any, EventDoc, EventDoc & { toJSON: () => Record<string, unknown> }, any>\n\tprivate handles: Record<string, EventDefinition<any, any>> = {}\n\n\tconstructor(\n\t\tprivate db: Db<any>,\n\t\tdbName: string,\n\t) {\n\t\tthis.table = db.use({\n\t\t\tdb: dbName,\n\t\t\tcol: '__audits',\n\t\t\tmapper: (model) => ({ ...model, toJSON: () => model as Record<string, unknown> }),\n\t\t\toptions: { skipAudit: true },\n\t\t})\n\t}\n\n\tasync #createEvent(type: string, payload: unknown, mode: 'sync' | 'async', context: Context) {\n\t\tconst handler = this.handles[type]\n\t\tif (!handler) throw new EquippedError('audit handler not found', { type, payload, mode })\n\n\t\tconst validPayload = v.assert(handler.pipe, payload)\n\t\tconst key = Instance.createId()\n\t\tconst now = new Date()\n\n\t\treturn await this.table.insertOne(\n\t\t\t{\n\t\t\t\tkey,\n\t\t\t\ttype,\n\t\t\t\tmode,\n\t\t\t\tts: now.getTime(),\n\t\t\t\tpayload: validPayload,\n\t\t\t\tstatus: 'pending',\n\t\t\t\tuserId: context.userId ?? null,\n\t\t\t\terror: null,\n\t\t\t\tstartedAt: null,\n\t\t\t\tcompletedAt: null,\n\t\t\t},\n\t\t\t{ getTime: () => now, makeId: () => key },\n\t\t)\n\t}\n\n\tasync #processEvent<R>(event: EventDoc) {\n\t\treturn this.db.session(async () => {\n\t\t\tconst handler = this.handles[event.type]\n\t\t\tif (!handler) throw new EquippedError('audit handler not found', { event })\n\t\t\ttry {\n\t\t\t\tawait this.table.updateOne(\n\t\t\t\t\t{ key: event.key },\n\t\t\t\t\t{ $set: { status: 'processing', startedAt: Date.now(), completedAt: null, error: null } },\n\t\t\t\t)\n\t\t\t\tconst result = await handler.handle(event.payload, {\n\t\t\t\t\tkey: event.key,\n\t\t\t\t\tuserId: event.userId,\n\t\t\t\t\tdate: new Date(event.ts),\n\t\t\t\t})\n\t\t\t\tawait this.table.updateOne({ key: event.key }, { $set: { status: 'done', completedAt: Date.now() } })\n\t\t\t\treturn result as R\n\t\t\t} catch (err) {\n\t\t\t\tconst message = err instanceof Error ? err.message : String(err)\n\t\t\t\tawait this.table.updateOne({ key: event.key }, { $set: { status: 'failed', error: message, completedAt: Date.now() } })\n\t\t\t\tthrow err\n\t\t\t}\n\t\t})\n\t}\n\n\tasync replay(from?: Date) {\n\t\tconst { results: events } = await this.table.query(\n\t\t\twrapQueryParams({\n\t\t\t\twhere: [...(from ? [{ field: 'ts', value: from.getTime(), condition: Conditions.gte }] : [])],\n\t\t\t\tsort: [{ field: 'ts', desc: false }],\n\t\t\t\tall: true,\n\t\t\t}),\n\t\t)\n\t\tfor (const event of events) await this.#processEvent(event)\n\t}\n\n\tasync rerun(key: string) {\n\t\tconst event = await this.table.findOne({ key })\n\t\tif (!event) throw new EquippedError('audit event not found', { key })\n\t\tawait this.#processEvent(event)\n\t}\n\n\tregister<P extends Pipe<any, any>, R>(type: string, handle: EventDefinition<P, R>) {\n\t\tif (this.handles[type]) throw new EquippedError(`${type} already has a registered handler`, {})\n\t\tthis.handles[type] = handle\n\t\tv.compile(handle.pipe)\n\t\treturn {\n\t\t\tsync: async (payload: PipeInput<P>, context: Context) => {\n\t\t\t\tconst event = await this.#createEvent(type, payload, 'sync', context)\n\t\t\t\treturn this.#processEvent<R>(event)\n\t\t\t},\n\t\t\tasync: async (payload: PipeInput<P>, context: Context) => {\n\t\t\t\tconst event = await this.#createEvent(type, payload, 'async', context)\n\t\t\t\tthis.#processEvent<R>(event).catch(() => {})\n\t\t\t},\n\t\t}\n\t}\n}\n"]}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } }var _pino = require('pino'); var _pino2 = _interopRequireDefault(_pino);
|
|
2
|
+
var _ulid = require('ulid');
|
|
2
3
|
var _valleyed = require('valleyed');
|
|
3
4
|
var _hookscjs = require('./hooks.cjs');
|
|
4
5
|
|
|
@@ -126,6 +127,9 @@ ${settingsValidity.error.toString()}`, {
|
|
|
126
127
|
console.error(error);
|
|
127
128
|
process.exit(1);
|
|
128
129
|
}
|
|
130
|
+
static createId() {
|
|
131
|
+
return _ulid.ulid.call(void 0, );
|
|
132
|
+
}
|
|
129
133
|
}
|
|
130
134
|
|
|
131
135
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/instance/index.ts","/home/runner/work/equipped/equipped/dist/cjs/instance/index.cjs"],"names":[],"mappings":"AAAA,qVAA6B;AAC7B,oCAA0D;AAE1D,uCAAwD;AACxD;AACC;AAEA;AAEA;AAEA;AACA;AAEA;AAAA,6CAIM;AACP,+CAA8B;AAEvB,MAAM,SAAS;AAAA,EACrB,OAAO,CAAA,EAAA;AAAA,EACP,OAAO,CAAA,QAAA;AAAA,EACP,OAAO,CAAA,MAAA,EAAmD,CAAC,CAAA;AAAA,EAClD;AAAA,EACA;AAAA,EAED,WAAA,CAAY,QAAA,EAAoB;AACvC,IAAA,QAAA,CAAS,CAAA,SAAA,EAAY,IAAA;AACrB,IAAA,IAAA,CAAK,SAAA,EAAW,MAAA,CAAO,MAAA,CAAO,QAAQ,CAAA;AACtC,IAAA,IAAA,CAAK,IAAA,EAAM,4BAAA;AAAY,MACtB,KAAA,EAAO,IAAA,CAAK,QAAA,CAAS,GAAA,CAAI,KAAA;AAAA,MACzB,WAAA,EAAa;AAAA,QACZ,GAAA,EAAK,cAAA,CAAK,cAAA,CAAe,GAAA;AAAA,QACzB,KAAA,EAAO,cAAA,CAAK,cAAA,CAAe,GAAA;AAAA,QAC3B,GAAA,EAAK,cAAA,CAAK,cAAA,CAAe,GAAA;AAAA,QACzB,GAAA,EAAK,cAAA,CAAK,cAAA,CAAe;AAAA,MAC1B,CAAA;AAAA,MACA,KAAA,EAAO,CAAA,EAAA,GAAA,CAAO;AAAA,QACb,UAAA,EAAY,QAAA,CAAS,CAAA;AAAA,MACtB,CAAA;AAAA,IACD,CAAC,CAAA;AACD,IAAA,QAAA,CAAS,CAAA,qBAAA,CAAuB,CAAA;AAAA,EACjC;AAAA,EAEA,KAAA,CAAM,EAAA,EAAY;AACjB,IAAA,GAAA,CAAI,QAAA,CAAS,CAAA,GAAA,IAAQ,KAAA,CAAA,EAAW,OAAO,QAAA,CAAS,KAAA,CAAM,IAAI,4BAAA,CAAc,+BAAA,EAAiC,CAAC,CAAC,CAAC,CAAA;AAC5G,IAAA,QAAA,CAAS,CAAA,GAAA,EAAM,EAAA;AAAA,EAChB;AAAA,EAEA,IAAI,EAAA,CAAA,EAAK;AACR,IAAA,GAAA,CAAI,QAAA,CAAS,CAAA,GAAA,IAAQ,KAAA,CAAA,EAAW,OAAO,QAAA,CAAS,KAAA,CAAM,IAAI,4BAAA,CAAc,mCAAA,EAAqC,CAAC,CAAC,CAAC,CAAA;AAChH,IAAA,OAAO,QAAA,CAAS,CAAA,EAAA;AAAA,EACjB;AAAA,EAEA,aAAA,CAAc,IAAA,EAAc,IAAA,EAAM,GAAA,EAAK;AACtC,IAAA,OAAO,CAAC,IAAA,CAAK,QAAA,CAAS,GAAA,CAAI,IAAA,EAAM,IAAI,CAAA,CAAE,IAAA,CAAK,GAAG,CAAA;AAAA,EAC/C;AAAA,EAEA,WAAA,CAA+D,KAAA,EAAiC;AAC/F,IAAA,OAAO,WAAA,CAAE,MAAA,CAAO,oCAAA,CAAU,EAAG,KAAK,CAAA;AAAA,EACnC;AAAA,EAEA,UAAA,CAA6D,KAAA,EAAiC;AAC7F,IAAA,OAAO,WAAA,CAAE,MAAA,CAAO,mCAAA,CAAS,EAAG,KAAK,CAAA;AAAA,EAClC;AAAA,EAEA,cAAA,CAAqE,KAAA,EAAiC;AACrG,IAAA,OAAO,WAAA,CAAE,MAAA,CAAO,uCAAA,CAAa,EAAG,KAAK,CAAA;AAAA,EACtC;AAAA,EAEA,QAAA,CAAyD,KAAA,EAAiC;AACzF,IAAA,OAAO,WAAA,CAAE,MAAA,CAAO,iCAAA,CAAO,EAAG,KAAK,CAAA;AAAA,EAChC;AAAA,EAEA,YAAA,CAAqE,KAAA,EAAiC;AACrG,IAAA,OAAO,WAAA,CAAE,MAAA,CAAO,yCAAA,CAAe,EAAG,KAAK,CAAA;AAAA,EACxC;AAAA,EAEA,MAAM,KAAA,CAAA,EAAQ;AACb,IAAA,IAAI;AACH,MAAA,MAAM,gCAAA,iBAAS,QAAA,CAAS,CAAA,KAAA,CAAO,OAAO,CAAA,UAAK,CAAC,GAAC,CAAA;AAC7C,MAAA,MAAM,gCAAA,iBAAS,QAAA,CAAS,CAAA,KAAA,CAAO,OAAO,CAAA,UAAK,CAAC,GAAC,CAAA;AAAA,IAC9C,EAAA,MAAA,CAAS,KAAA,EAAO;AACf,MAAA,QAAA,CAAS,KAAA,CAAM,IAAI,4BAAA,CAAc,CAAA,uBAAA,CAAA,EAA2B,CAAC,CAAA,EAAG,KAAK,CAAC,CAAA;AAAA,IACvE;AAAA,EACD;AAAA,EAEA,OAAO,IAAA,CAAuB,QAAA,EAA+B;AAC5D,IAAA,MAAM,YAAA,EAAc,WAAA,CAAE,QAAA,CAAS,QAAA,EAAU,OAAA,CAAQ,GAAG,CAAA;AACpD,IAAA,GAAA,CAAI,CAAC,WAAA,CAAY,KAAA,EAAO;AACvB,MAAA,QAAA,CAAS,KAAA;AAAA,QACR,IAAI,4BAAA,CAAc,CAAA;AAAA,EAAwC,WAAA,CAAY,KAAA,CAAM,QAAA,CAAS,CAAC,CAAA,CAAA;AAC3E,UAAA;AACV,QAAA;AACF,MAAA;AACD,IAAA;AACmB,IAAA;AACpB,EAAA;AAEuC,EAAA;AACd,IAAA;AACG,IAAA;AACL,IAAA;AACZ,MAAA;AACU,QAAA;AAAkD;AACzD,UAAA;AACV,QAAA;AACF,MAAA;AACD,IAAA;AACoB,IAAA;AACrB,EAAA;AAEa,EAAA;AACE,IAAA;AACG,MAAA;AACG,QAAA;AACnB,MAAA;AACe,IAAA;AACjB,EAAA;AAEuD,EAAA;AAC3B,IAAA;AACJ,IAAA;AACxB,EAAA;AAEO,EAAA;AACU,IAAA;AACP,MAAA;AACA,MAAA;AACC,MAAA;AACV,IAAA;AAEwB,IAAA;AACJ,MAAA;AACH,QAAA;AAAwC,QAAA;AAChC,QAAA;AACvB,MAAA;AACD,IAAA;AACF,EAAA;AAE6B,EAAA;AACX,IAAA;AACI,IAAA;AACd,IAAA;AACR,EAAA;AAE0C,EAAA;AAEtB,IAAA;AACL,IAAA;AACf,EAAA;AACD;
|
|
1
|
+
{"version":3,"sources":["../../../src/instance/index.ts","/home/runner/work/equipped/equipped/dist/cjs/instance/index.cjs"],"names":[],"mappings":"AAAA,qVAA6B;AAC7B,4BAAqB;AACrB,oCAA0D;AAE1D,uCAAwD;AACxD;AACC;AAEA;AAEA;AAEA;AACA;AAEA;AAAA,6CAIM;AACP,+CAA8B;AAEvB,MAAM,SAAS;AAAA,EACrB,OAAO,CAAA,EAAA;AAAA,EACP,OAAO,CAAA,QAAA;AAAA,EACP,OAAO,CAAA,MAAA,EAAmD,CAAC,CAAA;AAAA,EAClD;AAAA,EACA;AAAA,EAED,WAAA,CAAY,QAAA,EAAoB;AACvC,IAAA,QAAA,CAAS,CAAA,SAAA,EAAY,IAAA;AACrB,IAAA,IAAA,CAAK,SAAA,EAAW,MAAA,CAAO,MAAA,CAAO,QAAQ,CAAA;AACtC,IAAA,IAAA,CAAK,IAAA,EAAM,4BAAA;AAAY,MACtB,KAAA,EAAO,IAAA,CAAK,QAAA,CAAS,GAAA,CAAI,KAAA;AAAA,MACzB,WAAA,EAAa;AAAA,QACZ,GAAA,EAAK,cAAA,CAAK,cAAA,CAAe,GAAA;AAAA,QACzB,KAAA,EAAO,cAAA,CAAK,cAAA,CAAe,GAAA;AAAA,QAC3B,GAAA,EAAK,cAAA,CAAK,cAAA,CAAe,GAAA;AAAA,QACzB,GAAA,EAAK,cAAA,CAAK,cAAA,CAAe;AAAA,MAC1B,CAAA;AAAA,MACA,KAAA,EAAO,CAAA,EAAA,GAAA,CAAO;AAAA,QACb,UAAA,EAAY,QAAA,CAAS,CAAA;AAAA,MACtB,CAAA;AAAA,IACD,CAAC,CAAA;AACD,IAAA,QAAA,CAAS,CAAA,qBAAA,CAAuB,CAAA;AAAA,EACjC;AAAA,EAEA,KAAA,CAAM,EAAA,EAAY;AACjB,IAAA,GAAA,CAAI,QAAA,CAAS,CAAA,GAAA,IAAQ,KAAA,CAAA,EAAW,OAAO,QAAA,CAAS,KAAA,CAAM,IAAI,4BAAA,CAAc,+BAAA,EAAiC,CAAC,CAAC,CAAC,CAAA;AAC5G,IAAA,QAAA,CAAS,CAAA,GAAA,EAAM,EAAA;AAAA,EAChB;AAAA,EAEA,IAAI,EAAA,CAAA,EAAK;AACR,IAAA,GAAA,CAAI,QAAA,CAAS,CAAA,GAAA,IAAQ,KAAA,CAAA,EAAW,OAAO,QAAA,CAAS,KAAA,CAAM,IAAI,4BAAA,CAAc,mCAAA,EAAqC,CAAC,CAAC,CAAC,CAAA;AAChH,IAAA,OAAO,QAAA,CAAS,CAAA,EAAA;AAAA,EACjB;AAAA,EAEA,aAAA,CAAc,IAAA,EAAc,IAAA,EAAM,GAAA,EAAK;AACtC,IAAA,OAAO,CAAC,IAAA,CAAK,QAAA,CAAS,GAAA,CAAI,IAAA,EAAM,IAAI,CAAA,CAAE,IAAA,CAAK,GAAG,CAAA;AAAA,EAC/C;AAAA,EAEA,WAAA,CAA+D,KAAA,EAAiC;AAC/F,IAAA,OAAO,WAAA,CAAE,MAAA,CAAO,oCAAA,CAAU,EAAG,KAAK,CAAA;AAAA,EACnC;AAAA,EAEA,UAAA,CAA6D,KAAA,EAAiC;AAC7F,IAAA,OAAO,WAAA,CAAE,MAAA,CAAO,mCAAA,CAAS,EAAG,KAAK,CAAA;AAAA,EAClC;AAAA,EAEA,cAAA,CAAqE,KAAA,EAAiC;AACrG,IAAA,OAAO,WAAA,CAAE,MAAA,CAAO,uCAAA,CAAa,EAAG,KAAK,CAAA;AAAA,EACtC;AAAA,EAEA,QAAA,CAAyD,KAAA,EAAiC;AACzF,IAAA,OAAO,WAAA,CAAE,MAAA,CAAO,iCAAA,CAAO,EAAG,KAAK,CAAA;AAAA,EAChC;AAAA,EAEA,YAAA,CAAqE,KAAA,EAAiC;AACrG,IAAA,OAAO,WAAA,CAAE,MAAA,CAAO,yCAAA,CAAe,EAAG,KAAK,CAAA;AAAA,EACxC;AAAA,EAEA,MAAM,KAAA,CAAA,EAAQ;AACb,IAAA,IAAI;AACH,MAAA,MAAM,gCAAA,iBAAS,QAAA,CAAS,CAAA,KAAA,CAAO,OAAO,CAAA,UAAK,CAAC,GAAC,CAAA;AAC7C,MAAA,MAAM,gCAAA,iBAAS,QAAA,CAAS,CAAA,KAAA,CAAO,OAAO,CAAA,UAAK,CAAC,GAAC,CAAA;AAAA,IAC9C,EAAA,MAAA,CAAS,KAAA,EAAO;AACf,MAAA,QAAA,CAAS,KAAA,CAAM,IAAI,4BAAA,CAAc,CAAA,uBAAA,CAAA,EAA2B,CAAC,CAAA,EAAG,KAAK,CAAC,CAAA;AAAA,IACvE;AAAA,EACD;AAAA,EAEA,OAAO,IAAA,CAAuB,QAAA,EAA+B;AAC5D,IAAA,MAAM,YAAA,EAAc,WAAA,CAAE,QAAA,CAAS,QAAA,EAAU,OAAA,CAAQ,GAAG,CAAA;AACpD,IAAA,GAAA,CAAI,CAAC,WAAA,CAAY,KAAA,EAAO;AACvB,MAAA,QAAA,CAAS,KAAA;AAAA,QACR,IAAI,4BAAA,CAAc,CAAA;AAAA,EAAwC,WAAA,CAAY,KAAA,CAAM,QAAA,CAAS,CAAC,CAAA,CAAA;AAC3E,UAAA;AACV,QAAA;AACF,MAAA;AACD,IAAA;AACmB,IAAA;AACpB,EAAA;AAEuC,EAAA;AACd,IAAA;AACG,IAAA;AACL,IAAA;AACZ,MAAA;AACU,QAAA;AAAkD;AACzD,UAAA;AACV,QAAA;AACF,MAAA;AACD,IAAA;AACoB,IAAA;AACrB,EAAA;AAEa,EAAA;AACE,IAAA;AACG,MAAA;AACG,QAAA;AACnB,MAAA;AACe,IAAA;AACjB,EAAA;AAEuD,EAAA;AAC3B,IAAA;AACJ,IAAA;AACxB,EAAA;AAEO,EAAA;AACU,IAAA;AACP,MAAA;AACA,MAAA;AACC,MAAA;AACV,IAAA;AAEwB,IAAA;AACJ,MAAA;AACH,QAAA;AAAwC,QAAA;AAChC,QAAA;AACvB,MAAA;AACD,IAAA;AACF,EAAA;AAE6B,EAAA;AACX,IAAA;AACI,IAAA;AACd,IAAA;AACR,EAAA;AAE0C,EAAA;AAEtB,IAAA;AACL,IAAA;AACf,EAAA;AAEkB,EAAA;AACL,IAAA;AACb,EAAA;AACD;ACzB+B;AACA;AACA","file":"/home/runner/work/equipped/equipped/dist/cjs/instance/index.cjs","sourcesContent":["import pino, { Logger } from 'pino'\nimport { ulid } from 'ulid'\nimport { ConditionalObjectKeys, Pipe, PipeInput, v } from 'valleyed'\n\nimport { HookCb, HookEvent, HookRecord, runHooks } from './hooks'\nimport {\n\tcachePipe,\n\tCacheTypes,\n\tdbPipe,\n\tDbTypes,\n\teventBusPipe,\n\tEventBusTypes,\n\tinstanceSettingsPipe,\n\tjobsPipe,\n\tJobTypes,\n\tserverTypePipe,\n\tServerTypes,\n\tSettings,\n\tSettingsInput,\n} from './settings'\nimport { EquippedError } from '../errors'\n\nexport class Instance {\n\tstatic #id: string | undefined\n\tstatic #instance: Instance\n\tstatic #hooks: Partial<Record<HookEvent, HookRecord[]>> = {}\n\treadonly settings: Readonly<Settings>\n\treadonly log: Logger<never>\n\n\tprivate constructor(settings: Settings) {\n\t\tInstance.#instance = this\n\t\tthis.settings = Object.freeze(settings)\n\t\tthis.log = pino<never>({\n\t\t\tlevel: this.settings.log.level,\n\t\t\tserializers: {\n\t\t\t\terr: pino.stdSerializers.err,\n\t\t\t\terror: pino.stdSerializers.err,\n\t\t\t\treq: pino.stdSerializers.req,\n\t\t\t\tres: pino.stdSerializers.res,\n\t\t\t},\n\t\t\tmixin: () => ({\n\t\t\t\tinstanceId: Instance.#id,\n\t\t\t}),\n\t\t})\n\t\tInstance.#registerOnExitHandler()\n\t}\n\n\talias(id: string) {\n\t\tif (Instance.#id !== undefined) return Instance.crash(new EquippedError('Instance already has an alias', {}))\n\t\tInstance.#id = id\n\t}\n\n\tget id() {\n\t\tif (Instance.#id === undefined) return Instance.crash(new EquippedError('Instance doesnt have an alias yet', {}))\n\t\treturn Instance.#id\n\t}\n\n\tgetScopedName(name: string, key = '.') {\n\t\treturn [this.settings.app.name, name].join(key)\n\t}\n\n\tcreateCache<T extends PipeInput<ReturnType<typeof cachePipe>>>(input: ConditionalObjectKeys<T>) {\n\t\treturn v.assert(cachePipe(), input) as CacheTypes[T['type']]\n\t}\n\n\tcreateJobs<T extends PipeInput<ReturnType<typeof jobsPipe>>>(input: ConditionalObjectKeys<T>) {\n\t\treturn v.assert(jobsPipe(), input) as JobTypes[T['type']]\n\t}\n\n\tcreateEventBus<T extends PipeInput<ReturnType<typeof eventBusPipe>>>(input: ConditionalObjectKeys<T>) {\n\t\treturn v.assert(eventBusPipe(), input) as EventBusTypes[T['type']]\n\t}\n\n\tcreateDb<T extends PipeInput<ReturnType<typeof dbPipe>>>(input: ConditionalObjectKeys<T>) {\n\t\treturn v.assert(dbPipe(), input) as DbTypes[T['db']['type']]\n\t}\n\n\tcreateServer<T extends PipeInput<ReturnType<typeof serverTypePipe>>>(input: ConditionalObjectKeys<T>) {\n\t\treturn v.assert(serverTypePipe(), input) as ServerTypes[T['type']]\n\t}\n\n\tasync start() {\n\t\ttry {\n\t\t\tawait runHooks(Instance.#hooks['setup'] ?? [])\n\t\t\tawait runHooks(Instance.#hooks['start'] ?? [])\n\t\t} catch (error) {\n\t\t\tInstance.crash(new EquippedError(`Error starting instance`, {}, error))\n\t\t}\n\t}\n\n\tstatic envs<E extends object>(envsPipe: Pipe<unknown, E>): E {\n\t\tconst envValidity = v.validate(envsPipe, process.env)\n\t\tif (!envValidity.valid) {\n\t\t\tInstance.crash(\n\t\t\t\tnew EquippedError(`Environment variables are not valid\\n${envValidity.error.toString()}`, {\n\t\t\t\t\tmessages: envValidity.error.messages,\n\t\t\t\t}),\n\t\t\t)\n\t\t}\n\t\treturn envValidity.value\n\t}\n\n\tstatic create(settings: SettingsInput) {\n\t\tif (Instance.#instance) return Instance.crash(new EquippedError('Instance has been initialized already', {}))\n\t\tconst settingsValidity = v.validate(instanceSettingsPipe(), settings)\n\t\tif (!settingsValidity.valid) {\n\t\t\tInstance.crash(\n\t\t\t\tnew EquippedError(`Settings are not valid\\n${settingsValidity.error.toString()}`, {\n\t\t\t\t\tmessages: settingsValidity.error.messages,\n\t\t\t\t}),\n\t\t\t)\n\t\t}\n\t\treturn new Instance(settingsValidity.value)\n\t}\n\n\tstatic get() {\n\t\tif (!Instance.#instance)\n\t\t\treturn Instance.crash(\n\t\t\t\tnew EquippedError('Has not been initialized. Make sure an instance has been created before you get an instance', {}),\n\t\t\t)\n\t\treturn Instance.#instance\n\t}\n\n\tstatic on(event: HookEvent, cb: HookCb, order: number) {\n\t\tInstance.#hooks[event] ??= []\n\t\tInstance.#hooks[event].push({ cb, order })\n\t}\n\n\tstatic #registerOnExitHandler() {\n\t\tconst signals = {\n\t\t\tSIGHUP: 1,\n\t\t\tSIGINT: 2,\n\t\t\tSIGTERM: 15,\n\t\t}\n\n\t\tObject.entries(signals).forEach(([signal, code]) => {\n\t\t\tprocess.on(signal, async () => {\n\t\t\t\tawait runHooks(Instance.#hooks['close'] ?? [], () => {})\n\t\t\t\tprocess.exit(128 + code)\n\t\t\t})\n\t\t})\n\t}\n\n\tstatic resolveBeforeCrash<T>(cb: () => Promise<T>) {\n\t\tconst value = cb()\n\t\tInstance.on('close', async () => await value, 10)\n\t\treturn value\n\t}\n\n\tstatic crash(error: EquippedError): never {\n\t\t// eslint-disable-next-line no-console\n\t\tconsole.error(error)\n\t\tprocess.exit(1)\n\t}\n\n\tstatic createId() {\n\t\treturn ulid()\n\t}\n}\n",null]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } }var _pino = require('pino'); var _pino2 = _interopRequireDefault(_pino);var _valleyed = require('valleyed');var _hooksmincjs = require('./hooks.min.cjs');var _settingsmincjs = require('./settings.min.cjs');var _indexmincjs = require('../errors/index.min.cjs');class r{static#e;static#t;static#r= exports.Instance ={};constructor(e){r.#t=this,this.settings=Object.freeze(e),this.log=_pino2.default.call(void 0, {level:this.settings.log.level,serializers:{err:_pino2.default.stdSerializers.err,error:_pino2.default.stdSerializers.err,req:_pino2.default.stdSerializers.req,res:_pino2.default.stdSerializers.res},mixin:()=>({instanceId:r.#e})}),r.#s()}alias(e){if(r.#e!==void 0)return r.crash(new (0, _indexmincjs.EquippedError)("Instance already has an alias",{}));r.#e=e}get id(){return r.#e===void 0?r.crash(new (0, _indexmincjs.EquippedError)("Instance doesnt have an alias yet",{})):r.#e}getScopedName(e,t="."){return[this.settings.app.name,e].join(t)}createCache(e){return _valleyed.v.assert(_settingsmincjs.cachePipe.call(void 0, ),e)}createJobs(e){return _valleyed.v.assert(_settingsmincjs.jobsPipe.call(void 0, ),e)}createEventBus(e){return _valleyed.v.assert(_settingsmincjs.eventBusPipe.call(void 0, ),e)}createDb(e){return _valleyed.v.assert(_settingsmincjs.dbPipe.call(void 0, ),e)}createServer(e){return _valleyed.v.assert(_settingsmincjs.serverTypePipe.call(void 0, ),e)}async start(){try{await _hooksmincjs.runHooks.call(void 0, _nullishCoalesce(r.#r.setup, () => ([]))),await _hooksmincjs.runHooks.call(void 0, _nullishCoalesce(r.#r.start, () => ([])))}catch(e){r.crash(new (0, _indexmincjs.EquippedError)("Error starting instance",{},e))}}static envs(e){const t=_valleyed.v.validate(e,process.env);return t.valid||r.crash(new (0, _indexmincjs.EquippedError)(`Environment variables are not valid
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } }var _pino = require('pino'); var _pino2 = _interopRequireDefault(_pino);var _ulid = require('ulid');var _valleyed = require('valleyed');var _hooksmincjs = require('./hooks.min.cjs');var _settingsmincjs = require('./settings.min.cjs');var _indexmincjs = require('../errors/index.min.cjs');class r{static#e;static#t;static#r= exports.Instance ={};constructor(e){r.#t=this,this.settings=Object.freeze(e),this.log=_pino2.default.call(void 0, {level:this.settings.log.level,serializers:{err:_pino2.default.stdSerializers.err,error:_pino2.default.stdSerializers.err,req:_pino2.default.stdSerializers.req,res:_pino2.default.stdSerializers.res},mixin:()=>({instanceId:r.#e})}),r.#s()}alias(e){if(r.#e!==void 0)return r.crash(new (0, _indexmincjs.EquippedError)("Instance already has an alias",{}));r.#e=e}get id(){return r.#e===void 0?r.crash(new (0, _indexmincjs.EquippedError)("Instance doesnt have an alias yet",{})):r.#e}getScopedName(e,t="."){return[this.settings.app.name,e].join(t)}createCache(e){return _valleyed.v.assert(_settingsmincjs.cachePipe.call(void 0, ),e)}createJobs(e){return _valleyed.v.assert(_settingsmincjs.jobsPipe.call(void 0, ),e)}createEventBus(e){return _valleyed.v.assert(_settingsmincjs.eventBusPipe.call(void 0, ),e)}createDb(e){return _valleyed.v.assert(_settingsmincjs.dbPipe.call(void 0, ),e)}createServer(e){return _valleyed.v.assert(_settingsmincjs.serverTypePipe.call(void 0, ),e)}async start(){try{await _hooksmincjs.runHooks.call(void 0, _nullishCoalesce(r.#r.setup, () => ([]))),await _hooksmincjs.runHooks.call(void 0, _nullishCoalesce(r.#r.start, () => ([])))}catch(e){r.crash(new (0, _indexmincjs.EquippedError)("Error starting instance",{},e))}}static envs(e){const t=_valleyed.v.validate(e,process.env);return t.valid||r.crash(new (0, _indexmincjs.EquippedError)(`Environment variables are not valid
|
|
2
2
|
${t.error.toString()}`,{messages:t.error.messages})),t.value}static create(e){if(r.#t)return r.crash(new (0, _indexmincjs.EquippedError)("Instance has been initialized already",{}));const t=_valleyed.v.validate(_settingsmincjs.instanceSettingsPipe.call(void 0, ),e);return t.valid||r.crash(new (0, _indexmincjs.EquippedError)(`Settings are not valid
|
|
3
|
-
${t.error.toString()}`,{messages:t.error.messages})),new r(t.value)}static get(){return r.#t?r.#t:r.crash(new (0, _indexmincjs.EquippedError)("Has not been initialized. Make sure an instance has been created before you get an instance",{}))}static on(e,t,
|
|
3
|
+
${t.error.toString()}`,{messages:t.error.messages})),new r(t.value)}static get(){return r.#t?r.#t:r.crash(new (0, _indexmincjs.EquippedError)("Has not been initialized. Make sure an instance has been created before you get an instance",{}))}static on(e,t,n){r.#r[e]??=[],r.#r[e].push({cb:t,order:n})}static#s(){Object.entries({SIGHUP:1,SIGINT:2,SIGTERM:15}).forEach(([t,n])=>{process.on(t,async()=>{await _hooksmincjs.runHooks.call(void 0, _nullishCoalesce(r.#r.close, () => ([])),()=>{}),process.exit(128+n)})})}static resolveBeforeCrash(e){const t=e();return r.on("close",async()=>await t,10),t}static crash(e){console.error(e),process.exit(1)}static createId(){return _ulid.ulid.call(void 0, )}}exports.Instance = r;
|
|
4
4
|
//# sourceMappingURL=index.min.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/instance/index.ts"],"names":["#hooks","Instance","#instance","settings","pino","id","#id","EquippedError","input","v","cachePipe","jobsPipe","dbPipe","serverTypePipe","runHooks","error","envValidity"],"mappings":"AAAA,qVAA6B,
|
|
1
|
+
{"version":3,"sources":["../../../src/instance/index.ts"],"names":["#hooks","Instance","#instance","settings","pino","id","#id","EquippedError","input","v","cachePipe","jobsPipe","dbPipe","serverTypePipe","runHooks","error","envValidity"],"mappings":"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","file":"/home/runner/work/equipped/equipped/dist/cjs/instance/index.min.cjs","sourcesContent":["import pino, { Logger } from 'pino'\nimport { ulid } from 'ulid'\nimport { ConditionalObjectKeys, Pipe, PipeInput, v } from 'valleyed'\n\nimport { HookCb, HookEvent, HookRecord, runHooks } from './hooks'\nimport {\n\tcachePipe,\n\tCacheTypes,\n\tdbPipe,\n\tDbTypes,\n\teventBusPipe,\n\tEventBusTypes,\n\tinstanceSettingsPipe,\n\tjobsPipe,\n\tJobTypes,\n\tserverTypePipe,\n\tServerTypes,\n\tSettings,\n\tSettingsInput,\n} from './settings'\nimport { EquippedError } from '../errors'\n\nexport class Instance {\n\tstatic #id: string | undefined\n\tstatic #instance: Instance\n\tstatic #hooks: Partial<Record<HookEvent, HookRecord[]>> = {}\n\treadonly settings: Readonly<Settings>\n\treadonly log: Logger<never>\n\n\tprivate constructor(settings: Settings) {\n\t\tInstance.#instance = this\n\t\tthis.settings = Object.freeze(settings)\n\t\tthis.log = pino<never>({\n\t\t\tlevel: this.settings.log.level,\n\t\t\tserializers: {\n\t\t\t\terr: pino.stdSerializers.err,\n\t\t\t\terror: pino.stdSerializers.err,\n\t\t\t\treq: pino.stdSerializers.req,\n\t\t\t\tres: pino.stdSerializers.res,\n\t\t\t},\n\t\t\tmixin: () => ({\n\t\t\t\tinstanceId: Instance.#id,\n\t\t\t}),\n\t\t})\n\t\tInstance.#registerOnExitHandler()\n\t}\n\n\talias(id: string) {\n\t\tif (Instance.#id !== undefined) return Instance.crash(new EquippedError('Instance already has an alias', {}))\n\t\tInstance.#id = id\n\t}\n\n\tget id() {\n\t\tif (Instance.#id === undefined) return Instance.crash(new EquippedError('Instance doesnt have an alias yet', {}))\n\t\treturn Instance.#id\n\t}\n\n\tgetScopedName(name: string, key = '.') {\n\t\treturn [this.settings.app.name, name].join(key)\n\t}\n\n\tcreateCache<T extends PipeInput<ReturnType<typeof cachePipe>>>(input: ConditionalObjectKeys<T>) {\n\t\treturn v.assert(cachePipe(), input) as CacheTypes[T['type']]\n\t}\n\n\tcreateJobs<T extends PipeInput<ReturnType<typeof jobsPipe>>>(input: ConditionalObjectKeys<T>) {\n\t\treturn v.assert(jobsPipe(), input) as JobTypes[T['type']]\n\t}\n\n\tcreateEventBus<T extends PipeInput<ReturnType<typeof eventBusPipe>>>(input: ConditionalObjectKeys<T>) {\n\t\treturn v.assert(eventBusPipe(), input) as EventBusTypes[T['type']]\n\t}\n\n\tcreateDb<T extends PipeInput<ReturnType<typeof dbPipe>>>(input: ConditionalObjectKeys<T>) {\n\t\treturn v.assert(dbPipe(), input) as DbTypes[T['db']['type']]\n\t}\n\n\tcreateServer<T extends PipeInput<ReturnType<typeof serverTypePipe>>>(input: ConditionalObjectKeys<T>) {\n\t\treturn v.assert(serverTypePipe(), input) as ServerTypes[T['type']]\n\t}\n\n\tasync start() {\n\t\ttry {\n\t\t\tawait runHooks(Instance.#hooks['setup'] ?? [])\n\t\t\tawait runHooks(Instance.#hooks['start'] ?? [])\n\t\t} catch (error) {\n\t\t\tInstance.crash(new EquippedError(`Error starting instance`, {}, error))\n\t\t}\n\t}\n\n\tstatic envs<E extends object>(envsPipe: Pipe<unknown, E>): E {\n\t\tconst envValidity = v.validate(envsPipe, process.env)\n\t\tif (!envValidity.valid) {\n\t\t\tInstance.crash(\n\t\t\t\tnew EquippedError(`Environment variables are not valid\\n${envValidity.error.toString()}`, {\n\t\t\t\t\tmessages: envValidity.error.messages,\n\t\t\t\t}),\n\t\t\t)\n\t\t}\n\t\treturn envValidity.value\n\t}\n\n\tstatic create(settings: SettingsInput) {\n\t\tif (Instance.#instance) return Instance.crash(new EquippedError('Instance has been initialized already', {}))\n\t\tconst settingsValidity = v.validate(instanceSettingsPipe(), settings)\n\t\tif (!settingsValidity.valid) {\n\t\t\tInstance.crash(\n\t\t\t\tnew EquippedError(`Settings are not valid\\n${settingsValidity.error.toString()}`, {\n\t\t\t\t\tmessages: settingsValidity.error.messages,\n\t\t\t\t}),\n\t\t\t)\n\t\t}\n\t\treturn new Instance(settingsValidity.value)\n\t}\n\n\tstatic get() {\n\t\tif (!Instance.#instance)\n\t\t\treturn Instance.crash(\n\t\t\t\tnew EquippedError('Has not been initialized. Make sure an instance has been created before you get an instance', {}),\n\t\t\t)\n\t\treturn Instance.#instance\n\t}\n\n\tstatic on(event: HookEvent, cb: HookCb, order: number) {\n\t\tInstance.#hooks[event] ??= []\n\t\tInstance.#hooks[event].push({ cb, order })\n\t}\n\n\tstatic #registerOnExitHandler() {\n\t\tconst signals = {\n\t\t\tSIGHUP: 1,\n\t\t\tSIGINT: 2,\n\t\t\tSIGTERM: 15,\n\t\t}\n\n\t\tObject.entries(signals).forEach(([signal, code]) => {\n\t\t\tprocess.on(signal, async () => {\n\t\t\t\tawait runHooks(Instance.#hooks['close'] ?? [], () => {})\n\t\t\t\tprocess.exit(128 + code)\n\t\t\t})\n\t\t})\n\t}\n\n\tstatic resolveBeforeCrash<T>(cb: () => Promise<T>) {\n\t\tconst value = cb()\n\t\tInstance.on('close', async () => await value, 10)\n\t\treturn value\n\t}\n\n\tstatic crash(error: EquippedError): never {\n\t\t// eslint-disable-next-line no-console\n\t\tconsole.error(error)\n\t\tprocess.exit(1)\n\t}\n\n\tstatic createId() {\n\t\treturn ulid()\n\t}\n}\n"]}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{v as d}from"valleyed";import{Conditions as u,wrapQueryParams as c}from "../dbs/index.min.mjs";import{EquippedError as r}from "../errors/index.min.mjs";import{Instance as p}from "../instance/index.min.mjs";class D{constructor(t,n){this.db=t;this.table=t.use({db:n,col:"__audits",mapper:e=>({...e,toJSON:()=>e}),options:{skipAudit:!0}})}table;handles={};async#e(t,n,e,s){const a=this.handles[t];if(!a)throw new r("audit handler not found",{type:t,payload:n,mode:e});const l=d.assert(a.pipe,n),i=p.createId(),o=new Date;return await this.table.insertOne({key:i,type:t,mode:e,ts:o.getTime(),payload:l,status:"pending",userId:s.userId??null,error:null,startedAt:null,completedAt:null},{getTime:()=>o,makeId:()=>i})}async#t(t){return this.db.session(async()=>{const n=this.handles[t.type];if(!n)throw new r("audit handler not found",{event:t});try{await this.table.updateOne({key:t.key},{$set:{status:"processing",startedAt:Date.now(),completedAt:null,error:null}});const e=await n.handle(t.payload,{key:t.key,userId:t.userId,date:new Date(t.ts)});return await this.table.updateOne({key:t.key},{$set:{status:"done",completedAt:Date.now()}}),e}catch(e){const s=e instanceof Error?e.message:String(e);throw await this.table.updateOne({key:t.key},{$set:{status:"failed",error:s,completedAt:Date.now()}}),e}})}async replay(t){const{results:n}=await this.table.query(c({where:[...t?[{field:"ts",value:t.getTime(),condition:u.gte}]:[]],sort:[{field:"ts",desc:!1}],all:!0}));for(const e of n)await this.#t(e)}async rerun(t){const n=await this.table.findOne({key:t});if(!n)throw new r("audit event not found",{key:t});await this.#t(n)}register(t,n){if(this.handles[t])throw new r(`${t} already has a registered handler`,{});return this.handles[t]=n,d.compile(n.pipe),{sync:async(e,s)=>{const a=await this.#e(t,e,"sync",s);return this.#t(a)},async:async(e,s)=>{const a=await this.#e(t,e,"async",s);this.#t(a).catch(()=>{})}}}}export{D as EventAudit};
|
|
2
2
|
//# sourceMappingURL=events.min.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/audit/events.ts"],"sourcesContent":["import {
|
|
1
|
+
{"version":3,"sources":["../../../src/audit/events.ts"],"sourcesContent":["import { Pipe, PipeInput, PipeOutput, v } from 'valleyed'\n\nimport { Conditions, Db, Table, wrapQueryParams } from '../dbs'\nimport { EquippedError } from '../errors'\nimport { Instance } from '../instance'\n\nexport type EventDefinition<P extends Pipe<any, any>, R> = {\n\tpipe: P\n\thandle: (payload: PipeOutput<P>, context: EventContext) => R | Promise<R>\n}\n\nexport type EventContext = {\n\tkey: string\n\tuserId: string | null\n\tdate: Date\n}\n\nexport type EventDoc = {\n\tkey: string\n\ttype: string\n\tts: number\n\tpayload: unknown\n\tmode: 'sync' | 'async'\n\tstatus: 'pending' | 'processing' | 'done' | 'failed'\n\tuserId: string | null\n\terror: string | null\n\tstartedAt: number | null\n\tcompletedAt: number | null\n}\ntype Context = { userId?: string }\n\nexport class EventAudit {\n\tprivate table: Table<any, EventDoc, EventDoc & { toJSON: () => Record<string, unknown> }, any>\n\tprivate handles: Record<string, EventDefinition<any, any>> = {}\n\n\tconstructor(\n\t\tprivate db: Db<any>,\n\t\tdbName: string,\n\t) {\n\t\tthis.table = db.use({\n\t\t\tdb: dbName,\n\t\t\tcol: '__audits',\n\t\t\tmapper: (model) => ({ ...model, toJSON: () => model as Record<string, unknown> }),\n\t\t\toptions: { skipAudit: true },\n\t\t})\n\t}\n\n\tasync #createEvent(type: string, payload: unknown, mode: 'sync' | 'async', context: Context) {\n\t\tconst handler = this.handles[type]\n\t\tif (!handler) throw new EquippedError('audit handler not found', { type, payload, mode })\n\n\t\tconst validPayload = v.assert(handler.pipe, payload)\n\t\tconst key = Instance.createId()\n\t\tconst now = new Date()\n\n\t\treturn await this.table.insertOne(\n\t\t\t{\n\t\t\t\tkey,\n\t\t\t\ttype,\n\t\t\t\tmode,\n\t\t\t\tts: now.getTime(),\n\t\t\t\tpayload: validPayload,\n\t\t\t\tstatus: 'pending',\n\t\t\t\tuserId: context.userId ?? null,\n\t\t\t\terror: null,\n\t\t\t\tstartedAt: null,\n\t\t\t\tcompletedAt: null,\n\t\t\t},\n\t\t\t{ getTime: () => now, makeId: () => key },\n\t\t)\n\t}\n\n\tasync #processEvent<R>(event: EventDoc) {\n\t\treturn this.db.session(async () => {\n\t\t\tconst handler = this.handles[event.type]\n\t\t\tif (!handler) throw new EquippedError('audit handler not found', { event })\n\t\t\ttry {\n\t\t\t\tawait this.table.updateOne(\n\t\t\t\t\t{ key: event.key },\n\t\t\t\t\t{ $set: { status: 'processing', startedAt: Date.now(), completedAt: null, error: null } },\n\t\t\t\t)\n\t\t\t\tconst result = await handler.handle(event.payload, {\n\t\t\t\t\tkey: event.key,\n\t\t\t\t\tuserId: event.userId,\n\t\t\t\t\tdate: new Date(event.ts),\n\t\t\t\t})\n\t\t\t\tawait this.table.updateOne({ key: event.key }, { $set: { status: 'done', completedAt: Date.now() } })\n\t\t\t\treturn result as R\n\t\t\t} catch (err) {\n\t\t\t\tconst message = err instanceof Error ? err.message : String(err)\n\t\t\t\tawait this.table.updateOne({ key: event.key }, { $set: { status: 'failed', error: message, completedAt: Date.now() } })\n\t\t\t\tthrow err\n\t\t\t}\n\t\t})\n\t}\n\n\tasync replay(from?: Date) {\n\t\tconst { results: events } = await this.table.query(\n\t\t\twrapQueryParams({\n\t\t\t\twhere: [...(from ? [{ field: 'ts', value: from.getTime(), condition: Conditions.gte }] : [])],\n\t\t\t\tsort: [{ field: 'ts', desc: false }],\n\t\t\t\tall: true,\n\t\t\t}),\n\t\t)\n\t\tfor (const event of events) await this.#processEvent(event)\n\t}\n\n\tasync rerun(key: string) {\n\t\tconst event = await this.table.findOne({ key })\n\t\tif (!event) throw new EquippedError('audit event not found', { key })\n\t\tawait this.#processEvent(event)\n\t}\n\n\tregister<P extends Pipe<any, any>, R>(type: string, handle: EventDefinition<P, R>) {\n\t\tif (this.handles[type]) throw new EquippedError(`${type} already has a registered handler`, {})\n\t\tthis.handles[type] = handle\n\t\tv.compile(handle.pipe)\n\t\treturn {\n\t\t\tsync: async (payload: PipeInput<P>, context: Context) => {\n\t\t\t\tconst event = await this.#createEvent(type, payload, 'sync', context)\n\t\t\t\treturn this.#processEvent<R>(event)\n\t\t\t},\n\t\t\tasync: async (payload: PipeInput<P>, context: Context) => {\n\t\t\t\tconst event = await this.#createEvent(type, payload, 'async', context)\n\t\t\t\tthis.#processEvent<R>(event).catch(() => {})\n\t\t\t},\n\t\t}\n\t}\n}\n"],"mappings":"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","names":["v","Conditions","wrapQueryParams","EquippedError","Instance","EventAudit","db","dbName","model","#createEvent","type","payload","mode","context","handler","validPayload","key","now","#processEvent","event","result","err","message","from","events","handle"]}
|
|
@@ -1,27 +1,26 @@
|
|
|
1
|
-
import { ulid } from "ulid";
|
|
2
1
|
import { v } from "valleyed";
|
|
3
2
|
import { Conditions, wrapQueryParams } from "../dbs/index.mjs";
|
|
4
3
|
import { EquippedError } from "../errors/index.mjs";
|
|
4
|
+
import { Instance } from "../instance/index.mjs";
|
|
5
5
|
class EventAudit {
|
|
6
|
-
constructor(db, dbName
|
|
6
|
+
constructor(db, dbName) {
|
|
7
7
|
this.db = db;
|
|
8
|
-
this.handlers = handlers;
|
|
9
8
|
this.table = db.use({
|
|
10
9
|
db: dbName,
|
|
11
10
|
col: "__audits",
|
|
12
11
|
mapper: (model) => ({ ...model, toJSON: () => model }),
|
|
13
12
|
options: { skipAudit: true }
|
|
14
13
|
});
|
|
15
|
-
for (const key in handlers) v.compile(handlers[key].pipe);
|
|
16
14
|
}
|
|
17
15
|
table;
|
|
18
|
-
|
|
19
|
-
|
|
16
|
+
handles = {};
|
|
17
|
+
async #createEvent(type, payload, mode, context) {
|
|
18
|
+
const handler = this.handles[type];
|
|
20
19
|
if (!handler) throw new EquippedError("audit handler not found", { type, payload, mode });
|
|
21
20
|
const validPayload = v.assert(handler.pipe, payload);
|
|
22
|
-
const key =
|
|
21
|
+
const key = Instance.createId();
|
|
23
22
|
const now = /* @__PURE__ */ new Date();
|
|
24
|
-
|
|
23
|
+
return await this.table.insertOne(
|
|
25
24
|
{
|
|
26
25
|
key,
|
|
27
26
|
type,
|
|
@@ -29,17 +28,17 @@ class EventAudit {
|
|
|
29
28
|
ts: now.getTime(),
|
|
30
29
|
payload: validPayload,
|
|
31
30
|
status: "pending",
|
|
31
|
+
userId: context.userId ?? null,
|
|
32
32
|
error: null,
|
|
33
33
|
startedAt: null,
|
|
34
34
|
completedAt: null
|
|
35
35
|
},
|
|
36
36
|
{ getTime: () => now, makeId: () => key }
|
|
37
37
|
);
|
|
38
|
-
return audit;
|
|
39
38
|
}
|
|
40
39
|
async #processEvent(event) {
|
|
41
40
|
return this.db.session(async () => {
|
|
42
|
-
const handler = this.
|
|
41
|
+
const handler = this.handles[event.type];
|
|
43
42
|
if (!handler) throw new EquippedError("audit handler not found", { event });
|
|
44
43
|
try {
|
|
45
44
|
await this.table.updateOne(
|
|
@@ -47,8 +46,9 @@ class EventAudit {
|
|
|
47
46
|
{ $set: { status: "processing", startedAt: Date.now(), completedAt: null, error: null } }
|
|
48
47
|
);
|
|
49
48
|
const result = await handler.handle(event.payload, {
|
|
50
|
-
|
|
51
|
-
|
|
49
|
+
key: event.key,
|
|
50
|
+
userId: event.userId,
|
|
51
|
+
date: new Date(event.ts)
|
|
52
52
|
});
|
|
53
53
|
await this.table.updateOne({ key: event.key }, { $set: { status: "done", completedAt: Date.now() } });
|
|
54
54
|
return result;
|
|
@@ -59,15 +59,6 @@ class EventAudit {
|
|
|
59
59
|
}
|
|
60
60
|
});
|
|
61
61
|
}
|
|
62
|
-
async createSync(type, payload) {
|
|
63
|
-
const event = await this.#createEvent(type, payload, "sync");
|
|
64
|
-
return this.#processEvent(event);
|
|
65
|
-
}
|
|
66
|
-
async createAsync(type, payload) {
|
|
67
|
-
const event = await this.#createEvent(type, payload, "async");
|
|
68
|
-
this.#processEvent(event).catch(() => {
|
|
69
|
-
});
|
|
70
|
-
}
|
|
71
62
|
async replay(from) {
|
|
72
63
|
const { results: events } = await this.table.query(
|
|
73
64
|
wrapQueryParams({
|
|
@@ -83,11 +74,21 @@ class EventAudit {
|
|
|
83
74
|
if (!event) throw new EquippedError("audit event not found", { key });
|
|
84
75
|
await this.#processEvent(event);
|
|
85
76
|
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
return {
|
|
77
|
+
register(type, handle) {
|
|
78
|
+
if (this.handles[type]) throw new EquippedError(`${type} already has a registered handler`, {});
|
|
79
|
+
this.handles[type] = handle;
|
|
80
|
+
v.compile(handle.pipe);
|
|
81
|
+
return {
|
|
82
|
+
sync: async (payload, context) => {
|
|
83
|
+
const event = await this.#createEvent(type, payload, "sync", context);
|
|
84
|
+
return this.#processEvent(event);
|
|
85
|
+
},
|
|
86
|
+
async: async (payload, context) => {
|
|
87
|
+
const event = await this.#createEvent(type, payload, "async", context);
|
|
88
|
+
this.#processEvent(event).catch(() => {
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
};
|
|
91
92
|
}
|
|
92
93
|
}
|
|
93
94
|
export {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/audit/events.ts"],"sourcesContent":["import {
|
|
1
|
+
{"version":3,"sources":["../../../src/audit/events.ts"],"sourcesContent":["import { Pipe, PipeInput, PipeOutput, v } from 'valleyed'\n\nimport { Conditions, Db, Table, wrapQueryParams } from '../dbs'\nimport { EquippedError } from '../errors'\nimport { Instance } from '../instance'\n\nexport type EventDefinition<P extends Pipe<any, any>, R> = {\n\tpipe: P\n\thandle: (payload: PipeOutput<P>, context: EventContext) => R | Promise<R>\n}\n\nexport type EventContext = {\n\tkey: string\n\tuserId: string | null\n\tdate: Date\n}\n\nexport type EventDoc = {\n\tkey: string\n\ttype: string\n\tts: number\n\tpayload: unknown\n\tmode: 'sync' | 'async'\n\tstatus: 'pending' | 'processing' | 'done' | 'failed'\n\tuserId: string | null\n\terror: string | null\n\tstartedAt: number | null\n\tcompletedAt: number | null\n}\ntype Context = { userId?: string }\n\nexport class EventAudit {\n\tprivate table: Table<any, EventDoc, EventDoc & { toJSON: () => Record<string, unknown> }, any>\n\tprivate handles: Record<string, EventDefinition<any, any>> = {}\n\n\tconstructor(\n\t\tprivate db: Db<any>,\n\t\tdbName: string,\n\t) {\n\t\tthis.table = db.use({\n\t\t\tdb: dbName,\n\t\t\tcol: '__audits',\n\t\t\tmapper: (model) => ({ ...model, toJSON: () => model as Record<string, unknown> }),\n\t\t\toptions: { skipAudit: true },\n\t\t})\n\t}\n\n\tasync #createEvent(type: string, payload: unknown, mode: 'sync' | 'async', context: Context) {\n\t\tconst handler = this.handles[type]\n\t\tif (!handler) throw new EquippedError('audit handler not found', { type, payload, mode })\n\n\t\tconst validPayload = v.assert(handler.pipe, payload)\n\t\tconst key = Instance.createId()\n\t\tconst now = new Date()\n\n\t\treturn await this.table.insertOne(\n\t\t\t{\n\t\t\t\tkey,\n\t\t\t\ttype,\n\t\t\t\tmode,\n\t\t\t\tts: now.getTime(),\n\t\t\t\tpayload: validPayload,\n\t\t\t\tstatus: 'pending',\n\t\t\t\tuserId: context.userId ?? null,\n\t\t\t\terror: null,\n\t\t\t\tstartedAt: null,\n\t\t\t\tcompletedAt: null,\n\t\t\t},\n\t\t\t{ getTime: () => now, makeId: () => key },\n\t\t)\n\t}\n\n\tasync #processEvent<R>(event: EventDoc) {\n\t\treturn this.db.session(async () => {\n\t\t\tconst handler = this.handles[event.type]\n\t\t\tif (!handler) throw new EquippedError('audit handler not found', { event })\n\t\t\ttry {\n\t\t\t\tawait this.table.updateOne(\n\t\t\t\t\t{ key: event.key },\n\t\t\t\t\t{ $set: { status: 'processing', startedAt: Date.now(), completedAt: null, error: null } },\n\t\t\t\t)\n\t\t\t\tconst result = await handler.handle(event.payload, {\n\t\t\t\t\tkey: event.key,\n\t\t\t\t\tuserId: event.userId,\n\t\t\t\t\tdate: new Date(event.ts),\n\t\t\t\t})\n\t\t\t\tawait this.table.updateOne({ key: event.key }, { $set: { status: 'done', completedAt: Date.now() } })\n\t\t\t\treturn result as R\n\t\t\t} catch (err) {\n\t\t\t\tconst message = err instanceof Error ? err.message : String(err)\n\t\t\t\tawait this.table.updateOne({ key: event.key }, { $set: { status: 'failed', error: message, completedAt: Date.now() } })\n\t\t\t\tthrow err\n\t\t\t}\n\t\t})\n\t}\n\n\tasync replay(from?: Date) {\n\t\tconst { results: events } = await this.table.query(\n\t\t\twrapQueryParams({\n\t\t\t\twhere: [...(from ? [{ field: 'ts', value: from.getTime(), condition: Conditions.gte }] : [])],\n\t\t\t\tsort: [{ field: 'ts', desc: false }],\n\t\t\t\tall: true,\n\t\t\t}),\n\t\t)\n\t\tfor (const event of events) await this.#processEvent(event)\n\t}\n\n\tasync rerun(key: string) {\n\t\tconst event = await this.table.findOne({ key })\n\t\tif (!event) throw new EquippedError('audit event not found', { key })\n\t\tawait this.#processEvent(event)\n\t}\n\n\tregister<P extends Pipe<any, any>, R>(type: string, handle: EventDefinition<P, R>) {\n\t\tif (this.handles[type]) throw new EquippedError(`${type} already has a registered handler`, {})\n\t\tthis.handles[type] = handle\n\t\tv.compile(handle.pipe)\n\t\treturn {\n\t\t\tsync: async (payload: PipeInput<P>, context: Context) => {\n\t\t\t\tconst event = await this.#createEvent(type, payload, 'sync', context)\n\t\t\t\treturn this.#processEvent<R>(event)\n\t\t\t},\n\t\t\tasync: async (payload: PipeInput<P>, context: Context) => {\n\t\t\t\tconst event = await this.#createEvent(type, payload, 'async', context)\n\t\t\t\tthis.#processEvent<R>(event).catch(() => {})\n\t\t\t},\n\t\t}\n\t}\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import a from"pino";import{ulid as p}from"ulid";import{v as s}from"valleyed";import{runHooks as o}from "./hooks.min.mjs";import{cachePipe as c,dbPipe as d,eventBusPipe as u,instanceSettingsPipe as l,jobsPipe as y,serverTypePipe as g}from "./settings.min.mjs";import{EquippedError as i}from "../errors/index.min.mjs";class r{static#e;static#t;static#r={};settings;log;constructor(e){r.#t=this,this.settings=Object.freeze(e),this.log=a({level:this.settings.log.level,serializers:{err:a.stdSerializers.err,error:a.stdSerializers.err,req:a.stdSerializers.req,res:a.stdSerializers.res},mixin:()=>({instanceId:r.#e})}),r.#s()}alias(e){if(r.#e!==void 0)return r.crash(new i("Instance already has an alias",{}));r.#e=e}get id(){return r.#e===void 0?r.crash(new i("Instance doesnt have an alias yet",{})):r.#e}getScopedName(e,t="."){return[this.settings.app.name,e].join(t)}createCache(e){return s.assert(c(),e)}createJobs(e){return s.assert(y(),e)}createEventBus(e){return s.assert(u(),e)}createDb(e){return s.assert(d(),e)}createServer(e){return s.assert(g(),e)}async start(){try{await o(r.#r.setup??[]),await o(r.#r.start??[])}catch(e){r.crash(new i("Error starting instance",{},e))}}static envs(e){const t=s.validate(e,process.env);return t.valid||r.crash(new i(`Environment variables are not valid
|
|
2
2
|
${t.error.toString()}`,{messages:t.error.messages})),t.value}static create(e){if(r.#t)return r.crash(new i("Instance has been initialized already",{}));const t=s.validate(l(),e);return t.valid||r.crash(new i(`Settings are not valid
|
|
3
|
-
${t.error.toString()}`,{messages:t.error.messages})),new r(t.value)}static get(){return r.#t?r.#t:r.crash(new i("Has not been initialized. Make sure an instance has been created before you get an instance",{}))}static on(e,t,
|
|
3
|
+
${t.error.toString()}`,{messages:t.error.messages})),new r(t.value)}static get(){return r.#t?r.#t:r.crash(new i("Has not been initialized. Make sure an instance has been created before you get an instance",{}))}static on(e,t,n){r.#r[e]??=[],r.#r[e].push({cb:t,order:n})}static#s(){Object.entries({SIGHUP:1,SIGINT:2,SIGTERM:15}).forEach(([t,n])=>{process.on(t,async()=>{await o(r.#r.close??[],()=>{}),process.exit(128+n)})})}static resolveBeforeCrash(e){const t=e();return r.on("close",async()=>await t,10),t}static crash(e){console.error(e),process.exit(1)}static createId(){return p()}}export{r as Instance};
|
|
4
4
|
//# sourceMappingURL=index.min.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/instance/index.ts"],"sourcesContent":["import pino, { Logger } from 'pino'\nimport { ConditionalObjectKeys, Pipe, PipeInput, v } from 'valleyed'\n\nimport { HookCb, HookEvent, HookRecord, runHooks } from './hooks'\nimport {\n\tcachePipe,\n\tCacheTypes,\n\tdbPipe,\n\tDbTypes,\n\teventBusPipe,\n\tEventBusTypes,\n\tinstanceSettingsPipe,\n\tjobsPipe,\n\tJobTypes,\n\tserverTypePipe,\n\tServerTypes,\n\tSettings,\n\tSettingsInput,\n} from './settings'\nimport { EquippedError } from '../errors'\n\nexport class Instance {\n\tstatic #id: string | undefined\n\tstatic #instance: Instance\n\tstatic #hooks: Partial<Record<HookEvent, HookRecord[]>> = {}\n\treadonly settings: Readonly<Settings>\n\treadonly log: Logger<never>\n\n\tprivate constructor(settings: Settings) {\n\t\tInstance.#instance = this\n\t\tthis.settings = Object.freeze(settings)\n\t\tthis.log = pino<never>({\n\t\t\tlevel: this.settings.log.level,\n\t\t\tserializers: {\n\t\t\t\terr: pino.stdSerializers.err,\n\t\t\t\terror: pino.stdSerializers.err,\n\t\t\t\treq: pino.stdSerializers.req,\n\t\t\t\tres: pino.stdSerializers.res,\n\t\t\t},\n\t\t\tmixin: () => ({\n\t\t\t\tinstanceId: Instance.#id,\n\t\t\t}),\n\t\t})\n\t\tInstance.#registerOnExitHandler()\n\t}\n\n\talias(id: string) {\n\t\tif (Instance.#id !== undefined) return Instance.crash(new EquippedError('Instance already has an alias', {}))\n\t\tInstance.#id = id\n\t}\n\n\tget id() {\n\t\tif (Instance.#id === undefined) return Instance.crash(new EquippedError('Instance doesnt have an alias yet', {}))\n\t\treturn Instance.#id\n\t}\n\n\tgetScopedName(name: string, key = '.') {\n\t\treturn [this.settings.app.name, name].join(key)\n\t}\n\n\tcreateCache<T extends PipeInput<ReturnType<typeof cachePipe>>>(input: ConditionalObjectKeys<T>) {\n\t\treturn v.assert(cachePipe(), input) as CacheTypes[T['type']]\n\t}\n\n\tcreateJobs<T extends PipeInput<ReturnType<typeof jobsPipe>>>(input: ConditionalObjectKeys<T>) {\n\t\treturn v.assert(jobsPipe(), input) as JobTypes[T['type']]\n\t}\n\n\tcreateEventBus<T extends PipeInput<ReturnType<typeof eventBusPipe>>>(input: ConditionalObjectKeys<T>) {\n\t\treturn v.assert(eventBusPipe(), input) as EventBusTypes[T['type']]\n\t}\n\n\tcreateDb<T extends PipeInput<ReturnType<typeof dbPipe>>>(input: ConditionalObjectKeys<T>) {\n\t\treturn v.assert(dbPipe(), input) as DbTypes[T['db']['type']]\n\t}\n\n\tcreateServer<T extends PipeInput<ReturnType<typeof serverTypePipe>>>(input: ConditionalObjectKeys<T>) {\n\t\treturn v.assert(serverTypePipe(), input) as ServerTypes[T['type']]\n\t}\n\n\tasync start() {\n\t\ttry {\n\t\t\tawait runHooks(Instance.#hooks['setup'] ?? [])\n\t\t\tawait runHooks(Instance.#hooks['start'] ?? [])\n\t\t} catch (error) {\n\t\t\tInstance.crash(new EquippedError(`Error starting instance`, {}, error))\n\t\t}\n\t}\n\n\tstatic envs<E extends object>(envsPipe: Pipe<unknown, E>): E {\n\t\tconst envValidity = v.validate(envsPipe, process.env)\n\t\tif (!envValidity.valid) {\n\t\t\tInstance.crash(\n\t\t\t\tnew EquippedError(`Environment variables are not valid\\n${envValidity.error.toString()}`, {\n\t\t\t\t\tmessages: envValidity.error.messages,\n\t\t\t\t}),\n\t\t\t)\n\t\t}\n\t\treturn envValidity.value\n\t}\n\n\tstatic create(settings: SettingsInput) {\n\t\tif (Instance.#instance) return Instance.crash(new EquippedError('Instance has been initialized already', {}))\n\t\tconst settingsValidity = v.validate(instanceSettingsPipe(), settings)\n\t\tif (!settingsValidity.valid) {\n\t\t\tInstance.crash(\n\t\t\t\tnew EquippedError(`Settings are not valid\\n${settingsValidity.error.toString()}`, {\n\t\t\t\t\tmessages: settingsValidity.error.messages,\n\t\t\t\t}),\n\t\t\t)\n\t\t}\n\t\treturn new Instance(settingsValidity.value)\n\t}\n\n\tstatic get() {\n\t\tif (!Instance.#instance)\n\t\t\treturn Instance.crash(\n\t\t\t\tnew EquippedError('Has not been initialized. Make sure an instance has been created before you get an instance', {}),\n\t\t\t)\n\t\treturn Instance.#instance\n\t}\n\n\tstatic on(event: HookEvent, cb: HookCb, order: number) {\n\t\tInstance.#hooks[event] ??= []\n\t\tInstance.#hooks[event].push({ cb, order })\n\t}\n\n\tstatic #registerOnExitHandler() {\n\t\tconst signals = {\n\t\t\tSIGHUP: 1,\n\t\t\tSIGINT: 2,\n\t\t\tSIGTERM: 15,\n\t\t}\n\n\t\tObject.entries(signals).forEach(([signal, code]) => {\n\t\t\tprocess.on(signal, async () => {\n\t\t\t\tawait runHooks(Instance.#hooks['close'] ?? [], () => {})\n\t\t\t\tprocess.exit(128 + code)\n\t\t\t})\n\t\t})\n\t}\n\n\tstatic resolveBeforeCrash<T>(cb: () => Promise<T>) {\n\t\tconst value = cb()\n\t\tInstance.on('close', async () => await value, 10)\n\t\treturn value\n\t}\n\n\tstatic crash(error: EquippedError): never {\n\t\t// eslint-disable-next-line no-console\n\t\tconsole.error(error)\n\t\tprocess.exit(1)\n\t}\n}\n"],"mappings":"AAAA,OAAOA,MAAsB,OAC7B,OAAiD,KAAAC,MAAS,WAE1D,OAAwC,YAAAC,MAAgB,UACxD,OACC,aAAAC,EAEA,UAAAC,EAEA,gBAAAC,EAEA,wBAAAC,EACA,YAAAC,EAEA,kBAAAC,MAIM,aACP,OAAS,iBAAAC,MAAqB,YAEvB,MAAMC,CAAS,CACrB,MAAOC,GACP,MAAOC,GACP,MAAOC,GAAmD,CAAC,EAClD,SACA,IAED,YAAYC,EAAoB,CACvCJ,EAASE,GAAY,KACrB,KAAK,SAAW,OAAO,OAAOE,CAAQ,EACtC,KAAK,
|
|
1
|
+
{"version":3,"sources":["../../../src/instance/index.ts"],"sourcesContent":["import pino, { Logger } from 'pino'\nimport { ulid } from 'ulid'\nimport { ConditionalObjectKeys, Pipe, PipeInput, v } from 'valleyed'\n\nimport { HookCb, HookEvent, HookRecord, runHooks } from './hooks'\nimport {\n\tcachePipe,\n\tCacheTypes,\n\tdbPipe,\n\tDbTypes,\n\teventBusPipe,\n\tEventBusTypes,\n\tinstanceSettingsPipe,\n\tjobsPipe,\n\tJobTypes,\n\tserverTypePipe,\n\tServerTypes,\n\tSettings,\n\tSettingsInput,\n} from './settings'\nimport { EquippedError } from '../errors'\n\nexport class Instance {\n\tstatic #id: string | undefined\n\tstatic #instance: Instance\n\tstatic #hooks: Partial<Record<HookEvent, HookRecord[]>> = {}\n\treadonly settings: Readonly<Settings>\n\treadonly log: Logger<never>\n\n\tprivate constructor(settings: Settings) {\n\t\tInstance.#instance = this\n\t\tthis.settings = Object.freeze(settings)\n\t\tthis.log = pino<never>({\n\t\t\tlevel: this.settings.log.level,\n\t\t\tserializers: {\n\t\t\t\terr: pino.stdSerializers.err,\n\t\t\t\terror: pino.stdSerializers.err,\n\t\t\t\treq: pino.stdSerializers.req,\n\t\t\t\tres: pino.stdSerializers.res,\n\t\t\t},\n\t\t\tmixin: () => ({\n\t\t\t\tinstanceId: Instance.#id,\n\t\t\t}),\n\t\t})\n\t\tInstance.#registerOnExitHandler()\n\t}\n\n\talias(id: string) {\n\t\tif (Instance.#id !== undefined) return Instance.crash(new EquippedError('Instance already has an alias', {}))\n\t\tInstance.#id = id\n\t}\n\n\tget id() {\n\t\tif (Instance.#id === undefined) return Instance.crash(new EquippedError('Instance doesnt have an alias yet', {}))\n\t\treturn Instance.#id\n\t}\n\n\tgetScopedName(name: string, key = '.') {\n\t\treturn [this.settings.app.name, name].join(key)\n\t}\n\n\tcreateCache<T extends PipeInput<ReturnType<typeof cachePipe>>>(input: ConditionalObjectKeys<T>) {\n\t\treturn v.assert(cachePipe(), input) as CacheTypes[T['type']]\n\t}\n\n\tcreateJobs<T extends PipeInput<ReturnType<typeof jobsPipe>>>(input: ConditionalObjectKeys<T>) {\n\t\treturn v.assert(jobsPipe(), input) as JobTypes[T['type']]\n\t}\n\n\tcreateEventBus<T extends PipeInput<ReturnType<typeof eventBusPipe>>>(input: ConditionalObjectKeys<T>) {\n\t\treturn v.assert(eventBusPipe(), input) as EventBusTypes[T['type']]\n\t}\n\n\tcreateDb<T extends PipeInput<ReturnType<typeof dbPipe>>>(input: ConditionalObjectKeys<T>) {\n\t\treturn v.assert(dbPipe(), input) as DbTypes[T['db']['type']]\n\t}\n\n\tcreateServer<T extends PipeInput<ReturnType<typeof serverTypePipe>>>(input: ConditionalObjectKeys<T>) {\n\t\treturn v.assert(serverTypePipe(), input) as ServerTypes[T['type']]\n\t}\n\n\tasync start() {\n\t\ttry {\n\t\t\tawait runHooks(Instance.#hooks['setup'] ?? [])\n\t\t\tawait runHooks(Instance.#hooks['start'] ?? [])\n\t\t} catch (error) {\n\t\t\tInstance.crash(new EquippedError(`Error starting instance`, {}, error))\n\t\t}\n\t}\n\n\tstatic envs<E extends object>(envsPipe: Pipe<unknown, E>): E {\n\t\tconst envValidity = v.validate(envsPipe, process.env)\n\t\tif (!envValidity.valid) {\n\t\t\tInstance.crash(\n\t\t\t\tnew EquippedError(`Environment variables are not valid\\n${envValidity.error.toString()}`, {\n\t\t\t\t\tmessages: envValidity.error.messages,\n\t\t\t\t}),\n\t\t\t)\n\t\t}\n\t\treturn envValidity.value\n\t}\n\n\tstatic create(settings: SettingsInput) {\n\t\tif (Instance.#instance) return Instance.crash(new EquippedError('Instance has been initialized already', {}))\n\t\tconst settingsValidity = v.validate(instanceSettingsPipe(), settings)\n\t\tif (!settingsValidity.valid) {\n\t\t\tInstance.crash(\n\t\t\t\tnew EquippedError(`Settings are not valid\\n${settingsValidity.error.toString()}`, {\n\t\t\t\t\tmessages: settingsValidity.error.messages,\n\t\t\t\t}),\n\t\t\t)\n\t\t}\n\t\treturn new Instance(settingsValidity.value)\n\t}\n\n\tstatic get() {\n\t\tif (!Instance.#instance)\n\t\t\treturn Instance.crash(\n\t\t\t\tnew EquippedError('Has not been initialized. Make sure an instance has been created before you get an instance', {}),\n\t\t\t)\n\t\treturn Instance.#instance\n\t}\n\n\tstatic on(event: HookEvent, cb: HookCb, order: number) {\n\t\tInstance.#hooks[event] ??= []\n\t\tInstance.#hooks[event].push({ cb, order })\n\t}\n\n\tstatic #registerOnExitHandler() {\n\t\tconst signals = {\n\t\t\tSIGHUP: 1,\n\t\t\tSIGINT: 2,\n\t\t\tSIGTERM: 15,\n\t\t}\n\n\t\tObject.entries(signals).forEach(([signal, code]) => {\n\t\t\tprocess.on(signal, async () => {\n\t\t\t\tawait runHooks(Instance.#hooks['close'] ?? [], () => {})\n\t\t\t\tprocess.exit(128 + code)\n\t\t\t})\n\t\t})\n\t}\n\n\tstatic resolveBeforeCrash<T>(cb: () => Promise<T>) {\n\t\tconst value = cb()\n\t\tInstance.on('close', async () => await value, 10)\n\t\treturn value\n\t}\n\n\tstatic crash(error: EquippedError): never {\n\t\t// eslint-disable-next-line no-console\n\t\tconsole.error(error)\n\t\tprocess.exit(1)\n\t}\n\n\tstatic createId() {\n\t\treturn ulid()\n\t}\n}\n"],"mappings":"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","names":["pino","ulid","v","runHooks","cachePipe","dbPipe","eventBusPipe","instanceSettingsPipe","jobsPipe","serverTypePipe","EquippedError","Instance","#id","#instance","#hooks","settings","#registerOnExitHandler","id","name","key","input","error","envsPipe","envValidity","settingsValidity","event","cb","order","signal","code","value"]}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import pino from "pino";
|
|
2
|
+
import { ulid } from "ulid";
|
|
2
3
|
import { v } from "valleyed";
|
|
3
4
|
import { runHooks } from "./hooks.mjs";
|
|
4
5
|
import {
|
|
@@ -126,6 +127,9 @@ ${settingsValidity.error.toString()}`, {
|
|
|
126
127
|
console.error(error);
|
|
127
128
|
process.exit(1);
|
|
128
129
|
}
|
|
130
|
+
static createId() {
|
|
131
|
+
return ulid();
|
|
132
|
+
}
|
|
129
133
|
}
|
|
130
134
|
export {
|
|
131
135
|
Instance
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/instance/index.ts"],"sourcesContent":["import pino, { Logger } from 'pino'\nimport { ConditionalObjectKeys, Pipe, PipeInput, v } from 'valleyed'\n\nimport { HookCb, HookEvent, HookRecord, runHooks } from './hooks'\nimport {\n\tcachePipe,\n\tCacheTypes,\n\tdbPipe,\n\tDbTypes,\n\teventBusPipe,\n\tEventBusTypes,\n\tinstanceSettingsPipe,\n\tjobsPipe,\n\tJobTypes,\n\tserverTypePipe,\n\tServerTypes,\n\tSettings,\n\tSettingsInput,\n} from './settings'\nimport { EquippedError } from '../errors'\n\nexport class Instance {\n\tstatic #id: string | undefined\n\tstatic #instance: Instance\n\tstatic #hooks: Partial<Record<HookEvent, HookRecord[]>> = {}\n\treadonly settings: Readonly<Settings>\n\treadonly log: Logger<never>\n\n\tprivate constructor(settings: Settings) {\n\t\tInstance.#instance = this\n\t\tthis.settings = Object.freeze(settings)\n\t\tthis.log = pino<never>({\n\t\t\tlevel: this.settings.log.level,\n\t\t\tserializers: {\n\t\t\t\terr: pino.stdSerializers.err,\n\t\t\t\terror: pino.stdSerializers.err,\n\t\t\t\treq: pino.stdSerializers.req,\n\t\t\t\tres: pino.stdSerializers.res,\n\t\t\t},\n\t\t\tmixin: () => ({\n\t\t\t\tinstanceId: Instance.#id,\n\t\t\t}),\n\t\t})\n\t\tInstance.#registerOnExitHandler()\n\t}\n\n\talias(id: string) {\n\t\tif (Instance.#id !== undefined) return Instance.crash(new EquippedError('Instance already has an alias', {}))\n\t\tInstance.#id = id\n\t}\n\n\tget id() {\n\t\tif (Instance.#id === undefined) return Instance.crash(new EquippedError('Instance doesnt have an alias yet', {}))\n\t\treturn Instance.#id\n\t}\n\n\tgetScopedName(name: string, key = '.') {\n\t\treturn [this.settings.app.name, name].join(key)\n\t}\n\n\tcreateCache<T extends PipeInput<ReturnType<typeof cachePipe>>>(input: ConditionalObjectKeys<T>) {\n\t\treturn v.assert(cachePipe(), input) as CacheTypes[T['type']]\n\t}\n\n\tcreateJobs<T extends PipeInput<ReturnType<typeof jobsPipe>>>(input: ConditionalObjectKeys<T>) {\n\t\treturn v.assert(jobsPipe(), input) as JobTypes[T['type']]\n\t}\n\n\tcreateEventBus<T extends PipeInput<ReturnType<typeof eventBusPipe>>>(input: ConditionalObjectKeys<T>) {\n\t\treturn v.assert(eventBusPipe(), input) as EventBusTypes[T['type']]\n\t}\n\n\tcreateDb<T extends PipeInput<ReturnType<typeof dbPipe>>>(input: ConditionalObjectKeys<T>) {\n\t\treturn v.assert(dbPipe(), input) as DbTypes[T['db']['type']]\n\t}\n\n\tcreateServer<T extends PipeInput<ReturnType<typeof serverTypePipe>>>(input: ConditionalObjectKeys<T>) {\n\t\treturn v.assert(serverTypePipe(), input) as ServerTypes[T['type']]\n\t}\n\n\tasync start() {\n\t\ttry {\n\t\t\tawait runHooks(Instance.#hooks['setup'] ?? [])\n\t\t\tawait runHooks(Instance.#hooks['start'] ?? [])\n\t\t} catch (error) {\n\t\t\tInstance.crash(new EquippedError(`Error starting instance`, {}, error))\n\t\t}\n\t}\n\n\tstatic envs<E extends object>(envsPipe: Pipe<unknown, E>): E {\n\t\tconst envValidity = v.validate(envsPipe, process.env)\n\t\tif (!envValidity.valid) {\n\t\t\tInstance.crash(\n\t\t\t\tnew EquippedError(`Environment variables are not valid\\n${envValidity.error.toString()}`, {\n\t\t\t\t\tmessages: envValidity.error.messages,\n\t\t\t\t}),\n\t\t\t)\n\t\t}\n\t\treturn envValidity.value\n\t}\n\n\tstatic create(settings: SettingsInput) {\n\t\tif (Instance.#instance) return Instance.crash(new EquippedError('Instance has been initialized already', {}))\n\t\tconst settingsValidity = v.validate(instanceSettingsPipe(), settings)\n\t\tif (!settingsValidity.valid) {\n\t\t\tInstance.crash(\n\t\t\t\tnew EquippedError(`Settings are not valid\\n${settingsValidity.error.toString()}`, {\n\t\t\t\t\tmessages: settingsValidity.error.messages,\n\t\t\t\t}),\n\t\t\t)\n\t\t}\n\t\treturn new Instance(settingsValidity.value)\n\t}\n\n\tstatic get() {\n\t\tif (!Instance.#instance)\n\t\t\treturn Instance.crash(\n\t\t\t\tnew EquippedError('Has not been initialized. Make sure an instance has been created before you get an instance', {}),\n\t\t\t)\n\t\treturn Instance.#instance\n\t}\n\n\tstatic on(event: HookEvent, cb: HookCb, order: number) {\n\t\tInstance.#hooks[event] ??= []\n\t\tInstance.#hooks[event].push({ cb, order })\n\t}\n\n\tstatic #registerOnExitHandler() {\n\t\tconst signals = {\n\t\t\tSIGHUP: 1,\n\t\t\tSIGINT: 2,\n\t\t\tSIGTERM: 15,\n\t\t}\n\n\t\tObject.entries(signals).forEach(([signal, code]) => {\n\t\t\tprocess.on(signal, async () => {\n\t\t\t\tawait runHooks(Instance.#hooks['close'] ?? [], () => {})\n\t\t\t\tprocess.exit(128 + code)\n\t\t\t})\n\t\t})\n\t}\n\n\tstatic resolveBeforeCrash<T>(cb: () => Promise<T>) {\n\t\tconst value = cb()\n\t\tInstance.on('close', async () => await value, 10)\n\t\treturn value\n\t}\n\n\tstatic crash(error: EquippedError): never {\n\t\t// eslint-disable-next-line no-console\n\t\tconsole.error(error)\n\t\tprocess.exit(1)\n\t}\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/instance/index.ts"],"sourcesContent":["import pino, { Logger } from 'pino'\nimport { ulid } from 'ulid'\nimport { ConditionalObjectKeys, Pipe, PipeInput, v } from 'valleyed'\n\nimport { HookCb, HookEvent, HookRecord, runHooks } from './hooks'\nimport {\n\tcachePipe,\n\tCacheTypes,\n\tdbPipe,\n\tDbTypes,\n\teventBusPipe,\n\tEventBusTypes,\n\tinstanceSettingsPipe,\n\tjobsPipe,\n\tJobTypes,\n\tserverTypePipe,\n\tServerTypes,\n\tSettings,\n\tSettingsInput,\n} from './settings'\nimport { EquippedError } from '../errors'\n\nexport class Instance {\n\tstatic #id: string | undefined\n\tstatic #instance: Instance\n\tstatic #hooks: Partial<Record<HookEvent, HookRecord[]>> = {}\n\treadonly settings: Readonly<Settings>\n\treadonly log: Logger<never>\n\n\tprivate constructor(settings: Settings) {\n\t\tInstance.#instance = this\n\t\tthis.settings = Object.freeze(settings)\n\t\tthis.log = pino<never>({\n\t\t\tlevel: this.settings.log.level,\n\t\t\tserializers: {\n\t\t\t\terr: pino.stdSerializers.err,\n\t\t\t\terror: pino.stdSerializers.err,\n\t\t\t\treq: pino.stdSerializers.req,\n\t\t\t\tres: pino.stdSerializers.res,\n\t\t\t},\n\t\t\tmixin: () => ({\n\t\t\t\tinstanceId: Instance.#id,\n\t\t\t}),\n\t\t})\n\t\tInstance.#registerOnExitHandler()\n\t}\n\n\talias(id: string) {\n\t\tif (Instance.#id !== undefined) return Instance.crash(new EquippedError('Instance already has an alias', {}))\n\t\tInstance.#id = id\n\t}\n\n\tget id() {\n\t\tif (Instance.#id === undefined) return Instance.crash(new EquippedError('Instance doesnt have an alias yet', {}))\n\t\treturn Instance.#id\n\t}\n\n\tgetScopedName(name: string, key = '.') {\n\t\treturn [this.settings.app.name, name].join(key)\n\t}\n\n\tcreateCache<T extends PipeInput<ReturnType<typeof cachePipe>>>(input: ConditionalObjectKeys<T>) {\n\t\treturn v.assert(cachePipe(), input) as CacheTypes[T['type']]\n\t}\n\n\tcreateJobs<T extends PipeInput<ReturnType<typeof jobsPipe>>>(input: ConditionalObjectKeys<T>) {\n\t\treturn v.assert(jobsPipe(), input) as JobTypes[T['type']]\n\t}\n\n\tcreateEventBus<T extends PipeInput<ReturnType<typeof eventBusPipe>>>(input: ConditionalObjectKeys<T>) {\n\t\treturn v.assert(eventBusPipe(), input) as EventBusTypes[T['type']]\n\t}\n\n\tcreateDb<T extends PipeInput<ReturnType<typeof dbPipe>>>(input: ConditionalObjectKeys<T>) {\n\t\treturn v.assert(dbPipe(), input) as DbTypes[T['db']['type']]\n\t}\n\n\tcreateServer<T extends PipeInput<ReturnType<typeof serverTypePipe>>>(input: ConditionalObjectKeys<T>) {\n\t\treturn v.assert(serverTypePipe(), input) as ServerTypes[T['type']]\n\t}\n\n\tasync start() {\n\t\ttry {\n\t\t\tawait runHooks(Instance.#hooks['setup'] ?? [])\n\t\t\tawait runHooks(Instance.#hooks['start'] ?? [])\n\t\t} catch (error) {\n\t\t\tInstance.crash(new EquippedError(`Error starting instance`, {}, error))\n\t\t}\n\t}\n\n\tstatic envs<E extends object>(envsPipe: Pipe<unknown, E>): E {\n\t\tconst envValidity = v.validate(envsPipe, process.env)\n\t\tif (!envValidity.valid) {\n\t\t\tInstance.crash(\n\t\t\t\tnew EquippedError(`Environment variables are not valid\\n${envValidity.error.toString()}`, {\n\t\t\t\t\tmessages: envValidity.error.messages,\n\t\t\t\t}),\n\t\t\t)\n\t\t}\n\t\treturn envValidity.value\n\t}\n\n\tstatic create(settings: SettingsInput) {\n\t\tif (Instance.#instance) return Instance.crash(new EquippedError('Instance has been initialized already', {}))\n\t\tconst settingsValidity = v.validate(instanceSettingsPipe(), settings)\n\t\tif (!settingsValidity.valid) {\n\t\t\tInstance.crash(\n\t\t\t\tnew EquippedError(`Settings are not valid\\n${settingsValidity.error.toString()}`, {\n\t\t\t\t\tmessages: settingsValidity.error.messages,\n\t\t\t\t}),\n\t\t\t)\n\t\t}\n\t\treturn new Instance(settingsValidity.value)\n\t}\n\n\tstatic get() {\n\t\tif (!Instance.#instance)\n\t\t\treturn Instance.crash(\n\t\t\t\tnew EquippedError('Has not been initialized. Make sure an instance has been created before you get an instance', {}),\n\t\t\t)\n\t\treturn Instance.#instance\n\t}\n\n\tstatic on(event: HookEvent, cb: HookCb, order: number) {\n\t\tInstance.#hooks[event] ??= []\n\t\tInstance.#hooks[event].push({ cb, order })\n\t}\n\n\tstatic #registerOnExitHandler() {\n\t\tconst signals = {\n\t\t\tSIGHUP: 1,\n\t\t\tSIGINT: 2,\n\t\t\tSIGTERM: 15,\n\t\t}\n\n\t\tObject.entries(signals).forEach(([signal, code]) => {\n\t\t\tprocess.on(signal, async () => {\n\t\t\t\tawait runHooks(Instance.#hooks['close'] ?? [], () => {})\n\t\t\t\tprocess.exit(128 + code)\n\t\t\t})\n\t\t})\n\t}\n\n\tstatic resolveBeforeCrash<T>(cb: () => Promise<T>) {\n\t\tconst value = cb()\n\t\tInstance.on('close', async () => await value, 10)\n\t\treturn value\n\t}\n\n\tstatic crash(error: EquippedError): never {\n\t\t// eslint-disable-next-line no-console\n\t\tconsole.error(error)\n\t\tprocess.exit(1)\n\t}\n\n\tstatic createId() {\n\t\treturn ulid()\n\t}\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,27 +1,26 @@
|
|
|
1
|
-
import { ulid } from "ulid";
|
|
2
1
|
import { v } from "valleyed";
|
|
3
2
|
import { Conditions, wrapQueryParams } from "../dbs/index.js";
|
|
4
3
|
import { EquippedError } from "../errors/index.js";
|
|
4
|
+
import { Instance } from "../instance/index.js";
|
|
5
5
|
class EventAudit {
|
|
6
|
-
constructor(db, dbName
|
|
6
|
+
constructor(db, dbName) {
|
|
7
7
|
this.db = db;
|
|
8
|
-
this.handlers = handlers;
|
|
9
8
|
this.table = db.use({
|
|
10
9
|
db: dbName,
|
|
11
10
|
col: "__audits",
|
|
12
11
|
mapper: (model) => ({ ...model, toJSON: () => model }),
|
|
13
12
|
options: { skipAudit: true }
|
|
14
13
|
});
|
|
15
|
-
for (const key in handlers) v.compile(handlers[key].pipe);
|
|
16
14
|
}
|
|
17
15
|
table;
|
|
18
|
-
|
|
19
|
-
|
|
16
|
+
handles = {};
|
|
17
|
+
async #createEvent(type, payload, mode, context) {
|
|
18
|
+
const handler = this.handles[type];
|
|
20
19
|
if (!handler) throw new EquippedError("audit handler not found", { type, payload, mode });
|
|
21
20
|
const validPayload = v.assert(handler.pipe, payload);
|
|
22
|
-
const key =
|
|
21
|
+
const key = Instance.createId();
|
|
23
22
|
const now = /* @__PURE__ */ new Date();
|
|
24
|
-
|
|
23
|
+
return await this.table.insertOne(
|
|
25
24
|
{
|
|
26
25
|
key,
|
|
27
26
|
type,
|
|
@@ -29,17 +28,17 @@ class EventAudit {
|
|
|
29
28
|
ts: now.getTime(),
|
|
30
29
|
payload: validPayload,
|
|
31
30
|
status: "pending",
|
|
31
|
+
userId: context.userId ?? null,
|
|
32
32
|
error: null,
|
|
33
33
|
startedAt: null,
|
|
34
34
|
completedAt: null
|
|
35
35
|
},
|
|
36
36
|
{ getTime: () => now, makeId: () => key }
|
|
37
37
|
);
|
|
38
|
-
return audit;
|
|
39
38
|
}
|
|
40
39
|
async #processEvent(event) {
|
|
41
40
|
return this.db.session(async () => {
|
|
42
|
-
const handler = this.
|
|
41
|
+
const handler = this.handles[event.type];
|
|
43
42
|
if (!handler) throw new EquippedError("audit handler not found", { event });
|
|
44
43
|
try {
|
|
45
44
|
await this.table.updateOne(
|
|
@@ -47,8 +46,9 @@ class EventAudit {
|
|
|
47
46
|
{ $set: { status: "processing", startedAt: Date.now(), completedAt: null, error: null } }
|
|
48
47
|
);
|
|
49
48
|
const result = await handler.handle(event.payload, {
|
|
50
|
-
|
|
51
|
-
|
|
49
|
+
key: event.key,
|
|
50
|
+
userId: event.userId,
|
|
51
|
+
date: new Date(event.ts)
|
|
52
52
|
});
|
|
53
53
|
await this.table.updateOne({ key: event.key }, { $set: { status: "done", completedAt: Date.now() } });
|
|
54
54
|
return result;
|
|
@@ -59,15 +59,6 @@ class EventAudit {
|
|
|
59
59
|
}
|
|
60
60
|
});
|
|
61
61
|
}
|
|
62
|
-
async createSync(type, payload) {
|
|
63
|
-
const event = await this.#createEvent(type, payload, "sync");
|
|
64
|
-
return this.#processEvent(event);
|
|
65
|
-
}
|
|
66
|
-
async createAsync(type, payload) {
|
|
67
|
-
const event = await this.#createEvent(type, payload, "async");
|
|
68
|
-
this.#processEvent(event).catch(() => {
|
|
69
|
-
});
|
|
70
|
-
}
|
|
71
62
|
async replay(from) {
|
|
72
63
|
const { results: events } = await this.table.query(
|
|
73
64
|
wrapQueryParams({
|
|
@@ -83,11 +74,21 @@ class EventAudit {
|
|
|
83
74
|
if (!event) throw new EquippedError("audit event not found", { key });
|
|
84
75
|
await this.#processEvent(event);
|
|
85
76
|
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
return {
|
|
77
|
+
register(type, handle) {
|
|
78
|
+
if (this.handles[type]) throw new EquippedError(`${type} already has a registered handler`, {});
|
|
79
|
+
this.handles[type] = handle;
|
|
80
|
+
v.compile(handle.pipe);
|
|
81
|
+
return {
|
|
82
|
+
sync: async (payload, context) => {
|
|
83
|
+
const event = await this.#createEvent(type, payload, "sync", context);
|
|
84
|
+
return this.#processEvent(event);
|
|
85
|
+
},
|
|
86
|
+
async: async (payload, context) => {
|
|
87
|
+
const event = await this.#createEvent(type, payload, "async", context);
|
|
88
|
+
this.#processEvent(event).catch(() => {
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
};
|
|
91
92
|
}
|
|
92
93
|
}
|
|
93
94
|
export {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Pipe, PipeInput } from 'valleyed';
|
|
1
|
+
import { Pipe, PipeOutput, PipeInput } from 'valleyed';
|
|
2
2
|
import { D as Db } from '../db-Bh0mF2ja.js';
|
|
3
3
|
import '../core-BuPovjLX.js';
|
|
4
4
|
import 'mongodb';
|
|
@@ -6,32 +6,29 @@ import '../kafka-zsC3c8ar.js';
|
|
|
6
6
|
import '../overrides-6Hxg764S.js';
|
|
7
7
|
import '../base-CfeyC14V.js';
|
|
8
8
|
|
|
9
|
-
type EventDefinition<
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
handle: (payload: P, context: {
|
|
13
|
-
idempotencyKey: string;
|
|
14
|
-
idempotencyDate: Date;
|
|
15
|
-
}) => Promise<R>;
|
|
9
|
+
type EventDefinition<P extends Pipe<any, any>, R> = {
|
|
10
|
+
pipe: P;
|
|
11
|
+
handle: (payload: PipeOutput<P>, context: EventContext) => R | Promise<R>;
|
|
16
12
|
};
|
|
17
|
-
|
|
13
|
+
type EventContext = {
|
|
14
|
+
key: string;
|
|
15
|
+
userId: string | null;
|
|
16
|
+
date: Date;
|
|
17
|
+
};
|
|
18
|
+
type Context = {
|
|
19
|
+
userId?: string;
|
|
20
|
+
};
|
|
21
|
+
declare class EventAudit {
|
|
18
22
|
#private;
|
|
19
23
|
private db;
|
|
20
|
-
private handlers;
|
|
21
24
|
private table;
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
createAsync<K extends keyof E & string>(type: K, payload: PipeInput<E[K]['pipe']>): Promise<void>;
|
|
25
|
+
private handles;
|
|
26
|
+
constructor(db: Db<any>, dbName: string);
|
|
25
27
|
replay(from?: Date): Promise<void>;
|
|
26
28
|
rerun(key: string): Promise<void>;
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
pipe: Pipe<any, P>;
|
|
31
|
-
handle: (payload: P, context: {
|
|
32
|
-
idempotencyKey: string;
|
|
33
|
-
idempotencyDate: Date;
|
|
34
|
-
}) => Promise<R>;
|
|
29
|
+
register<P extends Pipe<any, any>, R>(type: string, handle: EventDefinition<P, R>): {
|
|
30
|
+
sync: (payload: PipeInput<P>, context: Context) => Promise<R>;
|
|
31
|
+
async: (payload: PipeInput<P>, context: Context) => Promise<void>;
|
|
35
32
|
};
|
|
36
33
|
}
|
|
37
34
|
|
|
@@ -178,6 +178,7 @@ declare class Instance {
|
|
|
178
178
|
static on(event: HookEvent, cb: HookCb, order: number): void;
|
|
179
179
|
static resolveBeforeCrash<T>(cb: () => Promise<T>): Promise<T>;
|
|
180
180
|
static crash(error: EquippedError): never;
|
|
181
|
+
static createId(): string;
|
|
181
182
|
}
|
|
182
183
|
|
|
183
184
|
export { Instance };
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import pino from "pino";
|
|
2
|
+
import { ulid } from "ulid";
|
|
2
3
|
import { v } from "valleyed";
|
|
3
4
|
import { runHooks } from "./hooks.js";
|
|
4
5
|
import {
|
|
@@ -126,6 +127,9 @@ ${settingsValidity.error.toString()}`, {
|
|
|
126
127
|
console.error(error);
|
|
127
128
|
process.exit(1);
|
|
128
129
|
}
|
|
130
|
+
static createId() {
|
|
131
|
+
return ulid();
|
|
132
|
+
}
|
|
129
133
|
}
|
|
130
134
|
export {
|
|
131
135
|
Instance
|