├── .editorconfig ├── .gitattributes ├── .github └── FUNDING.yml ├── .gitignore ├── .vscode └── settings.json ├── LICENSE ├── MONOREPO.md ├── README.md ├── SECURITY.md ├── docker ├── .dockerignore ├── .rsyncignore ├── Dockerfile ├── README.md ├── docker-compose.yml └── package.json ├── eslint.config.js ├── examples ├── basic-auth │ ├── .env.sample │ ├── .htpasswd │ ├── index.ts │ └── package.json ├── bin │ ├── package.json │ ├── public │ │ └── index.html │ └── src │ │ ├── main.ts │ │ └── module.ts ├── email │ ├── .env │ ├── index.ts │ └── package.json ├── minimal │ ├── .env │ ├── README.md │ ├── index.js │ └── package.json ├── oauth2 │ ├── index.ts │ └── package.json ├── openapi │ ├── index.ts │ ├── openapi.yaml │ ├── package.json │ └── shim.d.ts ├── plausible │ ├── .env │ ├── index.ts │ └── package.json ├── rpc │ ├── index.html │ ├── package.json │ ├── public │ │ └── icon.png │ ├── service.ts │ ├── src │ │ ├── App.vue │ │ ├── AppMessages.vue │ │ ├── _types.ts │ │ ├── hub.ts │ │ ├── main.ts │ │ └── shim.d.ts │ └── vite.config.ts ├── sandbox │ ├── README.md │ ├── main.ts │ └── package.json ├── vite-pwa │ ├── README.md │ ├── index.html │ ├── package.json │ ├── public │ │ └── favicon.ico │ ├── src │ │ ├── App.vue │ │ ├── main.ts │ │ ├── pwa.ts │ │ ├── service-worker.ts │ │ ├── shims-vue.d.ts │ │ └── zerva │ │ │ ├── index.ts │ │ │ └── module.ts │ ├── tsconfig.json │ └── vite.config.ts ├── vite-serviceworker │ ├── README.md │ ├── index.html │ ├── package.json │ ├── public │ │ ├── app.webmanifest │ │ ├── favicon.ico │ │ └── sw.js │ ├── src │ │ ├── App.vue │ │ ├── main.ts │ │ ├── pwa.ts │ │ ├── shims-vue.d.ts │ │ └── zerva │ │ │ ├── index.ts │ │ │ └── module.ts │ ├── tsconfig.json │ └── vite.config.ts ├── vite │ ├── README.md │ ├── help │ │ └── index.html │ ├── index.html │ ├── package.json │ ├── public │ │ └── favicon.ico │ ├── src │ │ ├── App.vue │ │ ├── Help.vue │ │ ├── help.ts │ │ ├── main.ts │ │ ├── shims-vue.d.ts │ │ └── zerva │ │ │ ├── index.ts │ │ │ └── module.ts │ ├── tsconfig.json │ └── vite.config.ts └── websocket │ ├── index.html │ ├── package.json │ ├── public │ └── icon.png │ ├── service.ts │ ├── src │ ├── App.vue │ ├── main.ts │ ├── protocol.ts │ └── shim.d.ts │ └── vite.config.ts ├── icon.png ├── package.json ├── pnpm-workspace.yaml ├── scripts ├── fix-package-json.js └── release.sh ├── tsconfig.json ├── tsup.config.ts ├── vitest.config.ts ├── zerva-basic-auth ├── README.md ├── package.json ├── src │ ├── auth.spec.ts │ ├── auth.ts │ ├── htpasswd-md5.spec.ts │ ├── htpasswd-md5.ts │ └── index.ts └── tsconfig.json ├── zerva-bin ├── README.md ├── demo │ ├── data.yml │ ├── shim-window.d.ts │ └── zerva.ts ├── icon.png ├── package.json ├── src │ ├── config.ts │ ├── index.ts │ ├── main.ts │ └── static.ts └── tsconfig.json ├── zerva-core ├── README.md ├── demo │ └── zerva.ts ├── package.json ├── src │ ├── config.spec.ts │ ├── config.ts │ ├── context.spec.ts │ ├── context.ts │ ├── index.ts │ ├── register.spec.ts │ ├── register.ts │ ├── serve.spec.ts │ ├── serve.ts │ └── types.ts └── tsconfig.json ├── zerva-email ├── README.md ├── package.json ├── src │ ├── index.ts │ ├── module.ts │ └── types.ts └── tsconfig.json ├── zerva-http-log ├── README.md ├── package.json ├── src │ └── index.ts └── tsconfig.json ├── zerva-http ├── README.md ├── demo │ └── zerva.ts ├── package.json ├── src │ ├── accepts.ts │ ├── compression.ts │ ├── http.spec.ts │ ├── http.ts │ ├── index.ts │ ├── status.ts │ └── types.ts └── tsconfig.json ├── zerva-mqtt ├── README.md ├── package.json ├── src │ ├── _types_homeassistant.ts │ ├── homeassistant.spec.ts │ ├── homeassistant.ts │ ├── index.ts │ └── module.ts └── tsconfig.json ├── zerva-openapi ├── README.md ├── package.json ├── src │ ├── index.ts │ ├── module.ts │ ├── static │ │ ├── index.css.txt │ │ ├── oauth2-redirect.html │ │ ├── swagger-initializer.js.txt │ │ ├── swagger-ui-bundle.js.txt │ │ ├── swagger-ui-es-bundle-core.js.txt │ │ ├── swagger-ui-es-bundle.js.txt │ │ ├── swagger-ui-standalone-preset.js.txt │ │ ├── swagger-ui.css.txt │ │ └── swagger-ui.js.txt │ └── types.ts └── tsconfig.json ├── zerva-plausible ├── README.md ├── package.json ├── src │ ├── index.ts │ ├── module.ts │ ├── track-plausible.ts │ └── types.ts └── tsconfig.json ├── zerva-rpc ├── README.md ├── package.json ├── src │ ├── _types.ts │ ├── channel-resilient.ts │ ├── client.ts │ ├── index.browser.ts │ ├── index.ts │ ├── rpc-hub.ts │ ├── server.spec.ts │ └── server.ts └── tsconfig.json ├── zerva-sqlite-bun ├── README.md ├── bun.lock ├── package.json ├── src │ ├── database.ts │ ├── index.spec.ts │ ├── index.ts │ └── table.ts └── tsconfig.json ├── zerva-sqlite ├── README.md ├── package.json ├── src │ ├── _types.ts │ ├── database.ts │ ├── drawdb │ │ ├── README.md │ │ ├── _tmp │ │ │ ├── rpc-setup.ts │ │ │ ├── rpc-types.ts │ │ │ ├── setup.ts │ │ │ └── types.ts │ │ ├── _types.spec.ts │ │ ├── _types.ts │ │ ├── create-rpc-setup.ts │ │ ├── create-rpc-types.ts │ │ ├── create-setup.ts │ │ ├── create-types.ts │ │ ├── create.spec.ts │ │ ├── create.ts │ │ └── demo.json │ ├── index.spec.ts │ ├── index.ts │ ├── sqlite.ts │ ├── table-schema.spec.ts │ ├── table-schema.ts │ └── table.ts └── tsconfig.json ├── zerva-vite ├── README.md ├── demo │ └── zerva.ts ├── package.json ├── src │ ├── index.ts │ ├── module.ts │ ├── multi.ts │ └── types.ts └── tsconfig.json └── zerva-websocket ├── README.md ├── demo └── zerva.ts ├── package.json ├── src ├── _server.ts ├── _types.ts ├── client-ng.ts ├── client.spec.ts ├── client.ts ├── index.browser.ts ├── index.ts ├── server.spec.ts ├── server.ts ├── singleton.spec.ts ├── singleton.ts └── use.ts └── tsconfig.json /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: http://EditorConfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | end_of_line = lf 7 | charset = utf-8 8 | insert_final_newline = true 9 | max_line_length = 80 10 | trim_trailing_whitespace = true 11 | indent_style = space 12 | indent_size = 2 13 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Don't allow people to merge changes to these generated files, because the result 2 | # may be invalid. You need to run "rush update" again. 3 | pnpm-lock.yaml merge=binary 4 | shrinkwrap.yaml merge=binary 5 | npm-shrinkwrap.json merge=binary 6 | yarn.lock merge=binary 7 | 8 | # Rush's JSON config files use JavaScript-style code comments. The rule below prevents pedantic 9 | # syntax highlighters such as GitHub's from highlighting these comments as errors. Your text editor 10 | # may also require a special configuration to allow comments in JSON. 11 | # 12 | # For more information, see this issue: https://github.com/microsoft/rushstack/issues/1088 13 | # 14 | *.json linguist-language=JSON-with-Comments 15 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [holtwick] 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | *.log 3 | npm-debug.log* 4 | yarn-debug.log* 5 | yarn-error.log* 6 | 7 | # Runtime data 8 | *.pid 9 | *.seed 10 | *.pid.lock 11 | 12 | # Directory for instrumented libs generated by jscoverage/JSCover 13 | lib-cov 14 | 15 | # Coverage directory used by tools like istanbul 16 | coverage 17 | 18 | # nyc test coverage 19 | .nyc_output 20 | 21 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 22 | .grunt 23 | 24 | # Bower dependency directory (https://bower.io/) 25 | bower_components 26 | 27 | # node-waf configuration 28 | .lock-wscript 29 | 30 | # Compiled binary addons (https://nodejs.org/api/addons.html) 31 | build/Release 32 | 33 | # Dependency directories 34 | node_modules/ 35 | jspm_packages/ 36 | 37 | # Optional npm cache directory 38 | .npm 39 | 40 | # Optional eslint cache 41 | .eslintcache 42 | 43 | # Optional REPL history 44 | .node_repl_history 45 | 46 | # Output of 'npm pack' 47 | *.tgz 48 | 49 | # Yarn Integrity file 50 | .yarn-integrity 51 | 52 | # dotenv environment variables file 53 | .env.local 54 | 55 | # next.js build output 56 | .next 57 | 58 | # OS X temporary files 59 | .DS_Store 60 | 61 | # Rush temporary files 62 | common/deploy/ 63 | common/temp/ 64 | common/autoinstallers/*/.npmrc 65 | **/.rush/temp/ 66 | 67 | # Heft 68 | .heft 69 | 70 | # 71 | 72 | node_modules 73 | .pnpm* 74 | dist 75 | tmp 76 | *.log 77 | .out* 78 | *.local 79 | 80 | .npmrc 81 | 82 | pnpm-lock.yaml 83 | package-lock.json 84 | 85 | dist_www 86 | 87 | *.rest 88 | *.node 89 | 90 | .npmrc* 91 | 92 | *.sqlite 93 | *.sqlite-* 94 | 95 | zerva-bin/bin.?js 96 | 97 | bun.lockb 98 | 99 | _archive -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | // Enable the ESlint flat config support 3 | "eslint.experimental.useFlatConfig": true, 4 | 5 | // Disable the default formatter, use eslint instead 6 | "prettier.enable": false, 7 | "editor.formatOnSave": false, 8 | 9 | // Auto fix 10 | "editor.codeActionsOnSave": { 11 | "source.fixAll.eslint": "explicit", 12 | "source.organizeImports": "never" 13 | }, 14 | 15 | // Silent the stylistic rules in you IDE, but still auto fix them 16 | "eslint.rules.customizations": [ 17 | { "rule": "style/*", "severity": "off" }, 18 | { "rule": "format/*", "severity": "off" }, 19 | { "rule": "*-indent", "severity": "off" }, 20 | { "rule": "*-spacing", "severity": "off" }, 21 | { "rule": "*-spaces", "severity": "off" }, 22 | { "rule": "*-order", "severity": "off" }, 23 | { "rule": "*-dangle", "severity": "off" }, 24 | { "rule": "*-newline", "severity": "off" }, 25 | { "rule": "*quotes", "severity": "off" }, 26 | { "rule": "*semi", "severity": "off" } 27 | ], 28 | 29 | // Enable eslint for all supported languages 30 | "eslint.validate": [ 31 | "javascript", 32 | "javascriptreact", 33 | "typescript", 34 | "typescriptreact", 35 | "vue", 36 | "html", 37 | "markdown", 38 | "json", 39 | "jsonc", 40 | "yaml", 41 | "toml", 42 | "gql", 43 | "graphql" 44 | ], 45 | 46 | "vitest.commandLine": "pnpm exec vitest", 47 | "vitest.enable": true, 48 | "vitest.exclude": [ 49 | "**/_archive/**", 50 | "**/node_modules/**", 51 | "**/dist/**", 52 | "**/cypress/**", 53 | "**/.{idea,git,cache,output,temp}/**" 54 | ], 55 | 56 | "github.copilot.enable": { 57 | "*": true, 58 | "plaintext": false, 59 | "markdown": false, 60 | "scminput": false 61 | }, 62 | "vitest.disableWorkspaceWarning": true 63 | } 64 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021-2024 Dirk Holtwick 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /MONOREPO.md: -------------------------------------------------------------------------------- 1 | # Monorepo Hints 2 | 3 | Uses PNPM: 4 | https://pnpm.io/workspaces#link-workspace-packages 5 | 6 | Inspiration for actual use see vitest setup: 7 | https://github.com/vitest-dev/vitest/blob/main/package.json#L21 8 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Reporting a Vulnerability 4 | 5 | Please report security issues to `dirk.holtwick@gmail.com`. 6 | -------------------------------------------------------------------------------- /docker/.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | pnpm* 3 | .pnpm* 4 | *.log 5 | .out* 6 | *.local 7 | .env 8 | .env.local 9 | Dockerfile-* 10 | *.md 11 | dist 12 | tmp 13 | data 14 | www -------------------------------------------------------------------------------- /docker/.rsyncignore: -------------------------------------------------------------------------------- 1 | + package.json 2 | + .dockerignore 3 | + Dockerfile 4 | + docker-compose.yml 5 | + dist 6 | + dist/** 7 | + data 8 | + data/** 9 | + www 10 | + www/** 11 | - * -------------------------------------------------------------------------------- /docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node 2 | COPY package.json /app/package.json 3 | RUN cd /app; npm install --production 4 | WORKDIR /app 5 | CMD ["node", "dist/main.mjs"] 6 | EXPOSE 8080 7 | -------------------------------------------------------------------------------- /docker/README.md: -------------------------------------------------------------------------------- 1 | # 🌱 Zerva Docker 2 | 3 | **Sample project for Docker setup** 4 | 5 | ### `package.json` 6 | -------------------------------------------------------------------------------- /docker/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | services: 4 | zerva: # set your preferred name here 5 | build: . 6 | restart: always 7 | volumes: 8 | - ./dist:/app/dist 9 | - ./www:/app/www 10 | - ./data:/app/data 11 | environment: 12 | - NODE_MODE:production 13 | - LOG:/app/data/zerva.log 14 | - ZEED:* 15 | 16 | networks: 17 | default: 18 | external: 19 | name: proxy 20 | -------------------------------------------------------------------------------- /docker/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@zerva/docker", 3 | "type": "module", 4 | "version": "0.7.13", 5 | "private": true, 6 | "scripts": { 7 | "build": "zerva build", 8 | "serve": "node dist/main.mjs", 9 | "start": "LEVEL=a zerva", 10 | "upload": "npm run build && rsync -rvz --exclude-from=.rsyncignore * my-docker-server:zerva-docker" 11 | }, 12 | "dependencies": {}, 13 | "devDependencies": {} 14 | } 15 | -------------------------------------------------------------------------------- /eslint.config.js: -------------------------------------------------------------------------------- 1 | import antfu from '@antfu/eslint-config' 2 | import { eslintIgnoreDefaults, eslintRulesDefaults } from 'zeed' 3 | 4 | export default antfu( 5 | { 6 | typescript: true, 7 | vue: true, 8 | 9 | regexp: false, 10 | 11 | ignores: [ 12 | ...eslintIgnoreDefaults(), 13 | '*.md', 14 | '**/*.md/**', 15 | '**/*.md', 16 | '_archive', 17 | '**/_archive/**', 18 | '.*', 19 | '**/.*/**', 20 | '*.json', 21 | '**/*.json/**', 22 | '*.local', 23 | '**/*.local/**', 24 | '*.log', 25 | '**/*.log/**', 26 | '*.wasm.js', 27 | '**/*.wasm.js/**', 28 | '*.mjs', 29 | '**/*.mjs/**', 30 | '*.cjs', 31 | '**/*.cjs/**', 32 | 'bg.jpg', 33 | '**/bg.jpg/**', 34 | 'build', 35 | '**/build/**', 36 | 'coverage', 37 | '**/coverage/**', 38 | 'data', 39 | '**/data/**', 40 | 'dist', 41 | '**/dist/**', 42 | 'dist_*', 43 | '**/dist_*/**', 44 | 'docker', 45 | '**/docker/**', 46 | 'geoip', 47 | '**/geoip/**', 48 | 'help', 49 | '**/help/**', 50 | 'internal', 51 | '**/internal/**', 52 | 'legacy', 53 | '**/legacy/**', 54 | 'logs', 55 | '**/logs/**', 56 | 'node_modules', 57 | '**/node_modules/**', 58 | 'npm-debug.log', 59 | '**/npm-debug.log/**', 60 | 'package-lock.json', 61 | '**/package-lock.json/**', 62 | 'pnpm-lock.yaml', 63 | '**/pnpm-lock.yaml/**', 64 | 'public', 65 | '**/public/**', 66 | 'scripts', 67 | '**/scripts/**', 68 | 'tmp', 69 | '**/tmp/**', 70 | 'video', 71 | '**/video/**', 72 | 'wiki', 73 | '**/wiki/**', 74 | 'www', 75 | '**/www/**', 76 | 'yarn-error.log', 77 | '**/yarn-error.log/**', 78 | 'vite.config.ts', 79 | '**/vite.config.ts/**', 80 | 'vitest*', 81 | '**/vitest*/**', 82 | 'zerva-vite/ssr-vue/*', 83 | 'zerva-vite/ssr-vue/*/**', 84 | 'examples/vite-ssr/*', 85 | 'examples/vite-ssr/*/**', 86 | '**/.out.*', 87 | '.out.*', 88 | ], 89 | }, 90 | {}, 91 | { 92 | rules: { 93 | ...eslintRulesDefaults(), 94 | 'regexp/*': 'off', 95 | 'regexp/confusing-quantifier': 'off', 96 | 'antfu/consistent-list-newline': 'off', 97 | 'eslint-disable-unused-imports/no-unused-imports': 'off', 98 | }, 99 | }, 100 | ) 101 | -------------------------------------------------------------------------------- /examples/basic-auth/.env.sample: -------------------------------------------------------------------------------- 1 | # 2 | # Module: http 3 | # 4 | 5 | HTTP_LOG= 6 | 7 | # Host to bind the server to 8 | HTTP_HOST= 9 | 10 | # Port to listen on 11 | HTTP_PORT=8080 12 | 13 | # Path to SSL certificate 14 | HTTP_SSL_CRT= 15 | 16 | # Path to SSL key 17 | HTTP_SSL_KEY= 18 | 19 | # Print server details to console 20 | HTTP_SHOW_SERVER_INFO=true 21 | 22 | # None of the following middlewares is installed, just plain express. Add your own at httpInit 23 | HTTP_NO_EXTRAS=false 24 | 25 | # Enable CORS middleware https://github.com/expressjs/cors 26 | HTTP_CORS=true 27 | 28 | # Security setting https://helmetjs.github.io/ 29 | HTTP_HELMET=true 30 | 31 | # Compress content 32 | HTTP_COMPRESSION=true 33 | 34 | # Trust proxy setting https://stackoverflow.com/a/46475726/140927 35 | HTTP_TRUST_PROXY=true 36 | 37 | # Express post body size limit https://expressjs.com/en/api.html#express 38 | HTTP_POST_LIMIT=1gb 39 | 40 | # application/json -> object 41 | HTTP_POST_JSON=true 42 | 43 | # text/plain -> string 44 | HTTP_POST_TEXT=true 45 | 46 | # application/octet-stream -> Buffer and application/* except json and urlencoded 47 | HTTP_POST_BINARY=true 48 | 49 | # application/x-www-form-urlencoded 50 | HTTP_POST_URL_ENCODED=true 51 | 52 | # Open a browser 53 | HTTP_OPEN_BROWSER=false 54 | 55 | # 56 | # Module: basic-auth 57 | # 58 | 59 | BASIC-AUTH_LOGOUT= 60 | 61 | BASIC-AUTH_REALM=default 62 | 63 | BASIC-AUTH_WAIT_SECONDS_BETWEEN_AUTHORIZATION=1 64 | -------------------------------------------------------------------------------- /examples/basic-auth/.htpasswd: -------------------------------------------------------------------------------- 1 | test:$apr1$VOKVO5UU$/S8G0W5sk5YfBicxqfyqt1 2 | -------------------------------------------------------------------------------- /examples/basic-auth/index.ts: -------------------------------------------------------------------------------- 1 | // Simple demo for node and CommonJS loading 2 | 3 | import type { LoggerInterface } from 'zeed' 4 | import { readFileSync } from 'node:fs' 5 | import { useBasicAuth, useHtpasswd } from '@zerva/basic-auth' 6 | import { on, serve } from '@zerva/core' 7 | import { useHttp } from '@zerva/http' 8 | import { Logger, writeText } from 'zeed' 9 | import { dumpConfig } from '../../zerva-core/src/config' 10 | 11 | const log: LoggerInterface = Logger('basic-auth') 12 | 13 | log('start') 14 | 15 | useHttp() 16 | 17 | const { validate } = useHtpasswd(readFileSync('.htpasswd', 'utf8')) 18 | 19 | useBasicAuth({ 20 | waitSecondsBetweenAuthorization: 5, 21 | routes: ['/protected'], 22 | logout: '/logout', 23 | auth: validate, // { a: 'b' }, 24 | }) 25 | 26 | on('httpInit', ({ get }) => { 27 | get( 28 | '/', 29 | `

