@live-change/billing-frontend 0.8.68

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/Dockerfile +55 -0
  2. package/LICENSE +21 -0
  3. package/data/GeoLite2-Country.mmdb +0 -0
  4. package/dev.Dockerfile +35 -0
  5. package/docker/app.initd.sh +73 -0
  6. package/docker/build-and-upload.sh +30 -0
  7. package/docker/build-docker-and-upload.sh +33 -0
  8. package/docker/commit-new-version.sh +17 -0
  9. package/docker/k8s-rsync-helper.sh +4 -0
  10. package/docker/onlyDependencies.js +12 -0
  11. package/docker/parse-args-and-config.sh +19 -0
  12. package/docker/restore-backup-with-service.sh +14 -0
  13. package/docker/restore-backup.sh +22 -0
  14. package/docker/start-service.sh +4 -0
  15. package/docker/upload-backup-and-restore.sh +12 -0
  16. package/front/index.html +78 -0
  17. package/front/locales/en.js +26 -0
  18. package/front/locales/en.json +7 -0
  19. package/front/public/favicon.ico +0 -0
  20. package/front/public/images/empty-photo.svg +38 -0
  21. package/front/public/images/empty-user-photo.svg +33 -0
  22. package/front/public/images/logo.svg +34 -0
  23. package/front/public/images/logo128.png +0 -0
  24. package/front/src/App.vue +61 -0
  25. package/front/src/Index.vue +34 -0
  26. package/front/src/analytics/index.js +15 -0
  27. package/front/src/components/BillingBalance.vue +11 -0
  28. package/front/src/config.js +26 -0
  29. package/front/src/entry-client.js +8 -0
  30. package/front/src/entry-server.js +8 -0
  31. package/front/src/router.js +79 -0
  32. package/front/tsconfig.json +26 -0
  33. package/front/tsconfig.node.json +11 -0
  34. package/front/vite.config.ts +53 -0
  35. package/index.js +2 -0
  36. package/package.json +106 -0
  37. package/server/app.config.js +109 -0
  38. package/server/init.js +10 -0
  39. package/server/page.documentType.js +103 -0
  40. package/server/security.config.js +53 -0
  41. package/server/services.list.js +61 -0
  42. package/server/start.js +11 -0
  43. package/start-dev-docker.sh +4 -0
