quidproquo-actionprocessor-awslambda 0.0.256 → 0.0.258

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 (39) hide show
  1. package/lib/commonjs/getActionProcessor/core/file/getFileGenerateTemporaryUploadSecureUrlActionProcessor.d.ts +2 -0
  2. package/lib/commonjs/getActionProcessor/core/file/getFileGenerateTemporaryUploadSecureUrlActionProcessor.js +35 -0
  3. package/lib/commonjs/getActionProcessor/core/file/index.js +2 -1
  4. package/lib/commonjs/getActionProcessor/webserver/extract/getExtractExpenseActionProcessor.d.ts +2 -0
  5. package/lib/commonjs/getActionProcessor/webserver/extract/getExtractExpenseActionProcessor.js +56 -0
  6. package/lib/commonjs/getActionProcessor/webserver/extract/index.d.ts +2 -0
  7. package/lib/commonjs/getActionProcessor/webserver/extract/index.js +17 -0
  8. package/lib/commonjs/getActionProcessor/webserver/index.d.ts +1 -0
  9. package/lib/commonjs/getActionProcessor/webserver/index.js +3 -1
  10. package/lib/commonjs/logic/dynamo/qpqDynamoOrm/buildDynamoUpdate.d.ts +1 -2
  11. package/lib/commonjs/logic/dynamo/qpqDynamoOrm/buildDynamoUpdate.js +43 -21
  12. package/lib/commonjs/logic/s3/generatePresignedUploadUrl.d.ts +1 -0
  13. package/lib/commonjs/logic/s3/generatePresignedUploadUrl.js +59 -0
  14. package/lib/commonjs/logic/textract/analyzeExpense.d.ts +51 -0
  15. package/lib/commonjs/logic/textract/analyzeExpense.js +31 -0
  16. package/lib/commonjs/logic/textract/index.d.ts +2 -0
  17. package/lib/commonjs/logic/textract/index.js +18 -0
  18. package/lib/commonjs/logic/textract/transformExpenseResponse.d.ts +29 -0
  19. package/lib/commonjs/logic/textract/transformExpenseResponse.js +180 -0
  20. package/lib/esm/getActionProcessor/core/file/getFileGenerateTemporaryUploadSecureUrlActionProcessor.d.ts +2 -0
  21. package/lib/esm/getActionProcessor/core/file/getFileGenerateTemporaryUploadSecureUrlActionProcessor.js +20 -0
  22. package/lib/esm/getActionProcessor/core/file/index.js +2 -0
  23. package/lib/esm/getActionProcessor/webserver/extract/getExtractExpenseActionProcessor.d.ts +2 -0
  24. package/lib/esm/getActionProcessor/webserver/extract/getExtractExpenseActionProcessor.js +40 -0
  25. package/lib/esm/getActionProcessor/webserver/extract/index.d.ts +2 -0
  26. package/lib/esm/getActionProcessor/webserver/extract/index.js +4 -0
  27. package/lib/esm/getActionProcessor/webserver/index.d.ts +1 -0
  28. package/lib/esm/getActionProcessor/webserver/index.js +3 -0
  29. package/lib/esm/logic/dynamo/qpqDynamoOrm/buildDynamoUpdate.d.ts +1 -2
  30. package/lib/esm/logic/dynamo/qpqDynamoOrm/buildDynamoUpdate.js +42 -19
  31. package/lib/esm/logic/s3/generatePresignedUploadUrl.d.ts +1 -0
  32. package/lib/esm/logic/s3/generatePresignedUploadUrl.js +49 -0
  33. package/lib/esm/logic/textract/analyzeExpense.d.ts +51 -0
  34. package/lib/esm/logic/textract/analyzeExpense.js +18 -0
  35. package/lib/esm/logic/textract/index.d.ts +2 -0
  36. package/lib/esm/logic/textract/index.js +2 -0
  37. package/lib/esm/logic/textract/transformExpenseResponse.d.ts +29 -0
  38. package/lib/esm/logic/textract/transformExpenseResponse.js +173 -0
  39. package/package.json +8 -6