30 | Not protected. 31 |

32 |

33 | But this one is with test:test. 34 |

`, 35 | ) 36 | 37 | get('/protected', ({ req }) => { 38 | return `

39 | This should be protected: 40 |

41 | User: ${req.user} 42 |

43 | Logout 44 |

` 45 | }) 46 | }) 47 | 48 | void serve() 49 | 50 | writeText('.env.sample', dumpConfig()) 51 | -------------------------------------------------------------------------------- /examples/basic-auth/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "zerva-example-basic-auth", 3 | "type": "module", 4 | "version": "1.0.0", 5 | "private": true, 6 | "description": "Just a simple test", 7 | "author": { 8 | "name": "Dirk Holtwick", 9 | "email": "dirk.holtwick@gmail.com", 10 | "url": "https://holtwick.de" 11 | }, 12 | "license": "MIT", 13 | "funding": { 14 | "type": "GitHub Sponsors ❤", 15 | "url": "https://github.com/sponsors/holtwick" 16 | }, 17 | "main": "index.js", 18 | "scripts": { 19 | "reset": "rm -rf node_modules pnpm-lock.yaml dist dist_www www", 20 | "start": "ZEED=* LEVEL=a zerva index.ts" 21 | }, 22 | "dependencies": { 23 | "@zerva/basic-auth": "workspace:*", 24 | "@zerva/bin": "workspace:*", 25 | "@zerva/core": "workspace:*", 26 | "@zerva/http": "workspace:*", 27 | "zeed": "^0.28.17" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /examples/bin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "zerva-example-bin", 3 | "type": "module", 4 | "version": "1.0.0", 5 | "private": true, 6 | "description": "Just a simple test", 7 | "author": { 8 | "name": "Dirk Holtwick", 9 | "email": "dirk.holtwick@gmail.com", 10 | "url": "https://holtwick.de" 11 | }, 12 | "license": "MIT", 13 | "funding": { 14 | "type": "GitHub Sponsors ❤", 15 | "url": "https://github.com/sponsors/holtwick" 16 | }, 17 | "main": "src/main.ts", 18 | "scripts": { 19 | "build": "zerva build", 20 | "minimal": "zerva minimal", 21 | "reset": "rm -rf node_modules pnpm-lock.yaml dist dist_www www", 22 | "serve": "node --enable-source-maps dist/main.cjs", 23 | "start": "LEVEL=i ZEED=* zerva" 24 | }, 25 | "dependencies": { 26 | "zeed": "^0.28.17" 27 | }, 28 | "devDependencies": { 29 | "@zerva/bin": "workspace:*", 30 | "@zerva/core": "workspace:*", 31 | "@zerva/http": "workspace:*" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /examples/bin/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Document 7 | 8 | 9 | 10 | TEST 11 | 12 | 13 | -------------------------------------------------------------------------------- /examples/bin/src/main.ts: -------------------------------------------------------------------------------- 1 | // Simple demo for node and CommonJS loading 2 | 3 | import process from 'node:process' 4 | import { on, serve } from '@zerva/core' 5 | import { useHttp } from '@zerva/http' 6 | import { Logger, valueToInteger } from 'zeed' 7 | import { useCounter } from './module' 8 | 9 | const log = Logger('app') 10 | 11 | // console.log(process.env, ZERVA_VERSION) 12 | // log.info(loggerStackTraceDebug) 13 | log.info('Start...') 14 | 15 | // useQrCode() 16 | 17 | useHttp({ 18 | port: valueToInteger(process.env.PORT, 8080), 19 | }) 20 | 21 | on('counterIncrement', (counter) => { 22 | log.info('counter inc', counter) 23 | }) 24 | 25 | useCounter() 26 | 27 | on('httpInit', ({ addStatic }) => { 28 | addStatic('/public', 'public') 29 | }) 30 | 31 | void serve() 32 | -------------------------------------------------------------------------------- /examples/bin/src/module.ts: -------------------------------------------------------------------------------- 1 | import { emit, on, register } from '@zerva/core' 2 | import { cloneObject, Logger } from 'zeed' 3 | import '@zerva/http' 4 | 5 | const log = Logger('counter') 6 | 7 | declare global { 8 | interface ZContextEvents { 9 | counterIncrement: (counter: number) => void 10 | } 11 | } 12 | 13 | export function useCounter() { 14 | log.info('use counter') 15 | register('counter', ['http']) 16 | let counter = 0 17 | on('httpInit', ({ onGET }) => { 18 | onGET(['/', '/tick'], async () => { 19 | await emit('counterIncrement', ++counter) 20 | return `
Counter ${counter}.

