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/
|
node_modules/
|
||||||
jspm_packages/
|
npm/
|
||||||
|
|
||||||
# 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
|
|
9
.vscode/settings.json
vendored
9
.vscode/settings.json
vendored
|
@ -1,8 +1,3 @@
|
||||||
{
|
{
|
||||||
"editor.formatOnSave": true,
|
"editor.formatOnSave": true
|
||||||
"editor.defaultFormatter": "biomejs.biome",
|
}
|
||||||
"editor.codeActionsOnSave": {
|
|
||||||
"source.organizeImports.biome": "explicit"
|
|
||||||
},
|
|
||||||
"typescript.tsdk": "node_modules/typescript/lib"
|
|
||||||
}
|
|
|
@ -1,14 +1,8 @@
|
||||||
when:
|
|
||||||
event: [push]
|
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
build:
|
build:
|
||||||
image: oven/bun:${BUN_VERSION}-slim
|
image: denoland/deno:1.39.2
|
||||||
commands:
|
commands:
|
||||||
- bun install
|
- apt update
|
||||||
- bun run build
|
- apt install curl -y
|
||||||
|
- curl -fsSL https://deb.nodesource.com/setup_lts.x | bash - && apt-get install -y nodejs
|
||||||
matrix:
|
- deno task build
|
||||||
BUN_VERSION:
|
|
||||||
- 1.0.25
|
|
||||||
- 1.0.26
|
|
|
@ -1,10 +1,9 @@
|
||||||
when:
|
|
||||||
event: [push]
|
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
lint:
|
lint:
|
||||||
image: oven/bun:1.0.26-slim
|
image: denoland/deno:${DENO_VERSION}
|
||||||
commands:
|
commands:
|
||||||
- bun install
|
- deno lint
|
||||||
- bun run ci
|
|
||||||
|
|
||||||
|
matrix:
|
||||||
|
DENO_VERSION:
|
||||||
|
- 1.39.2
|
|
@ -1,19 +1,14 @@
|
||||||
when:
|
|
||||||
event: [push]
|
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
test:
|
test:
|
||||||
image: oven/bun:${BUN_VERSION}-slim
|
image: denoland/deno:${DENO_VERSION}
|
||||||
environment:
|
environment:
|
||||||
- NATS_HOST=nats:4222
|
- NATS_HOST=nats:4222
|
||||||
commands:
|
commands:
|
||||||
- bun install
|
- deno task test
|
||||||
- bun run test
|
|
||||||
|
|
||||||
matrix:
|
matrix:
|
||||||
BUN_VERSION:
|
DENO_VERSION:
|
||||||
- 1.0.25
|
- 1.39.2
|
||||||
- 1.0.26
|
|
||||||
|
|
||||||
services:
|
services:
|
||||||
nats:
|
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 {
|
export default interface Adaptor {
|
||||||
subscribe(subject: string, fn: AdaptorSubscribeTypeFn): void;
|
subscribe(subject: string, fn: AdaptorSubscribeTypeFn): void;
|
||||||
request(subject: string, req: string): Promise<string>;
|
request(subject: string, req: string): Promise<string>;
|
||||||
listen(serviceName: string): Promise<void>;
|
listen(serviceName: string): Promise<void>;
|
||||||
stop(): Promise<void>;
|
stop(): Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,57 +1,57 @@
|
||||||
|
import { AdaptorSubscribeTypeFn } from "../types.ts";
|
||||||
|
import Adaptor from "./adaptor.ts";
|
||||||
import {
|
import {
|
||||||
type Codec,
|
Codec,
|
||||||
type ConnectionOptions,
|
connect,
|
||||||
type NatsConnection,
|
ConnectionOptions,
|
||||||
StringCodec,
|
NatsConnection,
|
||||||
type Subscription,
|
StringCodec,
|
||||||
connect,
|
Subscription,
|
||||||
} from "nats";
|
} from "nats";
|
||||||
import type { AdaptorSubscribeTypeFn } from "../types.ts";
|
|
||||||
import type Adaptor from "./adaptor.ts";
|
|
||||||
|
|
||||||
export default class NatsAdaptor implements Adaptor {
|
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) {
|
constructor(options: ConnectionOptions) {
|
||||||
this.options = options;
|
this.options = options;
|
||||||
this.sc = StringCodec();
|
this.sc = StringCodec();
|
||||||
this.callbacks = {};
|
this.callbacks = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
async listen(serviceName: string) {
|
async listen(serviceName: string) {
|
||||||
this.nc = await connect(this.options);
|
this.nc = await connect(this.options);
|
||||||
|
|
||||||
this.sub = this.nc.subscribe(`${serviceName}.*`);
|
this.sub = this.nc.subscribe(`${serviceName}.*`);
|
||||||
(async (sub: Subscription) => {
|
(async (sub: Subscription) => {
|
||||||
for await (const msg of sub) {
|
for await (const msg of sub) {
|
||||||
const res = await this.callbacks[msg.subject](this.sc.decode(msg.data));
|
const res = await this.callbacks[msg.subject](this.sc.decode(msg.data));
|
||||||
msg.respond(this.sc.encode(res));
|
msg.respond(this.sc.encode(res));
|
||||||
}
|
}
|
||||||
})(this.sub);
|
})(this.sub);
|
||||||
}
|
}
|
||||||
|
|
||||||
subscribe(subject: string, fn: AdaptorSubscribeTypeFn) {
|
subscribe(subject: string, fn: AdaptorSubscribeTypeFn) {
|
||||||
this.callbacks[subject] = fn;
|
this.callbacks[subject] = fn;
|
||||||
}
|
}
|
||||||
|
|
||||||
async request(subject: string, req: string): Promise<string> {
|
async request(subject: string, req: string): Promise<string> {
|
||||||
if (this.nc) {
|
if (this.nc) {
|
||||||
const msg = await this.nc.request(subject, this.sc.encode(req));
|
const msg = await this.nc.request(subject, this.sc.encode(req));
|
||||||
return this.sc.decode(msg.data);
|
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> {
|
async stop(): Promise<void> {
|
||||||
await this.nc?.drain();
|
await this.nc?.drain();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
10
src/error.ts
10
src/error.ts
|
@ -1,9 +1,9 @@
|
||||||
export class RequestError extends Error {
|
export class RequestError extends Error {
|
||||||
public statusCode: number;
|
public statusCode: number;
|
||||||
|
|
||||||
constructor(msg: string, statusCode: number) {
|
constructor(msg: string, statusCode: number) {
|
||||||
super(msg);
|
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";
|
import { z } from "zod";
|
||||||
|
|
||||||
export interface Request<T> {
|
export interface Request<T> {
|
||||||
service: string;
|
service: string;
|
||||||
subject: string;
|
subject: string;
|
||||||
data?: T;
|
data?: T;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const InternalRequestSchema = z.object({
|
export const InternalRequestSchema = z.object({
|
||||||
from: z.string(),
|
from: z.string(),
|
||||||
data: z.optional(z.any()),
|
data: z.optional(z.any()),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const InternalResponseSchema = z.object({
|
export const InternalResponseSchema = z.object({
|
||||||
data: z.optional(z.any()),
|
data: z.optional(z.any()),
|
||||||
statusCode: z.number(),
|
statusCode: z.number(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export type InternalRequest = z.infer<typeof InternalRequestSchema>;
|
export type InternalRequest = z.infer<typeof InternalRequestSchema>;
|
||||||
export type InternalResponse = z.infer<typeof InternalResponseSchema>;
|
export type InternalResponse = z.infer<typeof InternalResponseSchema>;
|
||||||
|
|
||||||
export interface Response<T> {
|
export interface Response<T> {
|
||||||
data?: T;
|
data?: T;
|
||||||
statusCode: number;
|
statusCode: number;
|
||||||
}
|
}
|
||||||
|
|
280
src/service.ts
280
src/service.ts
|
@ -1,156 +1,166 @@
|
||||||
import { z } from "zod";
|
import Adaptor from "./adaptors/adaptor.ts";
|
||||||
import type Adaptor from "./adaptors/adaptor";
|
import { RequestError } from "./error.ts";
|
||||||
import { RequestError } from "./error";
|
|
||||||
import {
|
import {
|
||||||
type InternalRequest,
|
InternalRequest,
|
||||||
InternalRequestSchema,
|
InternalRequestSchema,
|
||||||
type InternalResponse,
|
InternalResponse,
|
||||||
InternalResponseSchema,
|
InternalResponseSchema,
|
||||||
type Request,
|
Request,
|
||||||
type Response,
|
Response,
|
||||||
} from "./messages";
|
} from "./messages.ts";
|
||||||
import type { RouteSubscribeTypeFn } from "./types";
|
import { RouteSubscribeTypeFn } from "./types.ts";
|
||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
export default class Service {
|
export default class Service {
|
||||||
private name: string;
|
private name: string;
|
||||||
|
|
||||||
private adaptors: Record<string, Adaptor>;
|
private adaptors: Record<string, Adaptor>;
|
||||||
|
|
||||||
constructor(name: string) {
|
constructor(name: string) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.adaptors = {};
|
this.adaptors = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
public addAdaptor(name: string, adaptor: Adaptor) {
|
public addAdaptor(name: string, adaptor: Adaptor) {
|
||||||
this.adaptors[name] = adaptor;
|
this.adaptors[name] = adaptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
public subscribe<T extends z.ZodType<O>, O, U>(
|
public subscribe<T extends z.ZodType<O>, O, U>(
|
||||||
adaptor: string,
|
adaptor: string,
|
||||||
subject: string,
|
subject: string,
|
||||||
fn: RouteSubscribeTypeFn<z.infer<T>, U>,
|
fn: RouteSubscribeTypeFn<z.infer<T>, U>,
|
||||||
schema: T | undefined = undefined,
|
schema: T | undefined = undefined,
|
||||||
) {
|
) {
|
||||||
this.adaptors[adaptor].subscribe(
|
this.adaptors[adaptor].subscribe(
|
||||||
`${this.name}.${subject}`,
|
`${this.name}.${subject}`,
|
||||||
async (rawReq) => {
|
async (rawReq) => {
|
||||||
const rawReqJson = JSON.parse(rawReq);
|
const rawReqJson = JSON.parse(rawReq);
|
||||||
const internalRequestJson = InternalRequestSchema.safeParse(rawReqJson);
|
const internalRequestJson = InternalRequestSchema.safeParse(rawReqJson);
|
||||||
if (!internalRequestJson.success) {
|
if (!internalRequestJson.success) {
|
||||||
return JSON.stringify({
|
return JSON.stringify(
|
||||||
statusCode: 400,
|
{
|
||||||
data: "bad request structure",
|
statusCode: 400,
|
||||||
} satisfies InternalResponse);
|
data: "bad request structure",
|
||||||
}
|
} satisfies InternalResponse,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const internalRequest = internalRequestJson.data;
|
const internalRequest = internalRequestJson.data;
|
||||||
const req = {
|
const req = {
|
||||||
service: internalRequest.from,
|
service: internalRequest.from,
|
||||||
subject: subject,
|
subject: subject,
|
||||||
} as Request<z.infer<T>>;
|
} as Request<z.infer<T>>;
|
||||||
|
|
||||||
if (internalRequest.data && schema) {
|
if (internalRequest.data && schema) {
|
||||||
const validate = schema.safeParse(internalRequest.data);
|
const validate = schema.safeParse(internalRequest.data);
|
||||||
if (!validate.success) {
|
if (!validate.success) {
|
||||||
return JSON.stringify({
|
return JSON.stringify(
|
||||||
statusCode: 400,
|
{
|
||||||
data: validate.error,
|
statusCode: 400,
|
||||||
} satisfies InternalResponse);
|
data: validate.error,
|
||||||
}
|
} satisfies InternalResponse,
|
||||||
req.data = validate.data;
|
);
|
||||||
}
|
} else {
|
||||||
|
req.data = validate.data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const res = await fn(req);
|
const res = await fn(req);
|
||||||
const internalResponse = {
|
const internalResponse = {
|
||||||
statusCode: res.statusCode,
|
statusCode: res.statusCode,
|
||||||
data: res.data,
|
data: res.data,
|
||||||
} satisfies InternalResponse;
|
} satisfies InternalResponse;
|
||||||
|
|
||||||
return JSON.stringify(internalResponse);
|
return JSON.stringify(internalResponse);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (err instanceof RequestError) {
|
if (err instanceof RequestError) {
|
||||||
return JSON.stringify({
|
return JSON.stringify(
|
||||||
statusCode: err.statusCode,
|
{
|
||||||
data: err.message,
|
statusCode: err.statusCode,
|
||||||
} satisfies InternalResponse);
|
data: err.message,
|
||||||
}
|
} satisfies InternalResponse,
|
||||||
return JSON.stringify({
|
);
|
||||||
statusCode: 500,
|
} else {
|
||||||
data: "unknow error apend",
|
return JSON.stringify(
|
||||||
} satisfies InternalResponse);
|
{
|
||||||
}
|
statusCode: 500,
|
||||||
},
|
data: err?.message || "unknow error apend",
|
||||||
);
|
} satisfies InternalResponse,
|
||||||
}
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public async request<T, O, U extends z.ZodType<O>>(
|
public async request<T, O, U extends z.ZodType<O>>(
|
||||||
adaptor: string,
|
adaptor: string,
|
||||||
req: Request<T>,
|
req: Request<T>,
|
||||||
schema?: z.ZodType<O>,
|
schema?: z.ZodType<O>,
|
||||||
): Promise<Response<z.infer<U>>> {
|
): Promise<Response<z.infer<U>>> {
|
||||||
if (!this.adaptors[adaptor]) {
|
if (!this.adaptors[adaptor]) {
|
||||||
throw new Error(`${adaptor} adaptor not exist`);
|
throw new Error(`${adaptor} adaptor not exist`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const internalRequest = {
|
const internalRequest = {
|
||||||
from: this.name,
|
from: this.name,
|
||||||
data: req.data,
|
data: req.data,
|
||||||
} satisfies InternalRequest;
|
} satisfies InternalRequest;
|
||||||
const internalRequestJson = JSON.stringify(internalRequest);
|
const internalRequestJson = JSON.stringify(internalRequest);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const rawRes = await this.adaptors[adaptor].request(
|
const rawRes = await this.adaptors[adaptor].request(
|
||||||
`${req.service}.${req.subject}`,
|
`${req.service}.${req.subject}`,
|
||||||
internalRequestJson,
|
internalRequestJson,
|
||||||
);
|
);
|
||||||
const rawResJson: unknown = JSON.parse(rawRes);
|
const rawResJson: unknown = JSON.parse(rawRes);
|
||||||
const internalResponseJson = InternalResponseSchema.safeParse(rawResJson);
|
const internalResponseJson = InternalResponseSchema.safeParse(rawResJson);
|
||||||
if (!internalResponseJson.success) {
|
if (!internalResponseJson.success) {
|
||||||
throw new RequestError(internalResponseJson.error.toString(), 500);
|
throw new RequestError(internalResponseJson.error.toString(), 500);
|
||||||
}
|
}
|
||||||
|
|
||||||
const internalResponse = internalResponseJson.data;
|
const internalResponse = internalResponseJson.data;
|
||||||
if (
|
if (
|
||||||
internalResponse.statusCode < 200 ||
|
internalResponse.statusCode < 200 || internalResponse.statusCode >= 299
|
||||||
internalResponse.statusCode >= 299
|
) {
|
||||||
) {
|
throw new RequestError(
|
||||||
throw new RequestError(
|
internalResponse.data,
|
||||||
internalResponse.data,
|
internalResponse.statusCode,
|
||||||
internalResponse.statusCode,
|
);
|
||||||
);
|
}
|
||||||
}
|
const res: Response<z.infer<U>> = {
|
||||||
const res: Response<z.infer<U>> = {
|
statusCode: internalResponse.statusCode,
|
||||||
statusCode: internalResponse.statusCode,
|
};
|
||||||
};
|
if (internalResponse.data && schema) {
|
||||||
if (internalResponse.data && schema) {
|
const validate = schema.safeParse(internalResponse.data);
|
||||||
const validate = schema.safeParse(internalResponse.data);
|
|
||||||
|
|
||||||
if (!validate.success) {
|
if (!validate.success) {
|
||||||
throw new RequestError(validate.error.message, 400);
|
throw new RequestError(validate.error.message, 400);
|
||||||
}
|
} else {
|
||||||
res.data = validate.data;
|
res.data = validate.data;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (err instanceof RequestError) {
|
if (err instanceof RequestError) {
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new RequestError("unexpected error", 500);
|
throw new RequestError("unexpected error", 500);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async listen() {
|
public async listen() {
|
||||||
for (const index in this.adaptors) {
|
for (const index in this.adaptors) {
|
||||||
await this.adaptors[index].listen(this.name);
|
await this.adaptors[index].listen(this.name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async stop() {
|
public async stop() {
|
||||||
for (const index in this.adaptors) {
|
for (const index in this.adaptors) {
|
||||||
await this.adaptors[index].stop();
|
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 AdaptorSubscribeTypeFn = (msg: string) => Promise<string>;
|
||||||
export type RouteSubscribeTypeFn<T, U> = (
|
export type RouteSubscribeTypeFn<T, U> = (
|
||||||
msg: Request<T>,
|
msg: Request<T>,
|
||||||
) => Promise<Response<U>>;
|
) => Promise<Response<U>>;
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
import { expect, test } from "bun:test";
|
import { RequestError } from "../src/error.ts";
|
||||||
import { RequestError } from "../src/error";
|
import { assertEquals } from "std/assert/mod.ts";
|
||||||
|
|
||||||
test("request error", () => {
|
Deno.test("request error", () => {
|
||||||
const expectedMsg = "This is my err";
|
const expectedMsg = "This is my err";
|
||||||
const expectedStatusCode = 500;
|
const expectedStatusCode = 500;
|
||||||
|
|
||||||
const err = new RequestError(expectedMsg, expectedStatusCode);
|
const err = new RequestError(expectedMsg, expectedStatusCode);
|
||||||
|
|
||||||
expect(err.message).toBe(expectedMsg);
|
assertEquals(err.message, expectedMsg);
|
||||||
expect(err.statusCode).toBe(expectedStatusCode);
|
assertEquals(err.statusCode, expectedStatusCode);
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,97 +1,92 @@
|
||||||
import { afterEach, beforeEach, expect, test } from "bun:test";
|
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import NatsAdaptor from "../src/adaptors/nats";
|
import NatsAdaptor from "../src/adaptors/nats.ts";
|
||||||
import { RequestError } from "../src/error";
|
import Service from "../src/service.ts";
|
||||||
import Service from "../src/service";
|
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;
|
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 serviceName = "test-service";
|
||||||
const adaptorName = "nats";
|
const adaptorName = "nats";
|
||||||
const subject = "test";
|
const subject = "test";
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
srv = new Service(serviceName);
|
srv = new Service(serviceName);
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(async () => {
|
afterEach(async () => {
|
||||||
await srv.stop();
|
await srv.stop();
|
||||||
});
|
});
|
||||||
|
|
||||||
test("request success", async () => {
|
it("request success", {
|
||||||
const dataExpected = "hello success";
|
sanitizeExit: false,
|
||||||
const statusCodeExpected = 200;
|
sanitizeOps: false,
|
||||||
|
sanitizeResources: false,
|
||||||
|
}, async () => {
|
||||||
|
const dataExpected = "hello success";
|
||||||
|
const statusCodeExpected = 200;
|
||||||
|
|
||||||
srv.addAdaptor(adaptorName, new NatsAdaptor({ servers: [natsServer] }));
|
srv.addAdaptor(adaptorName, new NatsAdaptor({ servers: [natsServer] }));
|
||||||
srv.subscribe(
|
srv.subscribe(adaptorName, subject, async (msg) => {
|
||||||
adaptorName,
|
return { data: msg.data, statusCode: statusCodeExpected };
|
||||||
subject,
|
}, z.string());
|
||||||
async (msg) => {
|
|
||||||
return { data: msg.data, statusCode: statusCodeExpected };
|
|
||||||
},
|
|
||||||
z.string(),
|
|
||||||
);
|
|
||||||
|
|
||||||
await srv.listen();
|
await srv.listen();
|
||||||
|
|
||||||
const res = await srv.request(
|
const res = await srv.request(adaptorName, {
|
||||||
adaptorName,
|
service: serviceName,
|
||||||
{
|
subject: subject,
|
||||||
service: serviceName,
|
data: dataExpected,
|
||||||
subject: subject,
|
}, z.string());
|
||||||
data: dataExpected,
|
|
||||||
},
|
|
||||||
z.string(),
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(res.data).toBe(dataExpected);
|
assertEquals(res.data, dataExpected);
|
||||||
expect(res.statusCode).toBe(statusCodeExpected);
|
assertEquals(res.statusCode, statusCodeExpected);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("request error", async () => {
|
it("request error", {
|
||||||
const dataExpected = "hello error";
|
sanitizeExit: false,
|
||||||
const statusCodeExpected = 500;
|
sanitizeOps: false,
|
||||||
|
sanitizeResources: false,
|
||||||
|
}, async () => {
|
||||||
|
const dataExpected = "hello error";
|
||||||
|
const statusCodeExpected = 500;
|
||||||
|
|
||||||
srv.addAdaptor(adaptorName, new NatsAdaptor({ servers: [natsServer] }));
|
srv.addAdaptor(adaptorName, new NatsAdaptor({ servers: [natsServer] }));
|
||||||
srv.subscribe(
|
srv.subscribe(adaptorName, subject, async (msg) => {
|
||||||
adaptorName,
|
throw new RequestError("request error", 500);
|
||||||
subject,
|
}, z.string());
|
||||||
async (msg) => {
|
|
||||||
throw new RequestError("request error", 500);
|
|
||||||
},
|
|
||||||
z.string(),
|
|
||||||
);
|
|
||||||
|
|
||||||
await srv.listen();
|
await srv.listen();
|
||||||
expect(() => {
|
assertRejects(() => {
|
||||||
return srv.request(
|
return srv.request(adaptorName, {
|
||||||
adaptorName,
|
service: serviceName,
|
||||||
{
|
subject: subject,
|
||||||
service: serviceName,
|
data: dataExpected,
|
||||||
subject: subject,
|
}, z.string());
|
||||||
data: dataExpected,
|
});
|
||||||
},
|
|
||||||
z.string(),
|
|
||||||
);
|
|
||||||
}).toThrow();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test("request adaptor not found", async () => {
|
it("request adaptor not found", {
|
||||||
const dataExpected = "hello success";
|
sanitizeExit: false,
|
||||||
const statusCodeExpected = 200;
|
sanitizeOps: false,
|
||||||
|
sanitizeResources: false,
|
||||||
|
}, async () => {
|
||||||
|
const dataExpected = "hello success";
|
||||||
|
const statusCodeExpected = 200;
|
||||||
|
|
||||||
srv.addAdaptor(adaptorName, new NatsAdaptor({ servers: [natsServer] }));
|
srv.addAdaptor(adaptorName, new NatsAdaptor({ servers: [natsServer] }));
|
||||||
srv.subscribe(adaptorName, subject, async (msg) => {
|
srv.subscribe(adaptorName, subject, async (msg) => {
|
||||||
return { data: msg.data, statusCode: statusCodeExpected };
|
return { data: msg.data, statusCode: statusCodeExpected };
|
||||||
});
|
});
|
||||||
|
|
||||||
await srv.listen();
|
await srv.listen();
|
||||||
expect(() => {
|
assertRejects(() => {
|
||||||
return srv.request("bad adaptor", {
|
return srv.request("bad adaptor", {
|
||||||
service: serviceName,
|
service: serviceName,
|
||||||
subject: subject,
|
subject: subject,
|
||||||
data: dataExpected,
|
data: dataExpected,
|
||||||
});
|
});
|
||||||
}).toThrow();
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -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