@@ -0,0 +1,2 @@
1
+ import { ActionProcessorListResolver } from 'quidproquo-core';
2
+ export declare const getFileGenerateTemporaryUploadSecureUrlActionProcessor: ActionProcessorListResolver;
@@ -0,0 +1,35 @@
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.getFileGenerateTemporaryUploadSecureUrlActionProcessor = void 0;
13
+ const quidproquo_config_aws_1 = require("quidproquo-config-aws");
14
+ const quidproquo_core_1 = require("quidproquo-core");
15
+ const quidproquo_core_2 = require("quidproquo-core");
16
+ const generatePresignedUploadUrl_1 = require("../../../logic/s3/generatePresignedUploadUrl");
17
+ const utils_1 = require("./utils");
18
+ const getProcessFileGenerateTemporaryUploadSecureUrl = (qpqConfig) => {
19
+ return (_a, session_1) => __awaiter(void 0, [_a, session_1], void 0, function* ({ drive, filepath, expirationMs, contentType }, session) {
20
+ try {
21
+ const s3BucketName = (0, utils_1.resolveStorageDriveBucketName)(drive, qpqConfig);
22
+ const url = yield (0, generatePresignedUploadUrl_1.generatePresignedUploadUrl)(s3BucketName, filepath, quidproquo_config_aws_1.qpqConfigAwsUtils.getApplicationModuleDeployRegion(qpqConfig), expirationMs, session.correlation, contentType);
23
+ return (0, quidproquo_core_2.actionResult)(url);
24
+ }
25
+ catch (error) {
26
+ return (0, quidproquo_core_1.actionResultError)(quidproquo_core_1.ErrorTypeEnum.GenericError, 'Unable to generate temporary upload secure URL', error);
27
+ }
28
+ });
29
+ };
30
+ const getFileGenerateTemporaryUploadSecureUrlActionProcessor = (qpqConfig) => __awaiter(void 0, void 0, void 0, function* () {
31
+ return ({
32
+ [quidproquo_core_2.FileActionType.GenerateTemporaryUploadSecureUrl]: getProcessFileGenerateTemporaryUploadSecureUrl(qpqConfig),
33
+ });
34
+ });
35
+ exports.getFileGenerateTemporaryUploadSecureUrlActionProcessor = getFileGenerateTemporaryUploadSecureUrlActionProcessor;
@@ -13,6 +13,7 @@ exports.getFileActionProcessor = void 0;
13
13
  const getFileDeleteActionProcessor_1 = require("./getFileDeleteActionProcessor");
14
14
  const getFileExistsActionProcessor_1 = require("./getFileExistsActionProcessor");
15
15
  const getFileGenerateTemporarySecureUrlActionProcessor_1 = require("./getFileGenerateTemporarySecureUrlActionProcessor");
16
+ const getFileGenerateTemporaryUploadSecureUrlActionProcessor_1 = require("./getFileGenerateTemporaryUploadSecureUrlActionProcessor");
16
17
  const getFileIsColdStorageActionProcessor_1 = require("./getFileIsColdStorageActionProcessor");
17
18
  const getFileListDirectoryActionProcessor_1 = require("./getFileListDirectoryActionProcessor");
18
19
  const getFileReadBinaryContentsActionProcessor_1 = require("./getFileReadBinaryContentsActionProcessor");
