notification queue server for @gwen.works/churros

feat: actually working jetstream connection, typescript sender mock script

+3
docker-compose.yaml
··· 4 4 ports: 5 5 - "8222:8222" 6 6 - "4222:4222" 7 + volumes: 8 + - ./nats-dev-server.conf:/nats-server.conf 9 + command: ["-c", "/nats-server.conf"]
-1
go.mod
··· 18 18 github.com/nats-io/nkeys v0.4.7 // indirect 19 19 github.com/nats-io/nuid v1.0.1 // indirect 20 20 golang.org/x/crypto v0.18.0 // indirect 21 - golang.org/x/text v0.14.0 // indirect 22 21 ) 23 22 24 23 require (
-2
go.sum
··· 73 73 golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= 74 74 golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= 75 75 golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= 76 - golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= 77 - golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= 78 76 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 79 77 golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 80 78 golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
+4
nats-dev-server.conf
··· 1 + # nats-server.conf 2 + jetstream { 3 + enabled: true 4 + }
+528 -2
package-lock.json
··· 1 1 { 2 - "name": "churros-notella", 2 + "name": "notella", 3 3 "lockfileVersion": 3, 4 4 "requires": true, 5 5 "packages": { ··· 8 8 "@prisma/client": "^5.20.0" 9 9 }, 10 10 "devDependencies": { 11 - "prisma": "^5.20.0" 11 + "nats": "^2.28.2", 12 + "prisma": "^5.20.0", 13 + "tsx": "^4.19.2" 14 + } 15 + }, 16 + "node_modules/@esbuild/aix-ppc64": { 17 + "version": "0.23.1", 18 + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.23.1.tgz", 19 + "integrity": "sha512-6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQ==", 20 + "cpu": [ 21 + "ppc64" 22 + ], 23 + "dev": true, 24 + "license": "MIT", 25 + "optional": true, 26 + "os": [ 27 + "aix" 28 + ], 29 + "engines": { 30 + "node": ">=18" 31 + } 32 + }, 33 + "node_modules/@esbuild/android-arm": { 34 + "version": "0.23.1", 35 + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.23.1.tgz", 36 + "integrity": "sha512-uz6/tEy2IFm9RYOyvKl88zdzZfwEfKZmnX9Cj1BHjeSGNuGLuMD1kR8y5bteYmwqKm1tj8m4cb/aKEorr6fHWQ==", 37 + "cpu": [ 38 + "arm" 39 + ], 40 + "dev": true, 41 + "license": "MIT", 42 + "optional": true, 43 + "os": [ 44 + "android" 45 + ], 46 + "engines": { 47 + "node": ">=18" 48 + } 49 + }, 50 + "node_modules/@esbuild/android-arm64": { 51 + "version": "0.23.1", 52 + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.23.1.tgz", 53 + "integrity": "sha512-xw50ipykXcLstLeWH7WRdQuysJqejuAGPd30vd1i5zSyKK3WE+ijzHmLKxdiCMtH1pHz78rOg0BKSYOSB/2Khw==", 54 + "cpu": [ 55 + "arm64" 56 + ], 57 + "dev": true, 58 + "license": "MIT", 59 + "optional": true, 60 + "os": [ 61 + "android" 62 + ], 63 + "engines": { 64 + "node": ">=18" 65 + } 66 + }, 67 + "node_modules/@esbuild/android-x64": { 68 + "version": "0.23.1", 69 + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.23.1.tgz", 70 + "integrity": "sha512-nlN9B69St9BwUoB+jkyU090bru8L0NA3yFvAd7k8dNsVH8bi9a8cUAUSEcEEgTp2z3dbEDGJGfP6VUnkQnlReg==", 71 + "cpu": [ 72 + "x64" 73 + ], 74 + "dev": true, 75 + "license": "MIT", 76 + "optional": true, 77 + "os": [ 78 + "android" 79 + ], 80 + "engines": { 81 + "node": ">=18" 82 + } 83 + }, 84 + "node_modules/@esbuild/darwin-arm64": { 85 + "version": "0.23.1", 86 + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.23.1.tgz", 87 + "integrity": "sha512-YsS2e3Wtgnw7Wq53XXBLcV6JhRsEq8hkfg91ESVadIrzr9wO6jJDMZnCQbHm1Guc5t/CdDiFSSfWP58FNuvT3Q==", 88 + "cpu": [ 89 + "arm64" 90 + ], 91 + "dev": true, 92 + "license": "MIT", 93 + "optional": true, 94 + "os": [ 95 + "darwin" 96 + ], 97 + "engines": { 98 + "node": ">=18" 99 + } 100 + }, 101 + "node_modules/@esbuild/darwin-x64": { 102 + "version": "0.23.1", 103 + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.23.1.tgz", 104 + "integrity": "sha512-aClqdgTDVPSEGgoCS8QDG37Gu8yc9lTHNAQlsztQ6ENetKEO//b8y31MMu2ZaPbn4kVsIABzVLXYLhCGekGDqw==", 105 + "cpu": [ 106 + "x64" 107 + ], 108 + "dev": true, 109 + "license": "MIT", 110 + "optional": true, 111 + "os": [ 112 + "darwin" 113 + ], 114 + "engines": { 115 + "node": ">=18" 116 + } 117 + }, 118 + "node_modules/@esbuild/freebsd-arm64": { 119 + "version": "0.23.1", 120 + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.23.1.tgz", 121 + "integrity": "sha512-h1k6yS8/pN/NHlMl5+v4XPfikhJulk4G+tKGFIOwURBSFzE8bixw1ebjluLOjfwtLqY0kewfjLSrO6tN2MgIhA==", 122 + "cpu": [ 123 + "arm64" 124 + ], 125 + "dev": true, 126 + "license": "MIT", 127 + "optional": true, 128 + "os": [ 129 + "freebsd" 130 + ], 131 + "engines": { 132 + "node": ">=18" 133 + } 134 + }, 135 + "node_modules/@esbuild/freebsd-x64": { 136 + "version": "0.23.1", 137 + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.23.1.tgz", 138 + "integrity": "sha512-lK1eJeyk1ZX8UklqFd/3A60UuZ/6UVfGT2LuGo3Wp4/z7eRTRYY+0xOu2kpClP+vMTi9wKOfXi2vjUpO1Ro76g==", 139 + "cpu": [ 140 + "x64" 141 + ], 142 + "dev": true, 143 + "license": "MIT", 144 + "optional": true, 145 + "os": [ 146 + "freebsd" 147 + ], 148 + "engines": { 149 + "node": ">=18" 150 + } 151 + }, 152 + "node_modules/@esbuild/linux-arm": { 153 + "version": "0.23.1", 154 + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.23.1.tgz", 155 + "integrity": "sha512-CXXkzgn+dXAPs3WBwE+Kvnrf4WECwBdfjfeYHpMeVxWE0EceB6vhWGShs6wi0IYEqMSIzdOF1XjQ/Mkm5d7ZdQ==", 156 + "cpu": [ 157 + "arm" 158 + ], 159 + "dev": true, 160 + "license": "MIT", 161 + "optional": true, 162 + "os": [ 163 + "linux" 164 + ], 165 + "engines": { 166 + "node": ">=18" 167 + } 168 + }, 169 + "node_modules/@esbuild/linux-arm64": { 170 + "version": "0.23.1", 171 + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.23.1.tgz", 172 + "integrity": "sha512-/93bf2yxencYDnItMYV/v116zff6UyTjo4EtEQjUBeGiVpMmffDNUyD9UN2zV+V3LRV3/on4xdZ26NKzn6754g==", 173 + "cpu": [ 174 + "arm64" 175 + ], 176 + "dev": true, 177 + "license": "MIT", 178 + "optional": true, 179 + "os": [ 180 + "linux" 181 + ], 182 + "engines": { 183 + "node": ">=18" 184 + } 185 + }, 186 + "node_modules/@esbuild/linux-ia32": { 187 + "version": "0.23.1", 188 + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.23.1.tgz", 189 + "integrity": "sha512-VTN4EuOHwXEkXzX5nTvVY4s7E/Krz7COC8xkftbbKRYAl96vPiUssGkeMELQMOnLOJ8k3BY1+ZY52tttZnHcXQ==", 190 + "cpu": [ 191 + "ia32" 192 + ], 193 + "dev": true, 194 + "license": "MIT", 195 + "optional": true, 196 + "os": [ 197 + "linux" 198 + ], 199 + "engines": { 200 + "node": ">=18" 201 + } 202 + }, 203 + "node_modules/@esbuild/linux-loong64": { 204 + "version": "0.23.1", 205 + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.23.1.tgz", 206 + "integrity": "sha512-Vx09LzEoBa5zDnieH8LSMRToj7ir/Jeq0Gu6qJ/1GcBq9GkfoEAoXvLiW1U9J1qE/Y/Oyaq33w5p2ZWrNNHNEw==", 207 + "cpu": [ 208 + "loong64" 209 + ], 210 + "dev": true, 211 + "license": "MIT", 212 + "optional": true, 213 + "os": [ 214 + "linux" 215 + ], 216 + "engines": { 217 + "node": ">=18" 218 + } 219 + }, 220 + "node_modules/@esbuild/linux-mips64el": { 221 + "version": "0.23.1", 222 + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.23.1.tgz", 223 + "integrity": "sha512-nrFzzMQ7W4WRLNUOU5dlWAqa6yVeI0P78WKGUo7lg2HShq/yx+UYkeNSE0SSfSure0SqgnsxPvmAUu/vu0E+3Q==", 224 + "cpu": [ 225 + "mips64el" 226 + ], 227 + "dev": true, 228 + "license": "MIT", 229 + "optional": true, 230 + "os": [ 231 + "linux" 232 + ], 233 + "engines": { 234 + "node": ">=18" 235 + } 236 + }, 237 + "node_modules/@esbuild/linux-ppc64": { 238 + "version": "0.23.1", 239 + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.23.1.tgz", 240 + "integrity": "sha512-dKN8fgVqd0vUIjxuJI6P/9SSSe/mB9rvA98CSH2sJnlZ/OCZWO1DJvxj8jvKTfYUdGfcq2dDxoKaC6bHuTlgcw==", 241 + "cpu": [ 242 + "ppc64" 243 + ], 244 + "dev": true, 245 + "license": "MIT", 246 + "optional": true, 247 + "os": [ 248 + "linux" 249 + ], 250 + "engines": { 251 + "node": ">=18" 252 + } 253 + }, 254 + "node_modules/@esbuild/linux-riscv64": { 255 + "version": "0.23.1", 256 + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.23.1.tgz", 257 + "integrity": "sha512-5AV4Pzp80fhHL83JM6LoA6pTQVWgB1HovMBsLQ9OZWLDqVY8MVobBXNSmAJi//Csh6tcY7e7Lny2Hg1tElMjIA==", 258 + "cpu": [ 259 + "riscv64" 260 + ], 261 + "dev": true, 262 + "license": "MIT", 263 + "optional": true, 264 + "os": [ 265 + "linux" 266 + ], 267 + "engines": { 268 + "node": ">=18" 269 + } 270 + }, 271 + "node_modules/@esbuild/linux-s390x": { 272 + "version": "0.23.1", 273 + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.23.1.tgz", 274 + "integrity": "sha512-9ygs73tuFCe6f6m/Tb+9LtYxWR4c9yg7zjt2cYkjDbDpV/xVn+68cQxMXCjUpYwEkze2RcU/rMnfIXNRFmSoDw==", 275 + "cpu": [ 276 + "s390x" 277 + ], 278 + "dev": true, 279 + "license": "MIT", 280 + "optional": true, 281 + "os": [ 282 + "linux" 283 + ], 284 + "engines": { 285 + "node": ">=18" 286 + } 287 + }, 288 + "node_modules/@esbuild/linux-x64": { 289 + "version": "0.23.1", 290 + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.23.1.tgz", 291 + "integrity": "sha512-EV6+ovTsEXCPAp58g2dD68LxoP/wK5pRvgy0J/HxPGB009omFPv3Yet0HiaqvrIrgPTBuC6wCH1LTOY91EO5hQ==", 292 + "cpu": [ 293 + "x64" 294 + ], 295 + "dev": true, 296 + "license": "MIT", 297 + "optional": true, 298 + "os": [ 299 + "linux" 300 + ], 301 + "engines": { 302 + "node": ">=18" 303 + } 304 + }, 305 + "node_modules/@esbuild/netbsd-x64": { 306 + "version": "0.23.1", 307 + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.23.1.tgz", 308 + "integrity": "sha512-aevEkCNu7KlPRpYLjwmdcuNz6bDFiE7Z8XC4CPqExjTvrHugh28QzUXVOZtiYghciKUacNktqxdpymplil1beA==", 309 + "cpu": [ 310 + "x64" 311 + ], 312 + "dev": true, 313 + "license": "MIT", 314 + "optional": true, 315 + "os": [ 316 + "netbsd" 317 + ], 318 + "engines": { 319 + "node": ">=18" 320 + } 321 + }, 322 + "node_modules/@esbuild/openbsd-arm64": { 323 + "version": "0.23.1", 324 + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.23.1.tgz", 325 + "integrity": "sha512-3x37szhLexNA4bXhLrCC/LImN/YtWis6WXr1VESlfVtVeoFJBRINPJ3f0a/6LV8zpikqoUg4hyXw0sFBt5Cr+Q==", 326 + "cpu": [ 327 + "arm64" 328 + ], 329 + "dev": true, 330 + "license": "MIT", 331 + "optional": true, 332 + "os": [ 333 + "openbsd" 334 + ], 335 + "engines": { 336 + "node": ">=18" 337 + } 338 + }, 339 + "node_modules/@esbuild/openbsd-x64": { 340 + "version": "0.23.1", 341 + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.23.1.tgz", 342 + "integrity": "sha512-aY2gMmKmPhxfU+0EdnN+XNtGbjfQgwZj43k8G3fyrDM/UdZww6xrWxmDkuz2eCZchqVeABjV5BpildOrUbBTqA==", 343 + "cpu": [ 344 + "x64" 345 + ], 346 + "dev": true, 347 + "license": "MIT", 348 + "optional": true, 349 + "os": [ 350 + "openbsd" 351 + ], 352 + "engines": { 353 + "node": ">=18" 354 + } 355 + }, 356 + "node_modules/@esbuild/sunos-x64": { 357 + "version": "0.23.1", 358 + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.23.1.tgz", 359 + "integrity": "sha512-RBRT2gqEl0IKQABT4XTj78tpk9v7ehp+mazn2HbUeZl1YMdaGAQqhapjGTCe7uw7y0frDi4gS0uHzhvpFuI1sA==", 360 + "cpu": [ 361 + "x64" 362 + ], 363 + "dev": true, 364 + "license": "MIT", 365 + "optional": true, 366 + "os": [ 367 + "sunos" 368 + ], 369 + "engines": { 370 + "node": ">=18" 371 + } 372 + }, 373 + "node_modules/@esbuild/win32-arm64": { 374 + "version": "0.23.1", 375 + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.23.1.tgz", 376 + "integrity": "sha512-4O+gPR5rEBe2FpKOVyiJ7wNDPA8nGzDuJ6gN4okSA1gEOYZ67N8JPk58tkWtdtPeLz7lBnY6I5L3jdsr3S+A6A==", 377 + "cpu": [ 378 + "arm64" 379 + ], 380 + "dev": true, 381 + "license": "MIT", 382 + "optional": true, 383 + "os": [ 384 + "win32" 385 + ], 386 + "engines": { 387 + "node": ">=18" 388 + } 389 + }, 390 + "node_modules/@esbuild/win32-ia32": { 391 + "version": "0.23.1", 392 + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.23.1.tgz", 393 + "integrity": "sha512-BcaL0Vn6QwCwre3Y717nVHZbAa4UBEigzFm6VdsVdT/MbZ38xoj1X9HPkZhbmaBGUD1W8vxAfffbDe8bA6AKnQ==", 394 + "cpu": [ 395 + "ia32" 396 + ], 397 + "dev": true, 398 + "license": "MIT", 399 + "optional": true, 400 + "os": [ 401 + "win32" 402 + ], 403 + "engines": { 404 + "node": ">=18" 405 + } 406 + }, 407 + "node_modules/@esbuild/win32-x64": { 408 + "version": "0.23.1", 409 + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.23.1.tgz", 410 + "integrity": "sha512-BHpFFeslkWrXWyUPnbKm+xYYVYruCinGcftSBaa8zoF9hZO4BcSCFUvHVTtzpIY6YzUnYtuEhZ+C9iEXjxnasg==", 411 + "cpu": [ 412 + "x64" 413 + ], 414 + "dev": true, 415 + "license": "MIT", 416 + "optional": true, 417 + "os": [ 418 + "win32" 419 + ], 420 + "engines": { 421 + "node": ">=18" 12 422 } 13 423 }, 14 424 "node_modules/@prisma/client": { ··· 73 483 "@prisma/debug": "5.20.0" 74 484 } 75 485 }, 486 + "node_modules/esbuild": { 487 + "version": "0.23.1", 488 + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.23.1.tgz", 489 + "integrity": "sha512-VVNz/9Sa0bs5SELtn3f7qhJCDPCF5oMEl5cO9/SSinpE9hbPVvxbd572HH5AKiP7WD8INO53GgfDDhRjkylHEg==", 490 + "dev": true, 491 + "hasInstallScript": true, 492 + "license": "MIT", 493 + "bin": { 494 + "esbuild": "bin/esbuild" 495 + }, 496 + "engines": { 497 + "node": ">=18" 498 + }, 499 + "optionalDependencies": { 500 + "@esbuild/aix-ppc64": "0.23.1", 501 + "@esbuild/android-arm": "0.23.1", 502 + "@esbuild/android-arm64": "0.23.1", 503 + "@esbuild/android-x64": "0.23.1", 504 + "@esbuild/darwin-arm64": "0.23.1", 505 + "@esbuild/darwin-x64": "0.23.1", 506 + "@esbuild/freebsd-arm64": "0.23.1", 507 + "@esbuild/freebsd-x64": "0.23.1", 508 + "@esbuild/linux-arm": "0.23.1", 509 + "@esbuild/linux-arm64": "0.23.1", 510 + "@esbuild/linux-ia32": "0.23.1", 511 + "@esbuild/linux-loong64": "0.23.1", 512 + "@esbuild/linux-mips64el": "0.23.1", 513 + "@esbuild/linux-ppc64": "0.23.1", 514 + "@esbuild/linux-riscv64": "0.23.1", 515 + "@esbuild/linux-s390x": "0.23.1", 516 + "@esbuild/linux-x64": "0.23.1", 517 + "@esbuild/netbsd-x64": "0.23.1", 518 + "@esbuild/openbsd-arm64": "0.23.1", 519 + "@esbuild/openbsd-x64": "0.23.1", 520 + "@esbuild/sunos-x64": "0.23.1", 521 + "@esbuild/win32-arm64": "0.23.1", 522 + "@esbuild/win32-ia32": "0.23.1", 523 + "@esbuild/win32-x64": "0.23.1" 524 + } 525 + }, 76 526 "node_modules/fsevents": { 77 527 "version": "2.3.3", 78 528 "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", ··· 87 537 "node": "^8.16.0 || ^10.6.0 || >=11.0.0" 88 538 } 89 539 }, 540 + "node_modules/get-tsconfig": { 541 + "version": "4.8.1", 542 + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.8.1.tgz", 543 + "integrity": "sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg==", 544 + "dev": true, 545 + "license": "MIT", 546 + "dependencies": { 547 + "resolve-pkg-maps": "^1.0.0" 548 + }, 549 + "funding": { 550 + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" 551 + } 552 + }, 553 + "node_modules/nats": { 554 + "version": "2.28.2", 555 + "resolved": "https://registry.npmjs.org/nats/-/nats-2.28.2.tgz", 556 + "integrity": "sha512-02cvR8EPach+0BfVaQjPgsbPFn6uMjEQAuvXS2ppg8jiWEm2KYdfmeFmtshiU9b2+kFh3LSEKMEaIfRgk3K8tw==", 557 + "dev": true, 558 + "license": "Apache-2.0", 559 + "dependencies": { 560 + "nkeys.js": "1.1.0" 561 + }, 562 + "engines": { 563 + "node": ">= 14.0.0" 564 + } 565 + }, 566 + "node_modules/nkeys.js": { 567 + "version": "1.1.0", 568 + "resolved": "https://registry.npmjs.org/nkeys.js/-/nkeys.js-1.1.0.tgz", 569 + "integrity": "sha512-tB/a0shZL5UZWSwsoeyqfTszONTt4k2YS0tuQioMOD180+MbombYVgzDUYHlx+gejYK6rgf08n/2Df99WY0Sxg==", 570 + "dev": true, 571 + "license": "Apache-2.0", 572 + "dependencies": { 573 + "tweetnacl": "1.0.3" 574 + }, 575 + "engines": { 576 + "node": ">=10.0.0" 577 + } 578 + }, 90 579 "node_modules/prisma": { 91 580 "version": "5.20.0", 92 581 "resolved": "https://registry.npmjs.org/prisma/-/prisma-5.20.0.tgz", ··· 105 594 "optionalDependencies": { 106 595 "fsevents": "2.3.3" 107 596 } 597 + }, 598 + "node_modules/resolve-pkg-maps": { 599 + "version": "1.0.0", 600 + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", 601 + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", 602 + "dev": true, 603 + "license": "MIT", 604 + "funding": { 605 + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" 606 + } 607 + }, 608 + "node_modules/tsx": { 609 + "version": "4.19.2", 610 + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.19.2.tgz", 611 + "integrity": "sha512-pOUl6Vo2LUq/bSa8S5q7b91cgNSjctn9ugq/+Mvow99qW6x/UZYwzxy/3NmqoT66eHYfCVvFvACC58UBPFf28g==", 612 + "dev": true, 613 + "license": "MIT", 614 + "dependencies": { 615 + "esbuild": "~0.23.0", 616 + "get-tsconfig": "^4.7.5" 617 + }, 618 + "bin": { 619 + "tsx": "dist/cli.mjs" 620 + }, 621 + "engines": { 622 + "node": ">=18.0.0" 623 + }, 624 + "optionalDependencies": { 625 + "fsevents": "~2.3.3" 626 + } 627 + }, 628 + "node_modules/tweetnacl": { 629 + "version": "1.0.3", 630 + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", 631 + "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==", 632 + "dev": true, 633 + "license": "Unlicense" 108 634 } 109 635 } 110 636 }
+3 -1
package.json
··· 1 1 { 2 2 "devDependencies": { 3 - "prisma": "^5.20.0" 3 + "nats": "^2.28.2", 4 + "prisma": "^5.20.0", 5 + "tsx": "^4.19.2" 4 6 }, 5 7 "dependencies": { 6 8 "@prisma/client": "^5.20.0"
+4 -3
receiver.go
··· 1 1 package notella 2 2 3 3 import ( 4 - "github.com/nats-io/nats.go/jetstream" 4 + ll "github.com/ewen-lbh/label-logger-go" 5 + "github.com/nats-io/nats.go" 5 6 ) 6 7 7 - func NatsReceiver(m jetstream.Msg) { 8 - 8 + func NatsReceiver(m *nats.Msg) { 9 + ll.Log("Received", "cyan", "message: %s", string(m.Data)) 9 10 }
+62
scripts/mocksender.ts
··· 1 + import { connect, StringCodec, JetStreamManager, NatsConnection } from "nats" 2 + 3 + async function setupStream( 4 + jetStreamManager: JetStreamManager, 5 + streamName: string, 6 + subject: string 7 + ) { 8 + try { 9 + // Try to add the stream (will not recreate if it exists) 10 + await jetStreamManager.streams.add({ 11 + name: streamName, 12 + subjects: [subject], 13 + }) 14 + console.log(`Stream '${streamName}' created or already exists.`) 15 + } catch (err) { 16 + console.error(`Error setting up stream: ${err.message}`) 17 + } 18 + } 19 + 20 + async function publishMessages( 21 + nc: NatsConnection, 22 + subject: string, 23 + messageCount: number, 24 + delayMs: number 25 + ) { 26 + const js = nc.jetstream() 27 + const sc = StringCodec() 28 + 29 + for (let i = 1; i <= messageCount; i++) { 30 + const message = `Mock Order #${i}` 31 + await js.publish(subject, sc.encode(message)) 32 + console.log(`Sent message: ${message}`) 33 + await new Promise((resolve) => setTimeout(resolve, delayMs)) 34 + } 35 + } 36 + 37 + async function main() { 38 + const streamName = "notella:stream" 39 + const subject = "notella:notification" 40 + 41 + // Connect to the NATS server 42 + const nc = await connect({ servers: "localhost:4222" }) 43 + console.log("Connected to NATS") 44 + 45 + // Create a JetStream manager to manage streams 46 + const jsm = await nc.jetstreamManager() 47 + 48 + // Ensure the stream exists 49 + await setupStream(jsm, streamName, subject) 50 + 51 + // Publish messages at intervals 52 + const messageCount = 20 53 + const delayMs = 1000 // 1 second delay between messages 54 + await publishMessages(nc, subject, messageCount, delayMs) 55 + 56 + console.log("Finished sending messages.") 57 + await nc.close() 58 + } 59 + 60 + main().catch((err) => { 61 + console.error(`Error in sender: ${err.message}`) 62 + })
+54 -21
server/main.go
··· 5 5 import ( 6 6 "context" 7 7 "fmt" 8 + "log" 8 9 "os" 9 10 "os/signal" 10 11 "syscall" ··· 16 17 ll "github.com/ewen-lbh/label-logger-go" 17 18 "github.com/joho/godotenv" 18 19 "github.com/nats-io/nats.go" 19 - "github.com/nats-io/nats.go/jetstream" 20 20 ) 21 21 22 22 type Configuration struct { ··· 28 28 } 29 29 30 30 var Version = "DEV" 31 + 32 + const StreamName = "notella:stream" 33 + const SubjectName = "notella:notification" 31 34 32 35 func main() { 33 36 figure.NewColorFigure("Notella", "", "yellow", true).Print() ··· 66 69 return 67 70 } 68 71 69 - ctx, cancel := context.WithTimeout(context.Background(), 30 * time.Second) 70 - defer cancel() 71 - 72 - js, err := jetstream.New(nc) 72 + js, err := nc.JetStream() 73 73 if err != nil { 74 74 ll.ErrorDisplay("could not connect to Jetstream", err) 75 75 return 76 76 } 77 77 78 - ll.Log("Initializing", "cyan", "a Jetstream stream [bold]notella:stream[reset], listening for [bold]notella:*[reset] subjects") 78 + ll.Log("Initializing", "cyan", "a Jetstream stream [bold]%s[reset], listening for subject [bold]%s[reset]", StreamName, SubjectName) 79 79 80 - s, err := js.CreateStream(ctx, jetstream.StreamConfig{ 81 - Name: "notella:stream", 82 - Subjects: []string{"notella:*"}, 80 + _, err = js.AddStream(&nats.StreamConfig{ 81 + Name: StreamName, 82 + Subjects: []string{SubjectName}, 83 83 }) 84 84 if err != nil { 85 85 ll.ErrorDisplay("could not create stream", err) ··· 88 88 89 89 ll.Log("Initializing", "cyan", "Jetstream consumer [bold]NotellaConsumer[reset] with [bold]AckExplicitPolicy[reset]") 90 90 91 - cons, err := s.CreateOrUpdateConsumer(ctx, jetstream.ConsumerConfig{ 91 + _, err = js.AddConsumer(StreamName, &nats.ConsumerConfig{ 92 92 Durable: "NotellaConsumer", 93 - AckPolicy: jetstream.AckExplicitPolicy, 93 + AckPolicy: nats.AckExplicitPolicy, 94 94 }) 95 95 if err != nil { 96 96 ll.ErrorDisplay("could not create consumer", err) ··· 99 99 100 100 ll.Log("Starting", "cyan", "consumer [bold]NotellaConsumer[reset]") 101 101 102 - cc, err := cons.Consume(func(msg jetstream.Msg) { 103 - fmt.Println(string(msg.Data())) 104 - msg.Ack() 105 - }, jetstream.ConsumeErrHandler(func(consumeCtx jetstream.ConsumeContext, err error) { 106 - fmt.Println(err) 107 - })) 102 + sub, err := js.PullSubscribe(SubjectName, "NotellaConsumer") 108 103 if err != nil { 109 104 ll.ErrorDisplay("could not start consumer", err) 110 105 return 111 106 } 112 - defer cc.Stop() 107 + 108 + // Setup a context to handle graceful shutdowns 109 + ctx, cancel := context.WithCancel(context.Background()) 110 + defer cancel() 111 + 112 + // Capture OS signals for graceful shutdown 113 + go func() { 114 + sigChan := make(chan os.Signal, 1) 115 + signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM) 116 + <-sigChan 117 + log.Println("Received shutdown signal, shutting down...") 118 + cancel() 119 + }() 120 + 121 + // Continuously fetch and process messages 122 + go func() { 123 + for { 124 + select { 125 + case <-ctx.Done(): 126 + return 127 + default: 128 + // Fetch messages in batches 129 + msgs, err := sub.Fetch(10, nats.MaxWait(5*time.Second)) 130 + if err != nil && err != nats.ErrTimeout { 131 + log.Printf("Error fetching messages: %v", err) 132 + time.Sleep(2 * time.Second) // Wait before retrying 133 + continue 134 + } 113 135 114 - sig := make(chan os.Signal, 1) 115 - signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM) 116 - <-sig 136 + // Process each message 137 + for _, msg := range msgs { 138 + log.Printf("Processing message: %s", string(msg.Data)) 139 + // Simulate notification scheduling 140 + notella.NatsReceiver(msg) 141 + msg.Ack() // Acknowledge the message 142 + } 143 + } 144 + } 145 + }() 146 + 147 + // Block until the context is canceled (i.e., server shutdown signal received) 148 + <-ctx.Done() 149 + log.Println("Server stopped.") 117 150 }