Reload page to increase counter.
` 21 | }) 22 | onGET('/demo.json', async ({ req }) => { 23 | await emit('counterIncrement', ++counter) 24 | return { 25 | headers: cloneObject(req.headers), 26 | url: req.url, 27 | ip: req.ip, 28 | query: req.query, 29 | } 30 | }) 31 | onGET('/demo.txt', async () => { 32 | await emit('counterIncrement', ++counter) 33 | return `Counter ${counter}` 34 | }) 35 | }) 36 | } 37 | -------------------------------------------------------------------------------- /examples/email/.env: -------------------------------------------------------------------------------- 1 | # Use this template to create .env.local with appropriate SMTP settings 2 | 3 | EMAIL_TO = example@example.com 4 | 5 | EMAIL_HOST = example.com 6 | EMAIL_PORT = 465 7 | EMAIL_USER = user@example.com 8 | EMAIL_PASS = pasword123 9 | -------------------------------------------------------------------------------- /examples/email/index.ts: -------------------------------------------------------------------------------- 1 | import process from 'node:process' 2 | import { emit } from '@zerva/core' 3 | import { useEmail } from '@zerva/email' 4 | import { Logger, setupEnv, valueToInteger, valueToString } from 'zeed' 5 | 6 | setupEnv() 7 | 8 | const log = Logger('app') 9 | log.info('app') 10 | 11 | const transport = { 12 | host: valueToString(process.env.EMAIL_HOST), 13 | port: valueToInteger(process.env.EMAIL_PORT), 14 | secure: true, 15 | auth: { 16 | user: valueToString(process.env.EMAIL_USER), 17 | pass: valueToString(process.env.EMAIL_PASS), 18 | }, 19 | } 20 | 21 | log.info('email transport', JSON.stringify(transport, null, 2)) 22 | 23 | useEmail({ transport }) 24 | 25 | void emit('emailSend', { 26 | to: valueToString(process.env.EMAIL_TO, 'example@example.com'), 27 | }) 28 | 29 | // serve() 30 | -------------------------------------------------------------------------------- /examples/email/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "zerva-example-email", 3 | "type": "module", 4 | "version": "1.0.0", 5 | "private": true, 6 | "description": "Just a simple test", 7 | "author": { 8 | "name": "Dirk Holtwick", 9 | "email": "dirk.holtwick@gmail.com", 10 | "url": "https://holtwick.de" 11 | }, 12 | "license": "MIT", 13 | "funding": { 14 | "type": "GitHub Sponsors ❤", 15 | "url": "https://github.com/sponsors/holtwick" 16 | }, 17 | "main": "index.js", 18 | "scripts": { 19 | "reset": "rm -rf node_modules pnpm-lock.yaml dist dist_www www", 20 | "start": "zerva index.ts" 21 | }, 22 | "dependencies": { 23 | "@zerva/core": "workspace:*", 24 | "@zerva/email": "workspace:*", 25 | "zeed": "^0.28.17" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /examples/minimal/.env: -------------------------------------------------------------------------------- 1 | DEMO_SECRET=5ecre1 -------------------------------------------------------------------------------- /examples/minimal/README.md: -------------------------------------------------------------------------------- 1 | Simple demo for using Zeed as ESM in a plain node.js app. 2 | 3 | Please note that it is important to have this line in `package.json` to enable ESM support for node: 4 | 5 | ```json 6 | { "type": "module" } 7 | ``` 8 | -------------------------------------------------------------------------------- /examples/minimal/index.js: -------------------------------------------------------------------------------- 1 | // Simple demo for node and CommonJS loading 2 | 3 | import process from 'node:process' 4 | import { on, register, serve } from '@zerva/core' 5 | import { useHttp } from '@zerva/http' 6 | import { Logger, setupEnv } from 'zeed' 7 | 8 | const log = Logger('demo') 9 | 10 | setupEnv() 11 | 12 | function useCounter() { 13 | register('counter', ['http']) 14 | let counter = 1 15 | on('httpInit', ({ get }) => { 16 | get( 17 | '/', 18 | () => 19 | `
Counter ${counter++}.

