equipped 5.0.33 → 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 CHANGED
@@ -2,6 +2,13 @@
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
+
5
12
  ### [5.0.33](https://github.com/kevinand11/equipped/compare/v5.0.32...v5.0.33) (2025-10-02)
6
13
 
7
14
  ### [5.0.32](https://github.com/kevinand11/equipped/compare/v5.0.31...v5.0.32) (2025-10-02)
@@ -1,4 +1,4 @@
1
- "use strict";Object.defineProperty(exports, "__esModule", {value: true});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');
2
2
  var _indexcjs = require('../dbs/index.cjs');
3
3
  var _indexcjs3 = require('../errors/index.cjs');
4
4
  var _indexcjs5 = require('../instance/index.cjs');
@@ -14,7 +14,7 @@ class EventAudit {
14
14
  }
15
15
 
16
16
  __init() {this.handles = {}}
17
- async #createEvent(type, payload, mode) {
17
+ async #createEvent(type, payload, mode, context) {
18
18
  const handler = this.handles[type];
19
19
  if (!handler) throw new (0, _indexcjs3.EquippedError)("audit handler not found", { type, payload, mode });
20
20
  const validPayload = _valleyed.v.assert(handler.pipe, payload);
@@ -28,6 +28,7 @@ class EventAudit {
28
28
  ts: now.getTime(),
29
29
  payload: validPayload,
30
30
  status: "pending",
31
+ userId: _nullishCoalesce(context.userId, () => ( null)),
31
32
  error: null,
32
33
  startedAt: null,
33
34
  completedAt: null
@@ -45,8 +46,9 @@ class EventAudit {
45
46
  { $set: { status: "processing", startedAt: Date.now(), completedAt: null, error: null } }
46
47
  );
47
48
  const result = await handler.handle(event.payload, {
48
- idempotencyKey: event.key.toString(),
49
- idempotencyDate: new Date(event.ts)
49
+ key: event.key,
50
+ userId: event.userId,
51
+ date: new Date(event.ts)
50
52
  });
51
53
  await this.table.updateOne({ key: event.key }, { $set: { status: "done", completedAt: Date.now() } });
52
54
  return result;
@@ -77,12 +79,12 @@ class EventAudit {
77
79
  this.handles[type] = handle;
78
80
  _valleyed.v.compile(handle.pipe);
79
81
  return {
80
- sync: async (payload) => {
81
- const event = await this.#createEvent(type, payload, "sync");
82
+ sync: async (payload, context) => {
83
+ const event = await this.#createEvent(type, payload, "sync", context);
82
84
  return this.#processEvent(event);
83
85
  },
84
- async: async (payload) => {
85
- const event = await this.#createEvent(type, payload, "async");
86
+ async: async (payload, context) => {
87
+ const event = await this.#createEvent(type, payload, "async", context);
86
88
  this.#processEvent(event).catch(() => {
87
89
  });
88
90
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/audit/events.ts","/home/runner/work/equipped/equipped/dist/cjs/audit/events.cjs"],"names":[],"mappings":"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","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: { idempotencyKey: string; idempotencyDate: Date }) => R | Promise<R>\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\terror: string | null\n\tstartedAt: number | null\n\tcompletedAt: number | null\n}\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') {\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\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\tidempotencyKey: event.key.toString(),\n\t\t\t\t\tidempotencyDate: 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>) => {\n\t\t\t\tconst event = await this.#createEvent(type, payload, 'sync')\n\t\t\t\treturn this.#processEvent<R>(event)\n\t\t\t},\n\t\t\tasync: async (payload: PipeInput<P>) => {\n\t\t\t\tconst event = await this.#createEvent(type, payload, 'async')\n\t\t\t\tthis.#processEvent<R>(event).catch(() => {})\n\t\t\t},\n\t\t}\n\t}\n}\n",null]}
1
+ {"version":3,"sources":["../../../src/audit/events.ts","/home/runner/work/equipped/equipped/dist/cjs/audit/events.cjs"],"names":[],"mappings":"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","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});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 v{constructor(t,n){;v.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){const a=this.handles[t];if(!a)throw new (0, _indexmincjs3.EquippedError)("audit handler not found",{type:t,payload:n,mode:e});const d=_valleyed.v.assert(a.pipe,n),i=_indexmincjs5.Instance.createId(),r=new Date;return await this.table.insertOne({key:i,type:t,mode:e,ts:r.getTime(),payload:d,status:"pending",error:null,startedAt:null,completedAt:null},{getTime:()=>r,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,{idempotencyKey:t.key.toString(),idempotencyDate:new Date(t.ts)});return await this.table.updateOne({key:t.key},{$set:{status:"done",completedAt:Date.now()}}),e}catch(e){const a=e instanceof Error?e.message:String(e);throw await this.table.updateOne({key:t.key},{$set:{status:"failed",error:a,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=>{const a=await this.#e(t,e,"sync");return this.#t(a)},async:async e=>{const a=await this.#e(t,e,"async");this.#t(a).catch(()=>{})}}}}exports.EventAudit = v;
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":["model","payload","mode","handler","EquippedError","type","now","key","validPayload","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: { idempotencyKey: string; idempotencyDate: Date }) => R | Promise<R>\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\terror: string | null\n\tstartedAt: number | null\n\tcompletedAt: number | null\n}\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') {\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\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\tidempotencyKey: event.key.toString(),\n\t\t\t\t\tidempotencyDate: 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>) => {\n\t\t\t\tconst event = await this.#createEvent(type, payload, 'sync')\n\t\t\t\treturn this.#processEvent<R>(event)\n\t\t\t},\n\t\t\tasync: async (payload: PipeInput<P>) => {\n\t\t\t\tconst event = await this.#createEvent(type, payload, 'async')\n\t\t\t\tthis.#processEvent<R>(event).catch(() => {})\n\t\t\t},\n\t\t}\n\t}\n}\n"]}
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,2 +1,2 @@
1
- import{v as o}from"valleyed";import{Conditions as c,wrapQueryParams as l}from "../dbs/index.min.mjs";import{EquippedError as s}from "../errors/index.min.mjs";import{Instance as p}from "../instance/index.min.mjs";class v{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){const a=this.handles[t];if(!a)throw new s("audit handler not found",{type:t,payload:n,mode:e});const d=o.assert(a.pipe,n),i=p.createId(),r=new Date;return await this.table.insertOne({key:i,type:t,mode:e,ts:r.getTime(),payload:d,status:"pending",error:null,startedAt:null,completedAt:null},{getTime:()=>r,makeId:()=>i})}async#t(t){return this.db.session(async()=>{const n=this.handles[t.type];if(!n)throw new s("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,{idempotencyKey:t.key.toString(),idempotencyDate:new Date(t.ts)});return await this.table.updateOne({key:t.key},{$set:{status:"done",completedAt:Date.now()}}),e}catch(e){const a=e instanceof Error?e.message:String(e);throw await this.table.updateOne({key:t.key},{$set:{status:"failed",error:a,completedAt:Date.now()}}),e}})}async replay(t){const{results:n}=await this.table.query(l({where:[...t?[{field:"ts",value:t.getTime(),condition:c.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 s("audit event not found",{key:t});await this.#t(n)}register(t,n){if(this.handles[t])throw new s(`${t} already has a registered handler`,{});return this.handles[t]=n,o.compile(n.pipe),{sync:async e=>{const a=await this.#e(t,e,"sync");return this.#t(a)},async:async e=>{const a=await this.#e(t,e,"async");this.#t(a).catch(()=>{})}}}}export{v as EventAudit};
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 { 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: { idempotencyKey: string; idempotencyDate: Date }) => R | Promise<R>\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\terror: string | null\n\tstartedAt: number | null\n\tcompletedAt: number | null\n}\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') {\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\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\tidempotencyKey: event.key.toString(),\n\t\t\t\t\tidempotencyDate: 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>) => {\n\t\t\t\tconst event = await this.#createEvent(type, payload, 'sync')\n\t\t\t\treturn this.#processEvent<R>(event)\n\t\t\t},\n\t\t\tasync: async (payload: PipeInput<P>) => {\n\t\t\t\tconst event = await this.#createEvent(type, payload, 'async')\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","handler","validPayload","key","now","#processEvent","event","result","err","message","from","events","handle"]}
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"]}
@@ -14,7 +14,7 @@ class EventAudit {
14
14
  }
