@bimetal/alerting 0.29.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 +50 -0
- package/dist/.tsbuildinfo +1 -0
- package/dist/engine.d.ts +25 -0
- package/dist/engine.d.ts.map +1 -0
- package/dist/engine.js +55 -0
- package/dist/engine.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/orchestrator.d.ts +3 -0
- package/dist/orchestrator.d.ts.map +1 -0
- package/dist/orchestrator.js +120 -0
- package/dist/orchestrator.js.map +1 -0
- package/dist/types.d.ts +89 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +50 -0
package/README.md
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# @bimetal/alerting
|
|
2
|
+
|
|
3
|
+
Die **Alert-Engine**: reagiert auf Domain-Events (Kalender-Termin angelegt, …) und zeitbasierte Auslöser (`before_start`) und stellt über pluggable Channels zu. Built on `@bimetal/event-sourcing`, `@bimetal/alert-data` und `@bimetal/channel`.
|
|
4
|
+
|
|
5
|
+
Zwei tragende Architekturentscheidungen:
|
|
6
|
+
|
|
7
|
+
1. **Pure Engine + Host-Tick** — die Auswertung ist eine reine Funktion; **kein Scheduler/Timer im Core**. Der Host treibt `ingest(event)` + `tick(now)` (setInterval/Worker/Cron/Broker-Pulse). Deterministisch testbar.
|
|
8
|
+
2. **Alerts-as-Events** — der Zustell-Lebenszyklus ist event-sourced (`@bimetal/alert-data`). Replay/Rehydrate/Sync stellen NIE erneut zu.
|
|
9
|
+
|
|
10
|
+
## Installation
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npm install @bimetal/alerting @bimetal/alert-data @bimetal/channel @bimetal/event-sourcing
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## What's Inside
|
|
17
|
+
|
|
18
|
+
### Pure Engine (keine Side-Effects)
|
|
19
|
+
|
|
20
|
+
- **`alertSpecsForEvent(event, rules, now, template?)`** — Domain-Event + Regeln → zu planende/sofortige `AlertSpec[]` (berechnet `triggerKey` + `fireAt`). `on_create/update/delete` = sofort; `before_start` = `subject.startMs - offsetMs`.
|
|
21
|
+
- **`dueScheduled(alerts, now)`** — reine Projektion: welche `scheduled`-Alerts sind fällig. Greift **nur** `scheduled` auf — `requested`/`failed`/`dispatched` werden von einem Tick nie re-gefeuert.
|
|
22
|
+
- **`triggerKeyFor(rule, subject)`** — injektiver Key `JSON.stringify([ruleId, subjectId, occurrence ?? null])`.
|
|
23
|
+
|
|
24
|
+
### Typen
|
|
25
|
+
|
|
26
|
+
- **`AlertRule`** — `{ id, trigger, on[], extract(event)→AlertSubject|null, offsetMs?, condition?, channel, recipient, template?|render? }`. Dedizierter Typ (nicht die rule-engine `Rule<Cmd,Ctx>` — die wertet ein Command, ein AlertRule ein Event).
|
|
27
|
+
- **`AlertSubject`** — `{ id, startMs?, occurrence?, data }`. **Subjekt-generisch** — der Kern importiert KEIN Kalender; eine Rule zieht das Subjekt via `extract` aus dem Event.
|
|
28
|
+
|
|
29
|
+
### Orchestrator (Host-verdrahtet)
|
|
30
|
+
|
|
31
|
+
- **`createAlertOrchestrator(options)`** → `{ ingest, tick, redeliver }`.
|
|
32
|
+
- `ingest(event)` — schedulet matchende Alerts, liefert sofort Fälliges (`on_create`).
|
|
33
|
+
- `tick(now?)` — requestet + liefert jeden fälligen `scheduled`-Alert.
|
|
34
|
+
- `redeliver(triggerKey)` — Host-Recovery für einen in `requested` gestrandeten Alert (**at-least-once Opt-in**: der Original-Send könnte geglückt sein).
|
|
35
|
+
|
|
36
|
+
## Garantien & Verträge
|
|
37
|
+
|
|
38
|
+
- **Exactly-once-Zustellung.** Der `channel.send` hängt am `RequestAlert→AlertRequested`-Übergang, der idempotent ist. Re-Ingest/Re-Tick senden nie erneut.
|
|
39
|
+
- **Single-Flight.** `ingest`/`tick`/`redeliver` sind serialisiert (`DomainStore.dispatch` ist optimistic-locked, aber NICHT serialisiert) — keine zwei eigenen Dispatches gleichzeitig in-flight; ein verlorenes Rennen wird gefangen (skip, kein Throw).
|
|
40
|
+
- **deliver-Atomizität.** Ein geglückter Send, dessen `markDispatched` ein Rennen verliert, wird NIE als `failed` protokolliert (bleibt `requested`, via `redeliver` recoverbar).
|
|
41
|
+
- **Secrets-by-construction.** Der persistierte `AlertFailed`-Grund wird aus dem validierten numerischen `ChannelHttpError.status` abgeleitet (`HTTP <status>`) — nie aus `error.message`/`.detail` (beschreibbar, potenziell Secret-tragend). Alles andere → fester Grund `"Channel send failed"`. Der volle Fehler geht nur an den **transienten** `onError`-Sink, nie in den replaybaren Log.
|
|
42
|
+
- **Crash-Window.** `AlertRequested` committet VOR `channel.send`; ein Crash dazwischen strandet den Alert in `requested` (kein Auto-Retry — Duplikat-Risiko). Recovery ist Host-Sache: `redeliver` (at-least-once) oder `markFailed` (at-most-once).
|
|
43
|
+
|
|
44
|
+
## Bewusst NICHT in v0.18
|
|
45
|
+
|
|
46
|
+
UI für Alert-Verwaltung, durabler Scheduler-Adapter, rule-engine-Fusion, echte Provider-e2e-Calls. Die Retry-Schleife (wann/wie oft re-requesten) ist Host/App-Sache — das Framework liefert `MarkFailed`/`attempts` + `redeliver`.
|
|
47
|
+
|
|
48
|
+
## License
|
|
49
|
+
|
|
50
|
+
PolyForm Noncommercial License 1.0.0
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"fileNames":["../../../../node_modules/typescript/lib/lib.es5.d.ts","../../../../node_modules/typescript/lib/lib.es2015.d.ts","../../../../node_modules/typescript/lib/lib.es2016.d.ts","../../../../node_modules/typescript/lib/lib.es2017.d.ts","../../../../node_modules/typescript/lib/lib.es2018.d.ts","../../../../node_modules/typescript/lib/lib.es2019.d.ts","../../../../node_modules/typescript/lib/lib.es2020.d.ts","../../../../node_modules/typescript/lib/lib.es2021.d.ts","../../../../node_modules/typescript/lib/lib.es2022.d.ts","../../../../node_modules/typescript/lib/lib.es2023.d.ts","../../../../node_modules/typescript/lib/lib.es2015.core.d.ts","../../../../node_modules/typescript/lib/lib.es2015.collection.d.ts","../../../../node_modules/typescript/lib/lib.es2015.generator.d.ts","../../../../node_modules/typescript/lib/lib.es2015.iterable.d.ts","../../../../node_modules/typescript/lib/lib.es2015.promise.d.ts","../../../../node_modules/typescript/lib/lib.es2015.proxy.d.ts","../../../../node_modules/typescript/lib/lib.es2015.reflect.d.ts","../../../../node_modules/typescript/lib/lib.es2015.symbol.d.ts","../../../../node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","../../../../node_modules/typescript/lib/lib.es2016.array.include.d.ts","../../../../node_modules/typescript/lib/lib.es2016.intl.d.ts","../../../../node_modules/typescript/lib/lib.es2017.arraybuffer.d.ts","../../../../node_modules/typescript/lib/lib.es2017.date.d.ts","../../../../node_modules/typescript/lib/lib.es2017.object.d.ts","../../../../node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","../../../../node_modules/typescript/lib/lib.es2017.string.d.ts","../../../../node_modules/typescript/lib/lib.es2017.intl.d.ts","../../../../node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","../../../../node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","../../../../node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","../../../../node_modules/typescript/lib/lib.es2018.intl.d.ts","../../../../node_modules/typescript/lib/lib.es2018.promise.d.ts","../../../../node_modules/typescript/lib/lib.es2018.regexp.d.ts","../../../../node_modules/typescript/lib/lib.es2019.array.d.ts","../../../../node_modules/typescript/lib/lib.es2019.object.d.ts","../../../../node_modules/typescript/lib/lib.es2019.string.d.ts","../../../../node_modules/typescript/lib/lib.es2019.symbol.d.ts","../../../../node_modules/typescript/lib/lib.es2019.intl.d.ts","../../../../node_modules/typescript/lib/lib.es2020.bigint.d.ts","../../../../node_modules/typescript/lib/lib.es2020.date.d.ts","../../../../node_modules/typescript/lib/lib.es2020.promise.d.ts","../../../../node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts","../../../../node_modules/typescript/lib/lib.es2020.string.d.ts","../../../../node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts","../../../../node_modules/typescript/lib/lib.es2020.intl.d.ts","../../../../node_modules/typescript/lib/lib.es2020.number.d.ts","../../../../node_modules/typescript/lib/lib.es2021.promise.d.ts","../../../../node_modules/typescript/lib/lib.es2021.string.d.ts","../../../../node_modules/typescript/lib/lib.es2021.weakref.d.ts","../../../../node_modules/typescript/lib/lib.es2021.intl.d.ts","../../../../node_modules/typescript/lib/lib.es2022.array.d.ts","../../../../node_modules/typescript/lib/lib.es2022.error.d.ts","../../../../node_modules/typescript/lib/lib.es2022.intl.d.ts","../../../../node_modules/typescript/lib/lib.es2022.object.d.ts","../../../../node_modules/typescript/lib/lib.es2022.string.d.ts","../../../../node_modules/typescript/lib/lib.es2022.regexp.d.ts","../../../../node_modules/typescript/lib/lib.es2023.array.d.ts","../../../../node_modules/typescript/lib/lib.es2023.collection.d.ts","../../../../node_modules/typescript/lib/lib.es2023.intl.d.ts","../../../../node_modules/typescript/lib/lib.esnext.disposable.d.ts","../../../../node_modules/typescript/lib/lib.esnext.float16.d.ts","../../../../node_modules/typescript/lib/lib.decorators.d.ts","../../../../node_modules/typescript/lib/lib.decorators.legacy.d.ts","../../../engine/event-sourcing/dist/types.d.ts","../../../engine/event-sourcing/dist/wrap-intent.d.ts","../../../engine/event-sourcing/dist/create-domain-store.d.ts","../../../engine/event-sourcing/dist/aggregate-helpers.d.ts","../../../engine/event-sourcing/dist/errors.d.ts","../../../engine/event-sourcing/dist/id.d.ts","../../../engine/event-sourcing/dist/validation.d.ts","../../../engine/event-sourcing/dist/diagnostics.d.ts","../../../engine/event-sourcing/dist/in-memory-store.d.ts","../../../engine/event-sourcing/dist/validate-envelopes.d.ts","../../../engine/event-sourcing/dist/event-bus.d.ts","../../../engine/event-sourcing/dist/topic.d.ts","../../../engine/event-sourcing/dist/broker-bridge.d.ts","../../../engine/event-sourcing/dist/in-memory-snapshot-store.d.ts","../../../engine/event-sourcing/dist/index.d.ts","../../../transport/channel/dist/types.d.ts","../../../transport/channel/dist/template.d.ts","../../../transport/channel/dist/http.d.ts","../../../transport/channel/dist/in-process-channel.d.ts","../../../transport/channel/dist/index.d.ts","../../alert-data/dist/types.d.ts","../../alert-data/dist/commands.d.ts","../../alert-data/dist/aggregate.d.ts","../../alert-data/dist/projection.d.ts","../../alert-data/dist/alert-fold.d.ts","../../alert-data/dist/store.d.ts","../../alert-data/dist/index.d.ts","../src/types.ts","../src/engine.ts","../src/orchestrator.ts","../src/index.ts","../../../../node_modules/@types/node/compatibility/iterators.d.ts","../../../../node_modules/@types/node/globals.typedarray.d.ts","../../../../node_modules/@types/node/buffer.buffer.d.ts","../../../../node_modules/@types/node/globals.d.ts","../../../../node_modules/@types/node/web-globals/abortcontroller.d.ts","../../../../node_modules/@types/node/web-globals/blob.d.ts","../../../../node_modules/@types/node/web-globals/console.d.ts","../../../../node_modules/@types/node/web-globals/crypto.d.ts","../../../../node_modules/@types/node/web-globals/domexception.d.ts","../../../../node_modules/@types/node/web-globals/encoding.d.ts","../../../../node_modules/@types/node/web-globals/events.d.ts","../../../../node_modules/undici-types/utility.d.ts","../../../../node_modules/undici-types/header.d.ts","../../../../node_modules/undici-types/readable.d.ts","../../../../node_modules/undici-types/fetch.d.ts","../../../../node_modules/undici-types/formdata.d.ts","../../../../node_modules/undici-types/connector.d.ts","../../../../node_modules/undici-types/client-stats.d.ts","../../../../node_modules/undici-types/client.d.ts","../../../../node_modules/undici-types/errors.d.ts","../../../../node_modules/undici-types/dispatcher.d.ts","../../../../node_modules/undici-types/global-dispatcher.d.ts","../../../../node_modules/undici-types/global-origin.d.ts","../../../../node_modules/undici-types/pool-stats.d.ts","../../../../node_modules/undici-types/pool.d.ts","../../../../node_modules/undici-types/handlers.d.ts","../../../../node_modules/undici-types/balanced-pool.d.ts","../../../../node_modules/undici-types/round-robin-pool.d.ts","../../../../node_modules/undici-types/h2c-client.d.ts","../../../../node_modules/undici-types/agent.d.ts","../../../../node_modules/undici-types/mock-interceptor.d.ts","../../../../node_modules/undici-types/mock-call-history.d.ts","../../../../node_modules/undici-types/mock-agent.d.ts","../../../../node_modules/undici-types/mock-client.d.ts","../../../../node_modules/undici-types/mock-pool.d.ts","../../../../node_modules/undici-types/snapshot-agent.d.ts","../../../../node_modules/undici-types/mock-errors.d.ts","../../../../node_modules/undici-types/proxy-agent.d.ts","../../../../node_modules/undici-types/socks5-proxy-agent.d.ts","../../../../node_modules/undici-types/env-http-proxy-agent.d.ts","../../../../node_modules/undici-types/retry-handler.d.ts","../../../../node_modules/undici-types/retry-agent.d.ts","../../../../node_modules/undici-types/api.d.ts","../../../../node_modules/undici-types/cache-interceptor.d.ts","../../../../node_modules/undici-types/interceptors.d.ts","../../../../node_modules/undici-types/util.d.ts","../../../../node_modules/undici-types/cookies.d.ts","../../../../node_modules/undici-types/patch.d.ts","../../../../node_modules/undici-types/websocket.d.ts","../../../../node_modules/undici-types/eventsource.d.ts","../../../../node_modules/undici-types/diagnostics-channel.d.ts","../../../../node_modules/undici-types/content-type.d.ts","../../../../node_modules/undici-types/cache.d.ts","../../../../node_modules/undici-types/index.d.ts","../../../../node_modules/@types/node/web-globals/fetch.d.ts","../../../../node_modules/@types/node/web-globals/importmeta.d.ts","../../../../node_modules/@types/node/web-globals/messaging.d.ts","../../../../node_modules/@types/node/web-globals/navigator.d.ts","../../../../node_modules/@types/node/web-globals/performance.d.ts","../../../../node_modules/@types/node/web-globals/storage.d.ts","../../../../node_modules/@types/node/web-globals/streams.d.ts","../../../../node_modules/@types/node/web-globals/timers.d.ts","../../../../node_modules/@types/node/web-globals/url.d.ts","../../../../node_modules/@types/node/assert.d.ts","../../../../node_modules/@types/node/assert/strict.d.ts","../../../../node_modules/@types/node/async_hooks.d.ts","../../../../node_modules/@types/node/buffer.d.ts","../../../../node_modules/@types/node/child_process.d.ts","../../../../node_modules/@types/node/cluster.d.ts","../../../../node_modules/@types/node/console.d.ts","../../../../node_modules/@types/node/constants.d.ts","../../../../node_modules/@types/node/crypto.d.ts","../../../../node_modules/@types/node/dgram.d.ts","../../../../node_modules/@types/node/diagnostics_channel.d.ts","../../../../node_modules/@types/node/dns.d.ts","../../../../node_modules/@types/node/dns/promises.d.ts","../../../../node_modules/@types/node/domain.d.ts","../../../../node_modules/@types/node/events.d.ts","../../../../node_modules/@types/node/fs.d.ts","../../../../node_modules/@types/node/fs/promises.d.ts","../../../../node_modules/@types/node/http.d.ts","../../../../node_modules/@types/node/http2.d.ts","../../../../node_modules/@types/node/https.d.ts","../../../../node_modules/@types/node/inspector.d.ts","../../../../node_modules/@types/node/inspector.generated.d.ts","../../../../node_modules/@types/node/inspector/promises.d.ts","../../../../node_modules/@types/node/module.d.ts","../../../../node_modules/@types/node/net.d.ts","../../../../node_modules/buffer/index.d.ts","../../../../node_modules/@types/node/os.d.ts","../../../../node_modules/@types/node/path.d.ts","../../../../node_modules/@types/node/path/posix.d.ts","../../../../node_modules/@types/node/path/win32.d.ts","../../../../node_modules/@types/node/perf_hooks.d.ts","../../../../node_modules/@types/node/process.d.ts","../../../../node_modules/@types/node/punycode.d.ts","../../../../node_modules/@types/node/querystring.d.ts","../../../../node_modules/@types/node/quic.d.ts","../../../../node_modules/@types/node/readline.d.ts","../../../../node_modules/@types/node/readline/promises.d.ts","../../../../node_modules/@types/node/repl.d.ts","../../../../node_modules/@types/node/sea.d.ts","../../../../node_modules/@types/node/sqlite.d.ts","../../../../node_modules/@types/node/stream.d.ts","../../../../node_modules/@types/node/stream/consumers.d.ts","../../../../node_modules/@types/node/stream/promises.d.ts","../../../../node_modules/@types/node/stream/web.d.ts","../../../../node_modules/@types/node/string_decoder.d.ts","../../../../node_modules/@types/node/test.d.ts","../../../../node_modules/@types/node/test/reporters.d.ts","../../../../node_modules/@types/node/timers.d.ts","../../../../node_modules/@types/node/timers/promises.d.ts","../../../../node_modules/@types/node/tls.d.ts","../../../../node_modules/@types/node/trace_events.d.ts","../../../../node_modules/@types/node/tty.d.ts","../../../../node_modules/@types/node/url.d.ts","../../../../node_modules/@types/node/util.d.ts","../../../../node_modules/@types/node/util/types.d.ts","../../../../node_modules/@types/node/v8.d.ts","../../../../node_modules/@types/node/vm.d.ts","../../../../node_modules/@types/node/wasi.d.ts","../../../../node_modules/@types/node/worker_threads.d.ts","../../../../node_modules/@types/node/zlib.d.ts","../../../../node_modules/@types/node/index.d.ts","../../../../node_modules/@types/amqplib/properties.d.ts","../../../../node_modules/@types/amqplib/index.d.ts","../../../../node_modules/@types/aria-query/index.d.ts","../../../../node_modules/@babel/types/lib/index.d.ts","../../../../node_modules/@types/babel__generator/index.d.ts","../../../../node_modules/@babel/parser/typings/babel-parser.d.ts","../../../../node_modules/@types/babel__template/index.d.ts","../../../../node_modules/@types/babel__traverse/index.d.ts","../../../../node_modules/@types/babel__core/index.d.ts","../../../../node_modules/@types/better-sqlite3/index.d.ts","../../../../node_modules/@types/connect/index.d.ts","../../../../node_modules/@types/body-parser/index.d.ts","../../../../node_modules/@types/deep-eql/index.d.ts","../../../../node_modules/assertion-error/index.d.ts","../../../../node_modules/@types/chai/index.d.ts","../../../../node_modules/@types/ms/index.d.ts","../../../../node_modules/@types/debug/index.d.ts","../../../../node_modules/@types/estree/index.d.ts","../../../../node_modules/@types/estree-jsx/index.d.ts","../../../../node_modules/@types/send/index.d.ts","../../../../node_modules/@types/qs/index.d.ts","../../../../node_modules/@types/range-parser/index.d.ts","../../../../node_modules/@types/express-serve-static-core/index.d.ts","../../../../node_modules/@types/http-errors/index.d.ts","../../../../node_modules/@types/serve-static/index.d.ts","../../../../node_modules/@types/express/index.d.ts","../../../../node_modules/@types/google-protobuf/index.d.ts","../../../../node_modules/@types/unist/index.d.ts","../../../../node_modules/@types/hast/index.d.ts","../../../../node_modules/@types/mdast/index.d.ts","../../../../node_modules/@types/react/global.d.ts","../../../../node_modules/csstype/index.d.ts","../../../../node_modules/@types/react/index.d.ts","../../../../node_modules/@types/react-dom/index.d.ts","../../../../node_modules/@types/trusted-types/lib/index.d.ts","../../../../node_modules/@types/trusted-types/index.d.ts","../../../../node_modules/@types/whatwg-mimetype/index.d.ts","../../../../node_modules/@types/ws/index.d.ts"],"fileIdsList":[[97,161,169,173,176,178,179,180,193,222],[97,161,169,173,176,178,179,180,193],[97,161,169,172,173,176,178,179,180,193,218,219],[97,161,169,173,176,178,179,180,193,222,223,224,225,226],[97,161,169,173,176,178,179,180,193,222,224],[97,161,169,173,176,178,179,180,193,218],[97,161,169,173,175,176,178,179,180,193,218,229],[97,161,169,173,176,178,179,180,193,231,232],[97,161,169,173,175,176,178,179,180,193,218],[97,161,169,173,176,178,179,180,193,234],[97,161,169,173,176,178,179,180,193,236,237],[97,161,169,172,173,175,176,178,179,180,193,218,238,239,240],[97,161,169,173,176,178,179,180,193,230,241,243],[97,161,169,173,176,178,179,180,193,246],[97,158,159,161,169,173,176,178,179,180,193],[97,160,161,169,173,176,178,179,180,193],[161,169,173,176,178,179,180,193],[97,161,169,173,176,178,179,180,193,201],[97,161,162,167,169,172,173,176,178,179,180,182,193,198,210],[97,161,162,163,169,172,173,176,178,179,180,193],[97,161,164,169,173,176,178,179,180,193,211],[97,161,165,166,169,173,176,178,179,180,184,193],[97,161,166,169,173,176,178,179,180,193,198,207],[97,161,167,169,172,173,176,178,179,180,182,193],[97,160,161,168,169,173,176,178,179,180,193],[97,161,169,170,173,176,178,179,180,193],[97,161,169,171,172,173,176,178,179,180,193],[97,160,161,169,172,173,176,178,179,180,193],[97,161,169,172,173,174,176,178,179,180,193,198,210],[97,161,169,172,173,174,176,178,179,180,193,198,201],[97,148,161,169,172,173,175,176,178,179,180,182,193,198,210],[97,161,169,172,173,175,176,178,179,180,182,193,198,207,210],[97,161,169,173,175,176,177,178,179,180,193,198,207,210],[95,96,97,98,99,100,101,102,103,104,105,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217],[97,161,169,172,173,176,178,179,180,193],[97,161,169,173,176,178,180,193],[97,161,169,173,176,178,179,180,181,193,210],[97,161,169,172,173,176,178,179,180,182,193,198],[97,161,169,173,176,178,179,180,184,193],[97,161,169,173,176,178,179,180,185,193],[97,161,169,172,173,176,178,179,180,188,193],[97,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217],[97,161,169,173,176,178,179,180,190,193],[97,161,169,173,176,178,179,180,191,193],[97,161,166,169,173,176,178,179,180,182,193,201],[97,161,169,172,173,176,178,179,180,193,194],[97,161,169,173,176,178,179,180,193,195,211,214],[97,161,169,172,173,176,178,179,180,193,198,200,201],[97,161,169,173,176,178,179,180,193,199,201],[97,161,169,173,176,178,179,180,193,201,211],[97,161,169,173,176,178,179,180,193,202],[97,158,161,169,173,176,178,179,180,193,198,204,210],[97,161,169,173,176,178,179,180,193,198,203],[97,161,169,172,173,176,178,179,180,193,205,206],[97,161,169,173,176,178,179,180,193,205,206],[97,161,166,169,173,176,178,179,180,182,193,198,207],[97,161,169,173,176,178,179,180,193,208],[97,161,169,173,176,178,179,180,182,193,209],[97,161,169,173,175,176,178,179,180,191,193,210],[97,161,169,173,176,178,179,180,193,211,212],[97,161,166,169,173,176,178,179,180,193,212],[97,161,169,173,176,178,179,180,193,198,213],[97,161,169,173,176,178,179,180,181,193,214],[97,161,169,173,176,178,179,180,193,215],[97,161,164,169,173,176,178,179,180,193],[97,161,166,169,173,176,178,179,180,193],[97,161,169,173,176,178,179,180,193,211],[97,148,161,169,173,176,178,179,180,193],[97,161,169,173,176,178,179,180,193,210],[97,161,169,173,176,178,179,180,193,216],[97,161,169,173,176,178,179,180,188,193],[97,161,169,173,176,178,179,180,193,206],[97,148,161,169,172,173,174,176,178,179,180,188,193,198,201,210,213,214,216],[97,161,169,173,176,178,179,180,193,198,217],[97,161,169,173,176,178,179,180,193,251],[97,161,169,173,176,178,179,180,193,249,250],[97,161,169,173,176,178,179,180,193,198,218],[97,161,169,173,175,176,178,179,180,193,218,242],[97,161,169,173,176,178,179,180,193,253],[97,161,169,172,173,175,176,177,178,179,180,182,193,198,207,210,217,218],[97,112,115,118,119,161,169,173,176,178,179,180,193,210],[97,115,161,169,173,176,178,179,180,193,198,210],[97,115,119,161,169,173,176,178,179,180,193,210],[97,161,169,173,176,178,179,180,193,198],[97,109,161,169,173,176,178,179,180,193],[97,113,161,169,173,176,178,179,180,193],[97,111,112,115,161,169,173,176,178,179,180,193,210],[97,161,169,173,176,178,179,180,182,193,207],[97,109,161,169,173,176,178,179,180,193,218],[97,111,115,161,169,173,176,178,179,180,182,193,210],[97,106,107,108,110,114,161,169,172,173,176,178,179,180,193,198,210],[97,115,124,132,161,169,173,176,178,179,180,193],[97,107,113,161,169,173,176,178,179,180,193],[97,115,142,143,161,169,173,176,178,179,180,193],[97,107,110,115,161,169,173,176,178,179,180,193,201,210,218],[97,115,161,169,173,176,178,179,180,193],[97,111,115,161,169,173,176,178,179,180,193,210],[97,106,161,169,173,176,178,179,180,193],[97,109,110,111,113,114,115,116,117,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,143,144,145,146,147,161,169,173,176,178,179,180,193],[97,115,135,138,161,169,173,176,178,179,180,193],[97,115,124,125,126,161,169,173,176,178,179,180,193],[97,113,115,125,127,161,169,173,176,178,179,180,193],[97,114,161,169,173,176,178,179,180,193],[97,107,109,115,161,169,173,176,178,179,180,193],[97,115,119,125,127,161,169,173,176,178,179,180,193],[97,119,161,169,173,176,178,179,180,193],[97,113,115,118,161,169,173,176,178,179,180,193,210],[97,107,111,115,124,161,169,173,176,178,179,180,193],[97,115,135,161,169,173,176,178,179,180,193],[97,127,161,169,173,176,178,179,180,193],[97,107,111,115,119,161,169,173,176,178,179,180,193],[97,109,115,142,161,169,173,176,178,179,180,193,201,216,218],[78,84,97,161,169,173,176,178,179,180,193],[84,97,161,169,173,176,178,179,180,193],[84,85,86,87,88,89,97,161,169,173,176,178,179,180,193],[78,97,161,169,173,176,178,179,180,193],[78,83,90,91,97,161,169,173,176,178,179,180,193],[91,92,93,97,161,169,173,176,178,179,180,193],[78,83,90,91,92,97,161,169,173,176,178,179,180,193],[78,83,90,97,161,169,173,176,178,179,180,193],[64,97,161,169,173,176,178,179,180,193],[64,71,97,161,169,173,176,178,179,180,193],[64,65,66,67,68,69,70,71,72,73,74,75,76,77,97,161,169,173,176,178,179,180,193],[79,97,161,169,173,176,178,179,180,193],[79,80,81,82,97,161,169,173,176,178,179,180,193]],"fileInfos":[{"version":"69684132aeb9b5642cbcd9e22dff7818ff0ee1aa831728af0ecf97d3364d5546","affectsGlobalScope":true,"impliedFormat":1},{"version":"45b7ab580deca34ae9729e97c13cfd999df04416a79116c3bfb483804f85ded4","impliedFormat":1},{"version":"3facaf05f0c5fc569c5649dd359892c98a85557e3e0c847964caeb67076f4d75","impliedFormat":1},{"version":"e44bb8bbac7f10ecc786703fe0a6a4b952189f908707980ba8f3c8975a760962","impliedFormat":1},{"version":"5e1c4c362065a6b95ff952c0eab010f04dcd2c3494e813b493ecfd4fcb9fc0d8","impliedFormat":1},{"version":"68d73b4a11549f9c0b7d352d10e91e5dca8faa3322bfb77b661839c42b1ddec7","impliedFormat":1},{"version":"5efce4fc3c29ea84e8928f97adec086e3dc876365e0982cc8479a07954a3efd4","impliedFormat":1},{"version":"feecb1be483ed332fad555aff858affd90a48ab19ba7272ee084704eb7167569","impliedFormat":1},{"version":"ee7bad0c15b58988daa84371e0b89d313b762ab83cb5b31b8a2d1162e8eb41c2","impliedFormat":1},{"version":"27bdc30a0e32783366a5abeda841bc22757c1797de8681bbe81fbc735eeb1c10","impliedFormat":1},{"version":"c57796738e7f83dbc4b8e65132f11a377649c00dd3eee333f672b8f0a6bea671","affectsGlobalScope":true,"impliedFormat":1},{"version":"dc2df20b1bcdc8c2d34af4926e2c3ab15ffe1160a63e58b7e09833f616efff44","affectsGlobalScope":true,"impliedFormat":1},{"version":"515d0b7b9bea2e31ea4ec968e9edd2c39d3eebf4a2d5cbd04e88639819ae3b71","affectsGlobalScope":true,"impliedFormat":1},{"version":"0559b1f683ac7505ae451f9a96ce4c3c92bdc71411651ca6ddb0e88baaaad6a3","affectsGlobalScope":true,"impliedFormat":1},{"version":"0dc1e7ceda9b8b9b455c3a2d67b0412feab00bd2f66656cd8850e8831b08b537","affectsGlobalScope":true,"impliedFormat":1},{"version":"ce691fb9e5c64efb9547083e4a34091bcbe5bdb41027e310ebba8f7d96a98671","affectsGlobalScope":true,"impliedFormat":1},{"version":"8d697a2a929a5fcb38b7a65594020fcef05ec1630804a33748829c5ff53640d0","affectsGlobalScope":true,"impliedFormat":1},{"version":"4ff2a353abf8a80ee399af572debb8faab2d33ad38c4b4474cff7f26e7653b8d","affectsGlobalScope":true,"impliedFormat":1},{"version":"936e80ad36a2ee83fc3caf008e7c4c5afe45b3cf3d5c24408f039c1d47bdc1df","affectsGlobalScope":true,"impliedFormat":1},{"version":"d15bea3d62cbbdb9797079416b8ac375ae99162a7fba5de2c6c505446486ac0a","affectsGlobalScope":true,"impliedFormat":1},{"version":"68d18b664c9d32a7336a70235958b8997ebc1c3b8505f4f1ae2b7e7753b87618","affectsGlobalScope":true,"impliedFormat":1},{"version":"eb3d66c8327153d8fa7dd03f9c58d351107fe824c79e9b56b462935176cdf12a","affectsGlobalScope":true,"impliedFormat":1},{"version":"38f0219c9e23c915ef9790ab1d680440d95419ad264816fa15009a8851e79119","affectsGlobalScope":true,"impliedFormat":1},{"version":"69ab18c3b76cd9b1be3d188eaf8bba06112ebbe2f47f6c322b5105a6fbc45a2e","affectsGlobalScope":true,"impliedFormat":1},{"version":"fef8cfad2e2dc5f5b3d97a6f4f2e92848eb1b88e897bb7318cef0e2820bceaab","affectsGlobalScope":true,"impliedFormat":1},{"version":"2f11ff796926e0832f9ae148008138ad583bd181899ab7dd768a2666700b1893","affectsGlobalScope":true,"impliedFormat":1},{"version":"4de680d5bb41c17f7f68e0419412ca23c98d5749dcaaea1896172f06435891fc","affectsGlobalScope":true,"impliedFormat":1},{"version":"954296b30da6d508a104a3a0b5d96b76495c709785c1d11610908e63481ee667","affectsGlobalScope":true,"impliedFormat":1},{"version":"ac9538681b19688c8eae65811b329d3744af679e0bdfa5d842d0e32524c73e1c","affectsGlobalScope":true,"impliedFormat":1},{"version":"0a969edff4bd52585473d24995c5ef223f6652d6ef46193309b3921d65dd4376","affectsGlobalScope":true,"impliedFormat":1},{"version":"9e9fbd7030c440b33d021da145d3232984c8bb7916f277e8ffd3dc2e3eae2bdb","affectsGlobalScope":true,"impliedFormat":1},{"version":"811ec78f7fefcabbda4bfa93b3eb67d9ae166ef95f9bff989d964061cbf81a0c","affectsGlobalScope":true,"impliedFormat":1},{"version":"717937616a17072082152a2ef351cb51f98802fb4b2fdabd32399843875974ca","affectsGlobalScope":true,"impliedFormat":1},{"version":"d7e7d9b7b50e5f22c915b525acc5a49a7a6584cf8f62d0569e557c5cfc4b2ac2","affectsGlobalScope":true,"impliedFormat":1},{"version":"71c37f4c9543f31dfced6c7840e068c5a5aacb7b89111a4364b1d5276b852557","affectsGlobalScope":true,"impliedFormat":1},{"version":"576711e016cf4f1804676043e6a0a5414252560eb57de9faceee34d79798c850","affectsGlobalScope":true,"impliedFormat":1},{"version":"89c1b1281ba7b8a96efc676b11b264de7a8374c5ea1e6617f11880a13fc56dc6","affectsGlobalScope":true,"impliedFormat":1},{"version":"74f7fa2d027d5b33eb0471c8e82a6c87216223181ec31247c357a3e8e2fddc5b","affectsGlobalScope":true,"impliedFormat":1},{"version":"d6d7ae4d1f1f3772e2a3cde568ed08991a8ae34a080ff1151af28b7f798e22ca","affectsGlobalScope":true,"impliedFormat":1},{"version":"063600664504610fe3e99b717a1223f8b1900087fab0b4cad1496a114744f8df","affectsGlobalScope":true,"impliedFormat":1},{"version":"934019d7e3c81950f9a8426d093458b65d5aff2c7c1511233c0fd5b941e608ab","affectsGlobalScope":true,"impliedFormat":1},{"version":"52ada8e0b6e0482b728070b7639ee42e83a9b1c22d205992756fe020fd9f4a47","affectsGlobalScope":true,"impliedFormat":1},{"version":"3bdefe1bfd4d6dee0e26f928f93ccc128f1b64d5d501ff4a8cf3c6371200e5e6","affectsGlobalScope":true,"impliedFormat":1},{"version":"59fb2c069260b4ba00b5643b907ef5d5341b167e7d1dbf58dfd895658bda2867","affectsGlobalScope":true,"impliedFormat":1},{"version":"639e512c0dfc3fad96a84caad71b8834d66329a1f28dc95e3946c9b58176c73a","affectsGlobalScope":true,"impliedFormat":1},{"version":"368af93f74c9c932edd84c58883e736c9e3d53cec1fe24c0b0ff451f529ceab1","affectsGlobalScope":true,"impliedFormat":1},{"version":"af3dd424cf267428f30ccfc376f47a2c0114546b55c44d8c0f1d57d841e28d74","affectsGlobalScope":true,"impliedFormat":1},{"version":"995c005ab91a498455ea8dfb63aa9f83fa2ea793c3d8aa344be4a1678d06d399","affectsGlobalScope":true,"impliedFormat":1},{"version":"959d36cddf5e7d572a65045b876f2956c973a586da58e5d26cde519184fd9b8a","affectsGlobalScope":true,"impliedFormat":1},{"version":"965f36eae237dd74e6cca203a43e9ca801ce38824ead814728a2807b1910117d","affectsGlobalScope":true,"impliedFormat":1},{"version":"3925a6c820dcb1a06506c90b1577db1fdbf7705d65b62b99dce4be75c637e26b","affectsGlobalScope":true,"impliedFormat":1},{"version":"0a3d63ef2b853447ec4f749d3f368ce642264246e02911fcb1590d8c161b8005","affectsGlobalScope":true,"impliedFormat":1},{"version":"b5ce7a470bc3628408429040c4e3a53a27755022a32fd05e2cb694e7015386c7","affectsGlobalScope":true,"impliedFormat":1},{"version":"8444af78980e3b20b49324f4a16ba35024fef3ee069a0eb67616ea6ca821c47a","affectsGlobalScope":true,"impliedFormat":1},{"version":"3287d9d085fbd618c3971944b65b4be57859f5415f495b33a6adc994edd2f004","affectsGlobalScope":true,"impliedFormat":1},{"version":"b4b67b1a91182421f5df999988c690f14d813b9850b40acd06ed44691f6727ad","affectsGlobalScope":true,"impliedFormat":1},{"version":"df83c2a6c73228b625b0beb6669c7ee2a09c914637e2d35170723ad49c0f5cd4","affectsGlobalScope":true,"impliedFormat":1},{"version":"436aaf437562f276ec2ddbee2f2cdedac7664c1e4c1d2c36839ddd582eeb3d0a","affectsGlobalScope":true,"impliedFormat":1},{"version":"8e3c06ea092138bf9fa5e874a1fdbc9d54805d074bee1de31b99a11e2fec239d","affectsGlobalScope":true,"impliedFormat":1},{"version":"51ad4c928303041605b4d7ae32e0c1ee387d43a24cd6f1ebf4a2699e1076d4fa","affectsGlobalScope":true,"impliedFormat":1},{"version":"4245fee526a7d1754529d19227ecbf3be066ff79ebb6a380d78e41648f2f224d","affectsGlobalScope":true,"impliedFormat":1},{"version":"8e7f8264d0fb4c5339605a15daadb037bf238c10b654bb3eee14208f860a32ea","affectsGlobalScope":true,"impliedFormat":1},{"version":"782dec38049b92d4e85c1585fbea5474a219c6984a35b004963b00beb1aab538","affectsGlobalScope":true,"impliedFormat":1},"24c28fc1ded093cd96e5cbcba59787e07f47b7f0fd666d6a579464292bf35fa0","98e32045a66fc1149ec1376399c67f0695df6a7521cefa601cdf268824148dbf","239b6e23f278cca9421ea7e76dc69813603ee9ca74257446b4ada2a536bb0513","71dbc598080174b9bffbf6296bd410a5e20359fab4fada0c9fc7e457d025b57c","eedcb9d5cb4359a781662caed3fe1f272c0837d9d6f6e4be5dc5f47891d232ec","acb314e7ae9f9f2dd28ef4f0f1d916e8ad65a01521235b925111046edebbc45d","52f90291f47d74a00a30007fcdea55ddee4c9b9bb71f9225eb11de834bcfcfd1","df8bca724310793c45b8e6df8d77744b55a5986fd2dceb74bbfb2361890eed61","b178d3182f441bedf19f95be51e48cf68243cabf2629c90e3ebfcd084110de18","23a0f5bf62c18f6c534e09ade0109d26491a00d2ce90c3f09dbe6d1fca05a334","91a9e7fe477539623392444a3d866e27ff0ed28cf220026ac4c7ca169007fae0","1795a3dd93df189f4f60b4052ef2c26fdfc631984712f5a49e9fffabf5b925fe","8d1852dc8f23b7e6900704a99ef67750adb37ba526876fbb66f2abbfd95bc46e","68c6bba43ac9b6477d7843d770ae1d14ac495f52ae6d9f1f99cf44024623804c","970a2da64f680eb2ac07ae927405104541c6428c2aa2be6451c76ac37530dad2","dbca78bb210033c36423269dbf7c7e9319aea3f41f4877ac7468993192c10138","6b46970b568f719d791bda0553dddb5d5b4722249532f9d43446295d0a8f0fbf","e9e1d0e3288ff918dfdb7c7a1ee84c57c596efc1f165be011c75e36ba35c0d55","03f21b67c192ed193692b4ff9acb6209be68b814624ed30e03716dd6f1aee301","497fe7f2451817e9545ceff6c4fb3d6bcce9929853801ef34c301f62b3626963","c27f93f790f1d5e6fb107553ab309a4aa5c37ca4299c804b9c50e2822e95b94d","d6f0a0a4b18b37ad170f2992deccd63a70a36904a2c42b861c819491e74ac31f","94e49fab2355cf7f5bd9487b60b0bc39facf4eea9d09bf59ee9c4a5a6036e4e0","f1318af916590340f9a6b83fd5491918d9ed6bc78415ec4d76a2ac4b212521ce","70ef73b059feb613a84413b5aa0c6de55a8454b245ff1d9ef1471d796bb8ab39","d90b0cca8344959d70c979b33994499ce69a60d7327ba5931810d565f9bd3ab9","0871ce596caa93fcc05c46cc0f605a90701d1f0fa9585e241369ffa2d676aeb2",{"version":"ce03447d6c0b65fc7802cdf45328a83b211d372de43ad05fdf18bd1e61fadb97","signature":"6d41128a92a9781c81c498d28b6ea8dc1391f5057adbc48f8019605f392be58e"},{"version":"08d5c9f0f151e7ce0409fa1dbd503d51e21b6275d6f1ec104e3cff186dd46054","signature":"eea117019bc88621ca39fb5d7e2a101bef90552b6abc8e14c191c7295e0b42a2"},{"version":"a57e33d9c0e7b8f86edfe5f9e270bf2e2e238c4d249e48330f386ac7d71098c5","signature":"18995f2fcdac2559d5fd79febef25f9ad7b366a9f8382e8cc092b616b6e9cb09"},{"version":"eeb7f111d366c06f8c75938f521b83c173bc0599e90b3d3f19a4c3220890f0bb","signature":"7e1bd1898617e35b09d63ddfd895f2290e3e8f88b023b08e339fd7fbb58b625b"},{"version":"d153a11543fd884b596587ccd97aebbeed950b26933ee000f94009f1ab142848","affectsGlobalScope":true,"impliedFormat":1},{"version":"0ccdaa19852d25ecd84eec365c3bfa16e7859cadecf6e9ca6d0dbbbee439743f","affectsGlobalScope":true,"impliedFormat":1},{"version":"cc2110f7decca6bfb9392e30421cfa1436479e4a6756e8fec6cbc22625d4f881","affectsGlobalScope":true,"impliedFormat":1},{"version":"096116f8fedc1765d5bd6ef360c257b4a9048e5415054b3bf3c41b07f8951b0b","affectsGlobalScope":true,"impliedFormat":1},{"version":"e5e01375c9e124a83b52ee4b3244ed1a4d214a6cfb54ac73e164a823a4a7860a","affectsGlobalScope":true,"impliedFormat":1},{"version":"f90ae2bbce1505e67f2f6502392e318f5714bae82d2d969185c4a6cecc8af2fc","affectsGlobalScope":true,"impliedFormat":1},{"version":"4b58e207b93a8f1c88bbf2a95ddc686ac83962b13830fe8ad3f404ffc7051fb4","affectsGlobalScope":true,"impliedFormat":1},{"version":"1fefabcb2b06736a66d2904074d56268753654805e829989a46a0161cd8412c5","affectsGlobalScope":true,"impliedFormat":1},{"version":"9798340ffb0d067d69b1ae5b32faa17ab31b82466a3fc00d8f2f2df0c8554aaa","affectsGlobalScope":true,"impliedFormat":1},{"version":"c18a99f01eb788d849ad032b31cafd49de0b19e083fe775370834c5675d7df8e","affectsGlobalScope":true,"impliedFormat":1},{"version":"5247874c2a23b9a62d178ae84f2db6a1d54e6c9a2e7e057e178cc5eea13757fc","affectsGlobalScope":true,"impliedFormat":1},{"version":"cdcf9ea426ad970f96ac930cd176d5c69c6c24eebd9fc580e1572d6c6a88f62c","impliedFormat":1},{"version":"23cd712e2ce083d68afe69224587438e5914b457b8acf87073c22494d706a3d0","impliedFormat":1},{"version":"156a859e21ef3244d13afeeba4e49760a6afa035c149dda52f0c45ea8903b338","impliedFormat":1},{"version":"10ec5e82144dfac6f04fa5d1d6c11763b3e4dbbac6d99101427219ab3e2ae887","impliedFormat":1},{"version":"615754924717c0b1e293e083b83503c0a872717ad5aa60ed7f1a699eb1b4ea5c","impliedFormat":1},{"version":"14e9acf826baba0ef4b5665704084896e7bcc06f65a9ab13af7e93d27d6b7069","impliedFormat":1},{"version":"68834d631c8838c715f225509cfc3927913b9cc7a4870460b5b60c8dbdb99baf","impliedFormat":1},{"version":"21adf13435b9b748529c8cedf80f884e5130b9684188120a686cd2b26a2059c7","impliedFormat":1},{"version":"eec76bf6b9346f3f95fa402621b889489e96930e72295b0369022f332e9b4a6a","impliedFormat":1},{"version":"0ecd58f413f9bc3b7d4383eae31b0c8fc576985cd7404d6f99f8c643543ade74","impliedFormat":1},{"version":"ea6bc8de8b59f90a7a3960005fd01988f98fd0784e14bc6922dde2e93305ec7d","impliedFormat":1},{"version":"36107995674b29284a115e21a0618c4c2751b32a8766dd4cb3ba740308b16d59","impliedFormat":1},{"version":"914a0ae30d96d71915fc519ccb4efbf2b62c0ddfb3a3fc6129151076bc01dc60","impliedFormat":1},{"version":"9c32412007b5662fd34a8eb04292fb5314ec370d7016d1c2fb8aa193c807fe22","impliedFormat":1},{"version":"7fd1b31fd35876b0aa650811c25ec2c97a3c6387e5473eb18004bed86cdd76b6","impliedFormat":1},{"version":"4d327f7d72ad0918275cea3eee49a6a8dc8114ae1d5b7f3f5d0774de75f7439a","impliedFormat":1},{"version":"6ebe8ebb8659aaa9d1acbf3710d7dae3e923e97610238b9511c25dc39023a166","impliedFormat":1},{"version":"e85d7f8068f6a26710bff0cc8c0fc5e47f71089c3780fbede05857331d2ddec9","impliedFormat":1},{"version":"7befaf0e76b5671be1d47b77fcc65f2b0aad91cc26529df1904f4a7c46d216e9","impliedFormat":1},{"version":"0a60a292b89ca7218b8616f78e5bbd1c96b87e048849469cccb4355e98af959a","impliedFormat":1},{"version":"0b6e25234b4eec6ed96ab138d96eb70b135690d7dd01f3dd8a8ab291c35a683a","impliedFormat":1},{"version":"9666f2f84b985b62400d2e5ab0adae9ff44de9b2a34803c2c5bd3c8325b17dc0","impliedFormat":1},{"version":"40cd35c95e9cf22cfa5bd84e96408b6fcbca55295f4ff822390abb11afbc3dca","impliedFormat":1},{"version":"b1616b8959bf557feb16369c6124a97a0e74ed6f49d1df73bb4b9ddf68acf3f3","impliedFormat":1},{"version":"5b03a034c72146b61573aab280f295b015b9168470f2df05f6080a2122f9b4df","impliedFormat":1},{"version":"40b463c6766ca1b689bfcc46d26b5e295954f32ad43e37ee6953c0a677e4ae2b","impliedFormat":1},{"version":"249b9cab7f5d628b71308c7d9bb0a808b50b091e640ba3ed6e2d0516f4a8d91d","impliedFormat":1},{"version":"d33ce35e3f9cfcc1d94eca415bdd3bde94d5b153ffdd33e6c4455c029986c630","impliedFormat":1},{"version":"80aae6afc67faa5ac0b32b5b8bc8cc9f7fa299cff15cf09cc2e11fd28c6ae29e","impliedFormat":1},{"version":"f473cd2288991ff3221165dcf73cd5d24da30391f87e85b3dd4d0450c787a391","impliedFormat":1},{"version":"499e5b055a5aba1e1998f7311a6c441a369831c70905cc565ceac93c28083d53","impliedFormat":1},{"version":"8aee8b6d4f9f62cf3776cda1305fb18763e2aade7e13cea5bbe699112df85214","impliedFormat":1},{"version":"98498b101803bb3dde9f76a56e65c14b75db1cc8bec5f4db72be541570f74fc5","impliedFormat":1},{"version":"4dc59f6e1dbf3d5f66660fceabe6c174d3261b37b696ae1854f0dbaf255fc753","impliedFormat":1},{"version":"5d0375ca7310efb77e3ef18d068d53784faf62705e0ad04569597ae0e755c401","impliedFormat":1},{"version":"59af37caec41ecf7b2e76059c9672a49e682c1a2aa6f9d7dc78878f53aa284d6","impliedFormat":1},{"version":"addf417b9eb3f938fddf8d81e96393a165e4be0d4a8b6402292f9c634b1cb00d","impliedFormat":1},{"version":"436d7b4543b340b0f3eef4310d524242e41369b9652aa9c70428767c4dcac455","impliedFormat":1},{"version":"adf27937dba6af9f08a68c5b1d3fce0ca7d4b960c57e6d6c844e7d1a8e53adae","impliedFormat":1},{"version":"12950411eeab8563b349cb7959543d92d8d02c289ed893d78499a19becb5a8cc","impliedFormat":1},{"version":"2e85db9e6fd73cfa3d7f28e0ab6b55417ea18931423bd47b409a96e4a169e8e6","impliedFormat":1},{"version":"c46e079fe54c76f95c67fb89081b3e399da2c7d109e7dca8e4b58d83e332e605","impliedFormat":1},{"version":"114f493b30f364255290472111b5a4791d5902c308645670cd0401429cbc6930","impliedFormat":1},{"version":"c3f5289820990ab66b70c7fb5b63cb674001009ff84b13de40619619a9c8175f","affectsGlobalScope":true,"impliedFormat":1},{"version":"b3275d55fac10b799c9546804126239baf020d220136163f763b55a74e50e750","affectsGlobalScope":true,"impliedFormat":1},{"version":"fa68a0a3b7cb32c00e39ee3cd31f8f15b80cac97dce51b6ee7fc14a1e8deb30b","affectsGlobalScope":true,"impliedFormat":1},{"version":"1cf059eaf468efcc649f8cf6075d3cb98e9a35a0fe9c44419ec3d2f5428d7123","affectsGlobalScope":true,"impliedFormat":1},{"version":"6c36e755bced82df7fb6ce8169265d0a7bb046ab4e2cb6d0da0cb72b22033e89","affectsGlobalScope":true,"impliedFormat":1},{"version":"e7721c4f69f93c91360c26a0a84ee885997d748237ef78ef665b153e622b36c1","affectsGlobalScope":true,"impliedFormat":1},{"version":"7a93de4ff8a63bafe62ba86b89af1df0ccb5e40bb85b0c67d6bbcfdcf96bf3d4","affectsGlobalScope":true,"impliedFormat":1},{"version":"90e85f9bc549dfe2b5749b45fe734144e96cd5d04b38eae244028794e142a77e","affectsGlobalScope":true,"impliedFormat":1},{"version":"e0a5deeb610b2a50a6350bd23df6490036a1773a8a71d70f2f9549ab009e67ee","affectsGlobalScope":true,"impliedFormat":1},{"version":"d2ae155afe8a01cc0ae612d99117cf8ef16692ba7c4366590156fdec1bcf2d8c","impliedFormat":1},{"version":"3f5e5d9be35913db9fea42a63f3df0b7e3c8703b97670a2125587b4dbbd56d7c","impliedFormat":1},{"version":"8caeb65fdc3bfe0d13f86f67324fcb2d858ed1c55f1f0cce892eb1acfb9f3239","impliedFormat":1},{"version":"57c23df0b5f7a8e26363a3849b0bc7763f6b241207157c8e40089d1df4116f35","affectsGlobalScope":true,"impliedFormat":1},{"version":"3b8bc0c17b54081b0878673989216229e575d67a10874e84566a21025a2461ee","impliedFormat":1},{"version":"5b0db5a58b73498792a29bfebc333438e61906fef75da898b410e24e52229e6f","impliedFormat":1},{"version":"dbe055b2b29a7bab2c1ca8f259436306adb43f469dca7e639a02cd3695d3f621","impliedFormat":1},{"version":"1678b04557dca52feab73cc67610918a7f5e25bfdba3e7fa081acd625d93106d","impliedFormat":1},{"version":"e3905f6902f0b69e5eefc230daa69fdd4ab707a973ec2d086d65af1b3ea47ef0","impliedFormat":1},{"version":"2ea729503db9793f2691162fec3dd1118cab62e96d025f8eeb376d43ec293395","impliedFormat":1},{"version":"9ec87fea42b92894b0f209931a880789d43c3397d09dd99c631ae40a2f7071d1","impliedFormat":1},{"version":"c68e88cdfadfb6c8ba5fc38e58a3a166b0beae77b1f05b7d921150a32a5ffb8d","impliedFormat":1},{"version":"2bc7aa4fba46df0bd495425a7c8201437a7d465f83854fac859df2d67f664df3","impliedFormat":1},{"version":"41d17e1ad9a002feb11c8cdd2777e5bbc0cdb1e3f595d237e4dded0b6949983b","impliedFormat":1},{"version":"1fede9296beac11ce8e6b425396a1791f64341f2be85deebb6286faf6e16306e","affectsGlobalScope":true,"impliedFormat":1},{"version":"80219a97fd3ce5f91af5c355a264844027a899b3d9a3cd41cf6f3bc5947edc95","impliedFormat":1},{"version":"89444c76f16bf7994e230d98e1bc3f01d654de04ef02f60430d9a98d5b450a8b","impliedFormat":1},{"version":"0eb5d0cbf09de5d34542b977fd6a933bb2e0817bffe8e1a541b2f1ad1b9af1ff","impliedFormat":1},{"version":"fac3e88881b35d3a757ed891ac912b2674792c25e2a1a74e1f5fbc72d19a9792","impliedFormat":1},{"version":"2c2bdaa1d8ead9f68628d6d9d250e46ee8e81aa4898b4769a36956ae15e060fe","impliedFormat":1},{"version":"c32c840c62d8bd7aeb3147aa6754cd2d922b990a6b6634530cb2ebdce5adc8e9","impliedFormat":1},{"version":"e1c1a0b4d1ead0de9eca52203aeb1f771f21e6238d6fcd15aa56ac2a02f1b7bf","impliedFormat":1},{"version":"82b91e4e42e6c41bc7fc1b6c2dc5eba6a2ba98375eb1f210e6ff6bba2d54177e","impliedFormat":1},{"version":"6fe28249ac0c7bc19a79aa9264baf00efbd080e868dbe1d3052033ad1c64f206","affectsGlobalScope":true,"impliedFormat":1},{"version":"cbed824fec91efefc7bbdcb8b43d1a531fdbebd0e2ef19481501ff365a93cb70","impliedFormat":1},{"version":"8e9c23ba78aabc2e0a27033f18737a6df754067731e69dc5f52823957d60a4b6","impliedFormat":1},{"version":"d0716593b3f2b0451bcf0c24cfa86dec2235c325c89f201934248b7c742715fc","impliedFormat":1},{"version":"ec501101c2a96133a6c695f934c8f6642149cc728571b29cbb7b770984c1088e","impliedFormat":1},{"version":"b214ebcf76c51b115453f69729ee8aa7b7f8eccdae2a922b568a45c2d7ff52f7","impliedFormat":1},{"version":"429c9cdfa7d126255779efd7e6d9057ced2d69c81859bbab32073bad52e9ba76","impliedFormat":1},{"version":"2991bca2cc0f0628a278df2a2ccdb8d6cbcb700f3761abbed62bba137d5b1790","impliedFormat":1},{"version":"c51b3c3f6c5aa5b121124f4b593996826aab90667f95de88c1ff13c1736e11ba","affectsGlobalScope":true,"impliedFormat":1},{"version":"230763250f20449fa7b3c9273e1967adb0023dc890d4be1553faca658ee65971","impliedFormat":1},{"version":"c3e9078b60cb329d1221f5878e88cecfa3e74460550e605a58fcfb41a66029ff","impliedFormat":1},{"version":"a74edb3bab7394a9dbde529d60632be590def2f5f01024dbd85441587fbfbbe0","impliedFormat":1},{"version":"0ea59f7d3e51440baa64f429253759b106cfcbaf51e474cae606e02265b37cf8","impliedFormat":1},{"version":"bc18a1991ba681f03e13285fa1d7b99b03b67ee671b7bc936254467177543890","impliedFormat":1},{"version":"00049ccc87f3f37726db03c01ca68fe74fd9c0109b68c29eb9923ebec2c76b13","impliedFormat":1},{"version":"fa94bbf532b7af8f394b95fa310980d6e20bd2d4c871c6a6cb9f70f03750a44b","impliedFormat":1},{"version":"7fde0e1be5c8be204ffbf428abfcf01da2eb0f130e1bc3f539eb7275f4fd1f58","impliedFormat":1},{"version":"e284328553df5f425a5d33d36a0c3fa66b46af9d097cad6f4d2e8696dfdeb0f1","affectsGlobalScope":true,"impliedFormat":1},{"version":"7fa2214bb0d64701bc6f9ce8cde2fd2ff8c571e0b23065fa04a8a5a6beb91511","impliedFormat":1},{"version":"f1c93e046fb3d9b7f8249629f4b63dc068dd839b824dd0aa39a5e68476dc9420","impliedFormat":1},{"version":"016b29bf4926b80255a108c53a1451717350059da04fcae64d1075f5e93bbb39","impliedFormat":1},{"version":"841983e39bd4cbb463be385e92fda11057cab368bf27100a801c492f1d86cbaa","impliedFormat":1},{"version":"3856f7d31d0c47ec0dded3ec552519a3cd6639c1ad7be279dd1b31abffd8cc85","impliedFormat":1},{"version":"e16b319e5aca1031168de823c4946ff8e29629c4c8cc0ec0fcfe2a8ab2155043","impliedFormat":1},{"version":"e4156ddb25aa0e3b5303d372f26957b36778f0f6bbd4326359269873295e3058","affectsGlobalScope":true,"impliedFormat":1},{"version":"cc1b433a84cae05ddc5672d4823170af78606ad21ecef60dbc4570190cbf1357","impliedFormat":1},{"version":"9d3821bc75c59577e52643324cec92fc2145642e8d17cf7ee07a3181f21d985d","impliedFormat":1},{"version":"7f78cfb2b343838612c192cb251746e3a7c62ac7675726a47e130d9b213f6580","impliedFormat":1},{"version":"201db9cf1687fab1adf5282fcba861f382b32303dc4f67c89d59655e78a25461","impliedFormat":1},{"version":"2c3c5c0f54055e87640f5d233716fd889f3034fc7911d603b642369b0dbeb2a7","impliedFormat":1},{"version":"0a20eaf2e4b1e3c1e1f87f7bccb0c936375b23b022baeea750519b7c9bc6ce83","impliedFormat":1},{"version":"b484ec11ba00e3a2235562a41898d55372ccabe607986c6fa4f4aba72093749f","impliedFormat":1},{"version":"a16b91b27bd6b706c687c88cbc8a7d4ee98e5ed6043026d6b84bda923c0aed67","impliedFormat":1},{"version":"4ebf086fa2e5ef2b65133a944cb3f8ab518a22087727dfbfc802a3654c396f2f","impliedFormat":1},{"version":"99ab6d0d660ce4d21efb52288a39fd35bb3f556980ec5463b1ae8f304a3bbc85","impliedFormat":1},{"version":"6eeded8c7e352be6e0efb83f4935ec752513c4d22043b52522b90849a49a3a11","impliedFormat":1},{"version":"6c1ad90050ffbb151cacc68e2d06ea1a26a945659391e32651f5d42b86fd7f2c","impliedFormat":1},{"version":"55cdbeebe76a1fa18bbd7e7bf73350a2173926bd3085bb050cf5a5397025ee4e","impliedFormat":1},{"version":"0c51e46ad16a1d483119debc7227cd8fb6f8534408802cef1ce23d298b5a2dd5","impliedFormat":1},{"version":"cd1ac3689ea594fc7fc0e632de1e009106506055603f6457a361e87e15624f80","impliedFormat":1},{"version":"ae77d81a5541a8abb938a0efedf9ac4bea36fb3a24cc28cfa11c598863aba571","impliedFormat":1},{"version":"556ccd493ec36c7d7cb130d51be66e147b91cc1415be383d71da0f1e49f742a9","impliedFormat":1},{"version":"b6d03c9cfe2cf0ba4c673c209fcd7c46c815b2619fd2aad59fc4229aaef2ed43","impliedFormat":1},{"version":"95aba78013d782537cc5e23868e736bec5d377b918990e28ed56110e3ae8b958","impliedFormat":1},{"version":"670a76db379b27c8ff42f1ba927828a22862e2ab0b0908e38b671f0e912cc5ed","impliedFormat":1},{"version":"13b77ab19ef7aadd86a1e54f2f08ea23a6d74e102909e3c00d31f231ed040f62","impliedFormat":1},{"version":"069bebfee29864e3955378107e243508b163e77ab10de6a5ee03ae06939f0bb9","impliedFormat":1},{"version":"c2a6a737189ced24ffe0634e9239b087e4c26378d0490f95141b9b9b042b746c","impliedFormat":1},{"version":"104c67f0da1bdf0d94865419247e20eded83ce7f9911a1aa75fc675c077ca66e","impliedFormat":1},{"version":"cc0d0b339f31ce0ab3b7a5b714d8e578ce698f1e13d7f8c60bfb766baeb1d35c","impliedFormat":1},{"version":"427fe2004642504828c1476d0af4270e6ad4db6de78c0b5da3e4c5ca95052a99","impliedFormat":1},{"version":"2eeffcee5c1661ddca53353929558037b8cf305ffb86a803512982f99bcab50d","impliedFormat":99},{"version":"9afb4cb864d297e4092a79ee2871b5d3143ea14153f62ef0bb04ede25f432030","affectsGlobalScope":true,"impliedFormat":99},{"version":"fb893a0dfc3c9fb0f9ca93d0648694dd95f33cbad2c0f2c629f842981dfd4e2e","impliedFormat":1},{"version":"89e326922cadcc2331d7e851011cf9f0456a681aaf3c95b48b81f8d80e8cdfba","impliedFormat":1},{"version":"151ff381ef9ff8da2da9b9663ebf657eac35c4c9a19183420c05728f31a6761d","impliedFormat":1},{"version":"5d08a179b846f5ee674624b349ebebe2121c455e3a265dc93da4e8d9e89722b4","impliedFormat":1},{"version":"d34aa8df2d0b18fb56b1d772ff9b3c7aea7256cf0d692f969be6e1d27b74d660","impliedFormat":1},{"version":"93a3b8e57c68e348fc4054b245bd7cf4893225f56c991028844b693c2fa8c03c","impliedFormat":1},{"version":"2f5747b1508ccf83fad0c251ba1e5da2f5a30b78b09ffa1cfaf633045160afed","impliedFormat":1},{"version":"6823ccc7b5b77bbf898d878dbcad18aa45e0fa96bdd0abd0de98d514845d9ed9","affectsGlobalScope":true,"impliedFormat":1},{"version":"b71c603a539078a5e3a039b20f2b0a0d1708967530cf97dec8850a9ca45baa2b","impliedFormat":1},{"version":"168d88e14e0d81fe170e0dadd38ae9d217476c11435ea640ddb9b7382bdb6c1f","impliedFormat":1},{"version":"8e04cf0688e0d921111659c2b55851957017148fa7b977b02727477d155b3c47","impliedFormat":1},{"version":"4f817d326453d8d578758889131c3cab8665a0aa252df1ea254a83b653422efa","impliedFormat":1},{"version":"89121c1bf2990f5219bfd802a3e7fc557de447c62058d6af68d6b6348d64499a","impliedFormat":1},{"version":"79b4369233a12c6fa4a07301ecb7085802c98f3a77cf9ab97eee27e1656f82e6","impliedFormat":1},{"version":"d4a22007b481fe2a2e6bfd3a42c00cd62d41edb36d30fc4697df2692e9891fc8","impliedFormat":1},{"version":"7e29f41b158de217f94cb9676bf9cbd0cd9b5a46e1985141ed36e075c52bf6ad","affectsGlobalScope":true,"impliedFormat":1},{"version":"ac51dd7d31333793807a6abaa5ae168512b6131bd41d9c5b98477fc3b7800f9f","impliedFormat":1},{"version":"dc782ff85b2cb10075ecffc158af7bfb27ff97bf8491c917efea0c3d622d5ac4","impliedFormat":1},{"version":"be1cc4d94ea60cbe567bc29ed479d42587bf1e6cba490f123d329976b0fe4ee5","impliedFormat":1},{"version":"15fe687c59d62741b4494d5e623d497d55eb38966ecf5bea7f36e48fc3fbe15e","impliedFormat":1},{"version":"2c3b8be03577c98530ef9cb1a76e2c812636a871f367e9edf4c5f3ce702b77f8","affectsGlobalScope":true,"impliedFormat":1},{"version":"18942319aff2c9619e05c379641b571f0958506472a4b539f906be08fcccf806","impliedFormat":1},{"version":"1ba59c8bbeed2cb75b239bb12041582fa3e8ef32f8d0bd0ec802e38442d3f317","impliedFormat":1}],"root":[[91,94]],"options":{"composite":true,"declaration":true,"declarationMap":true,"module":99,"noFallthroughCasesInSwitch":true,"noUncheckedSideEffectImports":true,"outDir":"./","rootDir":"../src","skipLibCheck":true,"sourceMap":true,"strict":true,"target":10,"tsBuildInfoFile":"./.tsbuildinfo","verbatimModuleSyntax":true},"referencedMap":[[224,1],[222,2],[220,3],[219,2],[221,2],[227,4],[223,1],[225,5],[226,1],[228,6],[230,7],[233,8],[229,9],[235,10],[231,2],[237,11],[236,2],[241,12],[244,13],[245,2],[247,14],[242,2],[248,14],[234,2],[158,15],[159,15],[160,16],[97,17],[161,18],[162,19],[163,20],[95,2],[164,21],[165,22],[166,23],[167,24],[168,25],[169,26],[170,26],[171,27],[172,28],[173,29],[174,30],[98,2],[96,2],[175,31],[176,32],[177,33],[218,34],[178,35],[179,36],[180,35],[181,37],[182,38],[184,39],[185,40],[186,40],[187,40],[188,41],[189,42],[190,43],[191,44],[192,45],[193,46],[194,46],[195,47],[196,2],[197,2],[198,48],[199,49],[200,48],[201,50],[202,51],[203,52],[204,53],[205,54],[206,55],[207,56],[208,57],[209,58],[210,59],[211,60],[212,61],[213,62],[214,63],[215,64],[99,35],[100,2],[101,65],[102,66],[103,2],[104,67],[105,2],[149,68],[150,69],[151,70],[152,70],[153,71],[154,2],[155,18],[156,72],[157,69],[216,73],[217,74],[239,2],[240,2],[252,75],[249,2],[251,76],[238,77],[243,78],[254,79],[253,2],[246,2],[255,2],[256,80],[232,2],[183,2],[250,2],[62,2],[63,2],[12,2],[11,2],[2,2],[13,2],[14,2],[15,2],[16,2],[17,2],[18,2],[19,2],[20,2],[3,2],[21,2],[22,2],[4,2],[23,2],[27,2],[24,2],[25,2],[26,2],[28,2],[29,2],[30,2],[5,2],[31,2],[32,2],[33,2],[34,2],[6,2],[38,2],[35,2],[36,2],[37,2],[39,2],[7,2],[40,2],[45,2],[46,2],[41,2],[42,2],[43,2],[44,2],[8,2],[50,2],[47,2],[48,2],[49,2],[51,2],[9,2],[52,2],[53,2],[54,2],[56,2],[55,2],[57,2],[58,2],[10,2],[59,2],[1,2],[60,2],[61,2],[124,81],[137,82],[121,83],[138,84],[147,85],[112,86],[113,87],[111,88],[146,6],[141,89],[145,90],[115,91],[134,92],[114,93],[144,94],[109,95],[110,89],[116,96],[117,2],[123,97],[120,96],[107,98],[148,99],[139,100],[127,101],[126,96],[128,102],[131,103],[125,104],[129,105],[142,6],[118,106],[119,107],[132,108],[108,84],[136,109],[135,96],[122,107],[130,110],[133,111],[140,2],[106,2],[143,112],[86,113],[88,114],[85,114],[90,115],[87,113],[89,113],[84,116],[92,117],[94,118],[93,119],[91,120],[67,121],[76,121],[66,121],[71,121],[68,121],[74,121],[69,2],[77,121],[72,122],[78,123],[75,121],[64,2],[73,121],[70,2],[65,121],[81,2],[82,124],[83,125],[80,124],[79,2]],"latestChangedDtsFile":"./types.d.ts","version":"5.8.3"}
|
package/dist/engine.d.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The PURE alert engine. No side effects, no clock of its own, no scheduler —
|
|
3
|
+
* just functions over (event, rules, now) and (alerts, now). The host drives the
|
|
4
|
+
* tick; the orchestrator does the I/O. Deterministic and trivially testable.
|
|
5
|
+
*/
|
|
6
|
+
import type { DomainEvent } from '@bimetal/event-sourcing';
|
|
7
|
+
import type { Template } from '@bimetal/channel';
|
|
8
|
+
import type { Alert, AlertSpec } from '@bimetal/alert-data';
|
|
9
|
+
import type { AlertRule, AlertSubject } from './types.js';
|
|
10
|
+
/**
|
|
11
|
+
* Deterministic, INJECTIVE key: same rule + subject + occurrence ⇒ same key ⇒
|
|
12
|
+
* structural dedup. JSON-encoded (not a `::`-join) so component values that
|
|
13
|
+
* themselves contain the separator — e.g. `subjectId="a::b"` vs `occurrence="b"`
|
|
14
|
+
* — can never collide into the same key (which would silently swallow a real,
|
|
15
|
+
* distinct alert as a "duplicate").
|
|
16
|
+
*/
|
|
17
|
+
export declare function triggerKeyFor(rule: AlertRule, subject: AlertSubject): string;
|
|
18
|
+
/**
|
|
19
|
+
* Turn one domain event into the alert specs to schedule. `before_start` fires
|
|
20
|
+
* at `subject.startMs - offsetMs`; the other triggers fire `now` (immediate).
|
|
21
|
+
*/
|
|
22
|
+
export declare function alertSpecsForEvent(event: DomainEvent, rules: readonly AlertRule[], now: number, template?: Template): AlertSpec[];
|
|
23
|
+
/** The trigger keys of every scheduled alert whose `fireAt` has arrived. */
|
|
24
|
+
export declare function dueScheduled(alerts: readonly Alert[], now: number): string[];
|
|
25
|
+
//# sourceMappingURL=engine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEjD,OAAO,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE1D;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,YAAY,GAAG,MAAM,CAE5E;AAYD;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,WAAW,EAClB,KAAK,EAAE,SAAS,SAAS,EAAE,EAC3B,GAAG,EAAE,MAAM,EACX,QAAQ,GAAE,QAA0B,GACnC,SAAS,EAAE,CAqBb;AAED,4EAA4E;AAC5E,wBAAgB,YAAY,CAAC,MAAM,EAAE,SAAS,KAAK,EAAE,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAE5E"}
|
package/dist/engine.js
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { defaultTemplate } from '@bimetal/channel';
|
|
2
|
+
/**
|
|
3
|
+
* Deterministic, INJECTIVE key: same rule + subject + occurrence ⇒ same key ⇒
|
|
4
|
+
* structural dedup. JSON-encoded (not a `::`-join) so component values that
|
|
5
|
+
* themselves contain the separator — e.g. `subjectId="a::b"` vs `occurrence="b"`
|
|
6
|
+
* — can never collide into the same key (which would silently swallow a real,
|
|
7
|
+
* distinct alert as a "duplicate").
|
|
8
|
+
*/
|
|
9
|
+
export function triggerKeyFor(rule, subject) {
|
|
10
|
+
return JSON.stringify([rule.id, subject.id, subject.occurrence ?? null]);
|
|
11
|
+
}
|
|
12
|
+
function recipientOf(rule, subject) {
|
|
13
|
+
return typeof rule.recipient === 'function' ? rule.recipient(subject) : rule.recipient;
|
|
14
|
+
}
|
|
15
|
+
function payloadOf(rule, subject, template) {
|
|
16
|
+
if (rule.render)
|
|
17
|
+
return rule.render(subject);
|
|
18
|
+
if (rule.template !== undefined)
|
|
19
|
+
return { body: template.render(rule.template, subject.data) };
|
|
20
|
+
return { body: '' };
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Turn one domain event into the alert specs to schedule. `before_start` fires
|
|
24
|
+
* at `subject.startMs - offsetMs`; the other triggers fire `now` (immediate).
|
|
25
|
+
*/
|
|
26
|
+
export function alertSpecsForEvent(event, rules, now, template = defaultTemplate) {
|
|
27
|
+
const specs = [];
|
|
28
|
+
for (const rule of rules) {
|
|
29
|
+
if (!rule.on.includes(event.type))
|
|
30
|
+
continue;
|
|
31
|
+
const subject = rule.extract(event);
|
|
32
|
+
if (!subject)
|
|
33
|
+
continue;
|
|
34
|
+
if (rule.condition && !rule.condition(subject))
|
|
35
|
+
continue;
|
|
36
|
+
const fireAt = rule.trigger === 'before_start'
|
|
37
|
+
? (subject.startMs ?? now) - (rule.offsetMs ?? 0)
|
|
38
|
+
: now;
|
|
39
|
+
specs.push({
|
|
40
|
+
triggerKey: triggerKeyFor(rule, subject),
|
|
41
|
+
ruleId: rule.id,
|
|
42
|
+
subjectId: subject.id,
|
|
43
|
+
channel: rule.channel,
|
|
44
|
+
recipient: recipientOf(rule, subject),
|
|
45
|
+
payload: payloadOf(rule, subject, template),
|
|
46
|
+
fireAt,
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
return specs;
|
|
50
|
+
}
|
|
51
|
+
/** The trigger keys of every scheduled alert whose `fireAt` has arrived. */
|
|
52
|
+
export function dueScheduled(alerts, now) {
|
|
53
|
+
return alerts.filter(a => a.status === 'scheduled' && a.fireAt <= now).map(a => a.triggerKey);
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=engine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine.js","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAInD;;;;;;GAMG;AACH,MAAM,UAAU,aAAa,CAAC,IAAe,EAAE,OAAqB;IAClE,OAAO,IAAI,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,OAAO,CAAC,EAAE,EAAE,OAAO,CAAC,UAAU,IAAI,IAAI,CAAC,CAAC,CAAC;AAC3E,CAAC;AAED,SAAS,WAAW,CAAC,IAAe,EAAE,OAAqB;IACzD,OAAO,OAAO,IAAI,CAAC,SAAS,KAAK,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC;AACzF,CAAC;AAED,SAAS,SAAS,CAAC,IAAe,EAAE,OAAqB,EAAE,QAAkB;IAC3E,IAAI,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAC7C,IAAI,IAAI,CAAC,QAAQ,KAAK,SAAS;QAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;IAC/F,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC;AACtB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAChC,KAAkB,EAClB,KAA2B,EAC3B,GAAW,EACX,WAAqB,eAAe;IAEpC,MAAM,KAAK,GAAgB,EAAE,CAAC;IAC9B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC;YAAE,SAAS;QAC5C,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QACpC,IAAI,CAAC,OAAO;YAAE,SAAS;QACvB,IAAI,IAAI,CAAC,SAAS,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;YAAE,SAAS;QACzD,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,KAAK,cAAc;YAC5C,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,IAAI,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,IAAI,CAAC,CAAC;YACjD,CAAC,CAAC,GAAG,CAAC;QACR,KAAK,CAAC,IAAI,CAAC;YACT,UAAU,EAAE,aAAa,CAAC,IAAI,EAAE,OAAO,CAAC;YACxC,MAAM,EAAE,IAAI,CAAC,EAAE;YACf,SAAS,EAAE,OAAO,CAAC,EAAE;YACrB,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,SAAS,EAAE,WAAW,CAAC,IAAI,EAAE,OAAO,CAAC;YACrC,OAAO,EAAE,SAAS,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,CAAC;YAC3C,MAAM;SACP,CAAC,CAAC;IACL,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,4EAA4E;AAC5E,MAAM,UAAU,YAAY,CAAC,MAAwB,EAAE,GAAW;IAChE,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,WAAW,IAAI,CAAC,CAAC,MAAM,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;AAChG,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module @bimetal/alerting
|
|
3
|
+
*
|
|
4
|
+
* Alert engine (pure rule evaluation, host-driven clock tick — no scheduler in
|
|
5
|
+
* core) + orchestrator that wires domain events to the @bimetal/alert-data
|
|
6
|
+
* lifecycle and pluggable @bimetal/channel delivery. Idempotent: replay never
|
|
7
|
+
* re-delivers.
|
|
8
|
+
*/
|
|
9
|
+
export type { AlertTrigger, AlertSubject, AlertRule, AlertOrchestrator, AlertOrchestratorOptions, } from './types.js';
|
|
10
|
+
export { alertSpecsForEvent, dueScheduled, triggerKeyFor } from './engine.js';
|
|
11
|
+
export { createAlertOrchestrator } from './orchestrator.js';
|
|
12
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,YAAY,EACV,YAAY,EACZ,YAAY,EACZ,SAAS,EACT,iBAAiB,EACjB,wBAAwB,GACzB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,kBAAkB,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC9E,OAAO,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module @bimetal/alerting
|
|
3
|
+
*
|
|
4
|
+
* Alert engine (pure rule evaluation, host-driven clock tick — no scheduler in
|
|
5
|
+
* core) + orchestrator that wires domain events to the @bimetal/alert-data
|
|
6
|
+
* lifecycle and pluggable @bimetal/channel delivery. Idempotent: replay never
|
|
7
|
+
* re-delivers.
|
|
8
|
+
*/
|
|
9
|
+
export { alertSpecsForEvent, dueScheduled, triggerKeyFor } from './engine.js';
|
|
10
|
+
export { createAlertOrchestrator } from './orchestrator.js';
|
|
11
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAUH,OAAO,EAAE,kBAAkB,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC9E,OAAO,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"orchestrator.d.ts","sourceRoot":"","sources":["../src/orchestrator.ts"],"names":[],"mappings":"AAsCA,OAAO,KAAK,EAAE,iBAAiB,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AAgC9E,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,wBAAwB,GAAG,iBAAiB,CAuF5F"}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { defaultTemplate, ChannelHttpError } from '@bimetal/channel';
|
|
2
|
+
import { scheduleAlert, requestAlert, markDispatched, markFailed } from '@bimetal/alert-data';
|
|
3
|
+
import { alertSpecsForEvent, dueScheduled } from './engine.js';
|
|
4
|
+
const GENERIC_FAILURE = 'Channel send failed';
|
|
5
|
+
/**
|
|
6
|
+
* A reason string SAFE to persist in the immutable, replayable AlertFailed log.
|
|
7
|
+
*
|
|
8
|
+
* `Channel` is an open, pluggable interface — a custom channel can throw anything.
|
|
9
|
+
* We must NOT trust any free-text the error carries: `error.message` is a WRITABLE
|
|
10
|
+
* own property even on `ChannelHttpError` (it extends Error), so a custom channel
|
|
11
|
+
* could `new ChannelHttpError(503, …)` then overwrite `.message` with a secret
|
|
12
|
+
* before rejecting. Truncation does not help — a secret is usually short.
|
|
13
|
+
*
|
|
14
|
+
* So the persisted reason is safe BY CONSTRUCTION: the ONLY non-constant we persist
|
|
15
|
+
* is DERIVED from `ChannelHttpError.status` after validating it is a finite integer
|
|
16
|
+
* — a number cannot smuggle text, `HTTP ${n}` is pure digits. We never read
|
|
17
|
+
* `.message`/`.detail`. Everything else — a custom free-text message, an AbortError
|
|
18
|
+
* on timeout, a bare TypeError from fetch, or a tampered (non-numeric) status —
|
|
19
|
+
* collapses to the fixed, framework-owned reason. The full error always reaches the
|
|
20
|
+
* transient `onError` sink for live diagnostics.
|
|
21
|
+
*
|
|
22
|
+
* A custom channel that wants a meaningful PERSISTED reason throws a
|
|
23
|
+
* `ChannelHttpError` with a real numeric status; the generic reason is the safe
|
|
24
|
+
* default for everything else.
|
|
25
|
+
*/
|
|
26
|
+
function persistableError(error) {
|
|
27
|
+
if (error instanceof ChannelHttpError && Number.isInteger(error.status)) {
|
|
28
|
+
return `HTTP ${error.status}`; // derived from the numeric status, never the mutable message
|
|
29
|
+
}
|
|
30
|
+
return GENERIC_FAILURE;
|
|
31
|
+
}
|
|
32
|
+
export function createAlertOrchestrator(options) {
|
|
33
|
+
const { store, rules, channels } = options;
|
|
34
|
+
const clock = options.clock ?? { now: () => Date.now() };
|
|
35
|
+
const template = options.template ?? defaultTemplate;
|
|
36
|
+
// Single-flight chain: every ingest/tick runs after the previous one settles,
|
|
37
|
+
// so the orchestrator never has two of its own dispatches in flight at once.
|
|
38
|
+
let tail = Promise.resolve();
|
|
39
|
+
function serialize(op) {
|
|
40
|
+
const run = tail.then(op, op);
|
|
41
|
+
tail = run.then(() => undefined, () => undefined);
|
|
42
|
+
return run;
|
|
43
|
+
}
|
|
44
|
+
async function deliver(triggerKey) {
|
|
45
|
+
const alert = store.getAlert(triggerKey);
|
|
46
|
+
if (!alert || alert.status !== 'requested')
|
|
47
|
+
return; // raced/superseded — nothing to send
|
|
48
|
+
const channel = channels[alert.channel];
|
|
49
|
+
if (!channel) {
|
|
50
|
+
await store.dispatch(markFailed(triggerKey, `Unknown channel "${alert.channel}"`));
|
|
51
|
+
options.onError?.(new Error(`Unknown channel "${alert.channel}"`), { triggerKey, channel: alert.channel });
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
try {
|
|
55
|
+
await channel.send(alert.recipient, alert.payload);
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
// The SEND failed → errors-as-state. Persist only a bounded, body-free
|
|
59
|
+
// reason; the full error (incl. any provider detail) goes to the transient
|
|
60
|
+
// onError sink, never to the log.
|
|
61
|
+
await store.dispatch(markFailed(triggerKey, persistableError(error)));
|
|
62
|
+
options.onError?.(error, { triggerKey, channel: alert.channel });
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
// The send SUCCEEDED. Recording the dispatch is best-effort: if `markDispatched`
|
|
66
|
+
// loses a race (a co-writer bumped the stream version), the alert stays in
|
|
67
|
+
// `requested` — the documented crash-window, recoverable by the host. We must
|
|
68
|
+
// NOT `markFailed` here: that would lie about an alert that was actually
|
|
69
|
+
// delivered. Surface the recording failure to the transient sink and move on
|
|
70
|
+
// (a future tick won't re-send — `dueScheduled` only picks up `scheduled`).
|
|
71
|
+
try {
|
|
72
|
+
await store.dispatch(markDispatched(triggerKey));
|
|
73
|
+
}
|
|
74
|
+
catch (error) {
|
|
75
|
+
options.onError?.(error, { triggerKey, channel: alert.channel });
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
async function requestAndDeliver(now) {
|
|
79
|
+
for (const triggerKey of dueScheduled(store.getAlerts(), now)) {
|
|
80
|
+
let events;
|
|
81
|
+
try {
|
|
82
|
+
events = await store.dispatch(requestAlert(triggerKey));
|
|
83
|
+
}
|
|
84
|
+
catch (error) {
|
|
85
|
+
// Lost a race (ConcurrencyError) or transient store error: another writer
|
|
86
|
+
// requested it. Skip — do NOT send, do NOT crash the tick.
|
|
87
|
+
options.onError?.(error, { triggerKey, channel: store.getAlert(triggerKey)?.channel ?? 'unknown' });
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
// The send is gated on AlertRequested actually being emitted (idempotent).
|
|
91
|
+
if (events.some(e => e.type === 'bimetal.alerting.AlertRequested')) {
|
|
92
|
+
await deliver(triggerKey);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return {
|
|
97
|
+
ingest(event) {
|
|
98
|
+
return serialize(async () => {
|
|
99
|
+
const now = clock.now();
|
|
100
|
+
for (const spec of alertSpecsForEvent(event, rules, now, template)) {
|
|
101
|
+
await store.dispatch(scheduleAlert(spec));
|
|
102
|
+
}
|
|
103
|
+
// Immediately deliver anything already due (on_create alerts have fireAt=now).
|
|
104
|
+
await requestAndDeliver(now);
|
|
105
|
+
});
|
|
106
|
+
},
|
|
107
|
+
tick(now) {
|
|
108
|
+
return serialize(() => requestAndDeliver(now ?? clock.now()));
|
|
109
|
+
},
|
|
110
|
+
redeliver(triggerKey) {
|
|
111
|
+
// Host-driven recovery for an alert stranded in `requested` (the crash window
|
|
112
|
+
// above). The host EXPLICITLY opts into at-least-once: the original send may
|
|
113
|
+
// already have succeeded, so this can produce a duplicate external effect.
|
|
114
|
+
// Serialized with ingest/tick; a no-op unless the alert is currently
|
|
115
|
+
// `requested`, so calling it on an already-dispatched/failed alert is safe.
|
|
116
|
+
return serialize(() => deliver(triggerKey));
|
|
117
|
+
},
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=orchestrator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"orchestrator.js","sourceRoot":"","sources":["../src/orchestrator.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @bimetal/alerting — Type Definitions.
|
|
3
|
+
*
|
|
4
|
+
* The engine is GENERIC over the subject: it never imports calendar/kanban. A
|
|
5
|
+
* rule pulls an `AlertSubject` out of a domain event (`extract`), and the engine
|
|
6
|
+
* computes the trigger key + fire time. The host owns the clock tick.
|
|
7
|
+
*/
|
|
8
|
+
import type { DomainEvent, Clock } from '@bimetal/event-sourcing';
|
|
9
|
+
import type { Channel, Template } from '@bimetal/channel';
|
|
10
|
+
import type { AlertStore } from '@bimetal/alert-data';
|
|
11
|
+
export type AlertTrigger = 'before_start' | 'on_create' | 'on_update' | 'on_delete';
|
|
12
|
+
/**
|
|
13
|
+
* What a rule extracts from a domain event. The engine treats it opaquely except
|
|
14
|
+
* for `id` (→ subjectId), `startMs` (`before_start` timing) and `occurrence`
|
|
15
|
+
* (recurrence disambiguation — part of the trigger key). `data` is the template
|
|
16
|
+
* data.
|
|
17
|
+
*/
|
|
18
|
+
export interface AlertSubject {
|
|
19
|
+
readonly id: string;
|
|
20
|
+
readonly startMs?: number;
|
|
21
|
+
readonly occurrence?: string;
|
|
22
|
+
readonly data: unknown;
|
|
23
|
+
}
|
|
24
|
+
export interface AlertRule {
|
|
25
|
+
readonly id: string;
|
|
26
|
+
readonly trigger: AlertTrigger;
|
|
27
|
+
/** Event type FQNs this rule reacts to (e.g. 'bimetal.calendar.CalendarEventCreated'). */
|
|
28
|
+
readonly on: readonly string[];
|
|
29
|
+
/** Pull the subject out of the event (null = this event is not for this rule). */
|
|
30
|
+
readonly extract: (event: DomainEvent) => AlertSubject | null;
|
|
31
|
+
/** `before_start` only: fire `offsetMs` before `subject.startMs`. */
|
|
32
|
+
readonly offsetMs?: number;
|
|
33
|
+
/** Optional guard — only fire when this returns true. */
|
|
34
|
+
readonly condition?: (subject: AlertSubject) => boolean;
|
|
35
|
+
/** Logical channel name (resolved to a real Channel by the orchestrator). */
|
|
36
|
+
readonly channel: string;
|
|
37
|
+
/** Recipient address, static or derived from the subject. */
|
|
38
|
+
readonly recipient: string | ((subject: AlertSubject) => string);
|
|
39
|
+
/** String template rendered against `subject.data` via the configured Template → `{ body }`. */
|
|
40
|
+
readonly template?: string;
|
|
41
|
+
/** Full control over the channel payload; overrides `template`. */
|
|
42
|
+
readonly render?: (subject: AlertSubject) => unknown;
|
|
43
|
+
}
|
|
44
|
+
export interface AlertOrchestratorOptions {
|
|
45
|
+
readonly store: AlertStore;
|
|
46
|
+
readonly rules: readonly AlertRule[];
|
|
47
|
+
/** Channel-name → Channel. The orchestrator routes each alert by its `channel`. */
|
|
48
|
+
readonly channels: Readonly<Record<string, Channel>>;
|
|
49
|
+
readonly clock?: Clock;
|
|
50
|
+
/** Template engine for rule `template` strings. Default: the minimal `{{path}}` renderer. */
|
|
51
|
+
readonly template?: Template;
|
|
52
|
+
/**
|
|
53
|
+
* Surfaces channel-dispatch / wiring errors (a send failure is also recorded as
|
|
54
|
+
* `AlertFailed`, but with a bounded, body-free reason).
|
|
55
|
+
*
|
|
56
|
+
* **TRANSIENT sink — do NOT persist `error`.** The error passed here may carry a
|
|
57
|
+
* raw provider response on `ChannelHttpError.detail` (recipient echoes, mirrored
|
|
58
|
+
* auth headers, tokens). Only the body-free `AlertFailed.error` is safe for the
|
|
59
|
+
* immutable event log; this callback is for live diagnostics/metrics. Wiring it
|
|
60
|
+
* into a persistent/replayable log would re-introduce exactly the PII/secret leak
|
|
61
|
+
* the body-free error contract prevents.
|
|
62
|
+
*/
|
|
63
|
+
readonly onError?: (error: unknown, context: {
|
|
64
|
+
readonly triggerKey: string;
|
|
65
|
+
readonly channel: string;
|
|
66
|
+
}) => void;
|
|
67
|
+
}
|
|
68
|
+
export interface AlertOrchestrator {
|
|
69
|
+
/**
|
|
70
|
+
* Feed a domain event in. The host subscribes the source event store/broker and
|
|
71
|
+
* calls this. Schedules matching alerts, then immediately delivers any that are
|
|
72
|
+
* already due (so `on_create` fires now).
|
|
73
|
+
*/
|
|
74
|
+
ingest(event: DomainEvent): Promise<void>;
|
|
75
|
+
/** Host-driven time tick: request + deliver every scheduled alert now due. */
|
|
76
|
+
tick(now?: number): Promise<void>;
|
|
77
|
+
/**
|
|
78
|
+
* Host-driven recovery for an alert stranded in `requested` (committed
|
|
79
|
+
* `AlertRequested` but the process died before/around `channel.send`, so delivery
|
|
80
|
+
* is unknown). Re-sends and records the outcome (`dispatched`/`failed`).
|
|
81
|
+
*
|
|
82
|
+
* **At-least-once — opt-in:** the original send may already have succeeded, so
|
|
83
|
+
* this can cause a DUPLICATE external effect; only call it when a duplicate is
|
|
84
|
+
* acceptable. No-op unless the alert is currently `requested`. The alternative
|
|
85
|
+
* (at-most-once) is to `markFailed` the alert and never redeliver.
|
|
86
|
+
*/
|
|
87
|
+
redeliver(triggerKey: string): Promise<void>;
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,yBAAyB,CAAC;AAClE,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC1D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEtD,MAAM,MAAM,YAAY,GAAG,cAAc,GAAG,WAAW,GAAG,WAAW,GAAG,WAAW,CAAC;AAEpF;;;;;GAKG;AACH,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,OAAO,EAAE,YAAY,CAAC;IAC/B,0FAA0F;IAC1F,QAAQ,CAAC,EAAE,EAAE,SAAS,MAAM,EAAE,CAAC;IAC/B,kFAAkF;IAClF,QAAQ,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,YAAY,GAAG,IAAI,CAAC;IAC9D,qEAAqE;IACrE,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,yDAAyD;IACzD,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,YAAY,KAAK,OAAO,CAAC;IACxD,6EAA6E;IAC7E,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,6DAA6D;IAC7D,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,CAAC,CAAC,OAAO,EAAE,YAAY,KAAK,MAAM,CAAC,CAAC;IACjE,gGAAgG;IAChG,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,mEAAmE;IACnE,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,YAAY,KAAK,OAAO,CAAC;CACtD;AAED,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;IAC3B,QAAQ,CAAC,KAAK,EAAE,SAAS,SAAS,EAAE,CAAC;IACrC,mFAAmF;IACnF,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACrD,QAAQ,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC;IACvB,6FAA6F;IAC7F,QAAQ,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC;IAC7B;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE;QAAE,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;CACjH;AAED,MAAM,WAAW,iBAAiB;IAChC;;;;OAIG;IACH,MAAM,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1C,8EAA8E;IAC9E,IAAI,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAClC;;;;;;;;;OASG;IACH,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9C"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@bimetal/alerting",
|
|
3
|
+
"version": "0.29.0",
|
|
4
|
+
"description": "Alert engine + orchestrator: pure rule evaluation (host-driven clock tick, no scheduler in core) wiring domain events to the @bimetal/alert-data lifecycle and pluggable @bimetal/channel delivery. Idempotent — replay never re-delivers.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist",
|
|
16
|
+
"README.md",
|
|
17
|
+
"LICENSE"
|
|
18
|
+
],
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "tsc -b",
|
|
21
|
+
"dev": "tsc -b --watch",
|
|
22
|
+
"typecheck": "tsc --noEmit -p tsconfig.test.json",
|
|
23
|
+
"test": "vitest run",
|
|
24
|
+
"test:watch": "vitest",
|
|
25
|
+
"prepublishOnly": "npm run build"
|
|
26
|
+
},
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"@bimetal/event-sourcing": "^0.29.0",
|
|
29
|
+
"@bimetal/channel": "^0.29.0",
|
|
30
|
+
"@bimetal/alert-data": "^0.29.0"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"vitest": "^3.2.1"
|
|
34
|
+
},
|
|
35
|
+
"sideEffects": false,
|
|
36
|
+
"license": "PolyForm-Noncommercial-1.0.0",
|
|
37
|
+
"author": "Andreas Biederbeck",
|
|
38
|
+
"repository": {
|
|
39
|
+
"type": "git",
|
|
40
|
+
"url": "https://github.com/bimetal/bimetal.git",
|
|
41
|
+
"directory": "packages/alerting/alerting"
|
|
42
|
+
},
|
|
43
|
+
"keywords": [
|
|
44
|
+
"alerting",
|
|
45
|
+
"rules",
|
|
46
|
+
"event-driven",
|
|
47
|
+
"notifications",
|
|
48
|
+
"headless"
|
|
49
|
+
]
|
|
50
|
+
}
|