Reload page to increase counter.
`, 20 | ) 21 | }) 22 | return { 23 | getCounter: () => counter, 24 | } 25 | } 26 | 27 | log('Setup zerva') 28 | log.info('DEMO_SECRET =', process.env.DEMO_SECRET) 29 | 30 | useHttp({ 31 | port: 8080, 32 | // noExtras: true, 33 | openBrowser: true, 34 | }) 35 | 36 | useCounter() 37 | 38 | serve() 39 | -------------------------------------------------------------------------------- /examples/minimal/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "zerva-example-minimal", 3 | "type": "module", 4 | "version": "1.0.0", 5 | "private": true, 6 | "description": "Just a simple test", 7 | "author": { 8 | "name": "Dirk Holtwick", 9 | "email": "dirk.holtwick@gmail.com", 10 | "url": "https://holtwick.de" 11 | }, 12 | "license": "MIT", 13 | "funding": { 14 | "type": "GitHub Sponsors ❤", 15 | "url": "https://github.com/sponsors/holtwick" 16 | }, 17 | "main": "index.js", 18 | "scripts": { 19 | "reset": "rm -rf node_modules pnpm-lock.yaml dist dist_www www", 20 | "start": "ZEED=* node index.js" 21 | }, 22 | "dependencies": { 23 | "@zerva/core": "workspace:*", 24 | "@zerva/http": "workspace:*", 25 | "zeed": "^0.28.17" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /examples/oauth2/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "zerva-example-openid", 3 | "type": "module", 4 | "version": "1.0.0", 5 | "private": true, 6 | "description": "Just a simple test", 7 | "author": { 8 | "name": "Dirk Holtwick", 9 | "email": "dirk.holtwick@gmail.com", 10 | "url": "https://holtwick.de" 11 | }, 12 | "license": "MIT", 13 | "funding": { 14 | "type": "GitHub Sponsors ❤", 15 | "url": "https://github.com/sponsors/holtwick" 16 | }, 17 | "main": "index.js", 18 | "scripts": { 19 | "reset": "rm -rf node_modules pnpm-lock.yaml dist dist_www www", 20 | "start": "ZEED=* LEVEL=a zerva index.ts" 21 | }, 22 | "dependencies": { 23 | "@types/express-session": "^1.18.1", 24 | "@zerva/bin": "workspace:*", 25 | "@zerva/core": "workspace:*", 26 | "@zerva/http": "workspace:*", 27 | "express-session": "^1.18.1", 28 | "zeed": "^0.28.17" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /examples/openapi/index.ts: -------------------------------------------------------------------------------- 1 | // Simple demo for node and CommonJS loading 2 | 3 | import { on } from '@zerva/core' 4 | import { useHttp } from '@zerva/http' 5 | import { useOpenApi } from '@zerva/openapi' 6 | import data from './openapi.yaml' 7 | 8 | useHttp() 9 | 10 | on('httpInit', ({ get }) => { 11 | get('/', '

Goto API Documentation') 12 | get('/version', { version: '1.0' }) 13 | }) 14 | 15 | useOpenApi({ 16 | path: '/api', 17 | data, 18 | }) 19 | -------------------------------------------------------------------------------- /examples/openapi/openapi.yaml: -------------------------------------------------------------------------------- 1 | openapi: 3.1.0 2 | 3 | # https://swagger.io/specification/ 4 | 5 | info: 6 | title: Test 7 | description: Description 8 | contact: 9 | email: dirk.holtwick@gmail.com 10 | version: 1.0.0 11 | paths: 12 | /version: 13 | get: 14 | summary: Just a version info 15 | responses: 16 | '200': 17 | description: Version 18 | -------------------------------------------------------------------------------- /examples/openapi/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "zerva-example-umami", 3 | "type": "module", 4 | "version": "1.0.0", 5 | "private": true, 6 | "description": "Just a simple test", 7 | "author": { 8 | "name": "Dirk Holtwick", 9 | "email": "dirk.holtwick@gmail.com", 10 | "url": "https://holtwick.de" 11 | }, 12 | "license": "MIT", 13 | "funding": { 14 | "type": "GitHub Sponsors ❤", 15 | "url": "https://github.com/sponsors/holtwick" 16 | }, 17 | "main": "index.js", 18 | "scripts": { 19 | "reset": "rm -rf node_modules pnpm-lock.yaml dist dist_www www", 20 | "start": "ZEED=* LEVEL=i zerva index.ts" 21 | }, 22 | "dependencies": { 23 | "@zerva/bin": "workspace:*", 24 | "@zerva/core": "workspace:*", 25 | "@zerva/http": "workspace:*", 26 | "@zerva/openapi": "workspace:*", 27 | "zeed": "^0.28.17" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /examples/openapi/shim.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.yaml' { 2 | const value: unknown // Add type definitions here if desired 3 | export default value 4 | } 5 | -------------------------------------------------------------------------------- /examples/plausible/.env: -------------------------------------------------------------------------------- 1 | # Sample data. Please use these to create .env.local file with your settings. 2 | 3 | PLAUSIBLE_API_EVENT_URL = https://yourPlausibleSite.com/api/event 4 | PLAUSIBLE_WEBSITE_ID = replace-me.domain 5 | -------------------------------------------------------------------------------- /examples/plausible/index.ts: -------------------------------------------------------------------------------- 1 | // Simple demo for node and CommonJS loading 2 | 3 | import process from 'node:process' 4 | import { emit, on, serve } from '@zerva/core' 5 | import { useHttp } from '@zerva/http' 6 | import { usePlausible } from '@zerva/plausible' 7 | import { Logger, setupEnv, suid, valueToInteger } from 'zeed' 8 | 9 | setupEnv() 10 | 11 | const log = Logger('app') 12 | 13 | useHttp({ 14 | port: valueToInteger(process.env.PORT, 8080), 15 | }) 16 | 17 | usePlausible({ 18 | apiEventUrl: process.env.PLAUSIBLE_API_EVENT_URL!, 19 | websiteId: process.env.PLAUSIBLE_WEBSITE_ID!, 20 | }) 21 | 22 | on('httpInit', ({ get }) => { 23 | get( 24 | '/', 25 | 'trackEvent
trackPageView', 26 | ) 27 | 28 | const event = suid() 29 | 30 | get('/trackEvent', ({ req }) => { 31 | void emit( 32 | 'trackEvent', 33 | req, 34 | 'sample', 35 | { event: 'event', os: event }, 36 | ) 37 | return event 38 | }) 39 | 40 | get('/trackPageView', ({ req }) => { 41 | void emit('trackPageView', req, `/${event}`) 42 | return event 43 | }) 44 | }) 45 | 46 | void serve() 47 | -------------------------------------------------------------------------------- /examples/plausible/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "zerva-example-plausible", 3 | "type": "module", 4 | "version": "1.0.0", 5 | "private": true, 6 | "description": "Just a simple test", 7 | "author": { 8 | "name": "Dirk Holtwick", 9 | "email": "dirk.holtwick@gmail.com", 10 | "url": "https://holtwick.de" 11 | }, 12 | "license": "MIT", 13 | "funding": { 14 | "type": "GitHub Sponsors ❤", 15 | "url": "https://github.com/sponsors/holtwick" 16 | }, 17 | "main": "index.js", 18 | "scripts": { 19 | "reset": "rm -rf node_modules pnpm-lock.yaml dist dist_www www", 20 | "start": "ZEED=* LEVEL=i zerva index.ts" 21 | }, 22 | "dependencies": { 23 | "@zerva/bin": "workspace:*", 24 | "@zerva/core": "workspace:*", 25 | "@zerva/http": "workspace:*", 26 | "@zerva/plausible": "workspace:*", 27 | "zeed": "^0.28.17" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /examples/rpc/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite App 8 | 9 | 10 |

11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /examples/rpc/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "zerva-example-rpc", 3 | "type": "module", 4 | "version": "0.2.4", 5 | "author": { 6 | "name": "Dirk Holtwick", 7 | "email": "dirk.holtwick@gmail.com", 8 | "url": "https://holtwick.de" 9 | }, 10 | "license": "MIT", 11 | "funding": { 12 | "type": "GitHub Sponsors ❤", 13 | "url": "https://github.com/sponsors/holtwick" 14 | }, 15 | "scripts": { 16 | "build": "zerva build && vite build", 17 | "reset": "rm -rf node_modules pnpm-lock.yaml dist dist_www www", 18 | "serve": "ZEED=* LEVEL=a node dist/main.mjs", 19 | "start": "DEBUG=1 ZEED=* LEVEL=a zerva", 20 | "bun": "DEBUG=1 ZEED=* LEVEL=a zerva --debug --bun --external bun:sqlite" 21 | }, 22 | "dependencies": { 23 | "@zerva/rpc": "workspace:*", 24 | "vue": "^3.5.16", 25 | "zeed": "^0.28.17" 26 | }, 27 | "devDependencies": { 28 | "@vitejs/plugin-vue": "^5.2.4", 29 | "@vue/compiler-sfc": "^3.5.16", 30 | "@zerva/bin": "workspace:*", 31 | "@zerva/core": "workspace:*", 32 | "@zerva/http": "workspace:*", 33 | "@zerva/vite": "workspace:*", 34 | "vite": "^6.3.5" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /examples/rpc/public/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/holtwick/zerva/c667c89d809e34e2ac68166c9f2607fcba738a24/examples/rpc/public/icon.png -------------------------------------------------------------------------------- /examples/rpc/service.ts: -------------------------------------------------------------------------------- 1 | import type { RpcClientFunctions, RpcServerFunctions } from './src/_types' 2 | import { on, serve } from '@zerva/core' 3 | import { useHttp } from '@zerva/http' 4 | import { useWebsocketRpcHub } from '@zerva/rpc' 5 | import { useVite } from '@zerva/vite' 6 | import { Logger } from 'zeed' 7 | 8 | const log = Logger('service') 9 | 10 | useHttp({ port: 8080 }) 11 | 12 | useVite({ root: '.' }) 13 | 14 | useWebsocketRpcHub({ log: 0 }) 15 | 16 | let clientCounter = 1 17 | on('rpcConnect', async ({ rpcHub, dispose }) => { 18 | const rpc = rpcHub({ 19 | helloIAmNew(id) { 20 | log.info('New client with user agent:', id) 21 | // await sleep(10000) 22 | return clientCounter++ 23 | }, 24 | }) 25 | 26 | let counter = 0 27 | 28 | dispose.interval(() => { 29 | rpc.updateCounter(counter++) 30 | }, 2500) 31 | }) 32 | 33 | void serve() 34 | -------------------------------------------------------------------------------- /examples/rpc/src/App.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 11 | -------------------------------------------------------------------------------- /examples/rpc/src/AppMessages.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 23 | -------------------------------------------------------------------------------- /examples/rpc/src/_types.ts: -------------------------------------------------------------------------------- 1 | export interface RpcClientFunctions { 2 | updateCounter: (count: number) => void 3 | } 4 | 5 | export interface RpcServerFunctions { 6 | helloIAmNew: (id: string) => number 7 | } 8 | -------------------------------------------------------------------------------- /examples/rpc/src/hub.ts: -------------------------------------------------------------------------------- 1 | import type { RpcClientFunctions, RpcServerFunctions } from './_types' 2 | import { useWebsocketRpcHubClient } from '@zerva/rpc' 3 | import { ref } from 'vue' 4 | 5 | export function useAppRpc() { 6 | const { rpcHub } = useWebsocketRpcHubClient(undefined, { log: 0 }) 7 | 8 | const counter = ref(-1) 9 | 10 | const rpc = rpcHub({ 11 | updateCounter(count: number) { 12 | counter.value = count 13 | }, 14 | }) 15 | 16 | return { counter, rpc } 17 | } 18 | -------------------------------------------------------------------------------- /examples/rpc/src/main.ts: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue' 2 | import { Logger } from 'zeed' 3 | import App from './App.vue' 4 | 5 | const log = Logger('main') 6 | 7 | log('app starts') 8 | 9 | createApp(App).mount('#app') 10 | -------------------------------------------------------------------------------- /examples/rpc/src/shim.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | declare module '*.vue' { 4 | import type { ComponentOptions } from 'vue' 5 | 6 | const Component: ComponentOptions 7 | export default Component 8 | } 9 | 10 | declare module '*.md' { 11 | import type { ComponentOptions } from 'vue' 12 | 13 | const Component: ComponentOptions 14 | export default Component 15 | } 16 | 17 | declare interface Window { 18 | // extend the window 19 | } 20 | -------------------------------------------------------------------------------- /examples/rpc/vite.config.ts: -------------------------------------------------------------------------------- 1 | import vue from '@vitejs/plugin-vue' 2 | import { defineConfig } from 'vite' 3 | 4 | export default defineConfig({ 5 | plugins: [vue()], 6 | build: { 7 | outDir: 'dist_www', 8 | }, 9 | }) 10 | -------------------------------------------------------------------------------- /examples/sandbox/README.md: -------------------------------------------------------------------------------- 1 | # Zerva Sandbox 2 | 3 | Experiments for new core features. 4 | -------------------------------------------------------------------------------- /examples/sandbox/main.ts: -------------------------------------------------------------------------------- 1 | import * as zz from '@zerva/core' 2 | import { useHttp } from '@zerva/http' 3 | import { Logger } from 'zeed' 4 | 5 | const log = Logger('sandbox') 6 | 7 | declare global { 8 | interface ZContextEvents { 9 | counterInc: (up: number) => number 10 | } 11 | } 12 | 13 | function useCounter() { 14 | zz.register('counter', ['http']) 15 | let counter = 1 16 | 17 | zz.on({ 18 | counterInc(up) { 19 | log('counterInc', up) 20 | return (counter += up) 21 | }, 22 | httpInit({ get }) { 23 | get('/', ({ req }) => { 24 | log('get', req.path) 25 | return `
Counter ${counter++}.