@@ -22,6 +23,6 @@ const getFileWriteBinaryContentsActionProcessor_1 = require("./getFileWriteBinar
22
23
  const getFileWriteObjectJsonActionProcessor_1 = require("./getFileWriteObjectJsonActionProcessor");
23
24
  const getFileWriteTextContentsActionProcessor_1 = require("./getFileWriteTextContentsActionProcessor");
24
25
  const getFileActionProcessor = (qpqConfig, dynamicModuleLoader) => __awaiter(void 0, void 0, void 0, function* () {
25
- return (Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, (yield (0, getFileDeleteActionProcessor_1.getFileDeleteActionProcessor)(qpqConfig, dynamicModuleLoader))), (yield (0, getFileExistsActionProcessor_1.getFileExistsActionProcessor)(qpqConfig, dynamicModuleLoader))), (yield (0, getFileGenerateTemporarySecureUrlActionProcessor_1.getFileGenerateTemporarySecureUrlActionProcessor)(qpqConfig, dynamicModuleLoader))), (yield (0, getFileIsColdStorageActionProcessor_1.getFileIsColdStorageActionProcessor)(qpqConfig, dynamicModuleLoader))), (yield (0, getFileListDirectoryActionProcessor_1.getFileListDirectoryActionProcessor)(qpqConfig, dynamicModuleLoader))), (yield (0, getFileReadTextContentsActionProcessor_1.getFileReadTextContentsActionProcessor)(qpqConfig, dynamicModuleLoader))), (yield (0, getFileReadObjectJsonActionProcessor_1.getFileReadObjectJsonActionProcessor)(qpqConfig, dynamicModuleLoader))), (yield (0, getFileWriteTextContentsActionProcessor_1.getFileWriteTextContentsActionProcessor)(qpqConfig, dynamicModuleLoader))), (yield (0, getFileReadBinaryContentsActionProcessor_1.getFileReadBinaryContentsActionProcessor)(qpqConfig, dynamicModuleLoader))), (yield (0, getFileWriteObjectJsonActionProcessor_1.getFileWriteObjectJsonActionProcessor)(qpqConfig, dynamicModuleLoader))), (yield (0, getFileWriteBinaryContentsActionProcessor_1.getFileWriteBinaryContentsActionProcessor)(qpqConfig, dynamicModuleLoader))));
26
+ return (Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, (yield (0, getFileDeleteActionProcessor_1.getFileDeleteActionProcessor)(qpqConfig, dynamicModuleLoader))), (yield (0, getFileExistsActionProcessor_1.getFileExistsActionProcessor)(qpqConfig, dynamicModuleLoader))), (yield (0, getFileGenerateTemporarySecureUrlActionProcessor_1.getFileGenerateTemporarySecureUrlActionProcessor)(qpqConfig, dynamicModuleLoader))), (yield (0, getFileGenerateTemporaryUploadSecureUrlActionProcessor_1.getFileGenerateTemporaryUploadSecureUrlActionProcessor)(qpqConfig, dynamicModuleLoader))), (yield (0, getFileIsColdStorageActionProcessor_1.getFileIsColdStorageActionProcessor)(qpqConfig, dynamicModuleLoader))), (yield (0, getFileListDirectoryActionProcessor_1.getFileListDirectoryActionProcessor)(qpqConfig, dynamicModuleLoader))), (yield (0, getFileReadTextContentsActionProcessor_1.getFileReadTextContentsActionProcessor)(qpqConfig, dynamicModuleLoader))), (yield (0, getFileReadObjectJsonActionProcessor_1.getFileReadObjectJsonActionProcessor)(qpqConfig, dynamicModuleLoader))), (yield (0, getFileWriteTextContentsActionProcessor_1.getFileWriteTextContentsActionProcessor)(qpqConfig, dynamicModuleLoader))), (yield (0, getFileReadBinaryContentsActionProcessor_1.getFileReadBinaryContentsActionProcessor)(qpqConfig, dynamicModuleLoader))), (yield (0, getFileWriteObjectJsonActionProcessor_1.getFileWriteObjectJsonActionProcessor)(qpqConfig, dynamicModuleLoader))), (yield (0, getFileWriteBinaryContentsActionProcessor_1.getFileWriteBinaryContentsActionProcessor)(qpqConfig, dynamicModuleLoader))));
26
27
  });
27
28
  exports.getFileActionProcessor = getFileActionProcessor;