15
15
  table;
16
16
  handles = {};
17
- async #createEvent(type, payload, mode) {
17
+ async #createEvent(type, payload, mode, context) {
18
18
  const handler = this.handles[type];
19
19
  if (!handler) throw new EquippedError("audit handler not found", { type, payload, mode });
20
20
  const validPayload = v.assert(handler.pipe, payload);
@@ -28,6 +28,7 @@ class EventAudit {
28
28
  ts: now.getTime(),
29
29
  payload: validPayload,
30
30
  status: "pending",
31
+ userId: context.userId ?? null,
31
32
  error: null,
32
33
  startedAt: null,
33
34
  completedAt: null
@@ -45,8 +46,9 @@ class EventAudit {
45
46
  { $set: { status: "processing", startedAt: Date.now(), completedAt: null, error: null } }
46
47
  );
47
48
  const result = await handler.handle(event.payload, {
48
- idempotencyKey: event.key.toString(),
49
- idempotencyDate: new Date(event.ts)
49
+ key: event.key,
50
+ userId: event.userId,
51
+ date: new Date(event.ts)
50
52
  });
51
53
  await this.table.updateOne({ key: event.key }, { $set: { status: "done", completedAt: Date.now() } });
52
54
  return result;
@@ -77,12 +79,12 @@ class EventAudit {
77
79
  this.handles[type] = handle;
78
80
  v.compile(handle.pipe);
79
81
  return {
80
- sync: async (payload) => {
81
- const event = await this.#createEvent(type, payload, "sync");
82
+ sync: async (payload, context) => {
83
+ const event = await this.#createEvent(type, payload, "sync", context);
82
84
  return this.#processEvent(event);
83
85
  },
84
- async: async (payload) => {
85
- const event = await this.#createEvent(type, payload, "async");
86
+ async: async (payload, context) => {
87
+ const event = await this.#createEvent(type, payload, "async", context);
86
88
  this.#processEvent(event).catch(() => {
87
89
  });
88
90
  }
@@ -1 +1 @@
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: { idempotencyKey: string; idempotencyDate: Date }) => R | Promise<R>\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\terror: string | null\n\tstartedAt: number | null\n\tcompletedAt: number | null\n}\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') {\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\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\tidempotencyKey: event.key.toString(),\n\t\t\t\t\tidempotencyDate: 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>) => {\n\t\t\t\tconst event = await this.#createEvent(type, payload, 'sync')\n\t\t\t\treturn this.#processEvent<R>(event)\n\t\t\t},\n\t\t\tasync: async (payload: PipeInput<P>) => {\n\t\t\t\tconst event = await this.#createEvent(type, payload, 'async')\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
+ {"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":[]}
@@ -14,7 +14,7 @@ class EventAudit {
14
14
  }
15
15
  table;
16
16
  handles = {};
17
- async #createEvent(type, payload, mode) {
17
+ async #createEvent(type, payload, mode, context) {
18
18
  const handler = this.handles[type];
19
19
  if (!handler) throw new EquippedError("audit handler not found", { type, payload, mode });
20
20
  const validPayload = v.assert(handler.pipe, payload);
@@ -28,6 +28,7 @@ class EventAudit {
28
28
  ts: now.getTime(),
29
29
  payload: validPayload,
30
30
  status: "pending",
31
+ userId: context.userId ?? null,
31
32
  error: null,
32
33
  startedAt: null,
33
34
  completedAt: null
@@ -45,8 +46,9 @@ class EventAudit {
45
46
  { $set: { status: "processing", startedAt: Date.now(), completedAt: null, error: null } }
46
47
  );
47
48
  const result = await handler.handle(event.payload, {
48
- idempotencyKey: event.key.toString(),
49
- idempotencyDate: new Date(event.ts)
49
+ key: event.key,
50
+ userId: event.userId,
51
+ date: new Date(event.ts)
50
52
  });
51
53
  await this.table.updateOne({ key: event.key }, { $set: { status: "done", completedAt: Date.now() } });
52
54
  return result;
@@ -77,12 +79,12 @@ class EventAudit {
77
79
  this.handles[type] = handle;
78
80
  v.compile(handle.pipe);
79
81
  return {
80
- sync: async (payload) => {
81
- const event = await this.#createEvent(type, payload, "sync");
82
+ sync: async (payload, context) => {
83
+ const event = await this.#createEvent(type, payload, "sync", context);
82
84
  return this.#processEvent(event);
83
85
  },
84
- async: async (payload) => {
85
- const event = await this.#createEvent(type, payload, "async");
86
+ async: async (payload, context) => {
87
+ const event = await this.#createEvent(type, payload, "async", context);
86
88
  this.#processEvent(event).catch(() => {
87
89
  });
88
90
  }
@@ -8,10 +8,15 @@ import '../base-CfeyC14V.js';
8
8
 
9
9
  type EventDefinition<P extends Pipe<any, any>, R> = {
10
10
  pipe: P;
11
- handle: (payload: PipeOutput<P>, context: {
12
- idempotencyKey: string;
13
- idempotencyDate: Date;
14
- }) => R | Promise<R>;
11
+ handle: (payload: PipeOutput<P>, context: EventContext) => R | Promise<R>;
12
+ };
13
+ type EventContext = {
14
+ key: string;
15
+ userId: string | null;
16
+ date: Date;
17
+ };
18
+ type Context = {
19
+ userId?: string;
15
20
  };
16
21
  declare class EventAudit {
17
22
  #private;
@@ -22,8 +27,8 @@ declare class EventAudit {
22
27
  replay(from?: Date): Promise<void>;
23
28
  rerun(key: string): Promise<void>;
24
29
  register<P extends Pipe<any, any>, R>(type: string, handle: EventDefinition<P, R>): {
25
- sync: (payload: PipeInput<P>) => Promise<R>;
26
- async: (payload: PipeInput<P>) => Promise<void>;
30
+ sync: (payload: PipeInput<P>, context: Context) => Promise<R>;
31
+ async: (payload: PipeInput<P>, context: Context) => Promise<void>;
27
32
  };
28
33
  }
29
34
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "equipped",
3
- "version": "5.0.33",
3
+ "version": "5.0.34",
4
4
  "private": false,
5
5
  "description": "",
6
6
  "type": "module",