pockethost 1.6.1 → 3.0.0

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 (44) hide show
  1. package/CHANGELOG.md +123 -84
  2. package/README.md +96 -0
  3. package/dist/cli.js +21542 -0
  4. package/package.json +55 -53
  5. package/changesetx.ts +0 -110
  6. package/common.ts +0 -1
  7. package/core.ts +0 -1
  8. package/readme.md +0 -129
  9. package/src/cli/commands/ConfigCommand/index.ts +0 -28
  10. package/src/cli/commands/PluginCommand/index.ts +0 -81
  11. package/src/cli/commands/PluginCommand/util.ts +0 -140
  12. package/src/cli/commands/ServeCommand/index.ts +0 -36
  13. package/src/cli/index.ts +0 -70
  14. package/src/common/CleanupManager.ts +0 -65
  15. package/src/common/Logger.ts +0 -174
  16. package/src/common/ResourceAllocator.ts +0 -49
  17. package/src/common/TimerManager.ts +0 -64
  18. package/src/common/assert.ts +0 -26
  19. package/src/common/debug.ts +0 -8
  20. package/src/common/error.ts +0 -16
  21. package/src/common/events.ts +0 -53
  22. package/src/common/index.ts +0 -12
  23. package/src/common/mergeConfig.ts +0 -27
  24. package/src/common/mkSingleton.ts +0 -28
  25. package/src/common/plugin/action.ts +0 -164
  26. package/src/common/plugin/filter.ts +0 -197
  27. package/src/common/plugin/index.ts +0 -21
  28. package/src/common/promiseSerializer.ts +0 -22
  29. package/src/common/schema/BaseFields.ts +0 -10
  30. package/src/common/schema/Instance.ts +0 -46
  31. package/src/common/schema/InstanceLog.ts +0 -12
  32. package/src/common/schema/index.ts +0 -3
  33. package/src/common/schema/util.ts +0 -7
  34. package/src/constants.ts +0 -70
  35. package/src/core/Settings.ts +0 -119
  36. package/src/core/asyncExecutionGuard.ts +0 -49
  37. package/src/core/config.ts +0 -108
  38. package/src/core/exit.ts +0 -11
  39. package/src/core/index.ts +0 -8
  40. package/src/core/internal.ts +0 -3
  41. package/src/core/smartFetch.ts +0 -32
  42. package/src/core/tryFetch.ts +0 -69
  43. package/src/plugin.ts +0 -54
  44. package/src/server.ts +0 -129
