@pikku/core 0.6.9

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 (167) hide show
  1. package/CHANGELOG.md +339 -0
  2. package/README.md +5 -0
  3. package/dist/channel/channel-handler.d.ts +3 -0
  4. package/dist/channel/channel-handler.js +97 -0
  5. package/dist/channel/channel-runner.d.ts +26 -0
  6. package/dist/channel/channel-runner.js +86 -0
  7. package/dist/channel/channel-store.d.ts +14 -0
  8. package/dist/channel/channel-store.js +2 -0
  9. package/dist/channel/channel.types.d.ts +106 -0
  10. package/dist/channel/channel.types.js +1 -0
  11. package/dist/channel/eventhub-forwarder.d.ts +17 -0
  12. package/dist/channel/eventhub-forwarder.js +1 -0
  13. package/dist/channel/eventhub-service.d.ts +23 -0
  14. package/dist/channel/eventhub-service.js +1 -0
  15. package/dist/channel/eventhub-store.d.ts +5 -0
  16. package/dist/channel/eventhub-store.js +2 -0
  17. package/dist/channel/index.d.ts +9 -0
  18. package/dist/channel/index.js +9 -0
  19. package/dist/channel/local/index.d.ts +3 -0
  20. package/dist/channel/local/index.js +3 -0
  21. package/dist/channel/local/local-channel-handler.d.ts +17 -0
  22. package/dist/channel/local/local-channel-handler.js +41 -0
  23. package/dist/channel/local/local-channel-runner.d.ts +3 -0
  24. package/dist/channel/local/local-channel-runner.js +46 -0
  25. package/dist/channel/local/local-eventhub-service.d.ts +44 -0
  26. package/dist/channel/local/local-eventhub-service.js +81 -0
  27. package/dist/channel/log-channels.d.ts +6 -0
  28. package/dist/channel/log-channels.js +17 -0
  29. package/dist/channel/pikku-abstract-channel-handler.d.ts +15 -0
  30. package/dist/channel/pikku-abstract-channel-handler.js +33 -0
  31. package/dist/channel/serverless/index.d.ts +1 -0
  32. package/dist/channel/serverless/index.js +1 -0
  33. package/dist/channel/serverless/serverless-channel-runner.d.ts +10 -0
  34. package/dist/channel/serverless/serverless-channel-runner.js +98 -0
  35. package/dist/errors/error-handler.d.ts +39 -0
  36. package/dist/errors/error-handler.js +54 -0
  37. package/dist/errors/errors.d.ts +190 -0
  38. package/dist/errors/errors.js +315 -0
  39. package/dist/errors/index.d.ts +2 -0
  40. package/dist/errors/index.js +2 -0
  41. package/dist/http/http-route-runner.d.ts +30 -0
  42. package/dist/http/http-route-runner.js +208 -0
  43. package/dist/http/http-routes.types.d.ts +127 -0
  44. package/dist/http/http-routes.types.js +1 -0
  45. package/dist/http/http-session-service.d.ts +15 -0
  46. package/dist/http/http-session-service.js +1 -0
  47. package/dist/http/index.d.ts +6 -0
  48. package/dist/http/index.js +5 -0
  49. package/dist/http/log-http-routes.d.ts +6 -0
  50. package/dist/http/log-http-routes.js +17 -0
  51. package/dist/http/pikku-http-abstract-request.d.ts +57 -0
  52. package/dist/http/pikku-http-abstract-request.js +69 -0
  53. package/dist/http/pikku-http-abstract-response.d.ts +58 -0
  54. package/dist/http/pikku-http-abstract-response.js +54 -0
  55. package/dist/http/pikku-http-session-service.d.ts +45 -0
  56. package/dist/http/pikku-http-session-service.js +92 -0
  57. package/dist/index.d.ts +14 -0
  58. package/dist/index.js +14 -0
  59. package/dist/permissions.d.ts +10 -0
  60. package/dist/permissions.js +32 -0
  61. package/dist/pikku-request.d.ts +14 -0
  62. package/dist/pikku-request.js +21 -0
  63. package/dist/pikku-response.d.ts +6 -0
  64. package/dist/pikku-response.js +6 -0
  65. package/dist/scheduler/index.d.ts +3 -0
  66. package/dist/scheduler/index.js +3 -0
  67. package/dist/scheduler/log-schedulers.d.ts +6 -0
  68. package/dist/scheduler/log-schedulers.js +17 -0
  69. package/dist/scheduler/scheduler-runner.d.ts +21 -0
  70. package/dist/scheduler/scheduler-runner.js +73 -0
  71. package/dist/scheduler/scheduler.types.d.ts +21 -0
  72. package/dist/scheduler/scheduler.types.js +1 -0
  73. package/dist/schema.d.ts +26 -0
  74. package/dist/schema.js +100 -0
  75. package/dist/services/content-service.d.ts +55 -0
  76. package/dist/services/content-service.js +1 -0
  77. package/dist/services/index.d.ts +12 -0
  78. package/dist/services/index.js +14 -0
  79. package/dist/services/jwt-service.d.ts +29 -0
  80. package/dist/services/jwt-service.js +1 -0
  81. package/dist/services/local-content.d.ts +33 -0
  82. package/dist/services/local-content.js +6 -0
  83. package/dist/services/local-secrets.d.ts +26 -0
  84. package/dist/services/local-secrets.js +39 -0
  85. package/dist/services/local-variables.d.ts +7 -0
  86. package/dist/services/local-variables.js +12 -0
  87. package/dist/services/logger-console.d.ts +52 -0
  88. package/dist/services/logger-console.js +82 -0
  89. package/dist/services/logger.d.ts +48 -0
  90. package/dist/services/logger.js +9 -0
  91. package/dist/services/schema-service.d.ts +24 -0
  92. package/dist/services/schema-service.js +1 -0
  93. package/dist/services/secret-service.d.ts +17 -0
  94. package/dist/services/secret-service.js +1 -0
  95. package/dist/services/user-session-service.d.ts +6 -0
  96. package/dist/services/user-session-service.js +1 -0
  97. package/dist/services/variables-service.d.ts +4 -0
  98. package/dist/services/variables-service.js +1 -0
  99. package/dist/types/core.types.d.ts +109 -0
  100. package/dist/types/core.types.js +1 -0
  101. package/dist/types/functions.types.d.ts +27 -0
  102. package/dist/types/functions.types.js +1 -0
  103. package/dist/utils.d.ts +2 -0
  104. package/dist/utils.js +15 -0
  105. package/package.json +48 -0
  106. package/run-tests.sh +53 -0
  107. package/src/channel/channel-handler.ts +179 -0
  108. package/src/channel/channel-runner.ts +156 -0
  109. package/src/channel/channel-store.ts +32 -0
  110. package/src/channel/channel.types.ts +202 -0
  111. package/src/channel/eventhub-forwarder.ts +25 -0
  112. package/src/channel/eventhub-service.ts +30 -0
  113. package/src/channel/eventhub-store.ts +8 -0
  114. package/src/channel/index.ts +9 -0
  115. package/src/channel/local/index.ts +3 -0
  116. package/src/channel/local/local-channel-handler.ts +56 -0
  117. package/src/channel/local/local-channel-runner.test.ts +128 -0
  118. package/src/channel/local/local-channel-runner.ts +94 -0
  119. package/src/channel/local/local-eventhub-service.test.ts +95 -0
  120. package/src/channel/local/local-eventhub-service.ts +95 -0
  121. package/src/channel/log-channels.ts +20 -0
  122. package/src/channel/pikku-abstract-channel-handler.test.ts +77 -0
  123. package/src/channel/pikku-abstract-channel-handler.ts +44 -0
  124. package/src/channel/serverless/index.ts +1 -0
  125. package/src/channel/serverless/serverless-channel-runner.ts +190 -0
  126. package/src/errors/error-handler.ts +74 -0
  127. package/src/errors/error.test.ts +54 -0
  128. package/src/errors/errors.ts +340 -0
  129. package/src/errors/index.ts +2 -0
  130. package/src/http/http-route-runner.test.ts +193 -0
  131. package/src/http/http-route-runner.ts +365 -0
  132. package/src/http/http-routes.types.ts +189 -0
  133. package/src/http/http-session-service.ts +19 -0
  134. package/src/http/index.ts +16 -0
  135. package/src/http/log-http-routes.ts +20 -0
  136. package/src/http/pikku-http-abstract-request.ts +95 -0
  137. package/src/http/pikku-http-abstract-response.ts +79 -0
  138. package/src/http/pikku-http-session-service.test.ts +106 -0
  139. package/src/http/pikku-http-session-service.ts +135 -0
  140. package/src/index.ts +15 -0
  141. package/src/permissions.test.ts +58 -0
  142. package/src/permissions.ts +45 -0
  143. package/src/pikku-request.ts +19 -0
  144. package/src/pikku-response.ts +5 -0
  145. package/src/scheduler/index.ts +11 -0
  146. package/src/scheduler/log-schedulers.ts +20 -0
  147. package/src/scheduler/scheduler-runner.ts +132 -0
  148. package/src/scheduler/scheduler.types.ts +27 -0
  149. package/src/schema.test.ts +57 -0
  150. package/src/schema.ts +124 -0
  151. package/src/services/content-service.ts +69 -0
  152. package/src/services/index.ts +16 -0
  153. package/src/services/jwt-service.ts +36 -0
  154. package/src/services/local-content.ts +39 -0
  155. package/src/services/local-secrets.ts +43 -0
  156. package/src/services/local-variables.ts +17 -0
  157. package/src/services/logger-console.ts +97 -0
  158. package/src/services/logger.ts +57 -0
  159. package/src/services/schema-service.ts +26 -0
  160. package/src/services/secret-service.ts +17 -0
  161. package/src/services/user-session-service.ts +7 -0
  162. package/src/services/variables-service.ts +6 -0
  163. package/src/types/core.types.ts +162 -0
  164. package/src/types/functions.types.ts +44 -0
  165. package/src/utils.ts +21 -0
  166. package/tsconfig.json +13 -0
  167. package/tsconfig.tsbuildinfo +1 -0
