quidproquo-actionprocessor-awslambda 0.0.261 → 0.0.263
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/commonjs/getActionProcessor/core/ai/aiModelMap.d.ts +2 -0
- package/lib/commonjs/getActionProcessor/core/ai/aiModelMap.js +15 -0
- package/lib/commonjs/getActionProcessor/core/ai/getAiPromptActionProcessor.d.ts +2 -0
- package/lib/commonjs/getActionProcessor/core/ai/getAiPromptActionProcessor.js +75 -0
- package/lib/commonjs/getActionProcessor/core/ai/getAiPromptStreamActionProcessor.d.ts +2 -0
- package/lib/commonjs/getActionProcessor/core/ai/getAiPromptStreamActionProcessor.js +126 -0
- package/lib/commonjs/getActionProcessor/core/ai/index.d.ts +2 -0
- package/lib/commonjs/getActionProcessor/core/ai/index.js +18 -0
- package/lib/commonjs/getActionProcessor/core/apiKeyValidation/getApiKeyValidationValidateActionProcessor.d.ts +2 -0
- package/lib/commonjs/getActionProcessor/core/apiKeyValidation/getApiKeyValidationValidateActionProcessor.js +39 -0
- package/lib/commonjs/getActionProcessor/core/apiKeyValidation/index.d.ts +2 -0
- package/lib/commonjs/getActionProcessor/core/apiKeyValidation/index.js +17 -0
- package/lib/commonjs/getActionProcessor/core/event/apiGatwayEvent/api/getEventAutoRespondActionProcessor.js +2 -34
- package/lib/commonjs/getActionProcessor/core/event/apiGatwayEvent/api/getEventGetStorySessionActionProcessor.js +2 -31
- package/lib/commonjs/getActionProcessor/core/event/apiGatwayEvent/websocket/getEventTransformResponseResultActionProcessor.js +2 -2
- package/lib/commonjs/getActionProcessor/core/eventBus/getEventBusSendMessagesActionProcessor.js +2 -2
- package/lib/commonjs/getActionProcessor/core/file/getFileStreamOpenActionProcessor.d.ts +2 -0
- package/lib/commonjs/getActionProcessor/core/file/getFileStreamOpenActionProcessor.js +100 -0
- package/lib/commonjs/getActionProcessor/core/file/index.js +2 -1
- package/lib/commonjs/getActionProcessor/core/index.d.ts +2 -0
- package/lib/commonjs/getActionProcessor/core/index.js +6 -1
- package/lib/commonjs/getActionProcessor/core/queue/getQueueSendMessageActionProcessor.js +2 -2
- package/lib/commonjs/getActionProcessor/core/userDirectory/getUserDirectoryCreateUserActionProcessor.js +6 -1
- package/lib/commonjs/getActionProcessor/webserver/serviceFunction/getServiceFunctionExecuteActionProcessor.js +2 -2
- package/lib/esm/getActionProcessor/core/ai/aiModelMap.d.ts +2 -0
- package/lib/esm/getActionProcessor/core/ai/aiModelMap.js +12 -0
- package/lib/esm/getActionProcessor/core/ai/getAiPromptActionProcessor.d.ts +2 -0
- package/lib/esm/getActionProcessor/core/ai/getAiPromptActionProcessor.js +60 -0
- package/lib/esm/getActionProcessor/core/ai/getAiPromptStreamActionProcessor.d.ts +2 -0
- package/lib/esm/getActionProcessor/core/ai/getAiPromptStreamActionProcessor.js +75 -0
- package/lib/esm/getActionProcessor/core/ai/index.d.ts +2 -0
- package/lib/esm/getActionProcessor/core/ai/index.js +6 -0
- package/lib/esm/getActionProcessor/core/apiKeyValidation/getApiKeyValidationValidateActionProcessor.d.ts +2 -0
- package/lib/esm/getActionProcessor/core/apiKeyValidation/getApiKeyValidationValidateActionProcessor.js +24 -0
- package/lib/esm/getActionProcessor/core/apiKeyValidation/index.d.ts +2 -0
- package/lib/esm/getActionProcessor/core/apiKeyValidation/index.js +4 -0
- package/lib/esm/getActionProcessor/core/event/apiGatwayEvent/api/getEventAutoRespondActionProcessor.js +3 -32
- package/lib/esm/getActionProcessor/core/event/apiGatwayEvent/api/getEventGetStorySessionActionProcessor.js +3 -35
- package/lib/esm/getActionProcessor/core/event/apiGatwayEvent/websocket/getEventTransformResponseResultActionProcessor.js +2 -2
- package/lib/esm/getActionProcessor/core/eventBus/getEventBusSendMessagesActionProcessor.js +2 -5
- package/lib/esm/getActionProcessor/core/file/getFileStreamOpenActionProcessor.d.ts +2 -0
- package/lib/esm/getActionProcessor/core/file/getFileStreamOpenActionProcessor.js +50 -0
- package/lib/esm/getActionProcessor/core/file/index.js +2 -0
- package/lib/esm/getActionProcessor/core/index.d.ts +2 -0
- package/lib/esm/getActionProcessor/core/index.js +8 -0
- package/lib/esm/getActionProcessor/core/queue/getQueueSendMessageActionProcessor.js +2 -5
- package/lib/esm/getActionProcessor/core/userDirectory/getUserDirectoryCreateUserActionProcessor.js +7 -2
- package/lib/esm/getActionProcessor/webserver/serviceFunction/getServiceFunctionExecuteActionProcessor.js +2 -5
- package/package.json +7 -5
- package/lib/commonjs/getActionProcessor/core/event/utils/isAuthValid.d.ts +0 -3
- package/lib/commonjs/getActionProcessor/core/event/utils/isAuthValid.js +0 -68
- package/lib/esm/getActionProcessor/core/event/utils/isAuthValid.d.ts +0 -3
- package/lib/esm/getActionProcessor/core/event/utils/isAuthValid.js +0 -55
|
@@ -15,12 +15,17 @@ const quidproquo_core_1 = require("quidproquo-core");
|
|
|
15
15
|
const awsNamingUtils_1 = require("../../../awsNamingUtils");
|
|
16
16
|
const getExportedValue_1 = require("../../../logic/cloudformation/getExportedValue");
|
|
17
17
|
const createUser_1 = require("../../../logic/cognito/createUser");
|
|
18
|
+
const resolveUsernameByPreferredUsername_1 = require("../../../logic/cognito/resolveUsernameByPreferredUsername");
|
|
18
19
|
const getProcessCreateUser = (qpqConfig) => {
|
|
19
20
|
return (payload) => __awaiter(void 0, void 0, void 0, function* () {
|
|
20
21
|
const region = quidproquo_config_aws_1.qpqConfigAwsUtils.getApplicationModuleDeployRegion(qpqConfig);
|
|
21
22
|
const userPoolId = yield (0, getExportedValue_1.getExportedValue)((0, awsNamingUtils_1.getCFExportNameUserPoolIdFromConfig)(payload.userDirectoryName, qpqConfig), region);
|
|
22
23
|
const userPoolClientId = yield (0, getExportedValue_1.getExportedValue)((0, awsNamingUtils_1.getCFExportNameUserPoolClientIdFromConfig)(payload.userDirectoryName, qpqConfig), region);
|
|
23
|
-
const
|
|
24
|
+
const resolvedUsername = yield (0, resolveUsernameByPreferredUsername_1.resolveUsernameByPreferredUsername)(userPoolId, region, payload.createUserRequest.email);
|
|
25
|
+
if (resolvedUsername !== payload.createUserRequest.email) {
|
|
26
|
+
return (0, quidproquo_core_1.actionResultError)(quidproquo_core_1.ErrorTypeEnum.Conflict, 'An account with this email already exists');
|
|
27
|
+
}
|
|
28
|
+
const authResponse = yield (0, createUser_1.createUser)(userPoolId, region, userPoolClientId, payload.createUserRequest);
|
|
24
29
|
return (0, quidproquo_core_1.actionResult)(authResponse);
|
|
25
30
|
});
|
|
26
31
|
};
|
|
@@ -16,7 +16,7 @@ const quidproquo_webserver_1 = require("quidproquo-webserver");
|
|
|
16
16
|
const awsNamingUtils_1 = require("../../../awsNamingUtils");
|
|
17
17
|
const executeLambdaByName_1 = require("../../../logic/lambda/executeLambdaByName");
|
|
18
18
|
const getProcessExecute = (qpqConfig) => {
|
|
19
|
-
return (_a, session_1) => __awaiter(void 0, [_a, session_1], void 0, function* ({ functionName, service, payload,
|
|
19
|
+
return (_a, session_1) => __awaiter(void 0, [_a, session_1], void 0, function* ({ functionName, service, payload, isAsync }, session) {
|
|
20
20
|
const region = quidproquo_config_aws_1.qpqConfigAwsUtils.getApplicationModuleDeployRegion(qpqConfig);
|
|
21
21
|
const appName = quidproquo_core_1.qpqCoreUtils.getApplicationName(qpqConfig);
|
|
22
22
|
const environment = quidproquo_core_1.qpqCoreUtils.getApplicationModuleEnvironment(qpqConfig);
|
|
@@ -25,7 +25,7 @@ const getProcessExecute = (qpqConfig) => {
|
|
|
25
25
|
const serviceFunctionEvent = {
|
|
26
26
|
functionName: functionName,
|
|
27
27
|
payload: payload,
|
|
28
|
-
storySession:
|
|
28
|
+
storySession: session,
|
|
29
29
|
};
|
|
30
30
|
const result = yield (0, executeLambdaByName_1.executeLambdaByName)(awsFunctionName, region, serviceFunctionEvent, isAsync);
|
|
31
31
|
if (!result) {
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { AiModel } from 'quidproquo-core';
|
|
2
|
+
export const bedrockModelMap = {
|
|
3
|
+
[AiModel.ClaudeHaiku35]: 'us.anthropic.claude-3-5-haiku-20241022-v1:0',
|
|
4
|
+
[AiModel.ClaudeSonnet35]: 'us.anthropic.claude-3-5-sonnet-20241022-v2:0',
|
|
5
|
+
[AiModel.ClaudeSonnet4]: 'us.anthropic.claude-sonnet-4-20250514-v1:0',
|
|
6
|
+
[AiModel.ClaudeOpus4]: 'us.anthropic.claude-opus-4-20250514-v1:0',
|
|
7
|
+
[AiModel.ClaudeHaiku45]: 'us.anthropic.claude-haiku-4-5-20251001-v1:0',
|
|
8
|
+
[AiModel.ClaudeSonnet45]: 'us.anthropic.claude-sonnet-4-5-20250929-v1:0',
|
|
9
|
+
[AiModel.ClaudeOpus45]: 'us.anthropic.claude-opus-4-5-20251101-v1:0',
|
|
10
|
+
[AiModel.ClaudeSonnet46]: 'us.anthropic.claude-sonnet-4-6',
|
|
11
|
+
[AiModel.ClaudeOpus46]: 'us.anthropic.claude-opus-4-6-v1',
|
|
12
|
+
};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { qpqConfigAwsUtils } from 'quidproquo-config-aws';
|
|
2
|
+
import { actionResult, actionResultError, AiActionType, askInlineFunctionExecute, createImplementationRuntime, ErrorTypeEnum, qpqCoreUtils, } from 'quidproquo-core';
|
|
3
|
+
import { generateText, jsonSchema, stepCountIs } from 'ai';
|
|
4
|
+
import { createAmazonBedrock } from '@ai-sdk/amazon-bedrock';
|
|
5
|
+
import { randomGuid } from '../../../awsLambdaUtils';
|
|
6
|
+
import { bedrockModelMap } from './aiModelMap';
|
|
7
|
+
const getProcessAiPrompt = (qpqConfig) => {
|
|
8
|
+
return async (payload, session, actionProcessorList, logger, updateSession, dynamicModuleLoader, streamRegistry) => {
|
|
9
|
+
const region = qpqConfigAwsUtils.getApplicationModuleDeployRegion(qpqConfig);
|
|
10
|
+
const bedrock = createAmazonBedrock({ region });
|
|
11
|
+
const bedrockModelId = bedrockModelMap[payload.model];
|
|
12
|
+
if (!bedrockModelId) {
|
|
13
|
+
return actionResultError(ErrorTypeEnum.NotImplemented, `Unsupported AI model: ${payload.model}`);
|
|
14
|
+
}
|
|
15
|
+
// Build tools from defineAi config if aiName is provided
|
|
16
|
+
const aiTools = {};
|
|
17
|
+
if (payload.aiName) {
|
|
18
|
+
const aiConfigs = qpqCoreUtils.getAllAiConfigs(qpqConfig);
|
|
19
|
+
const aiConfig = aiConfigs.find((c) => c.aiName === payload.aiName);
|
|
20
|
+
if (!aiConfig) {
|
|
21
|
+
return actionResultError(ErrorTypeEnum.NotFound, `AI config not found: ${payload.aiName}`);
|
|
22
|
+
}
|
|
23
|
+
for (const toolDef of aiConfig.tools) {
|
|
24
|
+
aiTools[toolDef.name] = {
|
|
25
|
+
description: toolDef.description,
|
|
26
|
+
inputSchema: jsonSchema(toolDef.inputSchema),
|
|
27
|
+
execute: async (args) => {
|
|
28
|
+
const resolveStory = createImplementationRuntime(qpqConfig, [`AI Tool: ${toolDef.name}`], () => new Date().toISOString(), randomGuid, session, actionProcessorList, logger, dynamicModuleLoader, streamRegistry);
|
|
29
|
+
const storyResult = await resolveStory(function* () {
|
|
30
|
+
return yield* askInlineFunctionExecute(toolDef.executor, args);
|
|
31
|
+
}, []);
|
|
32
|
+
if (storyResult.error) {
|
|
33
|
+
throw new Error(storyResult.error.errorText);
|
|
34
|
+
}
|
|
35
|
+
return storyResult.result;
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
try {
|
|
41
|
+
const result = await generateText({
|
|
42
|
+
model: bedrock(bedrockModelId),
|
|
43
|
+
system: payload.system,
|
|
44
|
+
prompt: payload.prompt,
|
|
45
|
+
tools: Object.keys(aiTools).length > 0 ? aiTools : undefined,
|
|
46
|
+
stopWhen: stepCountIs(10),
|
|
47
|
+
});
|
|
48
|
+
return actionResult({ text: result.text });
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
if (error instanceof Error) {
|
|
52
|
+
return actionResultError(ErrorTypeEnum.GenericError, error.message);
|
|
53
|
+
}
|
|
54
|
+
return actionResultError(ErrorTypeEnum.GenericError, 'An error occurred during AI prompt execution.');
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
};
|
|
58
|
+
export const getAiPromptActionProcessor = async (qpqConfig) => ({
|
|
59
|
+
[AiActionType.Prompt]: getProcessAiPrompt(qpqConfig),
|
|
60
|
+
});
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { qpqConfigAwsUtils } from 'quidproquo-config-aws';
|
|
2
|
+
import { actionResult, actionResultError, AiActionType, askInlineFunctionExecute, createImplementationRuntime, ErrorTypeEnum, qpqCoreUtils, } from 'quidproquo-core';
|
|
3
|
+
import { jsonSchema, stepCountIs, streamText } from 'ai';
|
|
4
|
+
import { createAmazonBedrock } from '@ai-sdk/amazon-bedrock';
|
|
5
|
+
import { randomGuid } from '../../../awsLambdaUtils';
|
|
6
|
+
import { bedrockModelMap } from './aiModelMap';
|
|
7
|
+
const getProcessAiPromptStream = (qpqConfig) => {
|
|
8
|
+
return async (payload, session, actionProcessorList, logger, updateSession, dynamicModuleLoader, streamRegistry) => {
|
|
9
|
+
const region = qpqConfigAwsUtils.getApplicationModuleDeployRegion(qpqConfig);
|
|
10
|
+
const bedrock = createAmazonBedrock({ region });
|
|
11
|
+
const bedrockModelId = bedrockModelMap[payload.model];
|
|
12
|
+
if (!bedrockModelId) {
|
|
13
|
+
return actionResultError(ErrorTypeEnum.NotImplemented, `Unsupported AI model: ${payload.model}`);
|
|
14
|
+
}
|
|
15
|
+
// Build tools from defineAi config if aiName is provided
|
|
16
|
+
const aiTools = {};
|
|
17
|
+
if (payload.aiName) {
|
|
18
|
+
const aiConfigs = qpqCoreUtils.getAllAiConfigs(qpqConfig);
|
|
19
|
+
const aiConfig = aiConfigs.find((c) => c.aiName === payload.aiName);
|
|
20
|
+
if (!aiConfig) {
|
|
21
|
+
return actionResultError(ErrorTypeEnum.NotFound, `AI config not found: ${payload.aiName}`);
|
|
22
|
+
}
|
|
23
|
+
for (const toolDef of aiConfig.tools) {
|
|
24
|
+
aiTools[toolDef.name] = {
|
|
25
|
+
description: toolDef.description,
|
|
26
|
+
inputSchema: jsonSchema(toolDef.inputSchema),
|
|
27
|
+
execute: async (args) => {
|
|
28
|
+
const resolveStory = createImplementationRuntime(qpqConfig, [`AI Tool: ${toolDef.name}`], () => new Date().toISOString(), randomGuid, session, actionProcessorList, logger, dynamicModuleLoader, streamRegistry);
|
|
29
|
+
const storyResult = await resolveStory(function* () {
|
|
30
|
+
return yield* askInlineFunctionExecute(toolDef.executor, args);
|
|
31
|
+
}, []);
|
|
32
|
+
if (storyResult.error) {
|
|
33
|
+
throw new Error(storyResult.error.errorText);
|
|
34
|
+
}
|
|
35
|
+
return storyResult.result;
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
try {
|
|
41
|
+
const { fullStream } = streamText({
|
|
42
|
+
model: bedrock(bedrockModelId),
|
|
43
|
+
system: payload.system,
|
|
44
|
+
prompt: payload.messages ?? payload.prompt,
|
|
45
|
+
tools: Object.keys(aiTools).length > 0 ? aiTools : undefined,
|
|
46
|
+
stopWhen: stepCountIs(10),
|
|
47
|
+
});
|
|
48
|
+
const streamId = `ai-prompt-${Date.now()}-${randomGuid()}`;
|
|
49
|
+
async function* aiStreamIterator() {
|
|
50
|
+
for await (const part of fullStream) {
|
|
51
|
+
if (part.type === 'text-delta') {
|
|
52
|
+
yield JSON.stringify({ type: 'text-delta', text: part.text });
|
|
53
|
+
}
|
|
54
|
+
else if (part.type === 'tool-call') {
|
|
55
|
+
yield JSON.stringify({ type: 'tool-call', toolName: part.toolName, input: part.input });
|
|
56
|
+
}
|
|
57
|
+
else if (part.type === 'tool-result') {
|
|
58
|
+
yield JSON.stringify({ type: 'tool-result', toolName: part.toolName, output: part.output });
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
streamRegistry.register(streamId, aiStreamIterator());
|
|
63
|
+
return actionResult({ id: streamId, encoding: 'json' });
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
if (error instanceof Error) {
|
|
67
|
+
return actionResultError(ErrorTypeEnum.GenericError, error.message);
|
|
68
|
+
}
|
|
69
|
+
return actionResultError(ErrorTypeEnum.GenericError, 'An error occurred during AI prompt stream.');
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
};
|
|
73
|
+
export const getAiPromptStreamActionProcessor = async (qpqConfig) => ({
|
|
74
|
+
[AiActionType.PromptStream]: getProcessAiPromptStream(qpqConfig),
|
|
75
|
+
});
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { getAiPromptActionProcessor } from './getAiPromptActionProcessor';
|
|
2
|
+
import { getAiPromptStreamActionProcessor } from './getAiPromptStreamActionProcessor';
|
|
3
|
+
export const getAiActionProcessor = async (qpqConfig, dynamicModuleLoader) => ({
|
|
4
|
+
...(await getAiPromptActionProcessor(qpqConfig, dynamicModuleLoader)),
|
|
5
|
+
...(await getAiPromptStreamActionProcessor(qpqConfig, dynamicModuleLoader)),
|
|
6
|
+
});
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { qpqConfigAwsUtils } from 'quidproquo-config-aws';
|
|
2
|
+
import { actionResult, qpqCoreUtils, } from 'quidproquo-core';
|
|
3
|
+
import { ApiKeyValidationActionType } from 'quidproquo-webserver';
|
|
4
|
+
import { getConfigRuntimeResourceName } from '../../../awsNamingUtils';
|
|
5
|
+
import { getApiKeys } from '../../../logic/apiGateway/getApiKeys';
|
|
6
|
+
const getProcessApiKeyValidationValidate = (qpqConfig) => {
|
|
7
|
+
const region = qpqConfigAwsUtils.getApplicationModuleDeployRegion(qpqConfig);
|
|
8
|
+
const application = qpqCoreUtils.getApplicationName(qpqConfig);
|
|
9
|
+
const service = qpqCoreUtils.getApplicationModuleName(qpqConfig);
|
|
10
|
+
const environment = qpqCoreUtils.getApplicationModuleEnvironment(qpqConfig);
|
|
11
|
+
const feature = qpqCoreUtils.getApplicationModuleFeature(qpqConfig);
|
|
12
|
+
return async ({ apiKeyValue, apiKeyReferences }) => {
|
|
13
|
+
const realApiKeys = await getApiKeys(region, ...apiKeyReferences.map((apiKey) => {
|
|
14
|
+
const apiKeyApplication = apiKey.applicationName || application;
|
|
15
|
+
const apiKeyService = apiKey.serviceName || service;
|
|
16
|
+
return getConfigRuntimeResourceName(apiKey.name, apiKeyApplication, apiKeyService, environment, feature);
|
|
17
|
+
}));
|
|
18
|
+
const index = realApiKeys.findIndex((apiKey) => apiKey.value === apiKeyValue);
|
|
19
|
+
return actionResult(index >= 0);
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
export const getApiKeyValidationValidateActionProcessor = async (qpqConfig) => ({
|
|
23
|
+
[ApiKeyValidationActionType.Validate]: getProcessApiKeyValidationValidate(qpqConfig),
|
|
24
|
+
});
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { getApiKeyValidationValidateActionProcessor } from './getApiKeyValidationValidateActionProcessor';
|
|
2
|
+
export const getApiKeyValidationActionProcessor = async (qpqConfig, dynamicModuleLoader) => ({
|
|
3
|
+
...(await getApiKeyValidationValidateActionProcessor(qpqConfig, dynamicModuleLoader)),
|
|
4
|
+
});
|
|
@@ -1,33 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const getProcessAutoRespond = (qpqConfig) => {
|
|
5
|
-
return async ({ qpqEventRecord, matchResult }) => {
|
|
6
|
-
// Just auto respond for options requests
|
|
7
|
-
if (qpqEventRecord.method === 'OPTIONS') {
|
|
8
|
-
return actionResult({
|
|
9
|
-
status: 200,
|
|
10
|
-
isBase64Encoded: false,
|
|
11
|
-
body: '',
|
|
12
|
-
headers: qpqWebServerUtils.getCorsHeaders(qpqConfig, matchResult.config || {}, qpqEventRecord.headers),
|
|
13
|
-
});
|
|
14
|
-
}
|
|
15
|
-
// TODO: We can pull out the jwt from the session if thats a better way?
|
|
16
|
-
// Think about that when you dont have covid.
|
|
17
|
-
const authValid = await isAuthValid(qpqConfig, qpqWebServerUtils.getHeaderValue('Authorization', qpqEventRecord.headers), qpqWebServerUtils.getHeaderValue('x-api-key', qpqEventRecord.headers), matchResult.config?.routeAuthSettings);
|
|
18
|
-
if (!authValid) {
|
|
19
|
-
return actionResult({
|
|
20
|
-
status: 401,
|
|
21
|
-
isBase64Encoded: false,
|
|
22
|
-
body: JSON.stringify({
|
|
23
|
-
message: 'You are unauthorized to access this resource',
|
|
24
|
-
}),
|
|
25
|
-
headers: qpqWebServerUtils.getCorsHeaders(qpqConfig, matchResult.config || {}, qpqEventRecord.headers),
|
|
26
|
-
});
|
|
27
|
-
}
|
|
28
|
-
return actionResult(null);
|
|
29
|
-
};
|
|
30
|
-
};
|
|
31
|
-
export const getEventAutoRespondActionProcessor = async (qpqConfig) => ({
|
|
32
|
-
[EventActionType.AutoRespond]: getProcessAutoRespond(qpqConfig),
|
|
1
|
+
import { getHttpApiEventAutoRespondActionProcessor } from 'quidproquo-webserver';
|
|
2
|
+
export const getEventAutoRespondActionProcessor = async (qpqConfig, dynamicModuleLoader) => ({
|
|
3
|
+
...(await getHttpApiEventAutoRespondActionProcessor(qpqConfig, dynamicModuleLoader)),
|
|
33
4
|
});
|
|
@@ -1,36 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const getProcessGetStorySession = (qpqConfig) => {
|
|
5
|
-
return async ({ matchStoryResult, qpqEventRecord }, session) => {
|
|
6
|
-
const accessToken = qpqWebServerUtils.getAccessTokenFromHeaders(qpqEventRecord.headers);
|
|
7
|
-
if (!accessToken) {
|
|
8
|
-
return actionResult(void 0);
|
|
9
|
-
}
|
|
10
|
-
// if this endpoint has no auth settings, BUT we do have an access token
|
|
11
|
-
// then we want to just attempt to extract info for logs, but we will say that its
|
|
12
|
-
// wasValid = false
|
|
13
|
-
if (!matchStoryResult.config?.routeAuthSettings?.userDirectoryName) {
|
|
14
|
-
// If this endpoint is unauthenticated, then we will just decode it, and say it wasnt valid, for logs
|
|
15
|
-
const info = qpqWebServerUtils.decodeJWT(accessToken);
|
|
16
|
-
return actionResult({
|
|
17
|
-
...session,
|
|
18
|
-
decodedAccessToken: {
|
|
19
|
-
exp: info?.exp || 0,
|
|
20
|
-
userDirectory: '',
|
|
21
|
-
userId: info?.sub || info?.id || info?.userId || info?.username || '',
|
|
22
|
-
username: info?.username || info?.userId || info?.sub || info?.id || '',
|
|
23
|
-
wasValid: false,
|
|
24
|
-
},
|
|
25
|
-
});
|
|
26
|
-
}
|
|
27
|
-
const decodedAccessToken = await decodeAccessToken(matchStoryResult.config.routeAuthSettings.userDirectoryName, qpqConfig, accessToken, true);
|
|
28
|
-
return actionResult({
|
|
29
|
-
...session,
|
|
30
|
-
decodedAccessToken,
|
|
31
|
-
});
|
|
32
|
-
};
|
|
33
|
-
};
|
|
34
|
-
export const getEventGetStorySessionActionProcessor = async (qpqConfig) => ({
|
|
35
|
-
[EventActionType.GetStorySession]: getProcessGetStorySession(qpqConfig),
|
|
1
|
+
import { getHttpApiEventGetStorySessionActionProcessor } from 'quidproquo-webserver';
|
|
2
|
+
export const getEventGetStorySessionActionProcessor = async (qpqConfig, dynamicModuleLoader) => ({
|
|
3
|
+
...(await getHttpApiEventGetStorySessionActionProcessor(qpqConfig, dynamicModuleLoader)),
|
|
36
4
|
});
|
|
@@ -11,10 +11,10 @@ export function* askTransformResponseStory({ eventParams, qpqEventRecordResponse
|
|
|
11
11
|
const getProcessTransformResponseResult = (qpqConfig) => {
|
|
12
12
|
// Create a custom runtime for errored responses so we can log them out
|
|
13
13
|
const errorCustomImplementation = getProcessCustomImplementation(qpqConfig, askTransformResponseStory, 'Transform Errored Websocket Response', null, () => new Date().toISOString(), randomGuid);
|
|
14
|
-
return async (payload, session, actionProcessors, logger, updateSession, dynamicModuleLoader) => {
|
|
14
|
+
return async (payload, session, actionProcessors, logger, updateSession, dynamicModuleLoader, streamRegistry) => {
|
|
15
15
|
if (payload.qpqEventRecordResponses.some((r) => !r.success)) {
|
|
16
16
|
// We only wan't to run this for errors, because a custom imp is slower then a regular imp
|
|
17
|
-
return await errorCustomImplementation(payload, session, actionProcessors, logger, updateSession, dynamicModuleLoader);
|
|
17
|
+
return await errorCustomImplementation(payload, session, actionProcessors, logger, updateSession, dynamicModuleLoader, streamRegistry);
|
|
18
18
|
}
|
|
19
19
|
return actionResult({
|
|
20
20
|
statusCode: 200,
|
|
@@ -3,7 +3,7 @@ import { actionResult, actionResultError, ErrorTypeEnum, EventBusActionType, qpq
|
|
|
3
3
|
import { getEventBusSnsTopicArn } from '../../../awsNamingUtils';
|
|
4
4
|
import { publishMessage } from '../../../logic/sns/publishMessage';
|
|
5
5
|
const getProcessEventBusSendMessage = (qpqConfig) => {
|
|
6
|
-
return async ({ eventBusName, eventBusMessages,
|
|
6
|
+
return async ({ eventBusName, eventBusMessages, }, session) => {
|
|
7
7
|
const region = qpqConfigAwsUtils.getApplicationModuleDeployRegion(qpqConfig);
|
|
8
8
|
const eventBusConfig = qpqCoreUtils.getEventBusConfigByName(eventBusName, qpqConfig);
|
|
9
9
|
if (!eventBusConfig) {
|
|
@@ -13,10 +13,7 @@ const getProcessEventBusSendMessage = (qpqConfig) => {
|
|
|
13
13
|
await publishMessage(topicArn, region, eventBusMessages.map((message) => {
|
|
14
14
|
const eventBusMessageWithSession = {
|
|
15
15
|
...message,
|
|
16
|
-
storySession:
|
|
17
|
-
...session,
|
|
18
|
-
context,
|
|
19
|
-
},
|
|
16
|
+
storySession: session,
|
|
20
17
|
};
|
|
21
18
|
return JSON.stringify(eventBusMessageWithSession);
|
|
22
19
|
}));
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { qpqConfigAwsUtils } from 'quidproquo-config-aws';
|
|
2
|
+
import { actionResult, actionResultError, actionResultErrorFromCaughtError, ErrorTypeEnum, FileActionType, } from 'quidproquo-core';
|
|
3
|
+
import { GetObjectCommand, S3Client } from '@aws-sdk/client-s3';
|
|
4
|
+
import { createAwsClient } from '../../../logic/createAwsClient';
|
|
5
|
+
import { resolveStorageDriveBucketName } from './utils';
|
|
6
|
+
async function* chunkedReadableIterator(stream, chunkSize, transform) {
|
|
7
|
+
let buffer = Buffer.alloc(0);
|
|
8
|
+
for await (const chunk of stream) {
|
|
9
|
+
const incoming = typeof chunk === 'string' ? Buffer.from(chunk, 'utf8') : chunk;
|
|
10
|
+
buffer = Buffer.concat([buffer, incoming]);
|
|
11
|
+
while (buffer.length >= chunkSize) {
|
|
12
|
+
yield transform(buffer.subarray(0, chunkSize));
|
|
13
|
+
buffer = buffer.subarray(chunkSize);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
if (buffer.length > 0) {
|
|
17
|
+
yield transform(buffer);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
const getProcessFileStreamOpen = (qpqConfig) => {
|
|
21
|
+
return async ({ drive, filepath, encoding, chunkSize }, session, actionProcessors, logger, updateSession, dynamicModuleLoader, streamRegistry) => {
|
|
22
|
+
try {
|
|
23
|
+
const s3BucketName = resolveStorageDriveBucketName(drive, qpqConfig);
|
|
24
|
+
const region = qpqConfigAwsUtils.getApplicationModuleDeployRegion(qpqConfig);
|
|
25
|
+
const s3Client = createAwsClient(S3Client, { region });
|
|
26
|
+
const response = await s3Client.send(new GetObjectCommand({
|
|
27
|
+
Key: filepath,
|
|
28
|
+
Bucket: s3BucketName,
|
|
29
|
+
}));
|
|
30
|
+
if (!response.Body) {
|
|
31
|
+
return actionResultError(ErrorTypeEnum.GenericError, `Empty response body for: ${filepath}`);
|
|
32
|
+
}
|
|
33
|
+
const streamId = `s3-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
34
|
+
const isText = encoding === 'text';
|
|
35
|
+
const size = chunkSize ?? 65536;
|
|
36
|
+
const transform = isText
|
|
37
|
+
? (buf) => buf.toString('utf8')
|
|
38
|
+
: (buf) => buf.toString('base64');
|
|
39
|
+
const iterator = chunkedReadableIterator(response.Body, size, transform);
|
|
40
|
+
streamRegistry.register(streamId, iterator);
|
|
41
|
+
return actionResult({ id: streamId, encoding });
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
return actionResultErrorFromCaughtError(error, {});
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
export const getFileStreamOpenActionProcessor = async (qpqConfig) => ({
|
|
49
|
+
[FileActionType.StreamOpen]: getProcessFileStreamOpen(qpqConfig),
|
|
50
|
+
});
|
|
@@ -7,6 +7,7 @@ import { getFileListDirectoryActionProcessor } from './getFileListDirectoryActio
|
|
|
7
7
|
import { getFileReadBinaryContentsActionProcessor } from './getFileReadBinaryContentsActionProcessor';
|
|
8
8
|
import { getFileReadObjectJsonActionProcessor } from './getFileReadObjectJsonActionProcessor';
|
|
9
9
|
import { getFileReadTextContentsActionProcessor } from './getFileReadTextContentsActionProcessor';
|
|
10
|
+
import { getFileStreamOpenActionProcessor } from './getFileStreamOpenActionProcessor';
|
|
10
11
|
import { getFileWriteBinaryContentsActionProcessor } from './getFileWriteBinaryContentsActionProcessor';
|
|
11
12
|
import { getFileWriteObjectJsonActionProcessor } from './getFileWriteObjectJsonActionProcessor';
|
|
12
13
|
import { getFileWriteTextContentsActionProcessor } from './getFileWriteTextContentsActionProcessor';
|
|
@@ -23,4 +24,5 @@ export const getFileActionProcessor = async (qpqConfig, dynamicModuleLoader) =>
|
|
|
23
24
|
...(await getFileReadBinaryContentsActionProcessor(qpqConfig, dynamicModuleLoader)),
|
|
24
25
|
...(await getFileWriteObjectJsonActionProcessor(qpqConfig, dynamicModuleLoader)),
|
|
25
26
|
...(await getFileWriteBinaryContentsActionProcessor(qpqConfig, dynamicModuleLoader)),
|
|
27
|
+
...(await getFileStreamOpenActionProcessor(qpqConfig, dynamicModuleLoader)),
|
|
26
28
|
});
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
export * from './ai';
|
|
2
|
+
export * from './apiKeyValidation';
|
|
1
3
|
export * from './config';
|
|
2
4
|
export * from './event';
|
|
3
5
|
export * from './eventBus';
|
|
@@ -7,6 +9,9 @@ export * from './keyValueStore';
|
|
|
7
9
|
export * from './queue';
|
|
8
10
|
export * from './system';
|
|
9
11
|
export * from './userDirectory';
|
|
12
|
+
import { getRouteAuthValidationActionProcessor } from 'quidproquo-webserver';
|
|
13
|
+
import { getAiActionProcessor } from './ai';
|
|
14
|
+
import { getApiKeyValidationActionProcessor } from './apiKeyValidation';
|
|
10
15
|
import { getConfigActionProcessor } from './config';
|
|
11
16
|
import { getApiGatewayApiEventEventProcessor } from './event';
|
|
12
17
|
import { getEventBusActionProcessor } from './eventBus';
|
|
@@ -17,6 +22,8 @@ import { getQueueActionProcessor } from './queue';
|
|
|
17
22
|
import { getSystemActionProcessor } from './system';
|
|
18
23
|
import { getUserDirectoryActionProcessor } from './userDirectory';
|
|
19
24
|
export const getCoreActionProcessor = async (qpqConfig, dynamicModuleLoader) => ({
|
|
25
|
+
...(await getAiActionProcessor(qpqConfig, dynamicModuleLoader)),
|
|
26
|
+
...(await getApiKeyValidationActionProcessor(qpqConfig, dynamicModuleLoader)),
|
|
20
27
|
...(await getFileActionProcessor(qpqConfig, dynamicModuleLoader)),
|
|
21
28
|
...(await getKeyValueStoreActionProcessor(qpqConfig, dynamicModuleLoader)),
|
|
22
29
|
...(await getQueueActionProcessor(qpqConfig, dynamicModuleLoader)),
|
|
@@ -26,4 +33,5 @@ export const getCoreActionProcessor = async (qpqConfig, dynamicModuleLoader) =>
|
|
|
26
33
|
...(await getConfigActionProcessor(qpqConfig, dynamicModuleLoader)),
|
|
27
34
|
...(await getApiGatewayApiEventEventProcessor(qpqConfig, dynamicModuleLoader)),
|
|
28
35
|
...(await getGraphDatabaseActionProcessor(qpqConfig, dynamicModuleLoader)),
|
|
36
|
+
...(await getRouteAuthValidationActionProcessor(qpqConfig, dynamicModuleLoader)),
|
|
29
37
|
});
|
|
@@ -3,17 +3,14 @@ import { actionResult, QueueActionType } from 'quidproquo-core';
|
|
|
3
3
|
import { sendMessages } from '../../../logic/sqs/sendMessages';
|
|
4
4
|
import { resolveResourceName } from '../../../runtimeConfig/qpqAwsLambdaRuntimeConfigUtils';
|
|
5
5
|
const getProcessQueueSendMessage = (qpqConfig) => {
|
|
6
|
-
return async ({ queueName, queueMessages
|
|
6
|
+
return async ({ queueName, queueMessages }, session) => {
|
|
7
7
|
// While we have some uuids
|
|
8
8
|
const sqsQueueName = resolveResourceName(queueName, qpqConfig);
|
|
9
9
|
await sendMessages(sqsQueueName, qpqConfigAwsUtils.getApplicationModuleDeployRegion(qpqConfig), queueMessages.map((message) => {
|
|
10
10
|
// Add the session info to the message
|
|
11
11
|
const queueMessageWithSession = {
|
|
12
12
|
...message,
|
|
13
|
-
storySession:
|
|
14
|
-
...session,
|
|
15
|
-
context,
|
|
16
|
-
},
|
|
13
|
+
storySession: session,
|
|
17
14
|
};
|
|
18
15
|
return JSON.stringify(queueMessageWithSession);
|
|
19
16
|
}));
|
package/lib/esm/getActionProcessor/core/userDirectory/getUserDirectoryCreateUserActionProcessor.js
CHANGED
|
@@ -1,14 +1,19 @@
|
|
|
1
1
|
import { qpqConfigAwsUtils } from 'quidproquo-config-aws';
|
|
2
|
-
import { actionResult, UserDirectoryActionType, } from 'quidproquo-core';
|
|
2
|
+
import { actionResult, actionResultError, ErrorTypeEnum, UserDirectoryActionType, } from 'quidproquo-core';
|
|
3
3
|
import { getCFExportNameUserPoolClientIdFromConfig, getCFExportNameUserPoolIdFromConfig } from '../../../awsNamingUtils';
|
|
4
4
|
import { getExportedValue } from '../../../logic/cloudformation/getExportedValue';
|
|
5
5
|
import { createUser } from '../../../logic/cognito/createUser';
|
|
6
|
+
import { resolveUsernameByPreferredUsername } from '../../../logic/cognito/resolveUsernameByPreferredUsername';
|
|
6
7
|
const getProcessCreateUser = (qpqConfig) => {
|
|
7
8
|
return async (payload) => {
|
|
8
9
|
const region = qpqConfigAwsUtils.getApplicationModuleDeployRegion(qpqConfig);
|
|
9
10
|
const userPoolId = await getExportedValue(getCFExportNameUserPoolIdFromConfig(payload.userDirectoryName, qpqConfig), region);
|
|
10
11
|
const userPoolClientId = await getExportedValue(getCFExportNameUserPoolClientIdFromConfig(payload.userDirectoryName, qpqConfig), region);
|
|
11
|
-
const
|
|
12
|
+
const resolvedUsername = await resolveUsernameByPreferredUsername(userPoolId, region, payload.createUserRequest.email);
|
|
13
|
+
if (resolvedUsername !== payload.createUserRequest.email) {
|
|
14
|
+
return actionResultError(ErrorTypeEnum.Conflict, 'An account with this email already exists');
|
|
15
|
+
}
|
|
16
|
+
const authResponse = await createUser(userPoolId, region, userPoolClientId, payload.createUserRequest);
|
|
12
17
|
return actionResult(authResponse);
|
|
13
18
|
};
|
|
14
19
|
};
|
|
@@ -4,7 +4,7 @@ import { ServiceFunctionActionType } from 'quidproquo-webserver';
|
|
|
4
4
|
import { getConfigRuntimeResourceName } from '../../../awsNamingUtils';
|
|
5
5
|
import { executeLambdaByName } from '../../../logic/lambda/executeLambdaByName';
|
|
6
6
|
const getProcessExecute = (qpqConfig) => {
|
|
7
|
-
return async ({ functionName, service, payload,
|
|
7
|
+
return async ({ functionName, service, payload, isAsync }, session) => {
|
|
8
8
|
const region = qpqConfigAwsUtils.getApplicationModuleDeployRegion(qpqConfig);
|
|
9
9
|
const appName = qpqCoreUtils.getApplicationName(qpqConfig);
|
|
10
10
|
const environment = qpqCoreUtils.getApplicationModuleEnvironment(qpqConfig);
|
|
@@ -13,10 +13,7 @@ const getProcessExecute = (qpqConfig) => {
|
|
|
13
13
|
const serviceFunctionEvent = {
|
|
14
14
|
functionName: functionName,
|
|
15
15
|
payload: payload,
|
|
16
|
-
storySession:
|
|
17
|
-
...session,
|
|
18
|
-
context,
|
|
19
|
-
},
|
|
16
|
+
storySession: session,
|
|
20
17
|
};
|
|
21
18
|
const result = await executeLambdaByName(awsFunctionName, region, serviceFunctionEvent, isAsync);
|
|
22
19
|
if (!result) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "quidproquo-actionprocessor-awslambda",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.263",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "./lib/commonjs/index.js",
|
|
6
6
|
"module": "./lib/esm/index.js",
|
|
@@ -32,6 +32,7 @@
|
|
|
32
32
|
},
|
|
33
33
|
"homepage": "https://github.com/joe-coady/quidproquo#readme",
|
|
34
34
|
"dependencies": {
|
|
35
|
+
"@ai-sdk/amazon-bedrock": "^4.0.83",
|
|
35
36
|
"@aws-sdk/client-acm": "^3.744.0",
|
|
36
37
|
"@aws-sdk/client-api-gateway": "^3.744.0",
|
|
37
38
|
"@aws-sdk/client-apigatewaymanagementapi": "^3.744.0",
|
|
@@ -50,6 +51,7 @@
|
|
|
50
51
|
"@aws-sdk/s3-presigned-post": "^3.744.0",
|
|
51
52
|
"@aws-sdk/s3-request-presigner": "^3.744.0",
|
|
52
53
|
"@types/aws-lambda": "^8.10.109",
|
|
54
|
+
"ai": "^6.0.141",
|
|
53
55
|
"aws-jwt-verify": "^3.4.0",
|
|
54
56
|
"busboy": "^1.6.0",
|
|
55
57
|
"jsonwebtoken": "^9.0.0",
|
|
@@ -57,16 +59,16 @@
|
|
|
57
59
|
"lodash": "^4.17.21",
|
|
58
60
|
"node-cache": "^5.1.2",
|
|
59
61
|
"node-match-path": "^0.6.3",
|
|
60
|
-
"quidproquo-config-aws": "0.0.
|
|
61
|
-
"quidproquo-core": "0.0.
|
|
62
|
-
"quidproquo-webserver": "0.0.
|
|
62
|
+
"quidproquo-config-aws": "0.0.263",
|
|
63
|
+
"quidproquo-core": "0.0.263",
|
|
64
|
+
"quidproquo-webserver": "0.0.263"
|
|
63
65
|
},
|
|
64
66
|
"devDependencies": {
|
|
65
67
|
"@types/busboy": "^1.5.0",
|
|
66
68
|
"@types/jsonwebtoken": "^9.0.2",
|
|
67
69
|
"@types/lodash": "^4.14.194",
|
|
68
70
|
"@types/node": "^22.13.13",
|
|
69
|
-
"quidproquo-tsconfig": "0.0.
|
|
71
|
+
"quidproquo-tsconfig": "0.0.263",
|
|
70
72
|
"typescript": "^5.8.2"
|
|
71
73
|
}
|
|
72
74
|
}
|
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
import { QPQConfig } from 'quidproquo-core';
|
|
2
|
-
import { RouteAuthSettings } from 'quidproquo-webserver';
|
|
3
|
-
export declare const isAuthValid: (qpqConfig: QPQConfig, authHeader?: string | null, apiKeyHeader?: string | null, authSettings?: RouteAuthSettings) => Promise<boolean>;
|