pockethost 1.2.0 → 1.3.1
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.
- package/CHANGELOG.md +24 -0
- package/package.json +5 -6
- package/readme.md +18 -6
- package/src/cli/index.ts +4 -4
- package/src/common/Logger.ts +6 -2
- package/src/common/error.ts +16 -0
- package/src/common/index.ts +1 -1
- package/src/common/plugin/action.ts +101 -34
- package/src/common/plugin/filter.ts +89 -39
- package/src/common/plugin/index.ts +2 -8
- package/src/common/schema/Instance.ts +13 -22
- package/src/common/schema/index.ts +0 -3
- package/src/constants.ts +1 -0
- package/src/server.ts +48 -52
- package/src/common/plugin/helpers.ts +0 -17
- package/src/common/pocketbase-client-helpers/RestHelper.ts +0 -69
- package/src/common/pocketbase-client-helpers/index.ts +0 -1
- package/src/common/schema/Rest/CreateInstance.ts +0 -20
- package/src/common/schema/Rest/DeleteInstance.ts +0 -21
- package/src/common/schema/Rest/GetUserTokenInfo.ts +0 -22
- package/src/common/schema/Rest/UpdateInstance.ts +0 -61
- package/src/common/schema/Rest/index.ts +0 -23
- package/src/common/schema/User.ts +0 -24
- package/src/common/schema/types.ts +0 -18
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
# pockethost
|
|
2
2
|
|
|
3
|
+
## 1.3.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 8288197: Added plugin authoring guide
|
|
8
|
+
|
|
9
|
+
## 1.3.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- 96f355a: Now auto-creates first admin account by default
|
|
14
|
+
- 2fc2eeb: Added before/after instance start/stop events
|
|
15
|
+
- 3f99ea0: Added subdomain to request action and filter context
|
|
16
|
+
- 1384a86: BREAKING: refactored actions/filters
|
|
17
|
+
|
|
18
|
+
### Patch Changes
|
|
19
|
+
|
|
20
|
+
- 6812784: Added improved error parsing support
|
|
21
|
+
- da82667: Fix: properly determine hostname when running on nonstandard port
|
|
22
|
+
- cc4aa02: Moved mothership-related code into mothership plugin
|
|
23
|
+
- Updated dependencies [9d626ec]
|
|
24
|
+
- @pockethost/plugin-launcher-spawn@0.1.0
|
|
25
|
+
- @pockethost/plugin-console-logger@0.1.0
|
|
26
|
+
|
|
3
27
|
## 1.2.0
|
|
4
28
|
|
|
5
29
|
### Minor Changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pockethost",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.1",
|
|
4
4
|
"author": {
|
|
5
5
|
"name": "Ben Allfree",
|
|
6
6
|
"url": "https://github.com/benallfree"
|
|
@@ -39,8 +39,9 @@
|
|
|
39
39
|
"typescript": "^5.4.5",
|
|
40
40
|
"update-notifier": "^7.0.0",
|
|
41
41
|
"url-pattern": "^1.0.3",
|
|
42
|
-
"@pockethost/plugin-console-logger": "^0.0
|
|
43
|
-
"@pockethost/plugin-launcher-spawn": "^0.0
|
|
42
|
+
"@pockethost/plugin-console-logger": "^0.1.0",
|
|
43
|
+
"@pockethost/plugin-launcher-spawn": "^0.1.0",
|
|
44
|
+
"@pockethost/plugin-auto-admin": "^0.0.1"
|
|
44
45
|
},
|
|
45
46
|
"devDependencies": {
|
|
46
47
|
"@types/express": "^4.17.21",
|
|
@@ -49,9 +50,7 @@
|
|
|
49
50
|
"@types/node": "^20.8.10",
|
|
50
51
|
"@types/semver": "^7.5.4",
|
|
51
52
|
"@types/tmp": "^0.2.5",
|
|
52
|
-
"@types/update-notifier": "^6.0.8"
|
|
53
|
-
"@pockethost/plugin-launcher-spawn": "0.0.1",
|
|
54
|
-
"@pockethost/plugin-console-logger": "0.0.1"
|
|
53
|
+
"@types/update-notifier": "^6.0.8"
|
|
55
54
|
},
|
|
56
55
|
"scripts": {
|
|
57
56
|
"check-types": "tsc --noEmit ",
|
package/readme.md
CHANGED
|
@@ -40,18 +40,30 @@ Use `pockethost config` to set global defaults stored in `<PH_HOME>/.env`.
|
|
|
40
40
|
|
|
41
41
|
- `@pockethost/plugin-console-logger`
|
|
42
42
|
- `@pockethost/plugin-launcher-spawn`
|
|
43
|
+
- `@pockethost/plugin-auto-admin`
|
|
43
44
|
|
|
44
45
|
## Plugins
|
|
45
46
|
|
|
46
|
-
PocketHost uses a hook architecture and features
|
|
47
|
+
PocketHost uses a hook architecture and features a growing list plugins. Some plugins have a CLI component, whereas others add purely programmatic support to alter how PocketHost works:
|
|
47
48
|
|
|
48
|
-
|
|
49
|
+
Current plugins:
|
|
50
|
+
|
|
51
|
+
| name | description |
|
|
52
|
+
| --------------------- | ------------------------------------------------------------------------------------------------- |
|
|
53
|
+
| plugin-console-logger | Routes log messages to the console |
|
|
54
|
+
| plugin-auto-admin | Auto-creates a default admin account on instance launch |
|
|
55
|
+
| plugin-launcher-spawn | Launches PocketBase instances via `spawn()` on the local machine. PocketHost uses this by default |
|
|
56
|
+
|
|
57
|
+
Coming soon:
|
|
58
|
+
| name | description |
|
|
49
59
|
| ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
|
|
50
|
-
| plugin-ftp-server
|
|
60
|
+
| plugin-ftp-server | Used to provide secure FTPS access to PocketBase instance data. This FTP server can run along-side a PocketHost server. |
|
|
51
61
|
| plugin-launcher-docker | Launches PocketBase instances via Docker. This is useful for running untrusted PocketBase code and instances. pockethost.io uses this. |
|
|
52
|
-
| plugin-
|
|
53
|
-
| plugin-waf
|
|
54
|
-
|
|
62
|
+
| plugin-waf | A Web Application Firewall |
|
|
63
|
+
| plugin-waf-enforce-ssl | Enforce SSL at the
|
|
64
|
+
WAF
|
|
65
|
+
|
|
66
|
+
See the [./plugin-guide.md](Plugin Authoring Guide) for details about what hooks and filters are available.
|
|
55
67
|
|
|
56
68
|
## Support
|
|
57
69
|
|
package/src/cli/index.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env tsx
|
|
2
2
|
|
|
3
3
|
import { uniq } from '@s-libs/micro-dash'
|
|
4
|
-
import {
|
|
4
|
+
import { program } from 'commander'
|
|
5
5
|
import { readFileSync } from 'fs'
|
|
6
6
|
import updateNotifier from 'update-notifier'
|
|
7
7
|
import {
|
|
@@ -10,8 +10,7 @@ import {
|
|
|
10
10
|
LoggerService,
|
|
11
11
|
PH_PLUGINS,
|
|
12
12
|
PH_PROJECT_DIR,
|
|
13
|
-
|
|
14
|
-
filter,
|
|
13
|
+
doCliCommandsFilter,
|
|
15
14
|
loadPlugins,
|
|
16
15
|
} from '../../core'
|
|
17
16
|
import { ConfigCommand } from './commands/ConfigCommand'
|
|
@@ -36,11 +35,12 @@ export const main = async () => {
|
|
|
36
35
|
.description('Multitenant PocketBase hosting')
|
|
37
36
|
.version(version)
|
|
38
37
|
|
|
39
|
-
const commands = await
|
|
38
|
+
const commands = await doCliCommandsFilter([
|
|
40
39
|
ServeCommand(),
|
|
41
40
|
ConfigCommand(),
|
|
42
41
|
PluginCommand(),
|
|
43
42
|
])
|
|
43
|
+
|
|
44
44
|
for (const command of commands) {
|
|
45
45
|
program.addCommand(command)
|
|
46
46
|
}
|
package/src/common/Logger.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import chalk from 'chalk'
|
|
4
4
|
import stringify from 'json-stringify-safe'
|
|
5
|
-
import {
|
|
5
|
+
import { doLogAction, mergeConfig, mkSingleton } from '.'
|
|
6
6
|
|
|
7
7
|
export type LoggerConfig = {
|
|
8
8
|
level: LogLevelName
|
|
@@ -74,7 +74,11 @@ export const createLogger = (config: Partial<LoggerConfig>) => {
|
|
|
74
74
|
.join(' ')
|
|
75
75
|
|
|
76
76
|
const _log = (levelIn: LogLevelName, ...args: any[]) => {
|
|
77
|
-
|
|
77
|
+
doLogAction({
|
|
78
|
+
currentLevel: _config.level,
|
|
79
|
+
levelIn,
|
|
80
|
+
args,
|
|
81
|
+
})
|
|
78
82
|
}
|
|
79
83
|
|
|
80
84
|
const raw = (...args: any[]) => {
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { keys, map } from '@s-libs/micro-dash'
|
|
2
|
+
import { ClientResponseError } from 'pocketbase'
|
|
3
|
+
|
|
4
|
+
export const parseError = (e: any): string[] => {
|
|
5
|
+
if (e instanceof ClientResponseError) {
|
|
6
|
+
if (e.data.message && keys(e.data.data).length === 0)
|
|
7
|
+
return [e.data.message]
|
|
8
|
+
return map(e.data.data, (v, k) => (v ? v.message : undefined)).filter(
|
|
9
|
+
(v) => !!v,
|
|
10
|
+
)
|
|
11
|
+
}
|
|
12
|
+
if (e instanceof Error) {
|
|
13
|
+
return [e.message]
|
|
14
|
+
}
|
|
15
|
+
return [e.toString()]
|
|
16
|
+
}
|
package/src/common/index.ts
CHANGED
|
@@ -3,10 +3,10 @@ export * from './Logger'
|
|
|
3
3
|
export * from './TimerManager'
|
|
4
4
|
export * from './assert'
|
|
5
5
|
export * from './debug'
|
|
6
|
+
export * from './error'
|
|
6
7
|
export * from './events'
|
|
7
8
|
export * from './mergeConfig'
|
|
8
9
|
export * from './mkSingleton'
|
|
9
10
|
export * from './plugin'
|
|
10
|
-
export * from './pocketbase-client-helpers'
|
|
11
11
|
export * from './promiseSerializer'
|
|
12
12
|
export * from './schema'
|
|
@@ -1,60 +1,127 @@
|
|
|
1
|
+
import { Express, Request, Response } from 'express'
|
|
2
|
+
import { LogLevelName } from '../Logger'
|
|
1
3
|
import { DEBUG } from '../debug'
|
|
4
|
+
import { InstanceFields } from '../schema'
|
|
2
5
|
|
|
3
|
-
|
|
6
|
+
enum CoreActions {
|
|
7
|
+
Init = 'core_init',
|
|
8
|
+
AppMounted = 'core_on_app_mount',
|
|
9
|
+
AfterServeStart = 'core_after_serve_start',
|
|
4
10
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
Core_OnAppMount = 'on_app_mount',
|
|
9
|
-
Core_AfterServeStart = 'after_serve_start',
|
|
11
|
+
Cli_Before_ServeCommand = 'core_before_serve',
|
|
12
|
+
Log = 'core_log',
|
|
13
|
+
InstanceLog = 'core_instance_log',
|
|
10
14
|
|
|
11
|
-
|
|
12
|
-
Core_Log = 'log',
|
|
13
|
-
Core_InstanceLog = 'instance_log',
|
|
15
|
+
StartInstance = 'core_start_instance',
|
|
14
16
|
|
|
15
|
-
|
|
17
|
+
BeforeInstanceStarted = 'core_before_instance_started',
|
|
18
|
+
AfterInstanceStarted = 'core_after_instance_started',
|
|
16
19
|
|
|
17
|
-
|
|
18
|
-
|
|
20
|
+
BeforeInstanceStopped = 'core_before_instance_stopped',
|
|
21
|
+
AfterInstanceStopped = 'core_after_instance_stopped',
|
|
19
22
|
|
|
20
|
-
|
|
21
|
-
Core_AfterInstanceStopped = 'after_instance_stopped',
|
|
23
|
+
AfterInstanceFound = 'core_after_instance_found',
|
|
22
24
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
Core_OnRequestError = 'edge_on_request_error',
|
|
26
|
-
Core_Request = 'edge_request',
|
|
27
|
-
|
|
28
|
-
/** Firewall actions */
|
|
29
|
-
Waf_OnRequestError = 'waf_on_request_error',
|
|
30
|
-
Waf_OnAppMiddleware = 'waf_on_app_middleware',
|
|
31
|
-
|
|
32
|
-
/** Edge actions */
|
|
33
|
-
/** Health actions */
|
|
34
|
-
Health_OnMessage = 'health_on_message',
|
|
35
|
-
Health_OnError = 'health_on_error',
|
|
25
|
+
RequestError = 'core_edge_on_request_error',
|
|
26
|
+
Request = 'core_edge_request',
|
|
36
27
|
}
|
|
37
28
|
|
|
38
29
|
const actions: {
|
|
39
|
-
[key
|
|
30
|
+
[key: string]: ActionHandler<any>[]
|
|
40
31
|
} = {}
|
|
41
32
|
|
|
42
|
-
export type ActionHandler =
|
|
33
|
+
export type ActionHandler<TContext = {}> = (
|
|
34
|
+
context: TContext extends never ? [] : TContext,
|
|
35
|
+
) => Promise<void>
|
|
43
36
|
|
|
44
|
-
|
|
45
|
-
action:
|
|
37
|
+
async function registerAction(
|
|
38
|
+
action: string,
|
|
46
39
|
handler: (...args: any[]) => Promise<void>,
|
|
47
40
|
) {
|
|
48
41
|
if (!(action in actions)) actions[action] = []
|
|
49
42
|
actions[action]!.push(handler)
|
|
50
43
|
}
|
|
51
44
|
|
|
52
|
-
|
|
53
|
-
if (DEBUG() && actionName !==
|
|
45
|
+
async function action(actionName: string, context: any) {
|
|
46
|
+
if (DEBUG() && actionName !== CoreActions.Log) {
|
|
54
47
|
console.log(`a:${actionName}`)
|
|
55
48
|
}
|
|
56
49
|
const action = actions[actionName]
|
|
57
50
|
if (!action) return false
|
|
58
|
-
await Promise.all(action.map((handler) => handler(
|
|
51
|
+
await Promise.all(action.map((handler) => handler(context)))
|
|
59
52
|
return true
|
|
60
53
|
}
|
|
54
|
+
|
|
55
|
+
export function createCustomActionWithContext<TContext extends {}>(
|
|
56
|
+
actionName: CoreActions,
|
|
57
|
+
) {
|
|
58
|
+
return [
|
|
59
|
+
async (context: TContext) => action(actionName, context),
|
|
60
|
+
async (handler: ActionHandler<TContext>) =>
|
|
61
|
+
registerAction(actionName, handler),
|
|
62
|
+
] as const
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function createCustomAction(actionName: CoreActions) {
|
|
66
|
+
return [
|
|
67
|
+
async () => action(actionName, {}),
|
|
68
|
+
async (handler: ActionHandler) => registerAction(actionName, handler),
|
|
69
|
+
] as const
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export const [doRequestErrorAction, onRequestErrorAction] =
|
|
73
|
+
createCustomActionWithContext<{
|
|
74
|
+
err: Error
|
|
75
|
+
}>(CoreActions.RequestError)
|
|
76
|
+
|
|
77
|
+
export const [doAfterServerStartAction, onAfterServerStartAction] =
|
|
78
|
+
createCustomAction(CoreActions.AfterServeStart)
|
|
79
|
+
|
|
80
|
+
export const [doLogAction, onLogAction] = createCustomActionWithContext<{
|
|
81
|
+
currentLevel: LogLevelName
|
|
82
|
+
levelIn: LogLevelName
|
|
83
|
+
args: any[]
|
|
84
|
+
}>(CoreActions.Log)
|
|
85
|
+
|
|
86
|
+
export const [doInstanceLogAction, onInstanceLogAction] =
|
|
87
|
+
createCustomActionWithContext<{
|
|
88
|
+
instance: InstanceFields
|
|
89
|
+
type: 'stdout' | 'stderr'
|
|
90
|
+
data: string
|
|
91
|
+
}>(CoreActions.InstanceLog)
|
|
92
|
+
|
|
93
|
+
export const [doAppMountedAction, onAppMountedAction] =
|
|
94
|
+
createCustomActionWithContext<{ app: Express }>(CoreActions.AppMounted)
|
|
95
|
+
|
|
96
|
+
export const [doIncomingRequestAction, onIncomingRequestAction] =
|
|
97
|
+
createCustomActionWithContext<{ req: Request; res: Response; host: string }>(
|
|
98
|
+
CoreActions.Request,
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
export const [doAfterInstanceFoundAction, onAfterInstanceFoundAction] =
|
|
102
|
+
createCustomActionWithContext<{
|
|
103
|
+
req: Request
|
|
104
|
+
res: Response
|
|
105
|
+
host: string
|
|
106
|
+
instance: InstanceFields
|
|
107
|
+
}>(CoreActions.AfterInstanceFound)
|
|
108
|
+
|
|
109
|
+
export const [doBeforeInstanceStartedAction, onBeforeInstanceStartedAction] =
|
|
110
|
+
createCustomActionWithContext<{ instance: InstanceFields }>(
|
|
111
|
+
CoreActions.BeforeInstanceStarted,
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
export const [doAfterInstanceStartedAction, onAfterInstanceStartedAction] =
|
|
115
|
+
createCustomActionWithContext<{ instance: InstanceFields; url: string }>(
|
|
116
|
+
CoreActions.AfterInstanceStarted,
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
export const [doBeforeInstanceStoppedAction, onBeforeInstanceStoppedAction] =
|
|
120
|
+
createCustomActionWithContext<{ instance: InstanceFields; url: string }>(
|
|
121
|
+
CoreActions.BeforeInstanceStopped,
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
export const [doAfterInstanceStoppedAction, onAfterInstanceStoppedAction] =
|
|
125
|
+
createCustomActionWithContext<{ instance: InstanceFields; url: string }>(
|
|
126
|
+
CoreActions.AfterInstanceStopped,
|
|
127
|
+
)
|
|
@@ -1,56 +1,48 @@
|
|
|
1
|
+
import { Command } from 'commander'
|
|
2
|
+
import { Request, Response } from 'express'
|
|
1
3
|
import { DEBUG } from '../debug'
|
|
4
|
+
import { InstanceFields, InstanceId } from '../schema'
|
|
2
5
|
|
|
3
|
-
export enum
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
Core_NewInstanceRecord = 'core_new_instance_record',
|
|
16
|
-
|
|
17
|
-
/** Mothership Filters */
|
|
18
|
-
Mothership_MaintenanceMode_Message = 'mothership_maintenance_mode_message',
|
|
19
|
-
Mothership_UnverifiedAccountError_Message = 'mothership_unverified_account_error_message',
|
|
20
|
-
Mothership_PublicUrl = 'mothership_public_url',
|
|
21
|
-
|
|
22
|
-
/** Firewall Filters */
|
|
23
|
-
Waf_VHosts = 'waf_vhosts',
|
|
24
|
-
Waf_OnError_Message = 'waf_on_error_message',
|
|
25
|
-
Waf_AppMount = 'waf_app_mount',
|
|
26
|
-
|
|
27
|
-
/** Edge self checks */
|
|
28
|
-
EdgeSelfCheck_Checks = 'edge_self_check_checks',
|
|
6
|
+
export enum CoreFilters {
|
|
7
|
+
CliCommands = 'core_cli_commands',
|
|
8
|
+
SpawnConfig = 'core_spawn_config',
|
|
9
|
+
GetInstanceByRequestInfo = 'core_get_instance_by_request_info',
|
|
10
|
+
GetInstanceById = 'core_get_instance_by_id',
|
|
11
|
+
ErrorSpawningInstanceMessage = 'core_error_spawning_instance_message',
|
|
12
|
+
FailedToLaunchInstanceMessage = 'core_failed_to_launch_instance_message',
|
|
13
|
+
AuthenticateRequest = 'core_authenticate_request',
|
|
14
|
+
RequestError_Message = 'core_request_error_message',
|
|
15
|
+
GetOrProvisionInstanceUrl = 'core_get_or_provision_instance_url',
|
|
16
|
+
PocketBaseLaunchHandler = 'core_pocket_base_launch_handler',
|
|
17
|
+
NewInstanceRecord = 'core_new_instance_record',
|
|
29
18
|
}
|
|
30
19
|
|
|
31
|
-
export type FilterHandler<
|
|
20
|
+
export type FilterHandler<TCarry, TContext> = (
|
|
21
|
+
carry: TCarry,
|
|
22
|
+
context: TContext,
|
|
23
|
+
) => TCarry | Promise<TCarry>
|
|
32
24
|
type FilterEntry<T> = {
|
|
33
25
|
priority: number
|
|
34
|
-
handler: FilterHandler<T>
|
|
26
|
+
handler: FilterHandler<T, any>
|
|
35
27
|
}
|
|
36
28
|
const filters: {
|
|
37
|
-
[key
|
|
29
|
+
[key: string]: FilterEntry<any>[]
|
|
38
30
|
} = {}
|
|
39
31
|
|
|
40
|
-
|
|
41
|
-
filter:
|
|
42
|
-
handler: FilterHandler<
|
|
43
|
-
priority
|
|
32
|
+
async function registerFilter<TCarry, TContext extends {} = {}>(
|
|
33
|
+
filter: string,
|
|
34
|
+
handler: FilterHandler<TCarry, TContext>,
|
|
35
|
+
priority = 10,
|
|
44
36
|
) {
|
|
45
37
|
if (!(filter in filters)) filters[filter] = []
|
|
46
38
|
filters[filter]!.push({ priority, handler })
|
|
47
39
|
filters[filter]!.sort((a, b) => a.priority - b.priority)
|
|
48
40
|
}
|
|
49
41
|
|
|
50
|
-
|
|
51
|
-
filterName:
|
|
52
|
-
initialValue:
|
|
53
|
-
|
|
42
|
+
async function filter<TCarry, TContext extends {} = {}>(
|
|
43
|
+
filterName: string,
|
|
44
|
+
initialValue: TCarry,
|
|
45
|
+
context: TContext,
|
|
54
46
|
) {
|
|
55
47
|
if (DEBUG()) {
|
|
56
48
|
console.log(`f:${filterName}`)
|
|
@@ -59,7 +51,65 @@ export async function filter<TRet, TIn = TRet>(
|
|
|
59
51
|
if (!filter) return initialValue
|
|
60
52
|
return filter.reduce(
|
|
61
53
|
(carry, entry) =>
|
|
62
|
-
carry.then((carryRes) => entry.handler(carryRes,
|
|
54
|
+
carry.then((carryRes) => entry.handler(carryRes, context)),
|
|
63
55
|
Promise.resolve(initialValue),
|
|
64
|
-
) as
|
|
56
|
+
) as TCarry
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function createCustomFilterWithContext<TCarry, TContext extends {} = {}>(
|
|
60
|
+
filterName: CoreFilters,
|
|
61
|
+
) {
|
|
62
|
+
return [
|
|
63
|
+
async (initialValue: TCarry, context: TContext) =>
|
|
64
|
+
filter<TCarry, TContext>(filterName, initialValue, context),
|
|
65
|
+
async (handler: FilterHandler<TCarry, TContext>, priority = 10) =>
|
|
66
|
+
registerFilter<TCarry, TContext>(filterName, handler, priority),
|
|
67
|
+
] as const
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function createCustomFilter<TCarry>(filterName: string) {
|
|
71
|
+
return [
|
|
72
|
+
async (initialValue: TCarry) =>
|
|
73
|
+
filter<TCarry>(filterName, initialValue, {}),
|
|
74
|
+
async (handler: FilterHandler<TCarry, {}>, priority = 10) =>
|
|
75
|
+
registerFilter<TCarry, {}>(filterName, handler, priority),
|
|
76
|
+
] as const
|
|
65
77
|
}
|
|
78
|
+
|
|
79
|
+
export const [
|
|
80
|
+
doGetInstanceByRequestInfoFilter,
|
|
81
|
+
onGetInstanceByRequestInfoFilter,
|
|
82
|
+
] = createCustomFilterWithContext<
|
|
83
|
+
InstanceFields | undefined,
|
|
84
|
+
{ req: Request; res: Response; host: string; subdomain: string }
|
|
85
|
+
>(CoreFilters.GetInstanceByRequestInfo)
|
|
86
|
+
|
|
87
|
+
export const [doGetInstanceByIdFilter, onGetInstanceByIdFilter] =
|
|
88
|
+
createCustomFilterWithContext<
|
|
89
|
+
InstanceFields | undefined,
|
|
90
|
+
{ instanceId: InstanceId }
|
|
91
|
+
>(CoreFilters.GetInstanceById)
|
|
92
|
+
|
|
93
|
+
export const [doCliCommandsFilter, onCliCommandsFilter] = createCustomFilter<
|
|
94
|
+
Command[]
|
|
95
|
+
>(CoreFilters.CliCommands)
|
|
96
|
+
|
|
97
|
+
export const [doNewInstanceRecordFilter, onNewInstanceRecordFilter] =
|
|
98
|
+
createCustomFilter<InstanceFields>(CoreFilters.NewInstanceRecord)
|
|
99
|
+
|
|
100
|
+
export const [doRequestErrorMessageFilter, onRequestErrorMessageFilter] =
|
|
101
|
+
createCustomFilter<string>(CoreFilters.RequestError_Message)
|
|
102
|
+
|
|
103
|
+
export const [
|
|
104
|
+
doGetOrProvisionInstanceUrlFilter,
|
|
105
|
+
onGetOrProvisionInstanceUrlFilter,
|
|
106
|
+
] = createCustomFilterWithContext<
|
|
107
|
+
string,
|
|
108
|
+
{
|
|
109
|
+
req: Request
|
|
110
|
+
res: Response
|
|
111
|
+
host: string
|
|
112
|
+
subdomain: string
|
|
113
|
+
instance: InstanceFields
|
|
114
|
+
}
|
|
115
|
+
>(CoreFilters.GetOrProvisionInstanceUrl)
|
|
@@ -1,16 +1,10 @@
|
|
|
1
1
|
import { isString } from '@s-libs/micro-dash'
|
|
2
|
-
import { registerAction } from './action'
|
|
3
|
-
import { registerFilter } from './filter'
|
|
4
2
|
export * from './action'
|
|
5
3
|
export * from './filter'
|
|
6
|
-
export * from './helpers'
|
|
7
4
|
|
|
8
5
|
export type PocketHostPlugin = (api: PocketHostPluginApi) => Promise<void>
|
|
9
6
|
|
|
10
|
-
export type PocketHostPluginApi = {
|
|
11
|
-
registerAction: typeof registerAction
|
|
12
|
-
registerFilter: typeof registerFilter
|
|
13
|
-
}
|
|
7
|
+
export type PocketHostPluginApi = {}
|
|
14
8
|
|
|
15
9
|
export const loadPlugins = async (plugins: (string | PocketHostPlugin)[]) => {
|
|
16
10
|
await Promise.all(
|
|
@@ -20,7 +14,7 @@ export const loadPlugins = async (plugins: (string | PocketHostPlugin)[]) => {
|
|
|
20
14
|
const plugin = await import(pluginPathOrModule)
|
|
21
15
|
return plugin.default
|
|
22
16
|
})()
|
|
23
|
-
await plugin({
|
|
17
|
+
await plugin({})
|
|
24
18
|
}),
|
|
25
19
|
)
|
|
26
20
|
return plugins
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { doNewInstanceRecordFilter } from '../plugin'
|
|
2
2
|
|
|
3
3
|
export type VersionId = string
|
|
4
4
|
|
|
@@ -13,33 +13,24 @@ export enum InstanceStatus {
|
|
|
13
13
|
Failed = 'failed',
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
+
export type InstanceId = string
|
|
16
17
|
export type InstanceSecretKey = string
|
|
17
18
|
export type InstanceSecretValue = string
|
|
18
19
|
export type InstanceSecretCollection = {
|
|
19
20
|
[name: InstanceSecretKey]: InstanceSecretValue
|
|
20
21
|
}
|
|
21
22
|
|
|
22
|
-
export type InstanceFields =
|
|
23
|
-
subdomain:
|
|
24
|
-
uid: UserId
|
|
25
|
-
status: InstanceStatus
|
|
23
|
+
export type InstanceFields = {
|
|
24
|
+
subdomain: string
|
|
26
25
|
version: VersionId
|
|
27
|
-
secrets: InstanceSecretCollection
|
|
28
|
-
|
|
29
|
-
suspension: string
|
|
30
|
-
syncAdmin: boolean
|
|
31
|
-
cname: string
|
|
32
|
-
dev: boolean
|
|
33
|
-
cname_active: boolean
|
|
34
|
-
notifyMaintenanceMode: boolean
|
|
26
|
+
secrets: InstanceSecretCollection
|
|
27
|
+
dev: boolean // Should instance run in --dev mode
|
|
35
28
|
}
|
|
36
29
|
|
|
37
|
-
export
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
export type InstanceRecordsById = { [_: RecordId]: InstanceFields }
|
|
30
|
+
export const mkInstance = (subdomain: string) =>
|
|
31
|
+
doNewInstanceRecordFilter({
|
|
32
|
+
subdomain,
|
|
33
|
+
version: '*',
|
|
34
|
+
secrets: {},
|
|
35
|
+
dev: false,
|
|
36
|
+
})
|
package/src/constants.ts
CHANGED
package/src/server.ts
CHANGED
|
@@ -2,36 +2,36 @@ import express, { ErrorRequestHandler } from 'express'
|
|
|
2
2
|
import 'express-async-errors'
|
|
3
3
|
import { default as httpProxy } from 'http-proxy'
|
|
4
4
|
import {
|
|
5
|
-
|
|
5
|
+
APEX_DOMAIN,
|
|
6
6
|
LoggerService,
|
|
7
7
|
PORT,
|
|
8
|
-
PocketHostAction,
|
|
9
|
-
PocketHostFilter,
|
|
10
|
-
action,
|
|
11
8
|
asyncExitHook,
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
9
|
+
doAfterInstanceFoundAction,
|
|
10
|
+
doAfterServerStartAction,
|
|
11
|
+
doAppMountedAction,
|
|
12
|
+
doGetInstanceByRequestInfoFilter,
|
|
13
|
+
doGetOrProvisionInstanceUrlFilter,
|
|
14
|
+
doIncomingRequestAction,
|
|
15
|
+
doRequestErrorAction,
|
|
16
|
+
doRequestErrorMessageFilter,
|
|
17
|
+
onInstanceLogAction,
|
|
15
18
|
} from '../core'
|
|
16
19
|
|
|
17
20
|
export const serve = async () => {
|
|
18
21
|
const _proxyLogger = LoggerService().create('ProxyService')
|
|
19
22
|
const { dbg, error, info, trace, warn } = _proxyLogger
|
|
20
23
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
},
|
|
33
|
-
99,
|
|
34
|
-
)
|
|
24
|
+
onInstanceLogAction(async ({ instance, type, data }) => {
|
|
25
|
+
dbg(data.toString())
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
// registerFilter(
|
|
29
|
+
// CoreFilters.Waf_VHosts,
|
|
30
|
+
// async (routes: { [_: string]: string }) => {
|
|
31
|
+
// return { ...routes, '*': `http://localhost:${PORT()}` }
|
|
32
|
+
// },
|
|
33
|
+
// 99,
|
|
34
|
+
// )
|
|
35
35
|
|
|
36
36
|
const proxy = httpProxy.createProxyServer({})
|
|
37
37
|
proxy.on('error', (err, req, res, target) => {
|
|
@@ -47,59 +47,55 @@ export const serve = async () => {
|
|
|
47
47
|
})
|
|
48
48
|
|
|
49
49
|
const errorHandler: ErrorRequestHandler = async (err, req, res, next) => {
|
|
50
|
-
|
|
51
|
-
res
|
|
52
|
-
.status(500)
|
|
53
|
-
.send(
|
|
54
|
-
await filter(
|
|
55
|
-
PocketHostFilter.Core_RequestError_Message,
|
|
56
|
-
err.toString(),
|
|
57
|
-
),
|
|
58
|
-
)
|
|
50
|
+
doRequestErrorAction({ err })
|
|
51
|
+
res.status(500).send(await doRequestErrorMessageFilter(err.toString()))
|
|
59
52
|
}
|
|
60
53
|
app.use(errorHandler)
|
|
61
54
|
|
|
62
|
-
|
|
55
|
+
doAppMountedAction({ app })
|
|
63
56
|
|
|
64
57
|
app.all(`*`, async (req, res, next) => {
|
|
65
58
|
const method = req.method
|
|
66
|
-
const fullUrl =
|
|
67
|
-
|
|
59
|
+
const fullUrl = new URL(
|
|
60
|
+
req.protocol + '://' + req.get('host') + req.originalUrl,
|
|
61
|
+
)
|
|
62
|
+
const host = fullUrl.hostname
|
|
68
63
|
if (!host) {
|
|
69
64
|
throw new Error(`Host not found`)
|
|
70
65
|
}
|
|
66
|
+
const subdomain = host.slice(0, -`.${APEX_DOMAIN()}`.length)
|
|
71
67
|
|
|
72
|
-
dbg(
|
|
68
|
+
dbg(
|
|
69
|
+
`${method} ${fullUrl} (${subdomain}) -> ${`http://localhost:${PORT()}`}`,
|
|
70
|
+
)
|
|
73
71
|
|
|
74
|
-
await
|
|
72
|
+
await doIncomingRequestAction({ req, res, host })
|
|
75
73
|
|
|
76
|
-
const instance = await
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
74
|
+
const instance = await doGetInstanceByRequestInfoFilter(undefined, {
|
|
75
|
+
req,
|
|
76
|
+
res,
|
|
77
|
+
host,
|
|
78
|
+
subdomain,
|
|
79
|
+
})
|
|
81
80
|
if (!instance) {
|
|
82
81
|
res.status(404).end(`${host} not found`)
|
|
83
82
|
return
|
|
84
83
|
}
|
|
85
84
|
|
|
86
|
-
await
|
|
85
|
+
await doAfterInstanceFoundAction({
|
|
87
86
|
instance,
|
|
88
87
|
req,
|
|
89
88
|
res,
|
|
90
89
|
host,
|
|
91
90
|
})
|
|
92
91
|
|
|
93
|
-
const url = await
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
host,
|
|
101
|
-
},
|
|
102
|
-
)
|
|
92
|
+
const url = await doGetOrProvisionInstanceUrlFilter('', {
|
|
93
|
+
req,
|
|
94
|
+
res,
|
|
95
|
+
instance,
|
|
96
|
+
host,
|
|
97
|
+
subdomain,
|
|
98
|
+
})
|
|
103
99
|
|
|
104
100
|
dbg(`Forwarding request for ${req.url} to instance ${url}`)
|
|
105
101
|
|
|
@@ -110,7 +106,7 @@ export const serve = async () => {
|
|
|
110
106
|
|
|
111
107
|
app.listen(PORT(), () => {
|
|
112
108
|
info(`pockethost listening on port ${PORT()}`)
|
|
113
|
-
|
|
109
|
+
doAfterServerStartAction()
|
|
114
110
|
})
|
|
115
111
|
|
|
116
112
|
asyncExitHook(async () => {
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { InstanceFields } from '../schema'
|
|
2
|
-
import { ActionHandler, PocketHostAction, registerAction } from './action'
|
|
3
|
-
import { PocketHostFilter, filter } from './filter'
|
|
4
|
-
|
|
5
|
-
export async function getInstanceById(instanceId: string) {
|
|
6
|
-
return await filter<InstanceFields | undefined>(
|
|
7
|
-
PocketHostFilter.Core_GetInstanceById,
|
|
8
|
-
undefined,
|
|
9
|
-
{ instanceId },
|
|
10
|
-
)
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export const onAppMount = (cb: ActionHandler) =>
|
|
14
|
-
registerAction(PocketHostAction.Core_OnAppMount, cb)
|
|
15
|
-
|
|
16
|
-
export const onInit = (cb: ActionHandler) =>
|
|
17
|
-
registerAction(PocketHostAction.Core_Init, cb)
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
import Ajv, { JSONSchemaType } from 'ajv'
|
|
2
|
-
import PocketBase, { ClientResponseError } from 'pocketbase'
|
|
3
|
-
import type { JsonObject } from 'type-fest'
|
|
4
|
-
import { LoggerService, RestCommands, RestMethods } from '..'
|
|
5
|
-
|
|
6
|
-
export type RestHelperConfig = {
|
|
7
|
-
client: PocketBase
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export type RestHelper = ReturnType<typeof createRestHelper>
|
|
11
|
-
|
|
12
|
-
export const createRestHelper = (config: RestHelperConfig) => {
|
|
13
|
-
const _logger = LoggerService().create(`RestHelper`)
|
|
14
|
-
const { client } = config
|
|
15
|
-
|
|
16
|
-
const mkRest = <TPayload extends JsonObject, TResult extends JsonObject>(
|
|
17
|
-
cmd: RestCommands,
|
|
18
|
-
method: RestMethods,
|
|
19
|
-
schema: JSONSchemaType<TPayload>,
|
|
20
|
-
) => {
|
|
21
|
-
const validator = new Ajv().compile(schema)
|
|
22
|
-
return async (payload: TPayload): Promise<TResult> => {
|
|
23
|
-
const _restCallLogger = _logger.create(cmd)
|
|
24
|
-
const { dbg, error } = _restCallLogger
|
|
25
|
-
|
|
26
|
-
dbg(`Executing REST call`)
|
|
27
|
-
if (!validator(payload)) {
|
|
28
|
-
throw new Error(`Invalid REST payload: ${validator.errors}`)
|
|
29
|
-
}
|
|
30
|
-
const _payload = { ...payload }
|
|
31
|
-
|
|
32
|
-
const url = `/api/${cmd}${
|
|
33
|
-
method === RestMethods.Post ? '' : '/:id'
|
|
34
|
-
}`.replace(/:([a-zA-Z]+)/g, (_, key) => {
|
|
35
|
-
if (!(key in _payload)) {
|
|
36
|
-
throw new Error(`Payload must include '${key}`)
|
|
37
|
-
}
|
|
38
|
-
const value = _payload[key]!
|
|
39
|
-
delete _payload[key]
|
|
40
|
-
return encodeURIComponent(value.toString())
|
|
41
|
-
})
|
|
42
|
-
|
|
43
|
-
const options: any = {
|
|
44
|
-
method: method,
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
if (method !== RestMethods.Get) {
|
|
48
|
-
options.body = _payload
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
dbg({ url, options })
|
|
52
|
-
|
|
53
|
-
try {
|
|
54
|
-
const res = await client.send(url, options)
|
|
55
|
-
dbg(res)
|
|
56
|
-
return res
|
|
57
|
-
} catch (e) {
|
|
58
|
-
if (e instanceof ClientResponseError) {
|
|
59
|
-
error(`REST error: ${e.originalError}`)
|
|
60
|
-
throw e.originalError
|
|
61
|
-
}
|
|
62
|
-
error(`REST error: ${e}`)
|
|
63
|
-
throw e
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
return { mkRest }
|
|
69
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './RestHelper'
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { JSONSchemaType } from 'ajv'
|
|
2
|
-
import { InstanceFields, Subdomain } from '..'
|
|
3
|
-
|
|
4
|
-
export type CreateInstancePayload = {
|
|
5
|
-
subdomain: Subdomain
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export type CreateInstanceResult = {
|
|
9
|
-
instance: InstanceFields
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export const CreateInstancePayloadSchema: JSONSchemaType<CreateInstancePayload> =
|
|
13
|
-
{
|
|
14
|
-
type: 'object',
|
|
15
|
-
properties: {
|
|
16
|
-
subdomain: { type: 'string' },
|
|
17
|
-
},
|
|
18
|
-
required: ['subdomain'],
|
|
19
|
-
additionalProperties: false,
|
|
20
|
-
}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { JSONSchemaType } from 'ajv'
|
|
2
|
-
import { InstanceId } from '..'
|
|
3
|
-
|
|
4
|
-
export type DeleteInstancePayload = {
|
|
5
|
-
id: InstanceId
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export type DeleteInstanceResult = {
|
|
9
|
-
status: 'ok' | 'error'
|
|
10
|
-
message?: string
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export const DeleteInstancePayloadSchema: JSONSchemaType<DeleteInstancePayload> =
|
|
14
|
-
{
|
|
15
|
-
type: 'object',
|
|
16
|
-
properties: {
|
|
17
|
-
id: { type: 'string' },
|
|
18
|
-
},
|
|
19
|
-
required: ['id'],
|
|
20
|
-
additionalProperties: false,
|
|
21
|
-
}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { JSONSchemaType } from 'ajv'
|
|
2
|
-
import { UserId } from '..'
|
|
3
|
-
|
|
4
|
-
export type GetUserTokenPayload = {
|
|
5
|
-
id: UserId
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export type GetUserTokenResult = {
|
|
9
|
-
id: string
|
|
10
|
-
email: string
|
|
11
|
-
tokenKey: string
|
|
12
|
-
passwordHash: string
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export const GetUserTokenPayloadSchema: JSONSchemaType<GetUserTokenPayload> = {
|
|
16
|
-
type: 'object',
|
|
17
|
-
properties: {
|
|
18
|
-
id: { type: 'string' },
|
|
19
|
-
},
|
|
20
|
-
required: ['id'],
|
|
21
|
-
additionalProperties: false,
|
|
22
|
-
}
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
import { JSONSchemaType } from 'ajv'
|
|
2
|
-
import { InstanceFields, InstanceId } from '..'
|
|
3
|
-
|
|
4
|
-
export type UpdateInstancePayload = {
|
|
5
|
-
id: InstanceId
|
|
6
|
-
fields: Partial<
|
|
7
|
-
Pick<
|
|
8
|
-
InstanceFields,
|
|
9
|
-
| 'maintenance'
|
|
10
|
-
| 'secrets'
|
|
11
|
-
| 'subdomain'
|
|
12
|
-
| 'syncAdmin'
|
|
13
|
-
| 'version'
|
|
14
|
-
| 'dev'
|
|
15
|
-
| 'cname'
|
|
16
|
-
| 'notifyMaintenanceMode'
|
|
17
|
-
>
|
|
18
|
-
>
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export const SECRET_KEY_REGEX = /^[A-Z][A-Z0-9_]*$/
|
|
22
|
-
|
|
23
|
-
export type UpdateInstanceResult = {
|
|
24
|
-
status: 'ok' | 'error'
|
|
25
|
-
message?: string
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export const UpdateInstancePayloadSchema: JSONSchemaType<UpdateInstancePayload> =
|
|
29
|
-
{
|
|
30
|
-
type: 'object',
|
|
31
|
-
properties: {
|
|
32
|
-
id: { type: 'string' },
|
|
33
|
-
fields: {
|
|
34
|
-
type: 'object',
|
|
35
|
-
properties: {
|
|
36
|
-
syncAdmin: { type: 'boolean', nullable: true },
|
|
37
|
-
subdomain: { type: 'string', nullable: true },
|
|
38
|
-
maintenance: { type: 'boolean', nullable: true },
|
|
39
|
-
version: {
|
|
40
|
-
type: 'string',
|
|
41
|
-
nullable: true,
|
|
42
|
-
},
|
|
43
|
-
secrets: {
|
|
44
|
-
type: 'object',
|
|
45
|
-
nullable: true,
|
|
46
|
-
patternProperties: {
|
|
47
|
-
[SECRET_KEY_REGEX.source]: {
|
|
48
|
-
anyOf: [{ type: 'string' }],
|
|
49
|
-
},
|
|
50
|
-
},
|
|
51
|
-
required: [],
|
|
52
|
-
},
|
|
53
|
-
dev: { type: 'boolean', nullable: true },
|
|
54
|
-
cname: { type: 'string', nullable: true },
|
|
55
|
-
notifyMaintenanceMode: { type: 'boolean', nullable: true },
|
|
56
|
-
},
|
|
57
|
-
},
|
|
58
|
-
},
|
|
59
|
-
required: ['id', 'fields'],
|
|
60
|
-
additionalProperties: false,
|
|
61
|
-
}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import Ajv from 'ajv'
|
|
2
|
-
import { JsonObject } from 'type-fest'
|
|
3
|
-
|
|
4
|
-
export enum RestMethods {
|
|
5
|
-
Get = 'GET',
|
|
6
|
-
Post = 'POST',
|
|
7
|
-
Put = 'PUT',
|
|
8
|
-
Delete = 'DELETE',
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export enum RestCommands {
|
|
12
|
-
Instance = 'instance',
|
|
13
|
-
UserToken = 'userToken',
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export type RestPayloadBase = JsonObject
|
|
17
|
-
|
|
18
|
-
export const ajv = new Ajv()
|
|
19
|
-
|
|
20
|
-
export * from './CreateInstance'
|
|
21
|
-
export * from './DeleteInstance'
|
|
22
|
-
export * from './GetUserTokenInfo'
|
|
23
|
-
export * from './UpdateInstance'
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { BaseFields } from './types'
|
|
2
|
-
|
|
3
|
-
export enum SubscriptionType {
|
|
4
|
-
Legacy = 'legacy',
|
|
5
|
-
Free = 'free',
|
|
6
|
-
Premium = 'premium',
|
|
7
|
-
Lifetime = 'lifetime',
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export const PLAN_NAMES = {
|
|
11
|
-
[SubscriptionType.Legacy]: 'Legacy',
|
|
12
|
-
[SubscriptionType.Free]: 'Hacker',
|
|
13
|
-
[SubscriptionType.Premium]: `Pro`,
|
|
14
|
-
[SubscriptionType.Lifetime]: `Founder's Edition`,
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export type UserFields = BaseFields & {
|
|
18
|
-
email: string
|
|
19
|
-
verified: boolean
|
|
20
|
-
isLegacy: boolean
|
|
21
|
-
isFounder: boolean
|
|
22
|
-
subscription: SubscriptionType
|
|
23
|
-
notifyMaintenanceMode: boolean
|
|
24
|
-
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
export type RecordId = string
|
|
2
|
-
export type UserId = RecordId
|
|
3
|
-
export type InstanceId = RecordId
|
|
4
|
-
export type Semver = string
|
|
5
|
-
export type InternalInstanceId = RecordId
|
|
6
|
-
export type Subdomain = string
|
|
7
|
-
export type Port = number
|
|
8
|
-
export type IsoDate = string
|
|
9
|
-
export type ProcessId = number
|
|
10
|
-
export type Username = string
|
|
11
|
-
export type Password = string
|
|
12
|
-
export type CollectionName = string
|
|
13
|
-
export type Seconds = number
|
|
14
|
-
export type BaseFields = {
|
|
15
|
-
id: RecordId
|
|
16
|
-
created: IsoDate
|
|
17
|
-
updated: IsoDate
|
|
18
|
-
}
|