@@ -0,0 +1,2 @@
1
+ import { ActionProcessorListResolver } from 'quidproquo-core';
2
+ export declare const getExtractExpenseActionProcessor: ActionProcessorListResolver;
@@ -0,0 +1,56 @@
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.getExtractExpenseActionProcessor = void 0;
13
+ const quidproquo_config_aws_1 = require("quidproquo-config-aws");
14
+ const quidproquo_core_1 = require("quidproquo-core");
15
+ const quidproquo_webserver_1 = require("quidproquo-webserver");
16
+ const awsNamingUtils_1 = require("../../../awsNamingUtils");
17
+ const textract_1 = require("../../../logic/textract");
18
+ const resolveStorageDriveBucketName = (drive, qpqConfig) => {
19
+ var _a, _b;
20
+ const storageDriveConfig = quidproquo_core_1.qpqCoreUtils.getStorageDriveByName(drive, qpqConfig);
21
+ if (!storageDriveConfig) {
22
+ throw new Error(`Could not find storage drive config for [${drive}]`);
23
+ }
24
+ return (0, awsNamingUtils_1.getConfigRuntimeResourceNameFromConfigWithServiceOverride)(((_a = storageDriveConfig.owner) === null || _a === void 0 ? void 0 : _a.resourceNameOverride) || drive, qpqConfig, (_b = storageDriveConfig.owner) === null || _b === void 0 ? void 0 : _b.module);
25
+ };
26
+ const getProcessExtractExpense = (qpqConfig) => {
27
+ return (_a) => __awaiter(void 0, [_a], void 0, function* ({ storageDriveName, filePath }) {
28
+ try {
29
+ const bucketName = resolveStorageDriveBucketName(storageDriveName, qpqConfig);
30
+ const region = quidproquo_config_aws_1.qpqConfigAwsUtils.getApplicationModuleDeployRegion(qpqConfig);
31
+ // Call Textract to analyze the expense document
32
+ const textractResponse = yield (0, textract_1.analyzeExpenseDocument)(bucketName, filePath, region);
33
+ // Transform the response to our format
34
+ const extractedDocument = (0, textract_1.transformTextractExpenseResponse)(textractResponse, storageDriveName, filePath, true);
35
+ return (0, quidproquo_core_1.actionResult)(extractedDocument);
36
+ }
37
+ catch (error) {
38
+ // Handle specific AWS errors with proper error mapping
39
+ return (0, quidproquo_core_1.actionResultErrorFromCaughtError)(error, {
40
+ InvalidS3ObjectException: () => (0, quidproquo_core_1.actionResultError)(quidproquo_webserver_1.ExtractExpenseErrorTypeEnum.FileNotFound, 'The specified file could not be found or accessed'),
41
+ NoSuchKey: () => (0, quidproquo_core_1.actionResultError)(quidproquo_webserver_1.ExtractExpenseErrorTypeEnum.FileNotFound, 'The specified file does not exist'),
42
+ UnsupportedDocumentException: () => (0, quidproquo_core_1.actionResultError)(quidproquo_webserver_1.ExtractExpenseErrorTypeEnum.UnsupportedFormat, 'The document format is not supported for expense analysis'),
43
+ InvalidParameterException: () => (0, quidproquo_core_1.actionResultError)(quidproquo_webserver_1.ExtractExpenseErrorTypeEnum.InvalidParameter, 'Invalid parameters provided to the extraction service'),
44
+ ThrottlingException: () => (0, quidproquo_core_1.actionResultError)(quidproquo_webserver_1.ExtractExpenseErrorTypeEnum.RateLimited, 'Too many requests, please try again later'),
45
+ InvalidObjectState: () => (0, quidproquo_core_1.actionResultError)(quidproquo_webserver_1.ExtractExpenseErrorTypeEnum.InvalidStorageClass, 'File is in the wrong storage class'),
46
+ AccessDenied: () => (0, quidproquo_core_1.actionResultError)(quidproquo_webserver_1.ExtractExpenseErrorTypeEnum.AccessDenied, 'Access denied to the specified file'),
47
+ });
48
+ }
49
+ });
50
+ };
51
+ const getExtractExpenseActionProcessor = (qpqConfig) => __awaiter(void 0, void 0, void 0, function* () {
52
+ return ({
53
+ [quidproquo_webserver_1.ExtractActionType.Expense]: getProcessExtractExpense(qpqConfig),
54
+ });
55
+ });
56
+ exports.getExtractExpenseActionProcessor = getExtractExpenseActionProcessor;
@@ -0,0 +1,2 @@
1
+ import { ActionProcessorListResolver } from 'quidproquo-core';
2
+ export declare const getExtractActionProcessor: ActionProcessorListResolver;
@@ -0,0 +1,17 @@
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.getExtractActionProcessor = void 0;
13
+ const getExtractExpenseActionProcessor_1 = require("./getExtractExpenseActionProcessor");
14
+ const getExtractActionProcessor = (qpqConfig, dynamicModuleLoader) => __awaiter(void 0, void 0, void 0, function* () {
15
+ return (Object.assign({}, (yield (0, getExtractExpenseActionProcessor_1.getExtractExpenseActionProcessor)(qpqConfig, dynamicModuleLoader))));
16
+ });
17
+ exports.getExtractActionProcessor = getExtractActionProcessor;
@@ -1,3 +1,4 @@
1
+ export * from './extract';
1
2
  export * from './serviceFunction';
