├── .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 |
6 |
7 |
zerva-rpc demo
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/examples/rpc/src/AppMessages.vue:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 |
19 |
We receive a counter that goes up
20 |
counter = {{ counter }}
21 |
22 |
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 |
2 | Service Worker
3 |
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 |
2 | Service Worker
3 |
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 |