Reload page to increase counter.
` 26 | }) 27 | }, 28 | }) 29 | 30 | return { 31 | getCounter: () => counter, 32 | } 33 | } 34 | 35 | useHttp({ 36 | host: '0.0.0.0', 37 | port: 3333, 38 | }) 39 | 40 | useCounter() 41 | 42 | setTimeout(() => { 43 | zz.zerva.call.counterInc(100) 44 | }, 5e3) 45 | 46 | // We start the server manually, it would only start automatically 47 | // after all timeouts have finished and that would not be great 48 | 49 | void zz.serve() 50 | -------------------------------------------------------------------------------- /examples/sandbox/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "zerva-example-sandbox", 3 | "type": "module", 4 | "version": "1.0.0", 5 | "private": true, 6 | "author": { 7 | "name": "Dirk Holtwick", 8 | "email": "dirk.holtwick@gmail.com", 9 | "url": "https://holtwick.de" 10 | }, 11 | "license": "MIT", 12 | "funding": { 13 | "type": "GitHub Sponsors ❤", 14 | "url": "https://github.com/sponsors/holtwick" 15 | }, 16 | "main": "main.js", 17 | "scripts": { 18 | "build": "zerva build", 19 | "reset": "rm -rf node_modules pnpm-lock.yaml dist dist_www www", 20 | "serve": "ZEED=* node dist/man.cjs", 21 | "start": "ZEED=* zerva" 22 | }, 23 | "dependencies": { 24 | "@zerva/bin": "workspace:*", 25 | "@zerva/core": "workspace:*", 26 | "@zerva/http": "workspace:*", 27 | "zeed": "^0.28.17" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /examples/vite-pwa/README.md: -------------------------------------------------------------------------------- 1 | # Service Worker 2 | 3 | xxx 4 | -------------------------------------------------------------------------------- /examples/vite-pwa/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Vite App 9 | 10 | 11 | 12 | 13 |
14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /examples/vite-pwa/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vite-pwa", 3 | "version": "0.0.0", 4 | "author": { 5 | "name": "Dirk Holtwick", 6 | "email": "dirk.holtwick@gmail.com", 7 | "url": "https://holtwick.de" 8 | }, 9 | "license": "MIT", 10 | "funding": { 11 | "type": "GitHub Sponsors ❤", 12 | "url": "https://github.com/sponsors/holtwick" 13 | }, 14 | "scripts": { 15 | "build": "pnpm run clean && zerva build src/zerva/index.ts && vite build", 16 | "clean": "rm -rf dist dist_www", 17 | "prod": "pnpm run build && pnpm run serve", 18 | "reset": "rm -rf node_modules pnpm-lock.yaml dist dist_www www", 19 | "serve": "ZEED=* LEVEL=i node --enable-source-maps dist/main.mjs", 20 | "start": "ZEED=* LEVEL=a zerva src/zerva/index.ts", 21 | "vite_build": "vite build", 22 | "vite_dev": "vite", 23 | "vite_serve": "vite preview" 24 | }, 25 | "dependencies": { 26 | "vue": "^3.5.16", 27 | "zeed": "^0.28.17" 28 | }, 29 | "devDependencies": { 30 | "@vitejs/plugin-vue": "^5.2.4", 31 | "@zerva/bin": "workspace:*", 32 | "@zerva/core": "workspace:*", 33 | "@zerva/http": "workspace:*", 34 | "@zerva/vite": "workspace:*", 35 | "typescript": "^5.8.3", 36 | "vite": "^6.3.5", 37 | "vite-plugin-pwa": "^1.0.0" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /examples/vite-pwa/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/holtwick/zerva/c667c89d809e34e2ac68166c9f2607fcba738a24/examples/vite-pwa/public/favicon.ico -------------------------------------------------------------------------------- /examples/vite-pwa/src/App.vue: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /examples/vite-pwa/src/main.ts: -------------------------------------------------------------------------------- 1 | import type { LoggerInterface } from 'zeed' 2 | import { createApp } from 'vue' 3 | import { Logger } from 'zeed' 4 | import App from './App.vue' 5 | import { setupPWA } from './pwa' 6 | 7 | const log: LoggerInterface = Logger('main') 8 | 9 | log('register') 10 | 11 | void setupPWA() 12 | 13 | log('app') 14 | 15 | createApp(App).mount('#app') 16 | -------------------------------------------------------------------------------- /examples/vite-pwa/src/pwa.ts: -------------------------------------------------------------------------------- 1 | import type { LoggerInterface } from 'zeed' 2 | import { Logger } from 'zeed' 3 | 4 | const log: LoggerInterface = Logger('pwa') 5 | 6 | export async function setupPWA() { 7 | try { 8 | if ('serviceWorker' in navigator) { 9 | // Register Service Worker file if functionality is available 10 | const reg = await navigator.serviceWorker.register('/sw.js') 11 | log('serviceWorker registered') 12 | 13 | // Force to look for updates 14 | await reg.update() 15 | log('serviceWorker updated') 16 | } 17 | else { 18 | log.info('serviceWorker not supported') 19 | } 20 | } 21 | catch (err) { 22 | log.warn('PWA setup error:', err) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /examples/vite-pwa/src/service-worker.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | /* eslint-disable no-restricted-globals */ 4 | /* eslint-disable no-console */ 5 | 6 | // // Give TypeScript the correct global. 7 | // declare const self: ServiceWorkerGlobalScope 8 | // declare type ExtendableEvent = any 9 | 10 | // This code executes in its own worker or thread 11 | 12 | console.log('Service worker init 5') 13 | 14 | const files = self.__WB_MANIFEST 15 | console.log(files) 16 | 17 | self.addEventListener('install', (event) => { 18 | console.log('Service worker installed') 19 | 20 | event.waitUntil((async () => { 21 | // const cache = await caches.open(CACHE_NAME) 22 | // // Setting {cache: 'reload'} in the new request ensures that the 23 | // // response isn't fulfilled from the HTTP cache; i.e., it will be 24 | // // from the network. 25 | // await cache.add(new Request(OFFLINE_URL, { cache: "reload" })) 26 | })(), 27 | ) 28 | 29 | // Force the waiting service worker to become the active service worker. 30 | self.skipWaiting() 31 | }) 32 | 33 | self.addEventListener('activate', (event) => { 34 | console.log('Service worker activated!') 35 | 36 | event.waitUntil( 37 | (async () => { 38 | // Enable navigation preload if it's supported. 39 | // See https://developers.google.com/web/updates/2017/02/navigation-preload 40 | // if ("navigationPreload" in self.registration) { 41 | // await self.registration.navigationPreload.enable() 42 | // } 43 | })(), 44 | ) 45 | 46 | // Tell the active service worker to take control of the page immediately. 47 | self.clients.claim() 48 | }) 49 | 50 | self.addEventListener('fetch', (event) => { 51 | try { 52 | console.log('fetch', event.request.url) 53 | } 54 | catch (err) { 55 | console.error('fetch error', error) 56 | } 57 | }) 58 | -------------------------------------------------------------------------------- /examples/vite-pwa/src/shims-vue.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | declare module '*.vue' { 4 | import type { ComponentOptions } from 'vue' 5 | 6 | const Component: ComponentOptions 7 | export default Component 8 | } 9 | -------------------------------------------------------------------------------- /examples/vite-pwa/src/zerva/index.ts: -------------------------------------------------------------------------------- 1 | import { serve } from '@zerva/core' 2 | import { useHttp } from '@zerva/http' 3 | import { useVite } from '@zerva/vite' 4 | import { Logger } from 'zeed' 5 | import { useCounter } from './module' 6 | 7 | const log = Logger('service') 8 | 9 | // const isProduction = process.env.ZERVA_PRODUCTION 10 | 11 | useHttp() 12 | 13 | useVite() 14 | 15 | useCounter() 16 | 17 | void serve() 18 | -------------------------------------------------------------------------------- /examples/vite-pwa/src/zerva/module.ts: -------------------------------------------------------------------------------- 1 | import { emit, on, register } from '@zerva/core' 2 | import { cloneObject, Logger } from 'zeed' 3 | 4 | const log = Logger('counter') 5 | 6 | declare global { 7 | interface ZContextEvents { 8 | counterIncrement: (counter: number) => void 9 | } 10 | } 11 | 12 | export function useCounter() { 13 | log.info('use counter') 14 | register('counter', ['http']) 15 | let counter = 0 16 | on('httpInit', ({ get }) => { 17 | get('/counter', async () => { 18 | await emit('counterIncrement', ++counter) 19 | return `
Counter ${counter}.

