pika-shared 1.3.0 → 1.4.1

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 (63) hide show
  1. package/dist/index.js.map +1 -1
  2. package/dist/index.mjs.map +1 -1
  3. package/dist/types/chatbot/bedrock-lambda-error.js.map +1 -1
  4. package/dist/types/chatbot/bedrock-lambda-error.mjs.map +1 -1
  5. package/dist/types/chatbot/chatbot-types.d.mts +467 -14
  6. package/dist/types/chatbot/chatbot-types.d.ts +467 -14
  7. package/dist/types/chatbot/chatbot-types.js +6 -2
  8. package/dist/types/chatbot/chatbot-types.js.map +1 -1
  9. package/dist/types/chatbot/chatbot-types.mjs +6 -3
  10. package/dist/types/chatbot/chatbot-types.mjs.map +1 -1
  11. package/dist/types/chatbot/webcomp-types.d.mts +107 -0
  12. package/dist/types/chatbot/webcomp-types.d.ts +107 -0
  13. package/dist/types/chatbot/webcomp-types.js +4 -0
  14. package/dist/types/chatbot/webcomp-types.js.map +1 -0
  15. package/dist/types/chatbot/webcomp-types.mjs +3 -0
  16. package/dist/types/chatbot/webcomp-types.mjs.map +1 -0
  17. package/dist/util/api-gateway-utils.js +14 -1
  18. package/dist/util/api-gateway-utils.js.map +1 -1
  19. package/dist/util/api-gateway-utils.mjs +14 -1
  20. package/dist/util/api-gateway-utils.mjs.map +1 -1
  21. package/dist/util/bad-request-error.d.mts +7 -0
  22. package/dist/util/bad-request-error.d.ts +7 -0
  23. package/dist/util/bad-request-error.js +20 -0
  24. package/dist/util/bad-request-error.js.map +1 -0
  25. package/dist/util/bad-request-error.mjs +18 -0
  26. package/dist/util/bad-request-error.mjs.map +1 -0
  27. package/dist/util/bedrock.js.map +1 -1
  28. package/dist/util/bedrock.mjs.map +1 -1
  29. package/dist/util/chatbot-shared-utils.js.map +1 -1
  30. package/dist/util/chatbot-shared-utils.mjs.map +1 -1
  31. package/dist/util/forbidden-error.d.mts +7 -0
  32. package/dist/util/forbidden-error.d.ts +7 -0
  33. package/dist/util/forbidden-error.js +20 -0
  34. package/dist/util/forbidden-error.js.map +1 -0
  35. package/dist/util/forbidden-error.mjs +18 -0
  36. package/dist/util/forbidden-error.mjs.map +1 -0
  37. package/dist/util/http-status-error.js.map +1 -1
  38. package/dist/util/http-status-error.mjs.map +1 -1
  39. package/dist/util/instruction-assistance-utils.js.map +1 -1
  40. package/dist/util/instruction-assistance-utils.mjs.map +1 -1
  41. package/dist/util/jwt.js.map +1 -1
  42. package/dist/util/jwt.mjs.map +1 -1
  43. package/dist/util/server-client-utils.js.map +1 -1
  44. package/dist/util/server-client-utils.mjs.map +1 -1
  45. package/dist/util/server-utils.d.mts +41 -1
  46. package/dist/util/server-utils.d.ts +41 -1
  47. package/dist/util/server-utils.js +303 -0
  48. package/dist/util/server-utils.js.map +1 -1
  49. package/dist/util/server-utils.mjs +301 -1
  50. package/dist/util/server-utils.mjs.map +1 -1
  51. package/dist/util/unauthorized-error.d.mts +7 -0
  52. package/dist/util/unauthorized-error.d.ts +7 -0
  53. package/dist/util/unauthorized-error.js +20 -0
  54. package/dist/util/unauthorized-error.js.map +1 -0
  55. package/dist/util/unauthorized-error.mjs +18 -0
  56. package/dist/util/unauthorized-error.mjs.map +1 -0
  57. package/dist/util/wc-utils.d.mts +22 -0
  58. package/dist/util/wc-utils.d.ts +22 -0
  59. package/dist/util/wc-utils.js +26 -0
  60. package/dist/util/wc-utils.js.map +1 -0
  61. package/dist/util/wc-utils.mjs +24 -0
  62. package/dist/util/wc-utils.mjs.map +1 -0
  63. package/package.json +1 -1
@@ -0,0 +1,107 @@
1
+ import { UploadStatus } from '../upload-types.mjs';
2
+ import { ShowToastFn, ChatUser, RecordOrUndef, UserAwsCredentials, ShareSessionState, UserPrefs, ChatAppMode, CustomDataUiRepresentation, ChatAppOverridableFeatures, TagDefinition, TagDefinitionWidget, ChatSession, UserDataOverrideSettings, ChatMessageForRendering, ChatApp } from './chatbot-types.mjs';
3
+ import '@aws-sdk/client-bedrock-agent-runtime';
4
+ import '@aws-sdk/client-bedrock-agentcore';
5
+
6
+ type SidebarState = any;
7
+ type Snippet = any;
8
+ /** Declare global event map for pika context request */
9
+ declare global {
10
+ interface HTMLElementEventMap {
11
+ 'pika-context-request': PikaWCContextRequestEvent;
12
+ }
13
+ }
14
+ interface IIdentityState {
15
+ readonly fullName: string;
16
+ readonly initials: string;
17
+ readonly user: ChatUser<RecordOrUndef>;
18
+ readonly isSiteAdmin: boolean;
19
+ readonly isInternalUser: boolean;
20
+ readonly isContentAdmin: boolean;
21
+ getUserAwsCredentials(): Promise<UserAwsCredentials | undefined>;
22
+ }
23
+ interface IAppState {
24
+ readonly showToast: ShowToastFn;
25
+ readonly identity: IIdentityState;
26
+ readonly isMobile: boolean;
27
+ }
28
+ interface IChatAppState {
29
+ readonly entityFeatureEnabled: boolean;
30
+ readonly shareCurrentSessionState: ShareSessionState;
31
+ readonly showToast: ShowToastFn;
32
+ readonly userPrefs: IUserPrefsState;
33
+ readonly mode: ChatAppMode;
34
+ readonly customDataUiRepresentation: CustomDataUiRepresentation | undefined;
35
+ readonly features: ChatAppOverridableFeatures;
36
+ readonly tagDefs: TagDefinition<TagDefinitionWidget>[];
37
+ readonly userIsContentAdmin: boolean;
38
+ readonly userNeedsToProvideDataOverrides: boolean;
39
+ readonly isViewingContentForAnotherUser: boolean;
40
+ readonly currentSessionIsSharedBySomeoneElse: boolean;
41
+ readonly currentShareId: string | undefined;
42
+ readonly currentSessionIsReadOnly: boolean;
43
+ readonly sortedChatSessions: ChatSession<RecordOrUndef>[];
44
+ readonly userDataOverrideSettings: UserDataOverrideSettings;
45
+ readonly enableFileUpload: boolean;
46
+ readonly chatSessions: ChatSession<RecordOrUndef>[];
47
+ readonly waitingForFirstStreamedResponse: boolean;
48
+ readonly isStreamingResponseNow: boolean;
49
+ readonly isInterimSession: boolean;
50
+ readonly currentSession: ChatSession<RecordOrUndef>;
51
+ readonly currentSessionMessages: ChatMessageForRendering[];
52
+ readonly inputFiles: IUploadInstance[];
53
+ readonly newSession: boolean;
54
+ readonly chatInput: string;
55
+ readonly chatApp: ChatApp;
56
+ readonly retrievingMessages: boolean;
57
+ readonly pageTitle: string | undefined;
58
+ setCurrentSessionById(sessionId: string): void;
59
+ removeFile(s3Key: string): void;
60
+ startNewChatSession(): void;
61
+ refreshChatSessions(): Promise<void>;
62
+ downloadFile(s3Key: string): Promise<void>;
63
+ refreshMessagesForCurrentSession(): Promise<void>;
64
+ sendMessage(): Promise<void>;
65
+ getMessageByMessageId(messageId: string): ChatMessageForRendering | undefined;
66
+ uploadFiles(files: File[]): Promise<void>;
67
+ initializeData(): Promise<void>;
68
+ }
69
+ interface IUserPrefsState {
70
+ readonly initialized: boolean;
71
+ readonly prefs: UserPrefs | undefined;
72
+ refreshPrefsFromServer(): Promise<void>;
73
+ getPref<T>(key: string): Promise<T | undefined>;
74
+ modifyPref(key: string, value: unknown): Promise<void>;
75
+ }
76
+ interface IUploadInstance {
77
+ readonly s3Key: string;
78
+ readonly file: File | undefined;
79
+ readonly fileName: string;
80
+ readonly size: number;
81
+ readonly lastModified: number;
82
+ readonly type: string;
83
+ readonly xhr: XMLHttpRequest;
84
+ readonly status: {
85
+ status: UploadStatus['status'];
86
+ progress?: number;
87
+ error?: string;
88
+ };
89
+ }
90
+ /**
91
+ * This is the context object that is passed to the web component when it is rendered.
92
+ */
93
+ interface PikaWCContext {
94
+ appState: IAppState;
95
+ context: 'spotlight' | 'inline' | 'dialog' | 'canvas';
96
+ chatAppState: IChatAppState;
97
+ chatAppId: string;
98
+ }
99
+ type PikaWCContextRequestCallbackFn = (contextRequest: PikaWCContext) => void;
100
+ interface PikaWCContextRequestDetail {
101
+ callback: PikaWCContextRequestCallbackFn;
102
+ }
103
+ interface PikaWCContextRequestEvent extends CustomEvent<PikaWCContextRequestDetail> {
104
+ detail: PikaWCContextRequestDetail;
105
+ }
106
+
107
+ export type { IAppState, IChatAppState, IIdentityState, IUploadInstance, IUserPrefsState, PikaWCContext, PikaWCContextRequestCallbackFn, PikaWCContextRequestDetail, PikaWCContextRequestEvent, SidebarState, Snippet };
@@ -0,0 +1,107 @@
1
+ import { UploadStatus } from '../upload-types.js';
2
+ import { ShowToastFn, ChatUser, RecordOrUndef, UserAwsCredentials, ShareSessionState, UserPrefs, ChatAppMode, CustomDataUiRepresentation, ChatAppOverridableFeatures, TagDefinition, TagDefinitionWidget, ChatSession, UserDataOverrideSettings, ChatMessageForRendering, ChatApp } from './chatbot-types.js';
3
+ import '@aws-sdk/client-bedrock-agent-runtime';
4
+ import '@aws-sdk/client-bedrock-agentcore';
5
+
6
+ type SidebarState = any;
7
+ type Snippet = any;
8
+ /** Declare global event map for pika context request */
9
+ declare global {
10
+ interface HTMLElementEventMap {
11
+ 'pika-context-request': PikaWCContextRequestEvent;
12
+ }
13
+ }
14
+ interface IIdentityState {
15
+ readonly fullName: string;
16
+ readonly initials: string;
17
+ readonly user: ChatUser<RecordOrUndef>;
18
+ readonly isSiteAdmin: boolean;
19
+ readonly isInternalUser: boolean;
20
+ readonly isContentAdmin: boolean;
21
+ getUserAwsCredentials(): Promise<UserAwsCredentials | undefined>;
22
+ }
23
+ interface IAppState {
24
+ readonly showToast: ShowToastFn;
25
+ readonly identity: IIdentityState;
26
+ readonly isMobile: boolean;
27
+ }
28
+ interface IChatAppState {
29
+ readonly entityFeatureEnabled: boolean;
30
+ readonly shareCurrentSessionState: ShareSessionState;
31
+ readonly showToast: ShowToastFn;
32
+ readonly userPrefs: IUserPrefsState;
33
+ readonly mode: ChatAppMode;
34
+ readonly customDataUiRepresentation: CustomDataUiRepresentation | undefined;
35
+ readonly features: ChatAppOverridableFeatures;
36
+ readonly tagDefs: TagDefinition<TagDefinitionWidget>[];
37
+ readonly userIsContentAdmin: boolean;
38
+ readonly userNeedsToProvideDataOverrides: boolean;
39
+ readonly isViewingContentForAnotherUser: boolean;
40
+ readonly currentSessionIsSharedBySomeoneElse: boolean;
41
+ readonly currentShareId: string | undefined;
42
+ readonly currentSessionIsReadOnly: boolean;
43
+ readonly sortedChatSessions: ChatSession<RecordOrUndef>[];
44
+ readonly userDataOverrideSettings: UserDataOverrideSettings;
45
+ readonly enableFileUpload: boolean;
46
+ readonly chatSessions: ChatSession<RecordOrUndef>[];
47
+ readonly waitingForFirstStreamedResponse: boolean;
48
+ readonly isStreamingResponseNow: boolean;
49
+ readonly isInterimSession: boolean;
50
+ readonly currentSession: ChatSession<RecordOrUndef>;
51
+ readonly currentSessionMessages: ChatMessageForRendering[];
52
+ readonly inputFiles: IUploadInstance[];
53
+ readonly newSession: boolean;
54
+ readonly chatInput: string;
55
+ readonly chatApp: ChatApp;
56
+ readonly retrievingMessages: boolean;
57
+ readonly pageTitle: string | undefined;
58
+ setCurrentSessionById(sessionId: string): void;
59
+ removeFile(s3Key: string): void;
60
+ startNewChatSession(): void;
61
+ refreshChatSessions(): Promise<void>;
62
+ downloadFile(s3Key: string): Promise<void>;
63
+ refreshMessagesForCurrentSession(): Promise<void>;
64
+ sendMessage(): Promise<void>;
65
+ getMessageByMessageId(messageId: string): ChatMessageForRendering | undefined;
66
+ uploadFiles(files: File[]): Promise<void>;
67
+ initializeData(): Promise<void>;
68
+ }
69
+ interface IUserPrefsState {
70
+ readonly initialized: boolean;
71
+ readonly prefs: UserPrefs | undefined;
72
+ refreshPrefsFromServer(): Promise<void>;
73
+ getPref<T>(key: string): Promise<T | undefined>;
74
+ modifyPref(key: string, value: unknown): Promise<void>;
75
+ }
76
+ interface IUploadInstance {
77
+ readonly s3Key: string;
78
+ readonly file: File | undefined;
79
+ readonly fileName: string;
80
+ readonly size: number;
81
+ readonly lastModified: number;
82
+ readonly type: string;
83
+ readonly xhr: XMLHttpRequest;
84
+ readonly status: {
85
+ status: UploadStatus['status'];
86
+ progress?: number;
87
+ error?: string;
88
+ };
89
+ }
90
+ /**
91
+ * This is the context object that is passed to the web component when it is rendered.
92
+ */
93
+ interface PikaWCContext {
94
+ appState: IAppState;
95
+ context: 'spotlight' | 'inline' | 'dialog' | 'canvas';
96
+ chatAppState: IChatAppState;
97
+ chatAppId: string;
98
+ }
99
+ type PikaWCContextRequestCallbackFn = (contextRequest: PikaWCContext) => void;
100
+ interface PikaWCContextRequestDetail {
101
+ callback: PikaWCContextRequestCallbackFn;
102
+ }
103
+ interface PikaWCContextRequestEvent extends CustomEvent<PikaWCContextRequestDetail> {
104
+ detail: PikaWCContextRequestDetail;
105
+ }
106
+
107
+ export type { IAppState, IChatAppState, IIdentityState, IUploadInstance, IUserPrefsState, PikaWCContext, PikaWCContextRequestCallbackFn, PikaWCContextRequestDetail, PikaWCContextRequestEvent, SidebarState, Snippet };
@@ -0,0 +1,4 @@
1
+ 'use strict';
2
+
3
+ //# sourceMappingURL=webcomp-types.js.map
4
+ //# sourceMappingURL=webcomp-types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"webcomp-types.js"}
@@ -0,0 +1,3 @@
1
+
2
+ //# sourceMappingURL=webcomp-types.mjs.map
3
+ //# sourceMappingURL=webcomp-types.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"webcomp-types.mjs"}
@@ -1,5 +1,13 @@
1
1
  'use strict';
