Compare commits
No commits in common. "955b3ded7eeff136818af074365ed8a2099f2d75" and "a89f6a6351ad1e186f4afb34771b695315b373c5" have entirely different histories.
955b3ded7e
...
a89f6a6351
23 changed files with 519 additions and 565 deletions
175
.gitignore
vendored
175
.gitignore
vendored
|
@ -1,175 +1,2 @@
|
|||
# Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore
|
||||
|
||||
# Logs
|
||||
|
||||
logs
|
||||
_.log
|
||||
npm-debug.log_
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
lerna-debug.log*
|
||||
.pnpm-debug.log*
|
||||
|
||||
# Caches
|
||||
|
||||
.cache
|
||||
|
||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||
|
||||
report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json
|
||||
|
||||
# Runtime data
|
||||
|
||||
pids
|
||||
_.pid
|
||||
_.seed
|
||||
*.pid.lock
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
|
||||
coverage
|
||||
*.lcov
|
||||
|
||||
# nyc test coverage
|
||||
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# Snowpack dependency directory (https://snowpack.dev/)
|
||||
|
||||
web_modules/
|
||||
|
||||
# TypeScript cache
|
||||
|
||||
*.tsbuildinfo
|
||||
|
||||
# Optional npm cache directory
|
||||
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
|
||||
.eslintcache
|
||||
|
||||
# Optional stylelint cache
|
||||
|
||||
.stylelintcache
|
||||
|
||||
# Microbundle cache
|
||||
|
||||
.rpt2_cache/
|
||||
.rts2_cache_cjs/
|
||||
.rts2_cache_es/
|
||||
.rts2_cache_umd/
|
||||
|
||||
# Optional REPL history
|
||||
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variable files
|
||||
|
||||
.env
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
.env.local
|
||||
|
||||
# parcel-bundler cache (https://parceljs.org/)
|
||||
|
||||
.parcel-cache
|
||||
|
||||
# Next.js build output
|
||||
|
||||
.next
|
||||
out
|
||||
|
||||
# Nuxt.js build / generate output
|
||||
|
||||
.nuxt
|
||||
dist
|
||||
|
||||
# Gatsby files
|
||||
|
||||
# Comment in the public line in if your project uses Gatsby and not Next.js
|
||||
|
||||
# https://nextjs.org/blog/next-9-1#public-directory-support
|
||||
|
||||
# public
|
||||
|
||||
# vuepress build output
|
||||
|
||||
.vuepress/dist
|
||||
|
||||
# vuepress v2.x temp and cache directory
|
||||
|
||||
.temp
|
||||
|
||||
# Docusaurus cache and generated files
|
||||
|
||||
.docusaurus
|
||||
|
||||
# Serverless directories
|
||||
|
||||
.serverless/
|
||||
|
||||
# FuseBox cache
|
||||
|
||||
.fusebox/
|
||||
|
||||
# DynamoDB Local files
|
||||
|
||||
.dynamodb/
|
||||
|
||||
# TernJS port file
|
||||
|
||||
.tern-port
|
||||
|
||||
# Stores VSCode versions used for testing VSCode extensions
|
||||
|
||||
.vscode-test
|
||||
|
||||
# yarn v2
|
||||
|
||||
.yarn/cache
|
||||
.yarn/unplugged
|
||||
.yarn/build-state.yml
|
||||
.yarn/install-state.gz
|
||||
.pnp.*
|
||||
|
||||
# IntelliJ based IDEs
|
||||
.idea
|
||||
|
||||
# Finder (MacOS) folder config
|
||||
.DS_Store
|
||||
npm/
|
7
.vscode/settings.json
vendored
7
.vscode/settings.json
vendored
|
@ -1,8 +1,3 @@
|
|||
{
|
||||
"editor.formatOnSave": true,
|
||||
"editor.defaultFormatter": "biomejs.biome",
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.organizeImports.biome": "explicit"
|
||||
},
|
||||
"typescript.tsdk": "node_modules/typescript/lib"
|
||||
"editor.formatOnSave": true
|
||||
}
|
|
@ -1,14 +1,8 @@
|
|||
when:
|
||||
event: [push]
|
||||
|
||||
steps:
|
||||
build:
|
||||
image: oven/bun:${BUN_VERSION}-slim
|
||||
image: denoland/deno:1.39.2
|
||||
commands:
|
||||
- bun install
|
||||
- bun run build
|
||||
|
||||
matrix:
|
||||
BUN_VERSION:
|
||||
- 1.0.25
|
||||
- 1.0.26
|
||||
- apt update
|
||||
- apt install curl -y
|
||||
- curl -fsSL https://deb.nodesource.com/setup_lts.x | bash - && apt-get install -y nodejs
|
||||
- deno task build
|
|
@ -1,10 +1,9 @@
|
|||
when:
|
||||
event: [push]
|
||||
|
||||
steps:
|
||||
lint:
|
||||
image: oven/bun:1.0.26-slim
|
||||
image: denoland/deno:${DENO_VERSION}
|
||||
commands:
|
||||
- bun install
|
||||
- bun run ci
|
||||
- deno lint
|
||||
|
||||
matrix:
|
||||
DENO_VERSION:
|
||||
- 1.39.2
|
|
@ -1,19 +1,14 @@
|
|||
when:
|
||||
event: [push]
|
||||
|
||||
steps:
|
||||
test:
|
||||
image: oven/bun:${BUN_VERSION}-slim
|
||||
image: denoland/deno:${DENO_VERSION}
|
||||
environment:
|
||||
- NATS_HOST=nats:4222
|
||||
commands:
|
||||
- bun install
|
||||
- bun run test
|
||||
- deno task test
|
||||
|
||||
matrix:
|
||||
BUN_VERSION:
|
||||
- 1.0.25
|
||||
- 1.0.26
|
||||
DENO_VERSION:
|
||||
- 1.39.2
|
||||
|
||||
services:
|
||||
nats:
|
||||
|
|
20
biome.json
20
biome.json
|
@ -1,20 +0,0 @@
|
|||
{
|
||||
"$schema": "https://biomejs.dev/schemas/1.5.3/schema.json",
|
||||
"organizeImports": {
|
||||
"enabled": true
|
||||
},
|
||||
"linter": {
|
||||
"enabled": true,
|
||||
"rules": {
|
||||
"recommended": true
|
||||
}
|
||||
},
|
||||
"formatter": {
|
||||
"enabled": true
|
||||
},
|
||||
"vcs": {
|
||||
"enabled": true,
|
||||
"clientKind": "git",
|
||||
"useIgnoreFile": true
|
||||
}
|
||||
}
|
BIN
bun.lockb
BIN
bun.lockb
Binary file not shown.
16
deno.json
Normal file
16
deno.json
Normal file
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"imports": {
|
||||
"nats": "npm:nats",
|
||||
"zod": "npm:zod",
|
||||
"std/": "https://deno.land/std@0.211.0/",
|
||||
"dnt": "https://deno.land/x/dnt@0.39.0/mod.ts"
|
||||
},
|
||||
"tasks": {
|
||||
"test": "deno test --allow-net --allow-env --parallel",
|
||||
"build": "deno run -A scripts/build_npm.ts 0.1.0",
|
||||
"publish": "cd npm && npm publish"
|
||||
},
|
||||
"lint": {
|
||||
"include": ["src/"]
|
||||
}
|
||||
}
|
175
deno.lock
Normal file
175
deno.lock
Normal file
|
@ -0,0 +1,175 @@
|
|||
{
|
||||
"version": "3",
|
||||
"packages": {
|
||||
"specifiers": {
|
||||
"npm:nats": "npm:nats@2.18.0",
|
||||
"npm:zod": "npm:zod@3.22.4"
|
||||
},
|
||||
"npm": {
|
||||
"nats@2.18.0": {
|
||||
"integrity": "sha512-zZF004ejzf67Za0Tva+xphxoxBMNc5IMLqbZ7Ho0j9TMuisjpo+qCd1EktXRCLNxmrZ8O6Tbm1dBsZYNF6yR1A==",
|
||||
"dependencies": {
|
||||
"nkeys.js": "nkeys.js@1.0.5"
|
||||
}
|
||||
},
|
||||
"nkeys.js@1.0.5": {
|
||||
"integrity": "sha512-u25YnRPHiGVsNzwyHnn+PT90sgAhnS8jUJ1nxmkHMFYCJ6+Ic0lv291w7uhRBpJVJ3PH2GWbYqA151lGCRrB5g==",
|
||||
"dependencies": {
|
||||
"tweetnacl": "tweetnacl@1.0.3"
|
||||
}
|
||||
},
|
||||
"tweetnacl@1.0.3": {
|
||||
"integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==",
|
||||
"dependencies": {}
|
||||
},
|
||||
"zod@3.22.4": {
|
||||
"integrity": "sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==",
|
||||
"dependencies": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"remote": {
|
||||
"https://deno.land/std@0.140.0/_util/assert.ts": "e94f2eb37cebd7f199952e242c77654e43333c1ac4c5c700e929ea3aa5489f74",
|
||||
"https://deno.land/std@0.140.0/_util/os.ts": "3b4c6e27febd119d36a416d7a97bd3b0251b77c88942c8f16ee5953ea13e2e49",
|
||||
"https://deno.land/std@0.140.0/bytes/bytes_list.ts": "67eb118e0b7891d2f389dad4add35856f4ad5faab46318ff99653456c23b025d",
|
||||
"https://deno.land/std@0.140.0/bytes/equals.ts": "fc16dff2090cced02497f16483de123dfa91e591029f985029193dfaa9d894c9",
|
||||
"https://deno.land/std@0.140.0/bytes/mod.ts": "763f97d33051cc3f28af1a688dfe2830841192a9fea0cbaa55f927b49d49d0bf",
|
||||
"https://deno.land/std@0.140.0/fmt/colors.ts": "30455035d6d728394781c10755351742dd731e3db6771b1843f9b9e490104d37",
|
||||
"https://deno.land/std@0.140.0/fs/_util.ts": "0fb24eb4bfebc2c194fb1afdb42b9c3dda12e368f43e8f2321f84fc77d42cb0f",
|
||||
"https://deno.land/std@0.140.0/fs/ensure_dir.ts": "9dc109c27df4098b9fc12d949612ae5c9c7169507660dcf9ad90631833209d9d",
|
||||
"https://deno.land/std@0.140.0/io/buffer.ts": "bd0c4bf53db4b4be916ca5963e454bddfd3fcd45039041ea161dbf826817822b",
|
||||
"https://deno.land/std@0.140.0/path/_constants.ts": "df1db3ffa6dd6d1252cc9617e5d72165cd2483df90e93833e13580687b6083c3",
|
||||
"https://deno.land/std@0.140.0/path/_interface.ts": "ee3b431a336b80cf445441109d089b70d87d5e248f4f90ff906820889ecf8d09",
|
||||
"https://deno.land/std@0.140.0/path/_util.ts": "c1e9686d0164e29f7d880b2158971d805b6e0efc3110d0b3e24e4b8af2190d2b",
|
||||
"https://deno.land/std@0.140.0/path/common.ts": "bee563630abd2d97f99d83c96c2fa0cca7cee103e8cb4e7699ec4d5db7bd2633",
|
||||
"https://deno.land/std@0.140.0/path/glob.ts": "cb5255638de1048973c3e69e420c77dc04f75755524cb3b2e160fe9277d939ee",
|
||||
"https://deno.land/std@0.140.0/path/mod.ts": "d3e68d0abb393fb0bf94a6d07c46ec31dc755b544b13144dee931d8d5f06a52d",
|
||||
"https://deno.land/std@0.140.0/path/posix.ts": "293cdaec3ecccec0a9cc2b534302dfe308adb6f10861fa183275d6695faace44",
|
||||
"https://deno.land/std@0.140.0/path/separator.ts": "fe1816cb765a8068afb3e8f13ad272351c85cbc739af56dacfc7d93d710fe0f9",
|
||||
"https://deno.land/std@0.140.0/path/win32.ts": "31811536855e19ba37a999cd8d1b62078235548d67902ece4aa6b814596dd757",
|
||||
"https://deno.land/std@0.140.0/streams/conversion.ts": "712585bfa0172a97fb68dd46e784ae8ad59d11b88079d6a4ab098ff42e697d21",
|
||||
"https://deno.land/std@0.181.0/_util/asserts.ts": "178dfc49a464aee693a7e285567b3d0b555dc805ff490505a8aae34f9cfb1462",
|
||||
"https://deno.land/std@0.181.0/_util/os.ts": "d932f56d41e4f6a6093d56044e29ce637f8dcc43c5a90af43504a889cf1775e3",
|
||||
"https://deno.land/std@0.181.0/fmt/colors.ts": "d67e3cd9f472535241a8e410d33423980bec45047e343577554d3356e1f0ef4e",
|
||||
"https://deno.land/std@0.181.0/fs/_util.ts": "65381f341af1ff7f40198cee15c20f59951ac26e51ddc651c5293e24f9ce6f32",
|
||||
"https://deno.land/std@0.181.0/fs/empty_dir.ts": "c3d2da4c7352fab1cf144a1ecfef58090769e8af633678e0f3fabaef98594688",
|
||||
"https://deno.land/std@0.181.0/fs/ensure_dir.ts": "dc64c4c75c64721d4e3fb681f1382f803ff3d2868f08563ff923fdd20d071c40",
|
||||
"https://deno.land/std@0.181.0/fs/expand_glob.ts": "e4f56259a0a70fe23f05215b00de3ac5e6ba46646ab2a06ebbe9b010f81c972a",
|
||||
"https://deno.land/std@0.181.0/fs/walk.ts": "ea95ffa6500c1eda6b365be488c056edc7c883a1db41ef46ec3bf057b1c0fe32",
|
||||
"https://deno.land/std@0.181.0/path/_constants.ts": "e49961f6f4f48039c0dfed3c3f93e963ca3d92791c9d478ac5b43183413136e0",
|
||||
"https://deno.land/std@0.181.0/path/_interface.ts": "6471159dfbbc357e03882c2266d21ef9afdb1e4aa771b0545e90db58a0ba314b",
|
||||
"https://deno.land/std@0.181.0/path/_util.ts": "d7abb1e0dea065f427b89156e28cdeb32b045870acdf865833ba808a73b576d0",
|
||||
"https://deno.land/std@0.181.0/path/common.ts": "ee7505ab01fd22de3963b64e46cff31f40de34f9f8de1fff6a1bd2fe79380000",
|
||||
"https://deno.land/std@0.181.0/path/glob.ts": "d479e0a695621c94d3fd7fe7abd4f9499caf32a8de13f25073451c6ef420a4e1",
|
||||
"https://deno.land/std@0.181.0/path/mod.ts": "bf718f19a4fdd545aee1b06409ca0805bd1b68ecf876605ce632e932fe54510c",
|
||||
"https://deno.land/std@0.181.0/path/posix.ts": "8b7c67ac338714b30c816079303d0285dd24af6b284f7ad63da5b27372a2c94d",
|
||||
"https://deno.land/std@0.181.0/path/separator.ts": "0fb679739d0d1d7bf45b68dacfb4ec7563597a902edbaf3c59b50d5bcadd93b1",
|
||||
"https://deno.land/std@0.181.0/path/win32.ts": "d186344e5583bcbf8b18af416d13d82b35a317116e6460a5a3953508c3de5bba",
|
||||
"https://deno.land/std@0.210.0/assert/_constants.ts": "8a9da298c26750b28b326b297316cdde860bc237533b07e1337c021379e6b2a9",
|
||||
"https://deno.land/std@0.210.0/assert/_diff.ts": "2c9371f17cf08cbb843c924bc31ca77af422ec4fe162f73d42c651d547573fa8",
|
||||
"https://deno.land/std@0.210.0/assert/_format.ts": "335ce8e15c65b679ad142dbc9e5e97e5d58602c39dd3c9175cef6c85fe22d6d5",
|
||||
"https://deno.land/std@0.210.0/assert/assert.ts": "e265ad50a9341f3b40e51dd4cb41ab253d976943ba78a977106950e52e0302ab",
|
||||
"https://deno.land/std@0.210.0/assert/assert_almost_equals.ts": "a70d637856e1c6128dc733346d32aa73c67058489495116ca85091c39a60c767",
|
||||
"https://deno.land/std@0.210.0/assert/assert_array_includes.ts": "59d005d8897c1fbcbd5792170833f13a867f6a5ecd5a6b34a3d86b4b430de63c",
|
||||
"https://deno.land/std@0.210.0/assert/assert_equals.ts": "991b0c2b437a015d623654f758e48bfd931068211a52e8131b397cdf005c595f",
|
||||
"https://deno.land/std@0.210.0/assert/assert_exists.ts": "f24ecb0d3febad358a6cee235f012551077e07692517ebfe0630a561ba40a703",
|
||||
"https://deno.land/std@0.210.0/assert/assert_false.ts": "99cf237fe374cabf57072d2fb41b3eaff389029f850fbb96f643c875792f10ce",
|
||||
"https://deno.land/std@0.210.0/assert/assert_greater.ts": "e0bba9ac76a780573a864ab6eeb8b9fd71435b750bdd36d56a270e22ab9a79d9",
|
||||
"https://deno.land/std@0.210.0/assert/assert_greater_or_equal.ts": "aea1c7dc868926ba55f1e59f8c3560bb44706b5e3b6b009453ee4064eecf6746",
|
||||
"https://deno.land/std@0.210.0/assert/assert_instance_of.ts": "7c093d36b1a86666d5a60a8c290c91a51a627153b821a5a4dc40b24cab69f1e7",
|
||||
"https://deno.land/std@0.210.0/assert/assert_is_error.ts": "a8a758581661edec514c453910bee2f9c91b1346a515c58404963b130d81cd80",
|
||||
"https://deno.land/std@0.210.0/assert/assert_less.ts": "855aa58e49afa6a9e825f1abcd5947dc789c5878fc1b6f48b8a08115d48da32b",
|
||||
"https://deno.land/std@0.210.0/assert/assert_less_or_equal.ts": "2ae5246bd0e83da26e5c8e2815d1493252f71f7dc02afb83dc2fc0e0fb0bd894",
|
||||
"https://deno.land/std@0.210.0/assert/assert_match.ts": "e541a9769cf5726312ff9e15031e2faa2df3c59fbdc5573c8758b1f4668ccc62",
|
||||
"https://deno.land/std@0.210.0/assert/assert_not_equals.ts": "6bce4b28f3316029c0aef107f8390796798835c382d31c1004160baef0b80db0",
|
||||
"https://deno.land/std@0.210.0/assert/assert_not_instance_of.ts": "866243fd28bc6665e2ffcc027a9df1d2a69cb644aef1e9b8d1ce34377c6b8a84",
|
||||
"https://deno.land/std@0.210.0/assert/assert_not_match.ts": "59707eceb0d2b16d6892fbf92ec86f92fd76fcfc55f8b61508299db7d2972cab",
|
||||
"https://deno.land/std@0.210.0/assert/assert_not_strict_equals.ts": "c84b8e229450e8dfc44b9910d602788313ff7333d67d5bd8528371567b6a3632",
|
||||
"https://deno.land/std@0.210.0/assert/assert_object_match.ts": "ebeff248d48e5810f787e8742ae4f6b39904f4640edc2f69796596ceb6dbcdf8",
|
||||
"https://deno.land/std@0.210.0/assert/assert_rejects.ts": "f7e83272d816e1b39710012a0597ed950db2de6b193adcc5e50ddbcd9e177767",
|
||||
"https://deno.land/std@0.210.0/assert/assert_strict_equals.ts": "4007dabef1c2e9d6f1bb0e948ba7ba99ec9b1bee97ba34d67f7c10e7e5d794f7",
|
||||
"https://deno.land/std@0.210.0/assert/assert_string_includes.ts": "108a30d9348e5ff7a8b0b7cc836cf0a8cff27d5b33e861b8c56b52cc60b8219a",
|
||||
"https://deno.land/std@0.210.0/assert/assert_throws.ts": "a8767e6a06e94bac42ca9eebdad5d4e2decbc0c48bc892da7e06aa1fe0b388ba",
|
||||
"https://deno.land/std@0.210.0/assert/assertion_error.ts": "26ed1863d905005f00785c89750c001c3522c5417e4f58f95044b8143cfc1593",
|
||||
"https://deno.land/std@0.210.0/assert/equal.ts": "6f81c8a3b12c08bdc3510c8a1293b4db1c083692219d7e3828d2234b448d3d3d",
|
||||
"https://deno.land/std@0.210.0/assert/fail.ts": "f56fc64f9a141f98c1be5ff1005ddf158db888b7b206510e955bb3fedc69021c",
|
||||
"https://deno.land/std@0.210.0/assert/mod.ts": "37c49a26aae2b254bbe25723434dc28cd7532e444cf0b481a97c045d110ec085",
|
||||
"https://deno.land/std@0.210.0/assert/unimplemented.ts": "4e3e504792c87c485dbc5f4020489d8806ef697741403af2008dfa7b5a4711e8",
|
||||
"https://deno.land/std@0.210.0/assert/unreachable.ts": "1af8c99421cc5fb7332454b2b9eca074a4e394895a180bc837750dedcca75338",
|
||||
"https://deno.land/std@0.210.0/fmt/colors.ts": "2685c524bef9b16b3059a417daf6860c754eb755e19e812762ef5dff62f24481",
|
||||
"https://deno.land/std@0.210.0/testing/_test_suite.ts": "30f018feeb3835f12ab198d8a518f9089b1bcb2e8c838a8b615ab10d5005465c",
|
||||
"https://deno.land/std@0.210.0/testing/bdd.ts": "c41f019786c4a9112aadb7e5a7bbcc711f58429ac5904b3855fa248ba5fa0ba6",
|
||||
"https://deno.land/std@0.211.0/assert/_constants.ts": "a271e8ef5a573f1df8e822a6eb9d09df064ad66a4390f21b3e31f820a38e0975",
|
||||
"https://deno.land/std@0.211.0/assert/_diff.ts": "6a2d68f2c42d73a1e31818a4195f40598d672c7f02ac75c7f1b1e6789852c2bc",
|
||||
"https://deno.land/std@0.211.0/assert/_format.ts": "0ba808961bf678437fb486b56405b6fefad2cf87b5809667c781ddee8c32aff4",
|
||||
"https://deno.land/std@0.211.0/assert/assert.ts": "bec068b2fccdd434c138a555b19a2c2393b71dfaada02b7d568a01541e67cdc5",
|
||||
"https://deno.land/std@0.211.0/assert/assert_almost_equals.ts": "648ea72678296a5ad86d3bbb66904335fa97de3133223f44ca4596b225cdcbef",
|
||||
"https://deno.land/std@0.211.0/assert/assert_array_includes.ts": "dbb461c20681807a884ad84d873f9e4daead380859531b1e7f27fa4e8f8bf431",
|
||||
"https://deno.land/std@0.211.0/assert/assert_equals.ts": "b3b33ae8a85ae22a0754c61a7486d4ae870e8938830a94f5cacecba3a9b0442a",
|
||||
"https://deno.land/std@0.211.0/assert/assert_exists.ts": "24a7bf965e634f909242cd09fbaf38bde6b791128ece08e33ab08586a7cc55c9",
|
||||
"https://deno.land/std@0.211.0/assert/assert_false.ts": "6f382568e5128c0f855e5f7dbda8624c1ed9af4fcc33ef4a9afeeedcdce99769",
|
||||
"https://deno.land/std@0.211.0/assert/assert_greater.ts": "8dfcf082d2bcffcaab3bd0dab48d41e41c26266529567246de47bd6864936f6d",
|
||||
"https://deno.land/std@0.211.0/assert/assert_greater_or_equal.ts": "9e02ef89f32563f539f7e66556930033418728847aefcca4e3806a735b5f122e",
|
||||
"https://deno.land/std@0.211.0/assert/assert_instance_of.ts": "72dc1faff1e248692d873c89382fa1579dd7b53b56d52f37f9874a75b11ba444",
|
||||
"https://deno.land/std@0.211.0/assert/assert_is_error.ts": "6596f2b5ba89ba2fe9b074f75e9318cda97a2381e59d476812e30077fbdb6ed2",
|
||||
"https://deno.land/std@0.211.0/assert/assert_less.ts": "91a6fed705f9c39bbd683b62aa9dfc42547bc886c29f696997e681cafb886b16",
|
||||
"https://deno.land/std@0.211.0/assert/assert_less_or_equal.ts": "7a3c2e554eb20aa6af9dd4a410e550bcee9e8a28102d51f5f40cb1b8d141e4e1",
|
||||
"https://deno.land/std@0.211.0/assert/assert_match.ts": "ec2d9680ed3e7b9746ec57ec923a17eef6d476202f339ad91d22277d7f1d16e1",
|
||||
"https://deno.land/std@0.211.0/assert/assert_not_equals.ts": "cb78bf9a4357d69673c87b634491bc6b840412c8b55efe472af9877ef6f0a29b",
|
||||
"https://deno.land/std@0.211.0/assert/assert_not_instance_of.ts": "8f720d92d83775c40b2542a8d76c60c2d4aeddaf8713c8d11df8984af2604931",
|
||||
"https://deno.land/std@0.211.0/assert/assert_not_match.ts": "b4b7c77f146963e2b673c1ce4846473703409eb93f5ab0eb60f6e6f8aeffe39f",
|
||||
"https://deno.land/std@0.211.0/assert/assert_not_strict_equals.ts": "89ba25e1da5233404ac4c01651c088759b7977c51034eefc6050fe3fc2d10c46",
|
||||
"https://deno.land/std@0.211.0/assert/assert_object_match.ts": "e85e5eef62a56ce364c3afdd27978ccab979288a3e772e6855c270a7b118fa49",
|
||||
"https://deno.land/std@0.211.0/assert/assert_rejects.ts": "e9e0c8d9c3e164c7ac962c37b3be50577c5a2010db107ed272c4c1afb1269f54",
|
||||
"https://deno.land/std@0.211.0/assert/assert_strict_equals.ts": "0425a98f70badccb151644c902384c12771a93e65f8ff610244b8147b03a2366",
|
||||
"https://deno.land/std@0.211.0/assert/assert_string_includes.ts": "dfb072a890167146f8e5bdd6fde887ce4657098e9f71f12716ef37f35fb6f4a7",
|
||||
"https://deno.land/std@0.211.0/assert/assert_throws.ts": "edddd86b39606c342164b49ad88dd39a26e72a26655e07545d172f164b617fa7",
|
||||
"https://deno.land/std@0.211.0/assert/assertion_error.ts": "9f689a101ee586c4ce92f52fa7ddd362e86434ffdf1f848e45987dc7689976b8",
|
||||
"https://deno.land/std@0.211.0/assert/equal.ts": "fae5e8a52a11d3ac694bbe1a53e13a7969e3f60791262312e91a3e741ae519e2",
|
||||
"https://deno.land/std@0.211.0/assert/fail.ts": "f310e51992bac8e54f5fd8e44d098638434b2edb802383690e0d7a9be1979f1c",
|
||||
"https://deno.land/std@0.211.0/assert/mod.ts": "325df8c0683ad83a873b9691aa66b812d6275fc9fec0b2d180ac68a2c5efed3b",
|
||||
"https://deno.land/std@0.211.0/assert/unimplemented.ts": "47ca67d1c6dc53abd0bd729b71a31e0825fc452dbcd4fde4ca06789d5644e7fd",
|
||||
"https://deno.land/std@0.211.0/assert/unreachable.ts": "38cfecb95d8b06906022d2f9474794fca4161a994f83354fd079cac9032b5145",
|
||||
"https://deno.land/std@0.211.0/fmt/colors.ts": "be082d6a6bbb2980ae7b2bf8c23c6bb2811ba90a06a9bcb861344a71784c5a99",
|
||||
"https://deno.land/std@0.211.0/testing/_test_suite.ts": "f10a8a6338b60c403f07a76f3f46bdc9f1e1a820c0a1decddeb2949f7a8a0546",
|
||||
"https://deno.land/std@0.211.0/testing/bdd.ts": "3cbd17bd35f629a76ce63446238dfb4632240dd46b3b205027c45fa3dd67e554",
|
||||
"https://deno.land/x/code_block_writer@12.0.0/mod.ts": "2c3448060e47c9d08604c8f40dee34343f553f33edcdfebbf648442be33205e5",
|
||||
"https://deno.land/x/code_block_writer@12.0.0/utils/string_utils.ts": "60cb4ec8bd335bf241ef785ccec51e809d576ff8e8d29da43d2273b69ce2a6ff",
|
||||
"https://deno.land/x/deno_cache@0.6.2/auth_tokens.ts": "5d1d56474c54a9d152e44d43ea17c2e6a398dd1e9682c69811a313567c01ee1e",
|
||||
"https://deno.land/x/deno_cache@0.6.2/cache.ts": "58b53c128b742757efcad10af9a3871f23b4e200674cb5b0ddf61164fb9b2fe7",
|
||||
"https://deno.land/x/deno_cache@0.6.2/deno_dir.ts": "1ea355b8ba11c630d076b222b197cfc937dd81e5a4a260938997da99e8ff93a0",
|
||||
"https://deno.land/x/deno_cache@0.6.2/deps.ts": "12cca94516cf2d3ed42fccd4b721ecd8060679253f077d83057511045b0081aa",
|
||||
"https://deno.land/x/deno_cache@0.6.2/dirs.ts": "009c6f54e0b610914d6ce9f72f6f6ccfffd2d47a79a19061e0a9eb4253836069",
|
||||
"https://deno.land/x/deno_cache@0.6.2/disk_cache.ts": "66a1e604a8d564b6dd0500326cac33d08b561d331036bf7272def80f2f7952aa",
|
||||
"https://deno.land/x/deno_cache@0.6.2/file_fetcher.ts": "4f3e4a2c78a5ca1e4812099e5083f815a8525ab20d389b560b3517f6b1161dd6",
|
||||
"https://deno.land/x/deno_cache@0.6.2/http_cache.ts": "407135eaf2802809ed373c230d57da7ef8dff923c4abf205410b9b99886491fd",
|
||||
"https://deno.land/x/deno_cache@0.6.2/lib/deno_cache_dir.generated.js": "59f8defac32e8ebf2a30f7bc77e9d88f0e60098463fb1b75e00b9791a4bbd733",
|
||||
"https://deno.land/x/deno_cache@0.6.2/lib/snippets/deno_cache_dir-a2aecaa9536c9402/fs.js": "cbe3a976ed63c72c7cb34ef845c27013033a3b11f9d8d3e2c4aa5dda2c0c7af6",
|
||||
"https://deno.land/x/deno_cache@0.6.2/mod.ts": "b4004287e1c6123d7f07fe9b5b3e94ce6d990c4102949a89c527c68b19627867",
|
||||
"https://deno.land/x/deno_cache@0.6.2/util.ts": "f3f5a0cfc60051f09162942fb0ee87a0e27b11a12aec4c22076e3006be4cc1e2",
|
||||
"https://deno.land/x/dir@1.5.1/data_local_dir/mod.ts": "91eb1c4bfadfbeda30171007bac6d85aadacd43224a5ed721bbe56bc64e9eb66",
|
||||
"https://deno.land/x/dnt@0.39.0/lib/compiler.ts": "7f4447531581896348b8a379ab94730856b42ae50d99043f2468328360293cb1",
|
||||
"https://deno.land/x/dnt@0.39.0/lib/compiler_transforms.ts": "f21aba052f5dcf0b0595c734450842855c7f572e96165d3d34f8fed2fc1f7ba1",
|
||||
"https://deno.land/x/dnt@0.39.0/lib/mod.deps.ts": "8d6123c8e1162037e58aa8126686a03d1e2cffb250a8757bf715f80242097597",
|
||||
"https://deno.land/x/dnt@0.39.0/lib/npm_ignore.ts": "57fbb7e7b935417d225eec586c6aa240288905eb095847d3f6a88e290209df4e",
|
||||
"https://deno.land/x/dnt@0.39.0/lib/package_json.ts": "607b0a4f44acad071a4c8533b312a27d6671eac8e6a23625c8350ce29eadb2ba",
|
||||
"https://deno.land/x/dnt@0.39.0/lib/pkg/dnt_wasm.generated.js": "4f9c59b3ca6c875adabb10df256e273fff1129fca3a1557eb8936bddd7da7b18",
|
||||
"https://deno.land/x/dnt@0.39.0/lib/pkg/snippets/dnt-wasm-a15ef721fa5290c5/helpers.js": "aba69a019a6da6f084898a6c7b903b8b583bc0dbd82bfb338449cf0b5bce58fd",
|
||||
"https://deno.land/x/dnt@0.39.0/lib/shims.ts": "60fd285ad433c6944544595e7b885eab3eab09253252891380654f4cd3addaaa",
|
||||
"https://deno.land/x/dnt@0.39.0/lib/test_runner/get_test_runner_code.ts": "4dc7a73a13b027341c0688df2b29a4ef102f287c126f134c33f69f0339b46968",
|
||||
"https://deno.land/x/dnt@0.39.0/lib/test_runner/test_runner.ts": "4d0da0500ec427d5f390d9a8d42fb882fbeccc92c92d66b6f2e758606dbd40e6",
|
||||
"https://deno.land/x/dnt@0.39.0/lib/transform.deps.ts": "2e159661e1c5c650de9a573babe0e319349fe493105157307ec2ad2f6a52c94e",
|
||||
"https://deno.land/x/dnt@0.39.0/lib/types.ts": "b8e228b2fac44c2ae902fbb73b1689f6ab889915bd66486c8a85c0c24255f5fb",
|
||||
"https://deno.land/x/dnt@0.39.0/lib/utils.ts": "224f15f33e7226a2fd991e438d0291d7ed8c7889807efa2e1ecb67d2d1db6720",
|
||||
"https://deno.land/x/dnt@0.39.0/mod.ts": "9df36a862161d9eb376472b699f6cb08ba0ad1704e0826fbe13be766bd3c01da",
|
||||
"https://deno.land/x/dnt@0.39.0/transform.ts": "f68743a14cf9bf53bfc9c81073871d69d447a7f9e3453e0447ca2fb78926bb1d",
|
||||
"https://deno.land/x/ts_morph@20.0.0/bootstrap/mod.ts": "b53aad517f106c4079971fcd4a81ab79fadc40b50061a3ab2b741a09119d51e9",
|
||||
"https://deno.land/x/ts_morph@20.0.0/bootstrap/ts_morph_bootstrap.js": "6645ac03c5e6687dfa8c78109dc5df0250b811ecb3aea2d97c504c35e8401c06",
|
||||
"https://deno.land/x/ts_morph@20.0.0/common/DenoRuntime.ts": "6a7180f0c6e90dcf23ccffc86aa8271c20b1c4f34c570588d08a45880b7e172d",
|
||||
"https://deno.land/x/ts_morph@20.0.0/common/mod.ts": "01985d2ee7da8d1caee318a9d07664774fbee4e31602bc2bb6bb62c3489555ed",
|
||||
"https://deno.land/x/ts_morph@20.0.0/common/ts_morph_common.js": "2325f94f61dc5f3f98a1dab366dc93048d11b1433d718b10cfc6ee5a1cfebe8f",
|
||||
"https://deno.land/x/ts_morph@20.0.0/common/typescript.js": "b9edf0a451685d13e0467a7ed4351d112b74bd1e256b915a2b941054e31c1736",
|
||||
"https://deno.land/x/wasmbuild@0.15.1/cache.ts": "9d01b5cb24e7f2a942bbd8d14b093751fa690a6cde8e21709ddc97667e6669ed",
|
||||
"https://deno.land/x/wasmbuild@0.15.1/loader.ts": "8c2fc10e21678e42f84c5135d8ab6ab7dc92424c3f05d2354896a29ccfd02a63"
|
||||
}
|
||||
}
|
4
mod.ts
Normal file
4
mod.ts
Normal file
|
@ -0,0 +1,4 @@
|
|||
export * from "./src/service.ts";
|
||||
export * from "./src/adaptors/nats.ts";
|
||||
export * from "./src/error.ts";
|
||||
export type { Request, Response } from "./src/messages.ts";
|
26
package.json
26
package.json
|
@ -1,26 +0,0 @@
|
|||
{
|
||||
"name": "@qpismont/nano-service",
|
||||
"version": "0.0.1",
|
||||
"module": "index.ts",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
"files": ["/dist"],
|
||||
"scripts": {
|
||||
"ci": "biome ci . --error-on-warnings",
|
||||
"test": "bun test",
|
||||
"build": "tsc --project tsconfig.build.json"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "1.5.3",
|
||||
"@types/bun": "latest",
|
||||
"typescript": "^5.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": "^5.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"nats": "^2.19.0",
|
||||
"zod": "^3.22.4"
|
||||
}
|
||||
}
|
27
scripts/build_npm.ts
Normal file
27
scripts/build_npm.ts
Normal file
|
@ -0,0 +1,27 @@
|
|||
import { build, emptyDir } from "dnt";
|
||||
|
||||
await emptyDir("./npm");
|
||||
|
||||
await build({
|
||||
entryPoints: ["./mod.ts"],
|
||||
outDir: "./npm",
|
||||
shims: {
|
||||
deno: true,
|
||||
},
|
||||
test: false,
|
||||
importMap: "deno.json",
|
||||
package: {
|
||||
name: "@qpismont/nano-service",
|
||||
version: Deno.args[0],
|
||||
description: "Your package.",
|
||||
license: "MIT",
|
||||
repository: {
|
||||
"type": "git",
|
||||
"url": "https://gitea.qpismont.fr/qpismont/nano-service",
|
||||
},
|
||||
},
|
||||
postBuild() {
|
||||
Deno.copyFileSync("LICENSE", "npm/LICENSE");
|
||||
Deno.copyFileSync("README.md", "npm/README.md");
|
||||
},
|
||||
});
|
|
@ -1,8 +1,8 @@
|
|||
import type { AdaptorSubscribeTypeFn } from "../types.ts";
|
||||
import { AdaptorSubscribeTypeFn } from "../types.ts";
|
||||
|
||||
export default interface Adaptor {
|
||||
subscribe(subject: string, fn: AdaptorSubscribeTypeFn): void;
|
||||
request(subject: string, req: string): Promise<string>;
|
||||
listen(serviceName: string): Promise<void>;
|
||||
stop(): Promise<void>;
|
||||
subscribe(subject: string, fn: AdaptorSubscribeTypeFn): void;
|
||||
request(subject: string, req: string): Promise<string>;
|
||||
listen(serviceName: string): Promise<void>;
|
||||
stop(): Promise<void>;
|
||||
}
|
||||
|
|
|
@ -1,57 +1,57 @@
|
|||
import { AdaptorSubscribeTypeFn } from "../types.ts";
|
||||
import Adaptor from "./adaptor.ts";
|
||||
import {
|
||||
type Codec,
|
||||
type ConnectionOptions,
|
||||
type NatsConnection,
|
||||
StringCodec,
|
||||
type Subscription,
|
||||
connect,
|
||||
Codec,
|
||||
connect,
|
||||
ConnectionOptions,
|
||||
NatsConnection,
|
||||
StringCodec,
|
||||
Subscription,
|
||||
} from "nats";
|
||||
import type { AdaptorSubscribeTypeFn } from "../types.ts";
|
||||
import type Adaptor from "./adaptor.ts";
|
||||
|
||||
export default class NatsAdaptor implements Adaptor {
|
||||
private options: ConnectionOptions;
|
||||
private options: ConnectionOptions;
|
||||
|
||||
private nc?: NatsConnection;
|
||||
private nc?: NatsConnection;
|
||||
|
||||
private callbacks: Record<string, AdaptorSubscribeTypeFn>;
|
||||
private callbacks: Record<string, AdaptorSubscribeTypeFn>;
|
||||
|
||||
private sc: Codec<string>;
|
||||
private sc: Codec<string>;
|
||||
|
||||
private sub?: Subscription;
|
||||
private sub?: Subscription;
|
||||
|
||||
constructor(options: ConnectionOptions) {
|
||||
this.options = options;
|
||||
this.sc = StringCodec();
|
||||
this.callbacks = {};
|
||||
}
|
||||
constructor(options: ConnectionOptions) {
|
||||
this.options = options;
|
||||
this.sc = StringCodec();
|
||||
this.callbacks = {};
|
||||
}
|
||||
|
||||
async listen(serviceName: string) {
|
||||
this.nc = await connect(this.options);
|
||||
async listen(serviceName: string) {
|
||||
this.nc = await connect(this.options);
|
||||
|
||||
this.sub = this.nc.subscribe(`${serviceName}.*`);
|
||||
(async (sub: Subscription) => {
|
||||
for await (const msg of sub) {
|
||||
const res = await this.callbacks[msg.subject](this.sc.decode(msg.data));
|
||||
msg.respond(this.sc.encode(res));
|
||||
}
|
||||
})(this.sub);
|
||||
}
|
||||
this.sub = this.nc.subscribe(`${serviceName}.*`);
|
||||
(async (sub: Subscription) => {
|
||||
for await (const msg of sub) {
|
||||
const res = await this.callbacks[msg.subject](this.sc.decode(msg.data));
|
||||
msg.respond(this.sc.encode(res));
|
||||
}
|
||||
})(this.sub);
|
||||
}
|
||||
|
||||
subscribe(subject: string, fn: AdaptorSubscribeTypeFn) {
|
||||
this.callbacks[subject] = fn;
|
||||
}
|
||||
subscribe(subject: string, fn: AdaptorSubscribeTypeFn) {
|
||||
this.callbacks[subject] = fn;
|
||||
}
|
||||
|
||||
async request(subject: string, req: string): Promise<string> {
|
||||
if (this.nc) {
|
||||
const msg = await this.nc.request(subject, this.sc.encode(req));
|
||||
return this.sc.decode(msg.data);
|
||||
}
|
||||
async request(subject: string, req: string): Promise<string> {
|
||||
if (this.nc) {
|
||||
const msg = await this.nc.request(subject, this.sc.encode(req));
|
||||
return this.sc.decode(msg.data);
|
||||
}
|
||||
|
||||
throw new Error("nats connection is not initialized");
|
||||
}
|
||||
throw new Error("nats connection is not initialized");
|
||||
}
|
||||
|
||||
async stop(): Promise<void> {
|
||||
await this.nc?.drain();
|
||||
}
|
||||
async stop(): Promise<void> {
|
||||
await this.nc?.drain();
|
||||
}
|
||||
}
|
||||
|
|
10
src/error.ts
10
src/error.ts
|
@ -1,9 +1,9 @@
|
|||
export class RequestError extends Error {
|
||||
public statusCode: number;
|
||||
public statusCode: number;
|
||||
|
||||
constructor(msg: string, statusCode: number) {
|
||||
super(msg);
|
||||
constructor(msg: string, statusCode: number) {
|
||||
super(msg);
|
||||
|
||||
this.statusCode = statusCode;
|
||||
}
|
||||
this.statusCode = statusCode;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
export * from "./service";
|
||||
export * from "./adaptors/nats";
|
||||
export * from "./error";
|
||||
export type { Request, Response } from "./messages";
|
|
@ -1,25 +1,25 @@
|
|||
import { z } from "zod";
|
||||
|
||||
export interface Request<T> {
|
||||
service: string;
|
||||
subject: string;
|
||||
data?: T;
|
||||
service: string;
|
||||
subject: string;
|
||||
data?: T;
|
||||
}
|
||||
|
||||
export const InternalRequestSchema = z.object({
|
||||
from: z.string(),
|
||||
data: z.optional(z.any()),
|
||||
from: z.string(),
|
||||
data: z.optional(z.any()),
|
||||
});
|
||||
|
||||
export const InternalResponseSchema = z.object({
|
||||
data: z.optional(z.any()),
|
||||
statusCode: z.number(),
|
||||
data: z.optional(z.any()),
|
||||
statusCode: z.number(),
|
||||
});
|
||||
|
||||
export type InternalRequest = z.infer<typeof InternalRequestSchema>;
|
||||
export type InternalResponse = z.infer<typeof InternalResponseSchema>;
|
||||
|
||||
export interface Response<T> {
|
||||
data?: T;
|
||||
statusCode: number;
|
||||
data?: T;
|
||||
statusCode: number;
|
||||
}
|
||||
|
|
280
src/service.ts
280
src/service.ts
|
@ -1,156 +1,166 @@
|
|||
import { z } from "zod";
|
||||
import type Adaptor from "./adaptors/adaptor";
|
||||
import { RequestError } from "./error";
|
||||
import Adaptor from "./adaptors/adaptor.ts";
|
||||
import { RequestError } from "./error.ts";
|
||||
import {
|
||||
type InternalRequest,
|
||||
InternalRequestSchema,
|
||||
type InternalResponse,
|
||||
InternalResponseSchema,
|
||||
type Request,
|
||||
type Response,
|
||||
} from "./messages";
|
||||
import type { RouteSubscribeTypeFn } from "./types";
|
||||
InternalRequest,
|
||||
InternalRequestSchema,
|
||||
InternalResponse,
|
||||
InternalResponseSchema,
|
||||
Request,
|
||||
Response,
|
||||
} from "./messages.ts";
|
||||
import { RouteSubscribeTypeFn } from "./types.ts";
|
||||
import { z } from "zod";
|
||||
|
||||
export default class Service {
|
||||
private name: string;
|
||||
private name: string;
|
||||
|
||||
private adaptors: Record<string, Adaptor>;
|
||||
private adaptors: Record<string, Adaptor>;
|
||||
|
||||
constructor(name: string) {
|
||||
this.name = name;
|
||||
this.adaptors = {};
|
||||
}
|
||||
constructor(name: string) {
|
||||
this.name = name;
|
||||
this.adaptors = {};
|
||||
}
|
||||
|
||||
public addAdaptor(name: string, adaptor: Adaptor) {
|
||||
this.adaptors[name] = adaptor;
|
||||
}
|
||||
public addAdaptor(name: string, adaptor: Adaptor) {
|
||||
this.adaptors[name] = adaptor;
|
||||
}
|
||||
|
||||
public subscribe<T extends z.ZodType<O>, O, U>(
|
||||
adaptor: string,
|
||||
subject: string,
|
||||
fn: RouteSubscribeTypeFn<z.infer<T>, U>,
|
||||
schema: T | undefined = undefined,
|
||||
) {
|
||||
this.adaptors[adaptor].subscribe(
|
||||
`${this.name}.${subject}`,
|
||||
async (rawReq) => {
|
||||
const rawReqJson = JSON.parse(rawReq);
|
||||
const internalRequestJson = InternalRequestSchema.safeParse(rawReqJson);
|
||||
if (!internalRequestJson.success) {
|
||||
return JSON.stringify({
|
||||
statusCode: 400,
|
||||
data: "bad request structure",
|
||||
} satisfies InternalResponse);
|
||||
}
|
||||
public subscribe<T extends z.ZodType<O>, O, U>(
|
||||
adaptor: string,
|
||||
subject: string,
|
||||
fn: RouteSubscribeTypeFn<z.infer<T>, U>,
|
||||
schema: T | undefined = undefined,
|
||||
) {
|
||||
this.adaptors[adaptor].subscribe(
|
||||
`${this.name}.${subject}`,
|
||||
async (rawReq) => {
|
||||
const rawReqJson = JSON.parse(rawReq);
|
||||
const internalRequestJson = InternalRequestSchema.safeParse(rawReqJson);
|
||||
if (!internalRequestJson.success) {
|
||||
return JSON.stringify(
|
||||
{
|
||||
statusCode: 400,
|
||||
data: "bad request structure",
|
||||
} satisfies InternalResponse,
|
||||
);
|
||||
}
|
||||
|
||||
const internalRequest = internalRequestJson.data;
|
||||
const req = {
|
||||
service: internalRequest.from,
|
||||
subject: subject,
|
||||
} as Request<z.infer<T>>;
|
||||
const internalRequest = internalRequestJson.data;
|
||||
const req = {
|
||||
service: internalRequest.from,
|
||||
subject: subject,
|
||||
} as Request<z.infer<T>>;
|
||||
|
||||
if (internalRequest.data && schema) {
|
||||
const validate = schema.safeParse(internalRequest.data);
|
||||
if (!validate.success) {
|
||||
return JSON.stringify({
|
||||
statusCode: 400,
|
||||
data: validate.error,
|
||||
} satisfies InternalResponse);
|
||||
}
|
||||
req.data = validate.data;
|
||||
}
|
||||
if (internalRequest.data && schema) {
|
||||
const validate = schema.safeParse(internalRequest.data);
|
||||
if (!validate.success) {
|
||||
return JSON.stringify(
|
||||
{
|
||||
statusCode: 400,
|
||||
data: validate.error,
|
||||
} satisfies InternalResponse,
|
||||
);
|
||||
} else {
|
||||
req.data = validate.data;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const res = await fn(req);
|
||||
const internalResponse = {
|
||||
statusCode: res.statusCode,
|
||||
data: res.data,
|
||||
} satisfies InternalResponse;
|
||||
try {
|
||||
const res = await fn(req);
|
||||
const internalResponse = {
|
||||
statusCode: res.statusCode,
|
||||
data: res.data,
|
||||
} satisfies InternalResponse;
|
||||
|
||||
return JSON.stringify(internalResponse);
|
||||
} catch (err) {
|
||||
if (err instanceof RequestError) {
|
||||
return JSON.stringify({
|
||||
statusCode: err.statusCode,
|
||||
data: err.message,
|
||||
} satisfies InternalResponse);
|
||||
}
|
||||
return JSON.stringify({
|
||||
statusCode: 500,
|
||||
data: "unknow error apend",
|
||||
} satisfies InternalResponse);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
return JSON.stringify(internalResponse);
|
||||
} catch (err) {
|
||||
if (err instanceof RequestError) {
|
||||
return JSON.stringify(
|
||||
{
|
||||
statusCode: err.statusCode,
|
||||
data: err.message,
|
||||
} satisfies InternalResponse,
|
||||
);
|
||||
} else {
|
||||
return JSON.stringify(
|
||||
{
|
||||
statusCode: 500,
|
||||
data: err?.message || "unknow error apend",
|
||||
} satisfies InternalResponse,
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
public async request<T, O, U extends z.ZodType<O>>(
|
||||
adaptor: string,
|
||||
req: Request<T>,
|
||||
schema?: z.ZodType<O>,
|
||||
): Promise<Response<z.infer<U>>> {
|
||||
if (!this.adaptors[adaptor]) {
|
||||
throw new Error(`${adaptor} adaptor not exist`);
|
||||
}
|
||||
public async request<T, O, U extends z.ZodType<O>>(
|
||||
adaptor: string,
|
||||
req: Request<T>,
|
||||
schema?: z.ZodType<O>,
|
||||
): Promise<Response<z.infer<U>>> {
|
||||
if (!this.adaptors[adaptor]) {
|
||||
throw new Error(`${adaptor} adaptor not exist`);
|
||||
}
|
||||
|
||||
const internalRequest = {
|
||||
from: this.name,
|
||||
data: req.data,
|
||||
} satisfies InternalRequest;
|
||||
const internalRequestJson = JSON.stringify(internalRequest);
|
||||
const internalRequest = {
|
||||
from: this.name,
|
||||
data: req.data,
|
||||
} satisfies InternalRequest;
|
||||
const internalRequestJson = JSON.stringify(internalRequest);
|
||||
|
||||
try {
|
||||
const rawRes = await this.adaptors[adaptor].request(
|
||||
`${req.service}.${req.subject}`,
|
||||
internalRequestJson,
|
||||
);
|
||||
const rawResJson: unknown = JSON.parse(rawRes);
|
||||
const internalResponseJson = InternalResponseSchema.safeParse(rawResJson);
|
||||
if (!internalResponseJson.success) {
|
||||
throw new RequestError(internalResponseJson.error.toString(), 500);
|
||||
}
|
||||
try {
|
||||
const rawRes = await this.adaptors[adaptor].request(
|
||||
`${req.service}.${req.subject}`,
|
||||
internalRequestJson,
|
||||
);
|
||||
const rawResJson: unknown = JSON.parse(rawRes);
|
||||
const internalResponseJson = InternalResponseSchema.safeParse(rawResJson);
|
||||
if (!internalResponseJson.success) {
|
||||
throw new RequestError(internalResponseJson.error.toString(), 500);
|
||||
}
|
||||
|
||||
const internalResponse = internalResponseJson.data;
|
||||
if (
|
||||
internalResponse.statusCode < 200 ||
|
||||
internalResponse.statusCode >= 299
|
||||
) {
|
||||
throw new RequestError(
|
||||
internalResponse.data,
|
||||
internalResponse.statusCode,
|
||||
);
|
||||
}
|
||||
const res: Response<z.infer<U>> = {
|
||||
statusCode: internalResponse.statusCode,
|
||||
};
|
||||
if (internalResponse.data && schema) {
|
||||
const validate = schema.safeParse(internalResponse.data);
|
||||
const internalResponse = internalResponseJson.data;
|
||||
if (
|
||||
internalResponse.statusCode < 200 || internalResponse.statusCode >= 299
|
||||
) {
|
||||
throw new RequestError(
|
||||
internalResponse.data,
|
||||
internalResponse.statusCode,
|
||||
);
|
||||
}
|
||||
const res: Response<z.infer<U>> = {
|
||||
statusCode: internalResponse.statusCode,
|
||||
};
|
||||
if (internalResponse.data && schema) {
|
||||
const validate = schema.safeParse(internalResponse.data);
|
||||
|
||||
if (!validate.success) {
|
||||
throw new RequestError(validate.error.message, 400);
|
||||
}
|
||||
res.data = validate.data;
|
||||
}
|
||||
if (!validate.success) {
|
||||
throw new RequestError(validate.error.message, 400);
|
||||
} else {
|
||||
res.data = validate.data;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
} catch (err) {
|
||||
if (err instanceof RequestError) {
|
||||
throw err;
|
||||
}
|
||||
return res;
|
||||
} catch (err) {
|
||||
if (err instanceof RequestError) {
|
||||
throw err;
|
||||
}
|
||||
|
||||
throw new RequestError("unexpected error", 500);
|
||||
}
|
||||
}
|
||||
throw new RequestError("unexpected error", 500);
|
||||
}
|
||||
}
|
||||
|
||||
public async listen() {
|
||||
for (const index in this.adaptors) {
|
||||
await this.adaptors[index].listen(this.name);
|
||||
}
|
||||
}
|
||||
public async listen() {
|
||||
for (const index in this.adaptors) {
|
||||
await this.adaptors[index].listen(this.name);
|
||||
}
|
||||
}
|
||||
|
||||
public async stop() {
|
||||
for (const index in this.adaptors) {
|
||||
await this.adaptors[index].stop();
|
||||
}
|
||||
}
|
||||
public async stop() {
|
||||
for (const index in this.adaptors) {
|
||||
await this.adaptors[index].stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import type { Request, Response } from "./messages.ts";
|
||||
import { Request, Response } from "./messages.ts";
|
||||
|
||||
export type AdaptorSubscribeTypeFn = (msg: string) => Promise<string>;
|
||||
export type RouteSubscribeTypeFn<T, U> = (
|
||||
msg: Request<T>,
|
||||
msg: Request<T>,
|
||||
) => Promise<Response<U>>;
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import { expect, test } from "bun:test";
|
||||
import { RequestError } from "../src/error";
|
||||
import { RequestError } from "../src/error.ts";
|
||||
import { assertEquals } from "std/assert/mod.ts";
|
||||
|
||||
test("request error", () => {
|
||||
const expectedMsg = "This is my err";
|
||||
const expectedStatusCode = 500;
|
||||
Deno.test("request error", () => {
|
||||
const expectedMsg = "This is my err";
|
||||
const expectedStatusCode = 500;
|
||||
|
||||
const err = new RequestError(expectedMsg, expectedStatusCode);
|
||||
const err = new RequestError(expectedMsg, expectedStatusCode);
|
||||
|
||||
expect(err.message).toBe(expectedMsg);
|
||||
expect(err.statusCode).toBe(expectedStatusCode);
|
||||
assertEquals(err.message, expectedMsg);
|
||||
assertEquals(err.statusCode, expectedStatusCode);
|
||||
});
|
||||
|
|
|
@ -1,97 +1,92 @@
|
|||
import { afterEach, beforeEach, expect, test } from "bun:test";
|
||||
import { z } from "zod";
|
||||
import NatsAdaptor from "../src/adaptors/nats";
|
||||
import { RequestError } from "../src/error";
|
||||
import Service from "../src/service";
|
||||
import NatsAdaptor from "../src/adaptors/nats.ts";
|
||||
import Service from "../src/service.ts";
|
||||
import { assertEquals, assertRejects, assertThrows } from "std/assert/mod.ts";
|
||||
import { afterEach, beforeEach, it } from "std/testing/bdd.ts";
|
||||
import { RequestError } from "../src/error.ts";
|
||||
|
||||
let srv!: Service;
|
||||
|
||||
const natsServer = Bun.env.NATS_HOST || "127.0.0.1:4222";
|
||||
const natsServer = Deno.env.get("NATS_HOST") || "127.0.0.1:4222";
|
||||
const serviceName = "test-service";
|
||||
const adaptorName = "nats";
|
||||
const subject = "test";
|
||||
|
||||
beforeEach(() => {
|
||||
srv = new Service(serviceName);
|
||||
srv = new Service(serviceName);
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await srv.stop();
|
||||
await srv.stop();
|
||||
});
|
||||
|
||||
test("request success", async () => {
|
||||
const dataExpected = "hello success";
|
||||
const statusCodeExpected = 200;
|
||||
it("request success", {
|
||||
sanitizeExit: false,
|
||||
sanitizeOps: false,
|
||||
sanitizeResources: false,
|
||||
}, async () => {
|
||||
const dataExpected = "hello success";
|
||||
const statusCodeExpected = 200;
|
||||
|
||||
srv.addAdaptor(adaptorName, new NatsAdaptor({ servers: [natsServer] }));
|
||||
srv.subscribe(
|
||||
adaptorName,
|
||||
subject,
|
||||
async (msg) => {
|
||||
return { data: msg.data, statusCode: statusCodeExpected };
|
||||
},
|
||||
z.string(),
|
||||
);
|
||||
srv.addAdaptor(adaptorName, new NatsAdaptor({ servers: [natsServer] }));
|
||||
srv.subscribe(adaptorName, subject, async (msg) => {
|
||||
return { data: msg.data, statusCode: statusCodeExpected };
|
||||
}, z.string());
|
||||
|
||||
await srv.listen();
|
||||
await srv.listen();
|
||||
|
||||
const res = await srv.request(
|
||||
adaptorName,
|
||||
{
|
||||
service: serviceName,
|
||||
subject: subject,
|
||||
data: dataExpected,
|
||||
},
|
||||
z.string(),
|
||||
);
|
||||
const res = await srv.request(adaptorName, {
|
||||
service: serviceName,
|
||||
subject: subject,
|
||||
data: dataExpected,
|
||||
}, z.string());
|
||||
|
||||
expect(res.data).toBe(dataExpected);
|
||||
expect(res.statusCode).toBe(statusCodeExpected);
|
||||
assertEquals(res.data, dataExpected);
|
||||
assertEquals(res.statusCode, statusCodeExpected);
|
||||
});
|
||||
|
||||
test("request error", async () => {
|
||||
const dataExpected = "hello error";
|
||||
const statusCodeExpected = 500;
|
||||
it("request error", {
|
||||
sanitizeExit: false,
|
||||
sanitizeOps: false,
|
||||
sanitizeResources: false,
|
||||
}, async () => {
|
||||
const dataExpected = "hello error";
|
||||
const statusCodeExpected = 500;
|
||||
|
||||
srv.addAdaptor(adaptorName, new NatsAdaptor({ servers: [natsServer] }));
|
||||
srv.subscribe(
|
||||
adaptorName,
|
||||
subject,
|
||||
async (msg) => {
|
||||
throw new RequestError("request error", 500);
|
||||
},
|
||||
z.string(),
|
||||
);
|
||||
srv.addAdaptor(adaptorName, new NatsAdaptor({ servers: [natsServer] }));
|
||||
srv.subscribe(adaptorName, subject, async (msg) => {
|
||||
throw new RequestError("request error", 500);
|
||||
}, z.string());
|
||||
|
||||
await srv.listen();
|
||||
expect(() => {
|
||||
return srv.request(
|
||||
adaptorName,
|
||||
{
|
||||
service: serviceName,
|
||||
subject: subject,
|
||||
data: dataExpected,
|
||||
},
|
||||
z.string(),
|
||||
);
|
||||
}).toThrow();
|
||||
await srv.listen();
|
||||
assertRejects(() => {
|
||||
return srv.request(adaptorName, {
|
||||
service: serviceName,
|
||||
subject: subject,
|
||||
data: dataExpected,
|
||||
}, z.string());
|
||||
});
|
||||
});
|
||||
|
||||
test("request adaptor not found", async () => {
|
||||
const dataExpected = "hello success";
|
||||
const statusCodeExpected = 200;
|
||||
it("request adaptor not found", {
|
||||
sanitizeExit: false,
|
||||
sanitizeOps: false,
|
||||
sanitizeResources: false,
|
||||
}, async () => {
|
||||
const dataExpected = "hello success";
|
||||
const statusCodeExpected = 200;
|
||||
|
||||
srv.addAdaptor(adaptorName, new NatsAdaptor({ servers: [natsServer] }));
|
||||
srv.subscribe(adaptorName, subject, async (msg) => {
|
||||
return { data: msg.data, statusCode: statusCodeExpected };
|
||||
});
|
||||
srv.addAdaptor(adaptorName, new NatsAdaptor({ servers: [natsServer] }));
|
||||
srv.subscribe(adaptorName, subject, async (msg) => {
|
||||
return { data: msg.data, statusCode: statusCodeExpected };
|
||||
});
|
||||
|
||||
await srv.listen();
|
||||
expect(() => {
|
||||
return srv.request("bad adaptor", {
|
||||
service: serviceName,
|
||||
subject: subject,
|
||||
data: dataExpected,
|
||||
});
|
||||
}).toThrow();
|
||||
await srv.listen();
|
||||
assertRejects(() => {
|
||||
return srv.request("bad adaptor", {
|
||||
service: serviceName,
|
||||
subject: subject,
|
||||
data: dataExpected,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"noEmit": false,
|
||||
"noEmitOnError": true,
|
||||
"outDir": "dist/",
|
||||
"allowImportingTsExtensions": false,
|
||||
"declaration": true
|
||||
},
|
||||
"include": ["./src/**/*"]
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"lib": ["ESNext"],
|
||||
"target": "ESNext",
|
||||
"module": "ESNext",
|
||||
"moduleDetection": "force",
|
||||
"jsx": "react-jsx",
|
||||
"allowJs": true,
|
||||
|
||||
/* Bundler mode */
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"verbatimModuleSyntax": true,
|
||||
"noEmit": true,
|
||||
|
||||
/* Linting */
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"forceConsistentCasingInFileNames": true
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue