@pikku/core 0.12.3 → 0.12.4

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 (218) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/dist/services/in-memory-workflow-service.d.ts +15 -2
  3. package/dist/services/in-memory-workflow-service.js +49 -0
  4. package/lcov.info +18891 -0
  5. package/package.json +1 -1
  6. package/src/crypto-utils.test.ts +0 -214
  7. package/src/crypto-utils.ts +0 -213
  8. package/src/errors/error-handler.ts +0 -62
  9. package/src/errors/error.test.ts +0 -195
  10. package/src/errors/errors.ts +0 -374
  11. package/src/errors/index.ts +0 -2
  12. package/src/factory-functions.test.ts +0 -109
  13. package/src/function/function-runner.test.ts +0 -536
  14. package/src/function/function-runner.ts +0 -365
  15. package/src/function/functions.types.ts +0 -304
  16. package/src/function/index.ts +0 -5
  17. package/src/handle-error.test.ts +0 -424
  18. package/src/handle-error.ts +0 -69
  19. package/src/index.ts +0 -118
  20. package/src/internal.ts +0 -6
  21. package/src/middleware/auth-apikey.test.ts +0 -363
  22. package/src/middleware/auth-apikey.ts +0 -47
  23. package/src/middleware/auth-bearer.test.ts +0 -450
  24. package/src/middleware/auth-bearer.ts +0 -72
  25. package/src/middleware/auth-cookie.test.ts +0 -528
  26. package/src/middleware/auth-cookie.ts +0 -80
  27. package/src/middleware/cors.test.ts +0 -424
  28. package/src/middleware/cors.ts +0 -104
  29. package/src/middleware/index.ts +0 -5
  30. package/src/middleware/remote-auth.test.ts +0 -488
  31. package/src/middleware/remote-auth.ts +0 -68
  32. package/src/middleware/timeout.ts +0 -15
  33. package/src/middleware-runner.test.ts +0 -418
  34. package/src/middleware-runner.ts +0 -234
  35. package/src/permissions.test.ts +0 -434
  36. package/src/permissions.ts +0 -319
  37. package/src/pikku-request.ts +0 -23
  38. package/src/pikku-response.ts +0 -5
  39. package/src/pikku-state.test.ts +0 -224
  40. package/src/pikku-state.ts +0 -216
  41. package/src/run-tests-script.test.ts +0 -49
  42. package/src/schema.test.ts +0 -249
  43. package/src/schema.ts +0 -151
  44. package/src/services/ai-agent-runner-service.ts +0 -41
  45. package/src/services/ai-run-state-service.ts +0 -20
  46. package/src/services/ai-storage-service.ts +0 -39
  47. package/src/services/content-service.ts +0 -76
  48. package/src/services/deployment-service.ts +0 -22
  49. package/src/services/gateway-service.ts +0 -20
  50. package/src/services/gopass-secrets.ts +0 -98
  51. package/src/services/in-memory-ai-run-state-service.ts +0 -73
  52. package/src/services/in-memory-trigger-service.ts +0 -64
  53. package/src/services/in-memory-workflow-service.test.ts +0 -351
  54. package/src/services/in-memory-workflow-service.ts +0 -438
  55. package/src/services/index.ts +0 -56
  56. package/src/services/jwt-service.ts +0 -30
  57. package/src/services/local-content.ts +0 -120
  58. package/src/services/local-gateway-service.ts +0 -62
  59. package/src/services/local-secrets.test.ts +0 -80
  60. package/src/services/local-secrets.ts +0 -94
  61. package/src/services/local-variables.test.ts +0 -61
  62. package/src/services/local-variables.ts +0 -39
  63. package/src/services/logger-console.test.ts +0 -118
  64. package/src/services/logger-console.ts +0 -98
  65. package/src/services/logger.ts +0 -57
  66. package/src/services/scheduler-service.ts +0 -86
  67. package/src/services/schema-service.ts +0 -33
  68. package/src/services/scoped-secret-service.test.ts +0 -74
  69. package/src/services/scoped-secret-service.ts +0 -41
  70. package/src/services/secret-service.ts +0 -38
  71. package/src/services/trigger-service.ts +0 -17
  72. package/src/services/typed-secret-service.test.ts +0 -93
  73. package/src/services/typed-secret-service.ts +0 -70
  74. package/src/services/typed-variables-service.test.ts +0 -73
  75. package/src/services/typed-variables-service.ts +0 -81
  76. package/src/services/user-session-service.test.ts +0 -113
  77. package/src/services/user-session-service.ts +0 -86
  78. package/src/services/variables-service.ts +0 -11
  79. package/src/services/workflow-service.ts +0 -95
  80. package/src/testing/index.ts +0 -2
  81. package/src/testing/service-tests.ts +0 -873
  82. package/src/time-utils.test.ts +0 -56
  83. package/src/time-utils.ts +0 -107
  84. package/src/types/core.types.ts +0 -478
  85. package/src/types/state.types.ts +0 -188
  86. package/src/utils/hash.test.ts +0 -68
  87. package/src/utils/hash.ts +0 -26
  88. package/src/utils.test.ts +0 -350
  89. package/src/utils.ts +0 -129
  90. package/src/version.test.ts +0 -80
  91. package/src/version.ts +0 -25
  92. package/src/wirings/ai-agent/agent-dynamic-workflow.ts +0 -469
  93. package/src/wirings/ai-agent/ai-agent-helpers.test.ts +0 -152
  94. package/src/wirings/ai-agent/ai-agent-helpers.ts +0 -76
  95. package/src/wirings/ai-agent/ai-agent-memory.ts +0 -310
  96. package/src/wirings/ai-agent/ai-agent-model-config.test.ts +0 -115
  97. package/src/wirings/ai-agent/ai-agent-model-config.ts +0 -43
  98. package/src/wirings/ai-agent/ai-agent-prepare.ts +0 -636
  99. package/src/wirings/ai-agent/ai-agent-registry.test.ts +0 -37
  100. package/src/wirings/ai-agent/ai-agent-registry.ts +0 -82
  101. package/src/wirings/ai-agent/ai-agent-runner.test.ts +0 -319
  102. package/src/wirings/ai-agent/ai-agent-runner.ts +0 -773
  103. package/src/wirings/ai-agent/ai-agent-stream.test.ts +0 -859
  104. package/src/wirings/ai-agent/ai-agent-stream.ts +0 -1153
  105. package/src/wirings/ai-agent/ai-agent.types.ts +0 -382
  106. package/src/wirings/ai-agent/index.ts +0 -37
  107. package/src/wirings/channel/channel-common.ts +0 -90
  108. package/src/wirings/channel/channel-handler.ts +0 -250
  109. package/src/wirings/channel/channel-middleware-runner.ts +0 -120
  110. package/src/wirings/channel/channel-runner.ts +0 -166
  111. package/src/wirings/channel/channel-store.ts +0 -29
  112. package/src/wirings/channel/channel.types.ts +0 -172
  113. package/src/wirings/channel/define-channel-routes.ts +0 -25
  114. package/src/wirings/channel/eventhub-service.ts +0 -34
  115. package/src/wirings/channel/eventhub-store.ts +0 -13
  116. package/src/wirings/channel/index.ts +0 -24
  117. package/src/wirings/channel/local/index.ts +0 -3
  118. package/src/wirings/channel/local/local-channel-handler.ts +0 -81
  119. package/src/wirings/channel/local/local-channel-runner.test.ts +0 -215
  120. package/src/wirings/channel/local/local-channel-runner.ts +0 -210
  121. package/src/wirings/channel/local/local-eventhub-service.test.ts +0 -95
  122. package/src/wirings/channel/local/local-eventhub-service.ts +0 -101
  123. package/src/wirings/channel/log-channels.ts +0 -20
  124. package/src/wirings/channel/pikku-abstract-channel-handler.test.ts +0 -54
  125. package/src/wirings/channel/pikku-abstract-channel-handler.ts +0 -45
  126. package/src/wirings/channel/serverless/index.ts +0 -5
  127. package/src/wirings/channel/serverless/serverless-channel-runner.ts +0 -289
  128. package/src/wirings/cli/channel/cli-channel-runner.ts +0 -136
  129. package/src/wirings/cli/channel/index.ts +0 -1
  130. package/src/wirings/cli/cli-runner.test.ts +0 -403
  131. package/src/wirings/cli/cli-runner.ts +0 -529
  132. package/src/wirings/cli/cli.types.ts +0 -358
  133. package/src/wirings/cli/command-parser.test.ts +0 -445
  134. package/src/wirings/cli/command-parser.ts +0 -504
  135. package/src/wirings/cli/define-cli-commands.ts +0 -24
  136. package/src/wirings/cli/index.ts +0 -19
  137. package/src/wirings/gateway/gateway-runner.test.ts +0 -474
  138. package/src/wirings/gateway/gateway-runner.ts +0 -411
  139. package/src/wirings/gateway/gateway.types.ts +0 -149
  140. package/src/wirings/gateway/index.ts +0 -13
  141. package/src/wirings/http/http-routes.test.ts +0 -322
  142. package/src/wirings/http/http-routes.ts +0 -197
  143. package/src/wirings/http/http-runner.test.ts +0 -144
  144. package/src/wirings/http/http-runner.ts +0 -588
  145. package/src/wirings/http/http.types.ts +0 -369
  146. package/src/wirings/http/index.ts +0 -28
  147. package/src/wirings/http/log-http-routes.ts +0 -22
  148. package/src/wirings/http/pikku-fetch-http-request.test.ts +0 -237
  149. package/src/wirings/http/pikku-fetch-http-request.ts +0 -170
  150. package/src/wirings/http/pikku-fetch-http-response.test.ts +0 -82
  151. package/src/wirings/http/pikku-fetch-http-response.ts +0 -147
  152. package/src/wirings/http/routers/http-router.ts +0 -13
  153. package/src/wirings/http/routers/path-to-regex.test.ts +0 -319
  154. package/src/wirings/http/routers/path-to-regex.ts +0 -126
  155. package/src/wirings/http/web-request.test.ts +0 -236
  156. package/src/wirings/http/web-request.ts +0 -104
  157. package/src/wirings/mcp/index.ts +0 -27
  158. package/src/wirings/mcp/mcp-endpoint-registry.test.ts +0 -389
  159. package/src/wirings/mcp/mcp-endpoint-registry.ts +0 -159
  160. package/src/wirings/mcp/mcp-runner.ts +0 -323
  161. package/src/wirings/mcp/mcp.types.ts +0 -216
  162. package/src/wirings/node/index.ts +0 -2
  163. package/src/wirings/node/node.types.ts +0 -23
  164. package/src/wirings/oauth2/index.ts +0 -3
  165. package/src/wirings/oauth2/oauth2-client.test.ts +0 -929
  166. package/src/wirings/oauth2/oauth2-client.ts +0 -335
  167. package/src/wirings/oauth2/oauth2.types.ts +0 -69
  168. package/src/wirings/oauth2/wire-oauth2-credential.ts +0 -23
  169. package/src/wirings/queue/index.ts +0 -31
  170. package/src/wirings/queue/queue-runner.test.ts +0 -710
  171. package/src/wirings/queue/queue-runner.ts +0 -192
  172. package/src/wirings/queue/queue.types.ts +0 -189
  173. package/src/wirings/queue/register-queue-helper.ts +0 -60
  174. package/src/wirings/queue/validate-worker-config.test.ts +0 -108
  175. package/src/wirings/queue/validate-worker-config.ts +0 -116
  176. package/src/wirings/rpc/index.ts +0 -4
  177. package/src/wirings/rpc/rpc-runner.ts +0 -460
  178. package/src/wirings/rpc/rpc-types.ts +0 -56
  179. package/src/wirings/rpc/wire-addon.ts +0 -21
  180. package/src/wirings/scheduler/index.ts +0 -11
  181. package/src/wirings/scheduler/log-schedulers.ts +0 -20
  182. package/src/wirings/scheduler/scheduler-runner.test.ts +0 -660
  183. package/src/wirings/scheduler/scheduler-runner.ts +0 -133
  184. package/src/wirings/scheduler/scheduler.types.ts +0 -53
  185. package/src/wirings/secret/index.ts +0 -9
  186. package/src/wirings/secret/secret.types.ts +0 -32
  187. package/src/wirings/secret/validate-secret-definitions.test.ts +0 -140
  188. package/src/wirings/secret/validate-secret-definitions.ts +0 -82
  189. package/src/wirings/trigger/index.ts +0 -10
  190. package/src/wirings/trigger/pikku-trigger-service.ts +0 -112
  191. package/src/wirings/trigger/trigger-runner.test.ts +0 -79
  192. package/src/wirings/trigger/trigger-runner.ts +0 -135
  193. package/src/wirings/trigger/trigger.types.ts +0 -178
  194. package/src/wirings/variable/index.ts +0 -8
  195. package/src/wirings/variable/validate-variable-definitions.test.ts +0 -91
  196. package/src/wirings/variable/validate-variable-definitions.ts +0 -69
  197. package/src/wirings/variable/variable.types.ts +0 -22
  198. package/src/wirings/workflow/dsl/index.ts +0 -31
  199. package/src/wirings/workflow/dsl/workflow-dsl.types.ts +0 -320
  200. package/src/wirings/workflow/dsl/workflow-runner.ts +0 -28
  201. package/src/wirings/workflow/graph/graph-node.ts +0 -222
  202. package/src/wirings/workflow/graph/graph-runner.test.ts +0 -487
  203. package/src/wirings/workflow/graph/graph-runner.ts +0 -816
  204. package/src/wirings/workflow/graph/graph-validation.test.ts +0 -170
  205. package/src/wirings/workflow/graph/graph-validation.ts +0 -237
  206. package/src/wirings/workflow/graph/index.ts +0 -19
  207. package/src/wirings/workflow/graph/template.test.ts +0 -49
  208. package/src/wirings/workflow/graph/template.ts +0 -42
  209. package/src/wirings/workflow/graph/wire-workflow-graph.ts +0 -29
  210. package/src/wirings/workflow/graph/workflow-graph.types.ts +0 -104
  211. package/src/wirings/workflow/index.ts +0 -82
  212. package/src/wirings/workflow/pikku-workflow-service.test.ts +0 -200
  213. package/src/wirings/workflow/pikku-workflow-service.ts +0 -1176
  214. package/src/wirings/workflow/workflow-helpers.test.ts +0 -129
  215. package/src/wirings/workflow/workflow-helpers.ts +0 -79
  216. package/src/wirings/workflow/workflow.types.ts +0 -274
  217. package/tsconfig.json +0 -14
  218. package/tsconfig.tsbuildinfo +0 -1