@@ -0,0 +1,34 @@
1
+ <template>
2
+ <div class="w-full">
3
+
4
+ </div>
5
+ </template>
6
+
7
+ <script setup>
8
+
9
+ import InputText from "primevue/inputtext"
10
+
11
+ import {
12
+ defineProps, defineEmits, defineModel, toRefs, computed, watch, ref, watchEffect, onUnmounted,
13
+ getCurrentInstance, unref
14
+ } from 'vue'
15
+
16
+ import { usePath, live, useClient, useActions, reverseRange, useTimeSynchronization } from '@live-change/vue3-ssr'
17
+ const path = usePath()
18
+ const actions = useActions()
19
+
20
+ const allBalancesPath = computed(() => path.balanceTest.allBalances({}))
21
+
22
+ const [allBalances] = await Promise.all([
23
+ live(allBalancesPath)
24
+ ])
25
+
26
+ async function deleteBalance(balance) {
27
+ await actions.balanceTest.deleteBalance({ name: balance.owner })
28
+ }
29
+
30
+ </script>
31
+
32
+ <style scoped>
33
+
34
+ </style>
@@ -0,0 +1,15 @@
1
+ import { analytics } from "@live-change/vue3-components"
2
+
3
+ analytics.on('*', (type, e) => console.log('ANALYTICS EVENT', type, e) )
4
+
5
+ analytics.on('formDone', ({ service, action }) => {
6
+
7
+ })
8
+
9
+ analytics.on('menuOpen', e => {
10
+
11
+ })
12
+
13
+ analytics.on('pageView', ({ to, fullPath }) => {
14
+
15
+ })
@@ -0,0 +1,11 @@
1
+ <template>
2
+
3
+ </template>
4
+
5
+ <script setup>
6
+
7
+ </script>
8
+
9
+ <style scoped>
10
+
11
+ </style>
@@ -0,0 +1,26 @@
1
+ import deepmerge from 'deepmerge';
2
+
3
+ import * as en from "../locales/en.js"
4
+ import { locales as autoFormLocales } from "@live-change/frontend-auto-form"
5
+
6
+ export default {
7
+ defaultLocale: 'en',
8
+ i18n: {
9
+ messages: {
10
+ en: deepmerge.all([
11
+ autoFormLocales.en,
12
+ en.messages
13
+ ])
14
+ },
15
+ numberFormats: {
16
+ en: deepmerge.all([
17
+ en.numberFormats
18
+ ])
19
+ },
20
+ datetimeFormats: {
21
+ en: deepmerge.all([
22
+ en.datetimeFormats
23
+ ])
24
+ }
25
+ }
26
+ }
@@ -0,0 +1,8 @@
1
+ import { clientEntry } from '@live-change/frontend-base/client-entry.js'
2
+ import App from './App.vue'
3
+ import { createRouter } from './router'
4
+ import config from './config.js'
5
+
6
+ clientEntry(App, createRouter, config)
7
+
8
+ window.appStarted = true
@@ -0,0 +1,8 @@
1
+ import { serverEntry, sitemapEntry } from '@live-change/frontend-base/server-entry.js'
2
+ import App from './App.vue'
3
+ import { createRouter, sitemap as routerSitemap } from './router'
4
+ import config from './config.js'
5
+
6
+ const render = serverEntry(App, createRouter, config)
7
+ const sitemap = sitemapEntry(App, createRouter, routerSitemap, config)
8
+ export { render, sitemap }
@@ -0,0 +1,79 @@
1
+ import {
2
+ createMemoryHistory,
3
+ createRouter as _createRouter,
4
+ createWebHistory
5
+ } from 'vue-router'
6
+
7
+ import {
8
+ installRouterAnalytics
9
+ } from '@live-change/vue3-components'
10
+
11
+ import { dbAdminRoutes } from "@live-change/db-admin"
12
+ import { userRoutes } from "@live-change/user-frontend"
13
+ import { catchAllPagesRoute, contentEditRoutes, pagesSitemap } from "@live-change/content-frontend"
14
+
15
+
16
+ export function balanceRoutes(config = {}) {
17
+ const { prefix = '/', route = (r) => r } = config
18
+ return [
19
+
20
+
21
+
22
+
23
+
24
+ ]
25
+ }
26
+
27
+ export async function sitemap(route, api) {
28
+ route({
29
+ name: 'index'
30
+ })
31
+ await pagesSitemap(route, api)
32
+ }
33
+
34
+ import { client as useClient } from '@live-change/vue3-ssr'
35
+
36
+ export function createRouter(app, config) {
37
+ const client = useClient(app._context)
38
+
39
+ const router = _createRouter({
40
+ // use appropriate history implementation for server/client
41
+ // import.meta.env.SSR is injected by Vite.
42
+ history: import.meta.env.SSR ? createMemoryHistory() : createWebHistory(),
43
+ routes: [
44
+ ...userRoutes({ ...config, prefix: prefix + 'user/' }),
45
+
46
+ ...balanceRoutes(config),
47
+
48
+ {
49
+ name: 'index', path: '/', meta: { },
50
+ component: () => import("./Index.vue")
51
+ },
52
+
53
+ ...dbAdminRoutes({ prefix: '/_db', route: r => ({ ...r, meta: { ...r.meta, raw: true }}) }),
54
+ ...catchAllPagesRoute({ ...config }),
55
+ ]
56
+ })
57
+ installRouterAnalytics(router)
58
+ router.beforeEach(async (to, from) => {
59
+ if(to?.matched.find(m => m?.meta.signedIn)) {
60
+ if(!client.value.user) {
61
+ console.log("REDIRECT TO LOGIN BECAUSE PAGE REQUIRES LOGIN!")
62
+ router.redirectAfterSignIn = to.fullPath
63
+ return { name: 'user:signInEmail' }
64
+ }
65
+ }
66
+ if(to?.matched.find(m => m?.meta.signedOut)) {
67
+ if(client.value.user) {
68
+ console.log("REDIRECT TO USER INDEX BECAUSE PAGE REQUIRES LOGOUT!")
69
+ return { name: 'user:settings' }
70
+ }
71
+ }
72
+ if(to && to.name === 'user:signInEmail' && from?.matched.find(m => m?.meta.saveForSignIn)) {
73
+ console.log("SAVE FOR LOGIN", from.fullPath)
74
+ localStorage.redirectAfterLogin = from.fullPath
75
+ }
76
+ })
77
+ return router
78
+ }
79
+
@@ -0,0 +1,26 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "useDefineForClassFields": true,
5
+ "module": "ESNext",
6
+ "lib": ["ES2020", "DOM", "DOM.Iterable"],
7
+ "skipLibCheck": true,
8
+
9
+ /* Bundler mode */
10
+ "moduleResolution": "bundler",
11
+ "allowImportingTsExtensions": true,
12
+ "resolveJsonModule": true,
13
+ "isolatedModules": true,
14
+ "noEmit": true,
15
+ "jsx": "preserve",
16
+
17
+ /* Linting */
18
+ "strict": true,
19
+ "noUnusedLocals": true,
20
+ "noUnusedParameters": true,
21
+ "noFallthroughCasesInSwitch": true
22
+ },
23
+ "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"],
24
+ "references": [{ "path": "./tsconfig.node.json" }]
25
+ }
26
+
@@ -0,0 +1,11 @@
1
+ {
2
+ "compilerOptions": {
3
+ "composite": true,
4
+ "skipLibCheck": true,
5
+ "module": "ESNext",
6
+ "moduleResolution": "bundler",
7
+ "allowSyntheticDefaultImports": true,
8
+ "strict": true
9
+ },
10
+ "include": ["vite.config.ts"]
11
+ }
@@ -0,0 +1,53 @@
1
+ import { defineConfig } from 'vite'
2
+ import Pages from 'vite-plugin-pages'
3
+
4
+ import { fileURLToPath } from 'url'
5
+ import { dirname, join } from 'path'
6
+ import { accessSync, readFileSync } from 'fs'
7
+ const currentModuleDir = dirname(fileURLToPath(import.meta.url))
8
+ const packageJsonPath = dirname(fileURLToPath(import.meta.url))
9
+ .split('/').map((part, i, arr) =>
10
+ join(arr.slice(0, arr.length - i).join('/'), 'package.json')
11
+ ).find(p => { try { accessSync(p); return true } catch(e) { return false }})
12
+ const packageJson = packageJsonPath ? JSON.parse(readFileSync(packageJsonPath, 'utf-8')) : {}
13
+ const name = packageJson.name ?? "Example"
14
+ const version = process.env.VERSION ?? packageJson.version ?? 'unknown'
15
+ const homepage = process.env.BASE_HREF ?? packageJson.homepage
16
+ const domain = (homepage && homepage.match(/https\:\/\/([^\/]+)/)?.[1]) || 'example.com'
17
+
18
+ // @ts-ignore
19
+ import baseViteConfig from '@live-change/frontend-base/vite-config.js'
20
+
21
+ export default defineConfig(async ({ command, mode }) => {
22
+ const baseConfig = (await baseViteConfig({ command, mode }))
23
+ return {
24
+ ...baseConfig,
25
+
26
+ define: {
27
+ ...baseConfig.define,
28
+ ENV_VERSION: JSON.stringify(version),
29
+ ENV_BRAND_NAME: JSON.stringify(name[0].toUpperCase() + name.slice(1)),
30
+ ENV_BRAND_DOMAIN: JSON.stringify(domain),
31
+ },
32
+
33
+ plugins: [
34
+ ...baseConfig.plugins,
35
+ Pages({
36
+ dirs: [
37
+ // basic
38
+ { dir: 'src/pages', baseRoute: '' },
39
+ // blog
40
+ // { dir: 'src/blog', baseRoute: 'blog' },
41
+ ],
42
+ extensions: ['vue', 'md'],
43
+ }),
44
+ ],
45
+
46
+ resolve: {
47
+ ...baseConfig.resolve,
48
+ alias: [
49
+ ...baseConfig.resolve.alias,
50
+ ]
51
+ }
52
+ }
53
+ })
package/index.js ADDED
@@ -0,0 +1,2 @@
1
+
2
+ export { }
package/package.json ADDED
@@ -0,0 +1,106 @@
1
+ {
2
+ "name": "@live-change/billing-frontend",
3
+ "version": "0.8.68",
4
+ "scripts": {
5
+ "memDev": "node server/start.js memDev --enableSessions --initScript ./init.js --dbAccess",
6
+ "localDevInit": "rm tmp.db; node server/start.js localDev --enableSessions --initScript ./init.js",
7
+ "localDev": "node server/start.js localDev --enableSessions --dbAccess",
8
+ "dev": "node server/start.js dev --enableSessions",
9
+ "ssrDev": "node server/start.js ssrDev --enableSessions",
10
+ "serveAllMem": "cross-env NODE_ENV=production node server/start.js ssrServer --withApi --withServices --updateServices --enableSessions --withDb --dbBackend mem --createDb",
11
+ "serveAll": "cross-env NODE_ENV=production node server/start.js ssrServer --withApi --withServices --updateServices --enableSessions",
12
+ "serve": "cross-env NODE_ENV=production node server/start.js ssrServer --enableSessions",
13
+ "memDev:spa": "node server/start.js memDev --enableSessions --initScript ./init.js --dbAccess --spa",
14
+ "localDevInit:spa": "rm tmp.db; node server/start.js localDev --enableSessions --initScript ./init.js --spa",
15
+ "localDev:spa": "node server/start.js localDev --enableSessions --spa",
16
+ "dev:spa": "node server/start.js dev --enableSessions --spa",
17
+ "ssrDev:spa": "node server/start.js ssrDev --enableSessions --spa",
18
+ "serveAllMem:spa": "cross-env NODE_ENV=production node server/start.js server --withApi --withServices --updateServices --enableSessions --withDb --dbBackend mem --createDb --spa",
19
+ "serveAll:spa": "cross-env NODE_ENV=production node server/start.js server --withApi --withServices --updateServices --enableSessions --spa",
20
+ "serve:spa": "cross-env NODE_ENV=production node server/start.js server --enableSessions --spa",
21
+ "apiServer": "node server/start.js apiServer --enableSessions",
22
+ "devApiServer": "node server/start.js devApiServer --enableSessions",
23
+ "memApiServer": "node server/start.js memApiServer --enableSessions",
24
+ "build": "cd front; yarn build:client && yarn build:server",
25
+ "build:client": "cd front; dotenvx run -f ../.env -- vite build --ssrManifest --outDir dist/client",
26
+ "build:server": "cd front; dotenvx run -f ../.env -- vite build --ssr src/entry-server.js --outDir dist/server",
27
+ "build:spa": "cd front; dotenvx run -f ../.env -- vite build --outDir dist/spa",
28
+ "generate": "vite build --ssrManifest --outDir dist/static && yarn build:server && node prerender",
29
+ "debug": "node --inspect-brk server",
30
+ "describe": "node server/start.js describe",
31
+ "changes": "node server/start.js changes"
32
+ },
33
+ "type": "module",
34
+ "dependencies": {
35
+ "@codemirror/language": "6.10.1",
36
+ "@dotenvx/dotenvx": "0.27.0",
37
+ "@fortawesome/fontawesome-free": "^6.5.2",
38
+ "@live-change/access-control-frontend": "^0.8.68",
39
+ "@live-change/access-control-service": "^0.8.68",
40
+ "@live-change/backup-service": "^0.8.68",
41
+ "@live-change/blog-frontend": "^0.8.68",
42
+ "@live-change/blog-service": "^0.8.68",
43
+ "@live-change/cli": "^0.8.68",
44
+ "@live-change/content-frontend": "^0.8.68",
45
+ "@live-change/content-service": "^0.8.68",
46
+ "@live-change/dao": "^0.8.68",
47
+ "@live-change/dao-vue3": "^0.8.68",
48
+ "@live-change/dao-websocket": "^0.8.68",
49
+ "@live-change/db-client": "^0.8.68",
50
+ "@live-change/email-service": "^0.8.68",
51
+ "@live-change/framework": "^0.8.68",
52
+ "@live-change/frontend-auto-form": "^0.8.68",
53
+ "@live-change/frontend-base": "^0.8.68",
54
+ "@live-change/geoip-service": "^0.8.68",
55
+ "@live-change/image-frontend": "^0.8.68",
56
+ "@live-change/locale-settings-service": "^0.8.68",
57
+ "@live-change/password-authentication-service": "^0.8.68",
58
+ "@live-change/prosemirror-service": "^0.8.68",
59
+ "@live-change/secret-code-service": "^0.8.68",
60
+ "@live-change/secret-link-service": "^0.8.68",
61
+ "@live-change/session-service": "^0.8.68",
62
+ "@live-change/task-service": "^0.8.68",
63
+ "@live-change/upload-frontend": "^0.8.68",
64
+ "@live-change/url-frontend": "^0.8.68",
65
+ "@live-change/url-service": "^0.8.68",
66
+ "@live-change/user-frontend": "^0.8.68",
67
+ "@live-change/user-identification-service": "^0.8.68",
68
+ "@live-change/user-service": "^0.8.68",
69
+ "@live-change/vote-service": "^0.8.68",
70
+ "@live-change/vue3-components": "^0.8.68",
71
+ "@live-change/vue3-ssr": "^0.8.68",
72
+ "@live-change/wysiwyg-frontend": "^0.8.68",
73
+ "@vueuse/core": "^10.11.0",
74
+ "codeceptjs-assert": "^0.0.5",
75
+ "compression": "^1.7.4",
76
+ "cross-env": "^7.0.3",
77
+ "get-port-sync": "1.0.1",
78
+ "pica": "^9.0.1",
79
+ "pretty-bytes": "^6.1.1",
80
+ "primeflex": "^3.3.1",
81
+ "primeicons": "^7.0.0",
82
+ "primevue": "^3.52.0",
83
+ "rollup-plugin-node-builtins": "^2.1.2",
84
+ "rollup-plugin-visualizer": "5.12.0",
85
+ "serialize-javascript": "^6.0.2",
86
+ "serve-static": "^1.15.0",
87
+ "v-shared-element": "3.1.1",
88
+ "vue": "^3.4.29",
89
+ "vue-i18n": "^9.10.1",
90
+ "vue-router": "^4.3.3",
91
+ "vue3-scroll-border": "0.1.6"
92
+ },
93
+ "devDependencies": {
94
+ "@live-change/codeceptjs-helper": "^0.8.68",
95
+ "codeceptjs": "^3.6.5",
96
+ "generate-password": "1.7.1",
97
+ "playwright": "^1.41.2",
98
+ "random-profile-generator": "^2.3.0",
99
+ "txtgen": "^3.0.6",
100
+ "webdriverio": "^8.40.2"
101
+ },
102
+ "author": "Michał Łaszczewski <michal@laszczewski.pl>",
103
+ "license": "ISC",
104
+ "description": "",
105
+ "gitHead": "9f34ce84625f32092de0d93dcd19e4e4982982bd"
106
+ }
@@ -0,0 +1,109 @@
1
+ import dotenv from 'dotenv'
2
+ dotenv.config()
3
+
4
+ import App from "@live-change/framework"
5
+ const app = App.app()
6
+
7
+ const contactTypes = ['email']
8
+
9
+ import securityConfig from './security.config.js'
10
+ import documentTypePage from './page.documentType.js'
11
+
12
+ app.config = {
13
+ services: [
14
+ {
15
+ name: 'session',
16
+ createSessionOnUpdate: true
17
+ },
18
+ {
19
+ name: 'user',
20
+ },
21
+ {
22
+ name: 'email',
23
+ },
24
+ {
25
+ name: 'passwordAuthentication',
26
+ contactTypes,
27
+ signInWithoutPassword: true
28
+ },
29
+ {
30
+ name: 'userIdentification',
31
+ },
32
+ {
33
+ name: 'localeSettings',
34
+ },
35
+ {
36
+ name: 'identicon',
37
+ },
38
+ {
39
+ name: 'accessControl',
40
+ createSessionOnUpdate: true,
41
+ contactTypes,
42
+ },
43
+ {
44
+ name: 'security',
45
+ ...securityConfig,
46
+ },
47
+ {
48
+ name: 'notification',
49
+ contactTypes,
50
+ notificationTypes: ['example_TestNotification']
51
+ },
52
+ {
53
+ name: 'upload',
54
+ },
55
+ {
56
+ name: 'image',
57
+ },
58
+ {
59
+ name: 'secretCode',
60
+ },
61
+ {
62
+ name: 'secretLink',
63
+ },
64
+ {
65
+ name: 'messageAuthentication',
66
+ contactTypes,
67
+ signUp: true,
68
+ signIn: true,
69
+ connect: true
70
+ },
71
+ {
72
+ name: 'url',
73
+ },
74
+ {
75
+ name: 'prosemirror',
76
+ documentTypes: {
77
+ page: documentTypePage,
78
+ /*rich: require('./rich.documentType.js'),*/
79
+ },
80
+ testLatency: 2000
81
+ },
82
+ {
83
+ name: 'content',
84
+ },
85
+ {
86
+ name: 'geoIp',
87
+ geoIpCountryPath: "./data/GeoLite2-Country.mmdb",
88
+ //geoIpDefaultCountry: "pl"
89
+ },
90
+ {
91
+ name: 'vote',
92
+ },
93
+ {
94
+ name: 'task',
95
+ },
96
+ {
97
+ name: 'balance',
98
+ },
99
+ {
100
+ name: 'billing'
101
+ },
102
+ {
103
+ name: 'backup',
104
+ port: 8007
105
+ },
106
+ ]
107
+ }
108
+
109
+ export default app.config
package/server/init.js ADDED
@@ -0,0 +1,10 @@
1
+ import { createUser } from "@live-change/user-frontend/server/init-functions.js"
2
+ import App from '@live-change/framework'
3
+ const app = App.app()
4
+
5
+ export default async function(services) {
6
+
7
+ const testUser = await createUser(services,
8
+ 'Test User', 'test@test.com', 'Testy123', 'u1', ['writer'])
9
+
10
+ }
@@ -0,0 +1,103 @@
1
+ export default {
2
+ "marks": {
3
+ "bold": {},
4
+ "italic": {},
5
+ "underline": {},
6
+ "strike": {}
7
+ },
8
+ "nodes": {
9
+ "paragraph": {
10
+ "content": "inline*",
11
+ "group": "block"
12
+ },
13
+ "horizontalRule": {
14
+ "group": "block"
15
+ },
16
+ "heading": {
17
+ "content": "inline*",
18
+ "group": "block",
19
+ "defining": true,
20
+ "attrs": {
21
+ "level": {
22
+ "default": 1
23
+ }
24
+ }
25
+ },
26
+ "blockquote": {
27
+ "content": "block+",
28
+ "group": "block",
29
+ "defining": true
30
+ },
31
+ "codeBlock": {
32
+ "content": "text*",
33
+ "marks": "",
34
+ "group": "block",
35
+ "code": true,
36
+ "defining": true,
37
+ "attrs": {
38
+ "language": {
39
+ "default": null
40
+ }
41
+ }
42
+ },
43
+ "bulletList": {
44
+ "content": "listItem+",
45
+ "group": "block list"
46
+ },
47
+ "orderedList": {
48
+ "content": "listItem+",
49
+ "group": "block list",
50
+ "attrs": {
51
+ "start": {
52
+ "default": 1
53
+ }
54
+ }
55
+ },
56
+ "listItem": {
57
+ "content": "paragraph block*",
58
+ "defining": true
59
+ },
60
+ "image": {
61
+ "content": "",
62
+ "marks": "",
63
+ "group": "block",
64
+ "inline": false,
65
+ "atom": true,
66
+ "selectable": true,
67
+ "draggable": true,
68
+ "attrs": {
69
+ "image": {
70
+ "default": null
71
+ }
72
+ }
73
+ },
74
+ "doc": {
75
+ "content": "block+"
76
+ },
77
+ "text": {
78
+ "group": "inline"
79
+ },
80
+ "hardBreak": {
81
+ "group": "inline",
82
+ "inline": true,
83
+ "selectable": false
84
+ },
85
+ "component": {
86
+ "content": "block*",
87
+ "marks": "",
88
+ "group": "block",
89
+ "inline": false,
90
+ "selectable": true,
91
+ "draggable": true,
92
+ "attrs": {
93
+ "is": {
94
+ "default": "card"
95
+ },
96
+ "attrs": {
97
+ "default": {}
98
+ }
99
+ }
100
+ }
101
+ },
102
+ "topNode": "doc"
103
+ }
@@ -0,0 +1,53 @@
1
+ import lcp from "@live-change/pattern"
2
+
3
+ const clientKeys = (client) => [
4
+ { key: 'user', value: client.user },
5
+ { key: 'session', value: client.session },
6
+ { key: 'ip', value: client.ip }
7
+ ]
8
+
9
+ const failedAuthCodes = lcp.chain([
10
+ { type: "wrong-secret-code", id: "1st-failed-secret-code" },
11
+ { eq: "ip", expire: "10m" },
12
+ { type: "wrong-secret-code", id: "2nd-failed-secret-code" },
13
+ { eq: "ip", expire: "10m" },
14
+ { type: "wrong-secret-code", id: "3rd-failed-secret-code",
15
+ actions: [
16
+ { type: 'ban', keys: ['ip'], ban: { type: 'captcha', actions: ['checkSecretCode'], expire: "30m" } }
17
+ ]
18
+ }
19
+ ]).model
20
+
21
+ const patterns = lcp.mergeModels(
22
+ //failedAuthCodes
23
+ )
24
+
25
+ const counters = [
26
+ {
27
+ id: 'wrong-codes-captcha',
28
+ match: ['wrong-secret-code'],
29
+ keys: ['ip'],
30
+ max: 2,
31
+ duration: '1m',
32
+ actions: [
33
+ { type: 'ban', keys: ['ip'], ban: { type: 'captcha', actions: ['checkSecretCode'], expire: "30m" } }
34
+ ]
35
+ },
36
+ {
37
+ id: 'wrong-codes-ban',
38
+ visible: true,
39
+ match: ['wrong-secret-code'],
40
+ keys: ['ip'],
41
+ max: 5,
42
+ duration: '10m',
43
+ actions: [
44
+ { type: 'ban', keys: ['ip'], ban: { type: 'block', actions: ['checkSecretCode'], expire: "2m" } }
45
+ ]
46
+ }
47
+ ]
48
+
49
+ export default {
50
+ clientKeys,
51
+ patterns,
52
+ counters
53
+ }