quidproquo-actionprocessor-awslambda 0.0.262 → 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/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/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
|
@@ -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
|
}));
|
|
@@ -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>;
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
-
});
|
|
10
|
-
};
|
|
11
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
exports.isAuthValid = void 0;
|
|
13
|
-
const quidproquo_config_aws_1 = require("quidproquo-config-aws");
|
|
14
|
-
const quidproquo_core_1 = require("quidproquo-core");
|
|
15
|
-
const awsNamingUtils_1 = require("../../../../awsNamingUtils");
|
|
16
|
-
const getApiKeys_1 = require("../../../../logic/apiGateway/getApiKeys");
|
|
17
|
-
const getExportedValue_1 = require("../../../../logic/cloudformation/getExportedValue");
|
|
18
|
-
const verifyJwt_1 = require("../../../../logic/cognito/verifyJwt");
|
|
19
|
-
const isAuthValidForCognito = (qpqConfig, authSettings, authHeader) => __awaiter(void 0, void 0, void 0, function* () {
|
|
20
|
-
// If there are no auth settings ~ Its valid.
|
|
21
|
-
if (!authSettings.userDirectoryName) {
|
|
22
|
-
return true;
|
|
23
|
-
}
|
|
24
|
-
// We need a header to be able to auth
|
|
25
|
-
if (!authHeader) {
|
|
26
|
-
return false;
|
|
27
|
-
}
|
|
28
|
-
// Make sure we have a Bearer token
|
|
29
|
-
const [authType, accessToken] = authHeader.split(' ');
|
|
30
|
-
if (authType !== 'Bearer' || !accessToken) {
|
|
31
|
-
return false;
|
|
32
|
-
}
|
|
33
|
-
// Grab the user directory to auth against
|
|
34
|
-
const userDirectoryName = authSettings.userDirectoryName;
|
|
35
|
-
const region = quidproquo_config_aws_1.qpqConfigAwsUtils.getApplicationModuleDeployRegion(qpqConfig);
|
|
36
|
-
// Resolve the user pool id
|
|
37
|
-
const userPoolId = yield (0, getExportedValue_1.getExportedValue)((0, awsNamingUtils_1.getCFExportNameUserPoolIdFromConfig)(userDirectoryName, qpqConfig), region);
|
|
38
|
-
// Verify the token
|
|
39
|
-
return yield (0, verifyJwt_1.verifyJwt)(accessToken, userPoolId, region, false);
|
|
40
|
-
});
|
|
41
|
-
const isAuthValidForApiKeys = (qpqConfig, authSettings, apiKeyHeader) => __awaiter(void 0, void 0, void 0, function* () {
|
|
42
|
-
const apiKeys = authSettings.apiKeys || [];
|
|
43
|
-
if (apiKeys.length === 0) {
|
|
44
|
-
return true;
|
|
45
|
-
}
|
|
46
|
-
const region = quidproquo_config_aws_1.qpqConfigAwsUtils.getApplicationModuleDeployRegion(qpqConfig);
|
|
47
|
-
const application = quidproquo_core_1.qpqCoreUtils.getApplicationName(qpqConfig);
|
|
48
|
-
const service = quidproquo_core_1.qpqCoreUtils.getApplicationModuleName(qpqConfig);
|
|
49
|
-
const environment = quidproquo_core_1.qpqCoreUtils.getApplicationModuleEnvironment(qpqConfig);
|
|
50
|
-
const feature = quidproquo_core_1.qpqCoreUtils.getApplicationModuleFeature(qpqConfig);
|
|
51
|
-
const realApiKeys = yield (0, getApiKeys_1.getApiKeys)(region, ...apiKeys.map((apiKey) => {
|
|
52
|
-
const apiKeyApplication = apiKey.applicationName || application;
|
|
53
|
-
const apiKeyService = apiKey.serviceName || service;
|
|
54
|
-
return (0, awsNamingUtils_1.getConfigRuntimeResourceName)(apiKey.name, apiKeyApplication, apiKeyService, environment, feature);
|
|
55
|
-
}));
|
|
56
|
-
const index = realApiKeys.findIndex((apiKey) => apiKey.value === apiKeyHeader);
|
|
57
|
-
return index >= 0;
|
|
58
|
-
});
|
|
59
|
-
const isAuthValid = (qpqConfig, authHeader, apiKeyHeader, authSettings) => __awaiter(void 0, void 0, void 0, function* () {
|
|
60
|
-
// If there are no auth settings ~ Its valid.
|
|
61
|
-
if (!authSettings) {
|
|
62
|
-
return true;
|
|
63
|
-
}
|
|
64
|
-
const cognitoValid = yield isAuthValidForCognito(qpqConfig, authSettings, authHeader);
|
|
65
|
-
const authKeysValid = yield isAuthValidForApiKeys(qpqConfig, authSettings, apiKeyHeader);
|
|
66
|
-
return cognitoValid && authKeysValid;
|
|
67
|
-
});
|
|
68
|
-
exports.isAuthValid = isAuthValid;
|
|
@@ -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>;
|