2
2
 
3
+ // src/util/http-status-error.ts
4
+ var HttpStatusError = class extends Error {
5
+ constructor(message, statusCode) {
6
+ super(message);
7
+ this.statusCode = statusCode;
8
+ }
9
+ };
10
+
3
11
  // src/util/api-gateway-utils.ts
4
12
  function isObjectResponse(data) {
5
13
  return data !== null && data !== void 0 && typeof data === "object" && ("statusCode" in data || "body" in data);
@@ -25,7 +33,12 @@ function apiGatewayFunctionDecorator(fn) {
25
33
  }
26
34
  if (error) {
27
35
  console.error(error);
28
- return toResponse(typeof error === "string" ? error : error.message, error.statusCode ?? 500);
36
+ if (error instanceof HttpStatusError) {
37
+ return toResponse(error.message, error.statusCode);
38
+ }
39
+ const httpError = error;
40
+ const statusCode = httpError.statusCode || 500;
41
+ return toResponse(typeof error === "string" ? error : error.message, statusCode);
29
42
  }
30
43
  if (response === void 0) {
31
44
  return toResponse(
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/util/api-gateway-utils.ts"],"names":[],"mappings":"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","file":"api-gateway-utils.js","sourcesContent":["/**\n * Utility functions and types for AWS API Gateway Lambda integration.\n * This module provides type-safe wrappers and helpers for handling\n * API Gateway events and responses in AWS Lambda functions.\n */\nimport type {\n APIGatewayEventRequestContextV2,\n APIGatewayProxyEventV2WithRequestContext,\n APIGatewayProxyHandlerV2,\n APIGatewayProxyResultV2,\n APIGatewayProxyStructuredResultV2,\n Context\n} from 'aws-lambda';\n\n/**\n * Extends the standard Error interface to include an optional HTTP status code.\n * This allows for standardized error handling with appropriate HTTP responses.\n */\nexport interface HttpError extends Error {\n statusCode?: number;\n}\n\n/**\n * A type that enhances the standard API Gateway event by replacing the body property\n * with a strongly-typed version rather than the default string representation.\n *\n * @template TRequestBody - The type of the request body after parsing\n * @template TRequestContext - The type of the request context\n */\ninterface APIGatewayProxyEventPikaWithRequestContext<TRequestBody, TRequestContext> extends Omit<APIGatewayProxyEventV2WithRequestContext<TRequestContext>, 'body'> {\n body: TRequestBody;\n}\n\n/**\n * A specialized API Gateway event type that includes:\n * 1. A strongly-typed request body\n * 2. The standard API Gateway request context\n * 3. Additional path and httpMethod properties for routing\n *\n * @template TRequestBody - The type of the parsed request body (defaults to never if not provided)\n */\nexport type APIGatewayProxyEventPika<TRequestBody = never> = APIGatewayProxyEventPikaWithRequestContext<TRequestBody, APIGatewayEventRequestContextV2> & {\n path: string;\n httpMethod: string;\n resource: string;\n};\n\n/**\n * A generic handler type for AWS Lambda functions.\n *\n * @template TEvent - The event type (input) for the handler\n * @template TResult - The result type (output) returned by the handler\n * @returns Either void or a Promise containing the result\n */\nexport type HandlerPika<TEvent = unknown, TResult = unknown> = (event: TEvent, context: Context) => void | Promise<TResult>;\n\n/**\n * A specialized handler type for API Gateway Lambda integrations with typed request and response.\n *\n * @template B - The request body type (defaults to never if not provided)\n * @template T - The response type (defaults to never if not provided)\n */\nexport type APIGatewayProxyHandlerPika<B = never, T = never> = HandlerPika<APIGatewayProxyEventPika<B>, APIGatewayProxyResultV2<T>>;\n\n/**\n * Type guard function that determines if the provided data is a structured API Gateway response.\n * A structured response must be an object containing either 'statusCode' or 'body' properties.\n *\n * @template TResponse - The expected response type\n * @param data - The data to check\n * @returns A type predicate indicating if the data is a structured API Gateway response\n */\nfunction isObjectResponse<TResponse>(data: undefined | void | APIGatewayProxyResultV2<TResponse>): data is APIGatewayProxyStructuredResultV2 {\n return data !== null && data !== undefined && typeof data === 'object' && ('statusCode' in data || 'body' in data);\n}\n\n/**\n * A higher-order function that wraps a typed Lambda handler to provide:\n * 1. Automatic JSON parsing of the request body\n * 2. Error handling with appropriate status codes\n * 3. Consistent response formatting\n *\n * @template TRequestBody - The expected type of the request body after parsing\n * @template TResponse - The expected type of the response\n * @param fn - The Lambda handler function to wrap\n * @returns A standard API Gateway Lambda handler with error handling and type safety\n */\nexport function apiGatewayFunctionDecorator<TRequestBody, TResponse>(fn: APIGatewayProxyHandlerPika<TRequestBody, TResponse>): APIGatewayProxyHandlerV2<TResponse> {\n return async (event, context) => {\n let error: HttpError | undefined;\n let response: undefined | void | APIGatewayProxyResultV2<TResponse>;\n\n // Just in case, add another version of the headers with all lowercase keys;\n // helps when running locally. Seems APIGateway automatically converts to lowercase\n Object.keys(event.headers).forEach((k) => {\n let lowerK = k.toLowerCase();\n if (!event.headers[lowerK]) {\n event.headers[lowerK] = event.headers[k];\n }\n });\n try {\n // Parse the request body if present and create a typed event object\n const eventWithType: APIGatewayProxyEventPika<TRequestBody> = {\n ...(event as any),\n body: event.body ? JSON.parse(event.body) : undefined\n };\n\n // Call the handler with the typed event\n response = await fn(eventWithType, context);\n } catch (err) {\n // Capture any errors that occur during processing\n error = err as HttpError;\n }\n\n // Handle errors by returning an appropriate error response\n if (error) {\n console.error(error);\n return toResponse(typeof error === 'string' ? error : error.message, error.statusCode ?? 500);\n }\n\n // Return resource not found if the response is undefined\n if (response === undefined) {\n return toResponse(\n {\n message: 'Resource not found',\n code: 'RESOURCE_NOT_FOUND'\n },\n 404\n );\n }\n\n // Either return the structured response directly or wrap the result in a standard response\n return isObjectResponse(response) ? response : toResponse(response, 200);\n };\n}\n\n/**\n * Creates a standardized API Gateway response object.\n * Handles both string and non-string body types by automatically stringifying as needed.\n *\n * @template T - The type of the response body\n * @param body - The response body to send\n * @param statusCode - The HTTP status code (defaults to 200 OK)\n * @returns A properly formatted API Gateway response object\n */\nexport function toResponse<T>(body: T, statusCode = 200): APIGatewayProxyStructuredResultV2 {\n return {\n body: typeof body === 'string' ? body : JSON.stringify(body),\n statusCode\n };\n}\n\n/**\n * Type definition for Lambda Function URL events with additional IAM authorization details.\n * Extends the standard API Gateway event with specific requestContext properties for\n * Function URL integration patterns.\n *\n * @template T - The request body type\n */\nexport type LambdaFunctionUrlProxyEventPika<T = never> = APIGatewayProxyEventPika<T> & {\n requestContext: {\n authorizer?: {\n iam: {\n cognitoIdentity?: string;\n cognitoIdentityId?: string;\n userId?: string;\n user?: string;\n callerId?: string;\n caller?: string;\n accessKey?: string;\n principalOrgId?: string;\n accountId?: string;\n userArn?: string;\n [key: string]: any;\n };\n };\n identity?: {\n cognitoIdentity?: string;\n cognitoIdentityId?: string;\n user?: string;\n userId?: string;\n caller?: string;\n callerId?: string;\n accessKey?: string;\n principalOrgId?: string;\n accountId?: string;\n userArn?: string;\n [key: string]: any;\n };\n };\n};\n\n/**\n * Converts a Lambda Function URL event into a standardized API Gateway event.\n * This function ensures that IAM authorization details are properly mapped\n * from the authorizer to the identity property for consistent access patterns.\n *\n * Also, parses the body string into the generic type T if it exists and is a string\n *\n * This exists because the Lambda Function URL event has a different structure\n * than the API Gateway event and we almost never use Lambdas that are Function URL based\n * and so it's easier to just convert the event to a standard API Gateway event than\n * to handle the different event types.\n *\n * @template T - The request body type\n * @param event - The Lambda Function URL event to convert\n * @returns A standardized API Gateway event\n */\nexport function convertFunctionUrlEventToStandardApiGatewayEvent<T>(event: LambdaFunctionUrlProxyEventPika<T>): APIGatewayProxyEventPika<T> {\n if (event.requestContext.identity == null && event.requestContext.authorizer?.iam != null) {\n event.requestContext.identity = event.requestContext.authorizer.iam;\n event.requestContext.authorizer.iam.cognitoIdentityId = event.headers['cognito-identity-id'];\n event.requestContext.authorizer.iam.user = event.requestContext.authorizer.iam.userId;\n event.requestContext.authorizer.iam.caller = event.requestContext.authorizer.iam.callerId;\n }\n\n // Parse the body string into the generic type T if it exists and is a string\n if (event.body && typeof event.body === 'string') {\n try {\n // If content-type is not application/json, don't attempt to parse\n const contentType = event.headers['content-type'] || event.headers['Content-Type'];\n if (contentType && contentType.includes('application/json')) {\n event.body = JSON.parse(event.body) as T;\n }\n } catch (error) {\n console.error('Error parsing request body as JSON:', {\n body: event.body,\n errorMessage: error instanceof Error ? error.message : String(error),\n errorStack: error instanceof Error ? error.stack : undefined\n });\n throw error;\n }\n }\n\n return event;\n}\n"]}
1
+ {"version":3,"sources":["../../src/util/http-status-error.ts","../../src/util/api-gateway-utils.ts"],"names":[],"mappings":"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","file":"api-gateway-utils.js","sourcesContent":["/**\n * Throw this error to return a specific HTTP status code from an API Gateway Lambda function.\n */\nexport class HttpStatusError extends Error {\n constructor(\n message: string,\n public readonly statusCode: number\n ) {\n super(message);\n }\n}\n","/**\n * Utility functions and types for AWS API Gateway Lambda integration.\n * This module provides type-safe wrappers and helpers for handling\n * API Gateway events and responses in AWS Lambda functions.\n */\nimport type {\n APIGatewayEventRequestContextV2,\n APIGatewayProxyEventV2WithRequestContext,\n APIGatewayProxyHandlerV2,\n APIGatewayProxyResultV2,\n APIGatewayProxyStructuredResultV2,\n Context\n} from 'aws-lambda';\nimport { HttpStatusError } from './http-status-error';\n\n/**\n * Extends the standard Error interface to include an optional HTTP status code.\n * This allows for standardized error handling with appropriate HTTP responses.\n */\nexport interface HttpError extends Error {\n statusCode?: number;\n}\n\n/**\n * A type that enhances the standard API Gateway event by replacing the body property\n * with a strongly-typed version rather than the default string representation.\n *\n * @template TRequestBody - The type of the request body after parsing\n * @template TRequestContext - The type of the request context\n */\ninterface APIGatewayProxyEventPikaWithRequestContext<TRequestBody, TRequestContext> extends Omit<APIGatewayProxyEventV2WithRequestContext<TRequestContext>, 'body'> {\n body: TRequestBody;\n}\n\n/**\n * A specialized API Gateway event type that includes:\n * 1. A strongly-typed request body\n * 2. The standard API Gateway request context\n * 3. Additional path and httpMethod properties for routing\n *\n * @template TRequestBody - The type of the parsed request body (defaults to never if not provided)\n */\nexport type APIGatewayProxyEventPika<TRequestBody = never> = APIGatewayProxyEventPikaWithRequestContext<TRequestBody, APIGatewayEventRequestContextV2> & {\n path: string;\n httpMethod: string;\n resource: string;\n};\n\n/**\n * A generic handler type for AWS Lambda functions.\n *\n * @template TEvent - The event type (input) for the handler\n * @template TResult - The result type (output) returned by the handler\n * @returns Either void or a Promise containing the result\n */\nexport type HandlerPika<TEvent = unknown, TResult = unknown> = (event: TEvent, context: Context) => void | Promise<TResult>;\n\n/**\n * A specialized handler type for API Gateway Lambda integrations with typed request and response.\n *\n * @template B - The request body type (defaults to never if not provided)\n * @template T - The response type (defaults to never if not provided)\n */\nexport type APIGatewayProxyHandlerPika<B = never, T = never> = HandlerPika<APIGatewayProxyEventPika<B>, APIGatewayProxyResultV2<T>>;\n\n/**\n * Type guard function that determines if the provided data is a structured API Gateway response.\n * A structured response must be an object containing either 'statusCode' or 'body' properties.\n *\n * @template TResponse - The expected response type\n * @param data - The data to check\n * @returns A type predicate indicating if the data is a structured API Gateway response\n */\nfunction isObjectResponse<TResponse>(data: undefined | void | APIGatewayProxyResultV2<TResponse>): data is APIGatewayProxyStructuredResultV2 {\n return data !== null && data !== undefined && typeof data === 'object' && ('statusCode' in data || 'body' in data);\n}\n\n/**\n * A higher-order function that wraps a typed Lambda handler to provide:\n * 1. Automatic JSON parsing of the request body\n * 2. Error handling with appropriate status codes\n * 3. Consistent response formatting\n *\n * @template TRequestBody - The expected type of the request body after parsing\n * @template TResponse - The expected type of the response\n * @param fn - The Lambda handler function to wrap\n * @returns A standard API Gateway Lambda handler with error handling and type safety\n */\nexport function apiGatewayFunctionDecorator<TRequestBody, TResponse>(fn: APIGatewayProxyHandlerPika<TRequestBody, TResponse>): APIGatewayProxyHandlerV2<TResponse> {\n return async (event, context) => {\n let error: any; // Use 'any' to preserve original error type for instanceof checks\n let response: undefined | void | APIGatewayProxyResultV2<TResponse>;\n\n // Just in case, add another version of the headers with all lowercase keys;\n // helps when running locally. Seems APIGateway automatically converts to lowercase\n Object.keys(event.headers).forEach((k) => {\n let lowerK = k.toLowerCase();\n if (!event.headers[lowerK]) {\n event.headers[lowerK] = event.headers[k];\n }\n });\n try {\n // Parse the request body if present and create a typed event object\n const eventWithType: APIGatewayProxyEventPika<TRequestBody> = {\n ...(event as any),\n body: event.body ? JSON.parse(event.body) : undefined\n };\n\n // Call the handler with the typed event\n response = await fn(eventWithType, context);\n } catch (err) {\n // Capture any errors that occur during processing\n error = err;\n }\n\n // Handle errors by returning an appropriate error response\n if (error) {\n console.error(error);\n\n // Handle HttpStatusError specifically (has required statusCode property)\n if (error instanceof HttpStatusError) {\n return toResponse(error.message, error.statusCode);\n }\n\n // Handle other HttpError types (has optional statusCode property)\n const httpError = error as HttpError;\n const statusCode = httpError.statusCode || 500;\n return toResponse(typeof error === 'string' ? error : error.message, statusCode);\n }\n\n // Return resource not found if the response is undefined\n if (response === undefined) {\n return toResponse(\n {\n message: 'Resource not found',\n code: 'RESOURCE_NOT_FOUND'\n },\n 404\n );\n }\n\n // Either return the structured response directly or wrap the result in a standard response\n return isObjectResponse(response) ? response : toResponse(response, 200);\n };\n}\n\n/**\n * Creates a standardized API Gateway response object.\n * Handles both string and non-string body types by automatically stringifying as needed.\n *\n * @template T - The type of the response body\n * @param body - The response body to send\n * @param statusCode - The HTTP status code (defaults to 200 OK)\n * @returns A properly formatted API Gateway response object\n */\nexport function toResponse<T>(body: T, statusCode = 200): APIGatewayProxyStructuredResultV2 {\n return {\n body: typeof body === 'string' ? body : JSON.stringify(body),\n statusCode\n };\n}\n\n/**\n * Type definition for Lambda Function URL events with additional IAM authorization details.\n * Extends the standard API Gateway event with specific requestContext properties for\n * Function URL integration patterns.\n *\n * @template T - The request body type\n */\nexport type LambdaFunctionUrlProxyEventPika<T = never> = APIGatewayProxyEventPika<T> & {\n requestContext: {\n authorizer?: {\n iam: {\n cognitoIdentity?: string;\n cognitoIdentityId?: string;\n userId?: string;\n user?: string;\n callerId?: string;\n caller?: string;\n accessKey?: string;\n principalOrgId?: string;\n accountId?: string;\n userArn?: string;\n [key: string]: any;\n };\n };\n identity?: {\n cognitoIdentity?: string;\n cognitoIdentityId?: string;\n user?: string;\n userId?: string;\n caller?: string;\n callerId?: string;\n accessKey?: string;\n principalOrgId?: string;\n accountId?: string;\n userArn?: string;\n [key: string]: any;\n };\n };\n};\n\n/**\n * Converts a Lambda Function URL event into a standardized API Gateway event.\n * This function ensures that IAM authorization details are properly mapped\n * from the authorizer to the identity property for consistent access patterns.\n *\n * Also, parses the body string into the generic type T if it exists and is a string\n *\n * This exists because the Lambda Function URL event has a different structure\n * than the API Gateway event and we almost never use Lambdas that are Function URL based\n * and so it's easier to just convert the event to a standard API Gateway event than\n * to handle the different event types.\n *\n * @template T - The request body type\n * @param event - The Lambda Function URL event to convert\n * @returns A standardized API Gateway event\n */\nexport function convertFunctionUrlEventToStandardApiGatewayEvent<T>(event: LambdaFunctionUrlProxyEventPika<T>): APIGatewayProxyEventPika<T> {\n if (event.requestContext.identity == null && event.requestContext.authorizer?.iam != null) {\n event.requestContext.identity = event.requestContext.authorizer.iam;\n event.requestContext.authorizer.iam.cognitoIdentityId = event.headers['cognito-identity-id'];\n event.requestContext.authorizer.iam.user = event.requestContext.authorizer.iam.userId;\n event.requestContext.authorizer.iam.caller = event.requestContext.authorizer.iam.callerId;\n }\n\n // Parse the body string into the generic type T if it exists and is a string\n if (event.body && typeof event.body === 'string') {\n try {\n // If content-type is not application/json, don't attempt to parse\n const contentType = event.headers['content-type'] || event.headers['Content-Type'];\n if (contentType && contentType.includes('application/json')) {\n event.body = JSON.parse(event.body) as T;\n }\n } catch (error) {\n console.error('Error parsing request body as JSON:', {\n body: event.body,\n errorMessage: error instanceof Error ? error.message : String(error),\n errorStack: error instanceof Error ? error.stack : undefined\n });\n throw error;\n }\n }\n\n return event;\n}\n"]}
@@ -1,3 +1,11 @@
1
+ // src/util/http-status-error.ts
2
+ var HttpStatusError = class extends Error {
3
+ constructor(message, statusCode) {
4
+ super(message);
5
+ this.statusCode = statusCode;
6
+ }
7
+ };
8
+
1
9
  // src/util/api-gateway-utils.ts
2
10
  function isObjectResponse(data) {
3
11
  return data !== null && data !== void 0 && typeof data === "object" && ("statusCode" in data || "body" in data);
@@ -23,7 +31,12 @@ function apiGatewayFunctionDecorator(fn) {
23
31
  }
24
32
  if (error) {
25
33
  console.error(error);
26
- return toResponse(typeof error === "string" ? error : error.message, error.statusCode ?? 500);
34
+ if (error instanceof HttpStatusError) {
35
+ return toResponse(error.message, error.statusCode);
36
+ }
37
+ const httpError = error;
38
+ const statusCode = httpError.statusCode || 500;
39
+ return toResponse(typeof error === "string" ? error : error.message, statusCode);
27
40
  }
28
41
  if (response === void 0) {
29
42
  return toResponse(
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/util/api-gateway-utils.ts"],"names":[],"mappings":"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","file":"api-gateway-utils.mjs","sourcesContent":["/**\n * Utility functions and types for AWS API Gateway Lambda integration.\n * This module provides type-safe wrappers and helpers for handling\n * API Gateway events and responses in AWS Lambda functions.\n */\nimport type {\n APIGatewayEventRequestContextV2,\n APIGatewayProxyEventV2WithRequestContext,\n APIGatewayProxyHandlerV2,\n APIGatewayProxyResultV2,\n APIGatewayProxyStructuredResultV2,\n Context\n} from 'aws-lambda';\n\n/**\n * Extends the standard Error interface to include an optional HTTP status code.\n * This allows for standardized error handling with appropriate HTTP responses.\n */\nexport interface HttpError extends Error {\n statusCode?: number;\n}\n\n/**\n * A type that enhances the standard API Gateway event by replacing the body property\n * with a strongly-typed version rather than the default string representation.\n *\n * @template TRequestBody - The type of the request body after parsing\n * @template TRequestContext - The type of the request context\n */\ninterface APIGatewayProxyEventPikaWithRequestContext<TRequestBody, TRequestContext> extends Omit<APIGatewayProxyEventV2WithRequestContext<TRequestContext>, 'body'> {\n body: TRequestBody;\n}\n\n/**\n * A specialized API Gateway event type that includes:\n * 1. A strongly-typed request body\n * 2. The standard API Gateway request context\n * 3. Additional path and httpMethod properties for routing\n *\n * @template TRequestBody - The type of the parsed request body (defaults to never if not provided)\n */\nexport type APIGatewayProxyEventPika<TRequestBody = never> = APIGatewayProxyEventPikaWithRequestContext<TRequestBody, APIGatewayEventRequestContextV2> & {\n path: string;\n httpMethod: string;\n resource: string;\n};\n\n/**\n * A generic handler type for AWS Lambda functions.\n *\n * @template TEvent - The event type (input) for the handler\n * @template TResult - The result type (output) returned by the handler\n * @returns Either void or a Promise containing the result\n */\nexport type HandlerPika<TEvent = unknown, TResult = unknown> = (event: TEvent, context: Context) => void | Promise<TResult>;\n\n/**\n * A specialized handler type for API Gateway Lambda integrations with typed request and response.\n *\n * @template B - The request body type (defaults to never if not provided)\n * @template T - The response type (defaults to never if not provided)\n */\nexport type APIGatewayProxyHandlerPika<B = never, T = never> = HandlerPika<APIGatewayProxyEventPika<B>, APIGatewayProxyResultV2<T>>;\n\n/**\n * Type guard function that determines if the provided data is a structured API Gateway response.\n * A structured response must be an object containing either 'statusCode' or 'body' properties.\n *\n * @template TResponse - The expected response type\n * @param data - The data to check\n * @returns A type predicate indicating if the data is a structured API Gateway response\n */\nfunction isObjectResponse<TResponse>(data: undefined | void | APIGatewayProxyResultV2<TResponse>): data is APIGatewayProxyStructuredResultV2 {\n return data !== null && data !== undefined && typeof data === 'object' && ('statusCode' in data || 'body' in data);\n}\n\n/**\n * A higher-order function that wraps a typed Lambda handler to provide:\n * 1. Automatic JSON parsing of the request body\n * 2. Error handling with appropriate status codes\n * 3. Consistent response formatting\n *\n * @template TRequestBody - The expected type of the request body after parsing\n * @template TResponse - The expected type of the response\n * @param fn - The Lambda handler function to wrap\n * @returns A standard API Gateway Lambda handler with error handling and type safety\n */\nexport function apiGatewayFunctionDecorator<TRequestBody, TResponse>(fn: APIGatewayProxyHandlerPika<TRequestBody, TResponse>): APIGatewayProxyHandlerV2<TResponse> {\n return async (event, context) => {\n let error: HttpError | undefined;\n let response: undefined | void | APIGatewayProxyResultV2<TResponse>;\n\n // Just in case, add another version of the headers with all lowercase keys;\n // helps when running locally. Seems APIGateway automatically converts to lowercase\n Object.keys(event.headers).forEach((k) => {\n let lowerK = k.toLowerCase();\n if (!event.headers[lowerK]) {\n event.headers[lowerK] = event.headers[k];\n }\n });\n try {\n // Parse the request body if present and create a typed event object\n const eventWithType: APIGatewayProxyEventPika<TRequestBody> = {\n ...(event as any),\n body: event.body ? JSON.parse(event.body) : undefined\n };\n\n // Call the handler with the typed event\n response = await fn(eventWithType, context);\n } catch (err) {\n // Capture any errors that occur during processing\n error = err as HttpError;\n }\n\n // Handle errors by returning an appropriate error response\n if (error) {\n console.error(error);\n return toResponse(typeof error === 'string' ? error : error.message, error.statusCode ?? 500);\n }\n\n // Return resource not found if the response is undefined\n if (response === undefined) {\n return toResponse(\n {\n message: 'Resource not found',\n code: 'RESOURCE_NOT_FOUND'\n },\n 404\n );\n }\n\n // Either return the structured response directly or wrap the result in a standard response\n return isObjectResponse(response) ? response : toResponse(response, 200);\n };\n}\n\n/**\n * Creates a standardized API Gateway response object.\n * Handles both string and non-string body types by automatically stringifying as needed.\n *\n * @template T - The type of the response body\n * @param body - The response body to send\n * @param statusCode - The HTTP status code (defaults to 200 OK)\n * @returns A properly formatted API Gateway response object\n */\nexport function toResponse<T>(body: T, statusCode = 200): APIGatewayProxyStructuredResultV2 {\n return {\n body: typeof body === 'string' ? body : JSON.stringify(body),\n statusCode\n };\n}\n\n/**\n * Type definition for Lambda Function URL events with additional IAM authorization details.\n * Extends the standard API Gateway event with specific requestContext properties for\n * Function URL integration patterns.\n *\n * @template T - The request body type\n */\nexport type LambdaFunctionUrlProxyEventPika<T = never> = APIGatewayProxyEventPika<T> & {\n requestContext: {\n authorizer?: {\n iam: {\n cognitoIdentity?: string;\n cognitoIdentityId?: string;\n userId?: string;\n user?: string;\n callerId?: string;\n caller?: string;\n accessKey?: string;\n principalOrgId?: string;\n accountId?: string;\n userArn?: string;\n [key: string]: any;\n };\n };\n identity?: {\n cognitoIdentity?: string;\n cognitoIdentityId?: string;\n user?: string;\n userId?: string;\n caller?: string;\n callerId?: string;\n accessKey?: string;\n principalOrgId?: string;\n accountId?: string;\n userArn?: string;\n [key: string]: any;\n };\n };\n};\n\n/**\n * Converts a Lambda Function URL event into a standardized API Gateway event.\n * This function ensures that IAM authorization details are properly mapped\n * from the authorizer to the identity property for consistent access patterns.\n *\n * Also, parses the body string into the generic type T if it exists and is a string\n *\n * This exists because the Lambda Function URL event has a different structure\n * than the API Gateway event and we almost never use Lambdas that are Function URL based\n * and so it's easier to just convert the event to a standard API Gateway event than\n * to handle the different event types.\n *\n * @template T - The request body type\n * @param event - The Lambda Function URL event to convert\n * @returns A standardized API Gateway event\n */\nexport function convertFunctionUrlEventToStandardApiGatewayEvent<T>(event: LambdaFunctionUrlProxyEventPika<T>): APIGatewayProxyEventPika<T> {\n if (event.requestContext.identity == null && event.requestContext.authorizer?.iam != null) {\n event.requestContext.identity = event.requestContext.authorizer.iam;\n event.requestContext.authorizer.iam.cognitoIdentityId = event.headers['cognito-identity-id'];\n event.requestContext.authorizer.iam.user = event.requestContext.authorizer.iam.userId;\n event.requestContext.authorizer.iam.caller = event.requestContext.authorizer.iam.callerId;\n }\n\n // Parse the body string into the generic type T if it exists and is a string\n if (event.body && typeof event.body === 'string') {\n try {\n // If content-type is not application/json, don't attempt to parse\n const contentType = event.headers['content-type'] || event.headers['Content-Type'];\n if (contentType && contentType.includes('application/json')) {\n event.body = JSON.parse(event.body) as T;\n }\n } catch (error) {\n console.error('Error parsing request body as JSON:', {\n body: event.body,\n errorMessage: error instanceof Error ? error.message : String(error),\n errorStack: error instanceof Error ? error.stack : undefined\n });\n throw error;\n }\n }\n\n return event;\n}\n"]}
1
+ {"version":3,"sources":["../../src/util/http-status-error.ts","../../src/util/api-gateway-utils.ts"],"names":[],"mappings":"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","file":"api-gateway-utils.mjs","sourcesContent":["/**\n * Throw this error to return a specific HTTP status code from an API Gateway Lambda function.\n */\nexport class HttpStatusError extends Error {\n constructor(\n message: string,\n public readonly statusCode: number\n ) {\n super(message);\n }\n}\n","/**\n * Utility functions and types for AWS API Gateway Lambda integration.\n * This module provides type-safe wrappers and helpers for handling\n * API Gateway events and responses in AWS Lambda functions.\n */\nimport type {\n APIGatewayEventRequestContextV2,\n APIGatewayProxyEventV2WithRequestContext,\n APIGatewayProxyHandlerV2,\n APIGatewayProxyResultV2,\n APIGatewayProxyStructuredResultV2,\n Context\n} from 'aws-lambda';\nimport { HttpStatusError } from './http-status-error';\n\n/**\n * Extends the standard Error interface to include an optional HTTP status code.\n * This allows for standardized error handling with appropriate HTTP responses.\n */\nexport interface HttpError extends Error {\n statusCode?: number;\n}\n\n/**\n * A type that enhances the standard API Gateway event by replacing the body property\n * with a strongly-typed version rather than the default string representation.\n *\n * @template TRequestBody - The type of the request body after parsing\n * @template TRequestContext - The type of the request context\n */\ninterface APIGatewayProxyEventPikaWithRequestContext<TRequestBody, TRequestContext> extends Omit<APIGatewayProxyEventV2WithRequestContext<TRequestContext>, 'body'> {\n body: TRequestBody;\n}\n\n/**\n * A specialized API Gateway event type that includes:\n * 1. A strongly-typed request body\n * 2. The standard API Gateway request context\n * 3. Additional path and httpMethod properties for routing\n *\n * @template TRequestBody - The type of the parsed request body (defaults to never if not provided)\n */\nexport type APIGatewayProxyEventPika<TRequestBody = never> = APIGatewayProxyEventPikaWithRequestContext<TRequestBody, APIGatewayEventRequestContextV2> & {\n path: string;\n httpMethod: string;\n resource: string;\n};\n\n/**\n * A generic handler type for AWS Lambda functions.\n *\n * @template TEvent - The event type (input) for the handler\n * @template TResult - The result type (output) returned by the handler\n * @returns Either void or a Promise containing the result\n */\nexport type HandlerPika<TEvent = unknown, TResult = unknown> = (event: TEvent, context: Context) => void | Promise<TResult>;\n\n/**\n * A specialized handler type for API Gateway Lambda integrations with typed request and response.\n *\n * @template B - The request body type (defaults to never if not provided)\n * @template T - The response type (defaults to never if not provided)\n */\nexport type APIGatewayProxyHandlerPika<B = never, T = never> = HandlerPika<APIGatewayProxyEventPika<B>, APIGatewayProxyResultV2<T>>;\n\n/**\n * Type guard function that determines if the provided data is a structured API Gateway response.\n * A structured response must be an object containing either 'statusCode' or 'body' properties.\n *\n * @template TResponse - The expected response type\n * @param data - The data to check\n * @returns A type predicate indicating if the data is a structured API Gateway response\n */\nfunction isObjectResponse<TResponse>(data: undefined | void | APIGatewayProxyResultV2<TResponse>): data is APIGatewayProxyStructuredResultV2 {\n return data !== null && data !== undefined && typeof data === 'object' && ('statusCode' in data || 'body' in data);\n}\n\n/**\n * A higher-order function that wraps a typed Lambda handler to provide:\n * 1. Automatic JSON parsing of the request body\n * 2. Error handling with appropriate status codes\n * 3. Consistent response formatting\n *\n * @template TRequestBody - The expected type of the request body after parsing\n * @template TResponse - The expected type of the response\n * @param fn - The Lambda handler function to wrap\n * @returns A standard API Gateway Lambda handler with error handling and type safety\n */\nexport function apiGatewayFunctionDecorator<TRequestBody, TResponse>(fn: APIGatewayProxyHandlerPika<TRequestBody, TResponse>): APIGatewayProxyHandlerV2<TResponse> {\n return async (event, context) => {\n let error: any; // Use 'any' to preserve original error type for instanceof checks\n let response: undefined | void | APIGatewayProxyResultV2<TResponse>;\n\n // Just in case, add another version of the headers with all lowercase keys;\n // helps when running locally. Seems APIGateway automatically converts to lowercase\n Object.keys(event.headers).forEach((k) => {\n let lowerK = k.toLowerCase();\n if (!event.headers[lowerK]) {\n event.headers[lowerK] = event.headers[k];\n }\n });\n try {\n // Parse the request body if present and create a typed event object\n const eventWithType: APIGatewayProxyEventPika<TRequestBody> = {\n ...(event as any),\n body: event.body ? JSON.parse(event.body) : undefined\n };\n\n // Call the handler with the typed event\n response = await fn(eventWithType, context);\n } catch (err) {\n // Capture any errors that occur during processing\n error = err;\n }\n\n // Handle errors by returning an appropriate error response\n if (error) {\n console.error(error);\n\n // Handle HttpStatusError specifically (has required statusCode property)\n if (error instanceof HttpStatusError) {\n return toResponse(error.message, error.statusCode);\n }\n\n // Handle other HttpError types (has optional statusCode property)\n const httpError = error as HttpError;\n const statusCode = httpError.statusCode || 500;\n return toResponse(typeof error === 'string' ? error : error.message, statusCode);\n }\n\n // Return resource not found if the response is undefined\n if (response === undefined) {\n return toResponse(\n {\n message: 'Resource not found',\n code: 'RESOURCE_NOT_FOUND'\n },\n 404\n );\n }\n\n // Either return the structured response directly or wrap the result in a standard response\n return isObjectResponse(response) ? response : toResponse(response, 200);\n };\n}\n\n/**\n * Creates a standardized API Gateway response object.\n * Handles both string and non-string body types by automatically stringifying as needed.\n *\n * @template T - The type of the response body\n * @param body - The response body to send\n * @param statusCode - The HTTP status code (defaults to 200 OK)\n * @returns A properly formatted API Gateway response object\n */\nexport function toResponse<T>(body: T, statusCode = 200): APIGatewayProxyStructuredResultV2 {\n return {\n body: typeof body === 'string' ? body : JSON.stringify(body),\n statusCode\n };\n}\n\n/**\n * Type definition for Lambda Function URL events with additional IAM authorization details.\n * Extends the standard API Gateway event with specific requestContext properties for\n * Function URL integration patterns.\n *\n * @template T - The request body type\n */\nexport type LambdaFunctionUrlProxyEventPika<T = never> = APIGatewayProxyEventPika<T> & {\n requestContext: {\n authorizer?: {\n iam: {\n cognitoIdentity?: string;\n cognitoIdentityId?: string;\n userId?: string;\n user?: string;\n callerId?: string;\n caller?: string;\n accessKey?: string;\n principalOrgId?: string;\n accountId?: string;\n userArn?: string;\n [key: string]: any;\n };\n };\n identity?: {\n cognitoIdentity?: string;\n cognitoIdentityId?: string;\n user?: string;\n userId?: string;\n caller?: string;\n callerId?: string;\n accessKey?: string;\n principalOrgId?: string;\n accountId?: string;\n userArn?: string;\n [key: string]: any;\n };\n };\n};\n\n/**\n * Converts a Lambda Function URL event into a standardized API Gateway event.\n * This function ensures that IAM authorization details are properly mapped\n * from the authorizer to the identity property for consistent access patterns.\n *\n * Also, parses the body string into the generic type T if it exists and is a string\n *\n * This exists because the Lambda Function URL event has a different structure\n * than the API Gateway event and we almost never use Lambdas that are Function URL based\n * and so it's easier to just convert the event to a standard API Gateway event than\n * to handle the different event types.\n *\n * @template T - The request body type\n * @param event - The Lambda Function URL event to convert\n * @returns A standardized API Gateway event\n */\nexport function convertFunctionUrlEventToStandardApiGatewayEvent<T>(event: LambdaFunctionUrlProxyEventPika<T>): APIGatewayProxyEventPika<T> {\n if (event.requestContext.identity == null && event.requestContext.authorizer?.iam != null) {\n event.requestContext.identity = event.requestContext.authorizer.iam;\n event.requestContext.authorizer.iam.cognitoIdentityId = event.headers['cognito-identity-id'];\n event.requestContext.authorizer.iam.user = event.requestContext.authorizer.iam.userId;\n event.requestContext.authorizer.iam.caller = event.requestContext.authorizer.iam.callerId;\n }\n\n // Parse the body string into the generic type T if it exists and is a string\n if (event.body && typeof event.body === 'string') {\n try {\n // If content-type is not application/json, don't attempt to parse\n const contentType = event.headers['content-type'] || event.headers['Content-Type'];\n if (contentType && contentType.includes('application/json')) {\n event.body = JSON.parse(event.body) as T;\n }\n } catch (error) {\n console.error('Error parsing request body as JSON:', {\n body: event.body,\n errorMessage: error instanceof Error ? error.message : String(error),\n errorStack: error instanceof Error ? error.stack : undefined\n });\n throw error;\n }\n }\n\n return event;\n}\n"]}
@@ -0,0 +1,7 @@
1
+ import { HttpStatusError } from './http-status-error.mjs';
2
+
3
+ declare class BadRequestError extends HttpStatusError {
4
+ constructor(message: string);
5
+ }
6
+
7
+ export { BadRequestError };
@@ -0,0 +1,7 @@
1
+ import { HttpStatusError } from './http-status-error.js';
2
+
3
+ declare class BadRequestError extends HttpStatusError {
4
+ constructor(message: string);
5
+ }
6
+
7
+ export { BadRequestError };
@@ -0,0 +1,20 @@
1
+ 'use strict';
2
+
3
+ // src/util/http-status-error.ts
4
+ var HttpStatusError = class extends Error {
5
+ constructor(message, statusCode) {
6
+ super(message);
7
+ this.statusCode = statusCode;
8
+ }
9
+ };
10
+
11
+ // src/util/bad-request-error.ts
12
+ var BadRequestError = class extends HttpStatusError {
13
+ constructor(message) {
14
+ super(message, 400);
15
+ }
16
+ };
17
+
18
+ exports.BadRequestError = BadRequestError;
19
+ //# sourceMappingURL=bad-request-error.js.map
20
+ //# sourceMappingURL=bad-request-error.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/util/http-status-error.ts","../../src/util/bad-request-error.ts"],"names":[],"mappings":";;;AAGO,IAAM,eAAA,GAAN,cAA8B,KAAA,CAAM;AAAA,EACvC,WAAA,CACI,SACgB,UAAA,EAClB;AACE,IAAA,KAAA,CAAM,OAAO,CAAA;AAFG,IAAA,IAAA,CAAA,UAAA,GAAA,UAAA;AAAA,EAGpB;AACJ,CAAA;;;ACRO,IAAM,eAAA,GAAN,cAA8B,eAAA,CAAgB;AAAA,EACjD,YAAY,OAAA,EAAiB;AACzB,IAAA,KAAA,CAAM,SAAS,GAAG,CAAA;AAAA,EACtB;AACJ","file":"bad-request-error.js","sourcesContent":["/**\n * Throw this error to return a specific HTTP status code from an API Gateway Lambda function.\n */\nexport class HttpStatusError extends Error {\n constructor(\n message: string,\n public readonly statusCode: number\n ) {\n super(message);\n }\n}\n","import { HttpStatusError } from './http-status-error';\n\nexport class BadRequestError extends HttpStatusError {\n constructor(message: string) {\n super(message, 400);\n }\n}\n"]}
@@ -0,0 +1,18 @@
1
+ // src/util/http-status-error.ts
2
+ var HttpStatusError = class extends Error {
3
+ constructor(message, statusCode) {
4
+ super(message);
5
+ this.statusCode = statusCode;
6
+ }
7
+ };
8
+
9
+ // src/util/bad-request-error.ts
10
+ var BadRequestError = class extends HttpStatusError {
11
+ constructor(message) {
12
+ super(message, 400);
13
+ }
14
+ };
15
+
16
+ export { BadRequestError };
17
+ //# sourceMappingURL=bad-request-error.mjs.map
18
+ //# sourceMappingURL=bad-request-error.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/util/http-status-error.ts","../../src/util/bad-request-error.ts"],"names":[],"mappings":";AAGO,IAAM,eAAA,GAAN,cAA8B,KAAA,CAAM;AAAA,EACvC,WAAA,CACI,SACgB,UAAA,EAClB;AACE,IAAA,KAAA,CAAM,OAAO,CAAA;AAFG,IAAA,IAAA,CAAA,UAAA,GAAA,UAAA;AAAA,EAGpB;AACJ,CAAA;;;ACRO,IAAM,eAAA,GAAN,cAA8B,eAAA,CAAgB;AAAA,EACjD,YAAY,OAAA,EAAiB;AACzB,IAAA,KAAA,CAAM,SAAS,GAAG,CAAA;AAAA,EACtB;AACJ","file":"bad-request-error.mjs","sourcesContent":["/**\n * Throw this error to return a specific HTTP status code from an API Gateway Lambda function.\n */\nexport class HttpStatusError extends Error {\n constructor(\n message: string,\n public readonly statusCode: number\n ) {\n super(message);\n }\n}\n","import { HttpStatusError } from './http-status-error';\n\nexport class BadRequestError extends HttpStatusError {\n constructor(message: string) {\n super(message, 400);\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/types/chatbot/bedrock-lambda-error.ts","../../src/util/bedrock.ts"],"names":[],"mappings":"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","file":"bedrock.js","sourcesContent":["/**\n * This error is used to allow us to distinguish between errors that are\n * expected to be returned to the user and errors that are unexpected.\n *\n * These errors are caught in the Bedrock Lambda and converted into a\n * BedrockLambdaResponse object using the message as the body.\n */\nexport class BedrockLambdaError extends Error {\n constructor(message: string) {\n super(message);\n }\n}\n","import { BedrockActionGroupLambdaEvent, BedrockActionGroupLambdaResponse, Parameter } from '../types/chatbot/bedrock';\nimport { BedrockLambdaError } from '../types/chatbot/bedrock-lambda-error';\nimport { RecordOrUndef, SessionDataWithChatUserCustomDataSpreadIn } from '../types/chatbot/chatbot-types';\n\n/**\n * Handles an error and returns a BedrockLambdaResponse object.\n *\n * If the error is an instance of BedrockLambdaError, it will be returned as is.\n * Otherwise, it will be converted to a string and returned as a BedrockLambdaError.\n *\n * @param error The error to handle.\n * @returns A BedrockLambdaResponse object.\n */\nexport function handleBedrockError(\n error: unknown,\n event: BedrockActionGroupLambdaEvent,\n sessionAttributes?: SessionDataWithChatUserCustomDataSpreadIn<RecordOrUndef>\n): BedrockActionGroupLambdaResponse {\n if (error instanceof BedrockLambdaError) {\n return createBedrockLambdaResponse(error.message, event.actionGroup, event.messageVersion, event.function ?? 'NoFunctionNameSpecified', sessionAttributes);\n } else {\n console.error('Unexpected error:', error);\n const errorMessage = error instanceof Error ? error.message : String(error);\n return createBedrockLambdaResponse(errorMessage, event.actionGroup, event.messageVersion, event.function ?? 'NoFunctionNameSpecified', sessionAttributes, true);\n }\n}\n\n/**\n * Converter functions for Bedrock parameters.\n */\nexport const converters: Record<string, (v: string) => any> = {\n defaultPassThrough: (v: string) => v,\n number: (v: string) => parseFloat(v),\n boolean: (v: string) => v === 'true',\n integer: (v: string) => parseInt(v),\n array: (v: string) => {\n try {\n // First try to parse as valid JSON\n return JSON.parse(v);\n } catch {\n /* \n TODO: is this a good idea? Why did Bedrock give me a param that was invalid JSON for the array?\n\n {\n \"name\": \"s3Keys\",\n \"type\": \"array\",\n \"value\": \"[uploads/2fbbf97a-070d-48ca-9d5e-fc9bcc88e570/019735c5-b0f0-7419-94d5-093b4202977a_sample-data.csv]\"\n }\n */\n // If JSON.parse fails, try to handle array with unquoted strings\n // Remove brackets and split by comma, then trim whitespace\n if (v.startsWith('[') && v.endsWith(']')) {\n const content = v.slice(1, -1).trim();\n if (content === '') {\n return [];\n }\n return content.split(',').map((item) => item.trim());\n }\n // If it doesn't look like an array format, return as single-item array\n return [v];\n }\n }\n};\n\n/**\n * Converts Bedrock parameters to the correct type.\n * @param params - The parameters to convert.\n * @returns A record of parameter names and their converted values.\n */\nexport function convertBedrockParamsToCorrectType(params?: Parameter[]): Record<string, any> {\n return (\n params?.reduce(\n (acc, param) => {\n acc[param.name] = converters[param.type] ? converters[param.type](param.value) : converters.defaultPassThrough(param.value);\n return acc;\n },\n {} as Record<string, any>\n ) ?? {}\n );\n}\n\n/**\n * Normalizes the session attributes, converting the type to T. An empty sessionAttributes object is the\n * same as undefined.\n *\n * Type T is the type of the session attributes.\n *\n * @param sessionAttributes The session attributes.\n * @returns The normalized session attributes.\n */\nexport function normalizeSessionAttributes(\n sessionAttributes?: SessionDataWithChatUserCustomDataSpreadIn<RecordOrUndef>\n): SessionDataWithChatUserCustomDataSpreadIn<RecordOrUndef> | undefined {\n if (!sessionAttributes || Object.keys(sessionAttributes).length === 0) {\n return undefined;\n }\n\n return sessionAttributes;\n}\n\n/**\n * Creates a BedrockLambdaResponse object.\n *\n * Type T is the type of the session attributes. By including the sessionAttributes\n * parameter, we are telling Bedrock to persist the session attributes for the\n * duration of the session and they will be passed in on all subsequent calls\n * using the event.sessionAttributes parameter.\n *\n * @param body The body of the response.\n * @param actionGroup The action group.\n * @param messageVersion The message version.\n * @param functionName The function name.\n * @param sessionAttributes The session attributes.\n * @param failed Whether the response is a failure.\n * @returns A BedrockLambdaResponse object.\n */\nexport function createBedrockLambdaResponse(\n body: string | Record<string, any>,\n actionGroup: string,\n messageVersion: string,\n functionName: string,\n sessionAttributes?: SessionDataWithChatUserCustomDataSpreadIn<RecordOrUndef>,\n failed?: boolean\n): BedrockActionGroupLambdaResponse {\n return {\n messageVersion,\n response: {\n actionGroup,\n function: functionName,\n functionResponse: {\n ...(failed ? { responseState: 'FAILURE' } : {}),\n responseBody: {\n TEXT: {\n body: typeof body === 'string' ? body : JSON.stringify(body)\n }\n }\n }\n },\n sessionAttributes\n };\n}\n"]}
1
+ {"version":3,"sources":["../../src/types/chatbot/bedrock-lambda-error.ts","../../src/util/bedrock.ts"],"names":[],"mappings":"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","file":"bedrock.js","sourcesContent":["/**\n * This error is used to allow us to distinguish between errors that are\n * expected to be returned to the user and errors that are unexpected.\n *\n * These errors are caught in the Bedrock Lambda and converted into a\n * BedrockLambdaResponse object using the message as the body.\n */\nexport class BedrockLambdaError extends Error {\n constructor(message: string) {\n super(message);\n }\n}\n","import { BedrockActionGroupLambdaEvent, BedrockActionGroupLambdaResponse, Parameter } from '../types/chatbot/bedrock';\nimport { BedrockLambdaError } from '../types/chatbot/bedrock-lambda-error';\nimport { RecordOrUndef, SessionDataWithChatUserCustomDataSpreadIn } from '../types/chatbot/chatbot-types';\n\n/**\n * Handles an error and returns a BedrockLambdaResponse object.\n *\n * If the error is an instance of BedrockLambdaError, it will be returned as is.\n * Otherwise, it will be converted to a string and returned as a BedrockLambdaError.\n *\n * @param error The error to handle.\n * @returns A BedrockLambdaResponse object.\n */\nexport function handleBedrockError(\n error: unknown,\n event: BedrockActionGroupLambdaEvent,\n sessionAttributes?: SessionDataWithChatUserCustomDataSpreadIn<RecordOrUndef>\n): BedrockActionGroupLambdaResponse {\n if (error instanceof BedrockLambdaError) {\n return createBedrockLambdaResponse(error.message, event.actionGroup, event.messageVersion, event.function ?? 'NoFunctionNameSpecified', sessionAttributes);\n } else {\n console.error('Unexpected error:', error);\n const errorMessage = error instanceof Error ? error.message : String(error);\n return createBedrockLambdaResponse(errorMessage, event.actionGroup, event.messageVersion, event.function ?? 'NoFunctionNameSpecified', sessionAttributes, true);\n }\n}\n\n/**\n * Converter functions for Bedrock parameters.\n */\nexport const converters: Record<string, (v: string) => any> = {\n defaultPassThrough: (v: string) => v,\n number: (v: string) => parseFloat(v),\n boolean: (v: string) => v === 'true',\n integer: (v: string) => parseInt(v),\n array: (v: string) => {\n try {\n // First try to parse as valid JSON\n return JSON.parse(v);\n } catch {\n /* \n TODO: is this a good idea? Why did Bedrock give me a param that was invalid JSON for the array?\n\n {\n \"name\": \"s3Keys\",\n \"type\": \"array\",\n \"value\": \"[uploads/2fbbf97a-070d-48ca-9d5e-fc9bcc88e570/019735c5-b0f0-7419-94d5-093b4202977a_sample-data.csv]\"\n }\n */\n // If JSON.parse fails, try to handle array with unquoted strings\n // Remove brackets and split by comma, then trim whitespace\n if (v.startsWith('[') && v.endsWith(']')) {\n const content = v.slice(1, -1).trim();\n if (content === '') {\n return [];\n }\n return content.split(',').map((item) => item.trim());\n }\n // If it doesn't look like an array format, return as single-item array\n return [v];\n }\n }\n};\n\n/**\n * Converts Bedrock parameters to the correct type.\n * @param params - The parameters to convert.\n * @returns A record of parameter names and their converted values.\n */\nexport function convertBedrockParamsToCorrectType(params?: Parameter[]): Record<string, any> {\n return (\n params?.reduce(\n (acc, param) => {\n acc[param.name] = converters[param.type] ? converters[param.type](param.value) : converters.defaultPassThrough(param.value);\n return acc;\n },\n {} as Record<string, any>\n ) ?? {}\n );\n}\n\n/**\n * Normalizes the session attributes, converting the type to T. An empty sessionAttributes object is the\n * same as undefined.\n *\n * Type T is the type of the session attributes.\n *\n * @param sessionAttributes The session attributes.\n * @returns The normalized session attributes.\n */\nexport function normalizeSessionAttributes(\n sessionAttributes?: SessionDataWithChatUserCustomDataSpreadIn<RecordOrUndef>\n): SessionDataWithChatUserCustomDataSpreadIn<RecordOrUndef> | undefined {\n if (!sessionAttributes || Object.keys(sessionAttributes).length === 0) {\n return undefined;\n }\n\n return sessionAttributes;\n}\n\n/**\n * Creates a BedrockLambdaResponse object.\n *\n * Type T is the type of the session attributes. By including the sessionAttributes\n * parameter, we are telling Bedrock to persist the session attributes for the\n * duration of the session and they will be passed in on all subsequent calls\n * using the event.sessionAttributes parameter.\n *\n * @param body The body of the response.\n * @param actionGroup The action group.\n * @param messageVersion The message version.\n * @param functionName The function name.\n * @param sessionAttributes The session attributes.\n * @param failed Whether the response is a failure.\n * @returns A BedrockLambdaResponse object.\n */\nexport function createBedrockLambdaResponse(\n body: string | Record<string, any>,\n actionGroup: string,\n messageVersion: string,\n functionName: string,\n sessionAttributes?: SessionDataWithChatUserCustomDataSpreadIn<RecordOrUndef>,\n failed?: boolean\n): BedrockActionGroupLambdaResponse {\n return {\n messageVersion,\n response: {\n actionGroup,\n function: functionName,\n functionResponse: {\n ...(failed ? { responseState: 'FAILURE' } : {}),\n responseBody: {\n TEXT: {\n body: typeof body === 'string' ? body : JSON.stringify(body)\n }\n }\n }\n },\n sessionAttributes\n };\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/types/chatbot/bedrock-lambda-error.ts","../../src/util/bedrock.ts"],"names":[],"mappings":"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","file":"bedrock.mjs","sourcesContent":["/**\n * This error is used to allow us to distinguish between errors that are\n * expected to be returned to the user and errors that are unexpected.\n *\n * These errors are caught in the Bedrock Lambda and converted into a\n * BedrockLambdaResponse object using the message as the body.\n */\nexport class BedrockLambdaError extends Error {\n constructor(message: string) {\n super(message);\n }\n}\n","import { BedrockActionGroupLambdaEvent, BedrockActionGroupLambdaResponse, Parameter } from '../types/chatbot/bedrock';\nimport { BedrockLambdaError } from '../types/chatbot/bedrock-lambda-error';\nimport { RecordOrUndef, SessionDataWithChatUserCustomDataSpreadIn } from '../types/chatbot/chatbot-types';\n\n/**\n * Handles an error and returns a BedrockLambdaResponse object.\n *\n * If the error is an instance of BedrockLambdaError, it will be returned as is.\n * Otherwise, it will be converted to a string and returned as a BedrockLambdaError.\n *\n * @param error The error to handle.\n * @returns A BedrockLambdaResponse object.\n */\nexport function handleBedrockError(\n error: unknown,\n event: BedrockActionGroupLambdaEvent,\n sessionAttributes?: SessionDataWithChatUserCustomDataSpreadIn<RecordOrUndef>\n): BedrockActionGroupLambdaResponse {\n if (error instanceof BedrockLambdaError) {\n return createBedrockLambdaResponse(error.message, event.actionGroup, event.messageVersion, event.function ?? 'NoFunctionNameSpecified', sessionAttributes);\n } else {\n console.error('Unexpected error:', error);\n const errorMessage = error instanceof Error ? error.message : String(error);\n return createBedrockLambdaResponse(errorMessage, event.actionGroup, event.messageVersion, event.function ?? 'NoFunctionNameSpecified', sessionAttributes, true);\n }\n}\n\n/**\n * Converter functions for Bedrock parameters.\n */\nexport const converters: Record<string, (v: string) => any> = {\n defaultPassThrough: (v: string) => v,\n number: (v: string) => parseFloat(v),\n boolean: (v: string) => v === 'true',\n integer: (v: string) => parseInt(v),\n array: (v: string) => {\n try {\n // First try to parse as valid JSON\n return JSON.parse(v);\n } catch {\n /* \n TODO: is this a good idea? Why did Bedrock give me a param that was invalid JSON for the array?\n\n {\n \"name\": \"s3Keys\",\n \"type\": \"array\",\n \"value\": \"[uploads/2fbbf97a-070d-48ca-9d5e-fc9bcc88e570/019735c5-b0f0-7419-94d5-093b4202977a_sample-data.csv]\"\n }\n */\n // If JSON.parse fails, try to handle array with unquoted strings\n // Remove brackets and split by comma, then trim whitespace\n if (v.startsWith('[') && v.endsWith(']')) {\n const content = v.slice(1, -1).trim();\n if (content === '') {\n return [];\n }\n return content.split(',').map((item) => item.trim());\n }\n // If it doesn't look like an array format, return as single-item array\n return [v];\n }\n }\n};\n\n/**\n * Converts Bedrock parameters to the correct type.\n * @param params - The parameters to convert.\n * @returns A record of parameter names and their converted values.\n */\nexport function convertBedrockParamsToCorrectType(params?: Parameter[]): Record<string, any> {\n return (\n params?.reduce(\n (acc, param) => {\n acc[param.name] = converters[param.type] ? converters[param.type](param.value) : converters.defaultPassThrough(param.value);\n return acc;\n },\n {} as Record<string, any>\n ) ?? {}\n );\n}\n\n/**\n * Normalizes the session attributes, converting the type to T. An empty sessionAttributes object is the\n * same as undefined.\n *\n * Type T is the type of the session attributes.\n *\n * @param sessionAttributes The session attributes.\n * @returns The normalized session attributes.\n */\nexport function normalizeSessionAttributes(\n sessionAttributes?: SessionDataWithChatUserCustomDataSpreadIn<RecordOrUndef>\n): SessionDataWithChatUserCustomDataSpreadIn<RecordOrUndef> | undefined {\n if (!sessionAttributes || Object.keys(sessionAttributes).length === 0) {\n return undefined;\n }\n\n return sessionAttributes;\n}\n\n/**\n * Creates a BedrockLambdaResponse object.\n *\n * Type T is the type of the session attributes. By including the sessionAttributes\n * parameter, we are telling Bedrock to persist the session attributes for the\n * duration of the session and they will be passed in on all subsequent calls\n * using the event.sessionAttributes parameter.\n *\n * @param body The body of the response.\n * @param actionGroup The action group.\n * @param messageVersion The message version.\n * @param functionName The function name.\n * @param sessionAttributes The session attributes.\n * @param failed Whether the response is a failure.\n * @returns A BedrockLambdaResponse object.\n */\nexport function createBedrockLambdaResponse(\n body: string | Record<string, any>,\n actionGroup: string,\n messageVersion: string,\n functionName: string,\n sessionAttributes?: SessionDataWithChatUserCustomDataSpreadIn<RecordOrUndef>,\n failed?: boolean\n): BedrockActionGroupLambdaResponse {\n return {\n messageVersion,\n response: {\n actionGroup,\n function: functionName,\n functionResponse: {\n ...(failed ? { responseState: 'FAILURE' } : {}),\n responseBody: {\n TEXT: {\n body: typeof body === 'string' ? body : JSON.stringify(body)\n }\n }\n }\n },\n sessionAttributes\n };\n}\n"]}
1
+ {"version":3,"sources":["../../src/types/chatbot/bedrock-lambda-error.ts","../../src/util/bedrock.ts"],"names":[],"mappings":"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","file":"bedrock.mjs","sourcesContent":["/**\n * This error is used to allow us to distinguish between errors that are\n * expected to be returned to the user and errors that are unexpected.\n *\n * These errors are caught in the Bedrock Lambda and converted into a\n * BedrockLambdaResponse object using the message as the body.\n */\nexport class BedrockLambdaError extends Error {\n constructor(message: string) {\n super(message);\n }\n}\n","import { BedrockActionGroupLambdaEvent, BedrockActionGroupLambdaResponse, Parameter } from '../types/chatbot/bedrock';\nimport { BedrockLambdaError } from '../types/chatbot/bedrock-lambda-error';\nimport { RecordOrUndef, SessionDataWithChatUserCustomDataSpreadIn } from '../types/chatbot/chatbot-types';\n\n/**\n * Handles an error and returns a BedrockLambdaResponse object.\n *\n * If the error is an instance of BedrockLambdaError, it will be returned as is.\n * Otherwise, it will be converted to a string and returned as a BedrockLambdaError.\n *\n * @param error The error to handle.\n * @returns A BedrockLambdaResponse object.\n */\nexport function handleBedrockError(\n error: unknown,\n event: BedrockActionGroupLambdaEvent,\n sessionAttributes?: SessionDataWithChatUserCustomDataSpreadIn<RecordOrUndef>\n): BedrockActionGroupLambdaResponse {\n if (error instanceof BedrockLambdaError) {\n return createBedrockLambdaResponse(error.message, event.actionGroup, event.messageVersion, event.function ?? 'NoFunctionNameSpecified', sessionAttributes);\n } else {\n console.error('Unexpected error:', error);\n const errorMessage = error instanceof Error ? error.message : String(error);\n return createBedrockLambdaResponse(errorMessage, event.actionGroup, event.messageVersion, event.function ?? 'NoFunctionNameSpecified', sessionAttributes, true);\n }\n}\n\n/**\n * Converter functions for Bedrock parameters.\n */\nexport const converters: Record<string, (v: string) => any> = {\n defaultPassThrough: (v: string) => v,\n number: (v: string) => parseFloat(v),\n boolean: (v: string) => v === 'true',\n integer: (v: string) => parseInt(v),\n array: (v: string) => {\n try {\n // First try to parse as valid JSON\n return JSON.parse(v);\n } catch {\n /* \n TODO: is this a good idea? Why did Bedrock give me a param that was invalid JSON for the array?\n\n {\n \"name\": \"s3Keys\",\n \"type\": \"array\",\n \"value\": \"[uploads/2fbbf97a-070d-48ca-9d5e-fc9bcc88e570/019735c5-b0f0-7419-94d5-093b4202977a_sample-data.csv]\"\n }\n */\n // If JSON.parse fails, try to handle array with unquoted strings\n // Remove brackets and split by comma, then trim whitespace\n if (v.startsWith('[') && v.endsWith(']')) {\n const content = v.slice(1, -1).trim();\n if (content === '') {\n return [];\n }\n return content.split(',').map((item) => item.trim());\n }\n // If it doesn't look like an array format, return as single-item array\n return [v];\n }\n }\n};\n\n/**\n * Converts Bedrock parameters to the correct type.\n * @param params - The parameters to convert.\n * @returns A record of parameter names and their converted values.\n */\nexport function convertBedrockParamsToCorrectType(params?: Parameter[]): Record<string, any> {\n return (\n params?.reduce(\n (acc, param) => {\n acc[param.name] = converters[param.type] ? converters[param.type](param.value) : converters.defaultPassThrough(param.value);\n return acc;\n },\n {} as Record<string, any>\n ) ?? {}\n );\n}\n\n/**\n * Normalizes the session attributes, converting the type to T. An empty sessionAttributes object is the\n * same as undefined.\n *\n * Type T is the type of the session attributes.\n *\n * @param sessionAttributes The session attributes.\n * @returns The normalized session attributes.\n */\nexport function normalizeSessionAttributes(\n sessionAttributes?: SessionDataWithChatUserCustomDataSpreadIn<RecordOrUndef>\n): SessionDataWithChatUserCustomDataSpreadIn<RecordOrUndef> | undefined {\n if (!sessionAttributes || Object.keys(sessionAttributes).length === 0) {\n return undefined;\n }\n\n return sessionAttributes;\n}\n\n/**\n * Creates a BedrockLambdaResponse object.\n *\n * Type T is the type of the session attributes. By including the sessionAttributes\n * parameter, we are telling Bedrock to persist the session attributes for the\n * duration of the session and they will be passed in on all subsequent calls\n * using the event.sessionAttributes parameter.\n *\n * @param body The body of the response.\n * @param actionGroup The action group.\n * @param messageVersion The message version.\n * @param functionName The function name.\n * @param sessionAttributes The session attributes.\n * @param failed Whether the response is a failure.\n * @returns A BedrockLambdaResponse object.\n */\nexport function createBedrockLambdaResponse(\n body: string | Record<string, any>,\n actionGroup: string,\n messageVersion: string,\n functionName: string,\n sessionAttributes?: SessionDataWithChatUserCustomDataSpreadIn<RecordOrUndef>,\n failed?: boolean\n): BedrockActionGroupLambdaResponse {\n return {\n messageVersion,\n response: {\n actionGroup,\n function: functionName,\n functionResponse: {\n ...(failed ? { responseState: 'FAILURE' } : {}),\n responseBody: {\n TEXT: {\n body: typeof body === 'string' ? body : JSON.stringify(body)\n }\n }\n }\n },\n sessionAttributes\n };\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/util/chatbot-shared-utils.ts"],"names":["camelcaseKeys","snakecaseKeys"],"mappings":";;;;;;;;;;;AAwBO,SAAS,+BAAA,CAAgC,MAAgB,EAAA,QAAA,EAAkB,MAAwB,EAAA;AACtG,EAAA,OAAO,CAAW,QAAA,EAAA,MAAM,CAAI,CAAA,EAAA,MAAM,IAAI,QAAQ,CAAA,CAAA;AAClD;AAQO,SAAS,iBAAiB,QAA0B,EAAA;AACvD,EAAM,MAAA,YAAA,GAAe,QAAS,CAAA,WAAA,CAAY,GAAG,CAAA;AAG7C,EAAA,IAAI,iBAAiB,EAAM,IAAA,YAAA,KAAiB,SAAS,MAAS,GAAA,CAAA,IAAK,iBAAiB,CAAG,EAAA;AACnF,IAAO,OAAA,QAAA,CAAS,OAAQ,CAAA,iBAAA,EAAmB,EAAE,CAAA;AAAA;AAGjD,EAAA,MAAM,oBAAuB,GAAA,QAAA,CAAS,SAAU,CAAA,CAAA,EAAG,YAAY,CAAA;AAC/D,EAAA,MAAM,SAAY,GAAA,QAAA,CAAS,SAAU,CAAA,YAAA,GAAe,CAAC,CAAA;AAErD,EAAA,MAAM,aAAgB,GAAA,oBAAA,CAAqB,OAAQ,CAAA,iBAAA,EAAmB,EAAE,CAAA;AACxE,EAAA,MAAM,kBAAqB,GAAA,SAAA,CAAU,OAAQ,CAAA,iBAAA,EAAmB,EAAE,CAAA;AAElE,EAAA,OAAO,gBAAgB,GAAM,GAAA,kBAAA;AACjC;AAcO,SAAS,mBAAqC,IAAuB,EAAA;AACxE,EAAA,OAAOA,8BAAc,CAAA,IAAA,EAAM,EAAE,IAAA,EAAM,MAAM,CAAA;AAC7C;AAEO,SAAS,mBAAqD,IAAuB,EAAA;AACxF,EAAA,OAAOC,8BAAc,CAAA,IAAA,EAAM,EAAE,IAAA,EAAM,MAAM,CAAA;AAC7C;AAEO,SAAS,yBAAyB,GAAqB,EAAA;AAC1D,EAAA,MAAM,OAAU,GAAA,EAAE,CAAC,GAAG,GAAG,IAAK,EAAA;AAC9B,EAAM,MAAA,SAAA,GAAYA,+BAAc,OAAO,CAAA;AACvC,EAAA,OAAO,MAAO,CAAA,IAAA,CAAK,SAAS,CAAA,CAAE,CAAC,CAAA;AACnC","file":"chatbot-shared-utils.js","sourcesContent":["/**\n * These utilities are meant to be shared both client and server.\n * Don't add anything that can't be shared (especially dependencies)\n */\n\nimport type { ChatApp, ChatAppFeature, FeatureIdType } from '../types/chatbot/chatbot-types';\nimport camelcaseKeys from 'camelcase-keys';\nimport snakecaseKeys from 'snakecase-keys';\n\n/**\n * Generate a unique S3 key name for a chat file upload.\n *\n * Use the uuid module to generate the v7 uuid as in\n *\n * Replace punctation that isn't _ or - with a _\n *\n * import { v7 as uuidv7 } from 'uuid';\n * uuidv7()\n *\n * @param userId - The user id of the user uploading the file\n * @param fileName - The name of the file to upload. it should already be sanitized by calling sanitizeFileName\n * @param v7Uuid - The uuidv7 uuid of the file\n * @returns The S3 key name for the file\n */\nexport function generateChatFileUploadS3KeyName(userId: string, fileName: string, v7Uuid: string): string {\n return `uploads/${userId}/${v7Uuid}_${fileName}`;\n}\n\n/**\n * Remove all punctuation from a file name except for the ending period for the file extension if it exists\n *\n * @param fileName - The name of the file to sanitize\n * @returns The sanitized file name\n */\nexport function sanitizeFileName(fileName: string): string {\n const lastDotIndex = fileName.lastIndexOf('.');\n\n // If there's no dot, or the dot is at the end, or the dot is at the beginning, just remove all punctuation\n if (lastDotIndex === -1 || lastDotIndex === fileName.length - 1 || lastDotIndex === 0) {\n return fileName.replace(/[^a-zA-Z0-9_-]/g, '');\n }\n\n const nameWithoutExtension = fileName.substring(0, lastDotIndex);\n const extension = fileName.substring(lastDotIndex + 1);\n\n const sanitizedName = nameWithoutExtension.replace(/[^a-zA-Z0-9_-]/g, '');\n const sanitizedExtension = extension.replace(/[^a-zA-Z0-9_-]/g, '');\n\n return sanitizedName + '.' + sanitizedExtension;\n}\n\ntype ToSnakeCase<S extends string> = S extends `${infer T}${infer U}` ? `${T extends Capitalize<T> ? '_' : ''}${Lowercase<T>}${ToSnakeCase<U>}` : S;\n\ntype ToCamelCase<S extends string> = S extends `${infer P1}_${infer P2}${infer P3}` ? `${Lowercase<P1>}${Uppercase<P2>}${ToCamelCase<P3>}` : Lowercase<S>;\n\nexport type SnakeCase<T> = {\n [K in keyof T as K extends string ? ToSnakeCase<K> : K]: T[K] extends object ? SnakeCase<T[K]> : T[K];\n};\n\nexport type CamelCase<T> = {\n [K in keyof T as K extends string ? ToCamelCase<K> : K]: T[K] extends object ? CamelCase<T[K]> : T[K];\n};\n\nexport function convertToCamelCase<T extends object>(data: SnakeCase<T>): T {\n return camelcaseKeys(data, { deep: true }) as unknown as T;\n}\n\nexport function convertToSnakeCase<T extends { [key: string]: any }>(data: T): SnakeCase<T> {\n return snakecaseKeys(data, { deep: true }) as SnakeCase<T>;\n}\n\nexport function convertStringToSnakeCase(str: string): string {\n const tempObj = { [str]: true };\n const converted = snakecaseKeys(tempObj);\n return Object.keys(converted)[0];\n}\n\n// /**\n// * This lets us get a feature from a chat app and make sure it is the correct type.\n// */\n// export function getFeature<T extends FeatureIdType>(chatApp: ChatApp, featureId: T): Extract<ChatAppFeature, { featureId: T }> | undefined {\n// const feature = chatApp.features?.[featureId];\n\n// if (feature && feature.featureId === featureId) {\n// return feature as Extract<ChatAppFeature, { featureId: T }>;\n// }\n\n// return undefined;\n// }\n"]}
1
+ {"version":3,"sources":["../../src/util/chatbot-shared-utils.ts"],"names":["camelcaseKeys","snakecaseKeys"],"mappings":";;;;;;;;;;;AAwBO,SAAS,+BAAA,CAAgC,MAAA,EAAgB,QAAA,EAAkB,MAAA,EAAwB;AACtG,EAAA,OAAO,CAAA,QAAA,EAAW,MAAM,CAAA,CAAA,EAAI,MAAM,IAAI,QAAQ,CAAA,CAAA;AAClD;AAQO,SAAS,iBAAiB,QAAA,EAA0B;AACvD,EAAA,MAAM,YAAA,GAAe,QAAA,CAAS,WAAA,CAAY,GAAG,CAAA;AAG7C,EAAA,IAAI,iBAAiB,EAAA,IAAM,YAAA,KAAiB,SAAS,MAAA,GAAS,CAAA,IAAK,iBAAiB,CAAA,EAAG;AACnF,IAAA,OAAO,QAAA,CAAS,OAAA,CAAQ,iBAAA,EAAmB,EAAE,CAAA;AAAA,EACjD;AAEA,EAAA,MAAM,oBAAA,GAAuB,QAAA,CAAS,SAAA,CAAU,CAAA,EAAG,YAAY,CAAA;AAC/D,EAAA,MAAM,SAAA,GAAY,QAAA,CAAS,SAAA,CAAU,YAAA,GAAe,CAAC,CAAA;AAErD,EAAA,MAAM,aAAA,GAAgB,oBAAA,CAAqB,OAAA,CAAQ,iBAAA,EAAmB,EAAE,CAAA;AACxE,EAAA,MAAM,kBAAA,GAAqB,SAAA,CAAU,OAAA,CAAQ,iBAAA,EAAmB,EAAE,CAAA;AAElE,EAAA,OAAO,gBAAgB,GAAA,GAAM,kBAAA;AACjC;AAcO,SAAS,mBAAqC,IAAA,EAAuB;AACxE,EAAA,OAAOA,8BAAA,CAAc,IAAA,EAAM,EAAE,IAAA,EAAM,MAAM,CAAA;AAC7C;AAEO,SAAS,mBAAqD,IAAA,EAAuB;AACxF,EAAA,OAAOC,8BAAA,CAAc,IAAA,EAAM,EAAE,IAAA,EAAM,MAAM,CAAA;AAC7C;AAEO,SAAS,yBAAyB,GAAA,EAAqB;AAC1D,EAAA,MAAM,OAAA,GAAU,EAAE,CAAC,GAAG,GAAG,IAAA,EAAK;AAC9B,EAAA,MAAM,SAAA,GAAYA,+BAAc,OAAO,CAAA;AACvC,EAAA,OAAO,MAAA,CAAO,IAAA,CAAK,SAAS,CAAA,CAAE,CAAC,CAAA;AACnC","file":"chatbot-shared-utils.js","sourcesContent":["/**\n * These utilities are meant to be shared both client and server.\n * Don't add anything that can't be shared (especially dependencies)\n */\n\nimport type { ChatApp, ChatAppFeature, FeatureIdType } from '../types/chatbot/chatbot-types';\nimport camelcaseKeys from 'camelcase-keys';\nimport snakecaseKeys from 'snakecase-keys';\n\n/**\n * Generate a unique S3 key name for a chat file upload.\n *\n * Use the uuid module to generate the v7 uuid as in\n *\n * Replace punctation that isn't _ or - with a _\n *\n * import { v7 as uuidv7 } from 'uuid';\n * uuidv7()\n *\n * @param userId - The user id of the user uploading the file\n * @param fileName - The name of the file to upload. it should already be sanitized by calling sanitizeFileName\n * @param v7Uuid - The uuidv7 uuid of the file\n * @returns The S3 key name for the file\n */\nexport function generateChatFileUploadS3KeyName(userId: string, fileName: string, v7Uuid: string): string {\n return `uploads/${userId}/${v7Uuid}_${fileName}`;\n}\n\n/**\n * Remove all punctuation from a file name except for the ending period for the file extension if it exists\n *\n * @param fileName - The name of the file to sanitize\n * @returns The sanitized file name\n */\nexport function sanitizeFileName(fileName: string): string {\n const lastDotIndex = fileName.lastIndexOf('.');\n\n // If there's no dot, or the dot is at the end, or the dot is at the beginning, just remove all punctuation\n if (lastDotIndex === -1 || lastDotIndex === fileName.length - 1 || lastDotIndex === 0) {\n return fileName.replace(/[^a-zA-Z0-9_-]/g, '');\n }\n\n const nameWithoutExtension = fileName.substring(0, lastDotIndex);\n const extension = fileName.substring(lastDotIndex + 1);\n\n const sanitizedName = nameWithoutExtension.replace(/[^a-zA-Z0-9_-]/g, '');\n const sanitizedExtension = extension.replace(/[^a-zA-Z0-9_-]/g, '');\n\n return sanitizedName + '.' + sanitizedExtension;\n}\n\ntype ToSnakeCase<S extends string> = S extends `${infer T}${infer U}` ? `${T extends Capitalize<T> ? '_' : ''}${Lowercase<T>}${ToSnakeCase<U>}` : S;\n\ntype ToCamelCase<S extends string> = S extends `${infer P1}_${infer P2}${infer P3}` ? `${Lowercase<P1>}${Uppercase<P2>}${ToCamelCase<P3>}` : Lowercase<S>;\n\nexport type SnakeCase<T> = {\n [K in keyof T as K extends string ? ToSnakeCase<K> : K]: T[K] extends object ? SnakeCase<T[K]> : T[K];\n};\n\nexport type CamelCase<T> = {\n [K in keyof T as K extends string ? ToCamelCase<K> : K]: T[K] extends object ? CamelCase<T[K]> : T[K];\n};\n\nexport function convertToCamelCase<T extends object>(data: SnakeCase<T>): T {\n return camelcaseKeys(data, { deep: true }) as unknown as T;\n}\n\nexport function convertToSnakeCase<T extends { [key: string]: any }>(data: T): SnakeCase<T> {\n return snakecaseKeys(data, { deep: true }) as SnakeCase<T>;\n}\n\nexport function convertStringToSnakeCase(str: string): string {\n const tempObj = { [str]: true };\n const converted = snakecaseKeys(tempObj);\n return Object.keys(converted)[0];\n}\n\n// /**\n// * This lets us get a feature from a chat app and make sure it is the correct type.\n// */\n// export function getFeature<T extends FeatureIdType>(chatApp: ChatApp, featureId: T): Extract<ChatAppFeature, { featureId: T }> | undefined {\n// const feature = chatApp.features?.[featureId];\n\n// if (feature && feature.featureId === featureId) {\n// return feature as Extract<ChatAppFeature, { featureId: T }>;\n// }\n\n// return undefined;\n// }\n"]}