Reload page to increase counter.
` 20 | }) 21 | get('/demo.json', async ({ req }) => { 22 | await emit('counterIncrement', ++counter) 23 | return { 24 | headers: cloneObject(req.headers), 25 | url: req.url, 26 | ip: req.ip, 27 | query: req.query, 28 | } 29 | }) 30 | get('/demo.txt', async () => { 31 | await emit('counterIncrement', ++counter) 32 | return `Counter ${counter}` 33 | }) 34 | }) 35 | } 36 | -------------------------------------------------------------------------------- /examples/vite-pwa/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json" 3 | } 4 | -------------------------------------------------------------------------------- /examples/vite-pwa/vite.config.ts: -------------------------------------------------------------------------------- 1 | import vue from '@vitejs/plugin-vue' 2 | import { defineConfig } from 'vite' 3 | import { VitePWA } from 'vite-plugin-pwa' 4 | 5 | // https://vitejs.dev/config/ 6 | export default defineConfig({ 7 | plugins: [ 8 | vue(), 9 | VitePWA({ 10 | devOptions: { 11 | enabled: true, 12 | navigateFallback: 'index.html', 13 | type: 'module', 14 | }, 15 | 16 | srcDir: 'src', 17 | filename: 'service-worker.ts', 18 | 19 | strategies: 'injectManifest', 20 | injectRegister: false, 21 | 22 | manifest: { 23 | name: 'pwa-demo', 24 | }, 25 | 26 | // manifest: false, 27 | // injectManifest: { 28 | // injectionPoint: null, 29 | // }, 30 | }), 31 | ], 32 | build: { 33 | outDir: './dist_www', 34 | sourcemap: true, 35 | }, 36 | }) 37 | -------------------------------------------------------------------------------- /examples/vite-serviceworker/README.md: -------------------------------------------------------------------------------- 1 | # Service Worker 2 | 3 | xxx 4 | -------------------------------------------------------------------------------- /examples/vite-serviceworker/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Vite App 9 | 10 | 11 | 12 | 13 |
14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /examples/vite-serviceworker/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vite-serviceworker", 3 | "version": "0.0.0", 4 | "author": { 5 | "name": "Dirk Holtwick", 6 | "email": "dirk.holtwick@gmail.com", 7 | "url": "https://holtwick.de" 8 | }, 9 | "license": "MIT", 10 | "funding": { 11 | "type": "GitHub Sponsors ❤", 12 | "url": "https://github.com/sponsors/holtwick" 13 | }, 14 | "scripts": { 15 | "build": "pnpm run clean && zerva build src/zerva/index.ts && vite build", 16 | "clean": "rm -rf dist dist_www", 17 | "prod": "pnpm run build && pnpm run serve", 18 | "reset": "rm -rf node_modules pnpm-lock.yaml dist dist_www www", 19 | "serve": "ZEED=* LEVEL=i node --enable-source-maps dist/main.mjs", 20 | "start": "ZEED=* LEVEL=a zerva src/zerva/index.ts", 21 | "vite_build": "vite build", 22 | "vite_dev": "vite", 23 | "vite_serve": "vite preview" 24 | }, 25 | "dependencies": { 26 | "vue": "^3.5.16", 27 | "zeed": "^0.28.17" 28 | }, 29 | "devDependencies": { 30 | "@vitejs/plugin-vue": "^5.2.4", 31 | "@zerva/bin": "workspace:*", 32 | "@zerva/core": "workspace:*", 33 | "@zerva/http": "workspace:*", 34 | "@zerva/vite": "workspace:*", 35 | "typescript": "^5.8.3", 36 | "vite": "^6.3.5" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /examples/vite-serviceworker/public/app.webmanifest: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Zerva App" 3 | } -------------------------------------------------------------------------------- /examples/vite-serviceworker/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/holtwick/zerva/c667c89d809e34e2ac68166c9f2607fcba738a24/examples/vite-serviceworker/public/favicon.ico -------------------------------------------------------------------------------- /examples/vite-serviceworker/public/sw.js: -------------------------------------------------------------------------------- 1 | // This code executes in its own worker or thread 2 | 3 | console.log('Service worker init 4') 4 | 5 | self.addEventListener('install', (event) => { 6 | console.log('Service worker installed') 7 | 8 | event.waitUntil((async () => { 9 | // const cache = await caches.open(CACHE_NAME) 10 | // // Setting {cache: 'reload'} in the new request ensures that the 11 | // // response isn't fulfilled from the HTTP cache; i.e., it will be 12 | // // from the network. 13 | // await cache.add(new Request(OFFLINE_URL, { cache: "reload" })) 14 | })(), 15 | ) 16 | 17 | // Force the waiting service worker to become the active service worker. 18 | self.skipWaiting() 19 | }) 20 | 21 | self.addEventListener('activate', (event) => { 22 | console.log('Service worker activated!') 23 | 24 | event.waitUntil( 25 | (async () => { 26 | // Enable navigation preload if it's supported. 27 | // See https://developers.google.com/web/updates/2017/02/navigation-preload 28 | // if ("navigationPreload" in self.registration) { 29 | // await self.registration.navigationPreload.enable() 30 | // } 31 | })(), 32 | ) 33 | 34 | // Tell the active service worker to take control of the page immediately. 35 | self.clients.claim() 36 | }) 37 | 38 | self.addEventListener('fetch', (event) => { 39 | try { 40 | console.log('fetch', event.request.url) 41 | } 42 | catch (err) { 43 | console.error('fetch error', error) 44 | } 45 | }) 46 | -------------------------------------------------------------------------------- /examples/vite-serviceworker/src/App.vue: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /examples/vite-serviceworker/src/main.ts: -------------------------------------------------------------------------------- 1 | import type { LoggerInterface } from 'zeed' 2 | import { createApp } from 'vue' 3 | import { Logger } from 'zeed' 4 | import App from './App.vue' 5 | import { setupPWA } from './pwa' 6 | 7 | const log: LoggerInterface = Logger('main') 8 | 9 | log('register') 10 | 11 | void setupPWA() 12 | 13 | log('app') 14 | 15 | createApp(App).mount('#app') 16 | -------------------------------------------------------------------------------- /examples/vite-serviceworker/src/pwa.ts: -------------------------------------------------------------------------------- 1 | import type { LoggerInterface } from 'zeed' 2 | import { Logger } from 'zeed' 3 | 4 | const log: LoggerInterface = Logger('pwa') 5 | 6 | export async function setupPWA() { 7 | try { 8 | if ('serviceWorker' in navigator) { 9 | // Register Service Worker file if functionality is available 10 | const reg = await navigator.serviceWorker.register('/sw.js') 11 | log('serviceWorker registered') 12 | 13 | // Force to look for updates 14 | await reg.update() 15 | log('serviceWorker updated') 16 | } 17 | else { 18 | log.info('serviceWorker not supported') 19 | } 20 | } 21 | catch (err) { 22 | log.warn('PWA setup error:', err) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /examples/vite-serviceworker/src/shims-vue.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | declare module '*.vue' { 4 | import type { ComponentOptions } from 'vue' 5 | 6 | const Component: ComponentOptions 7 | export default Component 8 | } 9 | -------------------------------------------------------------------------------- /examples/vite-serviceworker/src/zerva/index.ts: -------------------------------------------------------------------------------- 1 | import { serve } from '@zerva/core' 2 | import { useHttp } from '@zerva/http' 3 | import { useVite } from '@zerva/vite' 4 | import { Logger } from 'zeed' 5 | import { useCounter } from './module' 6 | 7 | const log = Logger('service') 8 | 9 | // const isProduction = process.env.ZERVA_PRODUCTION 10 | 11 | useHttp() 12 | 13 | useVite() 14 | 15 | useCounter() 16 | 17 | void serve() 18 | -------------------------------------------------------------------------------- /examples/vite-serviceworker/src/zerva/module.ts: -------------------------------------------------------------------------------- 1 | import { emit, on, register } from '@zerva/core' 2 | import { cloneObject, Logger } from 'zeed' 3 | 4 | const log = Logger('counter') 5 | 6 | declare global { 7 | interface ZContextEvents { 8 | counterIncrement: (counter: number) => void 9 | } 10 | } 11 | 12 | export function useCounter() { 13 | log.info('use counter') 14 | register('counter', ['http']) 15 | let counter = 0 16 | on('httpInit', ({ get }) => { 17 | get('/counter', async () => { 18 | await emit('counterIncrement', ++counter) 19 | return `
Counter ${counter}.

