@warlock.js/notifications 5.30.0 → 5.32.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/CHANGELOG.md +22 -1
- package/cjs/index.cjs +2 -2
- package/cjs/index.cjs.map +1 -1
- package/esm/channels/database-channel.d.mts +2 -3
- package/esm/channels/database-channel.d.mts.map +1 -1
- package/esm/channels/index.d.mts +2 -1
- package/esm/channels/index.mjs +1 -1
- package/esm/channels/mail-channel.d.mts +6 -4
- package/esm/channels/mail-channel.d.mts.map +1 -1
- package/esm/config.d.mts +13 -9
- package/esm/config.d.mts.map +1 -1
- package/esm/config.mjs.map +1 -1
- package/esm/contracts/channel.contract.d.mts +1 -3
- package/esm/contracts/channel.contract.d.mts.map +1 -1
- package/esm/contracts/index.d.mts +2 -1
- package/esm/contracts/notification.contract.d.mts +1 -3
- package/esm/contracts/notification.contract.d.mts.map +1 -1
- package/esm/contracts/preference-provider.contract.d.mts +1 -3
- package/esm/contracts/preference-provider.contract.d.mts.map +1 -1
- package/esm/contracts/queue-dispatcher.contract.d.mts +1 -3
- package/esm/contracts/queue-dispatcher.contract.d.mts.map +1 -1
- package/esm/contracts/rate-limiter.contract.d.mts +1 -3
- package/esm/contracts/rate-limiter.contract.d.mts.map +1 -1
- package/esm/dispatch/define-channel.d.mts +2 -2
- package/esm/dispatch/define-channel.d.mts.map +1 -1
- package/esm/dispatch/define-notification.d.mts +5 -6
- package/esm/dispatch/define-notification.d.mts.map +1 -1
- package/esm/dispatch/define-notification.mjs.map +1 -1
- package/esm/dispatch/index.d.mts +2 -1
- package/esm/dispatch/index.mjs +1 -1
- package/esm/dispatch/notifications-event-bus.d.mts +2 -3
- package/esm/dispatch/notifications-event-bus.d.mts.map +1 -1
- package/esm/dispatch/notify.d.mts +3 -5
- package/esm/dispatch/notify.d.mts.map +1 -1
- package/esm/dispatch/notify.mjs.map +1 -1
- package/esm/errors.d.mts +5 -6
- package/esm/errors.d.mts.map +1 -1
- package/esm/in-app/base-notifications-repository.d.mts +6 -6
- package/esm/in-app/base-notifications-repository.d.mts.map +1 -1
- package/esm/in-app/base-notifications-repository.mjs +1 -1
- package/esm/in-app/base-notifications-repository.mjs.map +1 -1
- package/esm/in-app/column-map.d.mts +11 -8
- package/esm/in-app/column-map.d.mts.map +1 -1
- package/esm/in-app/database-notification.d.mts +2 -3
- package/esm/in-app/database-notification.d.mts.map +1 -1
- package/esm/in-app/in-app.d.mts +6 -5
- package/esm/in-app/in-app.d.mts.map +1 -1
- package/esm/in-app/index.d.mts +2 -1
- package/esm/in-app/index.mjs +1 -1
- package/esm/index.d.mts +6 -0
- package/esm/migration/index.d.mts +2 -1
- package/esm/migration/index.mjs +1 -1
- package/esm/migration/notification-columns.d.mts +6 -7
- package/esm/migration/notification-columns.d.mts.map +1 -1
- package/esm/migration/notification-columns.mjs.map +1 -1
- package/esm/queue/bullmq-queue.d.mts +9 -7
- package/esm/queue/bullmq-queue.d.mts.map +1 -1
- package/esm/queue/bullmq-queue.mjs.map +1 -1
- package/esm/queue/herald-queue.d.mts +6 -4
- package/esm/queue/herald-queue.d.mts.map +1 -1
- package/esm/queue/index.d.mts +2 -1
- package/esm/queue/index.mjs +1 -1
- package/esm/queue/load-herald.d.mts +1 -2
- package/esm/queue/load-herald.d.mts.map +1 -1
- package/esm/queue/load-herald.mjs +1 -1
- package/esm/queue/load-queue.d.mts +2 -3
- package/esm/queue/load-queue.d.mts.map +1 -1
- package/esm/queue/notifications-worker.d.mts +5 -4
- package/esm/queue/notifications-worker.d.mts.map +1 -1
- package/esm/queue/notifications-worker.mjs.map +1 -1
- package/esm/queue/queue-package-not-installed.error.d.mts +1 -2
- package/esm/queue/queue-package-not-installed.error.d.mts.map +1 -1
- package/esm/types.d.mts +22 -18
- package/esm/types.d.mts.map +1 -1
- package/llms-full.txt +89 -81
- package/package.json +10 -9
- package/skills/configure-notifications/SKILL.md +7 -7
- package/skills/define-channel/SKILL.md +9 -7
- package/skills/define-notification/SKILL.md +22 -25
- package/skills/index.md +4 -1
- package/skills/notifications-basics/SKILL.md +12 -12
- package/skills/observe-notifications/SKILL.md +14 -10
- package/skills/send-ad-hoc/SKILL.md +9 -9
- package/skills/use-in-app/SKILL.md +6 -4
- package/skills/write-notification-migration/SKILL.md +10 -7
- package/cjs/channel_api-C5ZZDkgQ.cjs +0 -7463
- package/cjs/channel_api-C5ZZDkgQ.cjs.map +0 -1
- package/cjs/chunk-fl3r8ClO.cjs +0 -41
- package/cjs/rabbitmq-driver-BFoWr21L.cjs +0 -3
- package/cjs/src-eu2jxS21.cjs +0 -11190
- package/cjs/src-eu2jxS21.cjs.map +0 -1
- package/esm/_virtual/_rolldown/runtime.mjs +0 -32
- package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/Random/_internal.mjs +0 -6
- package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/Random/_internal.mjs.map +0 -1
- package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/Random/bool.mjs +0 -3
- package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/Random/color.mjs +0 -3
- package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/Random/date.mjs +0 -3
- package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/Random/float.mjs +0 -3
- package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/Random/id.mjs +0 -3
- package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/Random/int.mjs +0 -3
- package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/Random/nanoid.mjs +0 -3
- package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/Random/pick.mjs +0 -3
- package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/Random/random.mjs +0 -16
- package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/Random/sample.mjs +0 -3
- package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/Random/string.mjs +0 -3
- package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/Random/token.mjs +0 -3
- package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/Random/uuid.mjs +0 -3
- package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/Random/weighted.mjs +0 -3
- package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/async/retry.mjs +0 -3
- package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/index.mjs +0 -24
- package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/mixed/clone/clone.mjs +0 -82
- package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/mixed/clone/clone.mjs.map +0 -1
- package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/number/round.mjs +0 -17
- package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/number/round.mjs.map +0 -1
- package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/object/except.mjs +0 -13
- package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/object/except.mjs.map +0 -1
- package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/object/get.mjs +0 -18
- package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/object/get.mjs.map +0 -1
- package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/object/omit.mjs +0 -17
- package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/object/omit.mjs.map +0 -1
- package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/object/unset.mjs +0 -30
- package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/object/unset.mjs.map +0 -1
- package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/string/capitalize.mjs +0 -19
- package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/string/capitalize.mjs.map +0 -1
- package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/string/ltrim.mjs +0 -18
- package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/string/ltrim.mjs.map +0 -1
- package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/string/readMoreChars.mjs +0 -14
- package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/string/readMoreChars.mjs.map +0 -1
- package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/string/rtrim.mjs +0 -18
- package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/string/rtrim.mjs.map +0 -1
- package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/string/toCamelCase.mjs +0 -22
- package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/string/toCamelCase.mjs.map +0 -1
- package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/string/toKebabCase.mjs +0 -17
- package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/string/toKebabCase.mjs.map +0 -1
- package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/string/toSnakeCase.mjs +0 -21
- package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/string/toSnakeCase.mjs.map +0 -1
- package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/string/toStudlyCase.mjs +0 -21
- package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/string/toStudlyCase.mjs.map +0 -1
- package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/string/trim.mjs +0 -20
- package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/string/trim.mjs.map +0 -1
- package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/string/ucfirst.mjs +0 -15
- package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/string/ucfirst.mjs.map +0 -1
- package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/string/words.mjs +0 -25
- package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/string/words.mjs.map +0 -1
- package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/utils/escapeRegex.mjs +0 -11
- package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/utils/escapeRegex.mjs.map +0 -1
- package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/utils/lazy.mjs +0 -100
- package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/utils/lazy.mjs.map +0 -1
- package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/utils/tap.mjs +0 -27
- package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/utils/tap.mjs.map +0 -1
- package/esm/node_modules/.pnpm/@mongez_supportive-is@3.0.0/node_modules/@mongez/supportive-is/esm/index.mjs +0 -358
- package/esm/node_modules/.pnpm/@mongez_supportive-is@3.0.0/node_modules/@mongez/supportive-is/esm/index.mjs.map +0 -1
- package/esm/node_modules/.pnpm/amqplib@0.10.9/node_modules/amqplib/channel_api.mjs +0 -28
- package/esm/node_modules/.pnpm/amqplib@0.10.9/node_modules/amqplib/channel_api.mjs.map +0 -1
- package/esm/node_modules/.pnpm/amqplib@0.10.9/node_modules/amqplib/lib/api_args.mjs +0 -241
- package/esm/node_modules/.pnpm/amqplib@0.10.9/node_modules/amqplib/lib/api_args.mjs.map +0 -1
- package/esm/node_modules/.pnpm/amqplib@0.10.9/node_modules/amqplib/lib/bitset.mjs +0 -130
- package/esm/node_modules/.pnpm/amqplib@0.10.9/node_modules/amqplib/lib/bitset.mjs.map +0 -1
- package/esm/node_modules/.pnpm/amqplib@0.10.9/node_modules/amqplib/lib/channel.mjs +0 -302
- package/esm/node_modules/.pnpm/amqplib@0.10.9/node_modules/amqplib/lib/channel.mjs.map +0 -1
- package/esm/node_modules/.pnpm/amqplib@0.10.9/node_modules/amqplib/lib/channel_model.mjs +0 -206
- package/esm/node_modules/.pnpm/amqplib@0.10.9/node_modules/amqplib/lib/channel_model.mjs.map +0 -1
- package/esm/node_modules/.pnpm/amqplib@0.10.9/node_modules/amqplib/lib/codec.mjs +0 -273
- package/esm/node_modules/.pnpm/amqplib@0.10.9/node_modules/amqplib/lib/codec.mjs.map +0 -1
- package/esm/node_modules/.pnpm/amqplib@0.10.9/node_modules/amqplib/lib/connect.mjs +0 -143
- package/esm/node_modules/.pnpm/amqplib@0.10.9/node_modules/amqplib/lib/connect.mjs.map +0 -1
- package/esm/node_modules/.pnpm/amqplib@0.10.9/node_modules/amqplib/lib/connection.mjs +0 -416
- package/esm/node_modules/.pnpm/amqplib@0.10.9/node_modules/amqplib/lib/connection.mjs.map +0 -1
- package/esm/node_modules/.pnpm/amqplib@0.10.9/node_modules/amqplib/lib/credentials.mjs +0 -50
- package/esm/node_modules/.pnpm/amqplib@0.10.9/node_modules/amqplib/lib/credentials.mjs.map +0 -1
- package/esm/node_modules/.pnpm/amqplib@0.10.9/node_modules/amqplib/lib/defs.mjs +0 -4600
- package/esm/node_modules/.pnpm/amqplib@0.10.9/node_modules/amqplib/lib/defs.mjs.map +0 -1
- package/esm/node_modules/.pnpm/amqplib@0.10.9/node_modules/amqplib/lib/error.mjs +0 -29
- package/esm/node_modules/.pnpm/amqplib@0.10.9/node_modules/amqplib/lib/error.mjs.map +0 -1
- package/esm/node_modules/.pnpm/amqplib@0.10.9/node_modules/amqplib/lib/format.mjs +0 -28
- package/esm/node_modules/.pnpm/amqplib@0.10.9/node_modules/amqplib/lib/format.mjs.map +0 -1
- package/esm/node_modules/.pnpm/amqplib@0.10.9/node_modules/amqplib/lib/frame.mjs +0 -130
- package/esm/node_modules/.pnpm/amqplib@0.10.9/node_modules/amqplib/lib/frame.mjs.map +0 -1
- package/esm/node_modules/.pnpm/amqplib@0.10.9/node_modules/amqplib/lib/heartbeat.mjs +0 -40
- package/esm/node_modules/.pnpm/amqplib@0.10.9/node_modules/amqplib/lib/heartbeat.mjs.map +0 -1
- package/esm/node_modules/.pnpm/amqplib@0.10.9/node_modules/amqplib/lib/mux.mjs +0 -86
- package/esm/node_modules/.pnpm/amqplib@0.10.9/node_modules/amqplib/lib/mux.mjs.map +0 -1
- package/esm/node_modules/.pnpm/amqplib@0.10.9/node_modules/amqplib/package.mjs +0 -41
- package/esm/node_modules/.pnpm/amqplib@0.10.9/node_modules/amqplib/package.mjs.map +0 -1
- package/esm/node_modules/.pnpm/buffer-more-ints@1.0.0/node_modules/buffer-more-ints/buffer-more-ints.mjs +0 -360
- package/esm/node_modules/.pnpm/buffer-more-ints@1.0.0/node_modules/buffer-more-ints/buffer-more-ints.mjs.map +0 -1
- package/esm/node_modules/.pnpm/dayjs@1.11.23/node_modules/dayjs/dayjs.min.mjs +0 -305
- package/esm/node_modules/.pnpm/dayjs@1.11.23/node_modules/dayjs/dayjs.min.mjs.map +0 -1
- package/esm/node_modules/.pnpm/querystringify@2.2.0/node_modules/querystringify/index.mjs +0 -80
- package/esm/node_modules/.pnpm/querystringify@2.2.0/node_modules/querystringify/index.mjs.map +0 -1
- package/esm/node_modules/.pnpm/requires-port@1.0.0/node_modules/requires-port/index.mjs +0 -35
- package/esm/node_modules/.pnpm/requires-port@1.0.0/node_modules/requires-port/index.mjs.map +0 -1
- package/esm/node_modules/.pnpm/url-parse@1.5.10/node_modules/url-parse/index.mjs +0 -388
- package/esm/node_modules/.pnpm/url-parse@1.5.10/node_modules/url-parse/index.mjs.map +0 -1
- package/esm/packages/herald/src/communicators/broker-registry.mjs +0 -204
- package/esm/packages/herald/src/communicators/broker-registry.mjs.map +0 -1
- package/esm/packages/herald/src/communicators/broker.mjs +0 -110
- package/esm/packages/herald/src/communicators/broker.mjs.map +0 -1
- package/esm/packages/herald/src/communicators/index.mjs +0 -4
- package/esm/packages/herald/src/decorators/consumable.mjs +0 -36
- package/esm/packages/herald/src/decorators/consumable.mjs.map +0 -1
- package/esm/packages/herald/src/decorators/index.mjs +0 -3
- package/esm/packages/herald/src/drivers/index.mjs +0 -5
- package/esm/packages/herald/src/drivers/rabbitmq/index.mjs +0 -4
- package/esm/packages/herald/src/drivers/rabbitmq/rabbitmq-channel.mjs +0 -403
- package/esm/packages/herald/src/drivers/rabbitmq/rabbitmq-channel.mjs.map +0 -1
- package/esm/packages/herald/src/drivers/rabbitmq/rabbitmq-driver.mjs +0 -303
- package/esm/packages/herald/src/drivers/rabbitmq/rabbitmq-driver.mjs.map +0 -1
- package/esm/packages/herald/src/index.mjs +0 -16
- package/esm/packages/herald/src/message-managers/event-consumer.mjs +0 -76
- package/esm/packages/herald/src/message-managers/event-consumer.mjs.map +0 -1
- package/esm/packages/herald/src/message-managers/event-message.mjs +0 -85
- package/esm/packages/herald/src/message-managers/event-message.mjs.map +0 -1
- package/esm/packages/herald/src/message-managers/index.mjs +0 -4
- package/esm/packages/herald/src/message-managers/prepare-consumer-subscription.mjs +0 -42
- package/esm/packages/herald/src/message-managers/prepare-consumer-subscription.mjs.map +0 -1
- package/esm/packages/herald/src/use-case-broadcast.mjs +0 -30
- package/esm/packages/herald/src/use-case-broadcast.mjs.map +0 -1
- package/esm/packages/herald/src/utils/connect-to-broker.mjs +0 -168
- package/esm/packages/herald/src/utils/connect-to-broker.mjs.map +0 -1
- package/esm/packages/herald/src/utils/index.mjs +0 -3
- package/esm/packages/seal/src/config.mjs +0 -15
- package/esm/packages/seal/src/config.mjs.map +0 -1
- package/esm/packages/seal/src/factory/index.mjs +0 -4
- package/esm/packages/seal/src/factory/validate.mjs +0 -42
- package/esm/packages/seal/src/factory/validate.mjs.map +0 -1
- package/esm/packages/seal/src/factory/validators.mjs +0 -133
- package/esm/packages/seal/src/factory/validators.mjs.map +0 -1
- package/esm/packages/seal/src/helpers/date-helpers.mjs +0 -24
- package/esm/packages/seal/src/helpers/date-helpers.mjs.map +0 -1
- package/esm/packages/seal/src/helpers/get-field-value.mjs +0 -46
- package/esm/packages/seal/src/helpers/get-field-value.mjs.map +0 -1
- package/esm/packages/seal/src/helpers/index.mjs +0 -6
- package/esm/packages/seal/src/helpers/is-empty-value.mjs +0 -10
- package/esm/packages/seal/src/helpers/is-empty-value.mjs.map +0 -1
- package/esm/packages/seal/src/helpers/path-helpers.mjs +0 -12
- package/esm/packages/seal/src/helpers/path-helpers.mjs.map +0 -1
- package/esm/packages/seal/src/helpers/validation-helpers.mjs +0 -78
- package/esm/packages/seal/src/helpers/validation-helpers.mjs.map +0 -1
- package/esm/packages/seal/src/index.mjs +0 -88
- package/esm/packages/seal/src/mutators/array-mutators.mjs +0 -32
- package/esm/packages/seal/src/mutators/array-mutators.mjs.map +0 -1
- package/esm/packages/seal/src/mutators/boolean-mutators.mjs +0 -40
- package/esm/packages/seal/src/mutators/boolean-mutators.mjs.map +0 -1
- package/esm/packages/seal/src/mutators/date-mutators.mjs +0 -94
- package/esm/packages/seal/src/mutators/date-mutators.mjs.map +0 -1
- package/esm/packages/seal/src/mutators/index.mjs +0 -9
- package/esm/packages/seal/src/mutators/number-mutators.mjs +0 -52
- package/esm/packages/seal/src/mutators/number-mutators.mjs.map +0 -1
- package/esm/packages/seal/src/mutators/object-mutators.mjs +0 -30
- package/esm/packages/seal/src/mutators/object-mutators.mjs.map +0 -1
- package/esm/packages/seal/src/mutators/scalar-mutators.mjs +0 -9
- package/esm/packages/seal/src/mutators/scalar-mutators.mjs.map +0 -1
- package/esm/packages/seal/src/mutators/string-mutators.mjs +0 -186
- package/esm/packages/seal/src/mutators/string-mutators.mjs.map +0 -1
- package/esm/packages/seal/src/object.mjs +0 -13
- package/esm/packages/seal/src/object.mjs.map +0 -1
- package/esm/packages/seal/src/rules/array/array-rules.mjs +0 -41
- package/esm/packages/seal/src/rules/array/array-rules.mjs.map +0 -1
- package/esm/packages/seal/src/rules/array/index.mjs +0 -3
- package/esm/packages/seal/src/rules/color/color-rules.mjs +0 -104
- package/esm/packages/seal/src/rules/color/color-rules.mjs.map +0 -1
- package/esm/packages/seal/src/rules/color/index.mjs +0 -3
- package/esm/packages/seal/src/rules/common/enum.mjs +0 -77
- package/esm/packages/seal/src/rules/common/enum.mjs.map +0 -1
- package/esm/packages/seal/src/rules/common/equals-field-rules.mjs +0 -42
- package/esm/packages/seal/src/rules/common/equals-field-rules.mjs.map +0 -1
- package/esm/packages/seal/src/rules/common/index.mjs +0 -8
- package/esm/packages/seal/src/rules/common/instanceof.mjs +0 -23
- package/esm/packages/seal/src/rules/common/instanceof.mjs.map +0 -1
- package/esm/packages/seal/src/rules/common/literal.mjs +0 -31
- package/esm/packages/seal/src/rules/common/literal.mjs.map +0 -1
- package/esm/packages/seal/src/rules/common/type-rules.mjs +0 -97
- package/esm/packages/seal/src/rules/common/type-rules.mjs.map +0 -1
- package/esm/packages/seal/src/rules/common/unknown-key.mjs +0 -25
- package/esm/packages/seal/src/rules/common/unknown-key.mjs.map +0 -1
- package/esm/packages/seal/src/rules/conditional/forbidden-if-rules.mjs +0 -116
- package/esm/packages/seal/src/rules/conditional/forbidden-if-rules.mjs.map +0 -1
- package/esm/packages/seal/src/rules/conditional/index.mjs +0 -12
- package/esm/packages/seal/src/rules/conditional/present-if-rules.mjs +0 -97
- package/esm/packages/seal/src/rules/conditional/present-if-rules.mjs.map +0 -1
- package/esm/packages/seal/src/rules/conditional/present-unless-rules.mjs +0 -30
- package/esm/packages/seal/src/rules/conditional/present-unless-rules.mjs.map +0 -1
- package/esm/packages/seal/src/rules/conditional/present-with-rules.mjs +0 -76
- package/esm/packages/seal/src/rules/conditional/present-with-rules.mjs.map +0 -1
- package/esm/packages/seal/src/rules/conditional/present-without-rules.mjs +0 -76
- package/esm/packages/seal/src/rules/conditional/present-without-rules.mjs.map +0 -1
- package/esm/packages/seal/src/rules/conditional/required-if-rules.mjs +0 -204
- package/esm/packages/seal/src/rules/conditional/required-if-rules.mjs.map +0 -1
- package/esm/packages/seal/src/rules/conditional/required-unless-rules.mjs +0 -31
- package/esm/packages/seal/src/rules/conditional/required-unless-rules.mjs.map +0 -1
- package/esm/packages/seal/src/rules/conditional/required-when-rule.mjs +0 -32
- package/esm/packages/seal/src/rules/conditional/required-when-rule.mjs.map +0 -1
- package/esm/packages/seal/src/rules/conditional/required-with-rules.mjs +0 -67
- package/esm/packages/seal/src/rules/conditional/required-with-rules.mjs.map +0 -1
- package/esm/packages/seal/src/rules/conditional/required-without-rules.mjs +0 -67
- package/esm/packages/seal/src/rules/conditional/required-without-rules.mjs.map +0 -1
- package/esm/packages/seal/src/rules/core/equal.mjs +0 -22
- package/esm/packages/seal/src/rules/core/equal.mjs.map +0 -1
- package/esm/packages/seal/src/rules/core/forbidden.mjs +0 -20
- package/esm/packages/seal/src/rules/core/forbidden.mjs.map +0 -1
- package/esm/packages/seal/src/rules/core/index.mjs +0 -7
- package/esm/packages/seal/src/rules/core/required.mjs +0 -36
- package/esm/packages/seal/src/rules/core/required.mjs.map +0 -1
- package/esm/packages/seal/src/rules/core/union.mjs +0 -32
- package/esm/packages/seal/src/rules/core/union.mjs.map +0 -1
- package/esm/packages/seal/src/rules/core/when.mjs +0 -37
- package/esm/packages/seal/src/rules/core/when.mjs.map +0 -1
- package/esm/packages/seal/src/rules/date/date-comparison-rules.mjs +0 -78
- package/esm/packages/seal/src/rules/date/date-comparison-rules.mjs.map +0 -1
- package/esm/packages/seal/src/rules/date/date-day-rules.mjs +0 -49
- package/esm/packages/seal/src/rules/date/date-day-rules.mjs.map +0 -1
- package/esm/packages/seal/src/rules/date/date-field-comparison-rules.mjs +0 -82
- package/esm/packages/seal/src/rules/date/date-field-comparison-rules.mjs.map +0 -1
- package/esm/packages/seal/src/rules/date/date-period-rules.mjs +0 -401
- package/esm/packages/seal/src/rules/date/date-period-rules.mjs.map +0 -1
- package/esm/packages/seal/src/rules/date/date-relative-rules.mjs +0 -55
- package/esm/packages/seal/src/rules/date/date-relative-rules.mjs.map +0 -1
- package/esm/packages/seal/src/rules/date/date-special-rules.mjs +0 -58
- package/esm/packages/seal/src/rules/date/date-special-rules.mjs.map +0 -1
- package/esm/packages/seal/src/rules/date/date.mjs +0 -235
- package/esm/packages/seal/src/rules/date/date.mjs.map +0 -1
- package/esm/packages/seal/src/rules/date/index.mjs +0 -9
- package/esm/packages/seal/src/rules/file/dimensions.mjs +0 -3
- package/esm/packages/seal/src/rules/file/file-size.mjs +0 -3
- package/esm/packages/seal/src/rules/file/index.mjs +0 -4
- package/esm/packages/seal/src/rules/index.mjs +0 -54
- package/esm/packages/seal/src/rules/length/index.mjs +0 -3
- package/esm/packages/seal/src/rules/length/length-rules.mjs +0 -98
- package/esm/packages/seal/src/rules/length/length-rules.mjs.map +0 -1
- package/esm/packages/seal/src/rules/number/index.mjs +0 -3
- package/esm/packages/seal/src/rules/number/number-rules.mjs +0 -197
- package/esm/packages/seal/src/rules/number/number-rules.mjs.map +0 -1
- package/esm/packages/seal/src/rules/scalar/accepted-rule.mjs +0 -123
- package/esm/packages/seal/src/rules/scalar/accepted-rule.mjs.map +0 -1
- package/esm/packages/seal/src/rules/scalar/declined-rule.mjs +0 -123
- package/esm/packages/seal/src/rules/scalar/declined-rule.mjs.map +0 -1
- package/esm/packages/seal/src/rules/scalar/index.mjs +0 -4
- package/esm/packages/seal/src/rules/string/alpha.mjs +0 -41
- package/esm/packages/seal/src/rules/string/alpha.mjs.map +0 -1
- package/esm/packages/seal/src/rules/string/credit-card.mjs +0 -32
- package/esm/packages/seal/src/rules/string/credit-card.mjs.map +0 -1
- package/esm/packages/seal/src/rules/string/email.mjs +0 -20
- package/esm/packages/seal/src/rules/string/email.mjs.map +0 -1
- package/esm/packages/seal/src/rules/string/id-formats.mjs +0 -104
- package/esm/packages/seal/src/rules/string/id-formats.mjs.map +0 -1
- package/esm/packages/seal/src/rules/string/index.mjs +0 -13
- package/esm/packages/seal/src/rules/string/ip.mjs +0 -66
- package/esm/packages/seal/src/rules/string/ip.mjs.map +0 -1
- package/esm/packages/seal/src/rules/string/matches.mjs +0 -4
- package/esm/packages/seal/src/rules/string/pattern.mjs +0 -20
- package/esm/packages/seal/src/rules/string/pattern.mjs.map +0 -1
- package/esm/packages/seal/src/rules/string/string-comparison.mjs +0 -56
- package/esm/packages/seal/src/rules/string/string-comparison.mjs.map +0 -1
- package/esm/packages/seal/src/rules/string/strong-password-rule.mjs +0 -31
- package/esm/packages/seal/src/rules/string/strong-password-rule.mjs.map +0 -1
- package/esm/packages/seal/src/rules/string/url.mjs +0 -23
- package/esm/packages/seal/src/rules/string/url.mjs.map +0 -1
- package/esm/packages/seal/src/rules/string/without-whitespace.mjs +0 -19
- package/esm/packages/seal/src/rules/string/without-whitespace.mjs.map +0 -1
- package/esm/packages/seal/src/standard-schema/json-schema.mjs +0 -81
- package/esm/packages/seal/src/standard-schema/json-schema.mjs.map +0 -1
- package/esm/packages/seal/src/standard-schema/map-result.mjs +0 -26
- package/esm/packages/seal/src/standard-schema/map-result.mjs.map +0 -1
- package/esm/packages/seal/src/string.mjs +0 -13
- package/esm/packages/seal/src/string.mjs.map +0 -1
- package/esm/packages/seal/src/types/date-types.mjs +0 -17
- package/esm/packages/seal/src/types/date-types.mjs.map +0 -1
- package/esm/packages/seal/src/validators/any-validator.mjs +0 -38
- package/esm/packages/seal/src/validators/any-validator.mjs.map +0 -1
- package/esm/packages/seal/src/validators/array-validator.mjs +0 -186
- package/esm/packages/seal/src/validators/array-validator.mjs.map +0 -1
- package/esm/packages/seal/src/validators/base-validator.mjs +0 -720
- package/esm/packages/seal/src/validators/base-validator.mjs.map +0 -1
- package/esm/packages/seal/src/validators/boolean-validator.mjs +0 -175
- package/esm/packages/seal/src/validators/boolean-validator.mjs.map +0 -1
- package/esm/packages/seal/src/validators/computed-validator.mjs +0 -118
- package/esm/packages/seal/src/validators/computed-validator.mjs.map +0 -1
- package/esm/packages/seal/src/validators/date-validator.mjs +0 -640
- package/esm/packages/seal/src/validators/date-validator.mjs.map +0 -1
- package/esm/packages/seal/src/validators/discriminated-union-validator.mjs +0 -138
- package/esm/packages/seal/src/validators/discriminated-union-validator.mjs.map +0 -1
- package/esm/packages/seal/src/validators/float-validator.mjs +0 -18
- package/esm/packages/seal/src/validators/float-validator.mjs.map +0 -1
- package/esm/packages/seal/src/validators/index.mjs +0 -28
- package/esm/packages/seal/src/validators/instanceof-validator.mjs +0 -64
- package/esm/packages/seal/src/validators/instanceof-validator.mjs.map +0 -1
- package/esm/packages/seal/src/validators/int-validator.mjs +0 -30
- package/esm/packages/seal/src/validators/int-validator.mjs.map +0 -1
- package/esm/packages/seal/src/validators/lazy-validator.mjs +0 -87
- package/esm/packages/seal/src/validators/lazy-validator.mjs.map +0 -1
- package/esm/packages/seal/src/validators/literal-validator.mjs +0 -72
- package/esm/packages/seal/src/validators/literal-validator.mjs.map +0 -1
- package/esm/packages/seal/src/validators/managed-validator.mjs +0 -39
- package/esm/packages/seal/src/validators/managed-validator.mjs.map +0 -1
- package/esm/packages/seal/src/validators/methods/equality-conditional-methods.mjs +0 -129
- package/esm/packages/seal/src/validators/methods/equality-conditional-methods.mjs.map +0 -1
- package/esm/packages/seal/src/validators/methods/forbidden-methods.mjs +0 -131
- package/esm/packages/seal/src/validators/methods/forbidden-methods.mjs.map +0 -1
- package/esm/packages/seal/src/validators/methods/present-methods.mjs +0 -235
- package/esm/packages/seal/src/validators/methods/present-methods.mjs.map +0 -1
- package/esm/packages/seal/src/validators/methods/required-methods.mjs +0 -347
- package/esm/packages/seal/src/validators/methods/required-methods.mjs.map +0 -1
- package/esm/packages/seal/src/validators/number-validator.mjs +0 -331
- package/esm/packages/seal/src/validators/number-validator.mjs.map +0 -1
- package/esm/packages/seal/src/validators/numeric-validator.mjs +0 -27
- package/esm/packages/seal/src/validators/numeric-validator.mjs.map +0 -1
- package/esm/packages/seal/src/validators/object-validator.mjs +0 -445
- package/esm/packages/seal/src/validators/object-validator.mjs.map +0 -1
- package/esm/packages/seal/src/validators/primitive-validator.mjs +0 -88
- package/esm/packages/seal/src/validators/primitive-validator.mjs.map +0 -1
- package/esm/packages/seal/src/validators/record-validator.mjs +0 -112
- package/esm/packages/seal/src/validators/record-validator.mjs.map +0 -1
- package/esm/packages/seal/src/validators/scalar-validator.mjs +0 -173
- package/esm/packages/seal/src/validators/scalar-validator.mjs.map +0 -1
- package/esm/packages/seal/src/validators/string-validator.mjs +0 -459
- package/esm/packages/seal/src/validators/string-validator.mjs.map +0 -1
- package/esm/packages/seal/src/validators/tuple-validator.mjs +0 -134
- package/esm/packages/seal/src/validators/tuple-validator.mjs.map +0 -1
- package/esm/packages/seal/src/validators/union-validator.mjs +0 -66
- package/esm/packages/seal/src/validators/union-validator.mjs.map +0 -1
package/llms-full.txt
CHANGED
|
@@ -25,7 +25,7 @@ import { Notification } from "app/notifications/models/notification/notification
|
|
|
25
25
|
|
|
26
26
|
const config: NotificationConfig = {
|
|
27
27
|
channels: {
|
|
28
|
-
mail:
|
|
28
|
+
mail: mailChannel({ from: "no-reply@store.com" }),
|
|
29
29
|
database: inApp.configure({ model: Notification }),
|
|
30
30
|
},
|
|
31
31
|
};
|
|
@@ -40,17 +40,17 @@ The `database` channel is returned by `inApp.configure({ model | repository })`
|
|
|
40
40
|
```ts
|
|
41
41
|
const config: NotificationConfig = {
|
|
42
42
|
channels: {
|
|
43
|
-
mail:
|
|
43
|
+
mail: mailChannel({ from }),
|
|
44
44
|
database: inApp.configure({ model: Notification }),
|
|
45
45
|
|
|
46
46
|
// custom channels
|
|
47
|
-
discord:
|
|
47
|
+
discord: discordChannel(), // defineChannel + declare module
|
|
48
48
|
},
|
|
49
49
|
|
|
50
50
|
// optional gates — both app-owned; package ships no defaults
|
|
51
|
-
preferences: userPreferences,
|
|
52
|
-
rateLimit,
|
|
53
|
-
queue: heraldQueue(),
|
|
51
|
+
preferences: userPreferences, // drops channels recipient muted
|
|
52
|
+
rateLimit, // drops channels over budget
|
|
53
|
+
queue: heraldQueue(), // backs `.queue()` (needs @warlock.js/herald)
|
|
54
54
|
};
|
|
55
55
|
|
|
56
56
|
export default config;
|
|
@@ -124,7 +124,7 @@ Dropped channels fire a `skipped` event with reason `"rate-limit"`. `force` does
|
|
|
124
124
|
```ts
|
|
125
125
|
import { getNotificationConfig } from "@warlock.js/notifications";
|
|
126
126
|
|
|
127
|
-
const cfg = getNotificationConfig();
|
|
127
|
+
const cfg = getNotificationConfig(); // throws NotificationsNotConfiguredError if unset
|
|
128
128
|
```
|
|
129
129
|
|
|
130
130
|
## Tests
|
|
@@ -200,12 +200,12 @@ Now `notify.discord(user, { content: "🎉" })` works, and `discord:` is a valid
|
|
|
200
200
|
|
|
201
201
|
## `route` resolution
|
|
202
202
|
|
|
203
|
-
| What `route` returns | Effect
|
|
204
|
-
|
|
205
|
-
| `string`
|
|
206
|
-
| `{ id: Id }`
|
|
207
|
-
| `undefined`
|
|
208
|
-
| `route` omitted
|
|
203
|
+
| What `route` returns | Effect |
|
|
204
|
+
| -------------------- | ----------------------------------------------------------------- |
|
|
205
|
+
| `string` | Used directly as the address (`"user@example.com"`, webhook URL). |
|
|
206
|
+
| `{ id: Id }` | The recipient's storage id — for database/internal channels. |
|
|
207
|
+
| `undefined` | Dispatcher falls back to `{ id: notifiable.id }`. |
|
|
208
|
+
| `route` omitted | Same as returning `undefined` — `{ id }` fallback. |
|
|
209
209
|
|
|
210
210
|
For raw-target ad-hoc sends (`notify.discord("https://hooks.../foo", payload)`), the raw string wins over `route()`.
|
|
211
211
|
|
|
@@ -233,7 +233,9 @@ import type { WebClient } from "@slack/web-api";
|
|
|
233
233
|
let Slack: typeof import("@slack/web-api");
|
|
234
234
|
let isModuleExists: boolean | null = null;
|
|
235
235
|
|
|
236
|
-
async function loadSlack() {
|
|
236
|
+
async function loadSlack() {
|
|
237
|
+
/* try/catch await import; set flag */
|
|
238
|
+
}
|
|
237
239
|
loadSlack();
|
|
238
240
|
|
|
239
241
|
export const slackChannel = (config: { token: string }) =>
|
|
@@ -282,11 +284,11 @@ defineNotification<Data>({
|
|
|
282
284
|
|
|
283
285
|
Returns `{ send, queue, only }`:
|
|
284
286
|
|
|
285
|
-
| Method
|
|
286
|
-
|
|
287
|
-
| `.send`
|
|
288
|
-
| `.queue`
|
|
289
|
-
| `.only(...channels)` | returns `{send, queue, only}` | Restrict dispatch to a subset of channels.
|
|
287
|
+
| Method | Signature | What it does |
|
|
288
|
+
| -------------------- | ----------------------------- | -------------------------------------------------------------- |
|
|
289
|
+
| `.send` | `(to, data, options?)` | Render + dispatch synchronously. |
|
|
290
|
+
| `.queue` | `(to, data, options?)` | Render + enqueue. Throws if no queue dispatcher is configured. |
|
|
291
|
+
| `.only(...channels)` | returns `{send, queue, only}` | Restrict dispatch to a subset of channels. |
|
|
290
292
|
|
|
291
293
|
`to` accepts a `Notifiable` OR a `Notifiable[]`. Fan-out emits one render+dispatch per recipient with per-recipient + per-channel `Promise.allSettled` (one failure does not abort the others).
|
|
292
294
|
|
|
@@ -308,9 +310,7 @@ await welcome.send(user, { name: "Hasan" });
|
|
|
308
310
|
export const orderShipped = defineNotification<{ order: Order }>({
|
|
309
311
|
type: "order.shipped",
|
|
310
312
|
via: (_data, to) =>
|
|
311
|
-
to.get("telegram_chat_id")
|
|
312
|
-
? ["database", "telegram"]
|
|
313
|
-
: ["database", "mail"],
|
|
313
|
+
to.get("telegram_chat_id") ? ["database", "telegram"] : ["database", "mail"],
|
|
314
314
|
database: ({ order }) => ({ title: `Order #${order.number} shipped` }),
|
|
315
315
|
mail: ({ order }, to) => ({
|
|
316
316
|
subject: `Order #${order.number} shipped`,
|
|
@@ -323,16 +323,15 @@ export const orderShipped = defineNotification<{ order: Order }>({
|
|
|
323
323
|
## The renderer's 3rd arg — `RenderContext`
|
|
324
324
|
|
|
325
325
|
```ts
|
|
326
|
-
mail: ({ campaignId }, to, { locale = "en", meta }) => ({
|
|
326
|
+
mail: (({ campaignId }, to, { locale = "en", meta }) => ({
|
|
327
327
|
subject: subjectsByLocale[locale],
|
|
328
|
-
html:
|
|
328
|
+
html: htmlByLocale[locale],
|
|
329
329
|
}),
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
});
|
|
330
|
+
// usage:
|
|
331
|
+
await marketing.queue(user, payload, {
|
|
332
|
+
locale: user.get("locale"),
|
|
333
|
+
meta: { campaignId, source: "blast" },
|
|
334
|
+
}));
|
|
336
335
|
```
|
|
337
336
|
|
|
338
337
|
`ctx` carries `locale` + `meta` from `SendOptions`. `meta` flows through to every observability event too.
|
|
@@ -343,7 +342,7 @@ The `database` renderer may OMIT `type` — the dispatcher injects `def.type` au
|
|
|
343
342
|
|
|
344
343
|
```ts
|
|
345
344
|
defineNotification({
|
|
346
|
-
type: "order.shipped",
|
|
345
|
+
type: "order.shipped", // ← single source of truth
|
|
347
346
|
via: ["database"],
|
|
348
347
|
database: () => ({ title: "Shipped" }), // type omitted; dispatcher injects "order.shipped"
|
|
349
348
|
});
|
|
@@ -373,14 +372,14 @@ await orderShipped.queue(user, { order }, { delay: "10m" });
|
|
|
373
372
|
|
|
374
373
|
## SendOptions
|
|
375
374
|
|
|
376
|
-
| Field
|
|
377
|
-
|
|
378
|
-
| `delay`
|
|
379
|
-
| `locale`
|
|
380
|
-
| `meta`
|
|
381
|
-
| `idempotencyKey` | Injected into the database payload (dedupe via unique index).
|
|
382
|
-
| `force`
|
|
383
|
-
| `type`
|
|
375
|
+
| Field | Effect |
|
|
376
|
+
| ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
377
|
+
| `delay` | Reserved — `"10m"` / `"3d"` / `600` (seconds). NOT honored yet: both `.send()` and the current `.queue()` worker dispatch immediately; delay-aware delivery is a follow-up. |
|
|
378
|
+
| `locale` | Passed to renderers via `RenderContext.locale`. |
|
|
379
|
+
| `meta` | Passed to renderers + included in every observability event. |
|
|
380
|
+
| `idempotencyKey` | Injected into the database payload (dedupe via unique index). |
|
|
381
|
+
| `force` | Bypass `PreferenceProvider`. Does NOT bypass `RateLimiter`. |
|
|
382
|
+
| `type` | Ignored by `defineNotification` — see `send-ad-hoc` for ad-hoc gating. |
|
|
384
383
|
|
|
385
384
|
## Failure isolation
|
|
386
385
|
|
|
@@ -409,7 +408,7 @@ Multi-channel notifications for Warlock.js. **Define once, fire anywhere.**
|
|
|
409
408
|
|
|
410
409
|
You have an event (`order.shipped`, `comment.mentioned`, `password.changed`) and one or more recipients. You want to address them through any combination of channels (mail, in-app, push, ...) with one render. That's what this package is.
|
|
411
410
|
|
|
412
|
-
It is NOT a queue, a template engine, a transport library, or an analytics pipeline — it orchestrates
|
|
411
|
+
It is NOT a queue, a template engine, a transport library, or an analytics pipeline — it orchestrates _over_ the transports cascade / core / herald / bridges already provide.
|
|
413
412
|
|
|
414
413
|
## Server-only package
|
|
415
414
|
|
|
@@ -432,7 +431,7 @@ import { Notification } from "app/notifications/models/notification/notification
|
|
|
432
431
|
|
|
433
432
|
const config: NotificationConfig = {
|
|
434
433
|
channels: {
|
|
435
|
-
mail:
|
|
434
|
+
mail: mailChannel({ from: "no-reply@store.com" }),
|
|
436
435
|
database: inApp.configure({ model: Notification }),
|
|
437
436
|
},
|
|
438
437
|
};
|
|
@@ -465,7 +464,7 @@ await orderShipped.send(user, { orderId: order.id, number: order.number });
|
|
|
465
464
|
await notify.mail(user, { subject: "Welcome", html: "<p>Hi!</p>" });
|
|
466
465
|
|
|
467
466
|
const unread = await inApp.listUnread(user);
|
|
468
|
-
const badge
|
|
467
|
+
const badge = await inApp.countUnread(user);
|
|
469
468
|
await inApp.markAsRead(user, "ntf_123");
|
|
470
469
|
```
|
|
471
470
|
|
|
@@ -475,15 +474,15 @@ await inApp.markAsRead(user, "ntf_123");
|
|
|
475
474
|
|
|
476
475
|
## Phase 1 vs Phase 2
|
|
477
476
|
|
|
478
|
-
| Channel
|
|
479
|
-
|
|
480
|
-
| `mail`
|
|
481
|
-
| `database` | 1 ✅
|
|
482
|
-
| `whatsapp` | 2
|
|
483
|
-
| `telegram` | 2
|
|
484
|
-
| `slack`
|
|
485
|
-
| `push`
|
|
486
|
-
| your own
|
|
477
|
+
| Channel | Phase | How |
|
|
478
|
+
| ---------- | ----- | ----------------------------------------- |
|
|
479
|
+
| `mail` | 1 ✅ | core `sendMail` |
|
|
480
|
+
| `database` | 1 ✅ | cascade repo (recipient-scoped reads) |
|
|
481
|
+
| `whatsapp` | 2 | bridges `MessageProvider` |
|
|
482
|
+
| `telegram` | 2 | bridges `MessageProvider` |
|
|
483
|
+
| `slack` | 2 | bridges `MessageProvider` |
|
|
484
|
+
| `push` | 2 | bridges `PushProvider` |
|
|
485
|
+
| your own | 1 ✅ | `defineChannel` + 3-line `declare module` |
|
|
487
486
|
|
|
488
487
|
## See also
|
|
489
488
|
|
|
@@ -512,27 +511,31 @@ import { notifications } from "@warlock.js/notifications";
|
|
|
512
511
|
|
|
513
512
|
// latency + delivery, keyed by recipient
|
|
514
513
|
notifications.on("sent", ({ channel, notifiable, durationMs, options }) =>
|
|
515
|
-
metrics.timing(`notif.${channel}.sent`, durationMs, { userId: notifiable?.id, ...options.meta })
|
|
514
|
+
metrics.timing(`notif.${channel}.sent`, durationMs, { userId: notifiable?.id, ...options.meta }),
|
|
515
|
+
);
|
|
516
516
|
|
|
517
517
|
notifications.on("failed", ({ channel, notifiable, error }) =>
|
|
518
|
-
log.error(`notif.${channel}`, error, { userId: notifiable?.id })
|
|
518
|
+
log.error(`notif.${channel}`, error, { userId: notifiable?.id }),
|
|
519
|
+
);
|
|
519
520
|
|
|
520
521
|
notifications.on("skipped", ({ channel, reason }) =>
|
|
521
|
-
metrics.inc(`notif.${channel}.skipped.${reason}`)
|
|
522
|
+
metrics.inc(`notif.${channel}.skipped.${reason}`),
|
|
523
|
+
);
|
|
522
524
|
|
|
523
525
|
// pair `sending` → terminal by dispatchId — open a span / arm a hung-send watchdog
|
|
524
526
|
notifications.on("sending", ({ dispatchId, channel, notifiable }) =>
|
|
525
|
-
tracer.open(dispatchId, { channel, userId: notifiable?.id })
|
|
527
|
+
tracer.open(dispatchId, { channel, userId: notifiable?.id }),
|
|
528
|
+
);
|
|
526
529
|
```
|
|
527
530
|
|
|
528
531
|
## Events
|
|
529
532
|
|
|
530
|
-
| Event
|
|
531
|
-
|
|
532
|
-
| `sending` | Gates passed; about to hit the transport (sync) / enqueue (queue) | `{ dispatchId, channel, notifiable?, payload, options }`
|
|
533
|
-
| `sent`
|
|
534
|
-
| `failed`
|
|
535
|
-
| `skipped` | A pre-send gate dropped this channel
|
|
533
|
+
| Event | Fires when | Payload |
|
|
534
|
+
| --------- | ----------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ |
|
|
535
|
+
| `sending` | Gates passed; about to hit the transport (sync) / enqueue (queue) | `{ dispatchId, channel, notifiable?, payload, options }` |
|
|
536
|
+
| `sent` | Channel dispatched OR job enqueued | `{ dispatchId, channel, notifiable?, payload, options, durationMs }` |
|
|
537
|
+
| `failed` | `channel.send` (or `queue.dispatch`) threw | `{ dispatchId, channel, notifiable?, payload, error, options, durationMs }` |
|
|
538
|
+
| `skipped` | A pre-send gate dropped this channel | `{ dispatchId, channel, notifiable?, reason, options }` — `reason: "preference" \| "rate-limit"` |
|
|
536
539
|
|
|
537
540
|
`notifiable` is the recipient **model** (undefined only for raw-target ad-hoc sends like `notify.mail("x@y.com", …)`) — read `notifiable?.id` / `notifiable?.get(...)` to key your metrics or logs.
|
|
538
541
|
|
|
@@ -716,7 +719,7 @@ Pass a string instead of a model to use the string as the route directly:
|
|
|
716
719
|
|
|
717
720
|
```ts
|
|
718
721
|
await notify.mail("guest@example.com", { subject: "Receipt", html: "<p>…</p>" });
|
|
719
|
-
await notify.whatsapp("+201234567890", { body: "Promo: 20% off!" });
|
|
722
|
+
await notify.whatsapp("+201234567890", { body: "Promo: 20% off!" }); // Phase 2
|
|
720
723
|
```
|
|
721
724
|
|
|
722
725
|
When the recipient isn't a model, `PreferenceProvider` and `RateLimiter` are skipped — there's no `Notifiable` to consult.
|
|
@@ -758,14 +761,14 @@ await notify.slack(staff, { text: "Deploy starting" });
|
|
|
758
761
|
|
|
759
762
|
## SendOptions (3rd arg)
|
|
760
763
|
|
|
761
|
-
| Field
|
|
762
|
-
|
|
763
|
-
| `delay`
|
|
764
|
-
| `locale`
|
|
765
|
-
| `meta`
|
|
766
|
-
| `idempotencyKey` | Injected into the database payload (dedupe).
|
|
767
|
-
| `force`
|
|
768
|
-
| `type`
|
|
764
|
+
| Field | Effect |
|
|
765
|
+
| ---------------- | ------------------------------------------------------------------- |
|
|
766
|
+
| `delay` | Reserved for `.queue` paths; not used by `notify.<channel>` (sync). |
|
|
767
|
+
| `locale` | Forwarded to the channel's `send({ options })`. |
|
|
768
|
+
| `meta` | Forwarded to the channel + included in every observability event. |
|
|
769
|
+
| `idempotencyKey` | Injected into the database payload (dedupe). |
|
|
770
|
+
| `force` | Bypass `PreferenceProvider`. Does NOT bypass `RateLimiter`. |
|
|
771
|
+
| `type` | Notification type for gating (ad-hoc only). |
|
|
769
772
|
|
|
770
773
|
## Failure surfaces
|
|
771
774
|
|
|
@@ -864,7 +867,9 @@ abstract class DatabaseNotification extends Model implements NotificationContrac
|
|
|
864
867
|
class BaseNotificationsRepository extends RepositoryManager {
|
|
865
868
|
// constructor resolves the model's columnMap → builds `filterBy` +
|
|
866
869
|
// createFor / markRead / markUnread / deleteFor from it.
|
|
867
|
-
public createFor(recipientId, input, tenantId?)
|
|
870
|
+
public createFor(recipientId, input, tenantId?) {
|
|
871
|
+
/* one insert, starts unread */
|
|
872
|
+
}
|
|
868
873
|
}
|
|
869
874
|
```
|
|
870
875
|
|
|
@@ -877,9 +882,9 @@ class BaseNotificationsRepository extends RepositoryManager {
|
|
|
877
882
|
```ts
|
|
878
883
|
export type NotificationColumnMap = {
|
|
879
884
|
recipient?: string; // recipient FK. Default "user_id"
|
|
880
|
-
tenant?: string;
|
|
881
|
-
readAt?: string;
|
|
882
|
-
isRead?: string;
|
|
885
|
+
tenant?: string; // multi-tenant scope, written from the recipient. Omit → single-tenant
|
|
886
|
+
readAt?: string; // read-timestamp column
|
|
887
|
+
isRead?: string; // read-flag column (indexed)
|
|
883
888
|
};
|
|
884
889
|
```
|
|
885
890
|
|
|
@@ -981,12 +986,12 @@ export default Migration.create(Notification, notificationColumns(Notification))
|
|
|
981
986
|
`notificationColumns(Notification)` reads the model's `columnMap` and returns the
|
|
982
987
|
matching columns:
|
|
983
988
|
|
|
984
|
-
| columnMap
|
|
985
|
-
|
|
986
|
-
| _(none / default)_
|
|
987
|
-
| `{ tenant: "organization_id", readAt: "read_at" }` | adds `organization_id`; read_at-only
|
|
988
|
-
| `{ isRead: "is_read" }`
|
|
989
|
-
| `{ isRead: "is_read", readAt: "read_at" }`
|
|
989
|
+
| columnMap | Columns |
|
|
990
|
+
| -------------------------------------------------- | --------------------------------------------------------------------------- |
|
|
991
|
+
| _(none / default)_ | `user_id`, `type`, `title`, `body`, `payload`, `read_at`, `idempotency_key` |
|
|
992
|
+
| `{ tenant: "organization_id", readAt: "read_at" }` | adds `organization_id`; read_at-only |
|
|
993
|
+
| `{ isRead: "is_read" }` | swaps `read_at` for `is_read` (indexed boolean) |
|
|
994
|
+
| `{ isRead: "is_read", readAt: "read_at" }` | both read-state columns |
|
|
990
995
|
|
|
991
996
|
The recipient / tenant / read-state column NAMES come from `columnMap`; `type` /
|
|
992
997
|
`title` / `body` / `payload` / `idempotency_key` are fixed. `id` / `createdAt` /
|
|
@@ -999,7 +1004,10 @@ are `bigint`, `integer`, or strings, pass `idType`; it is applied to every
|
|
|
999
1004
|
identifier column the factory creates:
|
|
1000
1005
|
|
|
1001
1006
|
```ts
|
|
1002
|
-
export default Migration.create(
|
|
1007
|
+
export default Migration.create(
|
|
1008
|
+
Notification,
|
|
1009
|
+
notificationColumns(Notification, { idType: "bigint" }),
|
|
1010
|
+
);
|
|
1003
1011
|
```
|
|
1004
1012
|
|
|
1005
1013
|
## With extras — spread + extend
|
package/package.json
CHANGED
|
@@ -5,18 +5,19 @@
|
|
|
5
5
|
"environment": "server"
|
|
6
6
|
},
|
|
7
7
|
"dependencies": {
|
|
8
|
-
"@warlock.js/cache": "5.
|
|
9
|
-
"@warlock.js/cascade": "5.
|
|
10
|
-
"@warlock.js/core": "5.
|
|
11
|
-
"@warlock.js/logger": "5.
|
|
12
|
-
},
|
|
13
|
-
"optionalDependencies": {
|
|
14
|
-
"@warlock.js/herald": "5.30.0"
|
|
8
|
+
"@warlock.js/cache": "5.32.0",
|
|
9
|
+
"@warlock.js/cascade": "5.32.0",
|
|
10
|
+
"@warlock.js/core": "5.32.0",
|
|
11
|
+
"@warlock.js/logger": "5.32.0"
|
|
15
12
|
},
|
|
16
13
|
"peerDependencies": {
|
|
17
|
-
"@warlock.js/
|
|
14
|
+
"@warlock.js/herald": "5.32.0",
|
|
15
|
+
"@warlock.js/queue": "5.32.0"
|
|
18
16
|
},
|
|
19
17
|
"peerDependenciesMeta": {
|
|
18
|
+
"@warlock.js/herald": {
|
|
19
|
+
"optional": true
|
|
20
|
+
},
|
|
20
21
|
"@warlock.js/queue": {
|
|
21
22
|
"optional": true
|
|
22
23
|
}
|
|
@@ -36,7 +37,7 @@
|
|
|
36
37
|
],
|
|
37
38
|
"author": "hassanzohdy",
|
|
38
39
|
"license": "MIT",
|
|
39
|
-
"version": "5.
|
|
40
|
+
"version": "5.32.0",
|
|
40
41
|
"main": "./cjs/index.cjs",
|
|
41
42
|
"module": "./esm/index.mjs",
|
|
42
43
|
"types": "./esm/index.d.mts",
|
|
@@ -17,7 +17,7 @@ import { Notification } from "app/notifications/models/notification/notification
|
|
|
17
17
|
|
|
18
18
|
const config: NotificationConfig = {
|
|
19
19
|
channels: {
|
|
20
|
-
mail:
|
|
20
|
+
mail: mailChannel({ from: "no-reply@store.com" }),
|
|
21
21
|
database: inApp.configure({ model: Notification }),
|
|
22
22
|
},
|
|
23
23
|
};
|
|
@@ -32,17 +32,17 @@ The `database` channel is returned by `inApp.configure({ model | repository })`
|
|
|
32
32
|
```ts
|
|
33
33
|
const config: NotificationConfig = {
|
|
34
34
|
channels: {
|
|
35
|
-
mail:
|
|
35
|
+
mail: mailChannel({ from }),
|
|
36
36
|
database: inApp.configure({ model: Notification }),
|
|
37
37
|
|
|
38
38
|
// custom channels
|
|
39
|
-
discord:
|
|
39
|
+
discord: discordChannel(), // defineChannel + declare module
|
|
40
40
|
},
|
|
41
41
|
|
|
42
42
|
// optional gates — both app-owned; package ships no defaults
|
|
43
|
-
preferences: userPreferences,
|
|
44
|
-
rateLimit,
|
|
45
|
-
queue: heraldQueue(),
|
|
43
|
+
preferences: userPreferences, // drops channels recipient muted
|
|
44
|
+
rateLimit, // drops channels over budget
|
|
45
|
+
queue: heraldQueue(), // backs `.queue()` (needs @warlock.js/herald)
|
|
46
46
|
};
|
|
47
47
|
|
|
48
48
|
export default config;
|
|
@@ -116,7 +116,7 @@ Dropped channels fire a `skipped` event with reason `"rate-limit"`. `force` does
|
|
|
116
116
|
```ts
|
|
117
117
|
import { getNotificationConfig } from "@warlock.js/notifications";
|
|
118
118
|
|
|
119
|
-
const cfg = getNotificationConfig();
|
|
119
|
+
const cfg = getNotificationConfig(); // throws NotificationsNotConfiguredError if unset
|
|
120
120
|
```
|
|
121
121
|
|
|
122
122
|
## Tests
|
|
@@ -50,12 +50,12 @@ Now `notify.discord(user, { content: "🎉" })` works, and `discord:` is a valid
|
|
|
50
50
|
|
|
51
51
|
## `route` resolution
|
|
52
52
|
|
|
53
|
-
| What `route` returns | Effect
|
|
54
|
-
|
|
55
|
-
| `string`
|
|
56
|
-
| `{ id: Id }`
|
|
57
|
-
| `undefined`
|
|
58
|
-
| `route` omitted
|
|
53
|
+
| What `route` returns | Effect |
|
|
54
|
+
| -------------------- | ----------------------------------------------------------------- |
|
|
55
|
+
| `string` | Used directly as the address (`"user@example.com"`, webhook URL). |
|
|
56
|
+
| `{ id: Id }` | The recipient's storage id — for database/internal channels. |
|
|
57
|
+
| `undefined` | Dispatcher falls back to `{ id: notifiable.id }`. |
|
|
58
|
+
| `route` omitted | Same as returning `undefined` — `{ id }` fallback. |
|
|
59
59
|
|
|
60
60
|
For raw-target ad-hoc sends (`notify.discord("https://hooks.../foo", payload)`), the raw string wins over `route()`.
|
|
61
61
|
|
|
@@ -83,7 +83,9 @@ import type { WebClient } from "@slack/web-api";
|
|
|
83
83
|
let Slack: typeof import("@slack/web-api");
|
|
84
84
|
let isModuleExists: boolean | null = null;
|
|
85
85
|
|
|
86
|
-
async function loadSlack() {
|
|
86
|
+
async function loadSlack() {
|
|
87
|
+
/* try/catch await import; set flag */
|
|
88
|
+
}
|
|
87
89
|
loadSlack();
|
|
88
90
|
|
|
89
91
|
export const slackChannel = (config: { token: string }) =>
|
|
@@ -21,11 +21,11 @@ defineNotification<Data>({
|
|
|
21
21
|
|
|
22
22
|
Returns `{ send, queue, only }`:
|
|
23
23
|
|
|
24
|
-
| Method
|
|
25
|
-
|
|
26
|
-
| `.send`
|
|
27
|
-
| `.queue`
|
|
28
|
-
| `.only(...channels)` | returns `{send, queue, only}` | Restrict dispatch to a subset of channels.
|
|
24
|
+
| Method | Signature | What it does |
|
|
25
|
+
| -------------------- | ----------------------------- | -------------------------------------------------------------- |
|
|
26
|
+
| `.send` | `(to, data, options?)` | Render + dispatch synchronously. |
|
|
27
|
+
| `.queue` | `(to, data, options?)` | Render + enqueue. Throws if no queue dispatcher is configured. |
|
|
28
|
+
| `.only(...channels)` | returns `{send, queue, only}` | Restrict dispatch to a subset of channels. |
|
|
29
29
|
|
|
30
30
|
`to` accepts a `Notifiable` OR a `Notifiable[]`. Fan-out emits one render+dispatch per recipient with per-recipient + per-channel `Promise.allSettled` (one failure does not abort the others).
|
|
31
31
|
|
|
@@ -47,9 +47,7 @@ await welcome.send(user, { name: "Hasan" });
|
|
|
47
47
|
export const orderShipped = defineNotification<{ order: Order }>({
|
|
48
48
|
type: "order.shipped",
|
|
49
49
|
via: (_data, to) =>
|
|
50
|
-
to.get("telegram_chat_id")
|
|
51
|
-
? ["database", "telegram"]
|
|
52
|
-
: ["database", "mail"],
|
|
50
|
+
to.get("telegram_chat_id") ? ["database", "telegram"] : ["database", "mail"],
|
|
53
51
|
database: ({ order }) => ({ title: `Order #${order.number} shipped` }),
|
|
54
52
|
mail: ({ order }, to) => ({
|
|
55
53
|
subject: `Order #${order.number} shipped`,
|
|
@@ -62,16 +60,15 @@ export const orderShipped = defineNotification<{ order: Order }>({
|
|
|
62
60
|
## The renderer's 3rd arg — `RenderContext`
|
|
63
61
|
|
|
64
62
|
```ts
|
|
65
|
-
mail: ({ campaignId }, to, { locale = "en", meta }) => ({
|
|
63
|
+
mail: (({ campaignId }, to, { locale = "en", meta }) => ({
|
|
66
64
|
subject: subjectsByLocale[locale],
|
|
67
|
-
html:
|
|
65
|
+
html: htmlByLocale[locale],
|
|
68
66
|
}),
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
});
|
|
67
|
+
// usage:
|
|
68
|
+
await marketing.queue(user, payload, {
|
|
69
|
+
locale: user.get("locale"),
|
|
70
|
+
meta: { campaignId, source: "blast" },
|
|
71
|
+
}));
|
|
75
72
|
```
|
|
76
73
|
|
|
77
74
|
`ctx` carries `locale` + `meta` from `SendOptions`. `meta` flows through to every observability event too.
|
|
@@ -82,7 +79,7 @@ The `database` renderer may OMIT `type` — the dispatcher injects `def.type` au
|
|
|
82
79
|
|
|
83
80
|
```ts
|
|
84
81
|
defineNotification({
|
|
85
|
-
type: "order.shipped",
|
|
82
|
+
type: "order.shipped", // ← single source of truth
|
|
86
83
|
via: ["database"],
|
|
87
84
|
database: () => ({ title: "Shipped" }), // type omitted; dispatcher injects "order.shipped"
|
|
88
85
|
});
|
|
@@ -112,14 +109,14 @@ await orderShipped.queue(user, { order }, { delay: "10m" });
|
|
|
112
109
|
|
|
113
110
|
## SendOptions
|
|
114
111
|
|
|
115
|
-
| Field
|
|
116
|
-
|
|
117
|
-
| `delay`
|
|
118
|
-
| `locale`
|
|
119
|
-
| `meta`
|
|
120
|
-
| `idempotencyKey` | Injected into the database payload (dedupe via unique index).
|
|
121
|
-
| `force`
|
|
122
|
-
| `type`
|
|
112
|
+
| Field | Effect |
|
|
113
|
+
| ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
114
|
+
| `delay` | Reserved — `"10m"` / `"3d"` / `600` (seconds). NOT honored yet: both `.send()` and the current `.queue()` worker dispatch immediately; delay-aware delivery is a follow-up. |
|
|
115
|
+
| `locale` | Passed to renderers via `RenderContext.locale`. |
|
|
116
|
+
| `meta` | Passed to renderers + included in every observability event. |
|
|
117
|
+
| `idempotencyKey` | Injected into the database payload (dedupe via unique index). |
|
|
118
|
+
| `force` | Bypass `PreferenceProvider`. Does NOT bypass `RateLimiter`. |
|
|
119
|
+
| `type` | Ignored by `defineNotification` — see `send-ad-hoc` for ad-hoc gating. |
|
|
123
120
|
|
|
124
121
|
## Failure isolation
|
|
125
122
|
|
package/skills/index.md
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
---
|
|
2
|
-
description:
|
|
2
|
+
description: 'Multi-channel notifications for Warlock: define once, send by mail, in-app database, or custom channels. Exports `defineNotification`, `notify`, `defineChannel`, `mailChannel`, `inApp`, `notificationColumns`, `notifications`, `bullmqQueue`, `heraldQueue`, `NotificationConfig`. Use for: "notify a user", "send order shipped by email and in-app", "unread notifications", "add a Slack or webhook channel", "queue notification delivery". Not this package: sending a plain email or mail templates → @warlock.js/core sendMail; background jobs → @warlock.js/queue.'
|
|
3
3
|
---
|
|
4
|
+
|
|
4
5
|
# @warlock.js/notifications
|
|
5
6
|
|
|
6
7
|
An orchestrator over transports that already exist: one event, many recipients, any mix of channels, one render per channel. It is not a queue, template engine, or transport. `defineNotification` builds a reusable notification (`send`, `queue`, `only`); `notify.<channel>` does ad-hoc single-channel sends; `inApp` is the read side of the database channel. Server-only.
|
|
7
8
|
|
|
8
9
|
## The 80% path
|
|
10
|
+
|
|
9
11
|
1. Orient with `notifications-basics.md`.
|
|
10
12
|
2. Configure channels in `src/config/notifications.ts`: `configure-notifications.md`; create the table: `write-notification-migration.md`.
|
|
11
13
|
3. Define the notification with `via` and a renderer per channel: `define-notification.md`; one-off sends: `send-ad-hoc.md`.
|
|
@@ -13,6 +15,7 @@ An orchestrator over transports that already exist: one event, many recipients,
|
|
|
13
15
|
5. Custom channel: `define-channel.md`; deferred delivery: `queue-notifications.md`; sent/failed/skipped hooks: `observe-notifications.md`.
|
|
14
16
|
|
|
15
17
|
## Conventions and pitfalls
|
|
18
|
+
|
|
16
19
|
- The config is declarative; the connector registers its default export, so never call `setNotificationConfig` yourself.
|
|
17
20
|
- Channel names are typed through `NotificationChannels` declaration merging.
|
|
18
21
|
- `mailChannel` wraps core `sendMail`; use core directly for non-notification mail.
|
|
@@ -11,7 +11,7 @@ Multi-channel notifications for Warlock.js. **Define once, fire anywhere.**
|
|
|
11
11
|
|
|
12
12
|
You have an event (`order.shipped`, `comment.mentioned`, `password.changed`) and one or more recipients. You want to address them through any combination of channels (mail, in-app, push, ...) with one render. That's what this package is.
|
|
13
13
|
|
|
14
|
-
It is NOT a queue, a template engine, a transport library, or an analytics pipeline — it orchestrates
|
|
14
|
+
It is NOT a queue, a template engine, a transport library, or an analytics pipeline — it orchestrates _over_ the transports cascade / core / herald / bridges already provide.
|
|
15
15
|
|
|
16
16
|
## Server-only package
|
|
17
17
|
|
|
@@ -34,7 +34,7 @@ import { Notification } from "app/notifications/models/notification/notification
|
|
|
34
34
|
|
|
35
35
|
const config: NotificationConfig = {
|
|
36
36
|
channels: {
|
|
37
|
-
mail:
|
|
37
|
+
mail: mailChannel({ from: "no-reply@store.com" }),
|
|
38
38
|
database: inApp.configure({ model: Notification }),
|
|
39
39
|
},
|
|
40
40
|
};
|
|
@@ -67,7 +67,7 @@ await orderShipped.send(user, { orderId: order.id, number: order.number });
|
|
|
67
67
|
await notify.mail(user, { subject: "Welcome", html: "<p>Hi!</p>" });
|
|
68
68
|
|
|
69
69
|
const unread = await inApp.listUnread(user);
|
|
70
|
-
const badge
|
|
70
|
+
const badge = await inApp.countUnread(user);
|
|
71
71
|
await inApp.markAsRead(user, "ntf_123");
|
|
72
72
|
```
|
|
73
73
|
|
|
@@ -77,15 +77,15 @@ await inApp.markAsRead(user, "ntf_123");
|
|
|
77
77
|
|
|
78
78
|
## Phase 1 vs Phase 2
|
|
79
79
|
|
|
80
|
-
| Channel
|
|
81
|
-
|
|
82
|
-
| `mail`
|
|
83
|
-
| `database` | 1 ✅
|
|
84
|
-
| `whatsapp` | 2
|
|
85
|
-
| `telegram` | 2
|
|
86
|
-
| `slack`
|
|
87
|
-
| `push`
|
|
88
|
-
| your own
|
|
80
|
+
| Channel | Phase | How |
|
|
81
|
+
| ---------- | ----- | ----------------------------------------- |
|
|
82
|
+
| `mail` | 1 ✅ | core `sendMail` |
|
|
83
|
+
| `database` | 1 ✅ | cascade repo (recipient-scoped reads) |
|
|
84
|
+
| `whatsapp` | 2 | bridges `MessageProvider` |
|
|
85
|
+
| `telegram` | 2 | bridges `MessageProvider` |
|
|
86
|
+
| `slack` | 2 | bridges `MessageProvider` |
|
|
87
|
+
| `push` | 2 | bridges `PushProvider` |
|
|
88
|
+
| your own | 1 ✅ | `defineChannel` + 3-line `declare module` |
|
|
89
89
|
|
|
90
90
|
## See also
|
|
91
91
|
|