@pikku/core 0.12.4 → 0.12.6
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 +21 -1
- package/dist/dev/hot-reload.d.ts +10 -0
- package/dist/dev/hot-reload.js +158 -0
- package/dist/middleware-runner.d.ts +1 -0
- package/dist/middleware-runner.js +5 -0
- package/dist/permissions.d.ts +1 -0
- package/dist/permissions.js +5 -0
- package/dist/services/content-service.d.ts +2 -0
- package/dist/services/in-memory-workflow-service.d.ts +1 -0
- package/dist/services/in-memory-workflow-service.js +16 -11
- package/dist/services/workflow-service.d.ts +1 -0
- package/dist/wirings/ai-agent/ai-agent-prepare.js +16 -1
- package/dist/wirings/channel/channel-middleware-runner.d.ts +1 -0
- package/dist/wirings/channel/channel-middleware-runner.js +5 -0
- package/dist/wirings/http/http-runner.js +1 -1
- package/dist/wirings/workflow/pikku-workflow-service.d.ts +6 -0
- package/dist/wirings/workflow/pikku-workflow-service.js +51 -16
- package/dist/wirings/workflow/workflow.types.d.ts +2 -0
- package/package.json +5 -3
- package/src/crypto-utils.test.ts +214 -0
- package/src/crypto-utils.ts +213 -0
- package/src/dev/hot-reload.test.ts +484 -0
- package/src/dev/hot-reload.ts +212 -0
- package/src/errors/error-handler.ts +62 -0
- package/src/errors/error.test.ts +195 -0
- package/src/errors/errors.ts +374 -0
- package/src/errors/index.ts +2 -0
- package/src/factory-functions.test.ts +109 -0
- package/src/function/function-runner.test.ts +536 -0
- package/src/function/function-runner.ts +365 -0
- package/src/function/functions.types.ts +304 -0
- package/src/function/index.ts +5 -0
- package/src/handle-error.test.ts +424 -0
- package/src/handle-error.ts +69 -0
- package/src/index.ts +118 -0
- package/src/internal.ts +6 -0
- package/src/middleware/auth-apikey.test.ts +363 -0
- package/src/middleware/auth-apikey.ts +47 -0
- package/src/middleware/auth-bearer.test.ts +450 -0
- package/src/middleware/auth-bearer.ts +72 -0
- package/src/middleware/auth-cookie.test.ts +528 -0
- package/src/middleware/auth-cookie.ts +80 -0
- package/src/middleware/cors.test.ts +424 -0
- package/src/middleware/cors.ts +104 -0
- package/src/middleware/index.ts +5 -0
- package/src/middleware/remote-auth.test.ts +488 -0
- package/src/middleware/remote-auth.ts +68 -0
- package/src/middleware/timeout.ts +15 -0
- package/src/middleware-runner.test.ts +418 -0
- package/src/middleware-runner.ts +240 -0
- package/src/permissions.test.ts +434 -0
- package/src/permissions.ts +327 -0
- package/src/pikku-request.ts +23 -0
- package/src/pikku-response.ts +5 -0
- package/src/pikku-state.test.ts +224 -0
- package/src/pikku-state.ts +216 -0
- package/src/run-tests-script.test.ts +49 -0
- package/src/schema.test.ts +249 -0
- package/src/schema.ts +151 -0
- package/src/services/ai-agent-runner-service.ts +41 -0
- package/src/services/ai-run-state-service.ts +20 -0
- package/src/services/ai-storage-service.ts +39 -0
- package/src/services/content-service.ts +81 -0
- package/src/services/deployment-service.ts +22 -0
- package/src/services/gateway-service.ts +20 -0
- package/src/services/gopass-secrets.ts +98 -0
- package/src/services/in-memory-ai-run-state-service.ts +73 -0
- package/src/services/in-memory-trigger-service.ts +64 -0
- package/src/services/in-memory-workflow-service.test.ts +351 -0
- package/src/services/in-memory-workflow-service.ts +512 -0
- package/src/services/index.ts +56 -0
- package/src/services/jwt-service.ts +30 -0
- package/src/services/local-content.ts +120 -0
- package/src/services/local-gateway-service.ts +62 -0
- package/src/services/local-secrets.test.ts +80 -0
- package/src/services/local-secrets.ts +94 -0
- package/src/services/local-variables.test.ts +61 -0
- package/src/services/local-variables.ts +39 -0
- package/src/services/logger-console.test.ts +118 -0
- package/src/services/logger-console.ts +98 -0
- package/src/services/logger.ts +57 -0
- package/src/services/scheduler-service.ts +86 -0
- package/src/services/schema-service.ts +33 -0
- package/src/services/scoped-secret-service.test.ts +74 -0
- package/src/services/scoped-secret-service.ts +41 -0
- package/src/services/secret-service.ts +38 -0
- package/src/services/trigger-service.ts +17 -0
- package/src/services/typed-secret-service.test.ts +93 -0
- package/src/services/typed-secret-service.ts +70 -0
- package/src/services/typed-variables-service.test.ts +73 -0
- package/src/services/typed-variables-service.ts +81 -0
- package/src/services/user-session-service.test.ts +113 -0
- package/src/services/user-session-service.ts +86 -0
- package/src/services/variables-service.ts +11 -0
- package/src/services/workflow-service.ts +96 -0
- package/src/testing/index.ts +2 -0
- package/src/testing/service-tests.ts +873 -0
- package/src/time-utils.test.ts +56 -0
- package/src/time-utils.ts +107 -0
- package/src/types/core.types.ts +478 -0
- package/src/types/state.types.ts +188 -0
- package/src/utils/hash.test.ts +68 -0
- package/src/utils/hash.ts +26 -0
- package/src/utils.test.ts +350 -0
- package/src/utils.ts +129 -0
- package/src/version.test.ts +80 -0
- package/src/version.ts +25 -0
- package/src/wirings/ai-agent/agent-dynamic-workflow.ts +469 -0
- package/src/wirings/ai-agent/ai-agent-helpers.test.ts +152 -0
- package/src/wirings/ai-agent/ai-agent-helpers.ts +76 -0
- package/src/wirings/ai-agent/ai-agent-memory.ts +310 -0
- package/src/wirings/ai-agent/ai-agent-model-config.test.ts +115 -0
- package/src/wirings/ai-agent/ai-agent-model-config.ts +43 -0
- package/src/wirings/ai-agent/ai-agent-prepare.ts +659 -0
- package/src/wirings/ai-agent/ai-agent-registry.test.ts +37 -0
- package/src/wirings/ai-agent/ai-agent-registry.ts +82 -0
- package/src/wirings/ai-agent/ai-agent-runner.test.ts +319 -0
- package/src/wirings/ai-agent/ai-agent-runner.ts +773 -0
- package/src/wirings/ai-agent/ai-agent-stream.test.ts +859 -0
- package/src/wirings/ai-agent/ai-agent-stream.ts +1153 -0
- package/src/wirings/ai-agent/ai-agent.types.ts +382 -0
- package/src/wirings/ai-agent/index.ts +37 -0
- package/src/wirings/channel/channel-common.ts +90 -0
- package/src/wirings/channel/channel-handler.ts +250 -0
- package/src/wirings/channel/channel-middleware-runner.ts +126 -0
- package/src/wirings/channel/channel-runner.ts +166 -0
- package/src/wirings/channel/channel-store.ts +29 -0
- package/src/wirings/channel/channel.types.ts +172 -0
- package/src/wirings/channel/define-channel-routes.ts +25 -0
- package/src/wirings/channel/eventhub-service.ts +34 -0
- package/src/wirings/channel/eventhub-store.ts +13 -0
- package/src/wirings/channel/index.ts +24 -0
- package/src/wirings/channel/local/index.ts +3 -0
- package/src/wirings/channel/local/local-channel-handler.ts +81 -0
- package/src/wirings/channel/local/local-channel-runner.test.ts +215 -0
- package/src/wirings/channel/local/local-channel-runner.ts +210 -0
- package/src/wirings/channel/local/local-eventhub-service.test.ts +95 -0
- package/src/wirings/channel/local/local-eventhub-service.ts +101 -0
- package/src/wirings/channel/log-channels.ts +20 -0
- package/src/wirings/channel/pikku-abstract-channel-handler.test.ts +54 -0
- package/src/wirings/channel/pikku-abstract-channel-handler.ts +45 -0
- package/src/wirings/channel/serverless/index.ts +5 -0
- package/src/wirings/channel/serverless/serverless-channel-runner.ts +289 -0
- package/src/wirings/cli/channel/cli-channel-runner.ts +136 -0
- package/src/wirings/cli/channel/index.ts +1 -0
- package/src/wirings/cli/cli-runner.test.ts +403 -0
- package/src/wirings/cli/cli-runner.ts +529 -0
- package/src/wirings/cli/cli.types.ts +358 -0
- package/src/wirings/cli/command-parser.test.ts +445 -0
- package/src/wirings/cli/command-parser.ts +504 -0
- package/src/wirings/cli/define-cli-commands.ts +24 -0
- package/src/wirings/cli/index.ts +19 -0
- package/src/wirings/gateway/gateway-runner.test.ts +474 -0
- package/src/wirings/gateway/gateway-runner.ts +411 -0
- package/src/wirings/gateway/gateway.types.ts +149 -0
- package/src/wirings/gateway/index.ts +13 -0
- package/src/wirings/http/http-routes.test.ts +322 -0
- package/src/wirings/http/http-routes.ts +197 -0
- package/src/wirings/http/http-runner.test.ts +144 -0
- package/src/wirings/http/http-runner.ts +588 -0
- package/src/wirings/http/http.types.ts +369 -0
- package/src/wirings/http/index.ts +28 -0
- package/src/wirings/http/log-http-routes.ts +22 -0
- package/src/wirings/http/pikku-fetch-http-request.test.ts +237 -0
- package/src/wirings/http/pikku-fetch-http-request.ts +170 -0
- package/src/wirings/http/pikku-fetch-http-response.test.ts +82 -0
- package/src/wirings/http/pikku-fetch-http-response.ts +147 -0
- package/src/wirings/http/routers/http-router.ts +13 -0
- package/src/wirings/http/routers/path-to-regex.test.ts +319 -0
- package/src/wirings/http/routers/path-to-regex.ts +126 -0
- package/src/wirings/http/web-request.test.ts +236 -0
- package/src/wirings/http/web-request.ts +104 -0
- package/src/wirings/mcp/index.ts +27 -0
- package/src/wirings/mcp/mcp-endpoint-registry.test.ts +389 -0
- package/src/wirings/mcp/mcp-endpoint-registry.ts +159 -0
- package/src/wirings/mcp/mcp-runner.ts +323 -0
- package/src/wirings/mcp/mcp.types.ts +216 -0
- package/src/wirings/node/index.ts +2 -0
- package/src/wirings/node/node.types.ts +23 -0
- package/src/wirings/oauth2/index.ts +3 -0
- package/src/wirings/oauth2/oauth2-client.test.ts +929 -0
- package/src/wirings/oauth2/oauth2-client.ts +335 -0
- package/src/wirings/oauth2/oauth2.types.ts +69 -0
- package/src/wirings/oauth2/wire-oauth2-credential.ts +23 -0
- package/src/wirings/queue/index.ts +31 -0
- package/src/wirings/queue/queue-runner.test.ts +710 -0
- package/src/wirings/queue/queue-runner.ts +192 -0
- package/src/wirings/queue/queue.types.ts +189 -0
- package/src/wirings/queue/register-queue-helper.ts +60 -0
- package/src/wirings/queue/validate-worker-config.test.ts +108 -0
- package/src/wirings/queue/validate-worker-config.ts +116 -0
- package/src/wirings/rpc/index.ts +4 -0
- package/src/wirings/rpc/rpc-runner.ts +460 -0
- package/src/wirings/rpc/rpc-types.ts +56 -0
- package/src/wirings/rpc/wire-addon.ts +21 -0
- package/src/wirings/scheduler/index.ts +11 -0
- package/src/wirings/scheduler/log-schedulers.ts +20 -0
- package/src/wirings/scheduler/scheduler-runner.test.ts +660 -0
- package/src/wirings/scheduler/scheduler-runner.ts +133 -0
- package/src/wirings/scheduler/scheduler.types.ts +53 -0
- package/src/wirings/secret/index.ts +9 -0
- package/src/wirings/secret/secret.types.ts +32 -0
- package/src/wirings/secret/validate-secret-definitions.test.ts +140 -0
- package/src/wirings/secret/validate-secret-definitions.ts +82 -0
- package/src/wirings/trigger/index.ts +10 -0
- package/src/wirings/trigger/pikku-trigger-service.ts +112 -0
- package/src/wirings/trigger/trigger-runner.test.ts +79 -0
- package/src/wirings/trigger/trigger-runner.ts +135 -0
- package/src/wirings/trigger/trigger.types.ts +178 -0
- package/src/wirings/variable/index.ts +8 -0
- package/src/wirings/variable/validate-variable-definitions.test.ts +91 -0
- package/src/wirings/variable/validate-variable-definitions.ts +69 -0
- package/src/wirings/variable/variable.types.ts +22 -0
- package/src/wirings/workflow/dsl/index.ts +31 -0
- package/src/wirings/workflow/dsl/workflow-dsl.types.ts +320 -0
- package/src/wirings/workflow/dsl/workflow-runner.ts +28 -0
- package/src/wirings/workflow/graph/graph-node.ts +222 -0
- package/src/wirings/workflow/graph/graph-runner.test.ts +487 -0
- package/src/wirings/workflow/graph/graph-runner.ts +816 -0
- package/src/wirings/workflow/graph/graph-validation.test.ts +170 -0
- package/src/wirings/workflow/graph/graph-validation.ts +237 -0
- package/src/wirings/workflow/graph/index.ts +19 -0
- package/src/wirings/workflow/graph/template.test.ts +49 -0
- package/src/wirings/workflow/graph/template.ts +42 -0
- package/src/wirings/workflow/graph/wire-workflow-graph.ts +29 -0
- package/src/wirings/workflow/graph/workflow-graph.types.ts +104 -0
- package/src/wirings/workflow/index.ts +82 -0
- package/src/wirings/workflow/pikku-workflow-service.test.ts +200 -0
- package/src/wirings/workflow/pikku-workflow-service.ts +1229 -0
- package/src/wirings/workflow/workflow-helpers.test.ts +129 -0
- package/src/wirings/workflow/workflow-helpers.ts +79 -0
- package/src/wirings/workflow/workflow.types.ts +276 -0
- package/tsconfig.json +14 -0
- package/tsconfig.tsbuildinfo +1 -0
- package/lcov.info +0 -18891
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
HTTPFunctionMetaInputTypes,
|
|
3
|
+
PikkuHTTPRequest,
|
|
4
|
+
PikkuHTTPResponse,
|
|
5
|
+
} from '../http/http.types.js'
|
|
6
|
+
import type {
|
|
7
|
+
CorePikkuMiddleware,
|
|
8
|
+
MiddlewareMetadata,
|
|
9
|
+
PermissionMetadata,
|
|
10
|
+
} from '../../types/core.types.js'
|
|
11
|
+
|
|
12
|
+
export type BinaryData = ArrayBuffer | Uint8Array
|
|
13
|
+
|
|
14
|
+
export type CorePikkuChannelMiddleware<Services = any, Event = unknown> = (
|
|
15
|
+
services: Services,
|
|
16
|
+
event: Event,
|
|
17
|
+
next: (event: Event | Event[] | null) => Promise<void> | void
|
|
18
|
+
) => Promise<void> | void
|
|
19
|
+
|
|
20
|
+
export type CorePikkuChannelMiddlewareFactory<
|
|
21
|
+
In = any,
|
|
22
|
+
Services = any,
|
|
23
|
+
Event = unknown,
|
|
24
|
+
> = (input: In) => CorePikkuChannelMiddleware<Services, Event>
|
|
25
|
+
import type {
|
|
26
|
+
CorePermissionGroup,
|
|
27
|
+
CorePikkuFunction,
|
|
28
|
+
CorePikkuFunctionConfig,
|
|
29
|
+
CorePikkuFunctionSessionless,
|
|
30
|
+
CorePikkuPermission,
|
|
31
|
+
} from '../../function/functions.types.js'
|
|
32
|
+
|
|
33
|
+
export type RunChannelOptions = Partial<{
|
|
34
|
+
skipUserSession: boolean
|
|
35
|
+
respondWith404: boolean
|
|
36
|
+
coerceDataFromSchema: boolean
|
|
37
|
+
logWarningsForStatusCodes: number[]
|
|
38
|
+
bubbleErrors: boolean
|
|
39
|
+
}>
|
|
40
|
+
|
|
41
|
+
export type RunChannelParams<ChannelData> = {
|
|
42
|
+
channelId: string
|
|
43
|
+
request?: PikkuHTTPRequest<ChannelData>
|
|
44
|
+
response?: PikkuHTTPResponse
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export interface ChannelMessageMeta {
|
|
48
|
+
pikkuFuncId: string
|
|
49
|
+
packageName?: string
|
|
50
|
+
summary?: string
|
|
51
|
+
description?: string
|
|
52
|
+
errors?: string[]
|
|
53
|
+
tags?: string[]
|
|
54
|
+
middleware?: MiddlewareMetadata[]
|
|
55
|
+
permissions?: PermissionMetadata[]
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export interface ChannelMeta {
|
|
59
|
+
name: string
|
|
60
|
+
route: string
|
|
61
|
+
params?: string[]
|
|
62
|
+
query?: string[]
|
|
63
|
+
input: string | null
|
|
64
|
+
inputTypes?: HTTPFunctionMetaInputTypes
|
|
65
|
+
connect: ChannelMessageMeta | null
|
|
66
|
+
disconnect: ChannelMessageMeta | null
|
|
67
|
+
message: ChannelMessageMeta | null
|
|
68
|
+
messageWirings: Record<string, Record<string, ChannelMessageMeta>>
|
|
69
|
+
binary?: boolean | null
|
|
70
|
+
summary?: string
|
|
71
|
+
description?: string
|
|
72
|
+
errors?: string[]
|
|
73
|
+
tags?: string[]
|
|
74
|
+
middleware?: MiddlewareMetadata[] // Pre-resolved middleware chain (tag + explicit)
|
|
75
|
+
permissions?: PermissionMetadata[] // Pre-resolved permission chain (tag + explicit)
|
|
76
|
+
channelMiddleware?: MiddlewareMetadata[]
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export type ChannelsMeta = Record<string, ChannelMeta>
|
|
80
|
+
|
|
81
|
+
export type CoreChannel<
|
|
82
|
+
ChannelData,
|
|
83
|
+
Channel extends string,
|
|
84
|
+
ChannelConnect = CorePikkuFunctionConfig<
|
|
85
|
+
| CorePikkuFunction<void, unknown>
|
|
86
|
+
| CorePikkuFunctionSessionless<void, unknown>,
|
|
87
|
+
CorePikkuPermission<void>,
|
|
88
|
+
CorePikkuMiddleware
|
|
89
|
+
>,
|
|
90
|
+
ChannelDisconnect = CorePikkuFunctionConfig<
|
|
91
|
+
CorePikkuFunction<void, void> | CorePikkuFunctionSessionless<void, void>,
|
|
92
|
+
CorePikkuPermission<void>,
|
|
93
|
+
CorePikkuMiddleware
|
|
94
|
+
>,
|
|
95
|
+
ChannelFunctionMessage = CorePikkuFunctionConfig<
|
|
96
|
+
| CorePikkuFunction<unknown, unknown>
|
|
97
|
+
| CorePikkuFunctionSessionless<unknown, unknown>,
|
|
98
|
+
CorePikkuPermission<unknown>,
|
|
99
|
+
CorePikkuMiddleware
|
|
100
|
+
>,
|
|
101
|
+
PikkuPermission = CorePikkuPermission<ChannelData>,
|
|
102
|
+
PikkuMiddleware = CorePikkuMiddleware,
|
|
103
|
+
> = {
|
|
104
|
+
name: string
|
|
105
|
+
route: Channel
|
|
106
|
+
onConnect?:
|
|
107
|
+
| ChannelConnect
|
|
108
|
+
| {
|
|
109
|
+
func?: ChannelConnect
|
|
110
|
+
middleware?: PikkuMiddleware[]
|
|
111
|
+
}
|
|
112
|
+
onDisconnect?:
|
|
113
|
+
| ChannelDisconnect
|
|
114
|
+
| {
|
|
115
|
+
func?: ChannelDisconnect
|
|
116
|
+
middleware?: PikkuMiddleware[]
|
|
117
|
+
}
|
|
118
|
+
onMessage?: ChannelFunctionMessage
|
|
119
|
+
onMessageWiring?: Record<
|
|
120
|
+
string,
|
|
121
|
+
Record<
|
|
122
|
+
string,
|
|
123
|
+
| ChannelFunctionMessage
|
|
124
|
+
| {
|
|
125
|
+
func: ChannelFunctionMessage
|
|
126
|
+
permissions?: CorePermissionGroup<PikkuPermission>
|
|
127
|
+
auth?: boolean
|
|
128
|
+
middleware?: PikkuMiddleware[]
|
|
129
|
+
}
|
|
130
|
+
>
|
|
131
|
+
>
|
|
132
|
+
middleware?: PikkuMiddleware[]
|
|
133
|
+
channelMiddleware?: Array<
|
|
134
|
+
CorePikkuChannelMiddleware | CorePikkuChannelMiddlewareFactory
|
|
135
|
+
>
|
|
136
|
+
permissions?: CorePermissionGroup<PikkuPermission>
|
|
137
|
+
auth?: boolean
|
|
138
|
+
binary?: boolean | null
|
|
139
|
+
onBinaryMessage?: (
|
|
140
|
+
services: any,
|
|
141
|
+
data: BinaryData,
|
|
142
|
+
channel: PikkuChannel<ChannelData, any>
|
|
143
|
+
) => Promise<BinaryData | void> | BinaryData | void
|
|
144
|
+
tags?: string[]
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export interface PikkuChannel<OpeningData, out Out> {
|
|
148
|
+
// The channel identifier
|
|
149
|
+
channelId: string
|
|
150
|
+
// The data the channel was created with. This could be query parameters
|
|
151
|
+
// or parameters in the url.
|
|
152
|
+
openingData: OpeningData
|
|
153
|
+
// The data to send. This will fail is the stream has been closed.
|
|
154
|
+
send(data: Out, isBinary?: boolean): Promise<void> | void
|
|
155
|
+
sendBinary(data: BinaryData): Promise<void> | void
|
|
156
|
+
// This will close the channel.
|
|
157
|
+
close(): Promise<void> | void
|
|
158
|
+
// The current state of the channel
|
|
159
|
+
state: 'initial' | 'open' | 'closed'
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export interface PikkuChannelHandler<OpeningData = unknown, Out = unknown> {
|
|
163
|
+
send(message: Out, isBinary?: boolean): Promise<void> | void
|
|
164
|
+
sendBinary(data: BinaryData): Promise<void> | void
|
|
165
|
+
getChannel(): PikkuChannel<OpeningData, Out>
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
export type PikkuChannelHandlerFactory<OpeningData = unknown, Out = unknown> = (
|
|
169
|
+
channelId: string,
|
|
170
|
+
channelName: string,
|
|
171
|
+
openingData: OpeningData
|
|
172
|
+
) => PikkuChannelHandler<OpeningData, Out>
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type-safe helper for defining channel message routes that can be composed.
|
|
3
|
+
* Returns the routes record as-is (identity function) for use with `wireChannel`.
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* ```typescript
|
|
7
|
+
* export const chatRoutes = defineChannelRoutes({
|
|
8
|
+
* greet: pikkuChannelFunc({ func: greetFunc }),
|
|
9
|
+
* farewell: pikkuChannelFunc({ func: farewellFunc }),
|
|
10
|
+
* })
|
|
11
|
+
*
|
|
12
|
+
* wireChannel({
|
|
13
|
+
* name: 'chat',
|
|
14
|
+
* route: '/ws/chat',
|
|
15
|
+
* onMessageWiring: {
|
|
16
|
+
* command: chatRoutes,
|
|
17
|
+
* }
|
|
18
|
+
* })
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
export function defineChannelRoutes<T extends Record<string, any>>(
|
|
22
|
+
routes: T
|
|
23
|
+
): T {
|
|
24
|
+
return routes
|
|
25
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interface defining the methods of a EventHub Service.
|
|
3
|
+
*/
|
|
4
|
+
export interface EventHubService<Topics extends Record<string, any>> {
|
|
5
|
+
/**
|
|
6
|
+
* Subscribes a connection to a specific topic.
|
|
7
|
+
* @param topic - The topic to subscribe to.
|
|
8
|
+
* @param channelId - The unique ID of the connection to subscribe.
|
|
9
|
+
*/
|
|
10
|
+
subscribe<T extends keyof Topics>(
|
|
11
|
+
topic: T,
|
|
12
|
+
channelId: string
|
|
13
|
+
): Promise<void> | void
|
|
14
|
+
/**
|
|
15
|
+
* Unsubscribes a connection from a specific topic.
|
|
16
|
+
* @param topic - The topic to unsubscribe from.
|
|
17
|
+
* @param channelId - The unique ID of the connection to unsubscribe.
|
|
18
|
+
*/
|
|
19
|
+
unsubscribe<T extends keyof Topics>(
|
|
20
|
+
topic: T,
|
|
21
|
+
channelId: string
|
|
22
|
+
): Promise<void> | void
|
|
23
|
+
/**
|
|
24
|
+
* Sends data to all connections subscribed to a topic.
|
|
25
|
+
* @param topic - The topic to send data to.
|
|
26
|
+
* @param data - The data to send to the subscribers.
|
|
27
|
+
*/
|
|
28
|
+
publish<T extends keyof Topics>(
|
|
29
|
+
topic: T,
|
|
30
|
+
channelId: string | null,
|
|
31
|
+
data: Topics[T],
|
|
32
|
+
isBinary?: boolean
|
|
33
|
+
): Promise<void> | void
|
|
34
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export abstract class EventHubStore<
|
|
2
|
+
EventTopics extends Record<string, any> = {},
|
|
3
|
+
> {
|
|
4
|
+
public abstract getChannelIdsForTopic(topic: string): Promise<string[]>
|
|
5
|
+
public abstract subscribe<T extends keyof EventTopics>(
|
|
6
|
+
topic: T,
|
|
7
|
+
channelId: string
|
|
8
|
+
): Promise<boolean>
|
|
9
|
+
public abstract unsubscribe<T extends keyof EventTopics>(
|
|
10
|
+
topic: T,
|
|
11
|
+
channelId: string
|
|
12
|
+
): Promise<boolean>
|
|
13
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export { wireChannel, openChannel } from './channel-runner.js'
|
|
2
|
+
export {
|
|
3
|
+
addChannelMiddleware,
|
|
4
|
+
combineChannelMiddleware,
|
|
5
|
+
wrapChannelWithMiddleware,
|
|
6
|
+
} from './channel-middleware-runner.js'
|
|
7
|
+
export { logChannels } from './log-channels.js'
|
|
8
|
+
export { PikkuAbstractChannelHandler } from './pikku-abstract-channel-handler.js'
|
|
9
|
+
export type { EventHubService } from './eventhub-service.js'
|
|
10
|
+
export { ChannelStore } from './channel-store.js'
|
|
11
|
+
export type { Channel } from './channel-store.js'
|
|
12
|
+
export { EventHubStore } from './eventhub-store.js'
|
|
13
|
+
export type {
|
|
14
|
+
BinaryData,
|
|
15
|
+
ChannelsMeta,
|
|
16
|
+
CoreChannel,
|
|
17
|
+
CorePikkuChannelMiddleware,
|
|
18
|
+
CorePikkuChannelMiddlewareFactory,
|
|
19
|
+
ChannelMessageMeta,
|
|
20
|
+
ChannelMeta,
|
|
21
|
+
PikkuChannel,
|
|
22
|
+
PikkuChannelHandlerFactory,
|
|
23
|
+
} from './channel.types.js'
|
|
24
|
+
export { defineChannelRoutes } from './define-channel-routes.js'
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import type { BinaryData } from '../channel.types.js'
|
|
2
|
+
import { PikkuAbstractChannelHandler } from '../pikku-abstract-channel-handler.js'
|
|
3
|
+
|
|
4
|
+
export class PikkuLocalChannelHandler<
|
|
5
|
+
OpeningData = unknown,
|
|
6
|
+
Out = unknown,
|
|
7
|
+
> extends PikkuAbstractChannelHandler<OpeningData, Out> {
|
|
8
|
+
private onMessageCallback?: (message: unknown) => void
|
|
9
|
+
private onBinaryMessageCallback?: (data: BinaryData) => void
|
|
10
|
+
private openCallBack?: () => void
|
|
11
|
+
private closeCallbacks: (() => void)[] = []
|
|
12
|
+
private sendCallback?: (message: Out, isBinary?: boolean) => void
|
|
13
|
+
private sendBinaryCallback?: (data: BinaryData) => void
|
|
14
|
+
|
|
15
|
+
public registerOnOpen(callback: () => void): void {
|
|
16
|
+
this.openCallBack = callback
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
public open() {
|
|
20
|
+
this.getChannel().state = 'open'
|
|
21
|
+
if (this.openCallBack) {
|
|
22
|
+
this.openCallBack()
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
public registerOnMessage(callback: (data: any) => Promise<unknown>): void {
|
|
27
|
+
this.onMessageCallback = callback
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
public async message(data: unknown): Promise<unknown> {
|
|
31
|
+
return this.onMessageCallback?.(data)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
public registerOnBinaryMessage(
|
|
35
|
+
callback: (
|
|
36
|
+
data: BinaryData
|
|
37
|
+
) => Promise<BinaryData | void> | BinaryData | void
|
|
38
|
+
): void {
|
|
39
|
+
this.onBinaryMessageCallback = callback
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
public async binaryMessage(data: BinaryData): Promise<BinaryData | void> {
|
|
43
|
+
return this.onBinaryMessageCallback?.(data)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
public registerOnClose(callback: () => void): void {
|
|
47
|
+
this.closeCallbacks.push(callback)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
public close() {
|
|
51
|
+
if (this.getChannel().state === 'closed') {
|
|
52
|
+
return
|
|
53
|
+
}
|
|
54
|
+
super.close()
|
|
55
|
+
for (const cb of this.closeCallbacks) {
|
|
56
|
+
cb()
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
public registerOnSend(send: (message: Out) => void) {
|
|
61
|
+
this.sendCallback = send
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
public send(message: Out, isBinary?: boolean): void {
|
|
65
|
+
if (!this.sendCallback) {
|
|
66
|
+
throw new Error('No send callback registered')
|
|
67
|
+
}
|
|
68
|
+
return this.sendCallback?.(message, isBinary)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
public registerOnSendBinary(send: (data: BinaryData) => void) {
|
|
72
|
+
this.sendBinaryCallback = send
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
public sendBinary(data: BinaryData): void {
|
|
76
|
+
if (!this.sendBinaryCallback) {
|
|
77
|
+
throw new Error('No sendBinary callback registered')
|
|
78
|
+
}
|
|
79
|
+
this.sendBinaryCallback(data)
|
|
80
|
+
}
|
|
81
|
+
}
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import { test, beforeEach, afterEach } from 'node:test'
|
|
2
|
+
import * as assert from 'node:assert/strict'
|
|
3
|
+
import { runLocalChannel } from './local-channel-runner.js'
|
|
4
|
+
import { pikkuState, resetPikkuState } from '../../../pikku-state.js'
|
|
5
|
+
import { wireChannel } from '../channel-runner.js'
|
|
6
|
+
import type {
|
|
7
|
+
HTTPMethod,
|
|
8
|
+
PikkuHTTPRequest,
|
|
9
|
+
PikkuHTTPResponse,
|
|
10
|
+
PikkuQuery,
|
|
11
|
+
} from '../../http/http.types.js'
|
|
12
|
+
import type { SerializeOptions } from 'cookie'
|
|
13
|
+
import { httpRouter } from '../../http/routers/http-router.js'
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Minimal stubs for dependencies that runChannel expects.
|
|
17
|
+
* In a real test setup, you may provide more comprehensive mocks
|
|
18
|
+
* or refactor your code to allow dependency injection.
|
|
19
|
+
*/
|
|
20
|
+
const mockLogger = {
|
|
21
|
+
info: () => {},
|
|
22
|
+
error: () => {},
|
|
23
|
+
warn: () => {},
|
|
24
|
+
debug: () => {},
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const mockSingletonServices = {
|
|
28
|
+
logger: mockLogger,
|
|
29
|
+
} as any
|
|
30
|
+
|
|
31
|
+
// Mock request and response objects
|
|
32
|
+
export class PikkuMockRequest implements PikkuHTTPRequest {
|
|
33
|
+
private _params: Record<string, string | string[] | undefined> = {}
|
|
34
|
+
|
|
35
|
+
constructor(
|
|
36
|
+
private _route: string,
|
|
37
|
+
private _method: HTTPMethod
|
|
38
|
+
) {}
|
|
39
|
+
|
|
40
|
+
method(): HTTPMethod {
|
|
41
|
+
return this._method
|
|
42
|
+
}
|
|
43
|
+
path(): string {
|
|
44
|
+
return this._route
|
|
45
|
+
}
|
|
46
|
+
json(): Promise<unknown> {
|
|
47
|
+
throw new Error('Method not implemented.')
|
|
48
|
+
}
|
|
49
|
+
arrayBuffer(): Promise<ArrayBuffer> {
|
|
50
|
+
throw new Error('Method not implemented.')
|
|
51
|
+
}
|
|
52
|
+
header(headerName: string): string | null {
|
|
53
|
+
throw new Error('Method not implemented.')
|
|
54
|
+
}
|
|
55
|
+
cookie(name?: string): string | null {
|
|
56
|
+
throw new Error('Method not implemented.')
|
|
57
|
+
}
|
|
58
|
+
params(): Partial<Record<string, string | string[]>> {
|
|
59
|
+
return this._params
|
|
60
|
+
}
|
|
61
|
+
setParams(params: Record<string, string | string[] | undefined>): void {
|
|
62
|
+
this._params = params
|
|
63
|
+
}
|
|
64
|
+
query(): PikkuQuery {
|
|
65
|
+
throw new Error('Method not implemented.')
|
|
66
|
+
}
|
|
67
|
+
public async data() {
|
|
68
|
+
return { test: 'data' }
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export class PikkuMockResponse implements PikkuHTTPResponse {
|
|
73
|
+
public _status: number | undefined
|
|
74
|
+
|
|
75
|
+
status(code: number): this {
|
|
76
|
+
this._status = code
|
|
77
|
+
return this
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
cookie(name: string, value: string | null, options: SerializeOptions): this {
|
|
81
|
+
throw new Error('Method not implemented.')
|
|
82
|
+
}
|
|
83
|
+
header(name: string, value: string | string[]): this {
|
|
84
|
+
throw new Error('Method not implemented.')
|
|
85
|
+
}
|
|
86
|
+
arrayBuffer(data: XMLHttpRequestBodyInit): this {
|
|
87
|
+
throw new Error('Method not implemented.')
|
|
88
|
+
}
|
|
89
|
+
json(data: unknown): this {
|
|
90
|
+
// We don't need to implement this for our test
|
|
91
|
+
return this
|
|
92
|
+
}
|
|
93
|
+
redirect(location: string, status?: number): this {
|
|
94
|
+
throw new Error('Method not implemented.')
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const mockCreateWireServices = async () => ({
|
|
99
|
+
wireServiceMock: true,
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
beforeEach(() => {
|
|
103
|
+
resetPikkuState()
|
|
104
|
+
httpRouter.reset()
|
|
105
|
+
pikkuState(null, 'package', 'singletonServices', mockSingletonServices as any)
|
|
106
|
+
pikkuState(null, 'package', 'factories', {
|
|
107
|
+
createWireServices: mockCreateWireServices,
|
|
108
|
+
} as any)
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
afterEach(() => {
|
|
112
|
+
resetPikkuState()
|
|
113
|
+
httpRouter.reset()
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
test('runChannel should return undefined and 404 if no matching channel is found', async () => {
|
|
117
|
+
const mockResponse = new PikkuMockResponse()
|
|
118
|
+
|
|
119
|
+
const result = await runLocalChannel({
|
|
120
|
+
channelId: 'test-channel-id',
|
|
121
|
+
request: new PikkuMockRequest('/non-existent-channel', 'get'),
|
|
122
|
+
response: mockResponse,
|
|
123
|
+
})
|
|
124
|
+
|
|
125
|
+
assert.equal(
|
|
126
|
+
result,
|
|
127
|
+
undefined,
|
|
128
|
+
'Should return undefined if no channel matches'
|
|
129
|
+
)
|
|
130
|
+
assert.equal(mockResponse._status, 404, 'Should set response status to 404')
|
|
131
|
+
// assert.equal(mockResponse._ended, true, 'Should end the response')
|
|
132
|
+
})
|
|
133
|
+
|
|
134
|
+
test('runChannel should return a channel handler if channel matches and no auth required', async () => {
|
|
135
|
+
resetPikkuState()
|
|
136
|
+
pikkuState(null, 'package', 'singletonServices', mockSingletonServices as any)
|
|
137
|
+
pikkuState(null, 'package', 'factories', {
|
|
138
|
+
createWireServices: mockCreateWireServices,
|
|
139
|
+
} as any)
|
|
140
|
+
|
|
141
|
+
pikkuState(null, 'channel', 'meta', {
|
|
142
|
+
test: {
|
|
143
|
+
name: 'test',
|
|
144
|
+
route: '/test-channel',
|
|
145
|
+
},
|
|
146
|
+
} as any)
|
|
147
|
+
wireChannel({
|
|
148
|
+
name: 'test',
|
|
149
|
+
route: '/test-channel',
|
|
150
|
+
auth: false,
|
|
151
|
+
})
|
|
152
|
+
|
|
153
|
+
// Initialize router after adding channel (for tests)
|
|
154
|
+
httpRouter.initialize()
|
|
155
|
+
|
|
156
|
+
const result = await runLocalChannel({
|
|
157
|
+
channelId: 'test-channel-id',
|
|
158
|
+
request: new PikkuMockRequest('/test-channel', 'get'),
|
|
159
|
+
response: new PikkuMockResponse(),
|
|
160
|
+
route: '/test-channel',
|
|
161
|
+
})
|
|
162
|
+
|
|
163
|
+
assert.ok(result, 'Should return a PikkuChannelHandler instance')
|
|
164
|
+
|
|
165
|
+
// Simulate opening the channel
|
|
166
|
+
result.open()
|
|
167
|
+
})
|
|
168
|
+
|
|
169
|
+
test('runChannel should close wire services once when channel closes', async () => {
|
|
170
|
+
resetPikkuState()
|
|
171
|
+
pikkuState(null, 'package', 'singletonServices', mockSingletonServices as any)
|
|
172
|
+
let closeCount = 0
|
|
173
|
+
|
|
174
|
+
pikkuState(null, 'channel', 'meta', {
|
|
175
|
+
test: {
|
|
176
|
+
name: 'test',
|
|
177
|
+
route: '/test-channel',
|
|
178
|
+
},
|
|
179
|
+
} as any)
|
|
180
|
+
wireChannel({
|
|
181
|
+
name: 'test',
|
|
182
|
+
route: '/test-channel',
|
|
183
|
+
auth: false,
|
|
184
|
+
})
|
|
185
|
+
|
|
186
|
+
httpRouter.initialize()
|
|
187
|
+
|
|
188
|
+
pikkuState(null, 'package', 'factories', {
|
|
189
|
+
createWireServices: async () => ({
|
|
190
|
+
tracked: {
|
|
191
|
+
close: async () => {
|
|
192
|
+
closeCount += 1
|
|
193
|
+
},
|
|
194
|
+
},
|
|
195
|
+
}),
|
|
196
|
+
} as any)
|
|
197
|
+
|
|
198
|
+
const result = await runLocalChannel({
|
|
199
|
+
channelId: 'test-channel-id',
|
|
200
|
+
request: new PikkuMockRequest('/test-channel', 'get'),
|
|
201
|
+
response: new PikkuMockResponse(),
|
|
202
|
+
route: '/test-channel',
|
|
203
|
+
})
|
|
204
|
+
|
|
205
|
+
assert.ok(result)
|
|
206
|
+
assert.equal(closeCount, 0)
|
|
207
|
+
|
|
208
|
+
result.close()
|
|
209
|
+
await new Promise((resolve) => setTimeout(resolve, 0))
|
|
210
|
+
assert.equal(closeCount, 1)
|
|
211
|
+
|
|
212
|
+
result.close()
|
|
213
|
+
await new Promise((resolve) => setTimeout(resolve, 0))
|
|
214
|
+
assert.equal(closeCount, 1)
|
|
215
|
+
})
|