Reload page to increase counter.
` 20 | }) 21 | get('/demo.json', async ({ req }) => { 22 | await emit('counterIncrement', ++counter) 23 | return { 24 | headers: cloneObject(req.headers), 25 | url: req.url, 26 | ip: req.ip, 27 | query: req.query, 28 | } 29 | }) 30 | get('/demo.txt', async () => { 31 | await emit('counterIncrement', ++counter) 32 | return `Counter ${counter}` 33 | }) 34 | }) 35 | } 36 | -------------------------------------------------------------------------------- /examples/vite-serviceworker/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json" 3 | } 4 | -------------------------------------------------------------------------------- /examples/vite-serviceworker/vite.config.ts: -------------------------------------------------------------------------------- 1 | import vue from '@vitejs/plugin-vue' 2 | import { defineConfig } from 'vite' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [ 7 | vue(), 8 | ], 9 | build: { 10 | outDir: './dist_www', 11 | sourcemap: true, 12 | }, 13 | }) 14 | -------------------------------------------------------------------------------- /examples/vite/README.md: -------------------------------------------------------------------------------- 1 | # Vue 3 + Typescript + Vite 2 | 3 | This template should help get you started developing with Vue 3 and Typescript in Vite. The template uses Vue 3 ` 15 | 16 | 17 | -------------------------------------------------------------------------------- /examples/vite/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite App 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /examples/vite/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vite-project", 3 | "version": "0.0.0", 4 | "author": { 5 | "name": "Dirk Holtwick", 6 | "email": "dirk.holtwick@gmail.com", 7 | "url": "https://holtwick.de" 8 | }, 9 | "license": "MIT", 10 | "funding": { 11 | "type": "GitHub Sponsors ❤", 12 | "url": "https://github.com/sponsors/holtwick" 13 | }, 14 | "scripts": { 15 | "build": "pnpm run clean && zerva build src/zerva/index.ts && vite build", 16 | "clean": "rm -rf dist dist_www", 17 | "prod": "pnpm run build && pnpm run serve", 18 | "reset": "rm -rf node_modules pnpm-lock.yaml dist dist_www www", 19 | "serve": "ZEED=* LEVEL=i node --enable-source-maps dist/main.mjs", 20 | "start": "ZEED=* LEVEL=a zerva src/zerva/index.ts", 21 | "vite_build": "vite build", 22 | "vite_dev": "vite", 23 | "vite_serve": "vite preview" 24 | }, 25 | "dependencies": { 26 | "vue": "^3.5.16" 27 | }, 28 | "devDependencies": { 29 | "@vitejs/plugin-vue": "^5.2.4", 30 | "@zerva/bin": "workspace:*", 31 | "@zerva/core": "workspace:*", 32 | "@zerva/http": "workspace:*", 33 | "@zerva/vite": "workspace:*", 34 | "typescript": "^5.8.3", 35 | "vite": "^6.3.5", 36 | "zeed": "^0.28.17" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /examples/vite/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/holtwick/zerva/c667c89d809e34e2ac68166c9f2607fcba738a24/examples/vite/public/favicon.ico -------------------------------------------------------------------------------- /examples/vite/src/App.vue: -------------------------------------------------------------------------------- 1 |