@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 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"}
@@ -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"}
@@ -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,3 @@
1
+ import type { AlertOrchestrator, AlertOrchestratorOptions } from './types.js';
2
+ export declare function createAlertOrchestrator(options: AlertOrchestratorOptions): AlertOrchestrator;
3
+ //# sourceMappingURL=orchestrator.d.ts.map
@@ -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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"}
@@ -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,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -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
+ }