@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,13 @@
|
|
|
1
|
+
import { AuthProvider } from '..';
|
|
2
|
+
import { AssertionFailed } from '../../../assertions';
|
|
3
|
+
import { ConfigProviderForConfig } from '../../../config';
|
|
4
|
+
declare type Config = {
|
|
5
|
+
application: string;
|
|
6
|
+
};
|
|
7
|
+
export declare const createUserRoleValidator: (auth: AuthProvider, config: ConfigProviderForConfig<Config>) => {
|
|
8
|
+
getUserRoles: () => Promise<string[]>;
|
|
9
|
+
userHasRole: (role: string[]) => Promise<boolean>;
|
|
10
|
+
assertUserRole: (role: string[], fail?: AssertionFailed) => Promise<void>;
|
|
11
|
+
};
|
|
12
|
+
export declare type UserRoleValidator = ReturnType<typeof createUserRoleValidator>;
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createUserRoleValidator = void 0;
|
|
4
|
+
const assertions_1 = require("../../../assertions");
|
|
5
|
+
const resolveConfigValue_1 = require("../../../config/resolveConfigValue");
|
|
6
|
+
const errors_1 = require("../../../errors");
|
|
7
|
+
const helpers_1 = require("../../../misc/helpers");
|
|
8
|
+
const createUserRoleValidator = (auth, config) => {
|
|
9
|
+
const application = (0, helpers_1.once)(() => (0, resolveConfigValue_1.resolveConfigValue)(config.application));
|
|
10
|
+
const getUserRoles = async () => {
|
|
11
|
+
var _a;
|
|
12
|
+
const user = await auth.getUser();
|
|
13
|
+
const appName = await application();
|
|
14
|
+
if (!user || !('applications' in user)) {
|
|
15
|
+
return [];
|
|
16
|
+
}
|
|
17
|
+
return ((_a = user.applications.find(a => a.name === appName)) === null || _a === void 0 ? void 0 : _a.roles) || [];
|
|
18
|
+
};
|
|
19
|
+
const userHasRole = async (role) => {
|
|
20
|
+
const roles = await getUserRoles();
|
|
21
|
+
if (!roles.some(r => role.includes(r))) {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
return true;
|
|
25
|
+
};
|
|
26
|
+
const assertUserRole = async (role, fail = new errors_1.UnauthorizedError()) => {
|
|
27
|
+
if (!await userHasRole(role)) {
|
|
28
|
+
return (0, assertions_1.doThrow)(fail);
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
return {
|
|
32
|
+
getUserRoles,
|
|
33
|
+
userHasRole,
|
|
34
|
+
assertUserRole
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
exports.createUserRoleValidator = createUserRoleValidator;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { AttributeValue } from '@aws-sdk/client-dynamodb';
|
|
2
|
+
import { DocumentBaseType, DocumentBaseValueTypes } from '.';
|
|
3
|
+
export declare const encodeDynamoAttribute: (value: DocumentBaseValueTypes) => AttributeValue;
|
|
4
|
+
export declare const encodeDynamoDocument: (base: DocumentBaseType) => {
|
|
5
|
+
[k: string]: AttributeValue;
|
|
6
|
+
};
|
|
7
|
+
export declare const decodeDynamoAttribute: (value: AttributeValue) => DocumentBaseValueTypes;
|
|
8
|
+
export declare const decodeDynamoDocument: <T extends DocumentBaseType>(document: {
|
|
9
|
+
[key: string]: AttributeValue;
|
|
10
|
+
}) => T;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.decodeDynamoDocument = exports.decodeDynamoAttribute = exports.encodeDynamoDocument = exports.encodeDynamoAttribute = void 0;
|
|
4
|
+
const guards_1 = require("../../guards");
|
|
5
|
+
const encodeDynamoAttribute = (value) => {
|
|
6
|
+
if (typeof value === 'string') {
|
|
7
|
+
return { S: value };
|
|
8
|
+
}
|
|
9
|
+
if (typeof value === 'number') {
|
|
10
|
+
return { N: value.toString() };
|
|
11
|
+
}
|
|
12
|
+
if (typeof value === 'boolean') {
|
|
13
|
+
return { BOOL: value };
|
|
14
|
+
}
|
|
15
|
+
if (value === null) {
|
|
16
|
+
return { NULL: true };
|
|
17
|
+
}
|
|
18
|
+
if (value instanceof Array) {
|
|
19
|
+
return { L: value.map(exports.encodeDynamoAttribute) };
|
|
20
|
+
}
|
|
21
|
+
if ((0, guards_1.isPlainObject)(value)) {
|
|
22
|
+
return { M: (0, exports.encodeDynamoDocument)(value) };
|
|
23
|
+
}
|
|
24
|
+
throw new Error(`unknown attribute type ${typeof value} with value ${value}.`);
|
|
25
|
+
};
|
|
26
|
+
exports.encodeDynamoAttribute = encodeDynamoAttribute;
|
|
27
|
+
const encodeDynamoDocument = (base) => Object.fromEntries(Object.entries(base).map(([key, value]) => ([key, (0, exports.encodeDynamoAttribute)(value)])));
|
|
28
|
+
exports.encodeDynamoDocument = encodeDynamoDocument;
|
|
29
|
+
const decodeDynamoAttribute = (value) => {
|
|
30
|
+
if (value.S !== undefined) {
|
|
31
|
+
return value.S;
|
|
32
|
+
}
|
|
33
|
+
if (value.N !== undefined) {
|
|
34
|
+
return parseFloat(value.N);
|
|
35
|
+
}
|
|
36
|
+
if (value.BOOL !== undefined) {
|
|
37
|
+
return value.BOOL;
|
|
38
|
+
}
|
|
39
|
+
if (value.NULL !== undefined) {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
if (value.L !== undefined) {
|
|
43
|
+
return value.L.map(exports.decodeDynamoAttribute);
|
|
44
|
+
}
|
|
45
|
+
if (value.M !== undefined) {
|
|
46
|
+
return (0, exports.decodeDynamoDocument)(value.M);
|
|
47
|
+
}
|
|
48
|
+
throw new Error(`unknown attribute type: ${JSON.stringify(value)}.`);
|
|
49
|
+
};
|
|
50
|
+
exports.decodeDynamoAttribute = decodeDynamoAttribute;
|
|
51
|
+
const decodeDynamoDocument = (document) => Object.fromEntries(Object.entries(document).map(([key, value]) => ([key, (0, exports.decodeDynamoAttribute)(value)])));
|
|
52
|
+
exports.decodeDynamoDocument = decodeDynamoDocument;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export declare type Config = {
|
|
2
|
+
tableName: string;
|
|
3
|
+
};
|
|
4
|
+
export declare type DocumentBaseMapType = {
|
|
5
|
+
[key: string]: DocumentBaseValueTypes;
|
|
6
|
+
};
|
|
7
|
+
export declare type DocumentBaseListType = DocumentBaseValueTypes[];
|
|
8
|
+
export declare type DocumentBaseValueTypes = number | boolean | string | null | DocumentBaseMapType | DocumentBaseListType;
|
|
9
|
+
export declare type DocumentBaseType = {
|
|
10
|
+
[key: string]: DocumentBaseValueTypes;
|
|
11
|
+
};
|
|
12
|
+
export declare type TDocument<T> = {
|
|
13
|
+
[k in keyof T]: DocumentBaseValueTypes;
|
|
14
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Config, TDocument } from '..';
|
|
2
|
+
import { ConfigProviderForConfig } from '../../../config';
|
|
3
|
+
interface Initializer<C> {
|
|
4
|
+
configSpace?: C;
|
|
5
|
+
}
|
|
6
|
+
export declare const dynamoUnversionedDocumentStore: <C extends string = "dynamodb">(initializer?: Initializer<C> | undefined) => <T extends TDocument<T>>() => (configProvider: { [key in C]: {
|
|
7
|
+
tableName: import("../../../config").ConfigValueProvider<string>;
|
|
8
|
+
}; }) => <K extends keyof T>(_: {}, hashKey: K) => {
|
|
9
|
+
loadAllDocumentsTheBadWay: () => Promise<T[]>;
|
|
10
|
+
batchGetItem: (ids: T[K][]) => Promise<T[]>;
|
|
11
|
+
getItem: (id: T[K]) => Promise<T | undefined>;
|
|
12
|
+
incrementItemAttribute: (id: T[K], attribute: keyof T) => Promise<number>;
|
|
13
|
+
patchItem: (item: Partial<T>) => Promise<T>;
|
|
14
|
+
putItem: (item: T) => Promise<T>;
|
|
15
|
+
};
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.dynamoUnversionedDocumentStore = void 0;
|
|
4
|
+
const client_dynamodb_1 = require("@aws-sdk/client-dynamodb");
|
|
5
|
+
const __1 = require("../../..");
|
|
6
|
+
const config_1 = require("../../../config");
|
|
7
|
+
const errors_1 = require("../../../errors");
|
|
8
|
+
const guards_1 = require("../../../guards");
|
|
9
|
+
const dynamoEncoding_1 = require("../dynamoEncoding");
|
|
10
|
+
const dynamodb = (0, __1.once)(() => new client_dynamodb_1.DynamoDB({ apiVersion: '2012-08-10' }));
|
|
11
|
+
const dynamoUnversionedDocumentStore = (initializer) => () => (configProvider) => (_, hashKey) => {
|
|
12
|
+
const options = (0, guards_1.ifDefined)(initializer, {});
|
|
13
|
+
const tableName = (0, __1.once)(() => (0, config_1.resolveConfigValue)(configProvider[(0, guards_1.ifDefined)(options.configSpace, 'dynamodb')].tableName));
|
|
14
|
+
return {
|
|
15
|
+
loadAllDocumentsTheBadWay: async () => {
|
|
16
|
+
const loadAllResults = async (ExclusiveStartKey) => {
|
|
17
|
+
var _a, _b;
|
|
18
|
+
const cmd = new client_dynamodb_1.ScanCommand({ TableName: await tableName(), ExclusiveStartKey });
|
|
19
|
+
const result = await dynamodb().send(cmd);
|
|
20
|
+
const resultItems = (_b = (_a = result.Items) === null || _a === void 0 ? void 0 : _a.map((item) => (0, dynamoEncoding_1.decodeDynamoDocument)(item))) !== null && _b !== void 0 ? _b : [];
|
|
21
|
+
if (result.LastEvaluatedKey) {
|
|
22
|
+
return [...resultItems, ...await loadAllResults(result.LastEvaluatedKey)];
|
|
23
|
+
}
|
|
24
|
+
return resultItems;
|
|
25
|
+
};
|
|
26
|
+
return loadAllResults();
|
|
27
|
+
},
|
|
28
|
+
batchGetItem: async (ids) => {
|
|
29
|
+
const table = await tableName();
|
|
30
|
+
const key = hashKey.toString();
|
|
31
|
+
const getBatches = async (requestItems) => {
|
|
32
|
+
const cmd = new client_dynamodb_1.BatchGetItemCommand({
|
|
33
|
+
RequestItems: requestItems !== null && requestItems !== void 0 ? requestItems : { [table]: { Keys: ids.map((id) => ({ [key]: (0, dynamoEncoding_1.encodeDynamoAttribute)(id) })) } },
|
|
34
|
+
});
|
|
35
|
+
const response = await dynamodb().send(cmd);
|
|
36
|
+
const currentResponses = response.Responses ?
|
|
37
|
+
response.Responses[table].map(response => (0, dynamoEncoding_1.decodeDynamoDocument)(response)) : [];
|
|
38
|
+
return currentResponses.concat(response.UnprocessedKeys ? await getBatches(response.UnprocessedKeys) : []);
|
|
39
|
+
};
|
|
40
|
+
return getBatches();
|
|
41
|
+
},
|
|
42
|
+
getItem: async (id) => {
|
|
43
|
+
const cmd = new client_dynamodb_1.GetItemCommand({
|
|
44
|
+
Key: { [hashKey.toString()]: (0, dynamoEncoding_1.encodeDynamoAttribute)(id) },
|
|
45
|
+
TableName: await tableName(),
|
|
46
|
+
});
|
|
47
|
+
return dynamodb().send(cmd).then(result => result.Item ? (0, dynamoEncoding_1.decodeDynamoDocument)(result.Item) : undefined);
|
|
48
|
+
},
|
|
49
|
+
/* atomically increments the given item attribute by 1 */
|
|
50
|
+
incrementItemAttribute: async (id, attribute) => {
|
|
51
|
+
const key = hashKey.toString();
|
|
52
|
+
const field = attribute.toString();
|
|
53
|
+
const cmd = new client_dynamodb_1.UpdateItemCommand({
|
|
54
|
+
Key: { [key]: (0, dynamoEncoding_1.encodeDynamoAttribute)(id) },
|
|
55
|
+
TableName: await tableName(),
|
|
56
|
+
UpdateExpression: 'ADD #f :one',
|
|
57
|
+
ConditionExpression: 'attribute_exists(#k)',
|
|
58
|
+
ExpressionAttributeNames: { '#k': hashKey.toString(), '#f': field },
|
|
59
|
+
ExpressionAttributeValues: { ':one': { N: '1' } },
|
|
60
|
+
ReturnValues: 'UPDATED_NEW',
|
|
61
|
+
});
|
|
62
|
+
return dynamodb().send(cmd).then((item) => {
|
|
63
|
+
var _a;
|
|
64
|
+
const result = (_a = item.Attributes) === null || _a === void 0 ? void 0 : _a[field]['N'];
|
|
65
|
+
if (!result) {
|
|
66
|
+
throw new errors_1.NotFoundError(`Item with ${key} "${id}" does not exist`);
|
|
67
|
+
}
|
|
68
|
+
return parseFloat(result);
|
|
69
|
+
}).catch((error) => {
|
|
70
|
+
throw error.name === 'ConditionalCheckFailedException' ?
|
|
71
|
+
new errors_1.NotFoundError(`Item with ${key} "${id}" does not exist`) : error;
|
|
72
|
+
});
|
|
73
|
+
},
|
|
74
|
+
/* replaces only specified attributes with the given data */
|
|
75
|
+
patchItem: async (item) => {
|
|
76
|
+
const id = item[hashKey];
|
|
77
|
+
const key = hashKey.toString();
|
|
78
|
+
if (!id) {
|
|
79
|
+
throw new Error(`Key attribute "${key}" is required for patchItem`);
|
|
80
|
+
}
|
|
81
|
+
const entries = Object.entries(item).filter(([field]) => field !== key);
|
|
82
|
+
if (entries.length === 0) {
|
|
83
|
+
throw new Error('No attributes to update');
|
|
84
|
+
}
|
|
85
|
+
const updates = [];
|
|
86
|
+
const expressionAttributeNames = { '#k': key };
|
|
87
|
+
const expressionAttributeValues = {};
|
|
88
|
+
entries.forEach(([field, value], index) => {
|
|
89
|
+
updates.push(`#f${index} = :f${index}`);
|
|
90
|
+
expressionAttributeNames[`#f${index}`] = field;
|
|
91
|
+
expressionAttributeValues[`:f${index}`] = (0, dynamoEncoding_1.encodeDynamoAttribute)(value);
|
|
92
|
+
});
|
|
93
|
+
const cmd = new client_dynamodb_1.UpdateItemCommand({
|
|
94
|
+
Key: { [key]: (0, dynamoEncoding_1.encodeDynamoAttribute)(id) },
|
|
95
|
+
TableName: await tableName(),
|
|
96
|
+
UpdateExpression: `SET ${updates.join(', ')}`,
|
|
97
|
+
ConditionExpression: 'attribute_exists(#k)',
|
|
98
|
+
ExpressionAttributeNames: expressionAttributeNames,
|
|
99
|
+
ExpressionAttributeValues: expressionAttributeValues,
|
|
100
|
+
ReturnValues: 'ALL_NEW',
|
|
101
|
+
});
|
|
102
|
+
return dynamodb().send(cmd).then((item) => {
|
|
103
|
+
if (!item.Attributes) {
|
|
104
|
+
throw new errors_1.NotFoundError(`Item with ${key} "${id}" does not exist`);
|
|
105
|
+
}
|
|
106
|
+
return (0, dynamoEncoding_1.decodeDynamoDocument)(item.Attributes);
|
|
107
|
+
}).catch((error) => {
|
|
108
|
+
throw error.name === 'ConditionalCheckFailedException' ?
|
|
109
|
+
new errors_1.NotFoundError(`Item with ${key} "${id}" does not exist`) : error;
|
|
110
|
+
});
|
|
111
|
+
},
|
|
112
|
+
/* replaces the entire document with the given data */
|
|
113
|
+
putItem: async (item) => {
|
|
114
|
+
const cmd = new client_dynamodb_1.PutItemCommand({
|
|
115
|
+
TableName: await tableName(),
|
|
116
|
+
Item: (0, dynamoEncoding_1.encodeDynamoDocument)(item),
|
|
117
|
+
});
|
|
118
|
+
return dynamodb().send(cmd).then(() => item);
|
|
119
|
+
},
|
|
120
|
+
};
|
|
121
|
+
};
|
|
122
|
+
exports.dynamoUnversionedDocumentStore = dynamoUnversionedDocumentStore;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Config, TDocument } from '..';
|
|
2
|
+
import { ConfigProviderForConfig } from '../../../config';
|
|
3
|
+
interface Initializer<C> {
|
|
4
|
+
dataDir: string;
|
|
5
|
+
fs?: Pick<typeof import('fs'), 'mkdir' | 'readdir' | 'readFile' | 'writeFile'>;
|
|
6
|
+
configSpace?: C;
|
|
7
|
+
}
|
|
8
|
+
export declare const fileSystemUnversionedDocumentStore: <C extends string = "fileSystem">(initializer: Initializer<C>) => <T extends TDocument<T>>() => (configProvider: { [key in C]: {
|
|
9
|
+
tableName: import("../../../config").ConfigValueProvider<string>;
|
|
10
|
+
}; }) => <K extends keyof T>(_: {}, hashKey: K) => {
|
|
11
|
+
loadAllDocumentsTheBadWay: () => Promise<T[]>;
|
|
12
|
+
batchGetItem: (ids: T[K][]) => Promise<Exclude<Awaited<T>, undefined>[]>;
|
|
13
|
+
getItem: (id: T[K]) => Promise<T | undefined>;
|
|
14
|
+
incrementItemAttribute: (id: T[K], attribute: keyof T) => Promise<number>;
|
|
15
|
+
patchItem: (item: Partial<T>) => Promise<T>;
|
|
16
|
+
putItem: (item: T) => Promise<T>;
|
|
17
|
+
};
|
|
18
|
+
export {};
|
|
@@ -0,0 +1,121 @@
|
|
|
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 __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
|
+
};
|
|
28
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
+
exports.fileSystemUnversionedDocumentStore = void 0;
|
|
30
|
+
const fsModule = __importStar(require("fs"));
|
|
31
|
+
const path_1 = __importDefault(require("path"));
|
|
32
|
+
const __1 = require("../../..");
|
|
33
|
+
const config_1 = require("../../../config");
|
|
34
|
+
const errors_1 = require("../../../errors");
|
|
35
|
+
const guards_1 = require("../../../guards");
|
|
36
|
+
const fileSystemUnversionedDocumentStore = (initializer) => () => (configProvider) => (_, hashKey) => {
|
|
37
|
+
const tableName = (0, config_1.resolveConfigValue)(configProvider[initializer.configSpace || 'fileSystem'].tableName);
|
|
38
|
+
const tablePath = tableName.then((table) => path_1.default.join(initializer.dataDir, table));
|
|
39
|
+
const { mkdir, readdir, readFile, writeFile } = (0, guards_1.ifDefined)(initializer.fs, fsModule);
|
|
40
|
+
const mkTableDir = new Promise((resolve, reject) => tablePath.then((path) => mkdir(path, { recursive: true }, (err) => err && err.code !== 'EEXIST' ? reject(err) : resolve())));
|
|
41
|
+
const hashFilename = (value) => `${(0, __1.hashValue)(value)}.json`;
|
|
42
|
+
const filePath = async (filename) => path_1.default.join(await tablePath, filename);
|
|
43
|
+
const load = async (filename) => {
|
|
44
|
+
const path = await filePath(filename);
|
|
45
|
+
await mkTableDir;
|
|
46
|
+
return new Promise((resolve, reject) => {
|
|
47
|
+
readFile(path, (err, readData) => {
|
|
48
|
+
if (err) {
|
|
49
|
+
err.code === 'ENOENT' ? resolve(undefined) : reject(err);
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
try {
|
|
53
|
+
const data = JSON.parse(readData.toString());
|
|
54
|
+
typeof data === 'object' ? resolve(data) : reject(new Error('unexpected non-object JSON'));
|
|
55
|
+
}
|
|
56
|
+
catch (err) {
|
|
57
|
+
reject(err);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
};
|
|
63
|
+
return {
|
|
64
|
+
loadAllDocumentsTheBadWay: async () => {
|
|
65
|
+
const path = await tablePath;
|
|
66
|
+
await mkTableDir;
|
|
67
|
+
return new Promise((resolve, reject) => readdir(path, (err, files) => err ?
|
|
68
|
+
reject(err) :
|
|
69
|
+
Promise.all(files.map((file) => load(file)))
|
|
70
|
+
.then((allData) => resolve(allData.filter(guards_1.isDefined)), (err) => reject(err))));
|
|
71
|
+
},
|
|
72
|
+
batchGetItem: async (ids) => {
|
|
73
|
+
const items = await Promise.all(ids.map((id) => load(hashFilename(id))));
|
|
74
|
+
return items.filter(guards_1.isDefined);
|
|
75
|
+
},
|
|
76
|
+
getItem: (id) => load(hashFilename(id)),
|
|
77
|
+
incrementItemAttribute: async (id, attribute) => {
|
|
78
|
+
const filename = hashFilename(id);
|
|
79
|
+
const path = await filePath(filename);
|
|
80
|
+
await mkTableDir;
|
|
81
|
+
const data = await load(filename);
|
|
82
|
+
if (!data) {
|
|
83
|
+
throw new errors_1.NotFoundError(`Item with ${hashKey.toString()} "${id}" does not exist`);
|
|
84
|
+
}
|
|
85
|
+
const newValue = typeof data[attribute] === 'number' ? data[attribute] + 1 : 1;
|
|
86
|
+
const newItem = { ...data, [hashKey]: id, [attribute]: newValue };
|
|
87
|
+
return new Promise((resolve, reject) => {
|
|
88
|
+
writeFile(path, JSON.stringify(newItem, null, 2), (err) => err ? reject(err) : resolve(newValue));
|
|
89
|
+
});
|
|
90
|
+
},
|
|
91
|
+
patchItem: async (item) => {
|
|
92
|
+
const id = item[hashKey];
|
|
93
|
+
if (!id) {
|
|
94
|
+
throw new Error(`Key attribute "${hashKey.toString()}" is required for patchItem`);
|
|
95
|
+
}
|
|
96
|
+
// This check is just to make this adapter consistent with the dynamo adapter
|
|
97
|
+
if (Object.keys(item).filter((key) => key !== hashKey.toString()).length === 0) {
|
|
98
|
+
throw new Error('No attributes to update');
|
|
99
|
+
}
|
|
100
|
+
const filename = hashFilename(id);
|
|
101
|
+
const path = await filePath(filename);
|
|
102
|
+
await mkTableDir;
|
|
103
|
+
const data = await load(filename);
|
|
104
|
+
if (!data) {
|
|
105
|
+
throw new errors_1.NotFoundError(`Item with ${hashKey.toString()} "${id}" does not exist`);
|
|
106
|
+
}
|
|
107
|
+
const newItem = { ...data, ...item };
|
|
108
|
+
return new Promise((resolve, reject) => {
|
|
109
|
+
writeFile(path, JSON.stringify(newItem, null, 2), (err) => err ? reject(err) : resolve(newItem));
|
|
110
|
+
});
|
|
111
|
+
},
|
|
112
|
+
putItem: async (item) => {
|
|
113
|
+
const path = await filePath(hashFilename(item[hashKey]));
|
|
114
|
+
await mkTableDir;
|
|
115
|
+
return new Promise((resolve, reject) => {
|
|
116
|
+
writeFile(path, JSON.stringify(item, null, 2), (err) => err ? reject(err) : resolve(item));
|
|
117
|
+
});
|
|
118
|
+
},
|
|
119
|
+
};
|
|
120
|
+
};
|
|
121
|
+
exports.fileSystemUnversionedDocumentStore = fileSystemUnversionedDocumentStore;
|
|
@@ -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,135 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.dynamoVersionedDocumentStore = void 0;
|
|
4
|
+
const client_dynamodb_1 = require("@aws-sdk/client-dynamodb");
|
|
5
|
+
const __1 = require("../../..");
|
|
6
|
+
const config_1 = require("../../../config");
|
|
7
|
+
const guards_1 = require("../../../guards");
|
|
8
|
+
const dynamoEncoding_1 = require("../dynamoEncoding");
|
|
9
|
+
const dynamodb = (0, __1.once)(() => new client_dynamodb_1.DynamoDB({ apiVersion: '2012-08-10' }));
|
|
10
|
+
// i'm not really excited about getAuthor being required, but ts is getting confused about the type when unspecified
|
|
11
|
+
const dynamoVersionedDocumentStore = (initializer) => () => (configProvider) => (_, hashKey, getAuthor) => {
|
|
12
|
+
const options = (0, guards_1.ifDefined)(initializer, {});
|
|
13
|
+
const tableName = (0, __1.once)(() => (0, config_1.resolveConfigValue)(configProvider[(0, guards_1.ifDefined)(options.configSpace, 'dynamodb')].tableName));
|
|
14
|
+
return {
|
|
15
|
+
loadAllDocumentsTheBadWay: async () => {
|
|
16
|
+
const loadAllResults = async (ExclusiveStartKey) => {
|
|
17
|
+
var _a;
|
|
18
|
+
const cmd = new client_dynamodb_1.ScanCommand({ TableName: await tableName(), ExclusiveStartKey });
|
|
19
|
+
const result = await dynamodb().send(cmd);
|
|
20
|
+
const resultItems = ((_a = result.Items) === null || _a === void 0 ? void 0 : _a.map(dynamoEncoding_1.decodeDynamoDocument)) || [];
|
|
21
|
+
if (result.LastEvaluatedKey) {
|
|
22
|
+
return [...resultItems, ...await loadAllResults(result.LastEvaluatedKey)];
|
|
23
|
+
}
|
|
24
|
+
return resultItems;
|
|
25
|
+
};
|
|
26
|
+
const allResults = await loadAllResults().then(results => results.reduce((result, document) => {
|
|
27
|
+
const current = result.get(document[hashKey]);
|
|
28
|
+
if (!current || current.timestamp < document.timestamp) {
|
|
29
|
+
return result.set(document[hashKey], document);
|
|
30
|
+
}
|
|
31
|
+
return result;
|
|
32
|
+
}, new Map()));
|
|
33
|
+
return Array.from(allResults.values());
|
|
34
|
+
},
|
|
35
|
+
getVersions: async (id, startVersion) => {
|
|
36
|
+
const cmd = new client_dynamodb_1.QueryCommand({
|
|
37
|
+
TableName: await tableName(),
|
|
38
|
+
KeyConditionExpression: '#hk = :hkv',
|
|
39
|
+
ExpressionAttributeValues: {
|
|
40
|
+
':hkv': (0, dynamoEncoding_1.encodeDynamoAttribute)(id)
|
|
41
|
+
},
|
|
42
|
+
ExpressionAttributeNames: {
|
|
43
|
+
'#hk': hashKey.toString()
|
|
44
|
+
},
|
|
45
|
+
...(startVersion
|
|
46
|
+
? { ExclusiveStartKey: {
|
|
47
|
+
[hashKey]: (0, dynamoEncoding_1.encodeDynamoAttribute)(id),
|
|
48
|
+
timestamp: { N: startVersion.toString() }
|
|
49
|
+
} }
|
|
50
|
+
: {}),
|
|
51
|
+
ScanIndexForward: false,
|
|
52
|
+
});
|
|
53
|
+
return dynamodb().send(cmd).then(result => {
|
|
54
|
+
var _a;
|
|
55
|
+
const items = (_a = result.Items) === null || _a === void 0 ? void 0 : _a.map(dynamoEncoding_1.decodeDynamoDocument);
|
|
56
|
+
if (!items || items.length === 0) {
|
|
57
|
+
return undefined;
|
|
58
|
+
}
|
|
59
|
+
return {
|
|
60
|
+
items,
|
|
61
|
+
nextPageToken: result.LastEvaluatedKey ? (0, dynamoEncoding_1.decodeDynamoDocument)(result.LastEvaluatedKey).timestamp : undefined
|
|
62
|
+
};
|
|
63
|
+
});
|
|
64
|
+
},
|
|
65
|
+
getItem: async (id, timestamp) => {
|
|
66
|
+
let keyConditionExpression = '#hk = :hkv';
|
|
67
|
+
const expressionAttributeNames = {
|
|
68
|
+
'#hk': hashKey.toString()
|
|
69
|
+
};
|
|
70
|
+
const expressionAttributeValues = {
|
|
71
|
+
':hkv': (0, dynamoEncoding_1.encodeDynamoAttribute)(id)
|
|
72
|
+
};
|
|
73
|
+
if (timestamp) {
|
|
74
|
+
keyConditionExpression += ' and #ts = :tsv';
|
|
75
|
+
expressionAttributeNames['#ts'] = 'timestamp';
|
|
76
|
+
expressionAttributeValues[':tsv'] = (0, dynamoEncoding_1.encodeDynamoAttribute)(timestamp);
|
|
77
|
+
}
|
|
78
|
+
const cmd = new client_dynamodb_1.QueryCommand({
|
|
79
|
+
TableName: await tableName(),
|
|
80
|
+
KeyConditionExpression: keyConditionExpression,
|
|
81
|
+
ExpressionAttributeNames: expressionAttributeNames,
|
|
82
|
+
ExpressionAttributeValues: expressionAttributeValues,
|
|
83
|
+
ScanIndexForward: false,
|
|
84
|
+
Limit: 1
|
|
85
|
+
});
|
|
86
|
+
return dynamodb().send(cmd).then(result => {
|
|
87
|
+
var _a;
|
|
88
|
+
return (_a = result.Items) === null || _a === void 0 ? void 0 : _a.map(dynamoEncoding_1.decodeDynamoDocument)[0];
|
|
89
|
+
});
|
|
90
|
+
},
|
|
91
|
+
/* prepares a new version of a document with the given data, then allows some additional
|
|
92
|
+
* changes to be input to a `save` function that actually saves it. useful for additional
|
|
93
|
+
* changes based on the new document version or author. the document version and author
|
|
94
|
+
* cannot be modified */
|
|
95
|
+
prepareItem: async (item, ...authorArgs) => {
|
|
96
|
+
// this getAuthor type is terrible
|
|
97
|
+
const author = getAuthor ? await getAuthor(...authorArgs) : authorArgs[0];
|
|
98
|
+
const timestamp = new Date().getTime();
|
|
99
|
+
return {
|
|
100
|
+
document: { ...item, timestamp, author },
|
|
101
|
+
save: async (changes) => {
|
|
102
|
+
const document = {
|
|
103
|
+
...item,
|
|
104
|
+
...changes,
|
|
105
|
+
timestamp,
|
|
106
|
+
author
|
|
107
|
+
};
|
|
108
|
+
const cmd = new client_dynamodb_1.PutItemCommand({
|
|
109
|
+
TableName: await tableName(),
|
|
110
|
+
Item: (0, dynamoEncoding_1.encodeDynamoDocument)(document),
|
|
111
|
+
});
|
|
112
|
+
return dynamodb().send(cmd)
|
|
113
|
+
.then(() => document);
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
},
|
|
117
|
+
/* saves a new version of a document with the given data */
|
|
118
|
+
putItem: async (item, ...authorArgs) => {
|
|
119
|
+
// this getAuthor type is terrible
|
|
120
|
+
const author = getAuthor ? await getAuthor(...authorArgs) : authorArgs[0];
|
|
121
|
+
const document = {
|
|
122
|
+
...item,
|
|
123
|
+
timestamp: new Date().getTime(),
|
|
124
|
+
author
|
|
125
|
+
};
|
|
126
|
+
const cmd = new client_dynamodb_1.PutItemCommand({
|
|
127
|
+
TableName: await tableName(),
|
|
128
|
+
Item: (0, dynamoEncoding_1.encodeDynamoDocument)(document),
|
|
129
|
+
});
|
|
130
|
+
return dynamodb().send(cmd)
|
|
131
|
+
.then(() => document);
|
|
132
|
+
},
|
|
133
|
+
};
|
|
134
|
+
};
|
|
135
|
+
exports.dynamoVersionedDocumentStore = dynamoVersionedDocumentStore;
|
|
@@ -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 {};
|