@pikku/core 0.7.0 → 0.7.2
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 +12 -0
- package/dist/channel/channel-runner.js +1 -1
- package/dist/channel/serverless/serverless-channel-runner.js +1 -1
- package/dist/function/function-runner.js +7 -5
- package/dist/http/http-runner.js +4 -2
- package/dist/http/log-http-routes.js +1 -1
- package/lcov.info +4596 -0
- package/package.json +1 -1
- package/src/channel/channel-handler.ts +165 -0
- package/src/channel/channel-runner.ts +153 -0
- package/src/channel/channel-store.ts +29 -0
- package/src/channel/channel.types.ts +133 -0
- package/src/channel/eventhub-service.ts +30 -0
- package/src/channel/eventhub-store.ts +8 -0
- package/src/channel/index.ts +8 -0
- package/src/channel/local/index.ts +3 -0
- package/src/channel/local/local-channel-handler.ts +50 -0
- package/src/channel/local/local-channel-runner.test.ts +157 -0
- package/src/channel/local/local-channel-runner.ts +139 -0
- package/src/channel/local/local-eventhub-service.test.ts +95 -0
- package/src/channel/local/local-eventhub-service.ts +95 -0
- package/src/channel/log-channels.ts +20 -0
- package/src/channel/pikku-abstract-channel-handler.test.ts +52 -0
- package/src/channel/pikku-abstract-channel-handler.ts +38 -0
- package/src/channel/serverless/index.ts +1 -0
- package/src/channel/serverless/serverless-channel-runner.ts +220 -0
- package/src/errors/error-handler.ts +61 -0
- package/src/errors/error.test.ts +54 -0
- package/src/errors/errors.ts +339 -0
- package/src/errors/index.ts +2 -0
- package/src/function/function-runner.ts +92 -0
- package/src/function/functions.types.ts +77 -0
- package/src/function/index.ts +2 -0
- package/src/handle-error.ts +73 -0
- package/src/http/http-runner.test.ts +140 -0
- package/src/http/http-runner.ts +493 -0
- package/src/http/http.types.ts +250 -0
- package/src/http/incomingmessage-to-request-convertor.ts +0 -0
- package/src/http/index.ts +8 -0
- package/src/http/log-http-routes.ts +22 -0
- package/src/http/pikku-fetch-http-request.test.ts +237 -0
- package/src/http/pikku-fetch-http-request.ts +163 -0
- package/src/http/pikku-fetch-http-response.test.ts +82 -0
- package/src/http/pikku-fetch-http-response.ts +138 -0
- package/src/index.ts +20 -0
- package/src/middleware/auth-apikey.ts +66 -0
- package/src/middleware/auth-bearer.ts +66 -0
- package/src/middleware/auth-cookie.ts +103 -0
- package/src/middleware/index.ts +3 -0
- package/src/middleware/timeout.ts +13 -0
- package/src/middleware-runner.ts +43 -0
- package/src/permissions.test.ts +58 -0
- package/src/permissions.ts +43 -0
- package/src/pikku-function.ts +1 -0
- package/src/pikku-request.ts +23 -0
- package/src/pikku-response.ts +5 -0
- package/src/pikku-state.ts +87 -0
- package/src/scheduler/index.ts +5 -0
- package/src/scheduler/log-schedulers.ts +20 -0
- package/src/scheduler/scheduler-runner.ts +105 -0
- package/src/scheduler/scheduler.types.ts +33 -0
- package/src/schema.test.ts +57 -0
- package/src/schema.ts +99 -0
- package/src/services/content-service.ts +68 -0
- package/src/services/index.ts +18 -0
- package/src/services/jwt-service.ts +30 -0
- package/src/services/local-content.ts +105 -0
- package/src/services/local-secrets.ts +43 -0
- package/src/services/local-variables.ts +17 -0
- package/src/services/logger-console.ts +97 -0
- package/src/services/logger.ts +57 -0
- package/src/services/schema-service.ts +26 -0
- package/src/services/secret-service.ts +17 -0
- package/src/services/user-session-service.ts +53 -0
- package/src/services/variables-service.ts +6 -0
- package/src/time-utils.test.ts +56 -0
- package/src/time-utils.ts +32 -0
- package/src/types/core.types.ts +178 -0
- package/src/utils.ts +40 -0
- package/tsconfig.json +13 -0
- package/tsconfig.tsbuildinfo +1 -0
- package/dist/http/http-route-runner.d.ts +0 -90
- package/dist/http/http-route-runner.js +0 -325
- package/dist/http/http-routes.types.d.ts +0 -179
- package/dist/http/http-routes.types.js +0 -1
- package/dist/http/pikku-http-request.d.ts +0 -56
- package/dist/http/pikku-http-request.js +0 -95
- package/dist/http/pikku-http-response.d.ts +0 -13
- package/dist/http/pikku-http-response.js +0 -60
- package/dist/parse-relative-time-offset.d.ts +0 -12
- package/dist/parse-relative-time-offset.js +0 -20
- package/dist/pikku-func.d.ts +0 -12
- package/dist/pikku-func.js +0 -39
- package/dist/types/functions.types.d.ts +0 -37
- package/dist/types/functions.types.js +0 -1
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { Logger, LogLevel } from './logger.js'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* A logger implementation that logs messages to the console.
|
|
5
|
+
*/
|
|
6
|
+
export class ConsoleLogger implements Logger {
|
|
7
|
+
/**
|
|
8
|
+
* The current logging level.
|
|
9
|
+
*/
|
|
10
|
+
private level: LogLevel = LogLevel.info
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Sets the logging level.
|
|
14
|
+
* @param level - The logging level to set.
|
|
15
|
+
*/
|
|
16
|
+
setLevel(level: LogLevel): void {
|
|
17
|
+
this.level = level
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Logs a trace message.
|
|
22
|
+
* @param message - The message to log.
|
|
23
|
+
* @param meta - Additional metadata to log.
|
|
24
|
+
*/
|
|
25
|
+
trace?(message: string, ...meta: any[]): void {
|
|
26
|
+
if (this.level <= LogLevel.trace) {
|
|
27
|
+
console.trace('TRACE:', message, ...meta)
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Logs a debug message.
|
|
33
|
+
* @param message - The message to log.
|
|
34
|
+
* @param meta - Additional metadata to log.
|
|
35
|
+
*/
|
|
36
|
+
debug(message: string, ...meta: any[]): void {
|
|
37
|
+
if (this.level <= LogLevel.debug) {
|
|
38
|
+
console.debug('DEBUG:', message, ...meta)
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Logs an informational message.
|
|
44
|
+
* @param messageOrObj - The message or object to log.
|
|
45
|
+
* @param meta - Additional metadata to log.
|
|
46
|
+
*/
|
|
47
|
+
info(messageOrObj: string | Record<string, any>, ...meta: any[]): void {
|
|
48
|
+
if (this.level <= LogLevel.info) {
|
|
49
|
+
console.info('INFO:', messageOrObj, ...meta)
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Logs a warning message.
|
|
55
|
+
* @param messageOrObj - The message or object to log.
|
|
56
|
+
* @param meta - Additional metadata to log.
|
|
57
|
+
*/
|
|
58
|
+
warn(messageOrObj: string | Record<string, any>, ...meta: any[]): void {
|
|
59
|
+
if (this.level <= LogLevel.warn) {
|
|
60
|
+
console.warn('WARN:', messageOrObj, ...meta)
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Logs an error message.
|
|
66
|
+
* @param messageOrObj - The message, object, or error to log.
|
|
67
|
+
* @param meta - Additional metadata to log.
|
|
68
|
+
*/
|
|
69
|
+
error(
|
|
70
|
+
messageOrObj: string | Record<string, any> | Error,
|
|
71
|
+
...meta: any[]
|
|
72
|
+
): void {
|
|
73
|
+
if (this.level <= LogLevel.error) {
|
|
74
|
+
console.error(
|
|
75
|
+
'ERROR:',
|
|
76
|
+
messageOrObj instanceof Error ? messageOrObj.message : messageOrObj,
|
|
77
|
+
...meta
|
|
78
|
+
)
|
|
79
|
+
if (messageOrObj instanceof Error) {
|
|
80
|
+
console.error('STACK:', messageOrObj.stack)
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Logs a message at a specified level.
|
|
87
|
+
* @param level - The logging level.
|
|
88
|
+
* @param message - The message to log.
|
|
89
|
+
* @param meta - Additional metadata to log.
|
|
90
|
+
*/
|
|
91
|
+
log(level: string, message: string, ...meta: any[]): void {
|
|
92
|
+
const logLevel = LogLevel[level as keyof typeof LogLevel]
|
|
93
|
+
if (this.level <= logLevel) {
|
|
94
|
+
console.log(`${level.toUpperCase()}:`, message, ...meta)
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
export enum LogLevel {
|
|
2
|
+
'trace', // Add this level
|
|
3
|
+
'debug',
|
|
4
|
+
'info',
|
|
5
|
+
'warn',
|
|
6
|
+
'error',
|
|
7
|
+
'critical',
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Interface for logging messages at various levels.
|
|
12
|
+
*/
|
|
13
|
+
export interface Logger {
|
|
14
|
+
/**
|
|
15
|
+
* Logs an informational message.
|
|
16
|
+
* @param messageOrObj - The message or object to log.
|
|
17
|
+
* @param meta - Additional metadata to log.
|
|
18
|
+
*/
|
|
19
|
+
info(messageOrObj: string | Record<string, any>, ...meta: any[]): void
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Logs a warning message.
|
|
23
|
+
* @param messageOrObj - The message or object to log.
|
|
24
|
+
* @param meta - Additional metadata to log.
|
|
25
|
+
*/
|
|
26
|
+
warn(messageOrObj: string | Record<string, any>, ...meta: any[]): void
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Logs an error message.
|
|
30
|
+
* @param messageOrObj - The message, object, or error to log.
|
|
31
|
+
* @param meta - Additional metadata to log.
|
|
32
|
+
*/
|
|
33
|
+
error(
|
|
34
|
+
messageOrObj: string | Record<string, any> | Error,
|
|
35
|
+
...meta: any[]
|
|
36
|
+
): void
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Logs a debug message.
|
|
40
|
+
* @param message - The message to log.
|
|
41
|
+
* @param meta - Additional metadata to log.
|
|
42
|
+
*/
|
|
43
|
+
debug(message: string, ...meta: any[]): void
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Logs a trace message.
|
|
47
|
+
* @param message - The message to log.
|
|
48
|
+
* @param meta - Additional metadata to log.
|
|
49
|
+
*/
|
|
50
|
+
trace?(message: string, ...meta: any[]): void
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Sets the logging level.
|
|
54
|
+
* @param level - The logging level to set.
|
|
55
|
+
*/
|
|
56
|
+
setLevel(level: LogLevel): void
|
|
57
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interface for a schema service that handles schema compilation, validation, and management.
|
|
3
|
+
*/
|
|
4
|
+
export interface SchemaService {
|
|
5
|
+
/**
|
|
6
|
+
* Compiles a schema with the provided name and value, making it available for use.
|
|
7
|
+
* @param {string} name - The unique name for the schema.
|
|
8
|
+
* @param {any} value - The schema definition or configuration to be compiled.
|
|
9
|
+
* @returns {Promise<void> | void} A promise if asynchronous, or void if synchronous.
|
|
10
|
+
*/
|
|
11
|
+
compileSchema: (name: string, value: any) => Promise<void> | void
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Validates data against a specified schema.
|
|
15
|
+
* @param {string} schema - The name of the schema to validate against.
|
|
16
|
+
* @param {any} data - The data to validate against the schema.
|
|
17
|
+
* @returns {Promise<void> | void} A promise if asynchronous, or void if synchronous.
|
|
18
|
+
*/
|
|
19
|
+
validateSchema: (schema: string, data: any) => Promise<void> | void
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Retrieves a set of all registered schema names.
|
|
23
|
+
* @returns {Set<string>} A set containing the names of all available schemas.
|
|
24
|
+
*/
|
|
25
|
+
getSchemaNames: () => Set<string>
|
|
26
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interface for retrieving secrets.
|
|
3
|
+
*/
|
|
4
|
+
export interface SecretService {
|
|
5
|
+
/**
|
|
6
|
+
* Retrieves a secret by key.
|
|
7
|
+
* @param key - The key of the secret to retrieve.
|
|
8
|
+
* @returns A promise that resolves to the secret value.
|
|
9
|
+
*/
|
|
10
|
+
getSecretJSON<Return = {}>(key: string): Promise<Return>
|
|
11
|
+
/**
|
|
12
|
+
* Retrieves a secret by key.
|
|
13
|
+
* @param key - The key of the secret to retrieve.
|
|
14
|
+
* @returns A promise that resolves to the secret value.
|
|
15
|
+
*/
|
|
16
|
+
getSecret(key: string): Promise<string>
|
|
17
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { ChannelStore } from '../channel/channel-store.js'
|
|
2
|
+
import { CoreUserSession } from '../types/core.types.js'
|
|
3
|
+
|
|
4
|
+
export interface UserSessionService<UserSession extends CoreUserSession> {
|
|
5
|
+
sessionChanged: boolean
|
|
6
|
+
setInitial(session: UserSession): void
|
|
7
|
+
set(session: UserSession): Promise<void> | void
|
|
8
|
+
clear(): Promise<void> | void
|
|
9
|
+
get(): Promise<UserSession | undefined> | UserSession | undefined
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export class PikkuUserSessionService<UserSession extends CoreUserSession>
|
|
13
|
+
implements UserSessionService<UserSession>
|
|
14
|
+
{
|
|
15
|
+
public sessionChanged = false
|
|
16
|
+
private session: UserSession | undefined
|
|
17
|
+
constructor(
|
|
18
|
+
private channelStore?: ChannelStore<unknown, unknown, UserSession>,
|
|
19
|
+
private channelId?: string
|
|
20
|
+
) {
|
|
21
|
+
if (channelStore && !channelId) {
|
|
22
|
+
throw new Error('Channel ID is required when using channel store')
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
public setInitial(session: UserSession) {
|
|
27
|
+
this.session = session
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
public set(session: UserSession) {
|
|
31
|
+
this.sessionChanged = true
|
|
32
|
+
this.session = session
|
|
33
|
+
return this.channelStore?.setUserSession(this.channelId!, session)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
public clear() {
|
|
37
|
+
this.sessionChanged = true
|
|
38
|
+
this.session = undefined
|
|
39
|
+
return this.channelStore?.setUserSession(this.channelId!, null)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
public get(): Promise<UserSession> | UserSession | undefined {
|
|
43
|
+
if (this.channelStore) {
|
|
44
|
+
const channel = this.channelStore.getChannelAndSession(this.channelId!)
|
|
45
|
+
if (channel instanceof Promise) {
|
|
46
|
+
return channel.then(({ session }) => session)
|
|
47
|
+
} else {
|
|
48
|
+
return channel.session
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return this.session
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { describe, test } from 'node:test'
|
|
2
|
+
import assert from 'node:assert/strict'
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
getRelativeTimeOffset,
|
|
6
|
+
getRelativeTimeOffsetFromNow,
|
|
7
|
+
RelativeTimeInput,
|
|
8
|
+
} from './time-utils'
|
|
9
|
+
|
|
10
|
+
const approxEqual = (a: number, b: number, delta: number = 10): boolean =>
|
|
11
|
+
Math.abs(a - b) <= delta
|
|
12
|
+
|
|
13
|
+
describe('Time Utils', () => {
|
|
14
|
+
const offsetCases: Array<{ input: RelativeTimeInput; expected: number }> = [
|
|
15
|
+
{ input: { value: 1, unit: 'second' }, expected: 1000 },
|
|
16
|
+
{ input: { value: 2, unit: 'minute' }, expected: 120000 },
|
|
17
|
+
{ input: { value: 1.5, unit: 'hour' }, expected: 5400000 },
|
|
18
|
+
{ input: { value: -1, unit: 'day' }, expected: -86400000 },
|
|
19
|
+
{ input: { value: 1, unit: 'week' }, expected: 604800000 },
|
|
20
|
+
{
|
|
21
|
+
input: { value: 2, unit: 'year' },
|
|
22
|
+
expected: Math.round(2 * 365.25 * 86400 * 1000),
|
|
23
|
+
},
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
describe('getRelativeTimeOffset', () => {
|
|
27
|
+
for (const { input, expected } of offsetCases) {
|
|
28
|
+
test(`returns ${expected} ms for ${input.value} ${input.unit}`, () => {
|
|
29
|
+
const actual = getRelativeTimeOffset(input)
|
|
30
|
+
assert.strictEqual(actual, expected)
|
|
31
|
+
})
|
|
32
|
+
}
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
describe('getRelativeTimeOffsetFromNow', () => {
|
|
36
|
+
test('returns a Date ~1 minute in the future', () => {
|
|
37
|
+
const now = Date.now()
|
|
38
|
+
const result = getRelativeTimeOffsetFromNow({ value: 1, unit: 'minute' })
|
|
39
|
+
const delta = result.getTime() - now
|
|
40
|
+
assert.ok(
|
|
41
|
+
approxEqual(delta, 60000),
|
|
42
|
+
`Expected ~60000ms ahead, got ${delta}ms`
|
|
43
|
+
)
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
test('returns a Date ~2 hours in the past', () => {
|
|
47
|
+
const now = Date.now()
|
|
48
|
+
const result = getRelativeTimeOffsetFromNow({ value: -2, unit: 'hour' })
|
|
49
|
+
const delta = now - result.getTime()
|
|
50
|
+
assert.ok(
|
|
51
|
+
approxEqual(delta, 7200000),
|
|
52
|
+
`Expected ~7200000ms ago, got ${delta}ms`
|
|
53
|
+
)
|
|
54
|
+
})
|
|
55
|
+
})
|
|
56
|
+
})
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
type TimeUnit = 'second' | 'minute' | 'hour' | 'day' | 'week' | 'year'
|
|
2
|
+
|
|
3
|
+
export interface RelativeTimeInput {
|
|
4
|
+
value: number // negative = in the past
|
|
5
|
+
unit: TimeUnit
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const multipliers: Record<TimeUnit, number> = {
|
|
9
|
+
second: 1,
|
|
10
|
+
minute: 60,
|
|
11
|
+
hour: 60 * 60,
|
|
12
|
+
day: 60 * 60 * 24,
|
|
13
|
+
week: 60 * 60 * 24 * 7,
|
|
14
|
+
year: Math.round(365.25 * 60 * 60 * 24),
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const getRelativeTimeOffset = ({
|
|
18
|
+
value,
|
|
19
|
+
unit,
|
|
20
|
+
}: RelativeTimeInput): number => {
|
|
21
|
+
return Math.round(value * multipliers[unit]) * 1000 // convert to milliseconds
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Returns a Unix timestamp (in seconds) offset from now by the given duration.
|
|
26
|
+
* e.g. value = -1 and unit = 'day' => 1 day ago => now - 86400 seconds
|
|
27
|
+
*/
|
|
28
|
+
export const getRelativeTimeOffsetFromNow = (
|
|
29
|
+
relativeTime: RelativeTimeInput
|
|
30
|
+
): Date => {
|
|
31
|
+
return new Date(Date.now() + getRelativeTimeOffset(relativeTime))
|
|
32
|
+
}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import type { Logger, LogLevel } from '../services/logger.js'
|
|
2
|
+
import { VariablesService } from '../services/variables-service.js'
|
|
3
|
+
import { EventHubService } from '../channel/eventhub-service.js'
|
|
4
|
+
import { SchemaService } from '../services/schema-service.js'
|
|
5
|
+
import { PikkuHTTP } from '../http/http.types.js'
|
|
6
|
+
import { UserSessionService } from '../services/user-session-service.js'
|
|
7
|
+
import { JWTService } from '../services/jwt-service.js'
|
|
8
|
+
import { SecretService } from '../services/secret-service.js'
|
|
9
|
+
import { PikkuChannel } from '../channel/channel.types.js'
|
|
10
|
+
|
|
11
|
+
export interface FunctionServicesMeta {
|
|
12
|
+
optimized: boolean
|
|
13
|
+
services: string[]
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export type FunctionsMeta = Record<
|
|
17
|
+
string,
|
|
18
|
+
{
|
|
19
|
+
pikkuFuncName: string
|
|
20
|
+
name?: string
|
|
21
|
+
services: FunctionServicesMeta
|
|
22
|
+
schemaName: string | null
|
|
23
|
+
inputs: string[] | null
|
|
24
|
+
outputs: string[] | null
|
|
25
|
+
}
|
|
26
|
+
>
|
|
27
|
+
|
|
28
|
+
export type MakeRequired<T, K extends keyof T> = Omit<T, K> &
|
|
29
|
+
Required<Pick<T, K>>
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Represents a JSON primitive type which can be a string, number, boolean, null, or undefined.
|
|
33
|
+
*/
|
|
34
|
+
export type JSONPrimitive = string | number | boolean | null | undefined
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Represents a JSON value which can be a primitive, an array, or an object.
|
|
38
|
+
*/
|
|
39
|
+
export type JSONValue =
|
|
40
|
+
| JSONPrimitive
|
|
41
|
+
| JSONValue[]
|
|
42
|
+
| {
|
|
43
|
+
[key: string]: JSONValue
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Utility type for making certain keys required and leaving the rest as optional.
|
|
48
|
+
*/
|
|
49
|
+
export type PickRequired<T, K extends keyof T> = Required<Pick<T, K>> &
|
|
50
|
+
Partial<T>
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Utility type for making certain keys optional while keeping the rest required.
|
|
54
|
+
*/
|
|
55
|
+
export type PickOptional<T, K extends keyof T> = Partial<T> & Pick<T, K>
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Utility type that ensures at least one key in the given type `T` is required.
|
|
59
|
+
*/
|
|
60
|
+
export type RequireAtLeastOne<T> = {
|
|
61
|
+
[K in keyof T]-?: Required<Pick<T, K>> & Partial<Pick<T, Exclude<keyof T, K>>>
|
|
62
|
+
}[keyof T]
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Interface for the core configuration settings of Pikku.
|
|
66
|
+
*/
|
|
67
|
+
export type CoreConfig<Config extends Record<string, unknown> = {}> = {
|
|
68
|
+
/** The log level for the application. */
|
|
69
|
+
logLevel?: LogLevel
|
|
70
|
+
/** Secrets used by the application (optional). */
|
|
71
|
+
secrets?: {}
|
|
72
|
+
} & Config
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Represents a core user session, which can be extended for more specific session information.
|
|
76
|
+
*/
|
|
77
|
+
export interface CoreUserSession {}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Interface for core singleton services provided by Pikku.
|
|
81
|
+
*/
|
|
82
|
+
export interface CoreSingletonServices<Config extends CoreConfig = CoreConfig> {
|
|
83
|
+
/** JWT Service */
|
|
84
|
+
jwt?: JWTService
|
|
85
|
+
/** The schema library used to validate data */
|
|
86
|
+
schema?: SchemaService
|
|
87
|
+
/** The core configuration for the application. */
|
|
88
|
+
config: Config
|
|
89
|
+
/** The logger used by the application. */
|
|
90
|
+
logger: Logger
|
|
91
|
+
/** The variable service to be used */
|
|
92
|
+
variables: VariablesService
|
|
93
|
+
/** The subscription service that is passed to streams */
|
|
94
|
+
eventHub?: EventHubService<unknown>
|
|
95
|
+
/** SecretServce */
|
|
96
|
+
secrets?: SecretService
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Represents different forms of interaction within Pikku and the outside world.
|
|
101
|
+
*/
|
|
102
|
+
export interface PikkuInteraction {
|
|
103
|
+
http?: PikkuHTTP
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* A function that can wrap an interaction and be called before or after
|
|
108
|
+
*/
|
|
109
|
+
export type PikkuMiddleware<
|
|
110
|
+
SingletonServices extends CoreSingletonServices = CoreSingletonServices,
|
|
111
|
+
UserSession extends CoreUserSession = CoreUserSession,
|
|
112
|
+
> = (
|
|
113
|
+
services: SingletonServices & {
|
|
114
|
+
userSession: UserSessionService<UserSession>
|
|
115
|
+
},
|
|
116
|
+
interactions: PikkuInteraction,
|
|
117
|
+
next: () => Promise<void>
|
|
118
|
+
) => Promise<void>
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Represents the core services used by Pikku, including singleton services and the request/response interaction.
|
|
122
|
+
*/
|
|
123
|
+
export type CoreServices<
|
|
124
|
+
SingletonServices = CoreSingletonServices,
|
|
125
|
+
UserSession extends CoreUserSession = CoreUserSession,
|
|
126
|
+
CoreServices extends Record<string, unknown> = {},
|
|
127
|
+
> = SingletonServices &
|
|
128
|
+
PikkuInteraction & {
|
|
129
|
+
userSession?: UserSessionService<UserSession>
|
|
130
|
+
channel?: PikkuChannel<unknown, unknown>
|
|
131
|
+
} & CoreServices
|
|
132
|
+
|
|
133
|
+
export type SessionServices<
|
|
134
|
+
SingletonServices extends CoreSingletonServices = CoreSingletonServices,
|
|
135
|
+
Services = CoreServices<SingletonServices>,
|
|
136
|
+
> = Omit<Services, keyof SingletonServices | keyof PikkuInteraction | 'session'>
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Defines a function type for creating singleton services from the given configuration.
|
|
140
|
+
*/
|
|
141
|
+
export type CreateSingletonServices<
|
|
142
|
+
Config extends CoreConfig,
|
|
143
|
+
SingletonServices extends CoreSingletonServices,
|
|
144
|
+
> = (
|
|
145
|
+
config: Config,
|
|
146
|
+
existingServices?: Partial<SingletonServices>
|
|
147
|
+
) => Promise<SingletonServices>
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Defines a function type for creating session-specific services.
|
|
151
|
+
*/
|
|
152
|
+
export type CreateSessionServices<
|
|
153
|
+
SingletonServices extends CoreSingletonServices = CoreSingletonServices,
|
|
154
|
+
Services extends
|
|
155
|
+
CoreServices<SingletonServices> = CoreServices<SingletonServices>,
|
|
156
|
+
UserSession extends CoreUserSession = CoreUserSession,
|
|
157
|
+
> = (
|
|
158
|
+
services: SingletonServices,
|
|
159
|
+
interaction: PikkuInteraction,
|
|
160
|
+
session: UserSession | undefined
|
|
161
|
+
) => Promise<SessionServices<Services, SingletonServices>>
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Defines a function type for creating config.
|
|
165
|
+
*/
|
|
166
|
+
export type CreateConfig<Config extends CoreConfig> = (
|
|
167
|
+
variables?: VariablesService
|
|
168
|
+
) => Promise<Config>
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Represents the documentation for a route, including summary, description, tags, and errors.
|
|
172
|
+
*/
|
|
173
|
+
export type APIDocs = {
|
|
174
|
+
summary?: string
|
|
175
|
+
description?: string
|
|
176
|
+
tags?: string[]
|
|
177
|
+
errors?: string[]
|
|
178
|
+
}
|
package/src/utils.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { Logger } from './services/logger.js'
|
|
2
|
+
|
|
3
|
+
// TODO: SessionServices probably needs it's own type
|
|
4
|
+
// but is an issue for the future and will be tackled
|
|
5
|
+
// with dependency injection
|
|
6
|
+
export const closeSessionServices = async (
|
|
7
|
+
logger: Logger,
|
|
8
|
+
sessionServices: Record<string, any>
|
|
9
|
+
) => {
|
|
10
|
+
await Promise.all(
|
|
11
|
+
Object.values(sessionServices).map(async (service) => {
|
|
12
|
+
if (service?.close) {
|
|
13
|
+
try {
|
|
14
|
+
await service.close()
|
|
15
|
+
} catch (e: any) {
|
|
16
|
+
logger.error(e)
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
})
|
|
20
|
+
)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export const createWeakUID = () => {
|
|
24
|
+
return Date.now().toString(36) + Math.random().toString(36).substring(2, 10)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export const isSerializable = (data: any): boolean => {
|
|
28
|
+
return !(
|
|
29
|
+
typeof data === 'string' ||
|
|
30
|
+
data instanceof ArrayBuffer ||
|
|
31
|
+
data instanceof Uint8Array ||
|
|
32
|
+
data instanceof Int8Array ||
|
|
33
|
+
data instanceof Uint16Array ||
|
|
34
|
+
data instanceof Int16Array ||
|
|
35
|
+
data instanceof Uint32Array ||
|
|
36
|
+
data instanceof Int32Array ||
|
|
37
|
+
data instanceof Float32Array ||
|
|
38
|
+
data instanceof Float64Array
|
|
39
|
+
)
|
|
40
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "../tsconfig.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"rootDir": "./src",
|
|
5
|
+
"composite": true,
|
|
6
|
+
"module": "Node16",
|
|
7
|
+
"outDir": "dist",
|
|
8
|
+
"target": "esnext",
|
|
9
|
+
"moduleResolution": "node16"
|
|
10
|
+
},
|
|
11
|
+
"exclude": ["**/*.test.ts", "node_modules", "dist"],
|
|
12
|
+
"references": []
|
|
13
|
+
}
|