easy-ping 0.2.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -4
- package/dist/{adapter-f0OR2DhY.d.cts → adapter-BfLe2J0t.d.cts} +10 -0
- package/dist/{adapter-f0OR2DhY.d.ts → adapter-BfLe2J0t.d.ts} +10 -0
- package/dist/adapters/drizzle.cjs +9 -4
- package/dist/adapters/drizzle.cjs.map +1 -1
- package/dist/adapters/drizzle.d.cts +35 -1
- package/dist/adapters/drizzle.d.ts +35 -1
- package/dist/adapters/drizzle.js +10 -5
- package/dist/adapters/drizzle.js.map +1 -1
- package/dist/adapters/mongodb.cjs +9 -4
- package/dist/adapters/mongodb.cjs.map +1 -1
- package/dist/adapters/mongodb.d.cts +2 -2
- package/dist/adapters/mongodb.d.ts +2 -2
- package/dist/adapters/mongodb.js +8 -4
- package/dist/adapters/mongodb.js.map +1 -1
- package/dist/adapters/postgres.cjs +136 -3
- package/dist/adapters/postgres.cjs.map +1 -1
- package/dist/adapters/postgres.d.cts +45 -2
- package/dist/adapters/postgres.d.ts +45 -2
- package/dist/adapters/postgres.js +38 -5
- package/dist/adapters/postgres.js.map +1 -1
- package/dist/{chunk-OZSOIX23.js → chunk-3Y2MBUAW.js} +53 -12
- package/dist/chunk-3Y2MBUAW.js.map +1 -0
- package/dist/chunk-CYKAM7LE.js +226 -0
- package/dist/chunk-CYKAM7LE.js.map +1 -0
- package/dist/chunk-DG3ZL5NP.js +315 -0
- package/dist/chunk-DG3ZL5NP.js.map +1 -0
- package/dist/{chunk-NYDVNMKG.js → chunk-PSJHXZPR.js} +4 -3
- package/dist/chunk-PSJHXZPR.js.map +1 -0
- package/dist/{chunk-BV3U542P.js → chunk-W6I3B2CI.js} +2 -2
- package/dist/chunk-W6I3B2CI.js.map +1 -0
- package/dist/chunk-YEMRRMJQ.js +199 -0
- package/dist/chunk-YEMRRMJQ.js.map +1 -0
- package/dist/client.cjs +3 -5
- package/dist/client.cjs.map +1 -1
- package/dist/client.js +3 -5
- package/dist/client.js.map +1 -1
- package/dist/index.cjs +377 -73
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +88 -22
- package/dist/index.d.ts +88 -22
- package/dist/index.js +119 -351
- package/dist/index.js.map +1 -1
- package/dist/node.cjs +27 -6
- package/dist/node.cjs.map +1 -1
- package/dist/node.d.cts +8 -2
- package/dist/node.d.ts +8 -2
- package/dist/node.js +26 -6
- package/dist/node.js.map +1 -1
- package/dist/{plugin-Bqj9xAOS.d.cts → plugin-C9Hoxus2.d.ts} +38 -10
- package/dist/{plugin-bTJKmnlq.d.ts → plugin-CiMsGlQe.d.cts} +38 -10
- package/dist/plugins/digests.d.cts +2 -2
- package/dist/plugins/digests.d.ts +2 -2
- package/dist/plugins/preferences-client.cjs.map +1 -1
- package/dist/plugins/preferences-client.d.cts +2 -2
- package/dist/plugins/preferences-client.d.ts +2 -2
- package/dist/plugins/preferences-client.js +1 -1
- package/dist/plugins/preferences.cjs +100 -15
- package/dist/plugins/preferences.cjs.map +1 -1
- package/dist/plugins/preferences.d.cts +4 -2
- package/dist/plugins/preferences.d.ts +4 -2
- package/dist/plugins/preferences.js +35 -7
- package/dist/plugins/preferences.js.map +1 -1
- package/dist/plugins/push.cjs +222 -61
- package/dist/plugins/push.cjs.map +1 -1
- package/dist/plugins/push.d.cts +81 -3
- package/dist/plugins/push.d.ts +81 -3
- package/dist/plugins/push.js +164 -62
- package/dist/plugins/push.js.map +1 -1
- package/dist/providers/web-push.cjs +37 -11
- package/dist/providers/web-push.cjs.map +1 -1
- package/dist/providers/web-push.d.cts +9 -3
- package/dist/providers/web-push.d.ts +9 -3
- package/dist/providers/web-push.js +37 -12
- package/dist/providers/web-push.js.map +1 -1
- package/dist/react.cjs +3 -5
- package/dist/react.cjs.map +1 -1
- package/dist/react.js +3 -5
- package/dist/react.js.map +1 -1
- package/dist/schema.cjs +2 -1
- package/dist/schema.cjs.map +1 -1
- package/dist/schema.d.cts +7 -2
- package/dist/schema.d.ts +7 -2
- package/dist/schema.js +2 -198
- package/dist/schema.js.map +1 -1
- package/dist/testing.cjs +29 -0
- package/dist/testing.cjs.map +1 -1
- package/dist/testing.d.cts +1 -1
- package/dist/testing.d.ts +1 -1
- package/dist/testing.js +29 -0
- package/dist/testing.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-BV3U542P.js.map +0 -1
- package/dist/chunk-NYDVNMKG.js.map +0 -1
- package/dist/chunk-OZSOIX23.js.map +0 -1
- package/dist/chunk-W3BMEPPQ.js +0 -50
- package/dist/chunk-W3BMEPPQ.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/adapters/mongodb/adapter.ts","../../src/adapters/mongodb/indexes.ts"],"names":["options","spec"],"mappings":";;;;;AA+EA,IAAM,GAAA,GAAM,CAAC,KAAA,KAA2B,MAAA,CAAO,KAAK,CAAA;AACpD,IAAM,cAAc,CAAC,KAAA,KAAmC,SAAS,IAAA,GAAO,IAAA,GAAO,OAAO,KAAK,CAAA;AAC3F,IAAM,GAAA,GAAM,CAAC,KAAA,KAA2B,MAAA,CAAO,KAAK,CAAA;AACpD,IAAM,IAAA,GAAO,CAAC,KAAA,KAA0B,KAAA,YAAiB,IAAA,GAAO,QAAQ,IAAI,IAAA,CAAK,MAAA,CAAO,KAAK,CAAC,CAAA;AAC9F,IAAM,YAAA,GAAe,CAAC,KAAA,KACpB,KAAA,IAAS,IAAA,GAAO,IAAA,GAAO,KAAA,YAAiB,IAAA,GAAO,KAAA,GAAQ,IAAI,IAAA,CAAK,MAAA,CAAO,KAAK,CAAC,CAAA;AAE/E,IAAM,YAAA,GAAe,CAAC,SAAA,EAAiB,EAAA,KACrC,eAAA,CAAgB,CAAA,EAAG,SAAA,CAAU,WAAA,EAAa,CAAA,CAAA,EAAI,EAAE,CAAA,CAAE,CAAA;AAEpD,SAAS,aAAa,MAAA,EAAwD;AAC5E,EAAA,MAAM,OAAA,GAAU,gBAAgB,MAAM,CAAA;AACtC,EAAA,IAAI,CAAC,SAAS,OAAO,IAAA;AAErB,EAAA,MAAM,CAAC,GAAA,EAAK,EAAE,CAAA,GAAI,OAAA,CAAQ,MAAM,GAAG,CAAA;AACnC,EAAA,IAAI,CAAC,GAAA,IAAO,CAAC,EAAA,EAAI,OAAO,IAAA;AAExB,EAAA,MAAM,SAAA,GAAY,IAAI,IAAA,CAAK,GAAG,CAAA;AAC9B,EAAA,OAAO,MAAA,CAAO,MAAM,SAAA,CAAU,OAAA,EAAS,CAAA,GAAI,IAAA,GAAO,EAAE,SAAA,EAAW,EAAA,EAAG;AACpE;AAGA,SAAS,eAAe,GAAA,EAAmC;AACzD,EAAA,OAAO;AAAA,IACL,EAAA,EAAI,GAAA,CAAI,GAAA,CAAI,GAAG,CAAA;AAAA,IACf,MAAA,EAAQ,GAAA,CAAI,GAAA,CAAI,MAAM,CAAA;AAAA,IACtB,IAAA,EAAM,GAAA,CAAI,GAAA,CAAI,IAAI,CAAA;AAAA,IAClB,SAAS,GAAA,CAAI,OAAA;AAAA,IACb,OAAA,EAAS,WAAA,CAAY,GAAA,CAAI,OAAO,CAAA;AAAA,IAChC,QAAA,EAAU,WAAA,CAAY,GAAA,CAAI,QAAQ,CAAA;AAAA,IAClC,SAAA,EAAW,WAAA,CAAY,GAAA,CAAI,SAAS,CAAA;AAAA,IACpC,MAAA,EAAQ,YAAA,CAAa,GAAA,CAAI,MAAM,CAAA;AAAA,IAC/B,MAAA,EAAQ,YAAA,CAAa,GAAA,CAAI,MAAM,CAAA;AAAA,IAC/B,UAAA,EAAY,YAAA,CAAa,GAAA,CAAI,UAAU,CAAA;AAAA,IACvC,SAAA,EAAW,IAAA,CAAK,GAAA,CAAI,SAAS;AAAA,GAC/B;AACF;AAEA,SAAS,WAAW,GAAA,EAA+B;AACjD,EAAA,OAAO;AAAA,IACL,EAAA,EAAI,GAAA,CAAI,GAAA,CAAI,GAAG,CAAA;AAAA,IACf,cAAA,EAAgB,GAAA,CAAI,GAAA,CAAI,cAAc,CAAA;AAAA,IACtC,OAAA,EAAS,GAAA,CAAI,GAAA,CAAI,OAAO,CAAA;AAAA,IACxB,MAAA,EAAQ,GAAA,CAAI,GAAA,CAAI,MAAM,CAAA;AAAA,IACtB,QAAA,EAAU,GAAA,CAAI,GAAA,CAAI,QAAQ,CAAA;AAAA,IAC1B,WAAA,EAAa,GAAA,CAAI,GAAA,CAAI,WAAW,CAAA;AAAA,IAChC,SAAA,EAAW,IAAA,CAAK,GAAA,CAAI,SAAS,CAAA;AAAA,IAC7B,SAAA,EAAW,YAAA,CAAa,GAAA,CAAI,SAAS,CAAA;AAAA,IACrC,SAAA,EAAW,WAAA,CAAY,GAAA,CAAI,SAAS,CAAA;AAAA,IACpC,SAAA,EAAW,WAAA,CAAY,GAAA,CAAI,SAAS,CAAA;AAAA,IACpC,SAAA,EAAW,IAAA,CAAK,GAAA,CAAI,SAAS;AAAA,GAC/B;AACF;AAGA,IAAM,YAAA,GAAe,CAAC,KAAA,KAAmB,KAAA,KAAU,OAAO,KAAA,GAAQ,KAAA;AAGlE,SAAS,SAAS,KAAA,EAA8B;AAC9C,EAAA,MAAM,SAAmB,EAAC;AAE1B,EAAA,KAAA,MAAW,CAAC,KAAA,EAAO,SAAS,KAAK,MAAA,CAAO,OAAA,CAAQ,KAAK,CAAA,EAAG;AACtD,IAAA,MAAM,GAAA,GAAM,aAAa,KAAK,CAAA;AAE9B,IAAA,IAAI,cAAc,IAAA,EAAM;AACtB,MAAA,MAAA,CAAO,GAAG,CAAA,GAAI,IAAA;AACd,MAAA;AAAA,IACF;AAEA,IAAA,IAAI,CAAC,UAAA,CAAW,SAAS,CAAA,EAAG;AAC1B,MAAA,MAAA,CAAO,GAAG,CAAA,GAAI,SAAA;AACd,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,QAAA,GAAW,SAAA;AACjB,IAAA,IAAI,IAAA,IAAQ,UAAU,MAAA,CAAO,GAAG,IAAI,EAAE,GAAA,EAAK,SAAS,EAAA,EAAG;AAAA,SAAA,IAC9C,IAAA,IAAQ,UAAU,MAAA,CAAO,GAAG,IAAI,EAAE,GAAA,EAAK,SAAS,EAAA,EAAG;AAAA,SAAA,IACnD,KAAA,IAAS,UAAU,MAAA,CAAO,GAAG,IAAI,EAAE,IAAA,EAAM,SAAS,GAAA,EAAI;AAAA,SAAA,IACtD,IAAA,IAAQ,UAAU,MAAA,CAAO,GAAG,IAAI,EAAE,GAAA,EAAK,SAAS,EAAA,EAAG;AAAA,SAAA,IACnD,KAAA,IAAS,UAAU,MAAA,CAAO,GAAG,IAAI,EAAE,IAAA,EAAM,SAAS,GAAA,EAAI;AAAA,SAAA,IACtD,SAAS,QAAA,EAAU;AAE1B,MAAA,MAAA,CAAO,GAAG,CAAA,GAAI,EAAE,GAAA,EAAK,SAAS,GAAA,EAAI;AAAA,IACpC;AAAA,EACF;AAEA,EAAA,OAAO,MAAA;AACT;AAGA,IAAM,cAAA,GAAiB,CAAC,KAAA,KAA4B;AAClD,EAAA,MAAM,OAAQ,KAAA,EAAgE,IAAA;AAC9E,EAAA,IAAI,IAAA,KAAS,MAAO,OAAO,IAAA;AAC3B,EAAA,MAAM,cAAe,KAAA,EAAiD,WAAA;AACtE,EAAA,OAAO,KAAA,CAAM,OAAA,CAAQ,WAAW,CAAA,IAAK,WAAA,CAAY,KAAK,CAAC,KAAA,KAAU,KAAA,EAAO,IAAA,KAAS,IAAK,CAAA;AACxF,CAAA;AAEO,SAAS,YAAA,CAAa,EAAA,EAAa,OAAA,GAA+B,EAAC,EAAoB;AAC5F,EAAA,MAAM,QAAA,GAAW,EAAA;AACjB,EAAA,MAAM,MAAA,GAAS,QAAQ,MAAA,IAAU,EAAA;AAEjC,EAAA,MAAM,SAAS,OAAA,CAAQ,MAAA;AAEvB,EAAA,MAAM,gBAAgB,MAAM,QAAA,CAAS,UAAA,CAAW,CAAA,EAAG,MAAM,CAAA,YAAA,CAAc,CAAA;AACvE,EAAA,MAAM,aAAa,MAAM,QAAA,CAAS,UAAA,CAAW,CAAA,EAAG,MAAM,CAAA,qBAAA,CAAuB,CAAA;AAW7E,EAAA,eAAe,WAAc,EAAA,EAAwD;AACnF,IAAA,IAAI,CAAC,MAAA,EAAQ,OAAO,EAAA,EAAG;AAEvB,IAAA,MAAM,OAAA,GAAU,OAAO,YAAA,EAAa;AACpC,IAAA,IAAI;AACF,MAAA,OAAO,MAAM,OAAA,CAAQ,eAAA,CAAgB,MAAM,EAAA,CAAG,OAAO,CAAC,CAAA;AAAA,IACxD,CAAA,SAAE;AACA,MAAA,MAAM,QAAQ,UAAA,EAAW;AAAA,IAC3B;AAAA,EACF;AAEA,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,SAAA;AAAA;AAAA,IAEN,MAAA,EAAQ,UAAA;AAAA,IACR,cAAA,EAAgB,KAAA;AAAA,IAEhB,MAAM,oBAAoB,KAAA,EAAsC;AAC9D,MAAA,IAAI,KAAA,CAAM,MAAA,KAAW,CAAA,EAAG,OAAO,EAAE,SAAS,EAAC,EAAG,OAAA,EAAS,EAAC,EAAE;AAE1D,MAAA,MAAM,UAAoB,EAAC;AAC3B,MAAA,MAAM,UAAoB,EAAC;AAE3B,MAAA,KAAA,MAAW,OAAO,KAAA,EAAO;AACvB,QAAA,MAAM,GAAA,uBAAU,IAAA,EAAK;AAErB,QAAA,IAAI;AACF,UAAA,MAAM,UAAA,CAAW,OAAO,OAAA,KAAY;AAClC,YAAA,MAAMA,QAAAA,GAAU,OAAA,GAAU,EAAE,OAAA,EAAQ,GAAI,KAAA,CAAA;AAIxC,YAAA,MAAM,eAAc,CAAE,SAAA;AAAA,cACpB;AAAA,gBACE,KAAK,GAAA,CAAI,EAAA;AAAA,gBACT,QAAQ,GAAA,CAAI,MAAA;AAAA,gBACZ,MAAM,GAAA,CAAI,IAAA;AAAA,gBACV,OAAA,EAAS,IAAI,OAAA,IAAW,IAAA;AAAA,gBACxB,OAAA,EAAS,IAAI,OAAA,IAAW,IAAA;AAAA,gBACxB,QAAA,EAAU,IAAI,QAAA,IAAY,IAAA;AAAA,gBAC1B,SAAA,EAAW,IAAI,SAAA,IAAa,IAAA;AAAA,gBAC5B,MAAA,EAAQ,IAAA;AAAA,gBACR,MAAA,EAAQ,IAAA;AAAA,gBACR,UAAA,EAAY,IAAA;AAAA,gBACZ,SAAA,EAAW;AAAA,eACb;AAAA,cACAA;AAAA,aACF;AAEA,YAAA,IAAI,GAAA,CAAI,UAAA,CAAW,MAAA,GAAS,CAAA,EAAG;AAC7B,cAAA,MAAM,YAAW,CAAE,UAAA;AAAA,gBACjB,GAAA,CAAI,UAAA,CAAW,GAAA,CAAI,CAAC,QAAA,MAAc;AAAA,kBAChC,KAAK,QAAA,CAAS,EAAA;AAAA,kBACd,gBAAgB,GAAA,CAAI,EAAA;AAAA,kBACpB,SAAS,QAAA,CAAS,OAAA;AAAA,kBAClB,MAAA,EAAQ,SAAA;AAAA,kBACR,QAAA,EAAU,CAAA;AAAA,kBACV,aAAa,QAAA,CAAS,WAAA;AAAA,kBACtB,WAAW,QAAA,CAAS,SAAA;AAAA,kBACpB,SAAA,EAAW,IAAA;AAAA,kBACX,SAAA,EAAW,IAAA;AAAA,kBACX,SAAA,EAAW,IAAA;AAAA,kBACX,SAAA,EAAW;AAAA,iBACb,CAAE,CAAA;AAAA,gBACFA;AAAA,eACF;AAAA,YACF;AAAA,UACF,CAAC,CAAA;AAED,UAAA,OAAA,CAAQ,IAAA,CAAK,IAAI,EAAE,CAAA;AAAA,QACrB,SAAS,KAAA,EAAO;AACd,UAAA,IAAI,CAAC,cAAA,CAAe,KAAK,CAAA,EAAG,MAAM,KAAA;AAClC,UAAA,OAAA,CAAQ,IAAA,CAAK,IAAI,EAAE,CAAA;AAAA,QACrB;AAAA,MACF;AAEA,MAAA,OAAO,EAAE,SAAS,OAAA,EAAQ;AAAA,IAC5B,CAAA;AAAA,IAEA,MAAM,uBAAuB,IAAA,EAAsD;AACjF,MAAA,MAAM,GAAA,GAAM,IAAA,CAAK,GAAA,oBAAO,IAAI,IAAA,EAAK;AACjC,MAAA,MAAM,cAAc,IAAI,IAAA,CAAK,IAAI,OAAA,EAAQ,GAAI,KAAK,OAAO,CAAA;AAEzD,MAAA,MAAM,QAAA,GAAqB;AAAA,QACzB,IAAA,EAAM;AAAA,UACJ;AAAA,YACE,GAAA,EAAK,CAAC,EAAE,MAAA,EAAQ,WAAU,EAAG,EAAE,MAAA,EAAQ,SAAA,EAAW,SAAA,EAAW,EAAE,GAAA,EAAK,WAAA,IAAe;AAAA,WACrF;AAAA,UACA,EAAE,SAAA,EAAW,EAAE,IAAA,EAAM,KAAI,EAAE;AAAA,UAC3B,EAAE,OAAO,EAAE,GAAA,EAAK,CAAC,WAAA,EAAa,cAAc,GAAE;AAAE;AAClD,OACF;AAEA,MAAA,IAAI,IAAA,CAAK,QAAA,IAAY,IAAA,CAAK,QAAA,CAAS,SAAS,CAAA,EAAG;AAC7C,QAAC,QAAA,CAAS,IAAA,CAAoB,IAAA,CAAK,EAAE,OAAA,EAAS,EAAE,GAAA,EAAK,CAAC,GAAG,IAAA,CAAK,QAAQ,CAAA,IAAK,CAAA;AAAA,MAC7E;AACA,MAAA,IAAI,IAAA,CAAK,GAAA,IAAO,IAAA,CAAK,GAAA,CAAI,SAAS,CAAA,EAAG;AACnC,QAAC,QAAA,CAAS,IAAA,CAAoB,IAAA,CAAK,EAAE,GAAA,EAAK,EAAE,GAAA,EAAK,CAAC,GAAG,IAAA,CAAK,GAAG,CAAA,IAAK,CAAA;AAAA,MACpE;AAKA,MAAA,MAAM,UAAsB,EAAC;AAC7B,MAAA,KAAA,IAAS,QAAQ,CAAA,EAAG,KAAA,GAAQ,IAAA,CAAK,KAAA,EAAO,SAAS,CAAA,EAAG;AAClD,QAAA,MAAM,GAAA,GAAM,MAAM,UAAA,EAAW,CAAE,gBAAA;AAAA,UAC7B,QAAA;AAAA,UACA,EAAE,IAAA,EAAM,EAAE,MAAA,EAAQ,SAAA,EAAW,WAAW,GAAA,EAAK,SAAA,EAAW,IAAA,CAAK,UAAA,EAAW,EAAE;AAAA,UAC1E,EAAE,MAAM,EAAE,SAAA,EAAW,GAAG,GAAA,EAAK,CAAA,EAAE,EAAG,cAAA,EAAgB,OAAA;AAAQ,SAC5D;AACA,QAAA,IAAI,CAAC,GAAA,EAAK;AACV,QAAA,OAAA,CAAQ,KAAK,GAAG,CAAA;AAAA,MAClB;AAEA,MAAA,IAAI,OAAA,CAAQ,MAAA,KAAW,CAAA,EAAG,OAAO,EAAC;AAGlC,MAAA,MAAM,UAAU,MAAM,aAAA,GACnB,IAAA,CAAK,EAAE,KAAK,EAAE,GAAA,EAAK,QAAQ,GAAA,CAAI,CAAC,QAAQ,GAAA,CAAI,cAAc,GAAE,EAAG,EAC/D,OAAA,EAAQ;AACX,MAAA,MAAM,IAAA,GAAO,IAAI,GAAA,CAAI,OAAA,CAAQ,IAAI,CAAC,GAAA,KAAQ,CAAC,GAAA,CAAI,GAAA,CAAI,GAAG,CAAA,EAAG,GAAG,CAAC,CAAC,CAAA;AAE9D,MAAA,OAAO,OAAA,CAAQ,OAAA,CAAQ,CAAC,GAAA,KAAQ;AAC9B,QAAA,MAAM,SAAS,IAAA,CAAK,GAAA,CAAI,GAAA,CAAI,GAAA,CAAI,cAAc,CAAC,CAAA;AAC/C,QAAA,IAAI,CAAC,MAAA,EAAQ,OAAO,EAAC;AAErB,QAAA,OAAO;AAAA,UACL;AAAA,YACE,EAAA,EAAI,GAAA,CAAI,GAAA,CAAI,GAAG,CAAA;AAAA,YACf,cAAA,EAAgB,GAAA,CAAI,GAAA,CAAI,cAAc,CAAA;AAAA,YACtC,OAAA,EAAS,GAAA,CAAI,GAAA,CAAI,OAAO,CAAA;AAAA,YACxB,QAAA,EAAU,GAAA,CAAI,GAAA,CAAI,QAAQ,CAAA;AAAA,YAC1B,WAAA,EAAa,GAAA,CAAI,GAAA,CAAI,WAAW,CAAA;AAAA,YAChC,YAAA,EAAc;AAAA,cACZ,MAAA,EAAQ,GAAA,CAAI,MAAA,CAAO,MAAM,CAAA;AAAA,cACzB,IAAA,EAAM,GAAA,CAAI,MAAA,CAAO,IAAI,CAAA;AAAA,cACrB,SAAS,MAAA,CAAO,OAAA;AAAA,cAChB,OAAA,EAAS,WAAA,CAAY,MAAA,CAAO,OAAO;AAAA;AACrC;AACF,SACF;AAAA,MACF,CAAC,CAAA;AAAA,IACH,CAAA;AAAA,IAEA,MAAM,kBAAkB,QAAA,EAAsC;AAC5D,MAAA,IAAI,QAAA,CAAS,WAAW,CAAA,EAAG;AAC3B,MAAA,MAAM,GAAA,uBAAU,IAAA,EAAK;AAErB,MAAA,KAAA,MAAW,EAAE,EAAA,EAAI,OAAA,EAAS,aAAA,MAAmB,QAAA,EAAU;AACrD,QAAA,MAAM,MAAA,GAAS,QAAQ,MAAA,KAAW,QAAA;AAClC,QAAA,MAAM,SAAA,GAAY,UAAU,OAAA,CAAQ,SAAA;AAIpC,QAAA,MAAM,YAAW,CAAE,SAAA,CAAU,EAAE,GAAA,EAAK,IAAG,EAAG;AAAA,UACxC;AAAA,YACE,IAAA,EAAM;AAAA,cACJ,QAAA,EAAU,SAAS,EAAE,IAAA,EAAM,CAAC,WAAA,EAAa,CAAC,GAAE,GAAI,WAAA;AAAA,cAChD,QAAQ,MAAA,GACJ;AAAA,gBACE,KAAA,EAAO;AAAA,kBACL,EAAE,IAAA,EAAM,CAAC,SAAA,EAAW,EAAE,KAAK,CAAC,EAAE,IAAA,EAAM,CAAC,aAAa,CAAC,CAAA,IAAK,cAAc,CAAA,EAAG,CAAA,EAAE;AAAA,kBAC3E,SAAA;AAAA,kBACA;AAAA;AACF,eACF,GACA,MAAA;AAAA;AAAA;AAAA,cAGJ,SAAA,EAAW,MAAA,GAAS,EAAE,QAAA,EAAU,OAAA,CAAQ,MAAM,KAAA,CAAM,CAAA,EAAG,GAAI,CAAA,EAAE,GAAI,IAAA;AAAA,cACjE,WAAW,aAAA,IAAiB,YAAA;AAAA;AAAA;AAAA;AAAA,cAI5B,SAAA,EAAW,IAAA;AAAA,cACX,SAAA,EAAW,IAAA;AAAA,cACX,SAAA,EAAW;AAAA;AACb;AACF,SACD,CAAA;AAAA,MACH;AAAA,IACF,CAAA;AAAA,IAEA,MAAM,kBAAkB,KAAA,EAAqC;AAC3D,MAAA,MAAM,SAAS,KAAA,CAAM,MAAA,GAAS,YAAA,CAAa,KAAA,CAAM,MAAM,CAAA,GAAI,IAAA;AAE3D,MAAA,MAAM,SAAmB,EAAE,MAAA,EAAQ,KAAA,CAAM,MAAA,EAAQ,YAAY,IAAA,EAAK;AAClE,MAAA,IAAI,KAAA,CAAM,UAAA,EAAY,MAAA,CAAO,MAAA,GAAS,IAAA;AAEtC,MAAA,IAAI,MAAA,EAAQ;AAEV,QAAA,MAAA,CAAO,GAAA,GAAM;AAAA,UACX,EAAE,SAAA,EAAW,EAAE,GAAA,EAAK,MAAA,CAAO,WAAU,EAAE;AAAA,UACvC,EAAE,WAAW,MAAA,CAAO,SAAA,EAAW,KAAK,EAAE,GAAA,EAAK,MAAA,CAAO,EAAA,EAAG;AAAE,SACzD;AAAA,MACF;AAEA,MAAA,MAAM,IAAA,GAAO,MAAM,aAAA,EAAc,CAC9B,KAAK,MAAA,EAAQ,EAAE,MAAM,EAAE,SAAA,EAAW,IAAI,GAAA,EAAK,EAAA,IAAM,KAAA,EAAO,KAAA,CAAM,QAAQ,CAAA,EAAG,EACzE,OAAA,EAAQ;AAEX,MAAA,MAAM,IAAA,GAAO,KAAK,KAAA,CAAM,CAAA,EAAG,MAAM,KAAK,CAAA,CAAE,IAAI,cAAc,CAAA;AAC1D,MAAA,MAAM,IAAA,GAAO,IAAA,CAAK,EAAA,CAAG,EAAE,CAAA;AAEvB,MAAA,OAAO;AAAA,QACL,aAAA,EAAe,IAAA;AAAA,QACf,UAAA,EACE,IAAA,CAAK,MAAA,GAAS,KAAA,CAAM,KAAA,IAAS,IAAA,GAAO,YAAA,CAAa,IAAA,CAAK,SAAA,EAAW,IAAA,CAAK,EAAE,CAAA,GAAI;AAAA,OAChF;AAAA,IACF,CAAA;AAAA,IAEA,MAAM,YAAY,MAAA,EAAgB;AAChC,MAAA,OAAO,aAAA,GAAgB,cAAA,CAAe,EAAE,QAAQ,MAAA,EAAQ,IAAA,EAAM,UAAA,EAAY,IAAA,EAAM,CAAA;AAAA,IAClF,CAAA;AAAA,IAEA,MAAM,QAAA,CAAS,MAAA,EAAgB,MAAA,EAAc;AAC3C,MAAA,MAAM,eAAc,CAAE,UAAA;AAAA,QACpB,EAAE,QAAQ,MAAA,EAAQ,IAAA,EAAM,WAAW,EAAE,IAAA,EAAM,QAAO,EAAE;AAAA,QACpD,EAAE,IAAA,EAAM,EAAE,wBAAQ,IAAI,IAAA,IAAO;AAAE,OACjC;AAAA,IACF,CAAA;AAAA,IAEA,MAAM,QAAA,CAAS,MAAA,EAAgB,eAAA,EAAoC;AACjE,MAAA,IAAI,eAAA,CAAgB,MAAA,KAAW,CAAA,EAAG,OAAO,CAAA;AAIzC,MAAA,MAAM,MAAA,GAAS,EAAE,MAAA,EAAQ,GAAA,EAAK,EAAE,KAAK,CAAC,GAAG,eAAe,CAAA,EAAE,EAAE;AAC5D,MAAA,MAAM,eAAc,CAAE,UAAA;AAAA,QACpB,EAAE,GAAG,MAAA,EAAQ,MAAA,EAAQ,IAAA,EAAK;AAAA,QAC1B;AAAA,UACE,IAAA,EAAM,EAAE,MAAA,kBAAQ,IAAI,MAAK;AAAE;AAC7B,OACF;AAEA,MAAA,OAAO,aAAA,EAAc,CAAE,cAAA,CAAe,MAAM,CAAA;AAAA,IAC9C,CAAA;AAAA,IAEA,MAAM,YAAY,MAAA,EAAgB;AAChC,MAAA,MAAM,MAAA,GAAS,MAAM,aAAA,EAAc,CAAE,UAAA;AAAA,QACnC,EAAE,MAAA,EAAQ,MAAA,EAAQ,IAAA,EAAK;AAAA,QACvB,EAAE,IAAA,EAAM,EAAE,wBAAQ,IAAI,IAAA,IAAO;AAAE,OACjC;AACA,MAAA,OAAO,MAAA,CAAO,aAAA;AAAA,IAChB,CAAA;AAAA,IAEA,MAAM,oBAAoB,IAAA,EAAsC;AAC9D,MAAA,MAAM,IAAA,GAAO,MAAM,UAAA,EAAW,CAC3B,IAAA;AAAA,QACC,EAAE,QAAQ,QAAA,EAAU,SAAA,EAAW,EAAE,IAAA,EAAM,IAAA,CAAK,OAAM,EAAE;AAAA,QACpD,EAAE,MAAM,EAAE,SAAA,EAAW,IAAG,EAAG,KAAA,EAAO,KAAK,KAAA;AAAM,QAE9C,OAAA,EAAQ;AAEX,MAAA,OAAO,IAAA,CAAK,IAAI,UAAU,CAAA;AAAA,IAC5B,CAAA;AAAA,IAEA,MAAM,UAAA,CAAW,KAAA,EAAe,KAAA,EAAoBA,QAAAA,EAAuB;AACzE,MAAA,MAAM,OAAiB,EAAC;AACxB,MAAA,IAAIA,QAAAA,CAAQ,KAAA,EAAO,IAAA,CAAK,KAAA,GAAQA,QAAAA,CAAQ,KAAA;AACxC,MAAA,IAAIA,SAAQ,OAAA,EAAS;AACnB,QAAA,MAAM,SAAA,GAAYA,QAAAA,CAAQ,OAAA,CAAQ,SAAA,KAAc,SAAS,EAAA,GAAK,CAAA;AAC9D,QAAA,IAAA,CAAK,IAAA,GAAO,EAAE,CAAC,YAAA,CAAaA,SAAQ,OAAA,CAAQ,KAAK,CAAC,GAAG,SAAA,EAAU;AAAA,MACjE;AAEA,MAAA,MAAM,IAAA,GAAO,MAAM,QAAA,CAAS,UAAA,CAAW,KAAK,CAAA,CAAE,IAAA,CAAK,QAAA,CAAS,KAAK,CAAA,EAAG,IAAI,CAAA,CAAE,OAAA,EAAQ;AAGlF,MAAA,OAAO,KAAK,GAAA,CAAI,CAAC,EAAE,GAAA,EAAK,GAAG,IAAA,EAAK,KAAO,GAAA,KAAQ,MAAA,GAAY,OAAO,EAAE,EAAA,EAAI,GAAA,EAAK,GAAG,MAAO,CAAA;AAAA,IACzF,CAAA;AAAA,IAEA,MAAM,UAAA,CACJ,KAAA,EACA,IAAA,EACA,UAAA,EACA;AACA,MAAA,IAAI,IAAA,CAAK,MAAA,KAAW,CAAA,EAAG,OAAO,CAAA;AAE9B,MAAA,MAAM,YAAY,IAAA,CAAK,GAAA;AAAA,QAAI,CAAC,EAAE,EAAA,EAAI,GAAG,IAAA,OACnC,EAAA,KAAO,MAAA,GAAY,EAAE,GAAG,MAAK,GAAI,EAAE,GAAA,EAAK,EAAA,EAAI,GAAG,IAAA;AAAK,OACtD;AAEA,MAAA,IAAI,CAAC,UAAA,IAAc,UAAA,CAAW,MAAA,KAAW,CAAA,EAAG;AAC1C,QAAA,MAAM,QAAA,CAAS,UAAA,CAAW,KAAK,CAAA,CAAE,WAAW,SAAuB,CAAA;AACnE,QAAA,OAAO,SAAA,CAAU,MAAA;AAAA,MACnB;AAGA,MAAA,IAAI,OAAA,GAAU,CAAA;AACd,MAAA,KAAA,MAAW,YAAY,SAAA,EAAyB;AAC9C,QAAA,MAAM,MAAgB,EAAC;AACvB,QAAA,KAAA,MAAW,KAAA,IAAS,UAAA,EAAY,GAAA,CAAI,YAAA,CAAa,KAAK,CAAC,CAAA,GAAI,QAAA,CAAS,YAAA,CAAa,KAAK,CAAC,CAAA;AAIvF,QAAA,MAAM,EAAE,GAAA,EAAK,GAAG,SAAA,EAAU,GAAI,QAAA;AAC9B,QAAA,MAAM,MAAA,GAAmB,EAAE,IAAA,EAAM,SAAA,EAAU;AAC3C,QAAA,IAAI,GAAA,KAAQ,MAAA,EAAW,MAAA,CAAO,YAAA,GAAe,EAAE,GAAA,EAAI;AAEnD,QAAA,MAAM,MAAA,GAAS,MAAM,QAAA,CAAS,UAAA,CAAW,KAAK,CAAA,CAAE,SAAA,CAAU,GAAA,EAAK,MAAA,EAAQ,EAAE,MAAA,EAAQ,IAAA,EAAM,CAAA;AACvF,QAAA,OAAA,IAAW,MAAA,CAAO,YAAA,IAAgB,MAAA,CAAO,aAAA,IAAiB,CAAA,CAAA;AAAA,MAC5D;AACA,MAAA,OAAO,OAAA;AAAA,IACT,CAAA;AAAA,IAEA,MAAM,UAAA,CAAW,KAAA,EAAe,KAAA,EAAoB,GAAA,EAA8B;AAChF,MAAA,MAAM,cAAwB,EAAC;AAC/B,MAAA,KAAA,MAAW,CAAC,KAAA,EAAO,KAAK,CAAA,IAAK,MAAA,CAAO,OAAA,CAAQ,GAAG,CAAA,EAAG,WAAA,CAAY,YAAA,CAAa,KAAK,CAAC,CAAA,GAAI,KAAA;AACrF,MAAA,IAAI,OAAO,IAAA,CAAK,WAAW,CAAA,CAAE,MAAA,KAAW,GAAG,OAAO,CAAA;AAElD,MAAA,MAAM,MAAA,GAAS,MAAM,QAAA,CAClB,UAAA,CAAW,KAAK,CAAA,CAChB,UAAA,CAAW,QAAA,CAAS,KAAK,CAAA,EAAG,EAAE,IAAA,EAAM,aAAa,CAAA;AACpD,MAAA,OAAO,MAAA,CAAO,YAAA;AAAA,IAChB,CAAA;AAAA,IAEA,MAAM,UAAA,CAAW,KAAA,EAAe,KAAA,EAAoB;AAClD,MAAA,MAAM,MAAA,GAAS,MAAM,QAAA,CAAS,UAAA,CAAW,KAAK,CAAA,CAAE,UAAA,CAAW,QAAA,CAAS,KAAK,CAAC,CAAA;AAC1E,MAAA,OAAO,MAAA,CAAO,YAAA;AAAA,IAChB;AAAA,GACF;AACF;;;AClfA,IAAM,SAAA,GAAsD;AAAA,EAC1D,MAAA,EAAQ,QAAA;AAAA,EACR,MAAA,EAAQ,QAAA;AAAA,EACR,OAAA,EAAS,MAAA;AAAA,EACT,IAAA,EAAM,MAAA;AAAA,EACN,IAAA,EAAM;AACR,CAAA;AAWA,eAAsB,mBAAA,CACpB,EAAA,EACA,MAAA,EACA,MAAA,GAAS,EAAA,EACM;AACf,EAAA,MAAM,QAAA,GAAW,EAAA;AAEjB,EAAA,KAAA,MAAW,KAAA,IAAS,MAAA,CAAO,MAAA,CAAO,MAAM,CAAA,EAAG;AACzC,IAAA,MAAM,UAAA,GAAa,QAAA,CAAS,UAAA,CAAW,MAAA,GAAS,MAAM,SAAS,CAAA;AAG/D,IAAA,IAAI,KAAA,CAAM,UAAA,IAAc,KAAA,CAAM,UAAA,CAAW,MAAA,GAAS,KAAK,KAAA,CAAM,UAAA,CAAW,CAAC,CAAA,KAAM,IAAA,EAAM;AACnF,MAAA,MAAM,OAAkB,EAAC;AACzB,MAAA,KAAA,MAAW,KAAA,IAAS,KAAA,CAAM,UAAA,EAAY,IAAA,CAAK,KAAK,CAAA,GAAI,CAAA;AACpD,MAAA,MAAM,UAAA,CAAW,YAAY,IAAA,EAAM;AAAA,QACjC,IAAA,EAAM,CAAA,EAAG,KAAA,CAAM,SAAS,CAAA,GAAA,CAAA;AAAA,QACxB,MAAA,EAAQ;AAAA,OACT,CAAA;AAAA,IACH;AAEA,IAAA,KAAA,MAAW,WAAA,IAAe,KAAA,CAAM,OAAA,IAAW,EAAC,EAAG;AAC7C,MAAA,MAAM,OAAkB,EAAC;AACzB,MAAA,KAAA,MAAW,KAAA,IAAS,WAAA,CAAY,EAAA,EAAI,IAAA,CAAK,KAAK,CAAA,GAAI,CAAA;AAElD,MAAA,MAAM,OAAA,GAAwB;AAAA,QAC5B,IAAA,EAAM,MAAA,IAAU,WAAA,CAAY,IAAA,IAAQ,CAAA,EAAG,KAAA,CAAM,SAAS,CAAA,CAAA,EAAI,WAAA,CAAY,EAAA,CAAG,IAAA,CAAK,GAAG,CAAC,CAAA,IAAA,CAAA;AAAA,OACpF;AAEA,MAAA,IAAI,YAAY,MAAA,EAAQ;AACtB,QAAA,OAAA,CAAQ,MAAA,GAAS,IAAA;AAEjB,QAAA,MAAM,UAAmC,EAAC;AAC1C,QAAA,KAAA,MAAW,KAAA,IAAS,YAAY,EAAA,EAAI;AAClC,UAAA,MAAMC,KAAAA,GAAO,KAAA,CAAM,MAAA,CAAO,KAAK,CAAA;AAC/B,UAAA,IAAIA,KAAAA,IAAQ,CAACA,KAAAA,CAAK,QAAA,EAAU,OAAA,CAAQ,KAAK,CAAA,GAAI,EAAE,KAAA,EAAO,SAAA,CAAUA,KAAAA,CAAK,IAAI,CAAA,EAAE;AAAA,QAC7E;AACA,QAAA,IAAI,OAAO,IAAA,CAAK,OAAO,EAAE,MAAA,GAAS,CAAA,UAAW,uBAAA,GAA0B,OAAA;AAAA,MACzE;AAEA,MAAA,MAAM,UAAA,CAAW,WAAA,CAAY,IAAA,EAAM,OAAO,CAAA;AAAA,IAC5C;AAAA,EACF;AACF;AAGO,IAAM,kBAAA,GAAqB,CAAC,EAAA,EAAa,OAAA,GAA+B,EAAC,KAC9E,mBAAA,CAAoB,EAAA,EAAI,UAAA,EAAY,OAAA,CAAQ,MAAA,IAAU,EAAE","file":"mongodb.js","sourcesContent":["import type {\n ClaimArgs,\n ClaimedDelivery,\n DatabaseAdapter,\n DeliveryRelease,\n FeedPage,\n FeedQuery,\n InsertNotification,\n} from \"../../core/adapter\";\nimport { decodeBase64Url, encodeBase64Url } from \"../../core/base64url\";\nimport { isOperator, type QueryOptions, type WhereClause } from \"../../core/store\";\nimport type { Channel, DeliveryRecord, DeliveryStatus, NotificationRecord } from \"../../core/types\";\n\ntype Document = Record<string, unknown>;\n\n/**\n * Minimal structural view of the pieces of the Mongo driver this uses.\n *\n * Typed structurally rather than against the real `Db` so `mongodb` stays an\n * optional peer dependency: an app on Postgres never installs it, and its\n * types are not needed to typecheck this file.\n */\ntype MongoCollection = {\n insertMany(docs: Document[], options?: unknown): Promise<unknown>;\n insertOne(doc: Document, options?: unknown): Promise<unknown>;\n find(filter: Document, options?: Document): { toArray(): Promise<Document[]> };\n findOne(filter: Document, options?: Document): Promise<Document | null>;\n findOneAndUpdate(\n filter: Document,\n update: Document | Document[],\n options?: Document,\n ): Promise<Document | null>;\n updateOne(\n filter: Document,\n update: Document | Document[],\n options?: Document,\n ): Promise<{\n matchedCount: number;\n modifiedCount: number;\n upsertedCount?: number;\n }>;\n updateMany(\n filter: Document,\n update: Document | Document[],\n options?: Document,\n ): Promise<{\n matchedCount: number;\n modifiedCount: number;\n }>;\n deleteMany(filter: Document, options?: Document): Promise<{ deletedCount: number }>;\n countDocuments(filter: Document, options?: Document): Promise<number>;\n createIndex(spec: Document, options?: Document): Promise<string>;\n};\n\ntype MongoDb = {\n collection(name: string): MongoCollection;\n};\n\ntype MongoSession = {\n withTransaction<T>(fn: () => Promise<T>): Promise<T>;\n endSession(): Promise<void>;\n};\n\ntype MongoClient = {\n startSession(): MongoSession;\n};\n\nexport type MongoAdapterOptions = {\n /** Prefixes every collection name, matching the SQL adapter's table prefix. */\n prefix?: string;\n /**\n * The MongoClient the db came from. Supplying it makes createNotifications\n * atomic; without it a crash between the two writes can leave a notification\n * with no deliveries. Transactions need a replica set, so it is opt-in — a\n * standalone mongod rejects the session outright.\n */\n client?: unknown;\n};\n\nconst str = (value: unknown): string => String(value);\nconst nullableStr = (value: unknown): string | null => (value == null ? null : String(value));\nconst num = (value: unknown): number => Number(value);\nconst date = (value: unknown): Date => (value instanceof Date ? value : new Date(String(value)));\nconst nullableDate = (value: unknown): Date | null =>\n value == null ? null : value instanceof Date ? value : new Date(String(value));\n\nconst encodeCursor = (createdAt: Date, id: string) =>\n encodeBase64Url(`${createdAt.toISOString()}|${id}`);\n\nfunction decodeCursor(cursor: string): { createdAt: Date; id: string } | null {\n const decoded = decodeBase64Url(cursor);\n if (!decoded) return null;\n\n const [iso, id] = decoded.split(\"|\");\n if (!iso || !id) return null;\n\n const createdAt = new Date(iso);\n return Number.isNaN(createdAt.getTime()) ? null : { createdAt, id };\n}\n\n/** Documents carry the id as `_id`; the rest of the library never sees that. */\nfunction toNotification(doc: Document): NotificationRecord {\n return {\n id: str(doc._id),\n userId: str(doc.userId),\n type: str(doc.type),\n payload: doc.payload,\n actorId: nullableStr(doc.actorId),\n groupKey: nullableStr(doc.groupKey),\n dedupeKey: nullableStr(doc.dedupeKey),\n seenAt: nullableDate(doc.seenAt),\n readAt: nullableDate(doc.readAt),\n archivedAt: nullableDate(doc.archivedAt),\n createdAt: date(doc.createdAt),\n };\n}\n\nfunction toDelivery(doc: Document): DeliveryRecord {\n return {\n id: str(doc._id),\n notificationId: str(doc.notificationId),\n channel: str(doc.channel) as Channel,\n status: str(doc.status) as DeliveryStatus,\n attempts: num(doc.attempts),\n maxAttempts: num(doc.maxAttempts),\n notBefore: date(doc.notBefore),\n claimedAt: nullableDate(doc.claimedAt),\n claimedBy: nullableStr(doc.claimedBy),\n lastError: nullableStr(doc.lastError),\n updatedAt: date(doc.updatedAt),\n };\n}\n\n/** The store hands `id`; documents key on `_id`. */\nconst toMongoField = (field: string) => (field === \"id\" ? \"_id\" : field);\n\n/** Translates a WhereClause into a Mongo filter. */\nfunction toFilter(where: WhereClause): Document {\n const filter: Document = {};\n\n for (const [field, condition] of Object.entries(where)) {\n const key = toMongoField(field);\n\n if (condition === null) {\n filter[key] = null;\n continue;\n }\n\n if (!isOperator(condition)) {\n filter[key] = condition;\n continue;\n }\n\n const operator = condition as Record<string, unknown>;\n if (\"in\" in operator) filter[key] = { $in: operator.in };\n else if (\"lt\" in operator) filter[key] = { $lt: operator.lt };\n else if (\"lte\" in operator) filter[key] = { $lte: operator.lte };\n else if (\"gt\" in operator) filter[key] = { $gt: operator.gt };\n else if (\"gte\" in operator) filter[key] = { $gte: operator.gte };\n else if (\"not\" in operator) {\n // $ne null also matches a missing field, which is what \"not null\" means.\n filter[key] = { $ne: operator.not };\n }\n }\n\n return filter;\n}\n\n/** A duplicate on a unique index, rather than a real write failure. */\nconst isDuplicateKey = (error: unknown): boolean => {\n const code = (error as { code?: number; writeErrors?: { code?: number }[] })?.code;\n if (code === 11000) return true;\n const writeErrors = (error as { writeErrors?: { code?: number }[] })?.writeErrors;\n return Array.isArray(writeErrors) && writeErrors.some((entry) => entry?.code === 11000);\n};\n\nexport function mongoAdapter(db: unknown, options: MongoAdapterOptions = {}): DatabaseAdapter {\n const database = db as MongoDb;\n const prefix = options.prefix ?? \"\";\n\n const client = options.client as MongoClient | undefined;\n\n const notifications = () => database.collection(`${prefix}notification`);\n const deliveries = () => database.collection(`${prefix}notification_delivery`);\n\n /**\n * Runs `fn` in a transaction when a client was supplied, and plainly\n * otherwise. The session must reach every command inside, so `fn` receives\n * it — a write that omits it silently runs outside the transaction.\n *\n * One transaction per notification, not per batch: a duplicate key aborts\n * the transaction it happens in, and dedupe is the expected path here, so a\n * batch-wide transaction would throw away the notifications around it.\n */\n async function atomically<T>(fn: (session?: MongoSession) => Promise<T>): Promise<T> {\n if (!client) return fn();\n\n const session = client.startSession();\n try {\n return await session.withTransaction(() => fn(session));\n } finally {\n await session.endSession();\n }\n }\n\n return {\n name: \"mongodb\",\n // Documents keep the declared camelCase, and store objects natively.\n naming: \"preserve\",\n serializesJson: false,\n\n async createNotifications(input: readonly InsertNotification[]) {\n if (input.length === 0) return { created: [], deduped: [] };\n\n const created: string[] = [];\n const deduped: string[] = [];\n\n for (const row of input) {\n const now = new Date();\n\n try {\n await atomically(async (session) => {\n const options = session ? { session } : undefined;\n\n // The notification goes in first: it carries the unique dedupe\n // index, so a duplicate is rejected before any delivery is written.\n await notifications().insertOne(\n {\n _id: row.id,\n userId: row.userId,\n type: row.type,\n payload: row.payload ?? null,\n actorId: row.actorId ?? null,\n groupKey: row.groupKey ?? null,\n dedupeKey: row.dedupeKey ?? null,\n seenAt: null,\n readAt: null,\n archivedAt: null,\n createdAt: now,\n },\n options,\n );\n\n if (row.deliveries.length > 0) {\n await deliveries().insertMany(\n row.deliveries.map((delivery) => ({\n _id: delivery.id,\n notificationId: row.id,\n channel: delivery.channel,\n status: \"pending\",\n attempts: 0,\n maxAttempts: delivery.maxAttempts,\n notBefore: delivery.notBefore,\n claimedAt: null,\n claimedBy: null,\n lastError: null,\n updatedAt: now,\n })),\n options,\n );\n }\n });\n\n created.push(row.id);\n } catch (error) {\n if (!isDuplicateKey(error)) throw error;\n deduped.push(row.id);\n }\n }\n\n return { created, deduped };\n },\n\n async claimPendingDeliveries(args: ClaimArgs): Promise<readonly ClaimedDelivery[]> {\n const now = args.now ?? new Date();\n const staleBefore = new Date(now.getTime() - args.leaseMs);\n\n const eligible: Document = {\n $and: [\n {\n $or: [{ status: \"pending\" }, { status: \"claimed\", claimedAt: { $lt: staleBefore } }],\n },\n { notBefore: { $lte: now } },\n { $expr: { $lt: [\"$attempts\", \"$maxAttempts\"] } },\n ],\n };\n\n if (args.channels && args.channels.length > 0) {\n (eligible.$and as Document[]).push({ channel: { $in: [...args.channels] } });\n }\n if (args.ids && args.ids.length > 0) {\n (eligible.$and as Document[]).push({ _id: { $in: [...args.ids] } });\n }\n\n // findOneAndUpdate is atomic per document, so two concurrent callers\n // cannot be handed the same delivery. updateMany would be one round trip\n // but gives no way to learn which documents this call actually won.\n const claimed: Document[] = [];\n for (let taken = 0; taken < args.limit; taken += 1) {\n const doc = await deliveries().findOneAndUpdate(\n eligible,\n { $set: { status: \"claimed\", claimedAt: now, claimedBy: args.claimToken } },\n { sort: { notBefore: 1, _id: 1 }, returnDocument: \"after\" },\n );\n if (!doc) break;\n claimed.push(doc);\n }\n\n if (claimed.length === 0) return [];\n\n // One lookup for the batch rather than one per delivery.\n const parents = await notifications()\n .find({ _id: { $in: claimed.map((doc) => doc.notificationId) } })\n .toArray();\n const byId = new Map(parents.map((doc) => [str(doc._id), doc]));\n\n return claimed.flatMap((doc) => {\n const parent = byId.get(str(doc.notificationId));\n if (!parent) return [];\n\n return [\n {\n id: str(doc._id),\n notificationId: str(doc.notificationId),\n channel: str(doc.channel) as Channel,\n attempts: num(doc.attempts),\n maxAttempts: num(doc.maxAttempts),\n notification: {\n userId: str(parent.userId),\n type: str(parent.type),\n payload: parent.payload,\n actorId: nullableStr(parent.actorId),\n },\n },\n ];\n });\n },\n\n async releaseDeliveries(releases: readonly DeliveryRelease[]) {\n if (releases.length === 0) return;\n const now = new Date();\n\n for (const { id, outcome, nextAttemptAt } of releases) {\n const failed = outcome.result === \"failed\";\n const retryable = failed && outcome.retryable;\n\n // An aggregation-pipeline update so the terminal-vs-retry decision\n // reads maxAttempts from the document itself, as the SQL CASE does.\n await deliveries().updateOne({ _id: id }, [\n {\n $set: {\n attempts: failed ? { $add: [\"$attempts\", 1] } : \"$attempts\",\n status: failed\n ? {\n $cond: [\n { $and: [retryable, { $lt: [{ $add: [\"$attempts\", 1] }, \"$maxAttempts\"] }] },\n \"pending\",\n \"failed\",\n ],\n }\n : \"sent\",\n // $literal: an error message starting with \"$\" would otherwise\n // be read as a field path.\n lastError: failed ? { $literal: outcome.error.slice(0, 2000) } : null,\n notBefore: nextAttemptAt ?? \"$notBefore\",\n // Written unconditionally: if the lease expired and another\n // worker re-sent, the duplicate already happened and the true\n // terminal state beats leaving the row wedged in \"claimed\".\n claimedAt: null,\n claimedBy: null,\n updatedAt: now,\n },\n },\n ]);\n }\n },\n\n async listNotifications(query: FeedQuery): Promise<FeedPage> {\n const cursor = query.cursor ? decodeCursor(query.cursor) : null;\n\n const filter: Document = { userId: query.userId, archivedAt: null };\n if (query.unreadOnly) filter.readAt = null;\n\n if (cursor) {\n // Matches the SQL row comparison (createdAt, id) < (cursor, cursorId).\n filter.$or = [\n { createdAt: { $lt: cursor.createdAt } },\n { createdAt: cursor.createdAt, _id: { $lt: cursor.id } },\n ];\n }\n\n const docs = await notifications()\n .find(filter, { sort: { createdAt: -1, _id: -1 }, limit: query.limit + 1 })\n .toArray();\n\n const page = docs.slice(0, query.limit).map(toNotification);\n const last = page.at(-1);\n\n return {\n notifications: page,\n nextCursor:\n docs.length > query.limit && last ? encodeCursor(last.createdAt, last.id) : null,\n };\n },\n\n async countUnseen(userId: string) {\n return notifications().countDocuments({ userId, seenAt: null, archivedAt: null });\n },\n\n async markSeen(userId: string, before: Date) {\n await notifications().updateMany(\n { userId, seenAt: null, createdAt: { $lte: before } },\n { $set: { seenAt: new Date() } },\n );\n },\n\n async markRead(userId: string, notificationIds: readonly string[]) {\n if (notificationIds.length === 0) return 0;\n\n // Scoped by userId as well as id, and idempotent: re-marking a read\n // notification reports success rather than a 404.\n const filter = { userId, _id: { $in: [...notificationIds] } };\n await notifications().updateMany(\n { ...filter, readAt: null },\n {\n $set: { readAt: new Date() },\n },\n );\n\n return notifications().countDocuments(filter);\n },\n\n async markAllRead(userId: string) {\n const result = await notifications().updateMany(\n { userId, readAt: null },\n { $set: { readAt: new Date() } },\n );\n return result.modifiedCount;\n },\n\n async getFailedDeliveries(args: { since: Date; limit: number }) {\n const docs = await deliveries()\n .find(\n { status: \"failed\", updatedAt: { $gte: args.since } },\n { sort: { updatedAt: -1 }, limit: args.limit },\n )\n .toArray();\n\n return docs.map(toDelivery);\n },\n\n async queryTable(table: string, where: WhereClause, options: QueryOptions) {\n const find: Document = {};\n if (options.limit) find.limit = options.limit;\n if (options.orderBy) {\n const direction = options.orderBy.direction === \"desc\" ? -1 : 1;\n find.sort = { [toMongoField(options.orderBy.field)]: direction };\n }\n\n const docs = await database.collection(table).find(toFilter(where), find).toArray();\n\n // `_id` is a storage detail; plugins declared the field as `id`.\n return docs.map(({ _id, ...rest }) => (_id === undefined ? rest : { id: _id, ...rest }));\n },\n\n async insertRows(\n table: string,\n rows: readonly Record<string, unknown>[],\n onConflict?: readonly string[],\n ) {\n if (rows.length === 0) return 0;\n\n const documents = rows.map(({ id, ...rest }) =>\n id === undefined ? { ...rest } : { _id: id, ...rest },\n );\n\n if (!onConflict || onConflict.length === 0) {\n await database.collection(table).insertMany(documents as Document[]);\n return documents.length;\n }\n\n // Upsert keyed on the conflict fields, matching ON CONFLICT DO UPDATE.\n let written = 0;\n for (const document of documents as Document[]) {\n const key: Document = {};\n for (const field of onConflict) key[toMongoField(field)] = document[toMongoField(field)];\n\n // _id goes in $setOnInsert, never $set: Mongo rejects an update that\n // would modify it, so a conflicting upsert must leave it alone.\n const { _id, ...updatable } = document;\n const update: Document = { $set: updatable };\n if (_id !== undefined) update.$setOnInsert = { _id };\n\n const result = await database.collection(table).updateOne(key, update, { upsert: true });\n written += result.matchedCount + (result.upsertedCount ?? 0);\n }\n return written;\n },\n\n async updateRows(table: string, where: WhereClause, set: Record<string, unknown>) {\n const assignments: Document = {};\n for (const [field, value] of Object.entries(set)) assignments[toMongoField(field)] = value;\n if (Object.keys(assignments).length === 0) return 0;\n\n const result = await database\n .collection(table)\n .updateMany(toFilter(where), { $set: assignments });\n return result.matchedCount;\n },\n\n async deleteRows(table: string, where: WhereClause) {\n const result = await database.collection(table).deleteMany(toFilter(where));\n return result.deletedCount;\n },\n };\n}\n","import type { FieldDeclaration, SchemaDeclaration } from \"../../core/plugin\";\nimport { coreSchema } from \"../../schema/declaration\";\n\ntype IndexSpec = Record<string, 1 | -1>;\n\ntype IndexOptions = {\n name: string;\n unique?: boolean;\n partialFilterExpression?: Record<string, unknown>;\n};\n\ntype IndexableDb = {\n collection(name: string): {\n createIndex(spec: IndexSpec, options: IndexOptions): Promise<string>;\n };\n};\n\nconst BSON_TYPE: Record<FieldDeclaration[\"type\"], string> = {\n string: \"string\",\n number: \"number\",\n boolean: \"bool\",\n date: \"date\",\n json: \"object\",\n};\n\n/**\n * Applies a SchemaDeclaration's indexes to Mongo. The document counterpart of\n * renderPostgresDdl — there are no tables to create, only indexes, and the\n * declaration is the same source of truth.\n *\n * A unique index over a nullable field gets a partial filter. Postgres treats\n * every NULL as distinct, so unlimited rows may leave dedupeKey unset; a plain\n * Mongo unique index treats them as one value and would allow exactly one.\n */\nexport async function createPluginIndexes(\n db: unknown,\n schema: SchemaDeclaration,\n prefix = \"\",\n): Promise<void> {\n const database = db as IndexableDb;\n\n for (const table of Object.values(schema)) {\n const collection = database.collection(prefix + table.tableName);\n\n // A single \"id\" key is stored as _id, which is already unique.\n if (table.primaryKey && table.primaryKey.length > 0 && table.primaryKey[0] !== \"id\") {\n const spec: IndexSpec = {};\n for (const field of table.primaryKey) spec[field] = 1;\n await collection.createIndex(spec, {\n name: `${table.tableName}_pk`,\n unique: true,\n });\n }\n\n for (const declaration of table.indexes ?? []) {\n const spec: IndexSpec = {};\n for (const field of declaration.on) spec[field] = 1;\n\n const options: IndexOptions = {\n name: prefix + (declaration.name ?? `${table.tableName}_${declaration.on.join(\"_\")}_idx`),\n };\n\n if (declaration.unique) {\n options.unique = true;\n\n const partial: Record<string, unknown> = {};\n for (const field of declaration.on) {\n const spec = table.fields[field];\n if (spec && !spec.required) partial[field] = { $type: BSON_TYPE[spec.type] };\n }\n if (Object.keys(partial).length > 0) options.partialFilterExpression = partial;\n }\n\n await collection.createIndex(spec, options);\n }\n }\n}\n\n/** Creates the indexes the core tables need. Call once at startup. */\nexport const createMongoIndexes = (db: unknown, options: { prefix?: string } = {}) =>\n createPluginIndexes(db, coreSchema, options.prefix ?? \"\");\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/adapters/mongodb/adapter.ts","../../src/adapters/mongodb/indexes.ts"],"names":["options","spec"],"mappings":"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","file":"mongodb.js","sourcesContent":["import type {\n ClaimArgs,\n ClaimedDelivery,\n DatabaseAdapter,\n DeliveryRelease,\n FeedPage,\n FeedQuery,\n InsertNotification,\n} from \"../../core/adapter\";\nimport { decodeBase64Url, encodeBase64Url } from \"../../core/base64url\";\nimport { isOperator, type QueryOptions, type WhereClause } from \"../../core/store\";\nimport type { Channel, DeliveryRecord, DeliveryStatus, NotificationRecord } from \"../../core/types\";\n\ntype Document = Record<string, unknown>;\n\n/**\n * Minimal structural view of the pieces of the Mongo driver this uses.\n *\n * Typed structurally rather than against the real `Db` so `mongodb` stays an\n * optional peer dependency: an app on Postgres never installs it, and its\n * types are not needed to typecheck this file.\n */\ntype MongoCollection = {\n insertMany(docs: Document[], options?: unknown): Promise<unknown>;\n insertOne(doc: Document, options?: unknown): Promise<unknown>;\n find(filter: Document, options?: Document): { toArray(): Promise<Document[]> };\n findOne(filter: Document, options?: Document): Promise<Document | null>;\n findOneAndUpdate(\n filter: Document,\n update: Document | Document[],\n options?: Document,\n ): Promise<Document | null>;\n updateOne(\n filter: Document,\n update: Document | Document[],\n options?: Document,\n ): Promise<{\n matchedCount: number;\n modifiedCount: number;\n upsertedCount?: number;\n }>;\n updateMany(\n filter: Document,\n update: Document | Document[],\n options?: Document,\n ): Promise<{\n matchedCount: number;\n modifiedCount: number;\n }>;\n deleteMany(filter: Document, options?: Document): Promise<{ deletedCount: number }>;\n countDocuments(filter: Document, options?: Document): Promise<number>;\n createIndex(spec: Document, options?: Document): Promise<string>;\n};\n\ntype MongoDb = {\n collection(name: string): MongoCollection;\n};\n\ntype MongoSession = {\n withTransaction<T>(fn: () => Promise<T>): Promise<T>;\n endSession(): Promise<void>;\n};\n\ntype MongoClient = {\n startSession(): MongoSession;\n};\n\nexport type MongoAdapterOptions = {\n /** Prefixes every collection name, matching the SQL adapter's table prefix. */\n prefix?: string;\n /**\n * The MongoClient the db came from. Supplying it makes createNotifications\n * atomic; without it a crash between the two writes can leave a notification\n * with no deliveries. Transactions need a replica set, so it is opt-in — a\n * standalone mongod rejects the session outright.\n */\n client?: unknown;\n};\n\nconst str = (value: unknown): string => String(value);\nconst nullableStr = (value: unknown): string | null => (value == null ? null : String(value));\nconst num = (value: unknown): number => Number(value);\nconst date = (value: unknown): Date => (value instanceof Date ? value : new Date(String(value)));\nconst nullableDate = (value: unknown): Date | null =>\n value == null ? null : value instanceof Date ? value : new Date(String(value));\n\nconst encodeCursor = (createdAt: Date, id: string) =>\n encodeBase64Url(`${createdAt.toISOString()}|${id}`);\n\nfunction decodeCursor(cursor: string): { createdAt: Date; id: string } | null {\n const decoded = decodeBase64Url(cursor);\n if (!decoded) return null;\n\n const [iso, id] = decoded.split(\"|\");\n if (!iso || !id) return null;\n\n const createdAt = new Date(iso);\n return Number.isNaN(createdAt.getTime()) ? null : { createdAt, id };\n}\n\n/** Documents carry the id as `_id`; the rest of the library never sees that. */\nfunction toNotification(doc: Document): NotificationRecord {\n return {\n id: str(doc._id),\n userId: str(doc.userId),\n type: str(doc.type),\n payload: doc.payload,\n actorId: nullableStr(doc.actorId),\n groupKey: nullableStr(doc.groupKey),\n dedupeKey: nullableStr(doc.dedupeKey),\n seenAt: nullableDate(doc.seenAt),\n readAt: nullableDate(doc.readAt),\n archivedAt: nullableDate(doc.archivedAt),\n createdAt: date(doc.createdAt),\n };\n}\n\nfunction toDelivery(doc: Document): DeliveryRecord {\n return {\n id: str(doc._id),\n notificationId: str(doc.notificationId),\n channel: str(doc.channel) as Channel,\n status: str(doc.status) as DeliveryStatus,\n attempts: num(doc.attempts),\n maxAttempts: num(doc.maxAttempts),\n notBefore: date(doc.notBefore),\n claimedAt: nullableDate(doc.claimedAt),\n claimedBy: nullableStr(doc.claimedBy),\n lastError: nullableStr(doc.lastError),\n updatedAt: date(doc.updatedAt),\n };\n}\n\n/** The store hands `id`; documents key on `_id`. */\nconst toMongoField = (field: string) => (field === \"id\" ? \"_id\" : field);\n\n/** Translates a WhereClause into a Mongo filter. */\nfunction toFilter(where: WhereClause): Document {\n const filter: Document = {};\n\n for (const [field, condition] of Object.entries(where)) {\n const key = toMongoField(field);\n\n if (condition === null) {\n filter[key] = null;\n continue;\n }\n\n if (!isOperator(condition)) {\n // The store already refuses these; this is the last line before the\n // driver, where `{ $ne: null }` stops being data and becomes a query.\n if (typeof condition === \"object\" && !(condition instanceof Date)) {\n throw new Error(`mongo filter on \"${field}\" received an object; only scalars are bound`);\n }\n filter[key] = condition;\n continue;\n }\n\n const operator = condition as Record<string, unknown>;\n if (\"in\" in operator) filter[key] = { $in: operator.in };\n else if (\"lt\" in operator) filter[key] = { $lt: operator.lt };\n else if (\"lte\" in operator) filter[key] = { $lte: operator.lte };\n else if (\"gt\" in operator) filter[key] = { $gt: operator.gt };\n else if (\"gte\" in operator) filter[key] = { $gte: operator.gte };\n else if (\"not\" in operator) {\n // $ne null also matches a missing field, which is what \"not null\" means.\n filter[key] = { $ne: operator.not };\n }\n }\n\n return filter;\n}\n\n/** A duplicate on a unique index, rather than a real write failure. */\nconst isDuplicateKey = (error: unknown): boolean => {\n const code = (error as { code?: number; writeErrors?: { code?: number }[] })?.code;\n if (code === 11000) return true;\n const writeErrors = (error as { writeErrors?: { code?: number }[] })?.writeErrors;\n return Array.isArray(writeErrors) && writeErrors.some((entry) => entry?.code === 11000);\n};\n\nexport function mongoAdapter(db: unknown, options: MongoAdapterOptions = {}): DatabaseAdapter {\n const database = db as MongoDb;\n const prefix = options.prefix ?? \"\";\n\n const client = options.client as MongoClient | undefined;\n\n const notifications = () => database.collection(`${prefix}notification`);\n const deliveries = () => database.collection(`${prefix}notification_delivery`);\n\n /**\n * Runs `fn` in a transaction when a client was supplied, and plainly\n * otherwise. The session must reach every command inside, so `fn` receives\n * it — a write that omits it silently runs outside the transaction.\n *\n * One transaction per notification, not per batch: a duplicate key aborts\n * the transaction it happens in, and dedupe is the expected path here, so a\n * batch-wide transaction would throw away the notifications around it.\n */\n async function atomically<T>(fn: (session?: MongoSession) => Promise<T>): Promise<T> {\n if (!client) return fn();\n\n const session = client.startSession();\n try {\n return await session.withTransaction(() => fn(session));\n } finally {\n await session.endSession();\n }\n }\n\n return {\n name: \"mongodb\",\n // Documents keep the declared camelCase, and store objects natively.\n naming: \"preserve\",\n serializesJson: false,\n\n async createNotifications(input: readonly InsertNotification[]) {\n if (input.length === 0) return { created: [], deduped: [] };\n\n const created: string[] = [];\n const deduped: string[] = [];\n\n for (const row of input) {\n const now = new Date();\n\n try {\n await atomically(async (session) => {\n const options = session ? { session } : undefined;\n\n // The notification goes in first: it carries the unique dedupe\n // index, so a duplicate is rejected before any delivery is written.\n await notifications().insertOne(\n {\n _id: row.id,\n userId: row.userId,\n type: row.type,\n payload: row.payload ?? null,\n actorId: row.actorId ?? null,\n groupKey: row.groupKey ?? null,\n dedupeKey: row.dedupeKey ?? null,\n seenAt: null,\n readAt: null,\n archivedAt: null,\n createdAt: now,\n },\n options,\n );\n\n if (row.deliveries.length > 0) {\n await deliveries().insertMany(\n row.deliveries.map((delivery) => ({\n _id: delivery.id,\n notificationId: row.id,\n channel: delivery.channel,\n status: \"pending\",\n attempts: 0,\n maxAttempts: delivery.maxAttempts,\n notBefore: delivery.notBefore,\n claimedAt: null,\n claimedBy: null,\n lastError: null,\n updatedAt: now,\n })),\n options,\n );\n }\n });\n\n created.push(row.id);\n } catch (error) {\n if (!isDuplicateKey(error)) throw error;\n deduped.push(row.id);\n }\n }\n\n return { created, deduped };\n },\n\n async claimPendingDeliveries(args: ClaimArgs): Promise<readonly ClaimedDelivery[]> {\n const now = args.now ?? new Date();\n const staleBefore = new Date(now.getTime() - args.leaseMs);\n\n const eligible: Document = {\n $and: [\n {\n $or: [{ status: \"pending\" }, { status: \"claimed\", claimedAt: { $lt: staleBefore } }],\n },\n { notBefore: { $lte: now } },\n { $expr: { $lt: [\"$attempts\", \"$maxAttempts\"] } },\n ],\n };\n\n if (args.channels && args.channels.length > 0) {\n (eligible.$and as Document[]).push({ channel: { $in: [...args.channels] } });\n }\n if (args.ids && args.ids.length > 0) {\n (eligible.$and as Document[]).push({ _id: { $in: [...args.ids] } });\n }\n\n // findOneAndUpdate is atomic per document, so two concurrent callers\n // cannot be handed the same delivery. updateMany would be one round trip\n // but gives no way to learn which documents this call actually won.\n const claimed: Document[] = [];\n for (let taken = 0; taken < args.limit; taken += 1) {\n const doc = await deliveries().findOneAndUpdate(\n eligible,\n { $set: { status: \"claimed\", claimedAt: now, claimedBy: args.claimToken } },\n { sort: { notBefore: 1, _id: 1 }, returnDocument: \"after\" },\n );\n if (!doc) break;\n claimed.push(doc);\n }\n\n if (claimed.length === 0) return [];\n\n // One lookup for the batch rather than one per delivery.\n const parents = await notifications()\n .find({ _id: { $in: claimed.map((doc) => doc.notificationId) } })\n .toArray();\n const byId = new Map(parents.map((doc) => [str(doc._id), doc]));\n\n return claimed.flatMap((doc) => {\n const parent = byId.get(str(doc.notificationId));\n if (!parent) return [];\n\n return [\n {\n id: str(doc._id),\n notificationId: str(doc.notificationId),\n channel: str(doc.channel) as Channel,\n attempts: num(doc.attempts),\n maxAttempts: num(doc.maxAttempts),\n notification: {\n userId: str(parent.userId),\n type: str(parent.type),\n payload: parent.payload,\n actorId: nullableStr(parent.actorId),\n },\n },\n ];\n });\n },\n\n async releaseDeliveries(releases: readonly DeliveryRelease[]) {\n if (releases.length === 0) return;\n const now = new Date();\n\n for (const { id, outcome, nextAttemptAt } of releases) {\n const failed = outcome.result === \"failed\";\n const skipped = outcome.result === \"skipped\";\n const retryable = failed && outcome.retryable;\n\n // An aggregation-pipeline update so the terminal-vs-retry decision\n // reads maxAttempts from the document itself, as the SQL CASE does.\n await deliveries().updateOne({ _id: id }, [\n {\n $set: {\n attempts: failed ? { $add: [\"$attempts\", 1] } : \"$attempts\",\n status: failed\n ? {\n $cond: [\n { $and: [retryable, { $lt: [{ $add: [\"$attempts\", 1] }, \"$maxAttempts\"] }] },\n \"pending\",\n \"failed\",\n ],\n }\n : skipped\n ? \"skipped\"\n : \"sent\",\n // $literal: an error message starting with \"$\" would otherwise\n // be read as a field path.\n lastError: failed\n ? { $literal: outcome.error.slice(0, 2000) }\n : skipped\n ? { $literal: outcome.reason.slice(0, 2000) }\n : null,\n notBefore: nextAttemptAt ?? \"$notBefore\",\n // Written unconditionally: if the lease expired and another\n // worker re-sent, the duplicate already happened and the true\n // terminal state beats leaving the row wedged in \"claimed\".\n claimedAt: null,\n claimedBy: null,\n updatedAt: now,\n },\n },\n ]);\n }\n },\n\n async listNotifications(query: FeedQuery): Promise<FeedPage> {\n const cursor = query.cursor ? decodeCursor(query.cursor) : null;\n\n const filter: Document = { userId: query.userId, archivedAt: null };\n if (query.unreadOnly) filter.readAt = null;\n\n if (cursor) {\n // Matches the SQL row comparison (createdAt, id) < (cursor, cursorId).\n filter.$or = [\n { createdAt: { $lt: cursor.createdAt } },\n { createdAt: cursor.createdAt, _id: { $lt: cursor.id } },\n ];\n }\n\n const docs = await notifications()\n .find(filter, { sort: { createdAt: -1, _id: -1 }, limit: query.limit + 1 })\n .toArray();\n\n const page = docs.slice(0, query.limit).map(toNotification);\n const last = page.at(-1);\n\n return {\n notifications: page,\n nextCursor:\n docs.length > query.limit && last ? encodeCursor(last.createdAt, last.id) : null,\n };\n },\n\n async countUnseen(userId: string) {\n return notifications().countDocuments({ userId, seenAt: null, archivedAt: null });\n },\n\n async markSeen(userId: string, before: Date) {\n await notifications().updateMany(\n { userId, seenAt: null, createdAt: { $lte: before } },\n { $set: { seenAt: new Date() } },\n );\n },\n\n async markRead(userId: string, notificationIds: readonly string[]) {\n if (notificationIds.length === 0) return 0;\n\n // Scoped by userId as well as id, and idempotent: re-marking a read\n // notification reports success rather than a 404.\n const filter = { userId, _id: { $in: [...notificationIds] } };\n await notifications().updateMany(\n { ...filter, readAt: null },\n {\n $set: { readAt: new Date() },\n },\n );\n\n return notifications().countDocuments(filter);\n },\n\n async markAllRead(userId: string) {\n const result = await notifications().updateMany(\n { userId, readAt: null },\n { $set: { readAt: new Date() } },\n );\n return result.modifiedCount;\n },\n\n async getFailedDeliveries(args: { since: Date; limit: number }) {\n const docs = await deliveries()\n .find(\n { status: \"failed\", updatedAt: { $gte: args.since } },\n { sort: { updatedAt: -1 }, limit: args.limit },\n )\n .toArray();\n\n return docs.map(toDelivery);\n },\n\n async queryTable(table: string, where: WhereClause, options: QueryOptions) {\n const find: Document = {};\n if (options.limit) find.limit = options.limit;\n if (options.orderBy) {\n const direction = options.orderBy.direction === \"desc\" ? -1 : 1;\n find.sort = { [toMongoField(options.orderBy.field)]: direction };\n }\n\n const docs = await database.collection(table).find(toFilter(where), find).toArray();\n\n // `_id` is a storage detail; plugins declared the field as `id`.\n return docs.map(({ _id, ...rest }) => (_id === undefined ? rest : { id: _id, ...rest }));\n },\n\n async insertRows(\n table: string,\n rows: readonly Record<string, unknown>[],\n onConflict?: readonly string[],\n ) {\n if (rows.length === 0) return 0;\n\n const documents = rows.map(({ id, ...rest }) =>\n id === undefined ? { ...rest } : { _id: id, ...rest },\n );\n\n if (!onConflict || onConflict.length === 0) {\n await database.collection(table).insertMany(documents as Document[]);\n return documents.length;\n }\n\n // Upsert keyed on the conflict fields, matching ON CONFLICT DO UPDATE.\n let written = 0;\n for (const document of documents as Document[]) {\n const key: Document = {};\n for (const field of onConflict) key[toMongoField(field)] = document[toMongoField(field)];\n\n // _id goes in $setOnInsert, never $set: Mongo rejects an update that\n // would modify it, so a conflicting upsert must leave it alone.\n const { _id, ...updatable } = document;\n const update: Document = { $set: updatable };\n if (_id !== undefined) update.$setOnInsert = { _id };\n\n const result = await database.collection(table).updateOne(key, update, { upsert: true });\n written += result.matchedCount + (result.upsertedCount ?? 0);\n }\n return written;\n },\n\n async updateRows(table: string, where: WhereClause, set: Record<string, unknown>) {\n const assignments: Document = {};\n for (const [field, value] of Object.entries(set)) assignments[toMongoField(field)] = value;\n if (Object.keys(assignments).length === 0) return 0;\n\n const result = await database\n .collection(table)\n .updateMany(toFilter(where), { $set: assignments });\n return result.matchedCount;\n },\n\n async deleteRows(table: string, where: WhereClause) {\n const result = await database.collection(table).deleteMany(toFilter(where));\n return result.deletedCount;\n },\n };\n}\n","import type { FieldDeclaration, SchemaDeclaration } from \"../../core/plugin\";\nimport { coreSchema } from \"../../schema/declaration\";\n\ntype IndexSpec = Record<string, 1 | -1>;\n\ntype IndexOptions = {\n name: string;\n unique?: boolean;\n partialFilterExpression?: Record<string, unknown>;\n};\n\ntype IndexableDb = {\n collection(name: string): {\n createIndex(spec: IndexSpec, options: IndexOptions): Promise<string>;\n };\n};\n\nconst BSON_TYPE: Record<FieldDeclaration[\"type\"], string> = {\n string: \"string\",\n number: \"number\",\n boolean: \"bool\",\n date: \"date\",\n json: \"object\",\n};\n\n/**\n * Applies a SchemaDeclaration's indexes to Mongo. The document counterpart of\n * renderPostgresDdl — there are no tables to create, only indexes, and the\n * declaration is the same source of truth.\n *\n * A unique index over a nullable field gets a partial filter. Postgres treats\n * every NULL as distinct, so unlimited rows may leave dedupeKey unset; a plain\n * Mongo unique index treats them as one value and would allow exactly one.\n */\nexport async function createPluginIndexes(\n db: unknown,\n schema: SchemaDeclaration,\n prefix = \"\",\n): Promise<void> {\n const database = db as IndexableDb;\n\n for (const table of Object.values(schema)) {\n const collection = database.collection(prefix + table.tableName);\n\n // A single \"id\" key is stored as _id, which is already unique.\n if (table.primaryKey && table.primaryKey.length > 0 && table.primaryKey[0] !== \"id\") {\n const spec: IndexSpec = {};\n for (const field of table.primaryKey) spec[field] = 1;\n await collection.createIndex(spec, {\n name: `${table.tableName}_pk`,\n unique: true,\n });\n }\n\n for (const declaration of table.indexes ?? []) {\n const spec: IndexSpec = {};\n for (const field of declaration.on) spec[field] = 1;\n\n const options: IndexOptions = {\n name: prefix + (declaration.name ?? `${table.tableName}_${declaration.on.join(\"_\")}_idx`),\n };\n\n if (declaration.unique) {\n options.unique = true;\n\n const partial: Record<string, unknown> = {};\n for (const field of declaration.on) {\n const spec = table.fields[field];\n if (spec && !spec.required) partial[field] = { $type: BSON_TYPE[spec.type] };\n }\n if (Object.keys(partial).length > 0) options.partialFilterExpression = partial;\n }\n\n await collection.createIndex(spec, options);\n }\n }\n}\n\n/** Creates the indexes the core tables need. Call once at startup. */\nexport const createMongoIndexes = (db: unknown, options: { prefix?: string } = {}) =>\n createPluginIndexes(db, coreSchema, options.prefix ?? \"\");\n"]}
|
|
@@ -22,10 +22,67 @@ function decodeBase64Url(value) {
|
|
|
22
22
|
|
|
23
23
|
// src/schema/declaration.ts
|
|
24
24
|
var toSnakeCase = (value) => value.replace(/[A-Z]/g, (c) => `_${c.toLowerCase()}`);
|
|
25
|
+
var coreSchema = {
|
|
26
|
+
notification: {
|
|
27
|
+
tableName: "notification",
|
|
28
|
+
fields: {
|
|
29
|
+
id: { type: "string", required: true },
|
|
30
|
+
userId: { type: "string", required: true },
|
|
31
|
+
type: { type: "string", required: true },
|
|
32
|
+
payload: { type: "json", required: true },
|
|
33
|
+
actorId: { type: "string" },
|
|
34
|
+
groupKey: { type: "string" },
|
|
35
|
+
dedupeKey: { type: "string" },
|
|
36
|
+
seenAt: { type: "date" },
|
|
37
|
+
readAt: { type: "date" },
|
|
38
|
+
archivedAt: { type: "date" },
|
|
39
|
+
createdAt: { type: "date", required: true, defaultNow: true }
|
|
40
|
+
},
|
|
41
|
+
primaryKey: ["id"],
|
|
42
|
+
indexes: [
|
|
43
|
+
{ on: ["userId", "createdAt"], name: "notification_feed_idx" },
|
|
44
|
+
{ on: ["userId", "groupKey"], name: "notification_group_idx" },
|
|
45
|
+
{ on: ["userId", "dedupeKey"], unique: true, name: "notification_dedupe_idx" }
|
|
46
|
+
]
|
|
47
|
+
},
|
|
48
|
+
notificationDelivery: {
|
|
49
|
+
tableName: "notification_delivery",
|
|
50
|
+
fields: {
|
|
51
|
+
id: { type: "string", required: true },
|
|
52
|
+
notificationId: { type: "string", required: true },
|
|
53
|
+
channel: { type: "string", required: true },
|
|
54
|
+
status: { type: "string", required: true, default: "pending" },
|
|
55
|
+
attempts: { type: "number", required: true, default: 0 },
|
|
56
|
+
maxAttempts: { type: "number", required: true, default: 5 },
|
|
57
|
+
notBefore: { type: "date", required: true, defaultNow: true },
|
|
58
|
+
claimedAt: { type: "date" },
|
|
59
|
+
claimedBy: { type: "string" },
|
|
60
|
+
lastError: { type: "string" },
|
|
61
|
+
updatedAt: { type: "date", required: true, defaultNow: true }
|
|
62
|
+
},
|
|
63
|
+
primaryKey: ["id"],
|
|
64
|
+
indexes: [
|
|
65
|
+
{ on: ["status", "notBefore"], name: "delivery_claim_idx" },
|
|
66
|
+
{ on: ["notificationId"], name: "delivery_notification_idx" }
|
|
67
|
+
]
|
|
68
|
+
},
|
|
69
|
+
notificationPreference: {
|
|
70
|
+
tableName: "notification_preference",
|
|
71
|
+
fields: {
|
|
72
|
+
userId: { type: "string", required: true },
|
|
73
|
+
type: { type: "string", required: true },
|
|
74
|
+
channel: { type: "string", required: true },
|
|
75
|
+
enabled: { type: "boolean", required: true, default: true },
|
|
76
|
+
frequency: { type: "string", required: true, default: "instant" },
|
|
77
|
+
updatedAt: { type: "date", required: true, defaultNow: true }
|
|
78
|
+
},
|
|
79
|
+
primaryKey: ["userId", "type", "channel"]
|
|
80
|
+
}
|
|
81
|
+
};
|
|
25
82
|
|
|
26
83
|
// src/core/store.ts
|
|
27
84
|
var OPERATORS = ["in", "lt", "lte", "gt", "gte", "not"];
|
|
28
|
-
var isOperator = (value) => typeof value === "object" && value !== null && !(value instanceof Date) && OPERATORS.some((op) => op
|
|
85
|
+
var isOperator = (value) => typeof value === "object" && value !== null && !(value instanceof Date) && OPERATORS.some((op) => Object.hasOwn(value, op));
|
|
29
86
|
|
|
30
87
|
// src/adapters/postgres/statement.ts
|
|
31
88
|
var Statement = class {
|
|
@@ -231,7 +288,7 @@ function postgresAdapter(query, options = {}) {
|
|
|
231
288
|
if (releases.length === 0) return;
|
|
232
289
|
const now = /* @__PURE__ */ new Date();
|
|
233
290
|
const statement = new Statement().raw(
|
|
234
|
-
`UPDATE ${DELIVERY} d SET status = CASE WHEN v.result = 'sent' THEN 'sent' WHEN v.retryable AND d.attempts + 1 < d.max_attempts THEN 'pending' ELSE 'failed' END, attempts = CASE WHEN v.result
|
|
291
|
+
`UPDATE ${DELIVERY} d SET status = CASE WHEN v.result = 'sent' THEN 'sent' WHEN v.result = 'skipped' THEN 'skipped' WHEN v.retryable AND d.attempts + 1 < d.max_attempts THEN 'pending' ELSE 'failed' END, attempts = CASE WHEN v.result IN ('sent', 'skipped') THEN d.attempts ELSE d.attempts + 1 END, last_error = v.error, not_before = COALESCE(v.not_before, d.not_before), claimed_at = NULL, claimed_by = NULL, updated_at = `
|
|
235
292
|
);
|
|
236
293
|
statement.value(now).raw("::timestamptz FROM (VALUES ");
|
|
237
294
|
releases.forEach(({ id, outcome, nextAttemptAt }, index) => {
|
|
@@ -240,7 +297,10 @@ function postgresAdapter(query, options = {}) {
|
|
|
240
297
|
[id, "text"],
|
|
241
298
|
[outcome.result, "text"],
|
|
242
299
|
[outcome.result === "failed" && outcome.retryable, "boolean"],
|
|
243
|
-
[
|
|
300
|
+
[
|
|
301
|
+
outcome.result === "failed" ? outcome.error.slice(0, 2e3) : outcome.result === "skipped" ? outcome.reason.slice(0, 2e3) : null,
|
|
302
|
+
"text"
|
|
303
|
+
],
|
|
244
304
|
[nextAttemptAt ?? null, "timestamptz"]
|
|
245
305
|
]);
|
|
246
306
|
});
|
|
@@ -347,6 +407,79 @@ function postgresAdapter(query, options = {}) {
|
|
|
347
407
|
};
|
|
348
408
|
}
|
|
349
409
|
|
|
410
|
+
// src/schema/render-sql.ts
|
|
411
|
+
var SQL_TYPE = {
|
|
412
|
+
string: "text",
|
|
413
|
+
number: "integer",
|
|
414
|
+
boolean: "boolean",
|
|
415
|
+
date: "timestamptz",
|
|
416
|
+
json: "jsonb"
|
|
417
|
+
};
|
|
418
|
+
var quote2 = (value) => `"${value.replace(/"/g, '""')}"`;
|
|
419
|
+
var defaultClause = (field) => {
|
|
420
|
+
if (field.defaultNow) return " DEFAULT now()";
|
|
421
|
+
if (field.default === void 0) return "";
|
|
422
|
+
if (typeof field.default === "string") return ` DEFAULT '${field.default.replace(/'/g, "''")}'`;
|
|
423
|
+
return ` DEFAULT ${field.default}`;
|
|
424
|
+
};
|
|
425
|
+
function renderPostgresDdl(schema, prefix = "") {
|
|
426
|
+
const statements = [];
|
|
427
|
+
for (const table of Object.values(schema)) {
|
|
428
|
+
const name = quote2(prefix + table.tableName);
|
|
429
|
+
const columns = Object.entries(table.fields).map(([field, spec]) => {
|
|
430
|
+
const nullability = spec.required ? " NOT NULL" : "";
|
|
431
|
+
return ` ${quote2(toSnakeCase(field))} ${SQL_TYPE[spec.type]}${nullability}${defaultClause(spec)}`;
|
|
432
|
+
});
|
|
433
|
+
if (table.primaryKey?.length) {
|
|
434
|
+
const key = table.primaryKey.map((field) => quote2(toSnakeCase(field))).join(", ");
|
|
435
|
+
columns.push(` PRIMARY KEY (${key})`);
|
|
436
|
+
}
|
|
437
|
+
statements.push(`CREATE TABLE IF NOT EXISTS ${name} (
|
|
438
|
+
${columns.join(",\n")}
|
|
439
|
+
)`);
|
|
440
|
+
for (const declaration of table.indexes ?? []) {
|
|
441
|
+
const indexName = quote2(
|
|
442
|
+
prefix + (declaration.name ?? `${table.tableName}_${declaration.on.join("_")}_idx`)
|
|
443
|
+
);
|
|
444
|
+
const columns2 = declaration.on.map((field) => quote2(toSnakeCase(field))).join(", ");
|
|
445
|
+
const unique = declaration.unique ? "UNIQUE " : "";
|
|
446
|
+
statements.push(`CREATE ${unique}INDEX IF NOT EXISTS ${indexName} ON ${name} (${columns2})`);
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
return statements;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
// src/adapters/postgres/helpers.ts
|
|
453
|
+
function pgTransaction(pool) {
|
|
454
|
+
return async (fn) => {
|
|
455
|
+
const client = await pool.connect();
|
|
456
|
+
try {
|
|
457
|
+
await client.query("BEGIN");
|
|
458
|
+
const result = await fn(async (text, params) => (await client.query(text, params)).rows);
|
|
459
|
+
await client.query("COMMIT");
|
|
460
|
+
return result;
|
|
461
|
+
} catch (error) {
|
|
462
|
+
await client.query("ROLLBACK");
|
|
463
|
+
throw error;
|
|
464
|
+
} finally {
|
|
465
|
+
client.release();
|
|
466
|
+
}
|
|
467
|
+
};
|
|
468
|
+
}
|
|
469
|
+
async function createPostgresTables(query, options = {}) {
|
|
470
|
+
const schemas = [coreSchema, ...options.plugins ?? []];
|
|
471
|
+
let count = 0;
|
|
472
|
+
for (const schema of schemas) {
|
|
473
|
+
for (const statement of renderPostgresDdl(schema, options.prefix)) {
|
|
474
|
+
await query(statement, []);
|
|
475
|
+
count += 1;
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
return count;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
exports.createPostgresTables = createPostgresTables;
|
|
482
|
+
exports.pgTransaction = pgTransaction;
|
|
350
483
|
exports.postgresAdapter = postgresAdapter;
|
|
351
484
|
//# sourceMappingURL=postgres.cjs.map
|
|
352
485
|
//# sourceMappingURL=postgres.cjs.map
|