package/src/cli/index.ts DELETED
@@ -1,70 +0,0 @@
1
- #!/usr/bin/env tsx
2
-
3
- import { uniq } from '@s-libs/micro-dash'
4
- import { program } from 'commander'
5
- import { readFileSync } from 'fs'
6
- import minimist from 'minimist'
7
- import updateNotifier from 'update-notifier'
8
- import { PH_PLUGINS, PH_PROJECT_DIR } from '../../core'
9
- import {
10
- DEBUG,
11
- LogLevelName,
12
- LoggerService,
13
- doAfterPluginsLoadedAction,
14
- doCliCommandsFilter,
15
- loadPlugins,
16
- } from '../common'
17
- import { pockethost } from '../plugin'
18
- import { ConfigCommand } from './commands/ConfigCommand'
19
- import { PluginCommand } from './commands/PluginCommand'
20
- import { ServeCommand } from './commands/ServeCommand'
21
-
22
- export const { dbg, info, error } = LoggerService({
23
- level: DEBUG() ? LogLevelName.Debug : LogLevelName.Info,
24
- })
25
-
26
- export type GlobalOptions = {
27
- extraPlugins: string[]
28
- }
29
-
30
- export const main = async () => {
31
- const pkg = await JSON.parse(
32
- readFileSync(PH_PROJECT_DIR(`package.json`), 'utf8').toString(),
33
- )
34
- updateNotifier({ pkg }).notify()
35
-
36
- const { version } = pkg
37
-
38
- const argv = minimist<{ e: string }>(process.argv.slice(2), {
39
- alias: { e: 'extra-plugins' },
40
- default: { e: '' },
41
- })
42
- const extraPlugins = argv.e
43
- .split(/,/)
44
- .map((s) => s.trim())
45
- .filter((v) => !!v)
46
-
47
- await loadPlugins([pockethost, ...uniq(PH_PLUGINS()), ...extraPlugins])
48
-
49
- await doAfterPluginsLoadedAction()
50
-
51
- program
52
- .name('pockethost')
53
- .description('Multitenant PocketBase hosting')
54
- .version(version)
55
- .option(`-e, --extra-plugins <plugins...>`, `Extra plugins to load`, [])
56
-
57
- const commands = await doCliCommandsFilter([
58
- await ServeCommand(),
59
- ConfigCommand(),
60
- PluginCommand(),
61
- ])
62
-
63
- for (const command of commands) {
64
- program.addCommand(command)
65
- }
66
-
67
- await program.parseAsync()
68
- }
69
-
70
- main()
@@ -1,65 +0,0 @@
1
- import { reduce, uniqueId, values } from '@s-libs/micro-dash'
2
- import { LoggerService } from '.'
3
-
4
- export type CleanupFunc = () => Promise<void> | void
5
-
6
- type CleanupRec = {
7
- cleanup: CleanupFunc
8
- priority: number
9
- }
10
-
11
- export const CLEANUP_DEFAULT_PRIORITY = 10
12
- export const CLEANUP_PRIORITY_HIGH = 1
13
- export const CLEANUP_PRIORITY_LOW = 20
14
- export const CLEANUP_PRIORITY_LAST = 1000
15
-
16
- export type CleanupManagerApi = ReturnType<typeof createCleanupManager>
17
-
18
- export const createCleanupManager = (slug?: string) => {
19
- const _slug = slug || uniqueId()
20
-
21
- const { error, warn, dbg } = LoggerService().create(`cleanupManager:${_slug}`)
22
-
23
- let i = 0
24
-
25
- const cleanups: { [_: number]: CleanupRec } = {}
26
-
27
- const add = (cb: CleanupFunc, priority = CLEANUP_DEFAULT_PRIORITY) => {
28
- const idx = i++
29
-
30
- const cleanup = async () => {
31
- await cb()
32
- delete cleanups[idx]
33
- }
34
-
35
- cleanups[idx] = { cleanup, priority }
36
-
37
- return cleanup
38
- }
39
-
40
- let _shutdownP: Promise<void> | undefined = undefined
41
-
42
- const shutdown: () => Promise<void> = () => {
43
- if (_shutdownP) return _shutdownP
44
-
45
- const _cleanupFuncs = values(cleanups)
46
- .sort((a, b) => a.priority - b.priority)
47
- .map((v) => v.cleanup)
48
- _shutdownP = reduce(
49
- _cleanupFuncs,
50
- (c, v) => {
51
- return c.then(() => v())
52
- },
53
- Promise.resolve(),
54
- ).catch((e) => {
55
- error(
56
- `Cleanup functions are failing. This should never happen, check all cleanup functions to make sure they are trapping their exceptions.`,
57
- )
58
- throw e
59
- })
60
-
61
- return _shutdownP
62
- }
63
-
64
- return { add, shutdown }
65
- }
@@ -1,174 +0,0 @@
1
- /// <require "node">
2
-
3
- import chalk from 'chalk'
4
- import stringify from 'json-stringify-safe'
5
- import { doLogAction, mergeConfig, mkSingleton } from '.'
6
-
7
- export type LoggerConfig = {
8
- level: LogLevelName
9
- pfx: string[]
10
- }
11
-
12
- export type Logger = ReturnType<typeof createLogger>
13
-
14
- export const isLevelLte = (a: LogLevelName, b: LogLevelName) => {
15
- return LogLevels[a] <= LogLevels[b]
16
- }
17
-
18
- export const isLevelGt = (a: LogLevelName, b: LogLevelName) => {
19
- return LogLevels[a] > LogLevels[b]
20
- }
21
-
22
- export const isLevelGte = (a: LogLevelName, b: LogLevelName) => {
23
- return LogLevels[a] >= LogLevels[b]
24
- }
25
-
26
- export enum LogLevelName {
27
- Trace = 'trace',
28
- Raw = 'raw',
29
- Debug = 'debug',
30
- Info = 'info',
31
- Warn = 'warn',
32
- Error = 'error',
33
- Abort = 'abort',
34
- }
35
-
36
- export const LEVEL_NAMES = [
37
- LogLevelName.Trace,
38
- LogLevelName.Raw,
39
- LogLevelName.Debug,
40
- LogLevelName.Info,
41
- LogLevelName.Warn,
42
- LogLevelName.Error,
43
- LogLevelName.Abort,
44
- ]
45
-
46
- export const LogLevels = {
47
- [LogLevelName.Trace]: 0,
48
- [LogLevelName.Raw]: 1,
49
- [LogLevelName.Debug]: 2,
50
- [LogLevelName.Info]: 3,
51
- [LogLevelName.Warn]: 4,
52
- [LogLevelName.Error]: 5,
53
- [LogLevelName.Abort]: 6,
54
- } as const
55
-
56
- export const namespace = (...names: string[]) =>
57
- names
58
- .filter((v) => !!v)
59
- .map((p) => `[${p}]`)
60
- .join(' ')
61
-
62
- export const createLogger = (config: Partial<LoggerConfig>) => {
63
- const _config = mergeConfig<LoggerConfig>(
64
- {
65
- level: LogLevelName.Debug,
66
- pfx: [''],
67
- },
68
- config,
69
- )
70
- const { pfx } = _config
71
-
72
- const setLevel = (level: LogLevelName) => {
73
- _config.level = level
74
- }
75
-
76
- const _pfx = (s: string) => namespace(s, ...pfx)
77
-
78
- const _log = (levelIn: LogLevelName, ...args: any[]) => {
79
- doLogAction({
80
- currentLevel: _config.level,
81
- levelIn,
82
- args,
83
- })
84
- }
85
-
86
- const raw = (...args: any[]) => {
87
- _log(LogLevelName.Raw, _pfx('RAW'), ...args)
88
- }
89
-
90
- const trace = (...args: any[]) => {
91
- _log(LogLevelName.Trace, _pfx(`TRACE`), ...args)
92
- }
93
-
94
- const dbg = (...args: any[]) => {
95
- _log(LogLevelName.Debug, _pfx(chalk.blueBright('DBG')), ...args)
96
- }
97
-
98
- const info = (...args: any[]) => {
99
- const _args = (() => {
100
- if (isLevelGt(LogLevelName.Info, _config.level)) {
101
- return [_pfx(chalk.gray(`INFO`)), ...args]
102
- }
103
- return [...args]
104
- })()
105
- _log(
106
- LogLevelName.Info,
107
-
108
- ..._args,
109
- )
110
- }
111
-
112
- const warn = (...args: any[]) => {
113
- _log(
114
- LogLevelName.Warn,
115
- _pfx(chalk.yellow(chalk.cyanBright('WARN'))),
116
- ...args,
117
- )
118
- }
119
-
120
- const error = (...args: any[]) => {
121
- _log(LogLevelName.Error, ...[_pfx(chalk.bgRed(`ERROR`)), ...args])
122
- }
123
-
124
- const criticalError = (...args: any[]) => {
125
- _log(LogLevelName.Error, ...[_pfx(chalk.bgRed(`ERROR`)), ...args])
126
- new Error().stack?.split(/\n/).forEach((line) => {
127
- _log(LogLevelName.Debug, _pfx(chalk.bgRed(`ERROR`)), line)
128
- })
129
- }
130
-
131
- const abort = (...args: any[]): never => {
132
- _log(LogLevelName.Abort, true, ...[_pfx(chalk.bgRed(`ABORT`)), ...args])
133
- throw new Error(`Fatal error: ${stringify(args)}`)
134
- }
135
-
136
- const create = (s: string, configOverride?: Partial<LoggerConfig>) =>
137
- createLogger({
138
- ..._config,
139
- ...configOverride,
140
- pfx: [..._config.pfx, s],
141
- })
142
-
143
- const breadcrumb = (s: string) => {
144
- pfx.push(s)
145
- return api
146
- }
147
-
148
- // Compatibility func
149
- const child = (extra: any) => create(stringify(extra))
150
-
151
- const api = {
152
- raw,
153
- dbg,
154
- warn,
155
- info,
156
- error,
157
- criticalError,
158
- create,
159
- child,
160
- trace,
161
- debug: dbg,
162
- breadcrumb,
163
- abort,
164
- shutdown() {
165
- dbg(`Logger shutting down`)
166
- },
167
- setLevel,
168
- }
169
- return api
170
- }
171
-
172
- export const LoggerService = mkSingleton((config: Partial<LoggerConfig> = {}) =>
173
- createLogger(config),
174
- )
@@ -1,49 +0,0 @@
1
- export type Deallocator = () => void
2
-
3
- export type Allocator<T> = {
4
- free: (item: T) => void
5
- alloc: () => [T, Deallocator]
6
- }
7
-
8
- export function ResourceAllocator<T>(
9
- initialPoolSize: number,
10
- initializer: () => T,
11
- ): Allocator<T> {
12
- // Available queue to hold resolved items of type T
13
- const available: T[] = []
14
-
15
- // Function to add an item back to the available queue
16
- const free = (item: T) => {
17
- available.push(item)
18
- }
19
-
20
- // Pre-populate the available queue with initial items
21
- for (let i = 0; i < initialPoolSize; i++) {
22
- available.push(initializer())
23
- }
24
-
25
- return {
26
- alloc() {
27
- if (available.length === 0) {
28
- available.push(initializer())
29
- }
30
- const newItem = initializer()
31
- return [newItem, () => free(newItem)]
32
- },
33
- free,
34
- }
35
- }
36
-
37
- /*
38
- // Example Usage
39
- const allocator = PromiseAllocator(2, async () => {
40
- return new Promise<number>((resolve) => {
41
- setTimeout(() => resolve(Math.random()), 1000);
42
- });
43
- });
44
-
45
- allocator.alloc().then(([num, freeFunc]) => {
46
- console.log(num); // e.g. 0.123456789
47
- freeFunc(); // Adds the number back to the available queue
48
- });
49
- */
@@ -1,64 +0,0 @@
1
- import { forEach, values } from '@s-libs/micro-dash'
2
- import { LoggerService } from '.'
3
-
4
- export type UnixTimestampMs = number
5
- export type TimerCanceler = () => void
6
-
7
- export type RepeatableTimerCallback = () => boolean | Promise<boolean>
8
- export type TimerCallback = () => void | Promise<void>
9
- export type TimeManagerConfig = {}
10
-
11
- export type TimeManager = ReturnType<typeof createTimerManager>
12
-
13
- export const createTimerManager = (config?: Partial<TimeManagerConfig>) => {
14
- const { dbg, error } = LoggerService().create(`timerManager`)
15
- let i = 0
16
- const cleanups: any = {}
17
- let isShutDown = false
18
-
19
- const add = (cb: TimerCallback, ms: UnixTimestampMs) => {
20
- if (isShutDown) throw new Error(`Already shut down`)
21
- const idx = i++
22
- const tid = setTimeout(async () => {
23
- cancel()
24
- try {
25
- await cb()
26
- } catch (e) {
27
- error(e)
28
- }
29
- }, ms)
30
- const cancel = () => {
31
- clearTimeout(tid)
32
- delete cleanups[idx]
33
- }
34
- cleanups[idx] = cancel
35
- return cancel
36
- }
37
-
38
- const shutdown = () => {
39
- isShutDown = true
40
-
41
- dbg(`Canceling ${values(cleanups.length).length} timers`)
42
- forEach(cleanups, (c) => c())
43
- dbg(`done`, cleanups)
44
- }
45
-
46
- const repeat = (
47
- cb: RepeatableTimerCallback,
48
- ms: UnixTimestampMs,
49
- initial = true,
50
- ) => {
51
- let _unsub: TimerCanceler | undefined = undefined
52
- const _again = async () => {
53
- const shouldRepeat = await cb()
54
- if (shouldRepeat && !isShutDown) _unsub = add(_again, ms)
55
- }
56
- add(_again, initial ? 0 : ms)
57
- return () => {
58
- _unsub?.()
59
- _unsub = undefined
60
- }
61
- }
62
-
63
- return { add, shutdown, repeat }
64
- }
@@ -1,26 +0,0 @@
1
- export function assertExists<TType>(
2
- v: TType,
3
- message = `Value does not exist`,
4
- ): asserts v is NonNullable<TType> {
5
- if (typeof v === 'undefined') {
6
- throw new Error(message)
7
- }
8
- }
9
-
10
- export function assertTruthy<TType>(
11
- v: unknown,
12
- message = `Value should be truthy`,
13
- ): asserts v is NonNullable<TType> {
14
- if (!v) {
15
- throw new Error(message)
16
- }
17
- }
18
-
19
- export function assert<T>(
20
- v: T | undefined | void | null,
21
- msg?: string,
22
- ): asserts v is T {
23
- if (!v) {
24
- throw new Error(msg || `Assertion failure`)
25
- }
26
- }
@@ -1,8 +0,0 @@
1
- import { boolean } from 'boolean'
2
-
3
- export const IS_DEV = () =>
4
- `PH_DEV` in process.env
5
- ? boolean(process.env.PH_DEV)
6
- : process.env.NODE_ENV === 'development'
7
- export const DEBUG = () =>
8
- `PH_DEBUG` in process.env ? boolean(process.env.PH_DEBUG) : IS_DEV()
@@ -1,16 +0,0 @@
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
- }
@@ -1,53 +0,0 @@
1
- import { values } from '@s-libs/micro-dash'
2
-
3
- export type Unsubscribe = () => void
4
-
5
- export type EventSubscriber<TPayload> = (
6
- cb: EventHandler<TPayload>,
7
- ) => Unsubscribe
8
- export type EventEmitter<TPayload> = (
9
- payload: TPayload,
10
- stopOnHandled?: boolean,
11
- ) => Promise<boolean>
12
- export type EventHandler<TPayload> = (
13
- payload: TPayload,
14
- isHandled: boolean,
15
- ) => boolean | void | Promise<boolean | void>
16
-
17
- /**
18
- * @param defaultHandler Optional handler to call if no handler calls
19
- * `handled()`
20
- * @returns Void
21
- */
22
- export const createEvent = <TPayload>(
23
- defaultHandler?: EventHandler<TPayload>,
24
- ): [EventSubscriber<TPayload>, EventEmitter<TPayload>] => {
25
- let i = 0
26
- const callbacks: any = {}
27
- let callbacksArray: EventHandler<TPayload>[] = []
28
- const onEvent = (cb: EventHandler<TPayload>) => {
29
- const id = i++
30
- callbacks[id] = cb
31
- callbacksArray = values(callbacks)
32
- return () => {
33
- delete callbacks[id]
34
- }
35
- }
36
-
37
- const fireEvent = async (payload: TPayload, stopOnHandled = false) => {
38
- let _handled = false
39
- for (let i = 0; i < callbacksArray.length; i++) {
40
- const cb = callbacksArray[i]
41
- if (!cb) continue
42
- const res: boolean = !!(await cb(payload, _handled))
43
- _handled = _handled || res
44
- if (stopOnHandled && _handled) break
45
- }
46
- if (!_handled) {
47
- await defaultHandler?.(payload, false)
48
- }
49
- return _handled
50
- }
51
-
52
- return [onEvent, fireEvent]
53
- }
@@ -1,12 +0,0 @@
1
- export * from './CleanupManager'
2
- export * from './Logger'
3
- export * from './TimerManager'
4
- export * from './assert'
5
- export * from './debug'
6
- export * from './error'
7
- export * from './events'
8
- export * from './mergeConfig'
9
- export * from './mkSingleton'
10
- export * from './plugin'
11
- export * from './promiseSerializer'
12
- export * from './schema'
@@ -1,27 +0,0 @@
1
- /**
2
- * Merges a config object with defaults. Shallow copies root descendants,
3
- * skipping`undefined` values.
4
- *
5
- * @param defaultConfig The default config values
6
- * @param partialConfigs A partial config to merge with defaults
7
- * @returns
8
- */
9
- export function mergeConfig<T>(
10
- defaultConfig: T,
11
- ...partialConfigs: Partial<T>[]
12
- ): T {
13
- const result: T = { ...defaultConfig }
14
-
15
- for (const partialConfig of partialConfigs) {
16
- for (const key in partialConfig) {
17
- if (Object.prototype.hasOwnProperty.call(partialConfig, key)) {
18
- const value = partialConfig[key as keyof typeof partialConfig]
19
- if (value !== undefined) {
20
- result[key as keyof T] = value as T[keyof T]
21
- }
22
- }
23
- }
24
- }
25
-
26
- return result
27
- }
@@ -1,28 +0,0 @@
1
- export type SingletonApi = Object
2
-
3
- export type SingletonBaseConfig = {}
4
-
5
- export function mkSingleton<TConfig, TInstance>(
6
- factory: (config: TConfig) => TInstance,
7
- ): (config?: TConfig) => TInstance {
8
- let instance: TInstance | undefined
9
-
10
- return (config?: TConfig): TInstance => {
11
- if (instance && config) {
12
- console.warn('Attempted to initialize service twice.')
13
- console.warn(new Error().stack)
14
- return instance
15
- }
16
-
17
- if (!instance && !config) {
18
- console.warn(new Error().stack)
19
- throw new Error('Attempted to use service before initialization.')
20
- }
21
-
22
- if (!instance) {
23
- instance = factory(config as TConfig)
24
- }
25
-
26
- return instance
27
- }
28
- }