2
3
  export * from './webEntry';
3
4
  export * from './websocket';
@@ -24,13 +24,15 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
24
24
  };
25
25
  Object.defineProperty(exports, "__esModule", { value: true });
26
26
  exports.getWebserverActionProcessor = void 0;
27
+ const extract_1 = require("./extract");
27
28
  const serviceFunction_1 = require("./serviceFunction");
28
29
  const webEntry_1 = require("./webEntry");
29
30
  const websocket_1 = require("./websocket");
31
+ __exportStar(require("./extract"), exports);
30
32
  __exportStar(require("./serviceFunction"), exports);
31
33
  __exportStar(require("./webEntry"), exports);
32
34
  __exportStar(require("./websocket"), exports);
33
35
  const getWebserverActionProcessor = (qpqConfig, dynamicModuleLoader) => __awaiter(void 0, void 0, void 0, function* () {
34
- return (Object.assign(Object.assign(Object.assign({}, (yield (0, webEntry_1.getWebEntryActionProcessor)(qpqConfig, dynamicModuleLoader))), (yield (0, serviceFunction_1.getServiceFunctionActionProcessor)(qpqConfig, dynamicModuleLoader))), (yield (0, websocket_1.getWebsocketActionProcessor)(qpqConfig, dynamicModuleLoader))));
36
+ return (Object.assign(Object.assign(Object.assign(Object.assign({}, (yield (0, extract_1.getExtractActionProcessor)(qpqConfig, dynamicModuleLoader))), (yield (0, webEntry_1.getWebEntryActionProcessor)(qpqConfig, dynamicModuleLoader))), (yield (0, serviceFunction_1.getServiceFunctionActionProcessor)(qpqConfig, dynamicModuleLoader))), (yield (0, websocket_1.getWebsocketActionProcessor)(qpqConfig, dynamicModuleLoader))));
35
37
  });
36
38
  exports.getWebserverActionProcessor = getWebserverActionProcessor;
@@ -1,4 +1,4 @@
1
- import { KvsUpdate, KvsUpdateActionType } from 'quidproquo-core';
1
+ import { KvsUpdate } from 'quidproquo-core';
2
2
  import { AttributeValue } from '@aws-sdk/client-dynamodb';
3
3
  interface ExpressionAttributeNameMap {
4
4
  [key: string]: string;
@@ -7,6 +7,5 @@ export declare const buildUpdateExpressionAttributeNames: (updates: KvsUpdate) =
7
7
  export declare const buildUpdateExpressionAttributeValues: (updates: KvsUpdate) => {
8
8
  [key: string]: AttributeValue;
9
9
  } | undefined;
10
- export declare const buildDynamoUpdateExpressionForType: (type: KvsUpdateActionType, kvsUpdate: KvsUpdate) => string;
11
10
  export declare const buildDynamoUpdateExpression: (updates: KvsUpdate) => string;
12
11
  export {};
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.buildDynamoUpdateExpression = exports.buildDynamoUpdateExpressionForType = exports.buildUpdateExpressionAttributeValues = exports.buildUpdateExpressionAttributeNames = void 0;
3
+ exports.buildDynamoUpdateExpression = exports.buildUpdateExpressionAttributeValues = exports.buildUpdateExpressionAttributeNames = void 0;
4
4
  const quidproquo_core_1 = require("quidproquo-core");
5
5
  const buildDynamoQuery_1 = require("./buildDynamoQuery");
6
6
  const buildUpdateExpressionAttributeNames = (updates) => {
@@ -35,6 +35,11 @@ const buildUpdateExpressionAttributeValues = (updates) => {
35
35
  const valuePlaceholder = (0, buildDynamoQuery_1.getValueName)(update.value);
36
36
  attributeValues[valuePlaceholder] = (0, buildDynamoQuery_1.buildAttributeValue)(update.value);
37
37
  }
38
+ // Include defaultValue for Increment actions
39
+ if (update.defaultValue !== undefined && update.defaultValue !== null) {
40
+ const defaultPlaceholder = (0, buildDynamoQuery_1.getValueName)(update.defaultValue);
41
+ attributeValues[defaultPlaceholder] = (0, buildDynamoQuery_1.buildAttributeValue)(update.defaultValue);
42
+ }
38
43
  }
39
44
  return Object.keys(attributeValues).length > 0 ? attributeValues : undefined;
40
45
  };
