@warlock.js/notifications 5.28.0 → 5.30.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.
Files changed (530) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/cjs/{channel_api-CBB_XoIl.cjs → channel_api-C5ZZDkgQ.cjs} +21 -21
  3. package/cjs/channel_api-C5ZZDkgQ.cjs.map +1 -0
  4. package/cjs/index.cjs +22 -22
  5. package/cjs/index.cjs.map +1 -1
  6. package/cjs/rabbitmq-driver-BFoWr21L.cjs +3 -0
  7. package/cjs/{src-B6UVThgW.cjs → src-eu2jxS21.cjs} +173 -135
  8. package/cjs/src-eu2jxS21.cjs.map +1 -0
  9. package/esm/channels/database-channel.d.mts +1 -1
  10. package/esm/channels/database-channel.d.mts.map +1 -1
  11. package/esm/channels/database-channel.mjs +1 -1
  12. package/esm/channels/database-channel.mjs.map +1 -1
  13. package/esm/channels/mail-channel.d.mts +1 -1
  14. package/esm/channels/mail-channel.d.mts.map +1 -1
  15. package/esm/channels/mail-channel.mjs +1 -1
  16. package/esm/channels/mail-channel.mjs.map +1 -1
  17. package/esm/config.d.mts +1 -1
  18. package/esm/config.d.mts.map +1 -1
  19. package/esm/config.mjs +1 -1
  20. package/esm/config.mjs.map +1 -1
  21. package/esm/contracts/channel.contract.d.mts +1 -1
  22. package/esm/contracts/channel.contract.d.mts.map +1 -1
  23. package/esm/contracts/notification.contract.d.mts +1 -1
  24. package/esm/contracts/notification.contract.d.mts.map +1 -1
  25. package/esm/contracts/preference-provider.contract.d.mts +1 -1
  26. package/esm/contracts/preference-provider.contract.d.mts.map +1 -1
  27. package/esm/contracts/queue-dispatcher.contract.d.mts +1 -1
  28. package/esm/contracts/queue-dispatcher.contract.d.mts.map +1 -1
  29. package/esm/contracts/rate-limiter.contract.d.mts +1 -1
  30. package/esm/contracts/rate-limiter.contract.d.mts.map +1 -1
  31. package/esm/dispatch/define-channel.d.mts +1 -1
  32. package/esm/dispatch/define-channel.d.mts.map +1 -1
  33. package/esm/dispatch/define-channel.mjs +1 -1
  34. package/esm/dispatch/define-channel.mjs.map +1 -1
  35. package/esm/dispatch/define-notification.d.mts +1 -1
  36. package/esm/dispatch/define-notification.d.mts.map +1 -1
  37. package/esm/dispatch/define-notification.mjs +1 -1
  38. package/esm/dispatch/define-notification.mjs.map +1 -1
  39. package/esm/dispatch/dispatch-id.mjs +1 -1
  40. package/esm/dispatch/dispatch-id.mjs.map +1 -1
  41. package/esm/dispatch/dispatcher.mjs +1 -1
  42. package/esm/dispatch/dispatcher.mjs.map +1 -1
  43. package/esm/dispatch/notifications-event-bus.d.mts +1 -1
  44. package/esm/dispatch/notifications-event-bus.d.mts.map +1 -1
  45. package/esm/dispatch/notifications-event-bus.mjs +1 -1
  46. package/esm/dispatch/notifications-event-bus.mjs.map +1 -1
  47. package/esm/dispatch/notify.d.mts +1 -1
  48. package/esm/dispatch/notify.d.mts.map +1 -1
  49. package/esm/dispatch/notify.mjs +1 -1
  50. package/esm/dispatch/notify.mjs.map +1 -1
  51. package/esm/errors.d.mts +1 -1
  52. package/esm/errors.d.mts.map +1 -1
  53. package/esm/errors.mjs +1 -1
  54. package/esm/errors.mjs.map +1 -1
  55. package/esm/in-app/base-notifications-repository.d.mts +1 -1
  56. package/esm/in-app/base-notifications-repository.d.mts.map +1 -1
  57. package/esm/in-app/base-notifications-repository.mjs +1 -1
  58. package/esm/in-app/base-notifications-repository.mjs.map +1 -1
  59. package/esm/in-app/column-map.d.mts +1 -1
  60. package/esm/in-app/column-map.d.mts.map +1 -1
  61. package/esm/in-app/column-map.mjs +1 -1
  62. package/esm/in-app/column-map.mjs.map +1 -1
  63. package/esm/in-app/database-notification.d.mts +1 -1
  64. package/esm/in-app/database-notification.d.mts.map +1 -1
  65. package/esm/in-app/database-notification.mjs +1 -1
  66. package/esm/in-app/database-notification.mjs.map +1 -1
  67. package/esm/in-app/in-app.d.mts +1 -1
  68. package/esm/in-app/in-app.d.mts.map +1 -1
  69. package/esm/in-app/in-app.mjs +1 -1
  70. package/esm/in-app/in-app.mjs.map +1 -1
  71. package/esm/migration/notification-columns.d.mts +1 -1
  72. package/esm/migration/notification-columns.d.mts.map +1 -1
  73. package/esm/migration/notification-columns.mjs +1 -1
  74. package/esm/migration/notification-columns.mjs.map +1 -1
  75. package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/Random/_internal.mjs +1 -1
  76. package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/Random/_internal.mjs.map +1 -1
  77. package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/mixed/clone/clone.mjs +1 -1
  78. package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/mixed/clone/clone.mjs.map +1 -1
  79. package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/number/round.mjs +1 -1
  80. package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/number/round.mjs.map +1 -1
  81. package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/object/except.mjs +1 -1
  82. package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/object/except.mjs.map +1 -1
  83. package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/object/get.mjs +1 -1
  84. package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/object/get.mjs.map +1 -1
  85. package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/object/omit.mjs +1 -1
  86. package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/object/omit.mjs.map +1 -1
  87. package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/object/unset.mjs +1 -1
  88. package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/object/unset.mjs.map +1 -1
  89. package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/string/capitalize.mjs +1 -1
  90. package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/string/capitalize.mjs.map +1 -1
  91. package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/string/ltrim.mjs +1 -1
  92. package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/string/ltrim.mjs.map +1 -1
  93. package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/string/readMoreChars.mjs +1 -1
  94. package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/string/readMoreChars.mjs.map +1 -1
  95. package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/string/rtrim.mjs +1 -1
  96. package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/string/rtrim.mjs.map +1 -1
  97. package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/string/toCamelCase.mjs +1 -1
  98. package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/string/toCamelCase.mjs.map +1 -1
  99. package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/string/toKebabCase.mjs +1 -1
  100. package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/string/toKebabCase.mjs.map +1 -1
  101. package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/string/toSnakeCase.mjs +1 -1
  102. package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/string/toSnakeCase.mjs.map +1 -1
  103. package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/string/toStudlyCase.mjs +1 -1
  104. package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/string/toStudlyCase.mjs.map +1 -1
  105. package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/string/trim.mjs +1 -1
  106. package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/string/trim.mjs.map +1 -1
  107. package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/string/ucfirst.mjs +1 -1
  108. package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/string/ucfirst.mjs.map +1 -1
  109. package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/string/words.mjs +1 -1
  110. package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/string/words.mjs.map +1 -1
  111. package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/utils/escapeRegex.mjs +1 -1
  112. package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/utils/escapeRegex.mjs.map +1 -1
  113. package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/utils/lazy.mjs +1 -1
  114. package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/utils/lazy.mjs.map +1 -1
  115. package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/utils/tap.mjs +1 -1
  116. package/esm/node_modules/.pnpm/@mongez_reinforcements@4.0.2/node_modules/@mongez/reinforcements/esm/utils/tap.mjs.map +1 -1
  117. package/esm/node_modules/.pnpm/@mongez_supportive-is@3.0.0/node_modules/@mongez/supportive-is/esm/index.mjs +1 -1
  118. package/esm/node_modules/.pnpm/@mongez_supportive-is@3.0.0/node_modules/@mongez/supportive-is/esm/index.mjs.map +1 -1
  119. package/esm/node_modules/.pnpm/amqplib@0.10.9/node_modules/amqplib/channel_api.mjs +1 -1
  120. package/esm/node_modules/.pnpm/amqplib@0.10.9/node_modules/amqplib/channel_api.mjs.map +1 -1
  121. package/esm/node_modules/.pnpm/amqplib@0.10.9/node_modules/amqplib/lib/api_args.mjs +1 -1
  122. package/esm/node_modules/.pnpm/amqplib@0.10.9/node_modules/amqplib/lib/api_args.mjs.map +1 -1
  123. package/esm/node_modules/.pnpm/amqplib@0.10.9/node_modules/amqplib/lib/bitset.mjs +1 -1
  124. package/esm/node_modules/.pnpm/amqplib@0.10.9/node_modules/amqplib/lib/bitset.mjs.map +1 -1
  125. package/esm/node_modules/.pnpm/amqplib@0.10.9/node_modules/amqplib/lib/channel.mjs +1 -1
  126. package/esm/node_modules/.pnpm/amqplib@0.10.9/node_modules/amqplib/lib/channel.mjs.map +1 -1
  127. package/esm/node_modules/.pnpm/amqplib@0.10.9/node_modules/amqplib/lib/channel_model.mjs +1 -1
  128. package/esm/node_modules/.pnpm/amqplib@0.10.9/node_modules/amqplib/lib/channel_model.mjs.map +1 -1
  129. package/esm/node_modules/.pnpm/amqplib@0.10.9/node_modules/amqplib/lib/codec.mjs +1 -1
  130. package/esm/node_modules/.pnpm/amqplib@0.10.9/node_modules/amqplib/lib/codec.mjs.map +1 -1
  131. package/esm/node_modules/.pnpm/amqplib@0.10.9/node_modules/amqplib/lib/connect.mjs +1 -1
  132. package/esm/node_modules/.pnpm/amqplib@0.10.9/node_modules/amqplib/lib/connect.mjs.map +1 -1
  133. package/esm/node_modules/.pnpm/amqplib@0.10.9/node_modules/amqplib/lib/connection.mjs +1 -1
  134. package/esm/node_modules/.pnpm/amqplib@0.10.9/node_modules/amqplib/lib/connection.mjs.map +1 -1
  135. package/esm/node_modules/.pnpm/amqplib@0.10.9/node_modules/amqplib/lib/credentials.mjs +1 -1
  136. package/esm/node_modules/.pnpm/amqplib@0.10.9/node_modules/amqplib/lib/credentials.mjs.map +1 -1
  137. package/esm/node_modules/.pnpm/amqplib@0.10.9/node_modules/amqplib/lib/defs.mjs +1 -1
  138. package/esm/node_modules/.pnpm/amqplib@0.10.9/node_modules/amqplib/lib/defs.mjs.map +1 -1
  139. package/esm/node_modules/.pnpm/amqplib@0.10.9/node_modules/amqplib/lib/error.mjs +1 -1
  140. package/esm/node_modules/.pnpm/amqplib@0.10.9/node_modules/amqplib/lib/error.mjs.map +1 -1
  141. package/esm/node_modules/.pnpm/amqplib@0.10.9/node_modules/amqplib/lib/format.mjs +1 -1
  142. package/esm/node_modules/.pnpm/amqplib@0.10.9/node_modules/amqplib/lib/format.mjs.map +1 -1
  143. package/esm/node_modules/.pnpm/amqplib@0.10.9/node_modules/amqplib/lib/frame.mjs +1 -1
  144. package/esm/node_modules/.pnpm/amqplib@0.10.9/node_modules/amqplib/lib/frame.mjs.map +1 -1
  145. package/esm/node_modules/.pnpm/amqplib@0.10.9/node_modules/amqplib/lib/heartbeat.mjs +1 -1
  146. package/esm/node_modules/.pnpm/amqplib@0.10.9/node_modules/amqplib/lib/heartbeat.mjs.map +1 -1
  147. package/esm/node_modules/.pnpm/amqplib@0.10.9/node_modules/amqplib/lib/mux.mjs +1 -1
  148. package/esm/node_modules/.pnpm/amqplib@0.10.9/node_modules/amqplib/lib/mux.mjs.map +1 -1
  149. package/esm/node_modules/.pnpm/amqplib@0.10.9/node_modules/amqplib/package.mjs +1 -1
  150. package/esm/node_modules/.pnpm/amqplib@0.10.9/node_modules/amqplib/package.mjs.map +1 -1
  151. package/esm/node_modules/.pnpm/buffer-more-ints@1.0.0/node_modules/buffer-more-ints/buffer-more-ints.mjs +1 -1
  152. package/esm/node_modules/.pnpm/buffer-more-ints@1.0.0/node_modules/buffer-more-ints/buffer-more-ints.mjs.map +1 -1
  153. package/esm/node_modules/.pnpm/dayjs@1.11.23/node_modules/dayjs/dayjs.min.mjs +1 -1
  154. package/esm/node_modules/.pnpm/dayjs@1.11.23/node_modules/dayjs/dayjs.min.mjs.map +1 -1
  155. package/esm/node_modules/.pnpm/querystringify@2.2.0/node_modules/querystringify/index.mjs +1 -1
  156. package/esm/node_modules/.pnpm/querystringify@2.2.0/node_modules/querystringify/index.mjs.map +1 -1
  157. package/esm/node_modules/.pnpm/requires-port@1.0.0/node_modules/requires-port/index.mjs +1 -1
  158. package/esm/node_modules/.pnpm/requires-port@1.0.0/node_modules/requires-port/index.mjs.map +1 -1
  159. package/esm/node_modules/.pnpm/url-parse@1.5.10/node_modules/url-parse/index.mjs +1 -1
  160. package/esm/node_modules/.pnpm/url-parse@1.5.10/node_modules/url-parse/index.mjs.map +1 -1
  161. package/esm/{herald → packages/herald}/src/communicators/broker-registry.mjs +1 -1
  162. package/esm/packages/herald/src/communicators/broker-registry.mjs.map +1 -0
  163. package/esm/{herald → packages/herald}/src/communicators/broker.mjs +1 -1
  164. package/esm/packages/herald/src/communicators/broker.mjs.map +1 -0
  165. package/esm/{herald → packages/herald}/src/decorators/consumable.mjs +1 -1
  166. package/esm/packages/herald/src/decorators/consumable.mjs.map +1 -0
  167. package/esm/{herald → packages/herald}/src/drivers/rabbitmq/rabbitmq-channel.mjs +1 -1
  168. package/esm/packages/herald/src/drivers/rabbitmq/rabbitmq-channel.mjs.map +1 -0
  169. package/esm/{herald → packages/herald}/src/drivers/rabbitmq/rabbitmq-driver.mjs +3 -3
  170. package/esm/packages/herald/src/drivers/rabbitmq/rabbitmq-driver.mjs.map +1 -0
  171. package/esm/{herald → packages/herald}/src/message-managers/event-consumer.mjs +1 -1
  172. package/esm/packages/herald/src/message-managers/event-consumer.mjs.map +1 -0
  173. package/esm/{herald → packages/herald}/src/message-managers/event-message.mjs +1 -1
  174. package/esm/packages/herald/src/message-managers/event-message.mjs.map +1 -0
  175. package/esm/{herald → packages/herald}/src/message-managers/prepare-consumer-subscription.mjs +1 -1
  176. package/esm/packages/herald/src/message-managers/prepare-consumer-subscription.mjs.map +1 -0
  177. package/esm/{herald → packages/herald}/src/use-case-broadcast.mjs +1 -1
  178. package/esm/packages/herald/src/use-case-broadcast.mjs.map +1 -0
  179. package/esm/{herald → packages/herald}/src/utils/connect-to-broker.mjs +1 -1
  180. package/esm/packages/herald/src/utils/connect-to-broker.mjs.map +1 -0
  181. package/esm/{seal → packages/seal}/src/config.mjs +1 -1
  182. package/esm/packages/seal/src/config.mjs.map +1 -0
  183. package/esm/{seal → packages/seal}/src/factory/validate.mjs +12 -4
  184. package/esm/packages/seal/src/factory/validate.mjs.map +1 -0
  185. package/esm/{seal → packages/seal}/src/factory/validators.mjs +1 -1
  186. package/esm/packages/seal/src/factory/validators.mjs.map +1 -0
  187. package/esm/{seal → packages/seal}/src/helpers/date-helpers.mjs +1 -1
  188. package/esm/packages/seal/src/helpers/date-helpers.mjs.map +1 -0
  189. package/esm/{seal → packages/seal}/src/helpers/get-field-value.mjs +3 -3
  190. package/esm/packages/seal/src/helpers/get-field-value.mjs.map +1 -0
  191. package/esm/packages/seal/src/helpers/is-empty-value.mjs +10 -0
  192. package/esm/packages/seal/src/helpers/is-empty-value.mjs.map +1 -0
  193. package/esm/{seal → packages/seal}/src/helpers/path-helpers.mjs +1 -1
  194. package/esm/packages/seal/src/helpers/path-helpers.mjs.map +1 -0
  195. package/esm/{seal → packages/seal}/src/helpers/validation-helpers.mjs +1 -1
  196. package/esm/packages/seal/src/helpers/validation-helpers.mjs.map +1 -0
  197. package/esm/{seal → packages/seal}/src/mutators/array-mutators.mjs +3 -3
  198. package/esm/packages/seal/src/mutators/array-mutators.mjs.map +1 -0
  199. package/esm/{seal → packages/seal}/src/mutators/boolean-mutators.mjs +1 -1
  200. package/esm/packages/seal/src/mutators/boolean-mutators.mjs.map +1 -0
  201. package/esm/{seal → packages/seal}/src/mutators/date-mutators.mjs +3 -3
  202. package/esm/packages/seal/src/mutators/date-mutators.mjs.map +1 -0
  203. package/esm/{seal → packages/seal}/src/mutators/number-mutators.mjs +4 -4
  204. package/esm/packages/seal/src/mutators/number-mutators.mjs.map +1 -0
  205. package/esm/{seal → packages/seal}/src/mutators/object-mutators.mjs +4 -4
  206. package/esm/packages/seal/src/mutators/object-mutators.mjs.map +1 -0
  207. package/esm/{seal → packages/seal}/src/mutators/scalar-mutators.mjs +1 -1
  208. package/esm/packages/seal/src/mutators/scalar-mutators.mjs.map +1 -0
  209. package/esm/{seal → packages/seal}/src/mutators/string-mutators.mjs +11 -11
  210. package/esm/packages/seal/src/mutators/string-mutators.mjs.map +1 -0
  211. package/esm/{seal → packages/seal}/src/object.mjs +1 -1
  212. package/esm/packages/seal/src/object.mjs.map +1 -0
  213. package/esm/{seal → packages/seal}/src/rules/array/array-rules.mjs +1 -1
  214. package/esm/packages/seal/src/rules/array/array-rules.mjs.map +1 -0
  215. package/esm/{seal → packages/seal}/src/rules/color/color-rules.mjs +1 -1
  216. package/esm/packages/seal/src/rules/color/color-rules.mjs.map +1 -0
  217. package/esm/{seal → packages/seal}/src/rules/common/enum.mjs +1 -1
  218. package/esm/packages/seal/src/rules/common/enum.mjs.map +1 -0
  219. package/esm/{seal → packages/seal}/src/rules/common/equals-field-rules.mjs +1 -1
  220. package/esm/packages/seal/src/rules/common/equals-field-rules.mjs.map +1 -0
  221. package/esm/{seal → packages/seal}/src/rules/common/instanceof.mjs +1 -1
  222. package/esm/packages/seal/src/rules/common/instanceof.mjs.map +1 -0
  223. package/esm/{seal → packages/seal}/src/rules/common/literal.mjs +1 -1
  224. package/esm/packages/seal/src/rules/common/literal.mjs.map +1 -0
  225. package/esm/{seal → packages/seal}/src/rules/common/type-rules.mjs +2 -2
  226. package/esm/packages/seal/src/rules/common/type-rules.mjs.map +1 -0
  227. package/esm/{seal → packages/seal}/src/rules/common/unknown-key.mjs +1 -1
  228. package/esm/packages/seal/src/rules/common/unknown-key.mjs.map +1 -0
  229. package/esm/{seal → packages/seal}/src/rules/conditional/forbidden-if-rules.mjs +1 -1
  230. package/esm/packages/seal/src/rules/conditional/forbidden-if-rules.mjs.map +1 -0
  231. package/esm/{seal → packages/seal}/src/rules/conditional/present-if-rules.mjs +1 -1
  232. package/esm/packages/seal/src/rules/conditional/present-if-rules.mjs.map +1 -0
  233. package/esm/{seal → packages/seal}/src/rules/conditional/present-unless-rules.mjs +1 -1
  234. package/esm/packages/seal/src/rules/conditional/present-unless-rules.mjs.map +1 -0
  235. package/esm/{seal → packages/seal}/src/rules/conditional/present-with-rules.mjs +3 -3
  236. package/esm/packages/seal/src/rules/conditional/present-with-rules.mjs.map +1 -0
  237. package/esm/{seal → packages/seal}/src/rules/conditional/present-without-rules.mjs +3 -3
  238. package/esm/packages/seal/src/rules/conditional/present-without-rules.mjs.map +1 -0
  239. package/esm/{seal → packages/seal}/src/rules/conditional/required-if-rules.mjs +3 -3
  240. package/esm/packages/seal/src/rules/conditional/required-if-rules.mjs.map +1 -0
  241. package/esm/{seal → packages/seal}/src/rules/conditional/required-unless-rules.mjs +1 -1
  242. package/esm/packages/seal/src/rules/conditional/required-unless-rules.mjs.map +1 -0
  243. package/esm/{seal → packages/seal}/src/rules/conditional/required-when-rule.mjs +1 -1
  244. package/esm/packages/seal/src/rules/conditional/required-when-rule.mjs.map +1 -0
  245. package/esm/{seal → packages/seal}/src/rules/conditional/required-with-rules.mjs +3 -3
  246. package/esm/packages/seal/src/rules/conditional/required-with-rules.mjs.map +1 -0
  247. package/esm/{seal → packages/seal}/src/rules/conditional/required-without-rules.mjs +3 -3
  248. package/esm/packages/seal/src/rules/conditional/required-without-rules.mjs.map +1 -0
  249. package/esm/{seal → packages/seal}/src/rules/core/equal.mjs +1 -1
  250. package/esm/packages/seal/src/rules/core/equal.mjs.map +1 -0
  251. package/esm/{seal → packages/seal}/src/rules/core/forbidden.mjs +1 -1
  252. package/esm/packages/seal/src/rules/core/forbidden.mjs.map +1 -0
  253. package/esm/{seal → packages/seal}/src/rules/core/required.mjs +1 -1
  254. package/esm/packages/seal/src/rules/core/required.mjs.map +1 -0
  255. package/esm/{seal → packages/seal}/src/rules/core/union.mjs +3 -1
  256. package/esm/packages/seal/src/rules/core/union.mjs.map +1 -0
  257. package/esm/{seal → packages/seal}/src/rules/core/when.mjs +3 -3
  258. package/esm/packages/seal/src/rules/core/when.mjs.map +1 -0
  259. package/esm/{seal → packages/seal}/src/rules/date/date-comparison-rules.mjs +1 -1
  260. package/esm/packages/seal/src/rules/date/date-comparison-rules.mjs.map +1 -0
  261. package/esm/{seal → packages/seal}/src/rules/date/date-day-rules.mjs +1 -1
  262. package/esm/packages/seal/src/rules/date/date-day-rules.mjs.map +1 -0
  263. package/esm/{seal → packages/seal}/src/rules/date/date-field-comparison-rules.mjs +3 -3
  264. package/esm/packages/seal/src/rules/date/date-field-comparison-rules.mjs.map +1 -0
  265. package/esm/{seal → packages/seal}/src/rules/date/date-period-rules.mjs +3 -3
  266. package/esm/packages/seal/src/rules/date/date-period-rules.mjs.map +1 -0
  267. package/esm/{seal → packages/seal}/src/rules/date/date-relative-rules.mjs +1 -1
  268. package/esm/packages/seal/src/rules/date/date-relative-rules.mjs.map +1 -0
  269. package/esm/{seal → packages/seal}/src/rules/date/date-special-rules.mjs +1 -1
  270. package/esm/packages/seal/src/rules/date/date-special-rules.mjs.map +1 -0
  271. package/esm/{seal → packages/seal}/src/rules/date/date.mjs +3 -3
  272. package/esm/packages/seal/src/rules/date/date.mjs.map +1 -0
  273. package/esm/{seal → packages/seal}/src/rules/length/length-rules.mjs +1 -1
  274. package/esm/packages/seal/src/rules/length/length-rules.mjs.map +1 -0
  275. package/esm/{seal → packages/seal}/src/rules/number/number-rules.mjs +3 -3
  276. package/esm/packages/seal/src/rules/number/number-rules.mjs.map +1 -0
  277. package/esm/{seal → packages/seal}/src/rules/scalar/accepted-rule.mjs +1 -1
  278. package/esm/packages/seal/src/rules/scalar/accepted-rule.mjs.map +1 -0
  279. package/esm/{seal → packages/seal}/src/rules/scalar/declined-rule.mjs +1 -1
  280. package/esm/packages/seal/src/rules/scalar/declined-rule.mjs.map +1 -0
  281. package/esm/{seal → packages/seal}/src/rules/string/alpha.mjs +1 -1
  282. package/esm/packages/seal/src/rules/string/alpha.mjs.map +1 -0
  283. package/esm/{seal → packages/seal}/src/rules/string/credit-card.mjs +1 -1
  284. package/esm/packages/seal/src/rules/string/credit-card.mjs.map +1 -0
  285. package/esm/{seal → packages/seal}/src/rules/string/email.mjs +2 -2
  286. package/esm/packages/seal/src/rules/string/email.mjs.map +1 -0
  287. package/esm/{seal → packages/seal}/src/rules/string/id-formats.mjs +1 -1
  288. package/esm/packages/seal/src/rules/string/id-formats.mjs.map +1 -0
  289. package/esm/{seal → packages/seal}/src/rules/string/ip.mjs +1 -1
  290. package/esm/packages/seal/src/rules/string/ip.mjs.map +1 -0
  291. package/esm/packages/seal/src/rules/string/matches.mjs +4 -0
  292. package/esm/{seal → packages/seal}/src/rules/string/pattern.mjs +1 -1
  293. package/esm/packages/seal/src/rules/string/pattern.mjs.map +1 -0
  294. package/esm/{seal → packages/seal}/src/rules/string/string-comparison.mjs +1 -1
  295. package/esm/packages/seal/src/rules/string/string-comparison.mjs.map +1 -0
  296. package/esm/{seal → packages/seal}/src/rules/string/strong-password-rule.mjs +1 -1
  297. package/esm/packages/seal/src/rules/string/strong-password-rule.mjs.map +1 -0
  298. package/esm/{seal → packages/seal}/src/rules/string/url.mjs +1 -1
  299. package/esm/packages/seal/src/rules/string/url.mjs.map +1 -0
  300. package/esm/{seal → packages/seal}/src/rules/string/without-whitespace.mjs +1 -1
  301. package/esm/packages/seal/src/rules/string/without-whitespace.mjs.map +1 -0
  302. package/esm/{seal → packages/seal}/src/standard-schema/json-schema.mjs +1 -1
  303. package/esm/packages/seal/src/standard-schema/json-schema.mjs.map +1 -0
  304. package/esm/{seal → packages/seal}/src/standard-schema/map-result.mjs +1 -1
  305. package/esm/packages/seal/src/standard-schema/map-result.mjs.map +1 -0
  306. package/esm/{seal → packages/seal}/src/string.mjs +1 -1
  307. package/esm/packages/seal/src/string.mjs.map +1 -0
  308. package/esm/{seal → packages/seal}/src/types/date-types.mjs +1 -1
  309. package/esm/packages/seal/src/types/date-types.mjs.map +1 -0
  310. package/esm/{seal → packages/seal}/src/validators/any-validator.mjs +1 -1
  311. package/esm/packages/seal/src/validators/any-validator.mjs.map +1 -0
  312. package/esm/{seal → packages/seal}/src/validators/array-validator.mjs +1 -1
  313. package/esm/packages/seal/src/validators/array-validator.mjs.map +1 -0
  314. package/esm/{seal → packages/seal}/src/validators/base-validator.mjs +25 -6
  315. package/esm/packages/seal/src/validators/base-validator.mjs.map +1 -0
  316. package/esm/{seal → packages/seal}/src/validators/boolean-validator.mjs +1 -1
  317. package/esm/packages/seal/src/validators/boolean-validator.mjs.map +1 -0
  318. package/esm/{seal → packages/seal}/src/validators/computed-validator.mjs +1 -1
  319. package/esm/packages/seal/src/validators/computed-validator.mjs.map +1 -0
  320. package/esm/{seal → packages/seal}/src/validators/date-validator.mjs +3 -3
  321. package/esm/packages/seal/src/validators/date-validator.mjs.map +1 -0
  322. package/esm/{seal → packages/seal}/src/validators/discriminated-union-validator.mjs +7 -2
  323. package/esm/packages/seal/src/validators/discriminated-union-validator.mjs.map +1 -0
  324. package/esm/{seal → packages/seal}/src/validators/float-validator.mjs +1 -1
  325. package/esm/packages/seal/src/validators/float-validator.mjs.map +1 -0
  326. package/esm/{seal → packages/seal}/src/validators/instanceof-validator.mjs +1 -1
  327. package/esm/packages/seal/src/validators/instanceof-validator.mjs.map +1 -0
  328. package/esm/{seal → packages/seal}/src/validators/int-validator.mjs +1 -1
  329. package/esm/packages/seal/src/validators/int-validator.mjs.map +1 -0
  330. package/esm/{seal → packages/seal}/src/validators/lazy-validator.mjs +1 -1
  331. package/esm/packages/seal/src/validators/lazy-validator.mjs.map +1 -0
  332. package/esm/{seal → packages/seal}/src/validators/literal-validator.mjs +5 -2
  333. package/esm/packages/seal/src/validators/literal-validator.mjs.map +1 -0
  334. package/esm/{seal → packages/seal}/src/validators/managed-validator.mjs +1 -1
  335. package/esm/packages/seal/src/validators/managed-validator.mjs.map +1 -0
  336. package/esm/{seal → packages/seal}/src/validators/methods/equality-conditional-methods.mjs +1 -1
  337. package/esm/packages/seal/src/validators/methods/equality-conditional-methods.mjs.map +1 -0
  338. package/esm/{seal → packages/seal}/src/validators/methods/forbidden-methods.mjs +1 -1
  339. package/esm/packages/seal/src/validators/methods/forbidden-methods.mjs.map +1 -0
  340. package/esm/{seal → packages/seal}/src/validators/methods/present-methods.mjs +1 -1
  341. package/esm/packages/seal/src/validators/methods/present-methods.mjs.map +1 -0
  342. package/esm/{seal → packages/seal}/src/validators/methods/required-methods.mjs +1 -1
  343. package/esm/packages/seal/src/validators/methods/required-methods.mjs.map +1 -0
  344. package/esm/{seal → packages/seal}/src/validators/number-validator.mjs +1 -1
  345. package/esm/packages/seal/src/validators/number-validator.mjs.map +1 -0
  346. package/esm/{seal → packages/seal}/src/validators/numeric-validator.mjs +2 -2
  347. package/esm/packages/seal/src/validators/numeric-validator.mjs.map +1 -0
  348. package/esm/{seal → packages/seal}/src/validators/object-validator.mjs +8 -6
  349. package/esm/packages/seal/src/validators/object-validator.mjs.map +1 -0
  350. package/esm/{seal → packages/seal}/src/validators/primitive-validator.mjs +1 -1
  351. package/esm/packages/seal/src/validators/primitive-validator.mjs.map +1 -0
  352. package/esm/{seal → packages/seal}/src/validators/record-validator.mjs +2 -2
  353. package/esm/packages/seal/src/validators/record-validator.mjs.map +1 -0
  354. package/esm/{seal → packages/seal}/src/validators/scalar-validator.mjs +1 -1
  355. package/esm/packages/seal/src/validators/scalar-validator.mjs.map +1 -0
  356. package/esm/{seal → packages/seal}/src/validators/string-validator.mjs +1 -1
  357. package/esm/packages/seal/src/validators/string-validator.mjs.map +1 -0
  358. package/esm/{seal → packages/seal}/src/validators/tuple-validator.mjs +1 -1
  359. package/esm/packages/seal/src/validators/tuple-validator.mjs.map +1 -0
  360. package/esm/{seal → packages/seal}/src/validators/union-validator.mjs +1 -1
  361. package/esm/packages/seal/src/validators/union-validator.mjs.map +1 -0
  362. package/esm/queue/bullmq-queue.d.mts +1 -1
  363. package/esm/queue/bullmq-queue.d.mts.map +1 -1
  364. package/esm/queue/bullmq-queue.mjs +1 -1
  365. package/esm/queue/bullmq-queue.mjs.map +1 -1
  366. package/esm/queue/herald-queue.d.mts +1 -1
  367. package/esm/queue/herald-queue.d.mts.map +1 -1
  368. package/esm/queue/herald-queue.mjs +1 -1
  369. package/esm/queue/herald-queue.mjs.map +1 -1
  370. package/esm/queue/load-herald.d.mts +1 -1
  371. package/esm/queue/load-herald.d.mts.map +1 -1
  372. package/esm/queue/load-herald.mjs +2 -2
  373. package/esm/queue/load-herald.mjs.map +1 -1
  374. package/esm/queue/load-queue.d.mts +1 -1
  375. package/esm/queue/load-queue.d.mts.map +1 -1
  376. package/esm/queue/load-queue.mjs +1 -1
  377. package/esm/queue/load-queue.mjs.map +1 -1
  378. package/esm/queue/notifications-worker.d.mts +1 -1
  379. package/esm/queue/notifications-worker.d.mts.map +1 -1
  380. package/esm/queue/notifications-worker.mjs +1 -1
  381. package/esm/queue/notifications-worker.mjs.map +1 -1
  382. package/esm/queue/queue-package-not-installed.error.d.mts +1 -1
  383. package/esm/queue/queue-package-not-installed.error.d.mts.map +1 -1
  384. package/esm/queue/queue-package-not-installed.error.mjs +1 -1
  385. package/esm/queue/queue-package-not-installed.error.mjs.map +1 -1
  386. package/esm/types.d.mts +1 -1
  387. package/esm/types.d.mts.map +1 -1
  388. package/llms-full.txt +57 -57
  389. package/llms.txt +8 -8
  390. package/package.json +9 -8
  391. package/skills/configure-notifications/SKILL.md +6 -6
  392. package/skills/define-channel/SKILL.md +6 -6
  393. package/skills/define-notification/SKILL.md +5 -5
  394. package/skills/notifications-basics/SKILL.md +8 -8
  395. package/skills/observe-notifications/SKILL.md +4 -4
  396. package/skills/queue-notifications/SKILL.md +5 -5
  397. package/skills/send-ad-hoc/SKILL.md +8 -8
  398. package/skills/use-in-app/SKILL.md +8 -8
  399. package/skills/write-notification-migration/SKILL.md +7 -7
  400. package/cjs/channel_api-CBB_XoIl.cjs.map +0 -1
  401. package/cjs/rabbitmq-driver-CYeFwv0w.cjs +0 -3
  402. package/cjs/src-B6UVThgW.cjs.map +0 -1
  403. package/esm/herald/src/communicators/broker-registry.mjs.map +0 -1
  404. package/esm/herald/src/communicators/broker.mjs.map +0 -1
  405. package/esm/herald/src/decorators/consumable.mjs.map +0 -1
  406. package/esm/herald/src/drivers/rabbitmq/rabbitmq-channel.mjs.map +0 -1
  407. package/esm/herald/src/drivers/rabbitmq/rabbitmq-driver.mjs.map +0 -1
  408. package/esm/herald/src/message-managers/event-consumer.mjs.map +0 -1
  409. package/esm/herald/src/message-managers/event-message.mjs.map +0 -1
  410. package/esm/herald/src/message-managers/prepare-consumer-subscription.mjs.map +0 -1
  411. package/esm/herald/src/use-case-broadcast.mjs.map +0 -1
  412. package/esm/herald/src/utils/connect-to-broker.mjs.map +0 -1
  413. package/esm/seal/src/config.mjs.map +0 -1
  414. package/esm/seal/src/factory/validate.mjs.map +0 -1
  415. package/esm/seal/src/factory/validators.mjs.map +0 -1
  416. package/esm/seal/src/helpers/date-helpers.mjs.map +0 -1
  417. package/esm/seal/src/helpers/get-field-value.mjs.map +0 -1
  418. package/esm/seal/src/helpers/is-empty-value.mjs +0 -10
  419. package/esm/seal/src/helpers/is-empty-value.mjs.map +0 -1
  420. package/esm/seal/src/helpers/path-helpers.mjs.map +0 -1
  421. package/esm/seal/src/helpers/validation-helpers.mjs.map +0 -1
  422. package/esm/seal/src/mutators/array-mutators.mjs.map +0 -1
  423. package/esm/seal/src/mutators/boolean-mutators.mjs.map +0 -1
  424. package/esm/seal/src/mutators/date-mutators.mjs.map +0 -1
  425. package/esm/seal/src/mutators/number-mutators.mjs.map +0 -1
  426. package/esm/seal/src/mutators/object-mutators.mjs.map +0 -1
  427. package/esm/seal/src/mutators/scalar-mutators.mjs.map +0 -1
  428. package/esm/seal/src/mutators/string-mutators.mjs.map +0 -1
  429. package/esm/seal/src/object.mjs.map +0 -1
  430. package/esm/seal/src/rules/array/array-rules.mjs.map +0 -1
  431. package/esm/seal/src/rules/color/color-rules.mjs.map +0 -1
  432. package/esm/seal/src/rules/common/enum.mjs.map +0 -1
  433. package/esm/seal/src/rules/common/equals-field-rules.mjs.map +0 -1
  434. package/esm/seal/src/rules/common/instanceof.mjs.map +0 -1
  435. package/esm/seal/src/rules/common/literal.mjs.map +0 -1
  436. package/esm/seal/src/rules/common/type-rules.mjs.map +0 -1
  437. package/esm/seal/src/rules/common/unknown-key.mjs.map +0 -1
  438. package/esm/seal/src/rules/conditional/forbidden-if-rules.mjs.map +0 -1
  439. package/esm/seal/src/rules/conditional/present-if-rules.mjs.map +0 -1
  440. package/esm/seal/src/rules/conditional/present-unless-rules.mjs.map +0 -1
  441. package/esm/seal/src/rules/conditional/present-with-rules.mjs.map +0 -1
  442. package/esm/seal/src/rules/conditional/present-without-rules.mjs.map +0 -1
  443. package/esm/seal/src/rules/conditional/required-if-rules.mjs.map +0 -1
  444. package/esm/seal/src/rules/conditional/required-unless-rules.mjs.map +0 -1
  445. package/esm/seal/src/rules/conditional/required-when-rule.mjs.map +0 -1
  446. package/esm/seal/src/rules/conditional/required-with-rules.mjs.map +0 -1
  447. package/esm/seal/src/rules/conditional/required-without-rules.mjs.map +0 -1
  448. package/esm/seal/src/rules/core/equal.mjs.map +0 -1
  449. package/esm/seal/src/rules/core/forbidden.mjs.map +0 -1
  450. package/esm/seal/src/rules/core/required.mjs.map +0 -1
  451. package/esm/seal/src/rules/core/union.mjs.map +0 -1
  452. package/esm/seal/src/rules/core/when.mjs.map +0 -1
  453. package/esm/seal/src/rules/date/date-comparison-rules.mjs.map +0 -1
  454. package/esm/seal/src/rules/date/date-day-rules.mjs.map +0 -1
  455. package/esm/seal/src/rules/date/date-field-comparison-rules.mjs.map +0 -1
  456. package/esm/seal/src/rules/date/date-period-rules.mjs.map +0 -1
  457. package/esm/seal/src/rules/date/date-relative-rules.mjs.map +0 -1
  458. package/esm/seal/src/rules/date/date-special-rules.mjs.map +0 -1
  459. package/esm/seal/src/rules/date/date.mjs.map +0 -1
  460. package/esm/seal/src/rules/length/length-rules.mjs.map +0 -1
  461. package/esm/seal/src/rules/number/number-rules.mjs.map +0 -1
  462. package/esm/seal/src/rules/scalar/accepted-rule.mjs.map +0 -1
  463. package/esm/seal/src/rules/scalar/declined-rule.mjs.map +0 -1
  464. package/esm/seal/src/rules/string/alpha.mjs.map +0 -1
  465. package/esm/seal/src/rules/string/credit-card.mjs.map +0 -1
  466. package/esm/seal/src/rules/string/email.mjs.map +0 -1
  467. package/esm/seal/src/rules/string/id-formats.mjs.map +0 -1
  468. package/esm/seal/src/rules/string/ip.mjs.map +0 -1
  469. package/esm/seal/src/rules/string/matches.mjs +0 -4
  470. package/esm/seal/src/rules/string/pattern.mjs.map +0 -1
  471. package/esm/seal/src/rules/string/string-comparison.mjs.map +0 -1
  472. package/esm/seal/src/rules/string/strong-password-rule.mjs.map +0 -1
  473. package/esm/seal/src/rules/string/url.mjs.map +0 -1
  474. package/esm/seal/src/rules/string/without-whitespace.mjs.map +0 -1
  475. package/esm/seal/src/standard-schema/json-schema.mjs.map +0 -1
  476. package/esm/seal/src/standard-schema/map-result.mjs.map +0 -1
  477. package/esm/seal/src/string.mjs.map +0 -1
  478. package/esm/seal/src/types/date-types.mjs.map +0 -1
  479. package/esm/seal/src/validators/any-validator.mjs.map +0 -1
  480. package/esm/seal/src/validators/array-validator.mjs.map +0 -1
  481. package/esm/seal/src/validators/base-validator.mjs.map +0 -1
  482. package/esm/seal/src/validators/boolean-validator.mjs.map +0 -1
  483. package/esm/seal/src/validators/computed-validator.mjs.map +0 -1
  484. package/esm/seal/src/validators/date-validator.mjs.map +0 -1
  485. package/esm/seal/src/validators/discriminated-union-validator.mjs.map +0 -1
  486. package/esm/seal/src/validators/float-validator.mjs.map +0 -1
  487. package/esm/seal/src/validators/instanceof-validator.mjs.map +0 -1
  488. package/esm/seal/src/validators/int-validator.mjs.map +0 -1
  489. package/esm/seal/src/validators/lazy-validator.mjs.map +0 -1
  490. package/esm/seal/src/validators/literal-validator.mjs.map +0 -1
  491. package/esm/seal/src/validators/managed-validator.mjs.map +0 -1
  492. package/esm/seal/src/validators/methods/equality-conditional-methods.mjs.map +0 -1
  493. package/esm/seal/src/validators/methods/forbidden-methods.mjs.map +0 -1
  494. package/esm/seal/src/validators/methods/present-methods.mjs.map +0 -1
  495. package/esm/seal/src/validators/methods/required-methods.mjs.map +0 -1
  496. package/esm/seal/src/validators/number-validator.mjs.map +0 -1
  497. package/esm/seal/src/validators/numeric-validator.mjs.map +0 -1
  498. package/esm/seal/src/validators/object-validator.mjs.map +0 -1
  499. package/esm/seal/src/validators/primitive-validator.mjs.map +0 -1
  500. package/esm/seal/src/validators/record-validator.mjs.map +0 -1
  501. package/esm/seal/src/validators/scalar-validator.mjs.map +0 -1
  502. package/esm/seal/src/validators/string-validator.mjs.map +0 -1
  503. package/esm/seal/src/validators/tuple-validator.mjs.map +0 -1
  504. package/esm/seal/src/validators/union-validator.mjs.map +0 -1
  505. /package/esm/{herald → packages/herald}/src/communicators/index.mjs +0 -0
  506. /package/esm/{herald → packages/herald}/src/decorators/index.mjs +0 -0
  507. /package/esm/{herald → packages/herald}/src/drivers/index.mjs +0 -0
  508. /package/esm/{herald → packages/herald}/src/drivers/rabbitmq/index.mjs +0 -0
  509. /package/esm/{herald → packages/herald}/src/index.mjs +0 -0
  510. /package/esm/{herald → packages/herald}/src/message-managers/index.mjs +0 -0
  511. /package/esm/{herald → packages/herald}/src/utils/index.mjs +0 -0
  512. /package/esm/{seal → packages/seal}/src/factory/index.mjs +0 -0
  513. /package/esm/{seal → packages/seal}/src/helpers/index.mjs +0 -0
  514. /package/esm/{seal → packages/seal}/src/index.mjs +0 -0
  515. /package/esm/{seal → packages/seal}/src/mutators/index.mjs +0 -0
  516. /package/esm/{seal → packages/seal}/src/rules/array/index.mjs +0 -0
  517. /package/esm/{seal → packages/seal}/src/rules/color/index.mjs +0 -0
  518. /package/esm/{seal → packages/seal}/src/rules/common/index.mjs +0 -0
  519. /package/esm/{seal → packages/seal}/src/rules/conditional/index.mjs +0 -0
  520. /package/esm/{seal → packages/seal}/src/rules/core/index.mjs +0 -0
  521. /package/esm/{seal → packages/seal}/src/rules/date/index.mjs +0 -0
  522. /package/esm/{seal → packages/seal}/src/rules/file/dimensions.mjs +0 -0
  523. /package/esm/{seal → packages/seal}/src/rules/file/file-size.mjs +0 -0
  524. /package/esm/{seal → packages/seal}/src/rules/file/index.mjs +0 -0
  525. /package/esm/{seal → packages/seal}/src/rules/index.mjs +0 -0
  526. /package/esm/{seal → packages/seal}/src/rules/length/index.mjs +0 -0
  527. /package/esm/{seal → packages/seal}/src/rules/number/index.mjs +0 -0
  528. /package/esm/{seal → packages/seal}/src/rules/scalar/index.mjs +0 -0
  529. /package/esm/{seal → packages/seal}/src/rules/string/index.mjs +0 -0
  530. /package/esm/{seal → packages/seal}/src/validators/index.mjs +0 -0
