@openstax/ts-utils 1.21.11 → 1.23.0
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/dist/cjs/assertions/index.d.ts +85 -0
- package/dist/cjs/assertions/index.js +157 -0
- package/dist/cjs/aws/ssmService.d.ts +5 -0
- package/dist/cjs/aws/ssmService.js +9 -0
- package/dist/cjs/config/awsParameterConfig.d.ts +10 -0
- package/dist/cjs/config/awsParameterConfig.js +26 -0
- package/dist/cjs/config/envConfig.d.ts +24 -0
- package/dist/cjs/config/envConfig.js +57 -0
- package/dist/cjs/config/index.d.ts +48 -0
- package/dist/cjs/config/index.js +35 -0
- package/dist/cjs/config/lambdaParameterConfig.d.ts +12 -0
- package/dist/cjs/config/lambdaParameterConfig.js +45 -0
- package/dist/cjs/config/replaceConfig.d.ts +14 -0
- package/dist/cjs/config/replaceConfig.js +22 -0
- package/dist/cjs/config/resolveConfigValue.d.ts +5 -0
- package/dist/cjs/config/resolveConfigValue.js +12 -0
- package/dist/cjs/errors/index.d.ts +77 -0
- package/dist/cjs/errors/index.js +109 -0
- package/dist/cjs/fetch/fetchStatusRetry.d.ts +7 -0
- package/dist/cjs/fetch/fetchStatusRetry.js +16 -0
- package/dist/cjs/fetch/index.d.ts +64 -0
- package/dist/cjs/fetch/index.js +55 -0
- package/dist/cjs/guards/index.d.ts +30 -0
- package/dist/cjs/guards/index.js +35 -0
- package/dist/cjs/index.d.ts +4 -0
- package/dist/cjs/index.js +20 -0
- package/dist/cjs/middleware/apiErrorHandler.d.ts +24 -0
- package/dist/cjs/middleware/apiErrorHandler.js +41 -0
- package/dist/cjs/middleware/apiSlowResponseMiddleware.d.ts +23 -0
- package/dist/cjs/middleware/apiSlowResponseMiddleware.js +54 -0
- package/dist/cjs/middleware/index.d.ts +47 -0
- package/dist/cjs/middleware/index.js +48 -0
- package/dist/cjs/middleware/lambdaCorsResponseMiddleware.d.ts +20 -0
- package/dist/cjs/middleware/lambdaCorsResponseMiddleware.js +42 -0
- package/dist/cjs/middleware/throwNotFoundMiddleware.d.ts +4 -0
- package/dist/cjs/middleware/throwNotFoundMiddleware.js +14 -0
- package/dist/cjs/misc/hashValue.d.ts +10 -0
- package/dist/cjs/misc/hashValue.js +17 -0
- package/dist/cjs/misc/helpers.d.ts +124 -0
- package/dist/cjs/misc/helpers.js +214 -0
- package/dist/cjs/misc/merge.d.ts +21 -0
- package/dist/cjs/misc/merge.js +45 -0
- package/dist/cjs/misc/partitionSequence.d.ts +35 -0
- package/dist/cjs/misc/partitionSequence.js +55 -0
- package/dist/cjs/pagination/index.d.ts +91 -0
- package/dist/cjs/pagination/index.js +83 -0
- package/dist/cjs/routing/helpers.d.ts +57 -0
- package/dist/cjs/routing/helpers.js +90 -0
- package/dist/cjs/routing/index.d.ts +272 -0
- package/dist/cjs/routing/index.js +270 -0
- package/dist/cjs/routing/validators/zod.d.ts +4 -0
- package/dist/cjs/routing/validators/zod.js +12 -0
- package/dist/cjs/services/accountsGateway/index.d.ts +85 -0
- package/dist/cjs/services/accountsGateway/index.js +118 -0
- package/dist/cjs/services/apiGateway/index.d.ts +63 -0
- package/dist/cjs/services/apiGateway/index.js +108 -0
- package/dist/cjs/services/authProvider/browser.d.ts +74 -0
- package/dist/cjs/services/authProvider/browser.js +154 -0
- package/dist/cjs/services/authProvider/decryption.d.ts +19 -0
- package/dist/cjs/services/authProvider/decryption.js +61 -0
- package/dist/cjs/services/authProvider/index.d.ts +61 -0
- package/dist/cjs/services/authProvider/index.js +26 -0
- package/dist/cjs/services/authProvider/subrequest.d.ts +16 -0
- package/dist/cjs/services/authProvider/subrequest.js +50 -0
- package/dist/cjs/services/authProvider/utils/decryptAndVerify.d.ts +29 -0
- package/dist/cjs/services/authProvider/utils/decryptAndVerify.js +91 -0
- package/dist/cjs/services/authProvider/utils/embeddedAuthProvider.d.ts +26 -0
- package/dist/cjs/services/authProvider/utils/embeddedAuthProvider.js +47 -0
- package/dist/cjs/services/authProvider/utils/userRoleValidator.d.ts +13 -0
- package/dist/cjs/services/authProvider/utils/userRoleValidator.js +37 -0
- package/dist/cjs/services/documentStore/dynamoEncoding.d.ts +10 -0
- package/dist/cjs/services/documentStore/dynamoEncoding.js +52 -0
- package/dist/cjs/services/documentStore/index.d.ts +14 -0
- package/dist/cjs/services/documentStore/index.js +2 -0
- package/dist/cjs/services/documentStore/unversioned/dynamodb.d.ts +16 -0
- package/dist/cjs/services/documentStore/unversioned/dynamodb.js +122 -0
- package/dist/cjs/services/documentStore/unversioned/file-system.d.ts +18 -0
- package/dist/cjs/services/documentStore/unversioned/file-system.js +121 -0
- package/dist/cjs/services/documentStore/unversioned/index.d.ts +2 -0
- package/dist/cjs/services/documentStore/unversioned/index.js +2 -0
- package/dist/cjs/services/documentStore/versioned/dynamodb.d.ts +22 -0
- package/dist/cjs/services/documentStore/versioned/dynamodb.js +135 -0
- package/dist/cjs/services/documentStore/versioned/file-system.d.ts +24 -0
- package/dist/cjs/services/documentStore/versioned/file-system.js +62 -0
- package/dist/cjs/services/documentStore/versioned/index.d.ts +17 -0
- package/dist/cjs/services/documentStore/versioned/index.js +2 -0
- package/dist/cjs/services/exercisesGateway/index.d.ts +71 -0
- package/dist/cjs/services/exercisesGateway/index.js +97 -0
- package/dist/cjs/services/fileServer/index.d.ts +17 -0
- package/dist/cjs/services/fileServer/index.js +19 -0
- package/dist/cjs/services/fileServer/localFileServer.d.ts +13 -0
- package/dist/cjs/services/fileServer/localFileServer.js +23 -0
- package/dist/cjs/services/fileServer/s3FileServer.d.ts +16 -0
- package/dist/cjs/services/fileServer/s3FileServer.js +25 -0
- package/dist/cjs/services/launchParams/index.d.ts +2 -0
- package/dist/cjs/services/launchParams/index.js +7 -0
- package/dist/cjs/services/launchParams/signer.d.ts +27 -0
- package/dist/cjs/services/launchParams/signer.js +58 -0
- package/dist/cjs/services/launchParams/verifier.d.ts +22 -0
- package/dist/cjs/services/launchParams/verifier.js +94 -0
- package/dist/cjs/services/logger/console.d.ts +4 -0
- package/dist/cjs/services/logger/console.js +12 -0
- package/dist/cjs/services/logger/index.d.ts +39 -0
- package/dist/cjs/services/logger/index.js +31 -0
- package/dist/cjs/services/lrsGateway/addStatementDefaultFields.d.ts +5 -0
- package/dist/cjs/services/lrsGateway/addStatementDefaultFields.js +21 -0
- package/dist/cjs/services/lrsGateway/attempt-utils.d.ts +70 -0
- package/dist/cjs/services/lrsGateway/attempt-utils.js +258 -0
- package/dist/cjs/services/lrsGateway/file-system.d.ts +17 -0
- package/dist/cjs/services/lrsGateway/file-system.js +140 -0
- package/dist/cjs/services/lrsGateway/index.d.ts +125 -0
- package/dist/cjs/services/lrsGateway/index.js +138 -0
- package/dist/cjs/services/lrsGateway/xapiUtils.d.ts +61 -0
- package/dist/cjs/services/lrsGateway/xapiUtils.js +94 -0
- package/dist/cjs/services/postgresConnection/index.d.ts +35 -0
- package/dist/cjs/services/postgresConnection/index.js +63 -0
- package/dist/cjs/services/searchProvider/index.d.ts +31 -0
- package/dist/cjs/services/searchProvider/index.js +2 -0
- package/dist/cjs/services/searchProvider/memorySearchTheBadWay.d.ts +14 -0
- package/dist/cjs/services/searchProvider/memorySearchTheBadWay.js +89 -0
- package/dist/cjs/tsconfig.without-specs.cjs.tsbuildinfo +1 -0
- package/dist/cjs/types.d.ts +31 -0
- package/dist/cjs/types.js +2 -0
- package/dist/esm/assertions/index.d.ts +85 -0
- package/dist/esm/assertions/index.js +146 -0
- package/dist/esm/aws/ssmService.d.ts +5 -0
- package/dist/esm/aws/ssmService.js +6 -0
- package/dist/esm/config/awsParameterConfig.d.ts +10 -0
- package/dist/esm/config/awsParameterConfig.js +22 -0
- package/dist/esm/config/envConfig.d.ts +24 -0
- package/dist/esm/config/envConfig.js +53 -0
- package/dist/esm/config/index.d.ts +48 -0
- package/dist/esm/config/index.js +17 -0
- package/dist/esm/config/lambdaParameterConfig.d.ts +12 -0
- package/dist/esm/config/lambdaParameterConfig.js +38 -0
- package/dist/esm/config/replaceConfig.d.ts +14 -0
- package/dist/esm/config/replaceConfig.js +18 -0
- package/dist/esm/config/resolveConfigValue.d.ts +5 -0
- package/dist/esm/config/resolveConfigValue.js +8 -0
- package/dist/esm/errors/index.d.ts +77 -0
- package/dist/esm/errors/index.js +99 -0
- package/dist/esm/fetch/fetchStatusRetry.d.ts +7 -0
- package/dist/esm/fetch/fetchStatusRetry.js +12 -0
- package/dist/esm/fetch/index.d.ts +64 -0
- package/dist/esm/fetch/index.js +46 -0
- package/dist/esm/guards/index.d.ts +30 -0
- package/dist/esm/guards/index.js +28 -0
- package/dist/esm/index.d.ts +4 -0
- package/dist/esm/index.js +4 -0
- package/dist/esm/middleware/apiErrorHandler.d.ts +24 -0
- package/dist/esm/middleware/apiErrorHandler.js +37 -0
- package/dist/esm/middleware/apiSlowResponseMiddleware.d.ts +23 -0
- package/dist/esm/middleware/apiSlowResponseMiddleware.js +50 -0
- package/dist/esm/middleware/index.d.ts +47 -0
- package/dist/esm/middleware/index.js +44 -0
- package/dist/esm/middleware/lambdaCorsResponseMiddleware.d.ts +20 -0
- package/dist/esm/middleware/lambdaCorsResponseMiddleware.js +38 -0
- package/dist/esm/middleware/throwNotFoundMiddleware.d.ts +4 -0
- package/dist/esm/middleware/throwNotFoundMiddleware.js +10 -0
- package/dist/esm/misc/hashValue.d.ts +10 -0
- package/dist/esm/misc/hashValue.js +13 -0
- package/dist/esm/misc/helpers.d.ts +124 -0
- package/dist/esm/misc/helpers.js +199 -0
- package/dist/esm/misc/merge.d.ts +21 -0
- package/dist/esm/misc/merge.js +40 -0
- package/dist/esm/misc/partitionSequence.d.ts +35 -0
- package/dist/esm/misc/partitionSequence.js +48 -0
- package/dist/esm/pagination/index.d.ts +91 -0
- package/dist/esm/pagination/index.js +77 -0
- package/dist/esm/routing/helpers.d.ts +57 -0
- package/dist/esm/routing/helpers.js +83 -0
- package/dist/esm/routing/index.d.ts +272 -0
- package/dist/esm/routing/index.js +232 -0
- package/dist/esm/routing/validators/zod.d.ts +4 -0
- package/dist/esm/routing/validators/zod.js +8 -0
- package/dist/esm/services/accountsGateway/index.d.ts +85 -0
- package/dist/esm/services/accountsGateway/index.js +111 -0
- package/dist/esm/services/apiGateway/index.d.ts +63 -0
- package/dist/esm/services/apiGateway/index.js +77 -0
- package/dist/esm/services/authProvider/browser.d.ts +74 -0
- package/dist/esm/services/authProvider/browser.js +150 -0
- package/dist/esm/services/authProvider/decryption.d.ts +19 -0
- package/dist/esm/services/authProvider/decryption.js +57 -0
- package/dist/esm/services/authProvider/index.d.ts +61 -0
- package/dist/esm/services/authProvider/index.js +18 -0
- package/dist/esm/services/authProvider/subrequest.d.ts +16 -0
- package/dist/esm/services/authProvider/subrequest.js +43 -0
- package/dist/esm/services/authProvider/utils/decryptAndVerify.d.ts +29 -0
- package/dist/esm/services/authProvider/utils/decryptAndVerify.js +85 -0
- package/dist/esm/services/authProvider/utils/embeddedAuthProvider.d.ts +26 -0
- package/dist/esm/services/authProvider/utils/embeddedAuthProvider.js +40 -0
- package/dist/esm/services/authProvider/utils/userRoleValidator.d.ts +13 -0
- package/dist/esm/services/authProvider/utils/userRoleValidator.js +33 -0
- package/dist/esm/services/documentStore/dynamoEncoding.d.ts +10 -0
- package/dist/esm/services/documentStore/dynamoEncoding.js +45 -0
- package/dist/esm/services/documentStore/index.d.ts +14 -0
- package/dist/esm/services/documentStore/index.js +1 -0
- package/dist/esm/services/documentStore/unversioned/dynamodb.d.ts +16 -0
- package/dist/esm/services/documentStore/unversioned/dynamodb.js +118 -0
- package/dist/esm/services/documentStore/unversioned/file-system.d.ts +18 -0
- package/dist/esm/services/documentStore/unversioned/file-system.js +91 -0
- package/dist/esm/services/documentStore/unversioned/index.d.ts +2 -0
- package/dist/esm/services/documentStore/unversioned/index.js +1 -0
- package/dist/esm/services/documentStore/versioned/dynamodb.d.ts +22 -0
- package/dist/esm/services/documentStore/versioned/dynamodb.js +131 -0
- package/dist/esm/services/documentStore/versioned/file-system.d.ts +24 -0
- package/dist/esm/services/documentStore/versioned/file-system.js +58 -0
- package/dist/esm/services/documentStore/versioned/index.d.ts +17 -0
- package/dist/esm/services/documentStore/versioned/index.js +1 -0
- package/dist/esm/services/exercisesGateway/index.d.ts +71 -0
- package/dist/esm/services/exercisesGateway/index.js +70 -0
- package/dist/esm/services/fileServer/index.d.ts +17 -0
- package/dist/esm/services/fileServer/index.js +13 -0
- package/dist/esm/services/fileServer/localFileServer.d.ts +13 -0
- package/dist/esm/services/fileServer/localFileServer.js +16 -0
- package/dist/esm/services/fileServer/s3FileServer.d.ts +16 -0
- package/dist/esm/services/fileServer/s3FileServer.js +21 -0
- package/dist/esm/services/launchParams/index.d.ts +2 -0
- package/dist/esm/services/launchParams/index.js +2 -0
- package/dist/esm/services/launchParams/signer.d.ts +27 -0
- package/dist/esm/services/launchParams/signer.js +51 -0
- package/dist/esm/services/launchParams/verifier.d.ts +22 -0
- package/dist/esm/services/launchParams/verifier.js +67 -0
- package/dist/esm/services/logger/console.d.ts +4 -0
- package/dist/esm/services/logger/console.js +8 -0
- package/dist/esm/services/logger/index.d.ts +39 -0
- package/dist/esm/services/logger/index.js +27 -0
- package/dist/esm/services/lrsGateway/addStatementDefaultFields.d.ts +5 -0
- package/dist/esm/services/lrsGateway/addStatementDefaultFields.js +14 -0
- package/dist/esm/services/lrsGateway/attempt-utils.d.ts +70 -0
- package/dist/esm/services/lrsGateway/attempt-utils.js +236 -0
- package/dist/esm/services/lrsGateway/file-system.d.ts +17 -0
- package/dist/esm/services/lrsGateway/file-system.js +110 -0
- package/dist/esm/services/lrsGateway/index.d.ts +125 -0
- package/dist/esm/services/lrsGateway/index.js +111 -0
- package/dist/esm/services/lrsGateway/xapiUtils.d.ts +61 -0
- package/dist/esm/services/lrsGateway/xapiUtils.js +84 -0
- package/dist/esm/services/postgresConnection/index.d.ts +35 -0
- package/dist/esm/services/postgresConnection/index.js +56 -0
- package/dist/esm/services/searchProvider/index.d.ts +31 -0
- package/dist/esm/services/searchProvider/index.js +1 -0
- package/dist/esm/services/searchProvider/memorySearchTheBadWay.d.ts +14 -0
- package/dist/esm/services/searchProvider/memorySearchTheBadWay.js +85 -0
- package/dist/esm/tsconfig.without-specs.esm.tsbuildinfo +1 -0
- package/dist/esm/types.d.ts +31 -0
- package/dist/esm/types.js +1 -0
- package/package.json +16 -16
- package/script/bin/deploy.bash +8 -0
- package/script/bin/get-env-param.bash +3 -3
- package/script/bin/init-params-script.bash +10 -1
- package/script/bin/upload-params.bash +3 -3
- package/dist/tsconfig.tsbuildinfo +0 -1
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import * as fsModule from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { hashValue } from '../../..';
|
|
4
|
+
import { resolveConfigValue } from '../../../config';
|
|
5
|
+
import { NotFoundError } from '../../../errors';
|
|
6
|
+
import { ifDefined, isDefined } from '../../../guards';
|
|
7
|
+
export const fileSystemUnversionedDocumentStore = (initializer) => () => (configProvider) => (_, hashKey) => {
|
|
8
|
+
const tableName = resolveConfigValue(configProvider[initializer.configSpace || 'fileSystem'].tableName);
|
|
9
|
+
const tablePath = tableName.then((table) => path.join(initializer.dataDir, table));
|
|
10
|
+
const { mkdir, readdir, readFile, writeFile } = ifDefined(initializer.fs, fsModule);
|
|
11
|
+
const mkTableDir = new Promise((resolve, reject) => tablePath.then((path) => mkdir(path, { recursive: true }, (err) => err && err.code !== 'EEXIST' ? reject(err) : resolve())));
|
|
12
|
+
const hashFilename = (value) => `${hashValue(value)}.json`;
|
|
13
|
+
const filePath = async (filename) => path.join(await tablePath, filename);
|
|
14
|
+
const load = async (filename) => {
|
|
15
|
+
const path = await filePath(filename);
|
|
16
|
+
await mkTableDir;
|
|
17
|
+
return new Promise((resolve, reject) => {
|
|
18
|
+
readFile(path, (err, readData) => {
|
|
19
|
+
if (err) {
|
|
20
|
+
err.code === 'ENOENT' ? resolve(undefined) : reject(err);
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
try {
|
|
24
|
+
const data = JSON.parse(readData.toString());
|
|
25
|
+
typeof data === 'object' ? resolve(data) : reject(new Error('unexpected non-object JSON'));
|
|
26
|
+
}
|
|
27
|
+
catch (err) {
|
|
28
|
+
reject(err);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
};
|
|
34
|
+
return {
|
|
35
|
+
loadAllDocumentsTheBadWay: async () => {
|
|
36
|
+
const path = await tablePath;
|
|
37
|
+
await mkTableDir;
|
|
38
|
+
return new Promise((resolve, reject) => readdir(path, (err, files) => err ?
|
|
39
|
+
reject(err) :
|
|
40
|
+
Promise.all(files.map((file) => load(file)))
|
|
41
|
+
.then((allData) => resolve(allData.filter(isDefined)), (err) => reject(err))));
|
|
42
|
+
},
|
|
43
|
+
batchGetItem: async (ids) => {
|
|
44
|
+
const items = await Promise.all(ids.map((id) => load(hashFilename(id))));
|
|
45
|
+
return items.filter(isDefined);
|
|
46
|
+
},
|
|
47
|
+
getItem: (id) => load(hashFilename(id)),
|
|
48
|
+
incrementItemAttribute: async (id, attribute) => {
|
|
49
|
+
const filename = hashFilename(id);
|
|
50
|
+
const path = await filePath(filename);
|
|
51
|
+
await mkTableDir;
|
|
52
|
+
const data = await load(filename);
|
|
53
|
+
if (!data) {
|
|
54
|
+
throw new NotFoundError(`Item with ${hashKey.toString()} "${id}" does not exist`);
|
|
55
|
+
}
|
|
56
|
+
const newValue = typeof data[attribute] === 'number' ? data[attribute] + 1 : 1;
|
|
57
|
+
const newItem = { ...data, [hashKey]: id, [attribute]: newValue };
|
|
58
|
+
return new Promise((resolve, reject) => {
|
|
59
|
+
writeFile(path, JSON.stringify(newItem, null, 2), (err) => err ? reject(err) : resolve(newValue));
|
|
60
|
+
});
|
|
61
|
+
},
|
|
62
|
+
patchItem: async (item) => {
|
|
63
|
+
const id = item[hashKey];
|
|
64
|
+
if (!id) {
|
|
65
|
+
throw new Error(`Key attribute "${hashKey.toString()}" is required for patchItem`);
|
|
66
|
+
}
|
|
67
|
+
// This check is just to make this adapter consistent with the dynamo adapter
|
|
68
|
+
if (Object.keys(item).filter((key) => key !== hashKey.toString()).length === 0) {
|
|
69
|
+
throw new Error('No attributes to update');
|
|
70
|
+
}
|
|
71
|
+
const filename = hashFilename(id);
|
|
72
|
+
const path = await filePath(filename);
|
|
73
|
+
await mkTableDir;
|
|
74
|
+
const data = await load(filename);
|
|
75
|
+
if (!data) {
|
|
76
|
+
throw new NotFoundError(`Item with ${hashKey.toString()} "${id}" does not exist`);
|
|
77
|
+
}
|
|
78
|
+
const newItem = { ...data, ...item };
|
|
79
|
+
return new Promise((resolve, reject) => {
|
|
80
|
+
writeFile(path, JSON.stringify(newItem, null, 2), (err) => err ? reject(err) : resolve(newItem));
|
|
81
|
+
});
|
|
82
|
+
},
|
|
83
|
+
putItem: async (item) => {
|
|
84
|
+
const path = await filePath(hashFilename(item[hashKey]));
|
|
85
|
+
await mkTableDir;
|
|
86
|
+
return new Promise((resolve, reject) => {
|
|
87
|
+
writeFile(path, JSON.stringify(item, null, 2), (err) => err ? reject(err) : resolve(item));
|
|
88
|
+
});
|
|
89
|
+
},
|
|
90
|
+
};
|
|
91
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Config } from '..';
|
|
2
|
+
import { ConfigProviderForConfig } from '../../../config';
|
|
3
|
+
import { VersionedDocumentAuthor, VersionedTDocument } from '.';
|
|
4
|
+
interface Initializer<C> {
|
|
5
|
+
configSpace?: C;
|
|
6
|
+
}
|
|
7
|
+
export declare const dynamoVersionedDocumentStore: <C extends string = "dynamodb">(initializer?: Initializer<C> | undefined) => <T extends VersionedTDocument<T>>() => (configProvider: { [key in C]: {
|
|
8
|
+
tableName: import("../../../config").ConfigValueProvider<string>;
|
|
9
|
+
}; }) => <K extends keyof T, A extends ((...a: any[]) => Promise<VersionedDocumentAuthor>) | undefined>(_: {}, hashKey: K, getAuthor: A) => {
|
|
10
|
+
loadAllDocumentsTheBadWay: () => Promise<T[]>;
|
|
11
|
+
getVersions: (id: T[K], startVersion?: number | undefined) => Promise<{
|
|
12
|
+
items: T[];
|
|
13
|
+
nextPageToken: number | undefined;
|
|
14
|
+
} | undefined>;
|
|
15
|
+
getItem: (id: T[K], timestamp?: number | undefined) => Promise<T | undefined>;
|
|
16
|
+
prepareItem: (item: Omit<T, "timestamp" | "author">, ...authorArgs: A extends Function ? Parameters<A> : [VersionedDocumentAuthor]) => Promise<{
|
|
17
|
+
document: T;
|
|
18
|
+
save: (changes?: Partial<Omit<T, "timestamp" | "author">> | undefined) => Promise<T>;
|
|
19
|
+
}>;
|
|
20
|
+
putItem: (item: Omit<T, "timestamp" | "author">, ...authorArgs: A extends Function ? Parameters<A> : [VersionedDocumentAuthor]) => Promise<T>;
|
|
21
|
+
};
|
|
22
|
+
export {};
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { DynamoDB, PutItemCommand, QueryCommand, ScanCommand } from '@aws-sdk/client-dynamodb';
|
|
2
|
+
import { once } from '../../..';
|
|
3
|
+
import { resolveConfigValue } from '../../../config';
|
|
4
|
+
import { ifDefined } from '../../../guards';
|
|
5
|
+
import { decodeDynamoDocument, encodeDynamoAttribute, encodeDynamoDocument } from '../dynamoEncoding';
|
|
6
|
+
const dynamodb = once(() => new DynamoDB({ apiVersion: '2012-08-10' }));
|
|
7
|
+
// i'm not really excited about getAuthor being required, but ts is getting confused about the type when unspecified
|
|
8
|
+
export const dynamoVersionedDocumentStore = (initializer) => () => (configProvider) => (_, hashKey, getAuthor) => {
|
|
9
|
+
const options = ifDefined(initializer, {});
|
|
10
|
+
const tableName = once(() => resolveConfigValue(configProvider[ifDefined(options.configSpace, 'dynamodb')].tableName));
|
|
11
|
+
return {
|
|
12
|
+
loadAllDocumentsTheBadWay: async () => {
|
|
13
|
+
const loadAllResults = async (ExclusiveStartKey) => {
|
|
14
|
+
var _a;
|
|
15
|
+
const cmd = new ScanCommand({ TableName: await tableName(), ExclusiveStartKey });
|
|
16
|
+
const result = await dynamodb().send(cmd);
|
|
17
|
+
const resultItems = ((_a = result.Items) === null || _a === void 0 ? void 0 : _a.map(decodeDynamoDocument)) || [];
|
|
18
|
+
if (result.LastEvaluatedKey) {
|
|
19
|
+
return [...resultItems, ...await loadAllResults(result.LastEvaluatedKey)];
|
|
20
|
+
}
|
|
21
|
+
return resultItems;
|
|
22
|
+
};
|
|
23
|
+
const allResults = await loadAllResults().then(results => results.reduce((result, document) => {
|
|
24
|
+
const current = result.get(document[hashKey]);
|
|
25
|
+
if (!current || current.timestamp < document.timestamp) {
|
|
26
|
+
return result.set(document[hashKey], document);
|
|
27
|
+
}
|
|
28
|
+
return result;
|
|
29
|
+
}, new Map()));
|
|
30
|
+
return Array.from(allResults.values());
|
|
31
|
+
},
|
|
32
|
+
getVersions: async (id, startVersion) => {
|
|
33
|
+
const cmd = new QueryCommand({
|
|
34
|
+
TableName: await tableName(),
|
|
35
|
+
KeyConditionExpression: '#hk = :hkv',
|
|
36
|
+
ExpressionAttributeValues: {
|
|
37
|
+
':hkv': encodeDynamoAttribute(id)
|
|
38
|
+
},
|
|
39
|
+
ExpressionAttributeNames: {
|
|
40
|
+
'#hk': hashKey.toString()
|
|
41
|
+
},
|
|
42
|
+
...(startVersion
|
|
43
|
+
? { ExclusiveStartKey: {
|
|
44
|
+
[hashKey]: encodeDynamoAttribute(id),
|
|
45
|
+
timestamp: { N: startVersion.toString() }
|
|
46
|
+
} }
|
|
47
|
+
: {}),
|
|
48
|
+
ScanIndexForward: false,
|
|
49
|
+
});
|
|
50
|
+
return dynamodb().send(cmd).then(result => {
|
|
51
|
+
var _a;
|
|
52
|
+
const items = (_a = result.Items) === null || _a === void 0 ? void 0 : _a.map(decodeDynamoDocument);
|
|
53
|
+
if (!items || items.length === 0) {
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
56
|
+
return {
|
|
57
|
+
items,
|
|
58
|
+
nextPageToken: result.LastEvaluatedKey ? decodeDynamoDocument(result.LastEvaluatedKey).timestamp : undefined
|
|
59
|
+
};
|
|
60
|
+
});
|
|
61
|
+
},
|
|
62
|
+
getItem: async (id, timestamp) => {
|
|
63
|
+
let keyConditionExpression = '#hk = :hkv';
|
|
64
|
+
const expressionAttributeNames = {
|
|
65
|
+
'#hk': hashKey.toString()
|
|
66
|
+
};
|
|
67
|
+
const expressionAttributeValues = {
|
|
68
|
+
':hkv': encodeDynamoAttribute(id)
|
|
69
|
+
};
|
|
70
|
+
if (timestamp) {
|
|
71
|
+
keyConditionExpression += ' and #ts = :tsv';
|
|
72
|
+
expressionAttributeNames['#ts'] = 'timestamp';
|
|
73
|
+
expressionAttributeValues[':tsv'] = encodeDynamoAttribute(timestamp);
|
|
74
|
+
}
|
|
75
|
+
const cmd = new QueryCommand({
|
|
76
|
+
TableName: await tableName(),
|
|
77
|
+
KeyConditionExpression: keyConditionExpression,
|
|
78
|
+
ExpressionAttributeNames: expressionAttributeNames,
|
|
79
|
+
ExpressionAttributeValues: expressionAttributeValues,
|
|
80
|
+
ScanIndexForward: false,
|
|
81
|
+
Limit: 1
|
|
82
|
+
});
|
|
83
|
+
return dynamodb().send(cmd).then(result => {
|
|
84
|
+
var _a;
|
|
85
|
+
return (_a = result.Items) === null || _a === void 0 ? void 0 : _a.map(decodeDynamoDocument)[0];
|
|
86
|
+
});
|
|
87
|
+
},
|
|
88
|
+
/* prepares a new version of a document with the given data, then allows some additional
|
|
89
|
+
* changes to be input to a `save` function that actually saves it. useful for additional
|
|
90
|
+
* changes based on the new document version or author. the document version and author
|
|
91
|
+
* cannot be modified */
|
|
92
|
+
prepareItem: async (item, ...authorArgs) => {
|
|
93
|
+
// this getAuthor type is terrible
|
|
94
|
+
const author = getAuthor ? await getAuthor(...authorArgs) : authorArgs[0];
|
|
95
|
+
const timestamp = new Date().getTime();
|
|
96
|
+
return {
|
|
97
|
+
document: { ...item, timestamp, author },
|
|
98
|
+
save: async (changes) => {
|
|
99
|
+
const document = {
|
|
100
|
+
...item,
|
|
101
|
+
...changes,
|
|
102
|
+
timestamp,
|
|
103
|
+
author
|
|
104
|
+
};
|
|
105
|
+
const cmd = new PutItemCommand({
|
|
106
|
+
TableName: await tableName(),
|
|
107
|
+
Item: encodeDynamoDocument(document),
|
|
108
|
+
});
|
|
109
|
+
return dynamodb().send(cmd)
|
|
110
|
+
.then(() => document);
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
},
|
|
114
|
+
/* saves a new version of a document with the given data */
|
|
115
|
+
putItem: async (item, ...authorArgs) => {
|
|
116
|
+
// this getAuthor type is terrible
|
|
117
|
+
const author = getAuthor ? await getAuthor(...authorArgs) : authorArgs[0];
|
|
118
|
+
const document = {
|
|
119
|
+
...item,
|
|
120
|
+
timestamp: new Date().getTime(),
|
|
121
|
+
author
|
|
122
|
+
};
|
|
123
|
+
const cmd = new PutItemCommand({
|
|
124
|
+
TableName: await tableName(),
|
|
125
|
+
Item: encodeDynamoDocument(document),
|
|
126
|
+
});
|
|
127
|
+
return dynamodb().send(cmd)
|
|
128
|
+
.then(() => document);
|
|
129
|
+
},
|
|
130
|
+
};
|
|
131
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Config } from '..';
|
|
2
|
+
import { ConfigProviderForConfig } from '../../../config';
|
|
3
|
+
import { VersionedDocumentAuthor, VersionedTDocument } from '.';
|
|
4
|
+
interface Initializer<C> {
|
|
5
|
+
dataDir: string;
|
|
6
|
+
fs?: Pick<typeof import('fs'), 'mkdir' | 'readdir' | 'readFile' | 'writeFile'>;
|
|
7
|
+
configSpace?: C;
|
|
8
|
+
}
|
|
9
|
+
export declare const fileSystemVersionedDocumentStore: <C extends string = "fileSystem">(initializer: Initializer<C>) => <T extends VersionedTDocument<T>>() => (configProvider: { [key in C]: {
|
|
10
|
+
tableName: import("../../../config").ConfigValueProvider<string>;
|
|
11
|
+
}; }) => <K extends keyof T, A extends ((...a: any[]) => Promise<VersionedDocumentAuthor>) | undefined>(_: {}, hashKey: K, getAuthor: A) => {
|
|
12
|
+
loadAllDocumentsTheBadWay: () => Promise<T[]>;
|
|
13
|
+
getVersions: (id: T[K], startVersion?: number | undefined) => Promise<{
|
|
14
|
+
items: T[];
|
|
15
|
+
nextPageToken: number | undefined;
|
|
16
|
+
} | undefined>;
|
|
17
|
+
getItem: (id: T[K], timestamp?: number | undefined) => Promise<T | undefined>;
|
|
18
|
+
prepareItem: (item: Omit<T, "timestamp" | "author">, ...authorArgs: A extends Function ? Parameters<A> : [VersionedDocumentAuthor]) => Promise<{
|
|
19
|
+
document: T;
|
|
20
|
+
save: (changes?: Partial<Omit<T, "timestamp" | "author">> | undefined) => Promise<T>;
|
|
21
|
+
}>;
|
|
22
|
+
putItem: (item: Omit<T, "timestamp" | "author">, ...authorArgs: A extends Function ? Parameters<A> : [VersionedDocumentAuthor]) => Promise<T>;
|
|
23
|
+
};
|
|
24
|
+
export {};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { fileSystemUnversionedDocumentStore } from '../unversioned/file-system';
|
|
2
|
+
const PAGE_LIMIT = 5;
|
|
3
|
+
export const fileSystemVersionedDocumentStore = (initializer) => () => (configProvider) => (_, hashKey, getAuthor) => {
|
|
4
|
+
const unversionedDocuments = fileSystemUnversionedDocumentStore(initializer)()(configProvider)({}, 'id');
|
|
5
|
+
return {
|
|
6
|
+
loadAllDocumentsTheBadWay: () => {
|
|
7
|
+
return unversionedDocuments.loadAllDocumentsTheBadWay().then(documents => documents.map(document => {
|
|
8
|
+
return document.items[document.items.length - 1];
|
|
9
|
+
}));
|
|
10
|
+
},
|
|
11
|
+
getVersions: async (id, startVersion) => {
|
|
12
|
+
const item = await unversionedDocuments.getItem(id);
|
|
13
|
+
const versions = item === null || item === void 0 ? void 0 : item.items.reverse();
|
|
14
|
+
if (!versions) {
|
|
15
|
+
return undefined;
|
|
16
|
+
}
|
|
17
|
+
const startIndex = startVersion ? versions.findIndex(version => version.timestamp === startVersion) + 1 : 0;
|
|
18
|
+
const items = versions.slice(startIndex, startIndex + PAGE_LIMIT);
|
|
19
|
+
const hasMore = (startIndex + 5) < versions.length;
|
|
20
|
+
return {
|
|
21
|
+
items,
|
|
22
|
+
nextPageToken: hasMore ? items[items.length - 1].timestamp : undefined
|
|
23
|
+
};
|
|
24
|
+
},
|
|
25
|
+
getItem: async (id, timestamp) => {
|
|
26
|
+
const item = await unversionedDocuments.getItem(id);
|
|
27
|
+
if (timestamp) {
|
|
28
|
+
return item === null || item === void 0 ? void 0 : item.items.find(version => version.timestamp === timestamp);
|
|
29
|
+
}
|
|
30
|
+
return item ? item.items[item.items.length - 1] : undefined;
|
|
31
|
+
},
|
|
32
|
+
prepareItem: async (item, ...authorArgs) => {
|
|
33
|
+
// this getAuthor type is terrible
|
|
34
|
+
const author = getAuthor ? await getAuthor(...authorArgs) : authorArgs[0];
|
|
35
|
+
const timestamp = new Date().getTime();
|
|
36
|
+
return {
|
|
37
|
+
document: { ...item, timestamp, author },
|
|
38
|
+
save: async (changes) => {
|
|
39
|
+
var _a;
|
|
40
|
+
const document = { ...item, ...changes, timestamp, author };
|
|
41
|
+
const container = (_a = await unversionedDocuments.getItem(document[hashKey])) !== null && _a !== void 0 ? _a : { id: document[hashKey], items: [] };
|
|
42
|
+
const updated = { ...container, items: [...container.items, document] };
|
|
43
|
+
await unversionedDocuments.putItem(updated);
|
|
44
|
+
return document;
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
},
|
|
48
|
+
putItem: async (item, ...authorArgs) => {
|
|
49
|
+
var _a;
|
|
50
|
+
const author = getAuthor ? await getAuthor(...authorArgs) : authorArgs[0];
|
|
51
|
+
const document = { ...item, timestamp: new Date().getTime(), author };
|
|
52
|
+
const container = (_a = await unversionedDocuments.getItem(document[hashKey])) !== null && _a !== void 0 ? _a : { id: document[hashKey], items: [] };
|
|
53
|
+
const updated = { ...container, items: [...container.items, document] };
|
|
54
|
+
await unversionedDocuments.putItem(updated);
|
|
55
|
+
return document;
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { TDocument } from '..';
|
|
2
|
+
import { dynamoVersionedDocumentStore } from './dynamodb';
|
|
3
|
+
export declare type VersionedDocumentAuthor = {
|
|
4
|
+
type: 'user';
|
|
5
|
+
uuid: string;
|
|
6
|
+
name: string;
|
|
7
|
+
reason?: string;
|
|
8
|
+
} | {
|
|
9
|
+
type: 'system';
|
|
10
|
+
reason: string;
|
|
11
|
+
};
|
|
12
|
+
export declare type VersionedDocumentRequiredFields = {
|
|
13
|
+
timestamp: number;
|
|
14
|
+
author: VersionedDocumentAuthor;
|
|
15
|
+
};
|
|
16
|
+
export declare type VersionedTDocument<T> = TDocument<T> & VersionedDocumentRequiredFields;
|
|
17
|
+
export declare type VersionedDocumentStoreCreator = typeof dynamoVersionedDocumentStore;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { ConfigProviderForConfig } from '../../config';
|
|
2
|
+
import { GenericFetch } from '../../fetch';
|
|
3
|
+
export declare type Config = {
|
|
4
|
+
defaultCorrectness?: string;
|
|
5
|
+
exercisesHost: string;
|
|
6
|
+
exercisesAuthToken: string;
|
|
7
|
+
};
|
|
8
|
+
interface Initializer<C> {
|
|
9
|
+
configSpace?: C;
|
|
10
|
+
fetch: GenericFetch;
|
|
11
|
+
}
|
|
12
|
+
export declare type Answer = {
|
|
13
|
+
id: number;
|
|
14
|
+
content_html: string;
|
|
15
|
+
correctness?: string;
|
|
16
|
+
feedback_html?: string;
|
|
17
|
+
};
|
|
18
|
+
export declare type Solution = {
|
|
19
|
+
images: any[];
|
|
20
|
+
solution_type: string;
|
|
21
|
+
content_html: string;
|
|
22
|
+
};
|
|
23
|
+
export declare type Question = {
|
|
24
|
+
id: number;
|
|
25
|
+
is_answer_order_important: boolean;
|
|
26
|
+
stimulus_html: string;
|
|
27
|
+
stem_html: string;
|
|
28
|
+
answers: Answer[];
|
|
29
|
+
hints: string[];
|
|
30
|
+
formats: string[];
|
|
31
|
+
combo_choices: any[];
|
|
32
|
+
collaborator_solutions?: Solution[];
|
|
33
|
+
community_solutions?: Solution[];
|
|
34
|
+
};
|
|
35
|
+
export declare type Exercise = {
|
|
36
|
+
images: any[];
|
|
37
|
+
tags: string[];
|
|
38
|
+
uuid: string;
|
|
39
|
+
group_uuid: string;
|
|
40
|
+
number: number;
|
|
41
|
+
version: number;
|
|
42
|
+
uid: string;
|
|
43
|
+
published_at: string;
|
|
44
|
+
solutions_are_public: boolean;
|
|
45
|
+
authors: any[];
|
|
46
|
+
copyright_holders: any[];
|
|
47
|
+
derived_from: any[];
|
|
48
|
+
is_vocab: boolean;
|
|
49
|
+
questions: Question[];
|
|
50
|
+
delegations: any[];
|
|
51
|
+
versions: number[];
|
|
52
|
+
stimulus_html: string;
|
|
53
|
+
};
|
|
54
|
+
export declare type ExercisesSearchResults = {
|
|
55
|
+
total_count: number;
|
|
56
|
+
items: Exercise[];
|
|
57
|
+
};
|
|
58
|
+
export declare type ExercisesSearchResultsWithDigest = ExercisesSearchResults & {
|
|
59
|
+
digest: string;
|
|
60
|
+
};
|
|
61
|
+
export declare const exercisesGateway: <C extends string = "exercises">(initializer: Initializer<C>) => (configProvider: { [key in C]: {
|
|
62
|
+
defaultCorrectness?: import("../../config").ConfigValueProvider<string> | undefined;
|
|
63
|
+
exercisesHost: import("../../config").ConfigValueProvider<string>;
|
|
64
|
+
exercisesAuthToken: import("../../config").ConfigValueProvider<string>;
|
|
65
|
+
}; }) => (_: {}) => {
|
|
66
|
+
searchDigest: (query: string, page?: number, per_page?: number) => Promise<string>;
|
|
67
|
+
get: (uuid: string) => Promise<Exercise | undefined>;
|
|
68
|
+
search: (query: string, page?: number, per_page?: number) => Promise<ExercisesSearchResultsWithDigest>;
|
|
69
|
+
};
|
|
70
|
+
export declare type ExercisesGateway = ReturnType<ReturnType<ReturnType<typeof exercisesGateway>>>;
|
|
71
|
+
export {};
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import * as queryString from 'query-string';
|
|
2
|
+
import { once } from '../..';
|
|
3
|
+
import { assertString } from '../../assertions';
|
|
4
|
+
import { resolveConfigValue } from '../../config';
|
|
5
|
+
import { ifDefined } from '../../guards';
|
|
6
|
+
import { METHOD } from '../../routing';
|
|
7
|
+
export const exercisesGateway = (initializer) => (configProvider) => {
|
|
8
|
+
const config = configProvider[ifDefined(initializer.configSpace, 'exercises')];
|
|
9
|
+
const exercisesHost = once(() => resolveConfigValue(config.exercisesHost));
|
|
10
|
+
const exercisesAuthToken = once(() => resolveConfigValue(config.exercisesAuthToken));
|
|
11
|
+
const defaultCorrectness = once(() => resolveConfigValue(config.defaultCorrectness || ''));
|
|
12
|
+
const doDefaultCorrectness = async (exercise) => {
|
|
13
|
+
if (await defaultCorrectness() !== 'true') {
|
|
14
|
+
return exercise;
|
|
15
|
+
}
|
|
16
|
+
for (const question of exercise.questions) {
|
|
17
|
+
const existingCorrect = question.answers.find(answer => answer.correctness !== undefined);
|
|
18
|
+
if (question.answers.length < 1 || existingCorrect) {
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
const defaultCorrectIndex = question.id % question.answers.length;
|
|
22
|
+
const defaultCorrect = question.answers[defaultCorrectIndex];
|
|
23
|
+
const defaultHint = `<em>random default: the correct answer is ${defaultCorrect.id}: ${defaultCorrect.content_html.slice(0, 20)}</em>`;
|
|
24
|
+
question.stem_html += `\n<br>${defaultHint}`;
|
|
25
|
+
question.collaborator_solutions = [
|
|
26
|
+
{ solution_type: 'detailed', images: [], content_html: defaultHint }
|
|
27
|
+
];
|
|
28
|
+
for (let index = 0; index < question.answers.length; index++) {
|
|
29
|
+
const answer = question.answers[index];
|
|
30
|
+
answer.correctness = defaultCorrectIndex === index ? '1.0' : '0.0';
|
|
31
|
+
answer.feedback_html = defaultCorrectIndex === index ? 'This is the good one!' : defaultHint;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return exercise;
|
|
35
|
+
};
|
|
36
|
+
return (_) => {
|
|
37
|
+
const request = async (method, path, query = undefined) => {
|
|
38
|
+
const host = (await exercisesHost()).replace(/\/+$/, '');
|
|
39
|
+
const baseUrl = `${host}/api/${path}`;
|
|
40
|
+
const url = query ? `${baseUrl}?${queryString.stringify(query)}` : baseUrl;
|
|
41
|
+
return initializer.fetch(url, {
|
|
42
|
+
headers: {
|
|
43
|
+
Authorization: `Bearer ${await exercisesAuthToken()}`,
|
|
44
|
+
},
|
|
45
|
+
method,
|
|
46
|
+
});
|
|
47
|
+
};
|
|
48
|
+
const searchDigest = async (query, page = 1, per_page = 100) => {
|
|
49
|
+
const response = await request(METHOD.HEAD, 'exercises', { query, page, per_page });
|
|
50
|
+
return assertString(response.headers.get('X-Digest'), 'OpenStax Exercises search endpoint HEAD did not return an X-Digest header');
|
|
51
|
+
};
|
|
52
|
+
const search = async (query, page = 1, per_page = 100) => {
|
|
53
|
+
const response = await request(METHOD.GET, 'exercises', { query, page, per_page });
|
|
54
|
+
const digest = assertString(response.headers.get('X-Digest'), 'OpenStax Exercises search endpoint GET did not return an X-Digest header');
|
|
55
|
+
const { items, total_count } = await response.json();
|
|
56
|
+
return { digest, items: await Promise.all(items.map(doDefaultCorrectness)), total_count };
|
|
57
|
+
};
|
|
58
|
+
const get = async (uuid) => {
|
|
59
|
+
const response = await request(METHOD.GET, `exercises/${uuid}`);
|
|
60
|
+
return response.status === 404
|
|
61
|
+
? undefined
|
|
62
|
+
: response.json().then(doDefaultCorrectness);
|
|
63
|
+
};
|
|
64
|
+
return {
|
|
65
|
+
searchDigest,
|
|
66
|
+
get,
|
|
67
|
+
search,
|
|
68
|
+
};
|
|
69
|
+
};
|
|
70
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
export declare type FileValue = {
|
|
3
|
+
dataType: 'file';
|
|
4
|
+
mimeType: string;
|
|
5
|
+
path: string;
|
|
6
|
+
label: string;
|
|
7
|
+
};
|
|
8
|
+
export declare type FolderValue = {
|
|
9
|
+
dataType: 'folder';
|
|
10
|
+
files: FileValue[];
|
|
11
|
+
};
|
|
12
|
+
export declare const isFileValue: (thing: any) => thing is FileValue;
|
|
13
|
+
export declare const isFolderValue: (thing: any) => thing is FolderValue;
|
|
14
|
+
export interface FileServerAdapter {
|
|
15
|
+
getFileContent: (source: FileValue) => Promise<Buffer>;
|
|
16
|
+
}
|
|
17
|
+
export declare const isFileOrFolder: (thing: any) => thing is FileValue | FolderValue;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { isPlainObject } from '../../guards';
|
|
2
|
+
export const isFileValue = (thing) => isPlainObject(thing)
|
|
3
|
+
&& Object.keys(thing).every(key => ['dataType', 'path', 'label', 'mimeType'].includes(key))
|
|
4
|
+
&& thing.dataType === 'file'
|
|
5
|
+
&& typeof thing.mimeType === 'string'
|
|
6
|
+
&& typeof thing.path === 'string'
|
|
7
|
+
&& typeof thing.label === 'string';
|
|
8
|
+
export const isFolderValue = (thing) => isPlainObject(thing)
|
|
9
|
+
&& Object.keys(thing).every(key => ['dataType', 'files'].includes(key))
|
|
10
|
+
&& thing.dataType === 'folder'
|
|
11
|
+
&& thing.files instanceof Array
|
|
12
|
+
&& thing.files.every(isFileValue);
|
|
13
|
+
export const isFileOrFolder = (thing) => isFileValue(thing) || isFolderValue(thing);
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { ConfigProviderForConfig } from '../../config';
|
|
2
|
+
import { FileServerAdapter } from '.';
|
|
3
|
+
export declare type Config = {
|
|
4
|
+
storagePrefix: string;
|
|
5
|
+
};
|
|
6
|
+
interface Initializer<C> {
|
|
7
|
+
dataDir: string;
|
|
8
|
+
configSpace?: C;
|
|
9
|
+
}
|
|
10
|
+
export declare const localFileServer: <C extends string = "local">(initializer: Initializer<C>) => (configProvider: { [key in C]: {
|
|
11
|
+
storagePrefix: import("../../config").ConfigValueProvider<string>;
|
|
12
|
+
}; }) => FileServerAdapter;
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { resolveConfigValue } from '../../config';
|
|
4
|
+
import { ifDefined } from '../../guards';
|
|
5
|
+
export const localFileServer = (initializer) => (configProvider) => {
|
|
6
|
+
const config = configProvider[ifDefined(initializer.configSpace, 'local')];
|
|
7
|
+
const storagePrefix = resolveConfigValue(config.storagePrefix);
|
|
8
|
+
const fileDir = storagePrefix.then((prefix) => path.join(initializer.dataDir, prefix));
|
|
9
|
+
const getFileContent = async (source) => {
|
|
10
|
+
const filePath = path.join(await fileDir, source.path);
|
|
11
|
+
return fs.promises.readFile(filePath);
|
|
12
|
+
};
|
|
13
|
+
return {
|
|
14
|
+
getFileContent,
|
|
15
|
+
};
|
|
16
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { S3Client } from '@aws-sdk/client-s3';
|
|
2
|
+
import { ConfigProviderForConfig } from '../../config';
|
|
3
|
+
import { FileServerAdapter } from '.';
|
|
4
|
+
export declare type Config = {
|
|
5
|
+
bucketName: string;
|
|
6
|
+
bucketRegion: string;
|
|
7
|
+
};
|
|
8
|
+
interface Initializer<C> {
|
|
9
|
+
configSpace?: C;
|
|
10
|
+
s3Client?: typeof S3Client;
|
|
11
|
+
}
|
|
12
|
+
export declare const s3FileServer: <C extends string = "deployed">(initializer: Initializer<C>) => (configProvider: { [key in C]: {
|
|
13
|
+
bucketName: import("../../config").ConfigValueProvider<string>;
|
|
14
|
+
bucketRegion: import("../../config").ConfigValueProvider<string>;
|
|
15
|
+
}; }) => FileServerAdapter;
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { GetObjectCommand, S3Client } from '@aws-sdk/client-s3';
|
|
2
|
+
import { once } from '../..';
|
|
3
|
+
import { assertDefined } from '../../assertions';
|
|
4
|
+
import { resolveConfigValue } from '../../config';
|
|
5
|
+
import { ifDefined } from '../../guards';
|
|
6
|
+
export const s3FileServer = (initializer) => (configProvider) => {
|
|
7
|
+
const config = configProvider[ifDefined(initializer.configSpace, 'deployed')];
|
|
8
|
+
const bucketName = once(() => resolveConfigValue(config.bucketName));
|
|
9
|
+
const bucketRegion = once(() => resolveConfigValue(config.bucketRegion));
|
|
10
|
+
const client = ifDefined(initializer.s3Client, S3Client);
|
|
11
|
+
const s3Service = once(async () => new client({ apiVersion: '2012-08-10', region: await bucketRegion() }));
|
|
12
|
+
const getFileContent = async (source) => {
|
|
13
|
+
const bucket = await bucketName();
|
|
14
|
+
const command = new GetObjectCommand({ Bucket: bucket, Key: source.path });
|
|
15
|
+
const response = await (await s3Service()).send(command);
|
|
16
|
+
return Buffer.from(await assertDefined(response.Body, new Error('Invalid Response from s3')).transformToByteArray());
|
|
17
|
+
};
|
|
18
|
+
return {
|
|
19
|
+
getFileContent,
|
|
20
|
+
};
|
|
21
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { JWK } from 'node-jose';
|
|
2
|
+
import { ConfigProviderForConfig } from '../../config';
|
|
3
|
+
declare type Config = {
|
|
4
|
+
alg: string;
|
|
5
|
+
expiresIn: string;
|
|
6
|
+
iss: string;
|
|
7
|
+
privateKey: string;
|
|
8
|
+
};
|
|
9
|
+
interface Initializer<C> {
|
|
10
|
+
configSpace?: C;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Creates a class that can sign launch params
|
|
14
|
+
*/
|
|
15
|
+
export declare const createLaunchSigner: <C extends string = "launch">({ configSpace }: Initializer<C>) => (configProvider: { [key in C]: {
|
|
16
|
+
alg: import("../../config").ConfigValueProvider<string>;
|
|
17
|
+
expiresIn: import("../../config").ConfigValueProvider<string>;
|
|
18
|
+
iss: import("../../config").ConfigValueProvider<string>;
|
|
19
|
+
privateKey: import("../../config").ConfigValueProvider<string>;
|
|
20
|
+
}; }) => {
|
|
21
|
+
jwks: () => Promise<{
|
|
22
|
+
keys: JWK.RawKey[];
|
|
23
|
+
}>;
|
|
24
|
+
sign: (subject: string, maxExp?: number | null | undefined) => Promise<string>;
|
|
25
|
+
};
|
|
26
|
+
export declare type LaunchSigner = ReturnType<ReturnType<typeof createLaunchSigner>>;
|
|
27
|
+
export {};
|