@@ -0,0 +1,208 @@
1
+ import { getErrorResponse } from '../errors/error-handler.js';
2
+ import { verifyPermissions } from '../permissions.js';
3
+ import { match } from 'path-to-regexp';
4
+ import { PikkuHTTPAbstractRequest } from './pikku-http-abstract-request.js';
5
+ import { PikkuHTTPAbstractResponse } from './pikku-http-abstract-response.js';
6
+ import { ForbiddenError, NotFoundError, NotImplementedError, } from '../errors/errors.js';
7
+ import crypto from 'crypto';
8
+ import { closeSessionServices } from '../utils.js';
9
+ import { getSchema, validateAndCoerce } from '../schema.js';
10
+ if (!globalThis.pikku?.httpRoutes) {
11
+ globalThis.pikku = globalThis.pikku || {};
12
+ globalThis.pikku.httpRoutes = [];
13
+ globalThis.pikku.httpRoutesMeta = [];
14
+ }
15
+ const httpRoutes = (data) => {
16
+ if (data) {
17
+ globalThis.pikku.httpRoutes = data;
18
+ }
19
+ return globalThis.pikku.httpRoutes;
20
+ };
21
+ const httpRoutesMeta = (data) => {
22
+ if (data) {
23
+ globalThis.pikku.httpRoutesMeta = data;
24
+ }
25
+ return globalThis.pikku.httpRoutesMeta;
26
+ };
27
+ export const addRoute = (route) => {
28
+ httpRoutes().push(route);
29
+ };
30
+ export const clearRoutes = () => {
31
+ httpRoutes([]);
32
+ };
33
+ /**
34
+ * @ignore
35
+ */
36
+ export const setHTTPRoutesMeta = (_routeMeta) => {
37
+ httpRoutesMeta(_routeMeta);
38
+ };
39
+ /**
40
+ * Returns all the registered routes and associated metadata.
41
+ * @internal
42
+ */
43
+ export const getRoutes = () => {
44
+ return {
45
+ routes: httpRoutes(),
46
+ routesMeta: httpRoutesMeta(),
47
+ };
48
+ };
49
+ const getMatchingRoute = (schemaService, requestType, requestPath) => {
50
+ for (const route of httpRoutes()) {
51
+ // TODO: This is a performance improvement, but we could
52
+ // run against all routes if we want to return a 405 method.
53
+ // Probably want a cache to support.
54
+ if (route.method !== requestType.toLowerCase()) {
55
+ continue;
56
+ }
57
+ const matchFunc = match(`/${route.route}`.replace(/^\/\//, '/'), {
58
+ decode: decodeURIComponent,
59
+ });
60
+ const matchedPath = matchFunc(requestPath.replace(/^\/\//, '/'));
61
+ if (matchedPath) {
62
+ // TODO: Cache this loop as a performance improvement
63
+ const schemaName = httpRoutesMeta().find((routeMeta) => routeMeta.method === route.method && routeMeta.route === route.route)?.input;
64
+ if (schemaName && schemaService) {
65
+ const schema = getSchema(schemaName);
66
+ schemaService.compileSchema(schemaName, schema);
67
+ }
68
+ return { matchedPath, params: matchedPath.params, route, schemaName };
69
+ }
70
+ }
71
+ return undefined;
72
+ };
73
+ export const getUserSession = async (httpSessionService, auth, request) => {
74
+ if (httpSessionService) {
75
+ return (await httpSessionService.getUserSession(auth, request));
76
+ }
77
+ else if (auth) {
78
+ throw new NotImplementedError('Session service not implemented');
79
+ }
80
+ return undefined;
81
+ };
82
+ export const loadUserSession = async (skipUserSession, requiresSession, http, matchedPath, route, logger, httpSessionService) => {
83
+ if (skipUserSession && requiresSession) {
84
+ throw new Error("Can't skip trying to get user session if auth is required");
85
+ }
86
+ if (skipUserSession === false) {
87
+ try {
88
+ if (http?.request) {
89
+ return await getUserSession(httpSessionService, requiresSession, http.request);
90
+ }
91
+ else if (requiresSession) {
92
+ logger.error({
93
+ action: 'Can only get user session with HTTP request',
94
+ path: matchedPath,
95
+ route,
96
+ });
97
+ throw new Error('Can only get user session with HTTP request');
98
+ }
99
+ }
100
+ catch (e) {
101
+ if (requiresSession) {
102
+ logger.info({
103
+ action: 'Rejecting route (invalid session)',
104
+ path: matchedPath,
105
+ });
106
+ throw e;
107
+ }
108
+ }
109
+ }
110
+ return undefined;
111
+ };
112
+ export const createHTTPInteraction = (request, response) => {
113
+ let http = undefined;
114
+ if (request instanceof PikkuHTTPAbstractRequest ||
115
+ response instanceof PikkuHTTPAbstractResponse) {
116
+ http = {};
117
+ if (request instanceof PikkuHTTPAbstractRequest) {
118
+ http.request = request;
119
+ }
120
+ if (response instanceof PikkuHTTPAbstractResponse) {
121
+ http.response = response;
122
+ }
123
+ }
124
+ return http;
125
+ };
126
+ export const handleError = (e, http, trackerId, logger, logWarningsForStatusCodes, respondWith404, bubbleError) => {
127
+ if (e instanceof NotFoundError && !respondWith404) {
128
+ return;
129
+ }
130
+ const errorResponse = getErrorResponse(e);
131
+ if (errorResponse != null) {
132
+ http?.response?.setStatus(errorResponse.status);
133
+ http?.response?.setJson({
134
+ message: errorResponse.message,
135
+ payload: e.payload,
136
+ traceId: trackerId,
137
+ });
138
+ if (logWarningsForStatusCodes.includes(errorResponse.status)) {
139
+ logger.warn(`Warning id: ${trackerId}`);
140
+ logger.warn(e);
141
+ }
142
+ }
143
+ else {
144
+ logger.warn(`Error id: ${trackerId}`);
145
+ logger.error(e);
146
+ http?.response?.setStatus(500);
147
+ http?.response?.setJson({ errorId: trackerId });
148
+ }
149
+ if (e instanceof NotFoundError) {
150
+ http?.response?.end();
151
+ }
152
+ if (bubbleError) {
153
+ throw e;
154
+ }
155
+ };
156
+ /**
157
+ * @ignore
158
+ */
159
+ export const runHTTPRoute = async ({ singletonServices, request, response, createSessionServices, route: apiRoute, method: apiType, skipUserSession = false, respondWith404 = true, logWarningsForStatusCodes = [], coerceToArray = false, bubbleErrors = false, }) => {
160
+ let sessionServices;
161
+ const trackerId = crypto.randomUUID().toString();
162
+ const http = createHTTPInteraction(request, response);
163
+ const matchedRoute = getMatchingRoute(singletonServices.schemaService, apiType, apiRoute);
164
+ try {
165
+ if (!matchedRoute) {
166
+ singletonServices.logger.info({
167
+ message: 'Route not found',
168
+ apiRoute,
169
+ apiType,
170
+ });
171
+ throw new NotFoundError(`Route not found: ${apiRoute}`);
172
+ }
173
+ const { matchedPath, params, route, schemaName } = matchedRoute;
174
+ const requiresSession = route.auth !== false;
175
+ http?.request?.setParams(params);
176
+ singletonServices.logger.info(`Matched route: ${route.route} | method: ${route.method.toUpperCase()} | auth: ${requiresSession.toString()}`);
177
+ const session = await loadUserSession(skipUserSession, requiresSession, http, matchedPath, route, singletonServices.logger, singletonServices.httpSessionService);
178
+ const data = await request.getData();
179
+ validateAndCoerce(singletonServices.logger, singletonServices.schemaService, schemaName, data, coerceToArray);
180
+ sessionServices = await createSessionServices(singletonServices, { http }, session);
181
+ const allServices = { ...singletonServices, ...sessionServices, http };
182
+ if (singletonServices.enforceHTTPAccess) {
183
+ await singletonServices.enforceHTTPAccess(route, session);
184
+ }
185
+ const permissioned = await verifyPermissions(route.permissions, allServices, data, session);
186
+ if (permissioned === false) {
187
+ throw new ForbiddenError('Permission denied');
188
+ }
189
+ const result = (await route.func(allServices, data, session));
190
+ if (route.returnsJSON === false) {
191
+ http?.response?.setResponse(result);
192
+ }
193
+ else {
194
+ http?.response?.setJson(result);
195
+ }
196
+ http?.response?.setStatus(200);
197
+ http?.response?.end();
198
+ return result;
199
+ }
200
+ catch (e) {
201
+ handleError(e, http, trackerId, singletonServices.logger, logWarningsForStatusCodes, respondWith404, bubbleErrors);
202
+ }
203
+ finally {
204
+ if (sessionServices) {
205
+ await closeSessionServices(singletonServices.logger, sessionServices);
206
+ }
207
+ }
208
+ };
@@ -0,0 +1,127 @@
1
+ import { EError } from '../errors/error-handler.js';
2
+ import { APIDocs, CoreServices, CoreSingletonServices, CoreUserSession, CreateSessionServices } from '../types/core.types.js';
3
+ import { CoreAPIFunction, CoreAPIFunctionSessionless, CoreAPIPermission } from '../types/functions.types.js';
4
+ import { PikkuRequest } from '../pikku-request.js';
5
+ import { PikkuResponse } from '../pikku-response.js';
6
+ import { PikkuHTTPAbstractRequest } from './pikku-http-abstract-request.js';
7
+ import { PikkuHTTPAbstractResponse } from './pikku-http-abstract-response.js';
8
+ type ExtractRouteParams<S extends string> = S extends `${string}:${infer Param}/${infer Rest}` ? Param | ExtractRouteParams<`/${Rest}`> : S extends `${string}:${infer Param}` ? Param : never;
9
+ export type AssertRouteParams<In, Route extends string> = ExtractRouteParams<Route> extends keyof In ? unknown : ['Error: Route parameters', ExtractRouteParams<Route>, 'not in', keyof In];
10
+ export type RunRouteOptions = Partial<{
11
+ skipUserSession: boolean;
12
+ respondWith404: boolean;
13
+ logWarningsForStatusCodes: number[];
14
+ coerceToArray: boolean;
15
+ bubbleErrors: boolean;
16
+ }>;
17
+ export type RunRouteParams<In> = {
18
+ singletonServices: CoreSingletonServices;
19
+ request: PikkuRequest<In> | PikkuHTTPAbstractRequest<In>;
20
+ response?: PikkuResponse | PikkuHTTPAbstractResponse | undefined;
21
+ createSessionServices: CreateSessionServices<CoreSingletonServices, CoreServices<CoreSingletonServices>, CoreUserSession>;
22
+ };
23
+ /**
24
+ * Represents the HTTP methods supported for API routes.
25
+ */
26
+ export type HTTPMethod = 'post' | 'get' | 'delete' | 'patch' | 'head' | 'put' | 'options';
27
+ /**
28
+ * Represents an API route without a function, including metadata such as content type, route, and timeout settings.
29
+ */
30
+ export type CoreHTTPFunction = {
31
+ contentType?: 'xml' | 'json';
32
+ route: string;
33
+ eventChannel?: false;
34
+ returnsJSON?: false;
35
+ timeout?: number;
36
+ docs?: Partial<{
37
+ description: string;
38
+ response: string;
39
+ errors: Array<typeof EError>;
40
+ tags: string[];
41
+ }>;
42
+ };
43
+ /**
44
+ * Represents a http interaction within Pikku, including a request and response.
45
+ */
46
+ export interface PikkuHTTP {
47
+ request?: PikkuHTTPAbstractRequest;
48
+ response?: PikkuHTTPAbstractResponse;
49
+ }
50
+ /**
51
+ * Represents request headers as either a record or a function to get headers by name.
52
+ */
53
+ export type RequestHeaders = Record<string, string | string[] | undefined> | ((headerName: string) => string | string[] | undefined);
54
+ /**
55
+ * Represents a query object for Pikku, where each key can be a string, a value, or an array of values.
56
+ */
57
+ export type PikkuQuery<T = Record<string, string | undefined>> = Record<string, string | T | null | Array<T | null>>;
58
+ /**
59
+ * Represents a core API route, which can have different configurations depending on whether it requires authentication and permissions.
60
+ *
61
+ * @template In - The input type.
62
+ * @template Out - The output type.
63
+ * @template R - The route string type.
64
+ * @template APIFunction - The API function type, defaults to `CoreAPIFunction`.
65
+ * @template APIFunctionSessionless - The sessionless API function type, defaults to `CoreAPIFunctionSessionless`.
66
+ * @template APIPermission - The permission function type, defaults to `CoreAPIPermission`.
67
+ */
68
+ export type CoreHTTPFunctionRoute<In, Out, R extends string, APIFunction = CoreAPIFunction<In, Out>, APIFunctionSessionless = CoreAPIFunctionSessionless<In, Out>, APIPermission = CoreAPIPermission<In>> = (CoreHTTPFunction & {
69
+ route: R;
70
+ method: HTTPMethod;
71
+ func: APIFunction;
72
+ permissions?: Record<string, APIPermission[] | APIPermission>;
73
+ auth?: true;
74
+ }) | (CoreHTTPFunction & {
75
+ route: R;
76
+ method: HTTPMethod;
77
+ func: APIFunctionSessionless;
78
+ permissions?: undefined;
79
+ auth?: false;
80
+ }) | (CoreHTTPFunction & {
81
+ route: R;
82
+ method: 'post';
83
+ func: APIFunction;
84
+ permissions?: Record<string, APIPermission[] | APIPermission>;
85
+ auth?: true;
86
+ query?: Array<keyof In>;
87
+ }) | (CoreHTTPFunction & {
88
+ route: R;
89
+ method: 'post';
90
+ func: APIFunctionSessionless;
91
+ permissions?: undefined;
92
+ auth?: false;
93
+ query?: Array<keyof In>;
94
+ });
95
+ /**
96
+ * Represents an array of core API routes.
97
+ */
98
+ export type CoreHTTPFunctionRoutes = Array<CoreHTTPFunctionRoute<any, any, string>>;
99
+ /**
100
+ * Represents the input types for route metadata, including parameters, query, and body types.
101
+ */
102
+ export type HTTPFunctionMetaInputTypes = {
103
+ params?: string;
104
+ query?: string;
105
+ body?: string;
106
+ };
107
+ /**
108
+ * Represents metadata for a set of routes, including route details, methods, input/output types, and documentation.
109
+ */
110
+ export type HTTPRoutesMeta = Array<{
111
+ route: string;
112
+ method: HTTPMethod;
113
+ params?: string[];
114
+ query?: string[];
115
+ input: string | null;
116
+ output: string | null;
117
+ inputTypes?: HTTPFunctionMetaInputTypes;
118
+ docs?: APIDocs;
119
+ }>;
120
+ /**
121
+ * Verifies access to a route.
122
+ * @param route - The route to verify access for.
123
+ * @param session - The user session.
124
+ * @returns A promise that resolves if access is granted.
125
+ */
126
+ export type enforceHTTPAccess = (route: CoreHTTPFunctionRoute<unknown, unknown, any>, session?: CoreUserSession) => Promise<void> | void;
127
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,15 @@
1
+ import { CoreUserSession } from '../types/core.types.js';
2
+ import { PikkuHTTPAbstractRequest } from './pikku-http-abstract-request.js';
3
+ /**
4
+ * Interface for handling user sessions.
5
+ * @template UserSession - The type of the user session.
6
+ */
7
+ export interface HTTPSessionService<UserSession = CoreUserSession> {
8
+ /**
9
+ * Retrieves the user session.
10
+ * @param credentialsRequired - A flag indicating whether credentials are required.
11
+ * @param pikkuRequest - The request object.
12
+ * @returns A promise that resolves to the user session or undefined.
13
+ */
14
+ getUserSession: (credentialsRequired: boolean, pikkuRequest: PikkuHTTPAbstractRequest) => Promise<UserSession | undefined>;
15
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,6 @@
1
+ export * from './pikku-http-session-service.js';
2
+ export * from './pikku-http-abstract-request.js';
3
+ export * from './pikku-http-abstract-response.js';
4
+ export * from './log-http-routes.js';
5
+ export { runHTTPRoute, getRoutes, setHTTPRoutesMeta, addRoute, } from './http-route-runner.js';
6
+ export type * from './http-routes.types.js';
@@ -0,0 +1,5 @@
1
+ export * from './pikku-http-session-service.js';
2
+ export * from './pikku-http-abstract-request.js';
3
+ export * from './pikku-http-abstract-response.js';
4
+ export * from './log-http-routes.js';
5
+ export { runHTTPRoute, getRoutes, setHTTPRoutesMeta, addRoute, } from './http-route-runner.js';
@@ -0,0 +1,6 @@
1
+ import { Logger } from '../services/index.js';
2
+ /**
3
+ * Logs all the loaded routes.
4
+ * @param logger - A logger for logging information.
5
+ */
6
+ export declare const logRoutes: (logger: Logger) => void;
@@ -0,0 +1,17 @@
1
+ import { getRoutes } from './http-route-runner.js';
2
+ /**
3
+ * Logs all the loaded routes.
4
+ * @param logger - A logger for logging information.
5
+ */
6
+ export const logRoutes = (logger) => {
7
+ const { routes } = getRoutes();
8
+ if (routes.length === 0) {
9
+ logger.info('No routes added');
10
+ return;
11
+ }
12
+ let routesMessage = 'Routes loaded:';
13
+ for (const { method, route } of routes) {
14
+ routesMessage += `\n\t- ${method.toUpperCase()} -> ${route}`;
15
+ }
16
+ logger.info(routesMessage);
17
+ };
@@ -0,0 +1,57 @@
1
+ import { PikkuRequest } from '../pikku-request.js';
2
+ import { PikkuQuery } from './http-routes.types.js';
3
+ /**
4
+ * Abstract class representing a pikku request.
5
+ * @template In - The type of the request body.
6
+ * @group RequestResponse
7
+ */
8
+ export declare abstract class PikkuHTTPAbstractRequest<In = unknown> extends PikkuRequest<In> {
9
+ private params;
10
+ /**
11
+ * Retrieves the request body.
12
+ * @returns A promise that resolves to the request body.
13
+ */
14
+ abstract getBody(): Promise<In>;
15
+ /**
16
+ * Retrieves the raw request body as a Buffer.
17
+ * @returns A promise that resolves to the raw request body.
18
+ */
19
+ getRawBody(): Promise<Buffer>;
20
+ /**
21
+ * Retrieves the value of a specific header.
22
+ * @param headerName - The name of the header to retrieve.
23
+ * @returns The value of the header, or undefined if the header is not found.
24
+ */
25
+ abstract getHeader(headerName: string): string | undefined;
26
+ /**
27
+ * Retrieves the cookies from the request.
28
+ * @returns An object containing the cookies.
29
+ */
30
+ getCookies(): Partial<Record<string, string>>;
31
+ /**
32
+ * Retrieves the request parameters.
33
+ * @returns An object containing the request parameters.
34
+ */
35
+ getParams(): Partial<Record<string, string | string[]>>;
36
+ /**
37
+ * Sets the request parameters.
38
+ * @param params - An object containing the request parameters to set.
39
+ */
40
+ setParams(params: Record<string, string | string[] | undefined>): void;
41
+ /**
42
+ * Retrieves the query parameters from the request.
43
+ * @returns An object containing the query parameters.
44
+ */
45
+ getQuery(): PikkuQuery;
46
+ /**
47
+ * Retrieves the IP address of the client making the request.
48
+ * @returns The IP address of the client.
49
+ * @throws {Error} This method is not implemented and should be overridden by subclasses.
50
+ */
51
+ getIP(): string;
52
+ /**
53
+ * Retrieves the combined data from the request, including parameters, query, and body.
54
+ * @returns A promise that resolves to an object containing the combined data.
55
+ */
56
+ getData(): Promise<In>;
57
+ }
@@ -0,0 +1,69 @@
1
+ import { parse as parseCookie } from 'cookie';
2
+ import { PikkuRequest } from '../pikku-request.js';
3
+ /**
4
+ * Abstract class representing a pikku request.
5
+ * @template In - The type of the request body.
6
+ * @group RequestResponse
7
+ */
8
+ export class PikkuHTTPAbstractRequest extends PikkuRequest {
9
+ params = {};
10
+ /**
11
+ * Retrieves the raw request body as a Buffer.
12
+ * @returns A promise that resolves to the raw request body.
13
+ */
14
+ getRawBody() {
15
+ throw new Error('Method not implemented.');
16
+ }
17
+ /**
18
+ * Retrieves the cookies from the request.
19
+ * @returns An object containing the cookies.
20
+ */
21
+ getCookies() {
22
+ const cookieHeader = this.getHeader('cookie');
23
+ if (cookieHeader) {
24
+ return parseCookie(cookieHeader);
25
+ }
26
+ return {};
27
+ }
28
+ /**
29
+ * Retrieves the request parameters.
30
+ * @returns An object containing the request parameters.
31
+ */
32
+ getParams() {
33
+ return this.params;
34
+ }
35
+ /**
36
+ * Sets the request parameters.
37
+ * @param params - An object containing the request parameters to set.
38
+ */
39
+ setParams(params) {
40
+ this.params = params;
41
+ }
42
+ /**
43
+ * Retrieves the query parameters from the request.
44
+ * @returns An object containing the query parameters.
45
+ */
46
+ getQuery() {
47
+ return {};
48
+ }
49
+ /**
50
+ * Retrieves the IP address of the client making the request.
51
+ * @returns The IP address of the client.
52
+ * @throws {Error} This method is not implemented and should be overridden by subclasses.
53
+ */
54
+ getIP() {
55
+ throw new Error('Method not implemented.');
56
+ }
57
+ /**
58
+ * Retrieves the combined data from the request, including parameters, query, and body.
59
+ * @returns A promise that resolves to an object containing the combined data.
60
+ */
61
+ async getData() {
62
+ return {
63
+ ...this.getParams(),
64
+ ...this.getQuery(),
65
+ // TODO: If body isn't an object, we should insert it as the word...
66
+ ...(await this.getBody()),
67
+ };
68
+ }
69
+ }
@@ -0,0 +1,58 @@
1
+ import { SerializeOptions } from 'cookie';
2
+ import { JSONValue } from '../types/core.types.js';
3
+ import { PikkuResponse } from '../pikku-response.js';
4
+ /**
5
+ * Abstract class representing a pikku response.
6
+ * @group RequestResponse
7
+ */
8
+ export declare abstract class PikkuHTTPAbstractResponse extends PikkuResponse {
9
+ /**
10
+ * Sets the HTTP status code for the response.
11
+ * @param status - The HTTP status code to set.
12
+ */
13
+ abstract setStatus(status: number): void;
14
+ /**
15
+ * Sets the JSON body for the response.
16
+ * @param body - The JSON body to set.
17
+ */
18
+ abstract setJson(body: JSONValue): void;
19
+ /**
20
+ * Sets the response content.
21
+ * @param response - The response content, which can be a string or a Buffer.
22
+ */
23
+ abstract setResponse(response: string | Buffer): void;
24
+ /**
25
+ * Sets a header for the response.
26
+ * @param name - The name of the header.
27
+ * @param value - The value of the header, which can be a string, boolean, or an array of strings.
28
+ */
29
+ setHeader(name: string, value: string | boolean | string[]): void;
30
+ /**
31
+ * Sets multiple headers for the response.
32
+ * @param headers - An object containing header names and values.
33
+ */
34
+ setHeaders(headers: Record<string, string>): void;
35
+ /**
36
+ * Sets a cookie for the response.
37
+ * @param name - The name of the cookie.
38
+ * @param value - The value of the cookie.
39
+ * @param options - Options for cookie serialization.
40
+ */
41
+ setCookie(name: string, value: string, options: SerializeOptions): void;
42
+ /**
43
+ * Clears a cookie from the response.
44
+ * @param name - The name of the cookie to clear.
45
+ */
46
+ clearCookie(name: string): void;
47
+ /**
48
+ * Sets a redirect for the response.
49
+ * @param path - The path to redirect to.
50
+ * @param status - The HTTP status code for the redirect.
51
+ */
52
+ setRedirect(path: string, status: number): void;
53
+ /**
54
+ * Informs the response that it has ended, useful for when setting
55
+ * a status without a body or response.
56
+ */
57
+ end(): void;
58
+ }
@@ -0,0 +1,54 @@
1
+ import { serialize } from 'cookie';
2
+ import { PikkuResponse } from '../pikku-response.js';
3
+ /**
4
+ * Abstract class representing a pikku response.
5
+ * @group RequestResponse
6
+ */
7
+ export class PikkuHTTPAbstractResponse extends PikkuResponse {
8
+ /**
9
+ * Sets a header for the response.
10
+ * @param name - The name of the header.
11
+ * @param value - The value of the header, which can be a string, boolean, or an array of strings.
12
+ */
13
+ setHeader(name, value) {
14
+ throw new Error('Method not implemented.');
15
+ }
16
+ /**
17
+ * Sets multiple headers for the response.
18
+ * @param headers - An object containing header names and values.
19
+ */
20
+ setHeaders(headers) {
21
+ for (const [name, value] of Object.entries(headers)) {
22
+ this.setHeader(name, value);
23
+ }
24
+ }
25
+ /**
26
+ * Sets a cookie for the response.
27
+ * @param name - The name of the cookie.
28
+ * @param value - The value of the cookie.
29
+ * @param options - Options for cookie serialization.
30
+ */
31
+ setCookie(name, value, options) {
32
+ this.setHeader('set-cookie', serialize(name, value, options));
33
+ }
34
+ /**
35
+ * Clears a cookie from the response.
36
+ * @param name - The name of the cookie to clear.
37
+ */
38
+ clearCookie(name) {
39
+ this.setHeader('set-cookie', serialize(name, '', { expires: new Date(0) }));
40
+ }
41
+ /**
42
+ * Sets a redirect for the response.
43
+ * @param path - The path to redirect to.
44
+ * @param status - The HTTP status code for the redirect.
45
+ */
46
+ setRedirect(path, status) {
47
+ throw new Error('Method not implemented.');
48
+ }
49
+ /**
50
+ * Informs the response that it has ended, useful for when setting
51
+ * a status without a body or response.
52
+ */
53
+ end() { }
54
+ }