package/esm/types.d.mts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { Model } from "@warlock.js/cascade";
2
2
 
3
- //#region ../notifications/src/types.d.ts
3
+ //#region ../../packages/notifications/src/types.d.ts
4
4
  /**
5
5
  * A recipient you send TO (a User, etc.) — NOT the stored record.
6
6
  * It's a cascade `Model` instance, so `.id` (number | string) and `.get(path)`
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.mts","names":[],"sources":["../../../../../../notifications/src/types.ts"],"mappings":";;;AAqBA;;;;AAAc;AAKd;;AALA,KAHY,UAAA,GAAa,KAAK;;KAGlB,EAAA;;KAKA,WAAA;EACV,OAAA;EACA,IAAA;EACA,IAAA;EACA,EAAA;AAAA;;KAIU,iBAAA;EACV,WAAA,EAAa,EAAA;EACb,IAAA;EACA,KAAA;EACA,IAAA;EACA,OAAA,GAAU,MAAM,mBAAhB;EAEA,cAAA;AAAA;;AAAc;AAOhB;;KAAY,eAAA,GAAkB,IAAI,CAAC,iBAAA;;AAAiB;AAiBpD;;;;;;;;;AAE2B;AAG3B;UALiB,oBAAA;EACf,IAAA,EAAM,WAAA;EACN,QAAA,EAAU,eAAe;AAAA;AAAA,KAGf,WAAA,SAAoB,oBAAoB;;;;;;;;;;;;AAkC9C;KAlBM,WAAA;EAsBa;;;AAAmB;AAiB5C;;;EA/BE,KAAA,oBAqCW;EAnCX,MAAA,WA0CW;EAxCX,IAAA,GAAO,MAAM,mBAgDJ;EA9CT,cAAA,WAqDe;EAnDf,KAAA,YAqDsB;EAnDtB,IAAA;AAAA;;KAIU,aAAA,GAAgB,IAAI,CAAC,WAAA;;;;;;;;;;;;;;KAiBrB,kBAAA;EACV,OAAA;IACE,UAAA;IACA,OAAA;IACA,UAAA,GAAa,UAAA;IACb,OAAA;IACA,OAAA,EAAS,WAAA;EAAA;EAEX,IAAA;IACE,UAAA;IACA,OAAA;IACA,UAAA,GAAa,UAAA;IACb,OAAA;IACA,OAAA,EAAS,WAAA;IACT,UAAA;EAAA;EAEF,MAAA;IACE,UAAA;IACA,OAAA;IACA,UAAA,GAAa,UAAA;IACb,OAAA;IACA,KAAA,EAAO,KAAA;IACP,OAAA,EAAS,WAAA;IACT,UAAA;EAAA;EAEF,OAAA;IACE,UAAA;IACA,OAAA;IACA,UAAA,GAAa,UAAA;IACb,MAAA;IACA,OAAA,EAAS,WAAA;EAAA;AAAA"}
1
+ {"version":3,"file":"types.d.mts","names":[],"sources":["../../../../../../../packages/notifications/src/types.ts"],"mappings":";;;AAqBA;;;;AAAc;AAKd;;AALA,KAHY,UAAA,GAAa,KAAK;;KAGlB,EAAA;;KAKA,WAAA;EACV,OAAA;EACA,IAAA;EACA,IAAA;EACA,EAAA;AAAA;;KAIU,iBAAA;EACV,WAAA,EAAa,EAAA;EACb,IAAA;EACA,KAAA;EACA,IAAA;EACA,OAAA,GAAU,MAAM,mBAAhB;EAEA,cAAA;AAAA;;AAAc;AAOhB;;KAAY,eAAA,GAAkB,IAAI,CAAC,iBAAA;;AAAiB;AAiBpD;;;;;;;;;AAE2B;AAG3B;UALiB,oBAAA;EACf,IAAA,EAAM,WAAA;EACN,QAAA,EAAU,eAAe;AAAA;AAAA,KAGf,WAAA,SAAoB,oBAAoB;;;;;;;;;;;;AAkC9C;KAlBM,WAAA;EAsBa;;;AAAmB;AAiB5C;;;EA/BE,KAAA,oBAqCW;EAnCX,MAAA,WA0CW;EAxCX,IAAA,GAAO,MAAM,mBAgDJ;EA9CT,cAAA,WAqDe;EAnDf,KAAA,YAqDsB;EAnDtB,IAAA;AAAA;;KAIU,aAAA,GAAgB,IAAI,CAAC,WAAA;;;;;;;;;;;;;;KAiBrB,kBAAA;EACV,OAAA;IACE,UAAA;IACA,OAAA;IACA,UAAA,GAAa,UAAA;IACb,OAAA;IACA,OAAA,EAAS,WAAA;EAAA;EAEX,IAAA;IACE,UAAA;IACA,OAAA;IACA,UAAA,GAAa,UAAA;IACb,OAAA;IACA,OAAA,EAAS,WAAA;IACT,UAAA;EAAA;EAEF,MAAA;IACE,UAAA;IACA,OAAA;IACA,UAAA,GAAa,UAAA;IACb,OAAA;IACA,KAAA,EAAO,KAAA;IACP,OAAA,EAAS,WAAA;IACT,UAAA;EAAA;EAEF,OAAA;IACE,UAAA;IACA,OAAA;IACA,UAAA,GAAa,UAAA;IACb,MAAA;IACA,OAAA,EAAS,WAAA;EAAA;AAAA"}
package/llms-full.txt CHANGED
@@ -8,7 +8,7 @@
8
8
 
9
9
  ---
10
10
  name: configure-notifications
11
- description: 'Wire `@warlock.js/notifications` via a declarative `src/config/notifications.ts` that exports a `NotificationConfig` default — the notifications connector registers it at boot, so app code never calls `setNotificationConfig`. `channels`: registry mapping name → factory result (`mailChannel`, `inApp.configure`, custom `defineChannel`); `queue`: optional `QueueDispatcher` (`.queue()` throws without it); `preferences`: optional `PreferenceProvider` (drops channels the recipient muted); `rateLimit`: optional `RateLimiter` (drops channels exceeding per-recipient budgets). Triggers: `config/notifications.ts`, `NotificationConfig`, `setNotificationConfig`, `getNotificationConfig`, `mailChannel`, `inApp.configure`, "configure notifications", "wire notifications at boot", "set preferences provider", "set rate limit"; typical import `import { type NotificationConfig, mailChannel, inApp } from "@warlock.js/notifications"`. Skip: building a reusable notification — `@warlock.js/notifications/define-notification/SKILL.md`; the in-app read API — `@warlock.js/notifications/use-in-app/SKILL.md`; adding a custom channel — `@warlock.js/notifications/define-channel/SKILL.md`.'
11
+ description: 'Wire `@warlock.js/notifications` via a declarative `src/config/notifications.ts` that exports a `NotificationConfig` default — the notifications connector registers it at boot, so app code never calls `setNotificationConfig`. `channels`: registry mapping name → factory result (`mailChannel`, `inApp.configure`, custom `defineChannel`); `queue`: optional `QueueDispatcher` (`.queue()` throws without it); `preferences`: optional `PreferenceProvider` (drops channels the recipient muted); `rateLimit`: optional `RateLimiter` (drops channels exceeding per-recipient budgets). Triggers: `config/notifications.ts`, `NotificationConfig`, `setNotificationConfig`, `getNotificationConfig`, `mailChannel`, `inApp.configure`, "configure notifications", "wire notifications at boot", "set preferences provider", "set rate limit"; typical import `import { type NotificationConfig, mailChannel, inApp } from "@warlock.js/notifications"`. Skip: building a reusable notification — the `define-notification` topic; the in-app read API — the `use-in-app` topic; adding a custom channel — the `define-channel` topic.'
12
12
  ---
13
13
 
14
14
  # Configure notifications
@@ -21,7 +21,7 @@ description: 'Wire `@warlock.js/notifications` via a declarative `src/config/not
21
21
 
22
22
  ```ts title="src/config/notifications.ts"
23
23
  import { type NotificationConfig, inApp, mailChannel } from "@warlock.js/notifications";
24
- import { Notification } from "app/notifications/notification.model";
24
+ import { Notification } from "app/notifications/models/notification/notification.model";
25
25
 
26
26
  const config: NotificationConfig = {
27
27
  channels: {
@@ -140,17 +140,17 @@ afterEach(() => resetNotificationConfig());
140
140
 
141
141
  ## See also
142
142
 
143
- - [`notifications-basics/SKILL.md`](../notifications-basics/SKILL.md) — package front door.
144
- - [`define-notification/SKILL.md`](../define-notification/SKILL.md) — reusable multi-channel definitions.
145
- - [`use-in-app/SKILL.md`](../use-in-app/SKILL.md) — in-app read API.
146
- - [`define-channel/SKILL.md`](../define-channel/SKILL.md) — custom channels.
143
+ - The `notifications-basics` topic — package front door.
144
+ - The `define-notification` topic — reusable multi-channel definitions.
145
+ - The `use-in-app` topic — in-app read API.
146
+ - The `define-channel` topic — custom channels.
147
147
 
148
148
 
149
149
  ## define-channel `@warlock.js/notifications/define-channel/SKILL.md`
150
150
 
151
151
  ---
152
152
  name: define-channel
153
- description: 'Add a custom notification channel — `defineChannel<P>({ name, route?, send })` returns a `Channel<P>` you register in the `channels` map of `setNotificationConfig`. `name` matches the key in `NotificationChannels` (extend via `declare module` for typing); `route(notifiable)` resolves the recipient''s address (defaults to `{ id }` when omitted); `send({ payload, route, notifiable, options })` does the actual transport. Use for Slack/Discord/internal-webhook/anything else — `fetch`-based with NO SDK is the simplest variant. Channels that load a heavy SDK should follow the lazy-import pattern from the develop-feature playbook. Triggers: `defineChannel`, `Channel<P>`, "custom notification channel", "add discord channel", "slack channel", "webhook channel", "new channel type", `declare module "@warlock.js/notifications"`; typical import `import { defineChannel } from "@warlock.js/notifications"`. Skip: lazy-loading an optional SDK behind the channel — `D:/xampp/htdocs/mongez/node/.claude/skills/develop-warlock.js-feature/SKILL.md`; using built-in channels — `@warlock.js/notifications/configure-notifications/SKILL.md`.'
153
+ description: 'Add a custom notification channel — `defineChannel<P>({ name, route?, send })` returns a `Channel<P>` you register in the `channels` map of `setNotificationConfig`. `name` matches the key in `NotificationChannels` (extend via `declare module` for typing); `route(notifiable)` resolves the recipient''s address (defaults to `{ id }` when omitted); `send({ payload, route, notifiable, options })` does the actual transport. Use for Slack/Discord/internal-webhook/anything else — `fetch`-based with NO SDK is the simplest variant. Channels that load a heavy SDK should follow the lazy-import pattern from the develop-feature playbook. Triggers: `defineChannel`, `Channel<P>`, "custom notification channel", "add discord channel", "slack channel", "webhook channel", "new channel type", `declare module "@warlock.js/notifications"`; typical import `import { defineChannel } from "@warlock.js/notifications"`. Skip: lazy-loading an optional SDK behind the channel — the `develop-warlock.js-feature` workspace skill; using built-in channels — the `configure-notifications` topic.'
154
154
  ---
155
155
 
156
156
  # `defineChannel` — custom channels
@@ -224,7 +224,7 @@ Throw to fail the send. The dispatcher catches per channel, fires a `failed` eve
224
224
 
225
225
  ## SDK-backed channels — lazy-import the SDK
226
226
 
227
- Channels that wrap a heavy SDK (Twilio, Slack SDK, FCM SDK) should follow the lazy-import pattern so apps that don't use them don't pay the install/load cost. The recipe + race-safe template lives in [`develop-warlock.js-feature`](../../../../.claude/skills/develop-warlock.js-feature/SKILL.md) — copy from there; do not invent a variant.
227
+ Channels that wrap a heavy SDK (Twilio, Slack SDK, FCM SDK) should follow the lazy-import pattern so apps that don't use them don't pay the install/load cost. The recipe + race-safe template lives in the `develop-warlock.js-feature` workspace skill — copy from there; do not invent a variant.
228
228
 
229
229
  Sketch:
230
230
 
@@ -251,17 +251,17 @@ export const slackChannel = (config: { token: string }) =>
251
251
 
252
252
  ## See also
253
253
 
254
- - [`configure-notifications/SKILL.md`](../configure-notifications/SKILL.md) — register channels in the config.
255
- - [`send-ad-hoc/SKILL.md`](../send-ad-hoc/SKILL.md) — `notify.<custom-channel>` works after registration.
256
- - [`define-notification/SKILL.md`](../define-notification/SKILL.md) — multi-channel renderers with the custom channel key.
257
- - `D:/xampp/htdocs/mongez/node/.claude/skills/develop-warlock.js-feature/SKILL.md` — lazy-import pattern for SDK-backed channels.
254
+ - The `configure-notifications` topic — register channels in the config.
255
+ - The `send-ad-hoc` topic — `notify.<custom-channel>` works after registration.
256
+ - The `define-notification` topic — multi-channel renderers with the custom channel key.
257
+ - The `develop-warlock.js-feature` workspace skill — lazy-import pattern for SDK-backed channels.
258
258
 
259
259
 
260
260
  ## define-notification `@warlock.js/notifications/define-notification/SKILL.md`
261
261
 
262
262
  ---
263
263
  name: define-notification
264
- description: 'Build a reusable multi-channel notification with `defineNotification<Data>({ type, via, ...renderers })`. `type` is the stable identifier preference/rate-limit gates use AND defaults the database channel''s `type`. `via` is `ChannelName[]` OR `(data, to) => ChannelName[]` for per-recipient channel selection. Renderers are `(data, to, ctx) => NotificationChannels[C]`; `ctx` carries `locale` + `meta` from `SendOptions`. The returned object exposes `.send(to|to[], data, options?)`, `.queue(to|to[], data, options?)`, and `.only(...channels)`. Per-recipient + per-channel `Promise.allSettled` isolates failures; the database channel''s `type` is auto-defaulted from `def.type`; `SendOptions.idempotencyKey` is injected into the database payload. Triggers: `defineNotification`, `via`, "reusable notification", "multi-channel notification", "send through several channels at once", "render per channel", `RenderContext`, `def.type`; "force on a notification", "queue with delay"; typical import `import { defineNotification } from "@warlock.js/notifications"`. Skip: single-channel ad-hoc sends — `@warlock.js/notifications/send-ad-hoc/SKILL.md`; adding a brand-new channel — `@warlock.js/notifications/define-channel/SKILL.md`; observing dispatch outcomes — `@warlock.js/notifications/observe-notifications/SKILL.md`.'
264
+ description: 'Build a reusable multi-channel notification with `defineNotification<Data>({ type, via, ...renderers })`. `type` is the stable identifier preference/rate-limit gates use AND defaults the database channel''s `type`. `via` is `ChannelName[]` OR `(data, to) => ChannelName[]` for per-recipient channel selection. Renderers are `(data, to, ctx) => NotificationChannels[C]`; `ctx` carries `locale` + `meta` from `SendOptions`. The returned object exposes `.send(to|to[], data, options?)`, `.queue(to|to[], data, options?)`, and `.only(...channels)`. Per-recipient + per-channel `Promise.allSettled` isolates failures; the database channel''s `type` is auto-defaulted from `def.type`; `SendOptions.idempotencyKey` is injected into the database payload. Triggers: `defineNotification`, `via`, "reusable notification", "multi-channel notification", "send through several channels at once", "render per channel", `RenderContext`, `def.type`; "force on a notification", "queue with delay"; typical import `import { defineNotification } from "@warlock.js/notifications"`. Skip: single-channel ad-hoc sends — the `send-ad-hoc` topic; adding a brand-new channel — the `define-channel` topic; observing dispatch outcomes — the `observe-notifications` topic.'
265
265
  ---
266
266
 
267
267
  # `defineNotification` — reusable multi-channel notification
@@ -388,10 +388,10 @@ Per-recipient: each recipient gets an independent `Promise.allSettled`. Per-chan
388
388
 
389
389
  ## See also
390
390
 
391
- - [`notifications-basics/SKILL.md`](../notifications-basics/SKILL.md) — package front door.
392
- - [`send-ad-hoc/SKILL.md`](../send-ad-hoc/SKILL.md) — `notify.<channel>` per-channel shorthand.
393
- - [`configure-notifications/SKILL.md`](../configure-notifications/SKILL.md) — wire channels + preferences + rate-limit + queue.
394
- - [`observe-notifications/SKILL.md`](../observe-notifications/SKILL.md) — `notifications.on("sending" | "sent" | "failed" | "skipped", …)`.
391
+ - The `notifications-basics` topic — package front door.
392
+ - The `send-ad-hoc` topic — `notify.<channel>` per-channel shorthand.
393
+ - The `configure-notifications` topic — wire channels + preferences + rate-limit + queue.
394
+ - The `observe-notifications` topic — `notifications.on("sending" | "sent" | "failed" | "skipped", …)`.
395
395
 
396
396
 
397
397
  ## notifications-basics `@warlock.js/notifications/notifications-basics/SKILL.md`
@@ -428,7 +428,7 @@ It is NOT a queue, a template engine, a transport library, or an analytics pipel
428
428
 
429
429
  ```ts title="src/config/notifications.ts"
430
430
  import { type NotificationConfig, mailChannel, inApp } from "@warlock.js/notifications";
431
- import { Notification } from "app/notifications/notification.model";
431
+ import { Notification } from "app/notifications/models/notification/notification.model";
432
432
 
433
433
  const config: NotificationConfig = {
434
434
  channels: {
@@ -487,20 +487,20 @@ await inApp.markAsRead(user, "ntf_123");
487
487
 
488
488
  ## See also
489
489
 
490
- - [`configure-notifications/SKILL.md`](../configure-notifications/SKILL.md) — wire `config/notifications.ts`.
491
- - [`define-notification/SKILL.md`](../define-notification/SKILL.md) — reusable multi-channel definitions.
492
- - [`send-ad-hoc/SKILL.md`](../send-ad-hoc/SKILL.md) — `notify.<channel>` shorthand.
493
- - [`use-in-app/SKILL.md`](../use-in-app/SKILL.md) — `inApp` read API.
494
- - [`define-channel/SKILL.md`](../define-channel/SKILL.md) — custom channels.
495
- - [`write-notification-migration/SKILL.md`](../write-notification-migration/SKILL.md) — columnMap-driven columns.
496
- - [`observe-notifications/SKILL.md`](../observe-notifications/SKILL.md) — events + metrics.
490
+ - The `configure-notifications` topic — wire `config/notifications.ts`.
491
+ - The `define-notification` topic — reusable multi-channel definitions.
492
+ - The `send-ad-hoc` topic — `notify.<channel>` shorthand.
493
+ - The `use-in-app` topic — `inApp` read API.
494
+ - The `define-channel` topic — custom channels.
495
+ - The `write-notification-migration` topic — columnMap-driven columns.
496
+ - The `observe-notifications` topic — events + metrics.
497
497
 
498
498
 
499
499
  ## observe-notifications `@warlock.js/notifications/observe-notifications/SKILL.md`
500
500
 
501
501
  ---
502
502
  name: observe-notifications
503
- description: 'Wire metrics, logging, tracing, and audits via `notifications.on(event, handler)` — four events fire per (channel, recipient): `sending` (gates passed, about to hit the transport), `sent` (succeeded), `failed` (channel threw — carries the Error), `skipped` (a pre-send gate dropped it — carries `reason: "preference" | "rate-limit"`). Every event carries the recipient as `notifiable?` (undefined only for raw-target ad-hoc sends) and a `dispatchId` — `sending` and its terminal `sent`/`failed` share it, so observers can pair them (spans, latency, hung-send detection). `sent`/`failed` also carry `durationMs`. Handler exceptions are logged-and-swallowed so one bad listener can not break the dispatcher. `on(...)` returns an unsubscribe function; `off(event, handler)` exists for symmetry. Triggers: `notifications.on`, `notifications.off`, `"sending"` event, `"sent"` event, `"failed"` event, `"skipped"` event, `dispatchId`, `durationMs`, `NotificationEvents`, "notification metrics", "notification latency", "trace notifications", "notification audit log", "track notification drops"; typical import `import { notifications } from "@warlock.js/notifications"`. Skip: building notifications — `@warlock.js/notifications/define-notification/SKILL.md`; configuring the preference/rate-limit gates that produce `skipped` — `@warlock.js/notifications/configure-notifications/SKILL.md`.'
503
+ description: 'Wire metrics, logging, tracing, and audits via `notifications.on(event, handler)` — four events fire per (channel, recipient): `sending` (gates passed, about to hit the transport), `sent` (succeeded), `failed` (channel threw — carries the Error), `skipped` (a pre-send gate dropped it — carries `reason: "preference" | "rate-limit"`). Every event carries the recipient as `notifiable?` (undefined only for raw-target ad-hoc sends) and a `dispatchId` — `sending` and its terminal `sent`/`failed` share it, so observers can pair them (spans, latency, hung-send detection). `sent`/`failed` also carry `durationMs`. Handler exceptions are logged-and-swallowed so one bad listener can not break the dispatcher. `on(...)` returns an unsubscribe function; `off(event, handler)` exists for symmetry. Triggers: `notifications.on`, `notifications.off`, `"sending"` event, `"sent"` event, `"failed"` event, `"skipped"` event, `dispatchId`, `durationMs`, `NotificationEvents`, "notification metrics", "notification latency", "trace notifications", "notification audit log", "track notification drops"; typical import `import { notifications } from "@warlock.js/notifications"`. Skip: building notifications — the `define-notification` topic; configuring the preference/rate-limit gates that produce `skipped` — the `configure-notifications` topic.'
504
504
  ---
505
505
 
506
506
  # Observe notifications
@@ -561,16 +561,16 @@ A handler that throws is logged and swallowed — the other handlers for the sam
561
561
 
562
562
  ## See also
563
563
 
564
- - [`notifications-basics/SKILL.md`](../notifications-basics/SKILL.md) — front door + mental model.
565
- - [`configure-notifications/SKILL.md`](../configure-notifications/SKILL.md) — `preferences` / `rateLimit` slots that emit `skipped`.
566
- - [`send-ad-hoc/SKILL.md`](../send-ad-hoc/SKILL.md) — when `notifiable` is undefined in events.
564
+ - The `notifications-basics` topic — front door + mental model.
565
+ - The `configure-notifications` topic — `preferences` / `rateLimit` slots that emit `skipped`.
566
+ - The `send-ad-hoc` topic — when `notifiable` is undefined in events.
567
567
 
568
568
 
569
569
  ## queue-notifications `@warlock.js/notifications/queue-notifications/SKILL.md`
570
570
 
571
571
  ---
572
572
  name: queue-notifications
573
- description: "Send notifications asynchronously through the herald backend or the BullMQ driver. Configure a QueueDispatcher in config/notifications.ts, then use notif.queue(to, data, options?) to enqueue rendered jobs. Herald uses heraldQueue() and startNotificationsWorker(); bullmqQueue({ attempts, backoff }) from @warlock.js/notifications uses BullMQ (lazy-loading the optional @warlock.js/queue peer), supports retries, and honours SendOptions.delay. Without a queue configured, .queue() rejects NoQueueDispatcherError. Triggers: heraldQueue, bullmqQueue, startNotificationsWorker, QueueDispatcher, .queue(, async notifications, queue notifications, notification worker, background notifications, notifications.dispatch. Skip: synchronous sends - @warlock.js/notifications/define-notification/SKILL.md; herald itself - @warlock.js/herald/*."
573
+ description: "Send notifications asynchronously through the herald backend or the BullMQ driver. Configure a QueueDispatcher in config/notifications.ts, then use notif.queue(to, data, options?) to enqueue rendered jobs. Herald uses heraldQueue() and startNotificationsWorker(); bullmqQueue({ attempts, backoff }) from @warlock.js/notifications uses BullMQ (lazy-loading the optional @warlock.js/queue peer), supports retries, and honours SendOptions.delay. Without a queue configured, .queue() rejects NoQueueDispatcherError. Triggers: heraldQueue, bullmqQueue, startNotificationsWorker, QueueDispatcher, .queue(, async notifications, queue notifications, notification worker, background notifications, notifications.dispatch. Skip: synchronous sends - the `define-notification` topic; herald itself - @warlock.js/herald/*."
574
574
  ---
575
575
 
576
576
  # Queue notifications (async)
@@ -587,7 +587,7 @@ import {
587
587
  inApp,
588
588
  mailChannel,
589
589
  } from "@warlock.js/notifications";
590
- import { Notification } from "app/notifications/notification.model";
590
+ import { Notification } from "app/notifications/models/notification/notification.model";
591
591
 
592
592
  const config: NotificationConfig = {
593
593
  channels: { mail: mailChannel(), database: inApp.configure({ model: Notification }) },
@@ -675,16 +675,16 @@ await orderShipped.queue(user, { order }, { idempotencyKey: `ship:${order.id}` }
675
675
 
676
676
  ## See also
677
677
 
678
- - [`define-notification/SKILL.md`](../define-notification/SKILL.md) - `.queue()` on a defined notification.
679
- - [`configure-notifications/SKILL.md`](../configure-notifications/SKILL.md) - the `queue` config slot.
680
- - [`@warlock.js/herald/herald-basics/SKILL.md`](../../../herald/skills/herald-basics/SKILL.md) - connecting the broker.
678
+ - The `define-notification` topic - `.queue()` on a defined notification.
679
+ - The `configure-notifications` topic - the `queue` config slot.
680
+ - The `herald-basics` topic of the `warlock-js-herald` skill - connecting the broker.
681
681
 
682
682
 
683
683
  ## send-ad-hoc `@warlock.js/notifications/send-ad-hoc/SKILL.md`
684
684
 
685
685
  ---
686
686
  name: send-ad-hoc
687
- description: 'Ad-hoc per-channel send via the `notify.<channel>(to, payload, options?)` Proxy facade. Works for any channel registered in `NotificationChannels` (built-in or custom). `to` accepts a `Notifiable` model OR a raw route string (`"x@y.com"`); `payload` is typed per channel via the registry; `options` is the standard `SendOptions`. `notify.channel(name).send(...)` is the runtime escape when the channel name is not a compile-time literal. Type-based preference gating applies when a type is known — explicit via `options.type` OR auto-detected from a database payload''s `type` field. For multi-channel sends use `defineNotification` instead — there is no inline `notify(to, { via, ... })` form on purpose. Triggers: `notify.<channel>`, `notify.channel(name)`, `notify.mail`, `notify.database`, "send a one-off notification", "ad-hoc notification", "send an email without defining a notification", "raw email target", "dynamic channel name"; typical import `import { notify } from "@warlock.js/notifications"`. Skip: reusable multi-channel notifications — `@warlock.js/notifications/define-notification/SKILL.md`; configuring channels — `@warlock.js/notifications/configure-notifications/SKILL.md`.'
687
+ description: 'Ad-hoc per-channel send via the `notify.<channel>(to, payload, options?)` Proxy facade. Works for any channel registered in `NotificationChannels` (built-in or custom). `to` accepts a `Notifiable` model OR a raw route string (`"x@y.com"`); `payload` is typed per channel via the registry; `options` is the standard `SendOptions`. `notify.channel(name).send(...)` is the runtime escape when the channel name is not a compile-time literal. Type-based preference gating applies when a type is known — explicit via `options.type` OR auto-detected from a database payload''s `type` field. For multi-channel sends use `defineNotification` instead — there is no inline `notify(to, { via, ... })` form on purpose. Triggers: `notify.<channel>`, `notify.channel(name)`, `notify.mail`, `notify.database`, "send a one-off notification", "ad-hoc notification", "send an email without defining a notification", "raw email target", "dynamic channel name"; typical import `import { notify } from "@warlock.js/notifications"`. Skip: reusable multi-channel notifications — the `define-notification` topic; configuring channels — the `configure-notifications` topic.'
688
688
  ---
689
689
 
690
690
  # `notify.<channel>` — ad-hoc, per-channel sends
@@ -698,7 +698,7 @@ await notify.mail(user, { subject: "Welcome", html: "<p>Hi!</p>" });
698
698
  await notify.database(user, { type: "welcome", title: "Welcome!" });
699
699
  ```
700
700
 
701
- For **multi-channel** sends, use [`defineNotification`](../define-notification/SKILL.md) — that's the reusable pattern and the only mental model for "send through several channels at once" (no inline multi-channel overload).
701
+ For **multi-channel** sends, use `defineNotification` (the `define-notification` topic) — that's the reusable pattern and the only mental model for "send through several channels at once" (no inline multi-channel overload).
702
702
 
703
703
  ## Shape
704
704
 
@@ -730,7 +730,7 @@ const channelName = await chooseChannelForUser(user);
730
730
  await notify.channel(channelName).send(user, payload);
731
731
  ```
732
732
 
733
- This is the only path with `unknown`-typed payloads — prefer the literal `notify.<channel>` when you can. `to` is still what decides the recipient: even for the `database` channel, a `recipientId`-shaped key on `payload` (or the model's physical recipient column name) is stripped before the row is built, so an untyped payload assembled from request JSON can't redirect the write to another recipient — see [`use-in-app/SKILL.md`](../use-in-app/SKILL.md#createfor-write-side--no-idor-either-since-4150).
733
+ This is the only path with `unknown`-typed payloads — prefer the literal `notify.<channel>` when you can. `to` is still what decides the recipient: even for the `database` channel, a `recipientId`-shaped key on `payload` (or the model's physical recipient column name) is stripped before the row is built, so an untyped payload assembled from request JSON can't redirect the write to another recipient — see the `createFor` write-side section of the `use-in-app` topic.
734
734
 
735
735
  ## Opt into preference/rate-limit gating
736
736
 
@@ -749,7 +749,7 @@ await notify.database(user, { type: "welcome", title: "Welcome!" });
749
749
 
750
750
  ## Custom channels
751
751
 
752
- After registering a custom channel (see [`define-channel`](../define-channel/SKILL.md)), it's first-class:
752
+ After registering a custom channel (see the `define-channel` topic), it's first-class:
753
753
 
754
754
  ```ts
755
755
  await notify.discord(user, { content: "Build finished 🎉" });
@@ -773,17 +773,17 @@ await notify.slack(staff, { text: "Deploy starting" });
773
773
 
774
774
  ## See also
775
775
 
776
- - [`notifications-basics/SKILL.md`](../notifications-basics/SKILL.md) — front door + mental model.
777
- - [`define-notification/SKILL.md`](../define-notification/SKILL.md) — reusable multi-channel.
778
- - [`define-channel/SKILL.md`](../define-channel/SKILL.md) — register a custom channel.
779
- - [`observe-notifications/SKILL.md`](../observe-notifications/SKILL.md) — `sending` / `sent` / `failed` / `skipped` events.
776
+ - The `notifications-basics` topic — front door + mental model.
777
+ - The `define-notification` topic — reusable multi-channel.
778
+ - The `define-channel` topic — register a custom channel.
779
+ - The `observe-notifications` topic — `sending` / `sent` / `failed` / `skipped` events.
780
780
 
781
781
 
782
782
  ## use-in-app `@warlock.js/notifications/use-in-app/SKILL.md`
783
783
 
784
784
  ---
785
785
  name: use-in-app
786
- description: 'Use the `inApp` facade for the in-app/database channel''s READ side: `inApp.configure({ model: Notification })` or `{ repository: myRepo }` binds the store AND returns the channel; `inApp.list / listUnread / countUnread / markAsRead / markAsUnread` are RECIPIENT-SCOPED by construction (no IDOR — `markAsRead(user, id)` cannot flip another user''s row even with a foreign id). `countUnread` uses `RepositoryManager.countCached` for the badge fast-path. Triggers: `inApp.configure`, `inApp.list`, `inApp.listUnread`, `inApp.countUnread`, `inApp.markAsRead`, `inApp.markAsUnread`, `BaseNotificationsRepository`, `DatabaseNotification`, `NotificationsFilter`, "in-app notifications", "mark notification as read", "unread count", "notification badge", "IDOR-safe markAsRead"; typical import `import { inApp } from "@warlock.js/notifications"`. Skip: writing notifications (use `defineNotification` or `notify.database`) — `@warlock.js/notifications/define-notification/SKILL.md`; the migration columns — `@warlock.js/notifications/write-notification-migration/SKILL.md`; wiring it into config — `@warlock.js/notifications/configure-notifications/SKILL.md`.'
786
+ description: 'Use the `inApp` facade for the in-app/database channel''s READ side: `inApp.configure({ model: Notification })` or `{ repository: myRepo }` binds the store AND returns the channel; `inApp.list / listUnread / countUnread / markAsRead / markAsUnread` are RECIPIENT-SCOPED by construction (no IDOR — `markAsRead(user, id)` cannot flip another user''s row even with a foreign id). `countUnread` uses `RepositoryManager.countCached` for the badge fast-path. Triggers: `inApp.configure`, `inApp.list`, `inApp.listUnread`, `inApp.countUnread`, `inApp.markAsRead`, `inApp.markAsUnread`, `BaseNotificationsRepository`, `DatabaseNotification`, `NotificationsFilter`, "in-app notifications", "mark notification as read", "unread count", "notification badge", "IDOR-safe markAsRead"; typical import `import { inApp } from "@warlock.js/notifications"`. Skip: writing notifications (use `defineNotification` or `notify.database`) — the `define-notification` topic; the migration columns — the `write-notification-migration` topic; wiring it into config — the `configure-notifications` topic.'
787
787
  ---
788
788
 
789
789
  # `inApp` — in-app notification read API
@@ -895,7 +895,7 @@ the repo; there is no `isRead` filter key to remember.
895
895
 
896
896
  ## Your model — declare `table`, `schema`, and `columnMap`
897
897
 
898
- ```ts title="src/app/notifications/notification.model.ts"
898
+ ```ts title="src/app/notifications/models/notification/notification.model.ts"
899
899
  import { RegisterModel } from "@warlock.js/cascade";
900
900
  import { v } from "@warlock.js/seal";
901
901
  import { DatabaseNotification, type NotificationColumnMap } from "@warlock.js/notifications";
@@ -930,9 +930,9 @@ repo filter, and the accessors all follow. For a different driver's naming
930
930
 
931
931
  `columnMap` already covers column naming. Subclass only for EXTRA query methods:
932
932
 
933
- ```ts title="src/app/notifications/notifications.repository.ts"
933
+ ```ts title="src/app/notifications/repositories/notifications.repository.ts"
934
934
  import { BaseNotificationsRepository } from "@warlock.js/notifications";
935
- import { Notification } from "./notification.model";
935
+ import { Notification } from "../models/notification/notification.model";
936
936
 
937
937
  export class NotificationsRepository extends BaseNotificationsRepository<Notification> {
938
938
  public source = Notification; // its columnMap still drives filter + write mapping
@@ -949,17 +949,17 @@ database: inApp.configure({ repository: notificationsRepository }),
949
949
 
950
950
  ## See also
951
951
 
952
- - [`notifications-basics/SKILL.md`](../notifications-basics/SKILL.md) — package front door.
953
- - [`configure-notifications/SKILL.md`](../configure-notifications/SKILL.md) — wire `inApp.configure` into the config.
954
- - [`write-notification-migration/SKILL.md`](../write-notification-migration/SKILL.md) — `notificationColumns(Notification)`, named from `columnMap`.
955
- - [`define-notification/SKILL.md`](../define-notification/SKILL.md) — create rows via the database channel.
952
+ - The `notifications-basics` topic — package front door.
953
+ - The `configure-notifications` topic — wire `inApp.configure` into the config.
954
+ - The `write-notification-migration` topic — `notificationColumns(Notification)`, named from `columnMap`.
955
+ - The `define-notification` topic — create rows via the database channel.
956
956
 
957
957
 
958
958
  ## write-notification-migration `@warlock.js/notifications/write-notification-migration/SKILL.md`
959
959
 
960
960
  ---
961
961
  name: write-notification-migration
962
- description: 'Create the notifications table with the `notificationColumns(Notification)` factory + cascade `Migration.create`. Column NAMES come from the model''s `columnMap` (recipient / tenant / readAt / isRead); the fixed columns are `type` / `title` / `body` / `payload` / `idempotency_key`. Set `{ idType: "bigint" }` for integer-key apps; UUID remains the default. Read-state follows columnMap presence: `readAt` → nullable timestamp, `isRead` → indexed boolean, both → both. Defaults to `user_id` + `read_at` when no columnMap. Spread + extend for extras (FK references, composite indexes). Triggers: `notificationColumns`, `Migration.create` for notifications, "create the notifications table", "notification migration", "add organization_id to notifications", `is_read` column, `read_at` column, `idempotency_key` column; typical import `import { Migration } from "@warlock.js/cascade"; import { notificationColumns } from "@warlock.js/notifications"`. Skip: generic cascade migration writing — `@warlock.js/cascade/write-migration/SKILL.md`; the model itself — `@warlock.js/notifications/use-in-app/SKILL.md`.'
962
+ description: 'Create the notifications table with the `notificationColumns(Notification)` factory + cascade `Migration.create`. Column NAMES come from the model''s `columnMap` (recipient / tenant / readAt / isRead); the fixed columns are `type` / `title` / `body` / `payload` / `idempotency_key`. Set `{ idType: "bigint" }` for integer-key apps; UUID remains the default. Read-state follows columnMap presence: `readAt` → nullable timestamp, `isRead` → indexed boolean, both → both. Defaults to `user_id` + `read_at` when no columnMap. Spread + extend for extras (FK references, composite indexes). Triggers: `notificationColumns`, `Migration.create` for notifications, "create the notifications table", "notification migration", "add organization_id to notifications", `is_read` column, `read_at` column, `idempotency_key` column; typical import `import { Migration } from "@warlock.js/cascade"; import { notificationColumns } from "@warlock.js/notifications"`. Skip: generic cascade migration writing — the `write-migration` topic of the `warlock-js-cascade` skill; the model itself — the `use-in-app` topic.'
963
963
  ---
964
964
 
965
965
  # Write the notifications migration
@@ -970,7 +970,7 @@ The package ships no table or migration (thin eject). You own the migration; the
970
970
 
971
971
  ## Common case — one line
972
972
 
973
- ```ts title="src/app/notifications/migrations/01-01-2026_00-00-00-notifications.migration.ts"
973
+ ```ts title="src/app/notifications/models/notification/migrations/01-01-2026_00-00-00-notifications.migration.ts"
974
974
  import { Migration } from "@warlock.js/cascade";
975
975
  import { notificationColumns } from "@warlock.js/notifications";
976
976
  import { Notification } from "../notification.model";
@@ -1017,7 +1017,7 @@ export default Migration.create(Notification, {
1017
1017
  });
1018
1018
  ```
1019
1019
 
1020
- Mirror any extra column in the model `schema`. To make it filterable, add a method to a custom repository (see `use-in-app/SKILL.md`).
1020
+ Mirror any extra column in the model `schema`. To make it filterable, add a method to a custom repository (see the `use-in-app` topic).
1021
1021
 
1022
1022
  ## Column naming follows `columnMap`
1023
1023
 
@@ -1030,12 +1030,12 @@ class Notification extends DatabaseNotification {
1030
1030
  // → notificationColumns(Notification) emits `userId` + `readAt`
1031
1031
  ```
1032
1032
 
1033
- Without a model passed, defaults to `user_id` + `read_at` (read_at-only). See [`use-in-app/SKILL.md`](../use-in-app/SKILL.md) for the full `columnMap` shape.
1033
+ Without a model passed, defaults to `user_id` + `read_at` (read_at-only). See the `use-in-app` topic for the full `columnMap` shape.
1034
1034
 
1035
1035
  ## See also
1036
1036
 
1037
- - [`use-in-app/SKILL.md`](../use-in-app/SKILL.md) — the model + repository the migration backs.
1038
- - [`@warlock.js/cascade/write-migration/SKILL.md`](../../../cascade/skills/write-migration/SKILL.md) — generic Cascade migration form, `Migration.alter`, etc.
1039
- - [`@warlock.js/cascade/manage-data-sources/SKILL.md`](../../../cascade/skills/manage-data-sources/SKILL.md) — multi-data-source setup.
1037
+ - The `use-in-app` topic — the model + repository the migration backs.
1038
+ - The `write-migration` topic of the `warlock-js-cascade` skill — generic Cascade migration form, `Migration.alter`, etc.
1039
+ - The `manage-data-sources` topic of the `warlock-js-cascade` skill — multi-data-source setup.
1040
1040
 
1041
1041
 
package/llms.txt CHANGED
@@ -6,12 +6,12 @@
6
6
 
7
7
  ## Skills
8
8
 
9
- - [configure-notifications](@warlock.js/notifications/configure-notifications/SKILL.md): Wire `@warlock.js/notifications` via a declarative `src/config/notifications.ts` that exports a `NotificationConfig` default — the notifications connector registers it at boot, so app code never calls `setNotificationConfig`. `channels`: registry mapping name → factory result (`mailChannel`, `inApp.configure`, custom `defineChannel`); `queue`: optional `QueueDispatcher` (`.queue()` throws without it); `preferences`: optional `PreferenceProvider` (drops channels the recipient muted); `rateLimit`: optional `RateLimiter` (drops channels exceeding per-recipient budgets). Triggers: `config/notifications.ts`, `NotificationConfig`, `setNotificationConfig`, `getNotificationConfig`, `mailChannel`, `inApp.configure`, "configure notifications", "wire notifications at boot", "set preferences provider", "set rate limit"; typical import `import { type NotificationConfig, mailChannel, inApp } from "@warlock.js/notifications"`. Skip: building a reusable notification — `@warlock.js/notifications/define-notification/SKILL.md`; the in-app read API — `@warlock.js/notifications/use-in-app/SKILL.md`; adding a custom channel — `@warlock.js/notifications/define-channel/SKILL.md`.
10
- - [define-channel](@warlock.js/notifications/define-channel/SKILL.md): Add a custom notification channel — `defineChannel<P>({ name, route?, send })` returns a `Channel<P>` you register in the `channels` map of `setNotificationConfig`. `name` matches the key in `NotificationChannels` (extend via `declare module` for typing); `route(notifiable)` resolves the recipient's address (defaults to `{ id }` when omitted); `send({ payload, route, notifiable, options })` does the actual transport. Use for Slack/Discord/internal-webhook/anything else — `fetch`-based with NO SDK is the simplest variant. Channels that load a heavy SDK should follow the lazy-import pattern from the develop-feature playbook. Triggers: `defineChannel`, `Channel<P>`, "custom notification channel", "add discord channel", "slack channel", "webhook channel", "new channel type", `declare module "@warlock.js/notifications"`; typical import `import { defineChannel } from "@warlock.js/notifications"`. Skip: lazy-loading an optional SDK behind the channel — `D:/xampp/htdocs/mongez/node/.claude/skills/develop-warlock.js-feature/SKILL.md`; using built-in channels — `@warlock.js/notifications/configure-notifications/SKILL.md`.
11
- - [define-notification](@warlock.js/notifications/define-notification/SKILL.md): Build a reusable multi-channel notification with `defineNotification<Data>({ type, via, ...renderers })`. `type` is the stable identifier preference/rate-limit gates use AND defaults the database channel's `type`. `via` is `ChannelName[]` OR `(data, to) => ChannelName[]` for per-recipient channel selection. Renderers are `(data, to, ctx) => NotificationChannels[C]`; `ctx` carries `locale` + `meta` from `SendOptions`. The returned object exposes `.send(to|to[], data, options?)`, `.queue(to|to[], data, options?)`, and `.only(...channels)`. Per-recipient + per-channel `Promise.allSettled` isolates failures; the database channel's `type` is auto-defaulted from `def.type`; `SendOptions.idempotencyKey` is injected into the database payload. Triggers: `defineNotification`, `via`, "reusable notification", "multi-channel notification", "send through several channels at once", "render per channel", `RenderContext`, `def.type`; "force on a notification", "queue with delay"; typical import `import { defineNotification } from "@warlock.js/notifications"`. Skip: single-channel ad-hoc sends — `@warlock.js/notifications/send-ad-hoc/SKILL.md`; adding a brand-new channel — `@warlock.js/notifications/define-channel/SKILL.md`; observing dispatch outcomes — `@warlock.js/notifications/observe-notifications/SKILL.md`.
9
+ - [configure-notifications](@warlock.js/notifications/configure-notifications/SKILL.md): Wire `@warlock.js/notifications` via a declarative `src/config/notifications.ts` that exports a `NotificationConfig` default — the notifications connector registers it at boot, so app code never calls `setNotificationConfig`. `channels`: registry mapping name → factory result (`mailChannel`, `inApp.configure`, custom `defineChannel`); `queue`: optional `QueueDispatcher` (`.queue()` throws without it); `preferences`: optional `PreferenceProvider` (drops channels the recipient muted); `rateLimit`: optional `RateLimiter` (drops channels exceeding per-recipient budgets). Triggers: `config/notifications.ts`, `NotificationConfig`, `setNotificationConfig`, `getNotificationConfig`, `mailChannel`, `inApp.configure`, "configure notifications", "wire notifications at boot", "set preferences provider", "set rate limit"; typical import `import { type NotificationConfig, mailChannel, inApp } from "@warlock.js/notifications"`. Skip: building a reusable notification — the `define-notification` topic; the in-app read API — the `use-in-app` topic; adding a custom channel — the `define-channel` topic.
10
+ - [define-channel](@warlock.js/notifications/define-channel/SKILL.md): Add a custom notification channel — `defineChannel<P>({ name, route?, send })` returns a `Channel<P>` you register in the `channels` map of `setNotificationConfig`. `name` matches the key in `NotificationChannels` (extend via `declare module` for typing); `route(notifiable)` resolves the recipient's address (defaults to `{ id }` when omitted); `send({ payload, route, notifiable, options })` does the actual transport. Use for Slack/Discord/internal-webhook/anything else — `fetch`-based with NO SDK is the simplest variant. Channels that load a heavy SDK should follow the lazy-import pattern from the develop-feature playbook. Triggers: `defineChannel`, `Channel<P>`, "custom notification channel", "add discord channel", "slack channel", "webhook channel", "new channel type", `declare module "@warlock.js/notifications"`; typical import `import { defineChannel } from "@warlock.js/notifications"`. Skip: lazy-loading an optional SDK behind the channel — the `develop-warlock.js-feature` workspace skill; using built-in channels — the `configure-notifications` topic.
11
+ - [define-notification](@warlock.js/notifications/define-notification/SKILL.md): Build a reusable multi-channel notification with `defineNotification<Data>({ type, via, ...renderers })`. `type` is the stable identifier preference/rate-limit gates use AND defaults the database channel's `type`. `via` is `ChannelName[]` OR `(data, to) => ChannelName[]` for per-recipient channel selection. Renderers are `(data, to, ctx) => NotificationChannels[C]`; `ctx` carries `locale` + `meta` from `SendOptions`. The returned object exposes `.send(to|to[], data, options?)`, `.queue(to|to[], data, options?)`, and `.only(...channels)`. Per-recipient + per-channel `Promise.allSettled` isolates failures; the database channel's `type` is auto-defaulted from `def.type`; `SendOptions.idempotencyKey` is injected into the database payload. Triggers: `defineNotification`, `via`, "reusable notification", "multi-channel notification", "send through several channels at once", "render per channel", `RenderContext`, `def.type`; "force on a notification", "queue with delay"; typical import `import { defineNotification } from "@warlock.js/notifications"`. Skip: single-channel ad-hoc sends — the `send-ad-hoc` topic; adding a brand-new channel — the `define-channel` topic; observing dispatch outcomes — the `observe-notifications` topic.
12
12
  - [notifications-basics](@warlock.js/notifications/notifications-basics/SKILL.md): Start here for @warlock.js/notifications channels, notification definitions, delivery, and application setup.
13
- - [observe-notifications](@warlock.js/notifications/observe-notifications/SKILL.md): Wire metrics, logging, tracing, and audits via `notifications.on(event, handler)` — four events fire per (channel, recipient): `sending` (gates passed, about to hit the transport), `sent` (succeeded), `failed` (channel threw — carries the Error), `skipped` (a pre-send gate dropped it — carries `reason: "preference" | "rate-limit"`). Every event carries the recipient as `notifiable?` (undefined only for raw-target ad-hoc sends) and a `dispatchId` — `sending` and its terminal `sent`/`failed` share it, so observers can pair them (spans, latency, hung-send detection). `sent`/`failed` also carry `durationMs`. Handler exceptions are logged-and-swallowed so one bad listener can not break the dispatcher. `on(...)` returns an unsubscribe function; `off(event, handler)` exists for symmetry. Triggers: `notifications.on`, `notifications.off`, `"sending"` event, `"sent"` event, `"failed"` event, `"skipped"` event, `dispatchId`, `durationMs`, `NotificationEvents`, "notification metrics", "notification latency", "trace notifications", "notification audit log", "track notification drops"; typical import `import { notifications } from "@warlock.js/notifications"`. Skip: building notifications — `@warlock.js/notifications/define-notification/SKILL.md`; configuring the preference/rate-limit gates that produce `skipped` — `@warlock.js/notifications/configure-notifications/SKILL.md`.
14
- - [queue-notifications](@warlock.js/notifications/queue-notifications/SKILL.md): Send notifications asynchronously through the herald backend or the BullMQ driver. Configure a QueueDispatcher in config/notifications.ts, then use notif.queue(to, data, options?) to enqueue rendered jobs. Herald uses heraldQueue() and startNotificationsWorker(); bullmqQueue({ attempts, backoff }) from @warlock.js/notifications uses BullMQ (lazy-loading the optional @warlock.js/queue peer), supports retries, and honours SendOptions.delay. Without a queue configured, .queue() rejects NoQueueDispatcherError. Triggers: heraldQueue, bullmqQueue, startNotificationsWorker, QueueDispatcher, .queue(, async notifications, queue notifications, notification worker, background notifications, notifications.dispatch. Skip: synchronous sends - @warlock.js/notifications/define-notification/SKILL.md; herald itself - @warlock.js/herald/*.
15
- - [send-ad-hoc](@warlock.js/notifications/send-ad-hoc/SKILL.md): Ad-hoc per-channel send via the `notify.<channel>(to, payload, options?)` Proxy facade. Works for any channel registered in `NotificationChannels` (built-in or custom). `to` accepts a `Notifiable` model OR a raw route string (`"x@y.com"`); `payload` is typed per channel via the registry; `options` is the standard `SendOptions`. `notify.channel(name).send(...)` is the runtime escape when the channel name is not a compile-time literal. Type-based preference gating applies when a type is known — explicit via `options.type` OR auto-detected from a database payload's `type` field. For multi-channel sends use `defineNotification` instead — there is no inline `notify(to, { via, ... })` form on purpose. Triggers: `notify.<channel>`, `notify.channel(name)`, `notify.mail`, `notify.database`, "send a one-off notification", "ad-hoc notification", "send an email without defining a notification", "raw email target", "dynamic channel name"; typical import `import { notify } from "@warlock.js/notifications"`. Skip: reusable multi-channel notifications — `@warlock.js/notifications/define-notification/SKILL.md`; configuring channels — `@warlock.js/notifications/configure-notifications/SKILL.md`.
16
- - [use-in-app](@warlock.js/notifications/use-in-app/SKILL.md): Use the `inApp` facade for the in-app/database channel's READ side: `inApp.configure({ model: Notification })` or `{ repository: myRepo }` binds the store AND returns the channel; `inApp.list / listUnread / countUnread / markAsRead / markAsUnread` are RECIPIENT-SCOPED by construction (no IDOR — `markAsRead(user, id)` cannot flip another user's row even with a foreign id). `countUnread` uses `RepositoryManager.countCached` for the badge fast-path. Triggers: `inApp.configure`, `inApp.list`, `inApp.listUnread`, `inApp.countUnread`, `inApp.markAsRead`, `inApp.markAsUnread`, `BaseNotificationsRepository`, `DatabaseNotification`, `NotificationsFilter`, "in-app notifications", "mark notification as read", "unread count", "notification badge", "IDOR-safe markAsRead"; typical import `import { inApp } from "@warlock.js/notifications"`. Skip: writing notifications (use `defineNotification` or `notify.database`) — `@warlock.js/notifications/define-notification/SKILL.md`; the migration columns — `@warlock.js/notifications/write-notification-migration/SKILL.md`; wiring it into config — `@warlock.js/notifications/configure-notifications/SKILL.md`.
17
- - [write-notification-migration](@warlock.js/notifications/write-notification-migration/SKILL.md): Create the notifications table with the `notificationColumns(Notification)` factory + cascade `Migration.create`. Column NAMES come from the model's `columnMap` (recipient / tenant / readAt / isRead); the fixed columns are `type` / `title` / `body` / `payload` / `idempotency_key`. Set `{ idType: "bigint" }` for integer-key apps; UUID remains the default. Read-state follows columnMap presence: `readAt` → nullable timestamp, `isRead` → indexed boolean, both → both. Defaults to `user_id` + `read_at` when no columnMap. Spread + extend for extras (FK references, composite indexes). Triggers: `notificationColumns`, `Migration.create` for notifications, "create the notifications table", "notification migration", "add organization_id to notifications", `is_read` column, `read_at` column, `idempotency_key` column; typical import `import { Migration } from "@warlock.js/cascade"; import { notificationColumns } from "@warlock.js/notifications"`. Skip: generic cascade migration writing — `@warlock.js/cascade/write-migration/SKILL.md`; the model itself — `@warlock.js/notifications/use-in-app/SKILL.md`.
13
+ - [observe-notifications](@warlock.js/notifications/observe-notifications/SKILL.md): Wire metrics, logging, tracing, and audits via `notifications.on(event, handler)` — four events fire per (channel, recipient): `sending` (gates passed, about to hit the transport), `sent` (succeeded), `failed` (channel threw — carries the Error), `skipped` (a pre-send gate dropped it — carries `reason: "preference" | "rate-limit"`). Every event carries the recipient as `notifiable?` (undefined only for raw-target ad-hoc sends) and a `dispatchId` — `sending` and its terminal `sent`/`failed` share it, so observers can pair them (spans, latency, hung-send detection). `sent`/`failed` also carry `durationMs`. Handler exceptions are logged-and-swallowed so one bad listener can not break the dispatcher. `on(...)` returns an unsubscribe function; `off(event, handler)` exists for symmetry. Triggers: `notifications.on`, `notifications.off`, `"sending"` event, `"sent"` event, `"failed"` event, `"skipped"` event, `dispatchId`, `durationMs`, `NotificationEvents`, "notification metrics", "notification latency", "trace notifications", "notification audit log", "track notification drops"; typical import `import { notifications } from "@warlock.js/notifications"`. Skip: building notifications — the `define-notification` topic; configuring the preference/rate-limit gates that produce `skipped` — the `configure-notifications` topic.
14
+ - [queue-notifications](@warlock.js/notifications/queue-notifications/SKILL.md): Send notifications asynchronously through the herald backend or the BullMQ driver. Configure a QueueDispatcher in config/notifications.ts, then use notif.queue(to, data, options?) to enqueue rendered jobs. Herald uses heraldQueue() and startNotificationsWorker(); bullmqQueue({ attempts, backoff }) from @warlock.js/notifications uses BullMQ (lazy-loading the optional @warlock.js/queue peer), supports retries, and honours SendOptions.delay. Without a queue configured, .queue() rejects NoQueueDispatcherError. Triggers: heraldQueue, bullmqQueue, startNotificationsWorker, QueueDispatcher, .queue(, async notifications, queue notifications, notification worker, background notifications, notifications.dispatch. Skip: synchronous sends - the `define-notification` topic; herald itself - @warlock.js/herald/*.
15
+ - [send-ad-hoc](@warlock.js/notifications/send-ad-hoc/SKILL.md): Ad-hoc per-channel send via the `notify.<channel>(to, payload, options?)` Proxy facade. Works for any channel registered in `NotificationChannels` (built-in or custom). `to` accepts a `Notifiable` model OR a raw route string (`"x@y.com"`); `payload` is typed per channel via the registry; `options` is the standard `SendOptions`. `notify.channel(name).send(...)` is the runtime escape when the channel name is not a compile-time literal. Type-based preference gating applies when a type is known — explicit via `options.type` OR auto-detected from a database payload's `type` field. For multi-channel sends use `defineNotification` instead — there is no inline `notify(to, { via, ... })` form on purpose. Triggers: `notify.<channel>`, `notify.channel(name)`, `notify.mail`, `notify.database`, "send a one-off notification", "ad-hoc notification", "send an email without defining a notification", "raw email target", "dynamic channel name"; typical import `import { notify } from "@warlock.js/notifications"`. Skip: reusable multi-channel notifications — the `define-notification` topic; configuring channels — the `configure-notifications` topic.
16
+ - [use-in-app](@warlock.js/notifications/use-in-app/SKILL.md): Use the `inApp` facade for the in-app/database channel's READ side: `inApp.configure({ model: Notification })` or `{ repository: myRepo }` binds the store AND returns the channel; `inApp.list / listUnread / countUnread / markAsRead / markAsUnread` are RECIPIENT-SCOPED by construction (no IDOR — `markAsRead(user, id)` cannot flip another user's row even with a foreign id). `countUnread` uses `RepositoryManager.countCached` for the badge fast-path. Triggers: `inApp.configure`, `inApp.list`, `inApp.listUnread`, `inApp.countUnread`, `inApp.markAsRead`, `inApp.markAsUnread`, `BaseNotificationsRepository`, `DatabaseNotification`, `NotificationsFilter`, "in-app notifications", "mark notification as read", "unread count", "notification badge", "IDOR-safe markAsRead"; typical import `import { inApp } from "@warlock.js/notifications"`. Skip: writing notifications (use `defineNotification` or `notify.database`) — the `define-notification` topic; the migration columns — the `write-notification-migration` topic; wiring it into config — the `configure-notifications` topic.
17
+ - [write-notification-migration](@warlock.js/notifications/write-notification-migration/SKILL.md): Create the notifications table with the `notificationColumns(Notification)` factory + cascade `Migration.create`. Column NAMES come from the model's `columnMap` (recipient / tenant / readAt / isRead); the fixed columns are `type` / `title` / `body` / `payload` / `idempotency_key`. Set `{ idType: "bigint" }` for integer-key apps; UUID remains the default. Read-state follows columnMap presence: `readAt` → nullable timestamp, `isRead` → indexed boolean, both → both. Defaults to `user_id` + `read_at` when no columnMap. Spread + extend for extras (FK references, composite indexes). Triggers: `notificationColumns`, `Migration.create` for notifications, "create the notifications table", "notification migration", "add organization_id to notifications", `is_read` column, `read_at` column, `idempotency_key` column; typical import `import { Migration } from "@warlock.js/cascade"; import { notificationColumns } from "@warlock.js/notifications"`. Skip: generic cascade migration writing — the `write-migration` topic of the `warlock-js-cascade` skill; the model itself — the `use-in-app` topic.
package/package.json CHANGED
@@ -5,16 +5,16 @@
5
5
  "environment": "server"
6
6
  },
7
7
  "dependencies": {
8
- "@warlock.js/cache": "5.28.0",
9
- "@warlock.js/cascade": "5.28.0",
10
- "@warlock.js/core": "5.28.0",
11
- "@warlock.js/logger": "5.28.0"
8
+ "@warlock.js/cache": "5.30.0",
9
+ "@warlock.js/cascade": "5.30.0",
10
+ "@warlock.js/core": "5.30.0",
11
+ "@warlock.js/logger": "5.30.0"
12
12
  },
13
13
  "optionalDependencies": {
14
- "@warlock.js/herald": "5.28.0"
14
+ "@warlock.js/herald": "5.30.0"
15
15
  },
16
16
  "peerDependencies": {
17
- "@warlock.js/queue": "5.28.0"
17
+ "@warlock.js/queue": "5.30.0"
18
18
  },
19
19
  "peerDependenciesMeta": {
20
20
  "@warlock.js/queue": {
@@ -23,7 +23,8 @@
23
23
  },
24
24
  "repository": {
25
25
  "type": "git",
26
- "url": "https://github.com/warlockjs/notifications"
26
+ "url": "git+https://github.com/warlockjs/framework.git",
27
+ "directory": "packages/notifications"
27
28
  },
28
29
  "keywords": [
29
30
  "notifications",
@@ -35,7 +36,7 @@
35
36
  ],
36
37
  "author": "hassanzohdy",
37
38
  "license": "MIT",
38
- "version": "5.28.0",
39
+ "version": "5.30.0",
39
40
  "main": "./cjs/index.cjs",
40
41
  "module": "./esm/index.mjs",
41
42
  "types": "./esm/index.d.mts",
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: configure-notifications
3
- description: 'Wire `@warlock.js/notifications` via a declarative `src/config/notifications.ts` that exports a `NotificationConfig` default — the notifications connector registers it at boot, so app code never calls `setNotificationConfig`. `channels`: registry mapping name → factory result (`mailChannel`, `inApp.configure`, custom `defineChannel`); `queue`: optional `QueueDispatcher` (`.queue()` throws without it); `preferences`: optional `PreferenceProvider` (drops channels the recipient muted); `rateLimit`: optional `RateLimiter` (drops channels exceeding per-recipient budgets). Triggers: `config/notifications.ts`, `NotificationConfig`, `setNotificationConfig`, `getNotificationConfig`, `mailChannel`, `inApp.configure`, "configure notifications", "wire notifications at boot", "set preferences provider", "set rate limit"; typical import `import { type NotificationConfig, mailChannel, inApp } from "@warlock.js/notifications"`. Skip: building a reusable notification — `@warlock.js/notifications/define-notification/SKILL.md`; the in-app read API — `@warlock.js/notifications/use-in-app/SKILL.md`; adding a custom channel — `@warlock.js/notifications/define-channel/SKILL.md`.'
3
+ description: 'Wire `@warlock.js/notifications` via a declarative `src/config/notifications.ts` that exports a `NotificationConfig` default — the notifications connector registers it at boot, so app code never calls `setNotificationConfig`. `channels`: registry mapping name → factory result (`mailChannel`, `inApp.configure`, custom `defineChannel`); `queue`: optional `QueueDispatcher` (`.queue()` throws without it); `preferences`: optional `PreferenceProvider` (drops channels the recipient muted); `rateLimit`: optional `RateLimiter` (drops channels exceeding per-recipient budgets). Triggers: `config/notifications.ts`, `NotificationConfig`, `setNotificationConfig`, `getNotificationConfig`, `mailChannel`, `inApp.configure`, "configure notifications", "wire notifications at boot", "set preferences provider", "set rate limit"; typical import `import { type NotificationConfig, mailChannel, inApp } from "@warlock.js/notifications"`. Skip: building a reusable notification — the `define-notification` topic; the in-app read API — the `use-in-app` topic; adding a custom channel — the `define-channel` topic.'
4
4
  ---
5
5
 
6
6
  # Configure notifications
@@ -13,7 +13,7 @@ description: 'Wire `@warlock.js/notifications` via a declarative `src/config/not
13
13
 
14
14
  ```ts title="src/config/notifications.ts"
15
15
  import { type NotificationConfig, inApp, mailChannel } from "@warlock.js/notifications";
16
- import { Notification } from "app/notifications/notification.model";
16
+ import { Notification } from "app/notifications/models/notification/notification.model";
17
17
 
18
18
  const config: NotificationConfig = {
19
19
  channels: {
@@ -132,7 +132,7 @@ afterEach(() => resetNotificationConfig());
132
132
 
133
133
  ## See also
134
134
 
135
- - [`notifications-basics/SKILL.md`](../notifications-basics/SKILL.md) — package front door.
136
- - [`define-notification/SKILL.md`](../define-notification/SKILL.md) — reusable multi-channel definitions.
137
- - [`use-in-app/SKILL.md`](../use-in-app/SKILL.md) — in-app read API.
138
- - [`define-channel/SKILL.md`](../define-channel/SKILL.md) — custom channels.
135
+ - The `notifications-basics` topic — package front door.
136
+ - The `define-notification` topic — reusable multi-channel definitions.
137
+ - The `use-in-app` topic — in-app read API.
138
+ - The `define-channel` topic — custom channels.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: define-channel
3
- description: 'Add a custom notification channel — `defineChannel<P>({ name, route?, send })` returns a `Channel<P>` you register in the `channels` map of `setNotificationConfig`. `name` matches the key in `NotificationChannels` (extend via `declare module` for typing); `route(notifiable)` resolves the recipient''s address (defaults to `{ id }` when omitted); `send({ payload, route, notifiable, options })` does the actual transport. Use for Slack/Discord/internal-webhook/anything else — `fetch`-based with NO SDK is the simplest variant. Channels that load a heavy SDK should follow the lazy-import pattern from the develop-feature playbook. Triggers: `defineChannel`, `Channel<P>`, "custom notification channel", "add discord channel", "slack channel", "webhook channel", "new channel type", `declare module "@warlock.js/notifications"`; typical import `import { defineChannel } from "@warlock.js/notifications"`. Skip: lazy-loading an optional SDK behind the channel — `D:/xampp/htdocs/mongez/node/.claude/skills/develop-warlock.js-feature/SKILL.md`; using built-in channels — `@warlock.js/notifications/configure-notifications/SKILL.md`.'
3
+ description: 'Add a custom notification channel — `defineChannel<P>({ name, route?, send })` returns a `Channel<P>` you register in the `channels` map of `setNotificationConfig`. `name` matches the key in `NotificationChannels` (extend via `declare module` for typing); `route(notifiable)` resolves the recipient''s address (defaults to `{ id }` when omitted); `send({ payload, route, notifiable, options })` does the actual transport. Use for Slack/Discord/internal-webhook/anything else — `fetch`-based with NO SDK is the simplest variant. Channels that load a heavy SDK should follow the lazy-import pattern from the develop-feature playbook. Triggers: `defineChannel`, `Channel<P>`, "custom notification channel", "add discord channel", "slack channel", "webhook channel", "new channel type", `declare module "@warlock.js/notifications"`; typical import `import { defineChannel } from "@warlock.js/notifications"`. Skip: lazy-loading an optional SDK behind the channel — the `develop-warlock.js-feature` workspace skill; using built-in channels — the `configure-notifications` topic.'
4
4
  ---
5
5
 
6
6
  # `defineChannel` — custom channels
@@ -74,7 +74,7 @@ Throw to fail the send. The dispatcher catches per channel, fires a `failed` eve
74
74
 
75
75
  ## SDK-backed channels — lazy-import the SDK
76
76
 
77
- Channels that wrap a heavy SDK (Twilio, Slack SDK, FCM SDK) should follow the lazy-import pattern so apps that don't use them don't pay the install/load cost. The recipe + race-safe template lives in [`develop-warlock.js-feature`](../../../../.claude/skills/develop-warlock.js-feature/SKILL.md) — copy from there; do not invent a variant.
77
+ Channels that wrap a heavy SDK (Twilio, Slack SDK, FCM SDK) should follow the lazy-import pattern so apps that don't use them don't pay the install/load cost. The recipe + race-safe template lives in the `develop-warlock.js-feature` workspace skill — copy from there; do not invent a variant.
78
78
 
79
79
  Sketch:
80
80
 
@@ -101,7 +101,7 @@ export const slackChannel = (config: { token: string }) =>
101
101
 
102
102
  ## See also
103
103
 
104
- - [`configure-notifications/SKILL.md`](../configure-notifications/SKILL.md) — register channels in the config.
105
- - [`send-ad-hoc/SKILL.md`](../send-ad-hoc/SKILL.md) — `notify.<custom-channel>` works after registration.
106
- - [`define-notification/SKILL.md`](../define-notification/SKILL.md) — multi-channel renderers with the custom channel key.
107
- - `D:/xampp/htdocs/mongez/node/.claude/skills/develop-warlock.js-feature/SKILL.md` — lazy-import pattern for SDK-backed channels.
104
+ - The `configure-notifications` topic — register channels in the config.
105
+ - The `send-ad-hoc` topic — `notify.<custom-channel>` works after registration.
106
+ - The `define-notification` topic — multi-channel renderers with the custom channel key.
107
+ - The `develop-warlock.js-feature` workspace skill — lazy-import pattern for SDK-backed channels.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: define-notification
3
- description: 'Build a reusable multi-channel notification with `defineNotification<Data>({ type, via, ...renderers })`. `type` is the stable identifier preference/rate-limit gates use AND defaults the database channel''s `type`. `via` is `ChannelName[]` OR `(data, to) => ChannelName[]` for per-recipient channel selection. Renderers are `(data, to, ctx) => NotificationChannels[C]`; `ctx` carries `locale` + `meta` from `SendOptions`. The returned object exposes `.send(to|to[], data, options?)`, `.queue(to|to[], data, options?)`, and `.only(...channels)`. Per-recipient + per-channel `Promise.allSettled` isolates failures; the database channel''s `type` is auto-defaulted from `def.type`; `SendOptions.idempotencyKey` is injected into the database payload. Triggers: `defineNotification`, `via`, "reusable notification", "multi-channel notification", "send through several channels at once", "render per channel", `RenderContext`, `def.type`; "force on a notification", "queue with delay"; typical import `import { defineNotification } from "@warlock.js/notifications"`. Skip: single-channel ad-hoc sends — `@warlock.js/notifications/send-ad-hoc/SKILL.md`; adding a brand-new channel — `@warlock.js/notifications/define-channel/SKILL.md`; observing dispatch outcomes — `@warlock.js/notifications/observe-notifications/SKILL.md`.'
3
+ description: 'Build a reusable multi-channel notification with `defineNotification<Data>({ type, via, ...renderers })`. `type` is the stable identifier preference/rate-limit gates use AND defaults the database channel''s `type`. `via` is `ChannelName[]` OR `(data, to) => ChannelName[]` for per-recipient channel selection. Renderers are `(data, to, ctx) => NotificationChannels[C]`; `ctx` carries `locale` + `meta` from `SendOptions`. The returned object exposes `.send(to|to[], data, options?)`, `.queue(to|to[], data, options?)`, and `.only(...channels)`. Per-recipient + per-channel `Promise.allSettled` isolates failures; the database channel''s `type` is auto-defaulted from `def.type`; `SendOptions.idempotencyKey` is injected into the database payload. Triggers: `defineNotification`, `via`, "reusable notification", "multi-channel notification", "send through several channels at once", "render per channel", `RenderContext`, `def.type`; "force on a notification", "queue with delay"; typical import `import { defineNotification } from "@warlock.js/notifications"`. Skip: single-channel ad-hoc sends — the `send-ad-hoc` topic; adding a brand-new channel — the `define-channel` topic; observing dispatch outcomes — the `observe-notifications` topic.'
4
4
  ---
5
5
 
6
6
  # `defineNotification` — reusable multi-channel notification
@@ -127,7 +127,7 @@ Per-recipient: each recipient gets an independent `Promise.allSettled`. Per-chan
127
127
 
128
128
  ## See also
129
129
 
130
- - [`notifications-basics/SKILL.md`](../notifications-basics/SKILL.md) — package front door.
131
- - [`send-ad-hoc/SKILL.md`](../send-ad-hoc/SKILL.md) — `notify.<channel>` per-channel shorthand.
132
- - [`configure-notifications/SKILL.md`](../configure-notifications/SKILL.md) — wire channels + preferences + rate-limit + queue.
133
- - [`observe-notifications/SKILL.md`](../observe-notifications/SKILL.md) — `notifications.on("sending" | "sent" | "failed" | "skipped", …)`.
130
+ - The `notifications-basics` topic — package front door.
131
+ - The `send-ad-hoc` topic — `notify.<channel>` per-channel shorthand.
132
+ - The `configure-notifications` topic — wire channels + preferences + rate-limit + queue.
133
+ - The `observe-notifications` topic — `notifications.on("sending" | "sent" | "failed" | "skipped", …)`.
@@ -30,7 +30,7 @@ It is NOT a queue, a template engine, a transport library, or an analytics pipel
30
30
 
31
31
  ```ts title="src/config/notifications.ts"
32
32
  import { type NotificationConfig, mailChannel, inApp } from "@warlock.js/notifications";
33
- import { Notification } from "app/notifications/notification.model";
33
+ import { Notification } from "app/notifications/models/notification/notification.model";
34
34
 
35
35
  const config: NotificationConfig = {
36
36
  channels: {
@@ -89,10 +89,10 @@ await inApp.markAsRead(user, "ntf_123");
89
89
 
90
90
  ## See also
91
91
 
92
- - [`configure-notifications/SKILL.md`](../configure-notifications/SKILL.md) — wire `config/notifications.ts`.
93
- - [`define-notification/SKILL.md`](../define-notification/SKILL.md) — reusable multi-channel definitions.
94
- - [`send-ad-hoc/SKILL.md`](../send-ad-hoc/SKILL.md) — `notify.<channel>` shorthand.
95
- - [`use-in-app/SKILL.md`](../use-in-app/SKILL.md) — `inApp` read API.
96
- - [`define-channel/SKILL.md`](../define-channel/SKILL.md) — custom channels.
97
- - [`write-notification-migration/SKILL.md`](../write-notification-migration/SKILL.md) — columnMap-driven columns.
98
- - [`observe-notifications/SKILL.md`](../observe-notifications/SKILL.md) — events + metrics.
92
+ - The `configure-notifications` topic — wire `config/notifications.ts`.
93
+ - The `define-notification` topic — reusable multi-channel definitions.
94
+ - The `send-ad-hoc` topic — `notify.<channel>` shorthand.
95
+ - The `use-in-app` topic — `inApp` read API.
96
+ - The `define-channel` topic — custom channels.
97
+ - The `write-notification-migration` topic — columnMap-driven columns.
98
+ - The `observe-notifications` topic — events + metrics.