@@ -62,6 +67,23 @@ const buildDynamoUpdateExpressionDelete = (update) => {
62
67
  return `${getNestedItemName(update.attributePath)}`;
63
68
  }
64
69
  };
70
+ const buildDynamoUpdateExpressionSetIfNotExists = (update) => {
71
+ if (update.value === undefined || update.value === null) {
72
+ throw new Error("Value must be provided for 'SetIfNotExists' action");
73
+ }
74
+ const attrPath = getNestedItemName(update.attributePath);
75
+ return `${attrPath} = if_not_exists(${attrPath}, ${(0, buildDynamoQuery_1.getValueName)(update.value)})`;
76
+ };
77
+ const buildDynamoUpdateExpressionIncrement = (update) => {
78
+ if (update.value === undefined || update.value === null) {
79
+ throw new Error("Increment value must be provided for 'Increment' action");
80
+ }
81
+ if (update.defaultValue === undefined || update.defaultValue === null) {
82
+ throw new Error("Default value must be provided for 'Increment' action");
83
+ }
84
+ const attrPath = getNestedItemName(update.attributePath);
85
+ return `${attrPath} = if_not_exists(${attrPath}, ${(0, buildDynamoQuery_1.getValueName)(update.defaultValue)}) + ${(0, buildDynamoQuery_1.getValueName)(update.value)}`;
86
+ };
65
87
  const getNestedItemName = (attributePath) => {
66
88
  if (Array.isArray(attributePath)) {
67
89
  let path = '';
@@ -89,36 +111,36 @@ const buildDynamoUpdateExpressionPart = (update, updateIndex) => {
89
111
  return buildDynamoUpdateExpressionAdd(update);
90
112
  case quidproquo_core_1.KvsUpdateActionType.Delete:
91
113
  return buildDynamoUpdateExpressionDelete(update);
114
+ case quidproquo_core_1.KvsUpdateActionType.SetIfNotExists:
115
+ return buildDynamoUpdateExpressionSetIfNotExists(update);
116
+ case quidproquo_core_1.KvsUpdateActionType.Increment:
117
+ return buildDynamoUpdateExpressionIncrement(update);
92
118
  default:
93
119
  throw new Error(`Invalid update action type: ${update.action}`);
94
120
  }
95
121
  };
96
- const buildDynamoUpdateExpressionForType = (type, kvsUpdate) => {
97
- const actions = kvsUpdate.filter((update) => update.action === type);
98
- // If there are no actions of this type, return an empty string
122
+ // Types that generate SET expressions
123
+ const SET_ACTION_TYPES = [
124
+ quidproquo_core_1.KvsUpdateActionType.Set,
125
+ quidproquo_core_1.KvsUpdateActionType.SetIfNotExists,
126
+ quidproquo_core_1.KvsUpdateActionType.Increment
127
+ ];
128
+ const buildDynamoUpdateExpressionForClause = (clause, actionTypes, kvsUpdate) => {
129
+ const actions = kvsUpdate.filter((update) => actionTypes.includes(update.action));
99
130
  if (actions.length === 0) {
100
131
  return '';
101
132
  }
102
133
  const expressions = actions.map((update, index) => buildDynamoUpdateExpressionPart(update, index)).join(', ');
103
- switch (type) {
104
- case quidproquo_core_1.KvsUpdateActionType.Set:
105
- return `SET ${expressions}`;
106
- case quidproquo_core_1.KvsUpdateActionType.Remove:
107
- return `REMOVE ${expressions}`;
108
- case quidproquo_core_1.KvsUpdateActionType.Add:
109
- return `ADD ${expressions}`;
110
- case quidproquo_core_1.KvsUpdateActionType.Delete:
111
- return `DELETE ${expressions}`;
112
- default:
113
- throw new Error(`Invalid update action type: ${type}`);
114
- }
134
+ return `${clause} ${expressions}`;
115
135
  };
116
- exports.buildDynamoUpdateExpressionForType = buildDynamoUpdateExpressionForType;
117
136
  const buildDynamoUpdateExpression = (updates) => {
118
- const updatesExpressions = [quidproquo_core_1.KvsUpdateActionType.Set, quidproquo_core_1.KvsUpdateActionType.Remove, quidproquo_core_1.KvsUpdateActionType.Add, quidproquo_core_1.KvsUpdateActionType.Delete]
119
- .map((kvsUpdateActionType) => (0, exports.buildDynamoUpdateExpressionForType)(kvsUpdateActionType, updates))
120
- .filter((expression) => !!expression);
121
- const result = updatesExpressions.join(' ');
137
+ const clauses = [
138
+ buildDynamoUpdateExpressionForClause('SET', SET_ACTION_TYPES, updates),
139
+ buildDynamoUpdateExpressionForClause('REMOVE', [quidproquo_core_1.KvsUpdateActionType.Remove], updates),
140
+ buildDynamoUpdateExpressionForClause('ADD', [quidproquo_core_1.KvsUpdateActionType.Add], updates),
141
+ buildDynamoUpdateExpressionForClause('DELETE', [quidproquo_core_1.KvsUpdateActionType.Delete], updates),
142
+ ].filter((expression) => !!expression);
143
+ const result = clauses.join(' ');
122
144
  console.log('Update Expression: ', result);
123
145
  return result;
124
146
  };
@@ -0,0 +1 @@
1
+ export declare const generatePresignedUploadUrl: (bucketName: string, objectKey: string, region: string, expirationMs: number, correlationId?: string, contentType?: string) => Promise<string>;
@@ -0,0 +1,59 @@
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.generatePresignedUploadUrl = void 0;
13
+ const client_s3_1 = require("@aws-sdk/client-s3");
14
+ const s3_request_presigner_1 = require("@aws-sdk/s3-request-presigner");
15
+ // import { createPresignedPost } from '@aws-sdk/s3-presigned-post';
16
+ const createAwsClient_1 = require("../createAwsClient");
17
+ // export const generatePresignedUploadFormUrl = async (
18
+ // bucketName: string,
19
+ // objectKey: string,
20
+ // region: string,
21
+ // expirationMs: number,
22
+ // contentType: string | undefined,
23
+ // maxSizeBytes?: number | undefined
24
+ // ): Promise<{ url: string; fields: Record<string, string> }> => {
25
+ // const s3Client = createAwsClient(S3Client, { region });
26
+ // const conditions: any[] = [];
27
+ // // Add content type condition if provided
28
+ // if (contentType) {
29
+ // conditions.push(['eq', '$Content-Type', contentType]);
30
+ // }
31
+ // // Add file size limit condition if provided
32
+ // if (maxSizeBytes) {
33
+ // conditions.push(['content-length-range', 0, maxSizeBytes]);
34
+ // }
35
+ // const presignedPost = await createPresignedPost(s3Client, {
36
+ // Bucket: bucketName,
37
+ // Key: objectKey,
38
+ // Conditions: conditions,
39
+ // Expires: Math.floor(expirationMs / 1000),
40
+ // });
41
+ // return {
42
+ // url: presignedPost.url,
43
+ // fields: presignedPost.fields
44
+ // };
45
+ // };
46
+ const generatePresignedUploadUrl = (bucketName, objectKey, region, expirationMs, correlationId, contentType) => __awaiter(void 0, void 0, void 0, function* () {
47
+ const s3Client = (0, createAwsClient_1.createAwsClient)(client_s3_1.S3Client, { region });
48
+ const putObjectCommand = new client_s3_1.PutObjectCommand({
49
+ Bucket: bucketName,
50
+ Key: objectKey,
51
+ ContentType: contentType,
52
+ Metadata: Object.assign(Object.assign({}, (correlationId && { 'correlation-id': correlationId })), { 'upload-timestamp': Date.now().toString() })
53
+ });
54
+ const url = yield (0, s3_request_presigner_1.getSignedUrl)(s3Client, putObjectCommand, {
55
+ expiresIn: expirationMs / 1000,
56
+ });
57
+ return url;
58
+ });
59
+ exports.generatePresignedUploadUrl = generatePresignedUploadUrl;
@@ -0,0 +1,51 @@
1
+ export interface TextractExpenseAnalysis {
2
+ DocumentMetadata?: {
3
+ Pages?: number;
4
+ };
5
+ ExpenseDocuments?: Array<{
6
+ ExpenseIndex?: number;
7
+ SummaryFields?: Array<{
8
+ Type?: {
9
+ Text?: string;
10
+ Confidence?: number;
11
+ };
12
+ ValueDetection?: {
13
+ Text?: string;
14
+ Confidence?: number;
15
+ };
16
+ LabelDetection?: {
17
+ Text?: string;
18
+ Confidence?: number;
19
+ };
20
+ PageNumber?: number;
21
+ }>;
22
+ LineItemGroups?: Array<{
23
+ LineItemGroupIndex?: number;
24
+ LineItems?: Array<{
25
+ LineItemExpenseFields?: Array<{
26
+ Type?: {
27
+ Text?: string;
28
+ Confidence?: number;
29
+ };
30
+ ValueDetection?: {
31
+ Text?: string;
32
+ Confidence?: number;
33
+ };
34
+ LabelDetection?: {
35
+ Text?: string;
36
+ Confidence?: number;
37
+ };
38
+ PageNumber?: number;
39
+ }>;
40
+ }>;
41
+ }>;
42
+ Blocks?: Array<{
43
+ BlockType?: string;
44
+ Text?: string;
45
+ Confidence?: number;
46
+ Page?: number;
47
+ Id?: string;
48
+ }>;
49
+ }>;
50
+ }
51
+ export declare const analyzeExpenseDocument: (bucketName: string, documentKey: string, region: string) => Promise<TextractExpenseAnalysis>;
@@ -0,0 +1,31 @@
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.analyzeExpenseDocument = void 0;
13
+ const client_textract_1 = require("@aws-sdk/client-textract");
14
+ const createAwsClient_1 = require("../createAwsClient");
15
+ const analyzeExpenseDocument = (bucketName, documentKey, region) => __awaiter(void 0, void 0, void 0, function* () {
16
+ const textractClient = (0, createAwsClient_1.createAwsClient)(client_textract_1.TextractClient, { region });
17
+ const command = new client_textract_1.AnalyzeExpenseCommand({
18
+ Document: {
19
+ S3Object: {
20
+ Bucket: bucketName,
21
+ Name: documentKey,
22
+ },
23
+ },
24
+ });
25
+ const response = yield textractClient.send(command);
26
+ return {
27
+ DocumentMetadata: response.DocumentMetadata,
28
+ ExpenseDocuments: response.ExpenseDocuments,
29
+ };
30
+ });
31
+ exports.analyzeExpenseDocument = analyzeExpenseDocument;
@@ -0,0 +1,2 @@
1
+ export * from './analyzeExpense';
2
+ export * from './transformExpenseResponse';
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./analyzeExpense"), exports);
18
+ __exportStar(require("./transformExpenseResponse"), exports);
@@ -0,0 +1,29 @@
1
+ import { TextractExpenseAnalysis } from './analyzeExpense';
2
+ export interface ExtractedExpenseDocument {
3
+ metadata: {
4
+ merchantName?: string;
5
+ merchantAddress?: string;
6
+ date?: string;
7
+ currency?: string;
8
+ paymentMethod?: string;
9
+ subtotal?: number;
10
+ tax?: number;
11
+ total?: number;
12
+ [key: string]: any;
13
+ };
14
+ lineItems?: Array<{
15
+ description: string;
16
+ quantity?: number;
17
+ unitPrice?: number;
18
+ total?: number;
19
+ [key: string]: any;
20
+ }>;
21
+ rawText?: string;
22
+ source: {
23
+ storageDrive: string;
24
+ filePath: string;
25
+ textractJobId?: string;
26
+ };
27
+ _raw?: any;
28
+ }
29
+ export declare function transformTextractExpenseResponse(textractResponse: TextractExpenseAnalysis, storageDrive: string, filePath: string, includeRaw?: boolean): ExtractedExpenseDocument;