@@ -1,170 +0,0 @@
1
- import { parse as parseQuery } from 'picoquery'
2
- import { parse as parseCookie } from 'cookie'
3
- import type { HTTPMethod, PikkuHTTPRequest, PikkuQuery } from './http.types.js'
4
- import { UnprocessableContentError } from '../../errors/errors.js'
5
-
6
- /**
7
- * Abstract class representing a pikku request.
8
- * @template In - The type of the request body.
9
- * @group RequestResponse
10
- */
11
- export class PikkuFetchHTTPRequest<In = unknown>
12
- implements PikkuHTTPRequest<In>
13
- {
14
- #cookies: Partial<Record<string, string>> | undefined
15
- #params: Partial<Record<string, string | string[]>> = {}
16
- #url: URL
17
-
18
- constructor(private request: Request) {
19
- this.#url = new URL(request.url)
20
- }
21
-
22
- public method(): HTTPMethod {
23
- return this.request.method.toLowerCase() as HTTPMethod
24
- }
25
-
26
- public path(): string {
27
- return this.#url.pathname
28
- }
29
-
30
- /**
31
- * Retrieves the request body.
32
- * @returns A promise that resolves to the request body.
33
- */
34
- public json(): Promise<In> {
35
- return this.request.json()
36
- }
37
-
38
- /**
39
- * Retrieves the raw request body as a Buffer.
40
- * @returns A promise that resolves to the raw request body.
41
- */
42
- public arrayBuffer(): Promise<ArrayBuffer> {
43
- return this.request.arrayBuffer()
44
- }
45
-
46
- public headers(): Record<string, string> {
47
- return Object.fromEntries(this.request.headers.entries())
48
- }
49
-
50
- /**
51
- * Retrieves the value of a specific header.
52
- * @param headerName - The name of the header to retrieve.
53
- * @returns The value of the header, or undefined if the header is not found.
54
- */
55
- public header(headerName: string): string | null {
56
- return this.request.headers.get(headerName.toLowerCase())
57
- }
58
-
59
- /**
60
- * Retrieves the cookies from the request.
61
- * @returns An object containing the cookies.
62
- */
63
- public cookie(cookieName: string): string | null {
64
- if (this.#cookies?.[cookieName]) {
65
- return this.#cookies[cookieName]
66
- }
67
- const cookieHeader = this.header('cookie')
68
- this.#cookies = cookieHeader ? parseCookie(cookieHeader) : {}
69
- return this.#cookies[cookieName] || null
70
- }
71
-
72
- /**
73
- * Retrieves the request parameters.
74
- * @returns An object containing the request parameters.
75
- */
76
- public params(): Partial<Record<string, string | string[]>> {
77
- return this.#params
78
- }
79
-
80
- /**
81
- * Sets the request parameters.
82
- * @param params - An object containing the request parameters to set.
83
- */
84
- public setParams(
85
- params: Record<string, string | string[] | undefined>
86
- ): void {
87
- this.#params = params
88
- }
89
-
90
- /**
91
- * Retrieves the query parameters from the request.
92
- * @returns An object containing the query parameters.
93
- */
94
- public query(): PikkuQuery {
95
- return parseQuery(this.#url.searchParams.toString()) as PikkuQuery
96
- }
97
-
98
- /**
99
- * Retrieves the combined data from the request, including parameters, query, and body.
100
- * @returns A promise that resolves to an object containing the combined data.
101
- */
102
- public async data(): Promise<In> {
103
- const body = await this.body()
104
- const parts = [this.params(), this.query(), body]
105
- const merged: Record<string, unknown> = {}
106
- for (const part of parts) {
107
- for (const [key, value] of Object.entries(part)) {
108
- if (key in merged && !valuesAreEquivalent(merged[key], value)) {
109
- throw new UnprocessableContentError(
110
- `Conflicting values for key "${key}": "${merged[key]}" vs "${value}"`
111
- )
112
- }
113
- merged[key] ??= value
114
- }
115
- }
116
- return merged as In
117
- }
118
-
119
- private async body(): Promise<any> {
120
- const noBodyMethods: HTTPMethod[] = ['get', 'head', 'options', 'delete']
121
- if (noBodyMethods.includes(this.method())) {
122
- return {}
123
- }
124
-
125
- let body: any = {}
126
- const contentType = this.header('content-type') || ''
127
- try {
128
- if (contentType.includes('application/json')) {
129
- const parsed = await this.json()
130
- body =
131
- typeof parsed === 'object' &&
132
- parsed !== null &&
133
- !Array.isArray(parsed)
134
- ? parsed
135
- : { data: parsed }
136
- } else if (contentType.includes('text/')) {
137
- const text = await this.request.text()
138
- body = { data: text }
139
- } else if (contentType.includes('application/octet-stream')) {
140
- const buffer = await this.request.arrayBuffer()
141
- body = { data: buffer }
142
- } else if (contentType === 'application/x-www-form-urlencoded') {
143
- const text = await this.request.text()
144
- body = Object.fromEntries(new URLSearchParams(text))
145
- } else {
146
- throw new UnprocessableContentError(
147
- `Unsupported content type ${contentType}`
148
- )
149
- }
150
- } catch (e) {
151
- throw new UnprocessableContentError(`Error parsing body: ${e}`)
152
- }
153
- return body
154
- }
155
- }
156
-
157
- function valuesAreEquivalent(a: unknown, b: unknown): boolean {
158
- return coerce(a) === coerce(b)
159
- }
160
-
161
- function coerce(value: unknown): string | number | boolean {
162
- if (typeof value === 'boolean' || typeof value === 'number') return value
163
- if (typeof value === 'string') {
164
- if (value === 'true') return true
165
- if (value === 'false') return false
166
- const num = Number(value)
167
- return isNaN(num) ? value : num
168
- }
169
- return value as any
170
- }
@@ -1,82 +0,0 @@
1
- import { describe, test } from 'node:test'
2
- import assert from 'assert'
3
- import { PikkuFetchHTTPResponse } from './pikku-fetch-http-response.js' // Adjust path if needed
4
-
5
- describe('PikkuFetchHTTPResponse', () => {
6
- test('sets status code', () => {
7
- const res = new PikkuFetchHTTPResponse().status(404).toResponse()
8
- assert.strictEqual(res.status, 404)
9
- })
10
-
11
- test('sets headers', async () => {
12
- const res = new PikkuFetchHTTPResponse()
13
- .header('X-Test', 'value')
14
- .header('X-Multi', ['a', 'b'])
15
- .toResponse()
16
-
17
- assert.strictEqual(res.headers.get('X-Test'), 'value')
18
- const multi = res.headers.get('X-Multi')?.split(', ')
19
- assert.deepEqual(multi, ['a', 'b'])
20
- })
21
-
22
- test('sets cookies', () => {
23
- const res = new PikkuFetchHTTPResponse()
24
- .cookie('token', 'abc123', { httpOnly: true, path: '/' })
25
- .cookie('other', 'val', { maxAge: 3600 })
26
- .toResponse()
27
-
28
- const setCookieHeader = res.headers.get('Set-Cookie')
29
- assert.ok(setCookieHeader)
30
-
31
- const cookies = setCookieHeader!.split(', ')
32
- assert.ok(cookies.some((c) => c.startsWith('token=abc123')))
33
- assert.ok(cookies.some((c) => c.startsWith('other=val')))
34
- })
35
-
36
- test('json sets correct content type and body', async () => {
37
- const res = new PikkuFetchHTTPResponse()
38
- .json({ hello: 'world' })
39
- .toResponse()
40
-
41
- assert.strictEqual(res.headers.get('Content-Type'), 'application/json')
42
- const body = await res.json()
43
- assert.deepEqual(body, { hello: 'world' })
44
- })
45
-
46
- test('text sets correct content type and body', async () => {
47
- const res = new PikkuFetchHTTPResponse().text('hello').toResponse()
48
-
49
- assert.strictEqual(res.headers.get('Content-Type'), 'text/plain')
50
- const text = await res.text()
51
- assert.strictEqual(text, 'hello')
52
- })
53
-
54
- test('html sets correct content type and body', async () => {
55
- const res = new PikkuFetchHTTPResponse().html('<p>hi</p>').toResponse()
56
-
57
- assert.strictEqual(res.headers.get('Content-Type'), 'text/html')
58
- const text = await res.text()
59
- assert.strictEqual(text, '<p>hi</p>')
60
- })
61
-
62
- test('arrayBuffer sets correct content type', async () => {
63
- const buffer = new Uint8Array([1, 2, 3]).buffer
64
- const res = new PikkuFetchHTTPResponse().arrayBuffer(buffer).toResponse()
65
-
66
- assert.strictEqual(
67
- res.headers.get('Content-Type'),
68
- 'application/octet-stream'
69
- )
70
- const body = await res.arrayBuffer()
71
- assert.deepEqual(new Uint8Array(body), new Uint8Array([1, 2, 3]))
72
- })
73
-
74
- test('redirect sets Location header and status', () => {
75
- const res = new PikkuFetchHTTPResponse()
76
- .redirect('/login', 301)
77
- .toResponse()
78
-
79
- assert.strictEqual(res.status, 301)
80
- assert.strictEqual(res.headers.get('Location'), '/login')
81
- })
82
- })
@@ -1,147 +0,0 @@
1
- import type { PikkuHTTPResponse } from './http.types.js'
2
- import type { SerializeOptions as CookieSerializeOptions } from 'cookie'
3
- import { serialize as serializeCookie } from 'cookie'
4
-
5
- export class PikkuFetchHTTPResponse implements PikkuHTTPResponse {
6
- #statusCode: number = 200
7
- #headers = new Headers()
8
- #cookies = new Map<string, { value: string; flags: CookieSerializeOptions }>()
9
-
10
- #body: BodyInit | null = null
11
- #responseMode: 'stream' | null = null
12
- #send: ((data: string) => void) | null = null
13
- #close: (() => void) | null = null
14
-
15
- public setMode(mode: 'stream') {
16
- this.#responseMode = 'stream'
17
- if (mode === 'stream') {
18
- this.#body = this.createStream()
19
- }
20
- }
21
-
22
- public status(code: number): this {
23
- this.#statusCode = code
24
- return this
25
- }
26
-
27
- public cookie(
28
- name: string,
29
- value: string,
30
- flags: CookieSerializeOptions
31
- ): this {
32
- this.#cookies.set(name, { value, flags })
33
- return this
34
- }
35
-
36
- public header(name: string, value: string | string[]): this {
37
- this.#headers.delete(name)
38
- if (Array.isArray(value)) {
39
- value.forEach((v) => this.#headers.append(name, v))
40
- } else {
41
- this.#headers.set(name, value)
42
- }
43
- return this
44
- }
45
-
46
- public arrayBuffer(data: XMLHttpRequestBodyInit): this {
47
- if (this.#responseMode === 'stream') {
48
- this.#send!(data as string)
49
- } else {
50
- this.#body = data
51
- this.header('Content-Type', 'application/octet-stream')
52
- }
53
- return this
54
- }
55
-
56
- public json(data: unknown): this {
57
- if (this.#responseMode === 'stream') {
58
- this.#send!(JSON.stringify(data))
59
- } else {
60
- this.#body = JSON.stringify(data)
61
- this.header('Content-Type', 'application/json')
62
- }
63
- return this
64
- }
65
-
66
- public text(content: string): this {
67
- if (this.#responseMode === 'stream') {
68
- this.#send!(content)
69
- } else {
70
- this.#body = content
71
- this.header('Content-Type', 'text/plain')
72
- }
73
- return this
74
- }
75
-
76
- public html(content: string): this {
77
- if (this.#responseMode === 'stream') {
78
- this.#send!(content)
79
- } else {
80
- this.#body = content
81
- this.header('Content-Type', 'text/html')
82
- }
83
- return this
84
- }
85
-
86
- public send(data: any): this {
87
- this.#body = data
88
- return this
89
- }
90
-
91
- public redirect(location: string, status: number = 302): this {
92
- if (
93
- !location.startsWith('/') &&
94
- !location.startsWith('https://') &&
95
- !location.startsWith('http://')
96
- ) {
97
- throw new Error(
98
- 'Invalid redirect location: must be a relative path or absolute URL'
99
- )
100
- }
101
- this.#statusCode = status
102
- this.header('Location', location)
103
- return this
104
- }
105
-
106
- public close(): this {
107
- if (this.#close) {
108
- this.#close()
109
- }
110
- return this
111
- }
112
-
113
- public toResponse(args?: Record<string, any>): Response {
114
- const cookieHeader = Array.from(this.#cookies.entries()).map(
115
- ([name, { value, flags }]) => serializeCookie(name, value, flags)
116
- )
117
- // Multiple Set-Cookie headers must be appended separately, not joined with commas
118
- // per HTTP specification (RFC 6265)
119
- cookieHeader.forEach((cookie) => this.#headers.append('Set-Cookie', cookie))
120
- return new Response(this.#body, {
121
- ...args,
122
- status: this.#statusCode,
123
- headers: this.#headers,
124
- })
125
- }
126
-
127
- private createStream(): ReadableStream<Uint8Array> {
128
- const encoder = new TextEncoder()
129
- return new ReadableStream({
130
- start: (controller) => {
131
- const send = (data: string) => {
132
- controller.enqueue(encoder.encode(`data: ${data}\n\n`))
133
- }
134
-
135
- const close = () => {
136
- controller.close()
137
- }
138
-
139
- this.#send = send
140
- this.#close = close
141
-
142
- // Force initial flush
143
- controller.enqueue(encoder.encode(':\n\n'))
144
- },
145
- })
146
- }
147
- }
@@ -1,13 +0,0 @@
1
- import type { HTTPMethod } from '../http.types.js'
2
- import { PathToRegexRouter } from './path-to-regex.js'
3
-
4
- export type MatchResult = {
5
- route: string
6
- params: Record<string, any>
7
- } | null
8
-
9
- export interface Router {
10
- match(method: HTTPMethod, path: string): MatchResult
11
- }
12
-
13
- export const httpRouter = new PathToRegexRouter()