pockethost 1.7.0 → 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.
- package/CHANGELOG.md +119 -86
- package/README.md +96 -0
- package/dist/cli.js +21542 -0
- package/package.json +55 -55
- package/changesetx.ts +0 -110
- package/common.ts +0 -1
- package/core.ts +0 -1
- package/readme.md +0 -129
- package/src/cli/commands/ConfigCommand/index.ts +0 -28
- package/src/cli/commands/PluginCommand/index.ts +0 -113
- package/src/cli/commands/PluginCommand/plugin-template/package.json +0 -38
- package/src/cli/commands/PluginCommand/plugin-template/readme.md +0 -33
- package/src/cli/commands/PluginCommand/plugin-template/src/constants.ts +0 -22
- package/src/cli/commands/PluginCommand/plugin-template/src/db.ts +0 -30
- package/src/cli/commands/PluginCommand/plugin-template/src/index.ts +0 -3
- package/src/cli/commands/PluginCommand/plugin-template/src/log.ts +0 -5
- package/src/cli/commands/PluginCommand/plugin-template/src/plugin.ts +0 -58
- package/src/cli/commands/PluginCommand/util.ts +0 -140
- package/src/cli/commands/ServeCommand/index.ts +0 -36
- package/src/cli/index.ts +0 -70
- package/src/common/CleanupManager.ts +0 -65
- package/src/common/Logger.ts +0 -174
- package/src/common/ResourceAllocator.ts +0 -49
- package/src/common/TimerManager.ts +0 -64
- package/src/common/assert.ts +0 -26
- package/src/common/debug.ts +0 -8
- package/src/common/error.ts +0 -16
- package/src/common/events.ts +0 -53
- package/src/common/index.ts +0 -12
- package/src/common/mergeConfig.ts +0 -27
- package/src/common/mkSingleton.ts +0 -28
- package/src/common/plugin/action.ts +0 -164
- package/src/common/plugin/filter.ts +0 -197
- package/src/common/plugin/index.ts +0 -21
- package/src/common/promiseSerializer.ts +0 -22
- package/src/common/schema/BaseFields.ts +0 -10
- package/src/common/schema/Instance.ts +0 -46
- package/src/common/schema/InstanceLog.ts +0 -12
- package/src/common/schema/index.ts +0 -3
- package/src/common/schema/util.ts +0 -7
- package/src/constants.ts +0 -70
- package/src/core/Settings.ts +0 -119
- package/src/core/asyncExecutionGuard.ts +0 -49
- package/src/core/config.ts +0 -108
- package/src/core/exit.ts +0 -11
- package/src/core/index.ts +0 -8
- package/src/core/internal.ts +0 -3
- package/src/core/smartFetch.ts +0 -32
- package/src/core/tryFetch.ts +0 -69
- package/src/plugin.ts +0 -54
- package/src/server.ts +0 -129
- /package/{src/cli/commands/PluginCommand/plugin-template/LICENSE.md → LICENSE.md} +0 -0
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
import { Command } from 'commander'
|
|
2
|
-
import { produce } from 'immer'
|
|
3
|
-
import {
|
|
4
|
-
PocketHostPlugin,
|
|
5
|
-
onCliCommandsFilter,
|
|
6
|
-
onInstanceConfigFilter,
|
|
7
|
-
onServeAction,
|
|
8
|
-
onServeSlugsFilter,
|
|
9
|
-
onSettingsFilter,
|
|
10
|
-
} from 'pockethost'
|
|
11
|
-
import {
|
|
12
|
-
PLUGIN_NAME,
|
|
13
|
-
PLUGIN_NAME_CONSTANT_CASE,
|
|
14
|
-
PROJECT_DIR,
|
|
15
|
-
settings,
|
|
16
|
-
} from './constants'
|
|
17
|
-
import { DbService } from './db'
|
|
18
|
-
import { dbg } from './log'
|
|
19
|
-
|
|
20
|
-
export const plugin: PocketHostPlugin = async ({}) => {
|
|
21
|
-
dbg(`initializing ${PLUGIN_NAME}`)
|
|
22
|
-
|
|
23
|
-
await DbService({})
|
|
24
|
-
|
|
25
|
-
onInstanceConfigFilter(async (config) => {
|
|
26
|
-
return produce(config, (draft) => {
|
|
27
|
-
draft.env[`PH_${PLUGIN_NAME_CONSTANT_CASE}_ENABLED`] = true.toString()
|
|
28
|
-
draft.binds.hooks.push({
|
|
29
|
-
src: PROJECT_DIR(`src/instance-app/hooks/**/*`),
|
|
30
|
-
base: PROJECT_DIR(`src/instance-app/hooks`),
|
|
31
|
-
})
|
|
32
|
-
})
|
|
33
|
-
})
|
|
34
|
-
|
|
35
|
-
onCliCommandsFilter(async (commands) => {
|
|
36
|
-
return [
|
|
37
|
-
...commands,
|
|
38
|
-
new Command(PLUGIN_NAME).description(`Command root`).addCommand(
|
|
39
|
-
new Command(`serve`)
|
|
40
|
-
.description(`Run a task`)
|
|
41
|
-
.action(async (options) => {
|
|
42
|
-
// do something
|
|
43
|
-
}),
|
|
44
|
-
),
|
|
45
|
-
]
|
|
46
|
-
})
|
|
47
|
-
|
|
48
|
-
onServeSlugsFilter(async (slugs) => {
|
|
49
|
-
return [...slugs, PLUGIN_NAME]
|
|
50
|
-
})
|
|
51
|
-
|
|
52
|
-
onServeAction(async ({ only }) => {
|
|
53
|
-
if (!only.includes(PLUGIN_NAME)) return
|
|
54
|
-
// Do something
|
|
55
|
-
})
|
|
56
|
-
|
|
57
|
-
onSettingsFilter(async (allSettings) => ({ ...allSettings, ...settings }))
|
|
58
|
-
}
|
|
@@ -1,140 +0,0 @@
|
|
|
1
|
-
import { exec } from 'child_process'
|
|
2
|
-
import fs from 'fs/promises'
|
|
3
|
-
import { Listr, ListrTask } from 'listr2'
|
|
4
|
-
import { createRequire } from 'module'
|
|
5
|
-
import fetch from 'node-fetch'
|
|
6
|
-
import semver from 'semver'
|
|
7
|
-
import util from 'util'
|
|
8
|
-
|
|
9
|
-
const execPromise = util.promisify(exec)
|
|
10
|
-
const require = createRequire(import.meta.url)
|
|
11
|
-
|
|
12
|
-
export async function getPackageJson(packageName: string): Promise<any | null> {
|
|
13
|
-
try {
|
|
14
|
-
const packageJsonPath = require.resolve(`${packageName}/package.json`)
|
|
15
|
-
const packageJson = JSON.parse(await fs.readFile(packageJsonPath, 'utf8'))
|
|
16
|
-
return packageJson
|
|
17
|
-
} catch (error) {
|
|
18
|
-
return null
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export async function fetchPackageData(
|
|
23
|
-
packageName: string,
|
|
24
|
-
): Promise<any | null> {
|
|
25
|
-
const npmRegistryUrl = `https://registry.npmjs.org/${packageName}`
|
|
26
|
-
try {
|
|
27
|
-
const response = await fetch(npmRegistryUrl)
|
|
28
|
-
return await response.json()
|
|
29
|
-
} catch (error) {
|
|
30
|
-
return null
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
async function installPackage(
|
|
35
|
-
packageName: string,
|
|
36
|
-
version: string,
|
|
37
|
-
): Promise<void> {
|
|
38
|
-
try {
|
|
39
|
-
await execPromise(`npm install -g ${packageName}@${version}`)
|
|
40
|
-
} catch (e) {
|
|
41
|
-
throw new Error(`Error installing ${packageName}@${version}: ${e}`)
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export async function removePackage(packageName: string): Promise<void> {
|
|
46
|
-
try {
|
|
47
|
-
await execPromise(`npm remove -g ${packageName}`)
|
|
48
|
-
} catch (e) {
|
|
49
|
-
throw new Error(`Error removing ${packageName}: ${e}`)
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
async function checkPackageCompatibility(
|
|
54
|
-
packageA: string,
|
|
55
|
-
versionA: string,
|
|
56
|
-
packageB: string,
|
|
57
|
-
): Promise<string> {
|
|
58
|
-
const localPackageJson = await getPackageJson(packageB)
|
|
59
|
-
|
|
60
|
-
if (localPackageJson) {
|
|
61
|
-
const { version: localPackageBVersion, dependencies } = localPackageJson
|
|
62
|
-
|
|
63
|
-
if (dependencies && semver.satisfies(versionA, dependencies[packageA])) {
|
|
64
|
-
return `Local ${packageB}@${localPackageBVersion} is already compatible with ${packageA}@${versionA}`
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
const packageBData = await fetchPackageData(packageB)
|
|
69
|
-
if (!packageBData) {
|
|
70
|
-
throw new Error(`Error fetching data for ${packageB}`)
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
const versions = packageBData.versions
|
|
74
|
-
let latestCompatibleVersion: string | null = null
|
|
75
|
-
|
|
76
|
-
for (const version in versions) {
|
|
77
|
-
const dependencies = versions[version].dependencies
|
|
78
|
-
if (
|
|
79
|
-
dependencies &&
|
|
80
|
-
packageA in dependencies &&
|
|
81
|
-
semver.satisfies(versionA, dependencies[packageA])
|
|
82
|
-
) {
|
|
83
|
-
if (
|
|
84
|
-
!latestCompatibleVersion ||
|
|
85
|
-
semver.gt(version, latestCompatibleVersion)
|
|
86
|
-
) {
|
|
87
|
-
latestCompatibleVersion = version
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
if (latestCompatibleVersion) {
|
|
93
|
-
await installPackage(packageB, latestCompatibleVersion)
|
|
94
|
-
return `${packageB}@${latestCompatibleVersion} installed successfully`
|
|
95
|
-
} else {
|
|
96
|
-
throw new Error(
|
|
97
|
-
`No compatible version of ${packageB} found for ${packageA}@${versionA}`,
|
|
98
|
-
)
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
export async function getCompatibleVersions(
|
|
103
|
-
packageA: string,
|
|
104
|
-
versionA: string,
|
|
105
|
-
packagesB: string[],
|
|
106
|
-
): Promise<void> {
|
|
107
|
-
const tasks = packagesB.map(
|
|
108
|
-
(packageB) =>
|
|
109
|
-
({
|
|
110
|
-
title: `Checking ${packageB}...`,
|
|
111
|
-
task: async (_, task) => {
|
|
112
|
-
try {
|
|
113
|
-
const result = await checkPackageCompatibility(
|
|
114
|
-
packageA,
|
|
115
|
-
versionA,
|
|
116
|
-
packageB,
|
|
117
|
-
)
|
|
118
|
-
task.output = result
|
|
119
|
-
} catch (error) {
|
|
120
|
-
task.output = `${error}`
|
|
121
|
-
throw error
|
|
122
|
-
}
|
|
123
|
-
},
|
|
124
|
-
}) as ListrTask,
|
|
125
|
-
)
|
|
126
|
-
|
|
127
|
-
const listr = new Listr(tasks, {
|
|
128
|
-
concurrent: true,
|
|
129
|
-
rendererOptions: { collapseSubtasks: false },
|
|
130
|
-
})
|
|
131
|
-
|
|
132
|
-
await listr.run()
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
// Example usage
|
|
136
|
-
// const packageA = 'express'
|
|
137
|
-
// const versionA = '4.17.1'
|
|
138
|
-
// const packagesB = ['some-package', 'another-package', 'yet-another-package']
|
|
139
|
-
|
|
140
|
-
// getCompatibleVersions(packageA, versionA, packagesB)
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { Command } from 'commander'
|
|
2
|
-
import {
|
|
3
|
-
LoggerService,
|
|
4
|
-
doServeAction,
|
|
5
|
-
doServeSlugsFilter,
|
|
6
|
-
} from '../../../common'
|
|
7
|
-
|
|
8
|
-
type Options = {
|
|
9
|
-
only: string[]
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export const ServeCommand = async () => {
|
|
13
|
-
const serveSlugs = await doServeSlugsFilter([])
|
|
14
|
-
|
|
15
|
-
const cmd = new Command(`serve`)
|
|
16
|
-
.description(`Run PocketHost`)
|
|
17
|
-
.option(
|
|
18
|
-
`-o, --only <only>`,
|
|
19
|
-
`Only run the specified services`,
|
|
20
|
-
(s) =>
|
|
21
|
-
s
|
|
22
|
-
.split(/,/)
|
|
23
|
-
.map((s) => s.trim())
|
|
24
|
-
.filter((s) => serveSlugs.includes(s)),
|
|
25
|
-
serveSlugs,
|
|
26
|
-
)
|
|
27
|
-
.action(async (options: Options, cmd: Command) => {
|
|
28
|
-
const logger = LoggerService().create(`ServeCommand`)
|
|
29
|
-
const { dbg, error, info, warn } = logger
|
|
30
|
-
info(`Starting`)
|
|
31
|
-
|
|
32
|
-
const { only } = options
|
|
33
|
-
await doServeAction({ only })
|
|
34
|
-
})
|
|
35
|
-
return cmd
|
|
36
|
-
}
|
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
|
-
}
|
package/src/common/Logger.ts
DELETED
|
@@ -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
|
-
}
|
package/src/common/assert.ts
DELETED
|
@@ -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
|
-
}
|
package/src/common/debug.ts
DELETED
|
@@ -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()
|
package/src/common/error.ts
DELETED
|
@@ -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
|
-
}
|