quidproquo-actionprocessor-node 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.
- package/lib/commonjs/dynamicActionProcessor/file/getFileDeleteActionProcessor.d.ts +3 -0
- package/lib/commonjs/dynamicActionProcessor/file/getFileDeleteActionProcessor.js +81 -0
- package/lib/commonjs/dynamicActionProcessor/file/getFileExistsActionProcessor.d.ts +3 -0
- package/lib/commonjs/dynamicActionProcessor/file/getFileExistsActionProcessor.js +72 -0
- package/lib/commonjs/dynamicActionProcessor/file/getFileGenerateTemporarySecureUrlActionProcessor.d.ts +3 -0
- package/lib/commonjs/dynamicActionProcessor/file/getFileGenerateTemporarySecureUrlActionProcessor.js +41 -0
- package/lib/commonjs/dynamicActionProcessor/file/getFileGenerateTemporaryUploadSecureUrlActionProcessor.d.ts +3 -0
- package/lib/commonjs/dynamicActionProcessor/file/getFileGenerateTemporaryUploadSecureUrlActionProcessor.js +44 -0
- package/lib/commonjs/dynamicActionProcessor/file/getFileIsColdStorageActionProcessor.d.ts +3 -0
- package/lib/commonjs/dynamicActionProcessor/file/getFileIsColdStorageActionProcessor.js +25 -0
- package/lib/commonjs/dynamicActionProcessor/file/getFileListDirectoryActionProcessor.d.ts +3 -0
- package/lib/commonjs/dynamicActionProcessor/file/getFileListDirectoryActionProcessor.js +98 -0
- package/lib/commonjs/dynamicActionProcessor/file/getFileReadBinaryContentsActionProcessor.d.ts +3 -0
- package/lib/commonjs/dynamicActionProcessor/file/getFileReadBinaryContentsActionProcessor.js +77 -0
- package/lib/commonjs/dynamicActionProcessor/file/getFileReadObjectJsonActionProcessor.d.ts +3 -0
- package/lib/commonjs/dynamicActionProcessor/file/getFileReadObjectJsonActionProcessor.js +74 -0
- package/lib/commonjs/dynamicActionProcessor/file/getFileReadTextContentsActionProcessor.d.ts +3 -0
- package/lib/commonjs/dynamicActionProcessor/file/getFileReadTextContentsActionProcessor.js +70 -0
- package/lib/commonjs/dynamicActionProcessor/file/getFileWriteBinaryContentsActionProcessor.d.ts +3 -0
- package/lib/commonjs/dynamicActionProcessor/file/getFileWriteBinaryContentsActionProcessor.js +70 -0
- package/lib/commonjs/dynamicActionProcessor/file/getFileWriteObjectJsonActionProcessor.d.ts +3 -0
- package/lib/commonjs/dynamicActionProcessor/file/getFileWriteObjectJsonActionProcessor.js +69 -0
- package/lib/commonjs/dynamicActionProcessor/file/getFileWriteTextContentsActionProcessor.d.ts +3 -0
- package/lib/commonjs/dynamicActionProcessor/file/getFileWriteTextContentsActionProcessor.js +68 -0
- package/lib/commonjs/dynamicActionProcessor/file/index.d.ts +6 -0
- package/lib/commonjs/dynamicActionProcessor/file/index.js +48 -0
- package/lib/commonjs/dynamicActionProcessor/file/secureUrlUtils.d.ts +10 -0
- package/lib/commonjs/dynamicActionProcessor/file/secureUrlUtils.js +84 -0
- package/lib/commonjs/dynamicActionProcessor/file/types.d.ts +6 -0
- package/lib/commonjs/dynamicActionProcessor/file/types.js +2 -0
- package/lib/commonjs/dynamicActionProcessor/file/utils.d.ts +6 -0
- package/lib/commonjs/dynamicActionProcessor/file/utils.js +90 -0
- package/lib/commonjs/dynamicActionProcessor/index.d.ts +1 -0
- package/lib/commonjs/dynamicActionProcessor/index.js +17 -0
- package/lib/commonjs/index.d.ts +1 -0
- package/lib/commonjs/index.js +1 -0
- package/lib/esm/dynamicActionProcessor/file/getFileDeleteActionProcessor.d.ts +3 -0
- package/lib/esm/dynamicActionProcessor/file/getFileDeleteActionProcessor.js +33 -0
- package/lib/esm/dynamicActionProcessor/file/getFileExistsActionProcessor.d.ts +3 -0
- package/lib/esm/dynamicActionProcessor/file/getFileExistsActionProcessor.js +24 -0
- package/lib/esm/dynamicActionProcessor/file/getFileGenerateTemporarySecureUrlActionProcessor.d.ts +3 -0
- package/lib/esm/dynamicActionProcessor/file/getFileGenerateTemporarySecureUrlActionProcessor.js +26 -0
- package/lib/esm/dynamicActionProcessor/file/getFileGenerateTemporaryUploadSecureUrlActionProcessor.d.ts +3 -0
- package/lib/esm/dynamicActionProcessor/file/getFileGenerateTemporaryUploadSecureUrlActionProcessor.js +29 -0
- package/lib/esm/dynamicActionProcessor/file/getFileIsColdStorageActionProcessor.d.ts +3 -0
- package/lib/esm/dynamicActionProcessor/file/getFileIsColdStorageActionProcessor.js +10 -0
- package/lib/esm/dynamicActionProcessor/file/getFileListDirectoryActionProcessor.d.ts +3 -0
- package/lib/esm/dynamicActionProcessor/file/getFileListDirectoryActionProcessor.js +50 -0
- package/lib/esm/dynamicActionProcessor/file/getFileReadBinaryContentsActionProcessor.d.ts +3 -0
- package/lib/esm/dynamicActionProcessor/file/getFileReadBinaryContentsActionProcessor.js +29 -0
- package/lib/esm/dynamicActionProcessor/file/getFileReadObjectJsonActionProcessor.d.ts +3 -0
- package/lib/esm/dynamicActionProcessor/file/getFileReadObjectJsonActionProcessor.js +26 -0
- package/lib/esm/dynamicActionProcessor/file/getFileReadTextContentsActionProcessor.d.ts +3 -0
- package/lib/esm/dynamicActionProcessor/file/getFileReadTextContentsActionProcessor.js +22 -0
- package/lib/esm/dynamicActionProcessor/file/getFileWriteBinaryContentsActionProcessor.d.ts +3 -0
- package/lib/esm/dynamicActionProcessor/file/getFileWriteBinaryContentsActionProcessor.js +22 -0
- package/lib/esm/dynamicActionProcessor/file/getFileWriteObjectJsonActionProcessor.d.ts +3 -0
- package/lib/esm/dynamicActionProcessor/file/getFileWriteObjectJsonActionProcessor.js +21 -0
- package/lib/esm/dynamicActionProcessor/file/getFileWriteTextContentsActionProcessor.d.ts +3 -0
- package/lib/esm/dynamicActionProcessor/file/getFileWriteTextContentsActionProcessor.js +20 -0
- package/lib/esm/dynamicActionProcessor/file/index.d.ts +6 -0
- package/lib/esm/dynamicActionProcessor/file/index.js +32 -0
- package/lib/esm/dynamicActionProcessor/file/secureUrlUtils.d.ts +10 -0
- package/lib/esm/dynamicActionProcessor/file/secureUrlUtils.js +45 -0
- package/lib/esm/dynamicActionProcessor/file/types.d.ts +6 -0
- package/lib/esm/dynamicActionProcessor/file/types.js +1 -0
- package/lib/esm/dynamicActionProcessor/file/utils.d.ts +6 -0
- package/lib/esm/dynamicActionProcessor/file/utils.js +41 -0
- package/lib/esm/dynamicActionProcessor/index.d.ts +1 -0
- package/lib/esm/dynamicActionProcessor/index.js +1 -0
- package/lib/esm/index.d.ts +1 -0
- package/lib/esm/index.js +1 -0
- package/package.json +4 -4
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { actionResult, actionResultError, ErrorTypeEnum, FileActionType, qpqCoreUtils, } from 'quidproquo-core';
|
|
2
|
+
import { createSecureUrlToken, getSecureUrlBaseUrl } from './secureUrlUtils';
|
|
3
|
+
import { resolveFilePath } from './utils';
|
|
4
|
+
const getProcessFileGenerateTemporaryUploadSecureUrl = (qpqConfig, config) => {
|
|
5
|
+
const serviceName = qpqCoreUtils.getApplicationModuleName(qpqConfig);
|
|
6
|
+
return async ({ drive, filepath, expirationMs, contentType }) => {
|
|
7
|
+
try {
|
|
8
|
+
const expiresAt = Date.now() + expirationMs;
|
|
9
|
+
// Create a token for upload
|
|
10
|
+
const token = createSecureUrlToken({
|
|
11
|
+
fullFilepath: resolveFilePath(config, serviceName, drive, filepath),
|
|
12
|
+
operation: 'upload',
|
|
13
|
+
expiresAt,
|
|
14
|
+
contentType,
|
|
15
|
+
}, config.secureUrlSecret);
|
|
16
|
+
// Build the secure URL
|
|
17
|
+
const baseUrl = getSecureUrlBaseUrl(config);
|
|
18
|
+
const url = `${baseUrl}/secure-upload?token=${token}`;
|
|
19
|
+
console.log(`Generated upload URL for ${filepath} in drive ${drive}, expires at ${new Date(expiresAt).toISOString()}`);
|
|
20
|
+
return actionResult(url);
|
|
21
|
+
}
|
|
22
|
+
catch (error) {
|
|
23
|
+
return actionResultError(ErrorTypeEnum.GenericError, `Unable to generate temporary upload secure URL: ${error.message}`);
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
export const getFileGenerateTemporaryUploadSecureUrlActionProcessor = (config) => async (qpqConfig) => ({
|
|
28
|
+
[FileActionType.GenerateTemporaryUploadSecureUrl]: getProcessFileGenerateTemporaryUploadSecureUrl(qpqConfig, config),
|
|
29
|
+
});
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { actionResult, FileActionType, } from 'quidproquo-core';
|
|
2
|
+
const getProcessFileIsColdStorage = (config) => (qpqConfig) => {
|
|
3
|
+
return async ({ drive, filepath }) => {
|
|
4
|
+
// Local filesystem doesn't have cold storage, always return false
|
|
5
|
+
return actionResult(false);
|
|
6
|
+
};
|
|
7
|
+
};
|
|
8
|
+
export const getFileIsColdStorageActionProcessor = (config) => async (qpqConfig) => ({
|
|
9
|
+
[FileActionType.IsColdStorage]: getProcessFileIsColdStorage(config)(qpqConfig),
|
|
10
|
+
});
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { actionResult, actionResultError, ErrorTypeEnum, FileActionType, qpqCoreUtils, } from 'quidproquo-core';
|
|
2
|
+
import * as fs from 'fs/promises';
|
|
3
|
+
import * as path from 'path';
|
|
4
|
+
import { resolveFilePath } from './utils';
|
|
5
|
+
const getProcessFileListDirectory = (config) => (qpqConfig) => {
|
|
6
|
+
const serviceName = qpqCoreUtils.getApplicationModuleName(qpqConfig);
|
|
7
|
+
return async ({ drive, folderPath, maxFiles, pageToken }) => {
|
|
8
|
+
try {
|
|
9
|
+
const fullPath = resolveFilePath(config, serviceName, drive, folderPath || '');
|
|
10
|
+
// Read all entries in the directory
|
|
11
|
+
const entries = await fs.readdir(fullPath, { withFileTypes: true });
|
|
12
|
+
// Build file info list
|
|
13
|
+
const allFiles = [];
|
|
14
|
+
for (const entry of entries) {
|
|
15
|
+
allFiles.push({
|
|
16
|
+
filepath: path.join(folderPath || '', entry.name),
|
|
17
|
+
drive: drive,
|
|
18
|
+
isDir: entry.isDirectory(),
|
|
19
|
+
hashMd5: undefined,
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
// Sort by filepath for consistent pagination
|
|
23
|
+
allFiles.sort((a, b) => a.filepath.localeCompare(b.filepath));
|
|
24
|
+
// Handle pagination
|
|
25
|
+
const startIndex = pageToken ? parseInt(pageToken, 10) : 0;
|
|
26
|
+
const endIndex = Math.min(startIndex + maxFiles, allFiles.length);
|
|
27
|
+
const paginatedFiles = allFiles.slice(startIndex, endIndex);
|
|
28
|
+
const result = {
|
|
29
|
+
fileInfos: paginatedFiles,
|
|
30
|
+
};
|
|
31
|
+
// Add page token if there are more files
|
|
32
|
+
if (endIndex < allFiles.length) {
|
|
33
|
+
result.pageToken = endIndex.toString();
|
|
34
|
+
}
|
|
35
|
+
return actionResult(result);
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
if (error.code === 'ENOENT') {
|
|
39
|
+
return actionResultError(ErrorTypeEnum.NotFound, `Directory not found: ${folderPath}`);
|
|
40
|
+
}
|
|
41
|
+
if (error.code === 'ENOTDIR') {
|
|
42
|
+
return actionResultError(ErrorTypeEnum.GenericError, `Path is not a directory: ${folderPath}`);
|
|
43
|
+
}
|
|
44
|
+
return actionResultError(ErrorTypeEnum.GenericError, `Error listing directory: ${error.message}`);
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
export const getFileListDirectoryActionProcessor = (config) => async (qpqConfig) => ({
|
|
49
|
+
[FileActionType.ListDirectory]: getProcessFileListDirectory(config)(qpqConfig),
|
|
50
|
+
});
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { actionResult, actionResultError, ErrorTypeEnum, FileActionType, qpqCoreUtils, } from 'quidproquo-core';
|
|
2
|
+
import * as fs from 'fs/promises';
|
|
3
|
+
import * as path from 'path';
|
|
4
|
+
import { resolveFilePath } from './utils';
|
|
5
|
+
const getProcessFileReadBinaryContents = (config) => (qpqConfig) => {
|
|
6
|
+
const serviceName = qpqCoreUtils.getApplicationModuleName(qpqConfig);
|
|
7
|
+
return async ({ drive, filepath }) => {
|
|
8
|
+
try {
|
|
9
|
+
const fullPath = resolveFilePath(config, serviceName, drive, filepath);
|
|
10
|
+
const buffer = await fs.readFile(fullPath);
|
|
11
|
+
// Convert Buffer to QPQBinaryData
|
|
12
|
+
const binaryData = {
|
|
13
|
+
base64Data: buffer.toString('base64'),
|
|
14
|
+
filename: path.basename(filepath),
|
|
15
|
+
mimetype: 'application/octet-stream', // Default mimetype for binary files
|
|
16
|
+
};
|
|
17
|
+
return actionResult(binaryData);
|
|
18
|
+
}
|
|
19
|
+
catch (error) {
|
|
20
|
+
if (error.code === 'ENOENT') {
|
|
21
|
+
return actionResultError(ErrorTypeEnum.NotFound, `File not found: ${filepath}`);
|
|
22
|
+
}
|
|
23
|
+
return actionResultError(ErrorTypeEnum.GenericError, `Error reading binary file: ${error.message}`);
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
export const getFileReadBinaryContentsActionProcessor = (config) => async (qpqConfig) => ({
|
|
28
|
+
[FileActionType.ReadBinaryContents]: getProcessFileReadBinaryContents(config)(qpqConfig),
|
|
29
|
+
});
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { actionResult, actionResultError, ErrorTypeEnum, FileActionType, qpqCoreUtils, } from 'quidproquo-core';
|
|
2
|
+
import * as fs from 'fs/promises';
|
|
3
|
+
import { resolveFilePath } from './utils';
|
|
4
|
+
const getProcessFileReadObjectJson = (config) => (qpqConfig) => {
|
|
5
|
+
const serviceName = qpqCoreUtils.getApplicationModuleName(qpqConfig);
|
|
6
|
+
return async ({ drive, filepath }) => {
|
|
7
|
+
try {
|
|
8
|
+
const fullPath = resolveFilePath(config, serviceName, drive, filepath);
|
|
9
|
+
const content = await fs.readFile(fullPath, 'utf8');
|
|
10
|
+
const jsonObject = JSON.parse(content);
|
|
11
|
+
return actionResult(jsonObject);
|
|
12
|
+
}
|
|
13
|
+
catch (error) {
|
|
14
|
+
if (error.code === 'ENOENT') {
|
|
15
|
+
return actionResultError(ErrorTypeEnum.NotFound, `File not found: ${filepath}`);
|
|
16
|
+
}
|
|
17
|
+
if (error instanceof SyntaxError) {
|
|
18
|
+
return actionResultError(ErrorTypeEnum.GenericError, `Invalid JSON in file: ${filepath}`);
|
|
19
|
+
}
|
|
20
|
+
return actionResultError(ErrorTypeEnum.GenericError, `Error reading JSON file: ${error.message}`);
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
export const getFileReadObjectJsonActionProcessor = (config) => async (qpqConfig) => ({
|
|
25
|
+
[FileActionType.ReadObjectJson]: getProcessFileReadObjectJson(config)(qpqConfig),
|
|
26
|
+
});
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { actionResult, actionResultError, ErrorTypeEnum, FileActionType, qpqCoreUtils, } from 'quidproquo-core';
|
|
2
|
+
import * as fs from 'fs/promises';
|
|
3
|
+
import { resolveFilePath } from './utils';
|
|
4
|
+
const getProcessFileReadTextContents = (qpqConfig, config) => {
|
|
5
|
+
const serviceName = qpqCoreUtils.getApplicationModuleName(qpqConfig);
|
|
6
|
+
return async ({ drive, filepath }) => {
|
|
7
|
+
try {
|
|
8
|
+
const fullPath = resolveFilePath(config, serviceName, drive, filepath);
|
|
9
|
+
const content = await fs.readFile(fullPath, 'utf8');
|
|
10
|
+
return actionResult(content);
|
|
11
|
+
}
|
|
12
|
+
catch (error) {
|
|
13
|
+
if (error.code === 'ENOENT') {
|
|
14
|
+
return actionResultError(ErrorTypeEnum.NotFound, `File not found: ${filepath}`);
|
|
15
|
+
}
|
|
16
|
+
return actionResultError(ErrorTypeEnum.GenericError, `Error reading file: ${error.message}`);
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
export const getFileReadTextContentsActionProcessor = (config) => async (qpqConfig) => ({
|
|
21
|
+
[FileActionType.ReadTextContents]: getProcessFileReadTextContents(qpqConfig, config),
|
|
22
|
+
});
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { actionResult, actionResultError, ErrorTypeEnum, FileActionType, qpqCoreUtils, } from 'quidproquo-core';
|
|
2
|
+
import * as fs from 'fs/promises';
|
|
3
|
+
import { ensureParentDirectoryExists, resolveFilePath } from './utils';
|
|
4
|
+
const getProcessFileWriteBinaryContents = (config) => (qpqConfig) => {
|
|
5
|
+
const serviceName = qpqCoreUtils.getApplicationModuleName(qpqConfig);
|
|
6
|
+
return async ({ drive, filepath, data }) => {
|
|
7
|
+
try {
|
|
8
|
+
const fullPath = resolveFilePath(config, serviceName, drive, filepath);
|
|
9
|
+
await ensureParentDirectoryExists(fullPath);
|
|
10
|
+
// Convert QPQBinaryData to Buffer
|
|
11
|
+
const buffer = Buffer.from(data.base64Data, 'base64');
|
|
12
|
+
await fs.writeFile(fullPath, buffer);
|
|
13
|
+
return actionResult(void 0);
|
|
14
|
+
}
|
|
15
|
+
catch (error) {
|
|
16
|
+
return actionResultError(ErrorTypeEnum.GenericError, `Error writing binary file: ${error.message}`);
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
export const getFileWriteBinaryContentsActionProcessor = (config) => async (qpqConfig) => ({
|
|
21
|
+
[FileActionType.WriteBinaryContents]: getProcessFileWriteBinaryContents(config)(qpqConfig),
|
|
22
|
+
});
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { actionResult, actionResultError, ErrorTypeEnum, FileActionType, qpqCoreUtils, } from 'quidproquo-core';
|
|
2
|
+
import * as fs from 'fs/promises';
|
|
3
|
+
import { ensureParentDirectoryExists, resolveFilePath } from './utils';
|
|
4
|
+
const getProcessFileWriteObjectJson = (config) => (qpqConfig) => {
|
|
5
|
+
const serviceName = qpqCoreUtils.getApplicationModuleName(qpqConfig);
|
|
6
|
+
return async ({ drive, filepath, data }) => {
|
|
7
|
+
try {
|
|
8
|
+
const fullPath = resolveFilePath(config, serviceName, drive, filepath);
|
|
9
|
+
await ensureParentDirectoryExists(fullPath);
|
|
10
|
+
const jsonString = JSON.stringify(data, null, 2);
|
|
11
|
+
await fs.writeFile(fullPath, jsonString, 'utf8');
|
|
12
|
+
return actionResult(void 0);
|
|
13
|
+
}
|
|
14
|
+
catch (error) {
|
|
15
|
+
return actionResultError(ErrorTypeEnum.GenericError, `Error writing JSON file: ${error.message}`);
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
export const getFileWriteObjectJsonActionProcessor = (config) => async (qpqConfig) => ({
|
|
20
|
+
[FileActionType.WriteObjectJson]: getProcessFileWriteObjectJson(config)(qpqConfig),
|
|
21
|
+
});
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { actionResult, actionResultError, ErrorTypeEnum, FileActionType, qpqCoreUtils, } from 'quidproquo-core';
|
|
2
|
+
import * as fs from 'fs/promises';
|
|
3
|
+
import { ensureParentDirectoryExists, resolveFilePath } from './utils';
|
|
4
|
+
const getProcessFileWriteTextContents = (qpqConfig, config) => {
|
|
5
|
+
const serviceName = qpqCoreUtils.getApplicationModuleName(qpqConfig);
|
|
6
|
+
return async ({ drive, filepath, data }) => {
|
|
7
|
+
try {
|
|
8
|
+
const fullPath = resolveFilePath(config, serviceName, drive, filepath);
|
|
9
|
+
await ensureParentDirectoryExists(fullPath);
|
|
10
|
+
await fs.writeFile(fullPath, data, 'utf8');
|
|
11
|
+
return actionResult(void 0);
|
|
12
|
+
}
|
|
13
|
+
catch (error) {
|
|
14
|
+
return actionResultError(ErrorTypeEnum.GenericError, `Error writing file: ${error.message}`);
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
export const getFileWriteTextContentsActionProcessor = (config) => async (qpqConfig) => ({
|
|
19
|
+
[FileActionType.WriteTextContents]: getProcessFileWriteTextContents(qpqConfig, config),
|
|
20
|
+
});
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { ActionProcessorListResolver } from 'quidproquo-core';
|
|
2
|
+
import { FileStorageConfig } from './types';
|
|
3
|
+
export * from './types';
|
|
4
|
+
export declare const getFileActionProcessor: (fileStorageConfig: FileStorageConfig) => ActionProcessorListResolver;
|
|
5
|
+
export * from "./secureUrlUtils";
|
|
6
|
+
export * from "./utils";
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { getFileDeleteActionProcessor } from './getFileDeleteActionProcessor';
|
|
2
|
+
import { getFileExistsActionProcessor } from './getFileExistsActionProcessor';
|
|
3
|
+
import { getFileGenerateTemporarySecureUrlActionProcessor } from './getFileGenerateTemporarySecureUrlActionProcessor';
|
|
4
|
+
import { getFileGenerateTemporaryUploadSecureUrlActionProcessor } from './getFileGenerateTemporaryUploadSecureUrlActionProcessor';
|
|
5
|
+
import { getFileIsColdStorageActionProcessor } from './getFileIsColdStorageActionProcessor';
|
|
6
|
+
import { getFileListDirectoryActionProcessor } from './getFileListDirectoryActionProcessor';
|
|
7
|
+
import { getFileReadBinaryContentsActionProcessor } from './getFileReadBinaryContentsActionProcessor';
|
|
8
|
+
import { getFileReadObjectJsonActionProcessor } from './getFileReadObjectJsonActionProcessor';
|
|
9
|
+
import { getFileReadTextContentsActionProcessor } from './getFileReadTextContentsActionProcessor';
|
|
10
|
+
import { getFileWriteBinaryContentsActionProcessor } from './getFileWriteBinaryContentsActionProcessor';
|
|
11
|
+
import { getFileWriteObjectJsonActionProcessor } from './getFileWriteObjectJsonActionProcessor';
|
|
12
|
+
import { getFileWriteTextContentsActionProcessor } from './getFileWriteTextContentsActionProcessor';
|
|
13
|
+
export * from './types';
|
|
14
|
+
// Main export that accepts configuration
|
|
15
|
+
export const getFileActionProcessor = (fileStorageConfig) => {
|
|
16
|
+
return async (qpqConfig, dynamicModuleLoader) => ({
|
|
17
|
+
...(await getFileReadTextContentsActionProcessor(fileStorageConfig)(qpqConfig, dynamicModuleLoader)),
|
|
18
|
+
...(await getFileWriteTextContentsActionProcessor(fileStorageConfig)(qpqConfig, dynamicModuleLoader)),
|
|
19
|
+
...(await getFileReadObjectJsonActionProcessor(fileStorageConfig)(qpqConfig, dynamicModuleLoader)),
|
|
20
|
+
...(await getFileWriteObjectJsonActionProcessor(fileStorageConfig)(qpqConfig, dynamicModuleLoader)),
|
|
21
|
+
...(await getFileReadBinaryContentsActionProcessor(fileStorageConfig)(qpqConfig, dynamicModuleLoader)),
|
|
22
|
+
...(await getFileWriteBinaryContentsActionProcessor(fileStorageConfig)(qpqConfig, dynamicModuleLoader)),
|
|
23
|
+
...(await getFileListDirectoryActionProcessor(fileStorageConfig)(qpqConfig, dynamicModuleLoader)),
|
|
24
|
+
...(await getFileExistsActionProcessor(fileStorageConfig)(qpqConfig, dynamicModuleLoader)),
|
|
25
|
+
...(await getFileDeleteActionProcessor(fileStorageConfig)(qpqConfig, dynamicModuleLoader)),
|
|
26
|
+
...(await getFileGenerateTemporarySecureUrlActionProcessor(fileStorageConfig)(qpqConfig, dynamicModuleLoader)),
|
|
27
|
+
...(await getFileGenerateTemporaryUploadSecureUrlActionProcessor(fileStorageConfig)(qpqConfig, dynamicModuleLoader)),
|
|
28
|
+
...(await getFileIsColdStorageActionProcessor(fileStorageConfig)(qpqConfig, dynamicModuleLoader)),
|
|
29
|
+
});
|
|
30
|
+
};
|
|
31
|
+
export * from "./secureUrlUtils";
|
|
32
|
+
export * from "./utils";
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { FileStorageConfig } from './types';
|
|
2
|
+
export interface SecureUrlToken {
|
|
3
|
+
fullFilepath: string;
|
|
4
|
+
operation: 'download' | 'upload';
|
|
5
|
+
expiresAt: number;
|
|
6
|
+
contentType?: string;
|
|
7
|
+
}
|
|
8
|
+
export declare const createSecureUrlToken: (token: SecureUrlToken, secret: string) => string;
|
|
9
|
+
export declare const verifySecureUrlToken: (tokenString: string, secret: string) => SecureUrlToken | null;
|
|
10
|
+
export declare const getSecureUrlBaseUrl: (config: FileStorageConfig) => string;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import * as crypto from 'crypto';
|
|
2
|
+
// Create a signed token for secure URLs
|
|
3
|
+
export const createSecureUrlToken = (token, secret) => {
|
|
4
|
+
const payload = JSON.stringify(token);
|
|
5
|
+
const payloadBase64 = Buffer.from(payload).toString('base64url');
|
|
6
|
+
// Create HMAC signature
|
|
7
|
+
const signature = crypto
|
|
8
|
+
.createHmac('sha256', secret)
|
|
9
|
+
.update(payloadBase64)
|
|
10
|
+
.digest('base64url');
|
|
11
|
+
// Return token as payload.signature
|
|
12
|
+
return `${payloadBase64}.${signature}`;
|
|
13
|
+
};
|
|
14
|
+
// Verify and decode a signed token
|
|
15
|
+
export const verifySecureUrlToken = (tokenString, secret) => {
|
|
16
|
+
try {
|
|
17
|
+
const [payloadBase64, signature] = tokenString.split('.');
|
|
18
|
+
if (!payloadBase64 || !signature) {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
// Verify signature
|
|
22
|
+
const expectedSignature = crypto
|
|
23
|
+
.createHmac('sha256', secret)
|
|
24
|
+
.update(payloadBase64)
|
|
25
|
+
.digest('base64url');
|
|
26
|
+
if (signature !== expectedSignature) {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
// Decode payload
|
|
30
|
+
const payload = Buffer.from(payloadBase64, 'base64url').toString();
|
|
31
|
+
const token = JSON.parse(payload);
|
|
32
|
+
// Check expiration
|
|
33
|
+
if (token.expiresAt < Date.now()) {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
return token;
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
// Get the secure URL base URL
|
|
43
|
+
export const getSecureUrlBaseUrl = (config) => {
|
|
44
|
+
return `http://${config.secureUrlHost}:${config.secureUrlPort}`;
|
|
45
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { QPQConfig } from 'quidproquo-core';
|
|
2
|
+
import { FileStorageConfig } from './types';
|
|
3
|
+
export declare const isStorageDriveNameValid: (drive: string, qpqConfig: QPQConfig) => boolean;
|
|
4
|
+
export declare function resolveFilePath(fileStorageConfig: FileStorageConfig, service: string, drive: string, filepath: string): string;
|
|
5
|
+
export declare const ensureDirectoryExists: (dirPath: string) => Promise<void>;
|
|
6
|
+
export declare const ensureParentDirectoryExists: (filePath: string) => Promise<void>;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { qpqCoreUtils } from 'quidproquo-core';
|
|
2
|
+
import * as fs from 'fs/promises';
|
|
3
|
+
import * as path from 'path';
|
|
4
|
+
// Resolve a drive name to a filesystem path
|
|
5
|
+
export const isStorageDriveNameValid = (drive, qpqConfig) => {
|
|
6
|
+
const storageDrive = qpqCoreUtils.getStorageDrives(qpqConfig).find((d) => d.storageDrive === drive);
|
|
7
|
+
if (!storageDrive) {
|
|
8
|
+
return false;
|
|
9
|
+
}
|
|
10
|
+
return true;
|
|
11
|
+
};
|
|
12
|
+
export function resolveFilePath(fileStorageConfig, service, drive, filepath) {
|
|
13
|
+
const root = path.resolve(fileStorageConfig.storagePath, service, drive);
|
|
14
|
+
// Block absolute paths and null bytes outright
|
|
15
|
+
if (path.isAbsolute(filepath)) {
|
|
16
|
+
throw new Error('Absolute paths are not allowed.');
|
|
17
|
+
}
|
|
18
|
+
// Check for null to prevent directory traversal attacks in native libs
|
|
19
|
+
if (filepath.includes('\0')) {
|
|
20
|
+
throw new Error('Invalid path.');
|
|
21
|
+
}
|
|
22
|
+
// Normalize user input (collapses ., .., slashes)
|
|
23
|
+
const cleaned = path.normalize(filepath);
|
|
24
|
+
// Resolve against the root
|
|
25
|
+
const target = path.resolve(root, cleaned);
|
|
26
|
+
// Ensure target stays within root
|
|
27
|
+
const rel = path.relative(root, target);
|
|
28
|
+
if (rel === '' || (!rel.startsWith('..') && !path.isAbsolute(rel))) {
|
|
29
|
+
return target;
|
|
30
|
+
}
|
|
31
|
+
throw new Error('Invalid file path: escapes drive root.');
|
|
32
|
+
}
|
|
33
|
+
// Ensure a directory exists
|
|
34
|
+
export const ensureDirectoryExists = async (dirPath) => {
|
|
35
|
+
await fs.mkdir(dirPath, { recursive: true });
|
|
36
|
+
};
|
|
37
|
+
// Ensure the parent directory of a file exists
|
|
38
|
+
export const ensureParentDirectoryExists = async (filePath) => {
|
|
39
|
+
const parentDir = path.dirname(filePath);
|
|
40
|
+
await ensureDirectoryExists(parentDir);
|
|
41
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './file';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './file';
|
package/lib/esm/index.d.ts
CHANGED
package/lib/esm/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "quidproquo-actionprocessor-node",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.258",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "./lib/commonjs/index.js",
|
|
6
6
|
"module": "./lib/esm/index.js",
|
|
@@ -35,15 +35,15 @@
|
|
|
35
35
|
"@anthropic-ai/sdk": "^0.19.1",
|
|
36
36
|
"axios": "^1.2.1",
|
|
37
37
|
"mime-types": "^2.1.35",
|
|
38
|
-
"quidproquo-core": "0.0.
|
|
39
|
-
"quidproquo-webserver": "0.0.
|
|
38
|
+
"quidproquo-core": "0.0.258",
|
|
39
|
+
"quidproquo-webserver": "0.0.258",
|
|
40
40
|
"uuid": "^9.0.0",
|
|
41
41
|
"uuidv7": "^1.0.1"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"@types/mime-types": "^2.1.1",
|
|
45
45
|
"@types/uuid": "^9.0.0",
|
|
46
|
-
"quidproquo-tsconfig": "0.0.
|
|
46
|
+
"quidproquo-tsconfig": "0.0.258",
|
|
47
47
|
"typescript": "^5.8.2"
|
|
48
48
|
}
|
|
49
49
|
}
|