@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,51 @@
|
|
|
1
|
+
import jwt from 'jsonwebtoken';
|
|
2
|
+
import ms from 'ms';
|
|
3
|
+
import { JWK } from 'node-jose';
|
|
4
|
+
import { once } from '../..';
|
|
5
|
+
import { resolveConfigValue } from '../../config';
|
|
6
|
+
import { ifDefined } from '../../guards';
|
|
7
|
+
const SUPPORTED_ALGORITHMS = [
|
|
8
|
+
'RS256', 'RS384', 'RS512', 'ES256', 'ES384', 'ES512', 'HS256', 'HS384', 'HS512', 'PS256', 'PS384', 'PS512'
|
|
9
|
+
];
|
|
10
|
+
const assertAlg = (alg) => {
|
|
11
|
+
if ((SUPPORTED_ALGORITHMS).includes(alg)) {
|
|
12
|
+
return alg;
|
|
13
|
+
}
|
|
14
|
+
throw new Error(`"${alg}" is not a valid algorithm`);
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Creates a class that can sign launch params
|
|
18
|
+
*/
|
|
19
|
+
export const createLaunchSigner = ({ configSpace }) => (configProvider) => {
|
|
20
|
+
const config = configProvider[ifDefined(configSpace, 'launch')];
|
|
21
|
+
const getAlg = once(async () => assertAlg(await resolveConfigValue(config.alg)));
|
|
22
|
+
const getExpiresIn = once(() => resolveConfigValue(config.expiresIn));
|
|
23
|
+
const getIss = once(() => resolveConfigValue(config.iss));
|
|
24
|
+
const getPrivateKey = once(() => resolveConfigValue(config.privateKey));
|
|
25
|
+
const getKeyStore = once(async () => {
|
|
26
|
+
const keystore = JWK.createKeyStore();
|
|
27
|
+
await keystore.add(await getPrivateKey(), 'pem');
|
|
28
|
+
return keystore;
|
|
29
|
+
});
|
|
30
|
+
const jwks = async () => (await getKeyStore()).toJSON(false);
|
|
31
|
+
const getExpiresInWithMax = async (maxExp) => {
|
|
32
|
+
const expiresIn = await getExpiresIn();
|
|
33
|
+
// The ms library used by jsonwebtoken can handle a value in seconds as well as a string like '1d'
|
|
34
|
+
if (!maxExp) {
|
|
35
|
+
return expiresIn;
|
|
36
|
+
}
|
|
37
|
+
// Convert both values to seconds for comparison
|
|
38
|
+
const expiresInSeconds = Math.floor(ms(expiresIn) / 1000);
|
|
39
|
+
const maxExpSeconds = maxExp - Math.floor(Date.now() / 1000);
|
|
40
|
+
return Math.min(expiresInSeconds, maxExpSeconds);
|
|
41
|
+
};
|
|
42
|
+
const sign = async (subject, maxExp) => {
|
|
43
|
+
const alg = await getAlg();
|
|
44
|
+
// expiresIn can be a number of seconds or a string like '1h' or '1d'
|
|
45
|
+
const expiresIn = await getExpiresInWithMax(maxExp);
|
|
46
|
+
const iss = await getIss();
|
|
47
|
+
const header = { alg, iss };
|
|
48
|
+
return jwt.sign({}, await getPrivateKey(), { algorithm: alg, expiresIn, header, issuer: iss, subject });
|
|
49
|
+
};
|
|
50
|
+
return { jwks, sign };
|
|
51
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import jwt from 'jsonwebtoken';
|
|
2
|
+
import type { JWK } from 'node-jose';
|
|
3
|
+
import { ConfigProviderForConfig } from '../../config';
|
|
4
|
+
declare type Config = {
|
|
5
|
+
trustedDomain: string;
|
|
6
|
+
};
|
|
7
|
+
interface Initializer<C> {
|
|
8
|
+
configSpace?: C;
|
|
9
|
+
fetcher?: (uri: string) => Promise<{
|
|
10
|
+
keys: JWK.RawKey[];
|
|
11
|
+
}>;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Creates a class that can verify launch params
|
|
15
|
+
*/
|
|
16
|
+
export declare const createLaunchVerifier: <C extends string = "launch">({ configSpace, fetcher }: Initializer<C>) => (configProvider: { [key in C]: {
|
|
17
|
+
trustedDomain: import("../../config").ConfigValueProvider<string>;
|
|
18
|
+
}; }) => {
|
|
19
|
+
verify: <T = undefined>(...[token, validator]: T extends undefined ? [string] : [string, (input: any) => T]) => Promise<T extends undefined ? jwt.JwtPayload : T>;
|
|
20
|
+
};
|
|
21
|
+
export declare type LaunchVerifier = ReturnType<ReturnType<typeof createLaunchVerifier>>;
|
|
22
|
+
export {};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import jwt, { TokenExpiredError } from 'jsonwebtoken';
|
|
2
|
+
import { JwksClient } from 'jwks-rsa';
|
|
3
|
+
import { memoize } from '../..';
|
|
4
|
+
import { resolveConfigValue } from '../../config';
|
|
5
|
+
import { SessionExpiredError } from '../../errors';
|
|
6
|
+
import { ifDefined } from '../../guards';
|
|
7
|
+
/**
|
|
8
|
+
* Creates a class that can verify launch params
|
|
9
|
+
*/
|
|
10
|
+
export const createLaunchVerifier = ({ configSpace, fetcher }) => (configProvider) => {
|
|
11
|
+
const config = configProvider[ifDefined(configSpace, 'launch')];
|
|
12
|
+
const getJwksClient = memoize((jwksUri) => new JwksClient({ fetcher, jwksUri }));
|
|
13
|
+
const getJwksKey = memoize(async (jwksUri, kid) => {
|
|
14
|
+
const client = getJwksClient(jwksUri);
|
|
15
|
+
const key = await client.getSigningKey(kid);
|
|
16
|
+
return key.getPublicKey();
|
|
17
|
+
});
|
|
18
|
+
const getKey = async (header, callback) => {
|
|
19
|
+
// The JWT spec allows iss in the header as a copy of the iss claim, but we require it
|
|
20
|
+
if (!header.iss) {
|
|
21
|
+
return callback(new Error('JWT header missing iss claim'));
|
|
22
|
+
}
|
|
23
|
+
const { iss, kid } = header;
|
|
24
|
+
try {
|
|
25
|
+
const jwksUrl = new URL('/.well-known/jwks.json', iss);
|
|
26
|
+
const launchDomain = jwksUrl.hostname;
|
|
27
|
+
const trustedDomain = await resolveConfigValue(config.trustedDomain);
|
|
28
|
+
if (launchDomain !== trustedDomain && !launchDomain.endsWith(`.${trustedDomain}`)) {
|
|
29
|
+
return callback(new Error(`Untrusted launch domain: "${launchDomain}"`));
|
|
30
|
+
}
|
|
31
|
+
callback(null, await getJwksKey(jwksUrl.toString(), kid));
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
callback(error);
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
const verify = (...[token, validator]) => new Promise((resolve, reject) => jwt.verify(token, getKey, {}, (err, payload) => {
|
|
38
|
+
if (err && err instanceof TokenExpiredError) {
|
|
39
|
+
reject(new SessionExpiredError());
|
|
40
|
+
}
|
|
41
|
+
else if (err) {
|
|
42
|
+
reject(err);
|
|
43
|
+
}
|
|
44
|
+
else if (typeof payload !== 'object') {
|
|
45
|
+
reject(new Error('received JWT token with unexpected non-JSON payload'));
|
|
46
|
+
}
|
|
47
|
+
else if (!payload.sub) {
|
|
48
|
+
reject(new Error('JWT payload missing sub claim'));
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
// we are migrating away from json encoding all the parameters into the `sub` claim
|
|
52
|
+
// and into using separate claims for each parameter. in transition, we check if the sub
|
|
53
|
+
// is json and return it if it is. this is still a breaking change when using this
|
|
54
|
+
// utility because applications no longer need to independently json parse the result
|
|
55
|
+
// starting now.
|
|
56
|
+
const parsed = payload;
|
|
57
|
+
try {
|
|
58
|
+
const jsonSubContents = JSON.parse(payload.sub);
|
|
59
|
+
Object.assign(parsed, jsonSubContents);
|
|
60
|
+
}
|
|
61
|
+
catch (e) { } // eslint-disable-line no-empty
|
|
62
|
+
// conditional return types are annoying
|
|
63
|
+
resolve((validator ? validator(parsed) : parsed));
|
|
64
|
+
}
|
|
65
|
+
}));
|
|
66
|
+
return { verify };
|
|
67
|
+
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { JsonCompatibleStruct } from '../../routing';
|
|
2
|
+
/**
|
|
3
|
+
* The log level
|
|
4
|
+
*/
|
|
5
|
+
export declare enum Level {
|
|
6
|
+
Info = "info",
|
|
7
|
+
Warn = "warn",
|
|
8
|
+
Error = "error"
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* A function that logs an event at a certain level.
|
|
12
|
+
*
|
|
13
|
+
* @param level - log level
|
|
14
|
+
* @param event - event to log
|
|
15
|
+
*/
|
|
16
|
+
export declare type LogEvent = (level: Level, event: JsonCompatibleStruct) => void;
|
|
17
|
+
/**
|
|
18
|
+
* A logger that can be used to log events.
|
|
19
|
+
*
|
|
20
|
+
* @property setContext - sets a context object to be included in all future logged events
|
|
21
|
+
* @property logEvent - logs an arbitrary event at a certain level, without context
|
|
22
|
+
* @property log - logs a message and the context at a certain level
|
|
23
|
+
* @property createSubContext - creates a new logger that inherits the context of this logger
|
|
24
|
+
*/
|
|
25
|
+
export interface Logger {
|
|
26
|
+
setContext: (obj: JsonCompatibleStruct) => void;
|
|
27
|
+
logEvent: LogEvent;
|
|
28
|
+
log: (message: string, level?: Level) => void;
|
|
29
|
+
createSubContext: () => Logger;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Creates a logger that logs events using the given driver and context provider.
|
|
33
|
+
*
|
|
34
|
+
* @param driver the driver that logs events
|
|
35
|
+
* @param getParentContext a provider that returns the context to use for this logger
|
|
36
|
+
* (the context is returned when messages are logged with the logger)
|
|
37
|
+
* @returns a Logger
|
|
38
|
+
*/
|
|
39
|
+
export declare const createCoreLogger: (driver: LogEvent, getParentContext?: (() => JsonCompatibleStruct) | undefined) => Logger;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The log level
|
|
3
|
+
*/
|
|
4
|
+
export var Level;
|
|
5
|
+
(function (Level) {
|
|
6
|
+
Level["Info"] = "info";
|
|
7
|
+
Level["Warn"] = "warn";
|
|
8
|
+
Level["Error"] = "error";
|
|
9
|
+
})(Level || (Level = {}));
|
|
10
|
+
/**
|
|
11
|
+
* Creates a logger that logs events using the given driver and context provider.
|
|
12
|
+
*
|
|
13
|
+
* @param driver the driver that logs events
|
|
14
|
+
* @param getParentContext a provider that returns the context to use for this logger
|
|
15
|
+
* (the context is returned when messages are logged with the logger)
|
|
16
|
+
* @returns a Logger
|
|
17
|
+
*/
|
|
18
|
+
export const createCoreLogger = (driver, getParentContext) => {
|
|
19
|
+
const context = {};
|
|
20
|
+
const getContext = () => ({ ...getParentContext === null || getParentContext === void 0 ? void 0 : getParentContext(), ...context });
|
|
21
|
+
return {
|
|
22
|
+
logEvent: (level, event) => driver(level, { ...event, context: getContext() }),
|
|
23
|
+
log: (message, level = Level.Info) => driver(level, { message, context: getContext() }),
|
|
24
|
+
setContext: (obj) => { Object.assign(context, obj); },
|
|
25
|
+
createSubContext: () => createCoreLogger(driver, getContext),
|
|
26
|
+
};
|
|
27
|
+
};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { User } from '../authProvider';
|
|
2
|
+
import { EagerXapiStatement, UXapiStatement, XapiStatement } from '.';
|
|
3
|
+
export declare const addStatementDefaultFields: (statement: (Pick<XapiStatement, 'object' | 'verb' | 'context' | 'result'> & {
|
|
4
|
+
id?: string;
|
|
5
|
+
}) | UXapiStatement, user: User) => EagerXapiStatement;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import formatISO from 'date-fns/formatISO';
|
|
2
|
+
import { v4 as uuid } from 'uuid';
|
|
3
|
+
export const addStatementDefaultFields = (statement, user) => ({
|
|
4
|
+
id: uuid(),
|
|
5
|
+
actor: {
|
|
6
|
+
account: {
|
|
7
|
+
homePage: 'https://openstax.org',
|
|
8
|
+
name: user.uuid,
|
|
9
|
+
},
|
|
10
|
+
objectType: 'Agent',
|
|
11
|
+
},
|
|
12
|
+
timestamp: formatISO(new Date()),
|
|
13
|
+
...statement,
|
|
14
|
+
});
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { LrsGateway, UXapiStatement } from '.';
|
|
2
|
+
export declare type ActivityState = {
|
|
3
|
+
attempts: number;
|
|
4
|
+
completedAttempts: number;
|
|
5
|
+
currentAttempt?: UXapiStatement;
|
|
6
|
+
currentAttemptCompleted?: UXapiStatement;
|
|
7
|
+
currentAttemptStatements: UXapiStatement[];
|
|
8
|
+
mostRecentAttemptWithCompleted?: UXapiStatement;
|
|
9
|
+
mostRecentAttemptWithCompletedCompleted?: UXapiStatement;
|
|
10
|
+
};
|
|
11
|
+
export declare const matchAttempt: (statement: UXapiStatement) => boolean;
|
|
12
|
+
export declare const matchAttemptCompleted: (attempt: UXapiStatement) => (statement: UXapiStatement) => boolean;
|
|
13
|
+
export declare const resolveAttempts: (statements: UXapiStatement[], options?: {
|
|
14
|
+
activityIRI?: string | undefined;
|
|
15
|
+
parentActivityAttempt?: string | undefined;
|
|
16
|
+
} | undefined) => UXapiStatement[];
|
|
17
|
+
export declare const resolveCompletedForAttempt: (statements: UXapiStatement[], attempt: UXapiStatement, activityIRI?: string | undefined) => UXapiStatement | undefined;
|
|
18
|
+
export declare const oldestStatement: (statements: UXapiStatement[]) => UXapiStatement | undefined;
|
|
19
|
+
export declare const mostRecentStatement: (statements: UXapiStatement[]) => UXapiStatement | undefined;
|
|
20
|
+
export declare const resolveAttemptInfo: (statements: UXapiStatement[], options?: {
|
|
21
|
+
activityIRI?: string | undefined;
|
|
22
|
+
currentAttempt?: string | undefined;
|
|
23
|
+
parentActivityAttempt?: string | undefined;
|
|
24
|
+
currentPreference?: "latest" | "oldest" | undefined;
|
|
25
|
+
} | undefined) => ActivityState;
|
|
26
|
+
export declare const loadStatementsForActivityAndFirstChildren: (gateway: LrsGateway, activityIRI: string, options?: {
|
|
27
|
+
anyUser?: boolean | undefined;
|
|
28
|
+
attempt?: string | undefined;
|
|
29
|
+
ensureSync?: boolean | undefined;
|
|
30
|
+
user?: string | undefined;
|
|
31
|
+
} | undefined) => Promise<import(".").XapiStatement[]>;
|
|
32
|
+
export declare const loadActivityAttemptInfo: (gateway: LrsGateway, activityIRI: string, options?: {
|
|
33
|
+
currentAttempt?: string | undefined;
|
|
34
|
+
parentActivityAttempt?: string | undefined;
|
|
35
|
+
ensureSync?: boolean | undefined;
|
|
36
|
+
} | undefined) => Promise<ActivityState>;
|
|
37
|
+
export declare const createStatement: (verb: UXapiStatement['verb'], activity: {
|
|
38
|
+
iri: string;
|
|
39
|
+
type: string;
|
|
40
|
+
name: string;
|
|
41
|
+
extensions?: {
|
|
42
|
+
[key: string]: string;
|
|
43
|
+
} | undefined;
|
|
44
|
+
}, attempt: string, parentActivityIRI?: string | undefined) => Pick<UXapiStatement, 'object' | 'verb' | 'context'>;
|
|
45
|
+
export declare const createAttemptStatement: (activity: {
|
|
46
|
+
iri: string;
|
|
47
|
+
type: string;
|
|
48
|
+
name: string;
|
|
49
|
+
extensions?: {
|
|
50
|
+
[key: string]: string;
|
|
51
|
+
} | undefined;
|
|
52
|
+
}, parentActivity?: {
|
|
53
|
+
iri?: string | undefined;
|
|
54
|
+
attempt?: string | undefined;
|
|
55
|
+
} | undefined) => Pick<UXapiStatement, 'object' | 'verb' | 'context'>;
|
|
56
|
+
export declare const putAttemptStatement: (gateway: LrsGateway, activity: {
|
|
57
|
+
iri: string;
|
|
58
|
+
type: string;
|
|
59
|
+
name: string;
|
|
60
|
+
extensions?: {
|
|
61
|
+
[key: string]: string;
|
|
62
|
+
} | undefined;
|
|
63
|
+
}, parentActivity?: {
|
|
64
|
+
iri?: string | undefined;
|
|
65
|
+
attempt?: string | undefined;
|
|
66
|
+
} | undefined) => Promise<import(".").EagerXapiStatement>;
|
|
67
|
+
export declare const createAttemptActivityStatement: (attemptStatement: UXapiStatement, verb: UXapiStatement['verb'], result?: UXapiStatement['result']) => Pick<UXapiStatement, 'object' | 'verb' | 'context' | 'result'>;
|
|
68
|
+
export declare const putAttemptActivityStatement: (gateway: LrsGateway, attemptStatement: UXapiStatement, verb: UXapiStatement['verb'], result?: UXapiStatement['result']) => Promise<import(".").EagerXapiStatement>;
|
|
69
|
+
export declare const createCompletedStatement: (attemptStatement: UXapiStatement, result?: UXapiStatement['result']) => Pick<UXapiStatement, 'object' | 'verb' | 'context' | 'result'>;
|
|
70
|
+
export declare const putCompletedStatement: (gateway: LrsGateway, attemptStatement: UXapiStatement, result: UXapiStatement['result']) => Promise<import(".").EagerXapiStatement>;
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* the structure of xapi statements for handling multiple attempts of an activity
|
|
3
|
+
* including the option of a parent activity/attempt such that a new attempt
|
|
4
|
+
* of a parent activity inherently creates a new attempt scope for sub-activities
|
|
5
|
+
* is done by convention using certain context and verb pieces of a statement.
|
|
6
|
+
* this module provides helpers for creating and retrieving statements according
|
|
7
|
+
* to this convention.
|
|
8
|
+
*/
|
|
9
|
+
import formatISODuration from 'date-fns/formatISODuration';
|
|
10
|
+
import intervalToDuration from 'date-fns/intervalToDuration';
|
|
11
|
+
import isAfter from 'date-fns/isAfter';
|
|
12
|
+
import isBefore from 'date-fns/isBefore';
|
|
13
|
+
import parseISO from 'date-fns/parseISO';
|
|
14
|
+
var Verb;
|
|
15
|
+
(function (Verb) {
|
|
16
|
+
Verb["Attempted"] = "http://adlnet.gov/expapi/verbs/attempted";
|
|
17
|
+
Verb["Completed"] = "http://adlnet.gov/expapi/verbs/completed";
|
|
18
|
+
})(Verb || (Verb = {}));
|
|
19
|
+
export const matchAttempt = (statement) => statement.verb.id === Verb.Attempted;
|
|
20
|
+
export const matchAttemptCompleted = (attempt) => (statement) => {
|
|
21
|
+
var _a, _b;
|
|
22
|
+
return statement.verb.id === Verb.Completed
|
|
23
|
+
&& statement.context !== undefined
|
|
24
|
+
&& ((_a = statement.context.statement) === null || _a === void 0 ? void 0 : _a.id) === attempt.id
|
|
25
|
+
&& statement.context.registration === ((_b = attempt.context) === null || _b === void 0 ? void 0 : _b.registration);
|
|
26
|
+
};
|
|
27
|
+
export const resolveAttempts = (statements, options) => statements.filter(statement => {
|
|
28
|
+
var _a;
|
|
29
|
+
return matchAttempt(statement)
|
|
30
|
+
&& (!(options === null || options === void 0 ? void 0 : options.activityIRI) || statement.object.id === options.activityIRI)
|
|
31
|
+
&& (!(options === null || options === void 0 ? void 0 : options.parentActivityAttempt) || ((_a = statement.context) === null || _a === void 0 ? void 0 : _a.registration) === options.parentActivityAttempt);
|
|
32
|
+
});
|
|
33
|
+
export const resolveCompletedForAttempt = (statements, attempt, activityIRI) => statements.find(statement => matchAttemptCompleted(attempt)(statement)
|
|
34
|
+
&& (!activityIRI || statement.object.id === activityIRI));
|
|
35
|
+
export const oldestStatement = (statements) => statements.reduce((result, statement) => result && isBefore(parseISO('stored' in result && result.stored ? result.stored : result.timestamp), parseISO(statement.timestamp)) ? result : statement, statements[0]);
|
|
36
|
+
export const mostRecentStatement = (statements) => statements.reduce((result, statement) => result && isAfter(parseISO('stored' in result && result.stored ? result.stored : result.timestamp), parseISO(statement.timestamp)) ? result : statement, statements[0]);
|
|
37
|
+
export const resolveAttemptInfo = (statements, options) => {
|
|
38
|
+
// TODO optimize. i'm 100% that this could all be done in one iteration but i'm not messing around with that for now.
|
|
39
|
+
const attempts = resolveAttempts(statements, options);
|
|
40
|
+
/* attempts that have a completed statement */
|
|
41
|
+
const completedAttempts = attempts.filter(attempt => !!resolveCompletedForAttempt(statements, attempt, options === null || options === void 0 ? void 0 : options.activityIRI));
|
|
42
|
+
/* the last attempt sorted by timestamp */
|
|
43
|
+
const currentAttempt = (options === null || options === void 0 ? void 0 : options.currentAttempt)
|
|
44
|
+
? attempts.find(attempt => attempt.id === options.currentAttempt)
|
|
45
|
+
: (options === null || options === void 0 ? void 0 : options.currentPreference) === 'oldest'
|
|
46
|
+
? oldestStatement(attempts)
|
|
47
|
+
: mostRecentStatement(attempts);
|
|
48
|
+
/* all statements for the current attempt (doesn't include the attempt or completed statements) */
|
|
49
|
+
const currentAttemptStatements = currentAttempt ? statements.filter(statement => {
|
|
50
|
+
var _a;
|
|
51
|
+
return (!(options === null || options === void 0 ? void 0 : options.activityIRI) || statement.object.id === options.activityIRI)
|
|
52
|
+
&& ((_a = statement.context) === null || _a === void 0 ? void 0 : _a.registration) === currentAttempt.id;
|
|
53
|
+
}) : [];
|
|
54
|
+
const currentAttemptCompleted = currentAttempt && resolveCompletedForAttempt(statements, currentAttempt, options === null || options === void 0 ? void 0 : options.activityIRI);
|
|
55
|
+
const mostRecentAttemptWithCompleted = completedAttempts.reduce((current, attempt) => current && isAfter(parseISO(current.timestamp), parseISO(attempt.timestamp)) ? current : attempt, completedAttempts[0]);
|
|
56
|
+
const mostRecentAttemptWithCompletedCompleted = mostRecentAttemptWithCompleted
|
|
57
|
+
&& resolveCompletedForAttempt(statements, mostRecentAttemptWithCompleted, options === null || options === void 0 ? void 0 : options.activityIRI);
|
|
58
|
+
/*
|
|
59
|
+
* the structure allows for the possibility of multiple incomplete attempts.
|
|
60
|
+
* the implementation can choose at its discretion to ignore the currentAttempt
|
|
61
|
+
* and instead make a new one, for instance if the implementation desires
|
|
62
|
+
* an attempt timeout feature
|
|
63
|
+
*/
|
|
64
|
+
return {
|
|
65
|
+
attempts: attempts.length,
|
|
66
|
+
completedAttempts: completedAttempts.length,
|
|
67
|
+
currentAttempt,
|
|
68
|
+
currentAttemptCompleted: currentAttemptCompleted,
|
|
69
|
+
currentAttemptStatements,
|
|
70
|
+
mostRecentAttemptWithCompleted,
|
|
71
|
+
mostRecentAttemptWithCompletedCompleted,
|
|
72
|
+
};
|
|
73
|
+
};
|
|
74
|
+
/*
|
|
75
|
+
* loads all statements (for this actor) that have the given activityIRI as the object.id or the context.contextActivities.parent.id
|
|
76
|
+
*
|
|
77
|
+
* note: if you filter on attempt you're only gonna get the `Attempted` statements from the child activities, subsequent child activity
|
|
78
|
+
* statements would then have to be fetched using
|
|
79
|
+
* `gateway.getAllXapiStatements({ activity: childActivityIRI, registration: childAttemptStatementID })`.
|
|
80
|
+
* this is because child activities could have multiple attempts under one attempt on the parent activity.
|
|
81
|
+
*/
|
|
82
|
+
export const loadStatementsForActivityAndFirstChildren = (gateway, activityIRI, options) => {
|
|
83
|
+
const { attempt, ...partialOptions } = options ? options : { attempt: undefined };
|
|
84
|
+
const getOptions = attempt ? { registration: attempt, ...partialOptions } : partialOptions;
|
|
85
|
+
return gateway.getAllXapiStatements({
|
|
86
|
+
activity: activityIRI,
|
|
87
|
+
related_activities: true,
|
|
88
|
+
...getOptions,
|
|
89
|
+
});
|
|
90
|
+
};
|
|
91
|
+
export const loadActivityAttemptInfo = async (gateway, activityIRI, options) => {
|
|
92
|
+
const { parentActivityAttempt, ...partialOptions } = options ? options : { parentActivityAttempt: undefined };
|
|
93
|
+
const loadOptions = parentActivityAttempt ? { ...partialOptions, registration: parentActivityAttempt } : partialOptions;
|
|
94
|
+
return resolveAttemptInfo(await gateway.getAllXapiStatements({ ...loadOptions, activity: activityIRI }), { ...options, activityIRI });
|
|
95
|
+
};
|
|
96
|
+
export const createStatement = (verb, activity, attempt, parentActivityIRI) => {
|
|
97
|
+
return {
|
|
98
|
+
context: {
|
|
99
|
+
...(parentActivityIRI ? {
|
|
100
|
+
contextActivities: {
|
|
101
|
+
parent: [
|
|
102
|
+
{
|
|
103
|
+
id: parentActivityIRI,
|
|
104
|
+
objectType: 'Activity',
|
|
105
|
+
},
|
|
106
|
+
],
|
|
107
|
+
},
|
|
108
|
+
} : {}),
|
|
109
|
+
registration: attempt,
|
|
110
|
+
},
|
|
111
|
+
object: {
|
|
112
|
+
definition: {
|
|
113
|
+
extensions: {
|
|
114
|
+
...activity.extensions
|
|
115
|
+
},
|
|
116
|
+
name: {
|
|
117
|
+
'en-US': activity.name,
|
|
118
|
+
},
|
|
119
|
+
type: activity.type,
|
|
120
|
+
},
|
|
121
|
+
id: activity.iri,
|
|
122
|
+
objectType: 'Activity'
|
|
123
|
+
},
|
|
124
|
+
verb,
|
|
125
|
+
};
|
|
126
|
+
};
|
|
127
|
+
/*
|
|
128
|
+
* activity:
|
|
129
|
+
* - iri: the IRI formatted id for this activity
|
|
130
|
+
* - type: the IRI formatted activity type (eg: http://id.tincanapi.com/activitytype/school-assignment)
|
|
131
|
+
* - name: the plaintext name of the activity, for reporting
|
|
132
|
+
*
|
|
133
|
+
* parentActivity:
|
|
134
|
+
* - iri: the IRI formatted id for the parent activity
|
|
135
|
+
* - attempt: the statement id for the parent attempt (the object of which should be the parentActivity.iri)
|
|
136
|
+
*/
|
|
137
|
+
export const createAttemptStatement = (activity, parentActivity) => {
|
|
138
|
+
return {
|
|
139
|
+
...((parentActivity === null || parentActivity === void 0 ? void 0 : parentActivity.iri) || (parentActivity === null || parentActivity === void 0 ? void 0 : parentActivity.attempt) ? {
|
|
140
|
+
context: {
|
|
141
|
+
...(parentActivity.iri ? {
|
|
142
|
+
contextActivities: {
|
|
143
|
+
parent: [
|
|
144
|
+
{
|
|
145
|
+
id: parentActivity.iri,
|
|
146
|
+
objectType: 'Activity',
|
|
147
|
+
},
|
|
148
|
+
],
|
|
149
|
+
},
|
|
150
|
+
} : {}),
|
|
151
|
+
...(parentActivity.attempt ? {
|
|
152
|
+
registration: parentActivity.attempt,
|
|
153
|
+
} : {})
|
|
154
|
+
},
|
|
155
|
+
} : {}),
|
|
156
|
+
object: {
|
|
157
|
+
definition: {
|
|
158
|
+
extensions: {
|
|
159
|
+
...activity.extensions
|
|
160
|
+
},
|
|
161
|
+
name: {
|
|
162
|
+
'en-US': activity.name,
|
|
163
|
+
},
|
|
164
|
+
type: activity.type,
|
|
165
|
+
},
|
|
166
|
+
id: activity.iri,
|
|
167
|
+
objectType: 'Activity'
|
|
168
|
+
},
|
|
169
|
+
verb: {
|
|
170
|
+
display: { 'en-US': 'Attempted' },
|
|
171
|
+
id: Verb.Attempted,
|
|
172
|
+
},
|
|
173
|
+
};
|
|
174
|
+
};
|
|
175
|
+
/* resolves with the statement id */
|
|
176
|
+
export const putAttemptStatement = async (gateway, activity, parentActivity) => {
|
|
177
|
+
return (await gateway.putXapiStatements([createAttemptStatement(activity, parentActivity)]))[0];
|
|
178
|
+
};
|
|
179
|
+
/*
|
|
180
|
+
* creates a statement under the given attempt.
|
|
181
|
+
*
|
|
182
|
+
* `result` optional context for the attempt result (score, selected answer, etc)
|
|
183
|
+
*/
|
|
184
|
+
export const createAttemptActivityStatement = (attemptStatement, verb, result) => {
|
|
185
|
+
var _a;
|
|
186
|
+
return {
|
|
187
|
+
context: {
|
|
188
|
+
...(((_a = attemptStatement.context) === null || _a === void 0 ? void 0 : _a.contextActivities) ? {
|
|
189
|
+
contextActivities: attemptStatement.context.contextActivities,
|
|
190
|
+
} : {}),
|
|
191
|
+
registration: attemptStatement.id,
|
|
192
|
+
},
|
|
193
|
+
object: attemptStatement.object,
|
|
194
|
+
verb: verb,
|
|
195
|
+
...(result ? { result } : {}),
|
|
196
|
+
};
|
|
197
|
+
};
|
|
198
|
+
export const putAttemptActivityStatement = async (gateway, attemptStatement, verb, result) => {
|
|
199
|
+
return (await gateway.putXapiStatements([createAttemptActivityStatement(attemptStatement, verb, result)]))[0];
|
|
200
|
+
};
|
|
201
|
+
/*
|
|
202
|
+
* creates a statement that completes the given attempt.
|
|
203
|
+
*
|
|
204
|
+
* `result` optional context for the attempt result (score, selected answer, etc)
|
|
205
|
+
*/
|
|
206
|
+
export const createCompletedStatement = (attemptStatement, result) => {
|
|
207
|
+
var _a, _b;
|
|
208
|
+
return {
|
|
209
|
+
context: {
|
|
210
|
+
...(((_a = attemptStatement.context) === null || _a === void 0 ? void 0 : _a.contextActivities) ? {
|
|
211
|
+
contextActivities: attemptStatement.context.contextActivities,
|
|
212
|
+
} : {}),
|
|
213
|
+
...(((_b = attemptStatement.context) === null || _b === void 0 ? void 0 : _b.registration) ? {
|
|
214
|
+
registration: attemptStatement.context.registration,
|
|
215
|
+
} : {}),
|
|
216
|
+
statement: {
|
|
217
|
+
objectType: 'StatementRef',
|
|
218
|
+
id: attemptStatement.id,
|
|
219
|
+
}
|
|
220
|
+
},
|
|
221
|
+
object: attemptStatement.object,
|
|
222
|
+
verb: {
|
|
223
|
+
display: { 'en-US': 'Completed' },
|
|
224
|
+
id: Verb.Completed,
|
|
225
|
+
},
|
|
226
|
+
result: {
|
|
227
|
+
duration: formatISODuration(intervalToDuration({
|
|
228
|
+
start: parseISO(attemptStatement.timestamp), end: new Date()
|
|
229
|
+
})),
|
|
230
|
+
...result,
|
|
231
|
+
}
|
|
232
|
+
};
|
|
233
|
+
};
|
|
234
|
+
export const putCompletedStatement = async (gateway, attemptStatement, result) => {
|
|
235
|
+
return (await gateway.putXapiStatements([createCompletedStatement(attemptStatement, result)]))[0];
|
|
236
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { ConfigProviderForConfig } from '../../config';
|
|
2
|
+
import { AuthProvider } from '../authProvider';
|
|
3
|
+
import { LrsGateway } from '.';
|
|
4
|
+
declare type Config = {
|
|
5
|
+
name: string;
|
|
6
|
+
};
|
|
7
|
+
interface Initializer<C> {
|
|
8
|
+
dataDir: string;
|
|
9
|
+
fs?: Pick<typeof import('fs'), 'readFile' | 'writeFile'>;
|
|
10
|
+
configSpace?: C;
|
|
11
|
+
}
|
|
12
|
+
export declare const fileSystemLrsGateway: <C extends string = "fileSystem">(initializer: Initializer<C>) => (configProvider: { [key in C]: {
|
|
13
|
+
name: import("../../config").ConfigValueProvider<string>;
|
|
14
|
+
}; }) => ({ authProvider }: {
|
|
15
|
+
authProvider: AuthProvider;
|
|
16
|
+
}) => LrsGateway;
|
|
17
|
+
export {};
|