@openstax/ts-utils 1.2.9 → 1.3.1
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.d.ts +75 -0
- package/dist/cjs/assertions.js +74 -29
- package/dist/cjs/aws/ssmService.d.ts +3 -0
- package/dist/cjs/aws/ssmService.js +3 -0
- package/dist/cjs/config/awsParameterConfig.d.ts +8 -0
- package/dist/cjs/config/awsParameterConfig.js +8 -0
- package/dist/cjs/config/envConfig.d.ts +21 -0
- package/dist/cjs/config/envConfig.js +20 -14
- package/dist/cjs/config/index.d.ts +28 -0
- package/dist/cjs/config/index.js +3 -6
- package/dist/cjs/config/lambdaParameterConfig.d.ts +10 -0
- package/dist/cjs/config/lambdaParameterConfig.js +10 -2
- package/dist/cjs/config/replaceConfig.d.ts +10 -0
- package/dist/cjs/config/replaceConfig.js +10 -0
- package/dist/cjs/config/resolveConfigValue.d.ts +3 -0
- package/dist/cjs/config/resolveConfigValue.js +2 -2
- package/dist/cjs/errors.d.ts +27 -0
- package/dist/cjs/errors.js +29 -2
- package/dist/cjs/guards.d.ts +24 -0
- package/dist/cjs/guards.js +18 -19
- package/dist/cjs/middleware/apiErrorHandler.d.ts +8 -0
- package/dist/cjs/middleware/apiErrorHandler.js +8 -0
- package/dist/cjs/middleware/apiSlowResponseMiddleware.d.ts +12 -0
- package/dist/cjs/middleware/apiSlowResponseMiddleware.js +12 -0
- package/dist/cjs/middleware/lambdaCorsResponseMiddleware.d.ts +11 -1
- package/dist/cjs/middleware/lambdaCorsResponseMiddleware.js +11 -1
- package/dist/cjs/middleware/throwNotFoundMiddleware.d.ts +3 -0
- package/dist/cjs/middleware/throwNotFoundMiddleware.js +3 -0
- package/dist/cjs/middleware.d.ts +38 -0
- package/dist/cjs/middleware.js +26 -16
- package/dist/cjs/misc/hashValue.d.ts +5 -0
- package/dist/cjs/misc/hashValue.js +3 -4
- package/dist/cjs/misc/helpers.d.ts +94 -0
- package/dist/cjs/misc/helpers.js +52 -14
- package/dist/cjs/misc/merge.d.ts +18 -0
- package/dist/cjs/misc/merge.js +10 -3
- package/dist/cjs/misc/partitionSequence.d.ts +31 -0
- package/dist/cjs/misc/partitionSequence.js +1 -1
- package/dist/cjs/pagination.d.ts +28 -0
- package/dist/cjs/pagination.js +1 -1
- package/dist/cjs/routing/helpers.d.ts +45 -0
- package/dist/cjs/routing/helpers.js +40 -22
- package/dist/cjs/routing/index.d.ts +169 -0
- package/dist/cjs/routing/index.js +127 -45
- package/dist/cjs/services/apiGateway/index.d.ts +1 -0
- package/dist/cjs/services/apiGateway/index.js +2 -0
- package/dist/cjs/services/authProvider/index.d.ts +2 -1
- package/dist/cjs/services/authProvider/utils/decryptAndVerify.d.ts +9 -0
- package/dist/cjs/services/authProvider/utils/decryptAndVerify.js +9 -0
- package/dist/cjs/services/logger/console.d.ts +3 -0
- package/dist/cjs/services/logger/console.js +3 -0
- package/dist/cjs/services/logger/index.d.ts +25 -0
- package/dist/cjs/services/logger/index.js +11 -0
- package/dist/cjs/services/lrsGateway/attempt-utils.d.ts +7 -10
- package/dist/cjs/services/lrsGateway/attempt-utils.js +19 -40
- package/dist/cjs/services/lrsGateway/file-system.js +17 -3
- package/dist/cjs/services/lrsGateway/index.d.ts +7 -1
- package/dist/cjs/services/lrsGateway/index.js +2 -2
- package/dist/cjs/tsconfig.without-specs.cjs.tsbuildinfo +1 -1
- package/dist/cjs/types.d.ts +21 -0
- package/dist/esm/assertions.d.ts +75 -0
- package/dist/esm/assertions.js +74 -29
- package/dist/esm/aws/ssmService.d.ts +3 -0
- package/dist/esm/aws/ssmService.js +3 -0
- package/dist/esm/config/awsParameterConfig.d.ts +8 -0
- package/dist/esm/config/awsParameterConfig.js +8 -0
- package/dist/esm/config/envConfig.d.ts +21 -0
- package/dist/esm/config/envConfig.js +20 -14
- package/dist/esm/config/index.d.ts +28 -0
- package/dist/esm/config/index.js +3 -6
- package/dist/esm/config/lambdaParameterConfig.d.ts +10 -0
- package/dist/esm/config/lambdaParameterConfig.js +10 -2
- package/dist/esm/config/replaceConfig.d.ts +10 -0
- package/dist/esm/config/replaceConfig.js +10 -0
- package/dist/esm/config/resolveConfigValue.d.ts +3 -0
- package/dist/esm/config/resolveConfigValue.js +2 -2
- package/dist/esm/errors.d.ts +27 -0
- package/dist/esm/errors.js +27 -0
- package/dist/esm/guards.d.ts +24 -0
- package/dist/esm/guards.js +18 -19
- package/dist/esm/middleware/apiErrorHandler.d.ts +8 -0
- package/dist/esm/middleware/apiErrorHandler.js +8 -0
- package/dist/esm/middleware/apiSlowResponseMiddleware.d.ts +12 -0
- package/dist/esm/middleware/apiSlowResponseMiddleware.js +12 -0
- package/dist/esm/middleware/lambdaCorsResponseMiddleware.d.ts +11 -1
- package/dist/esm/middleware/lambdaCorsResponseMiddleware.js +11 -1
- package/dist/esm/middleware/throwNotFoundMiddleware.d.ts +3 -0
- package/dist/esm/middleware/throwNotFoundMiddleware.js +3 -0
- package/dist/esm/middleware.d.ts +38 -0
- package/dist/esm/middleware.js +26 -16
- package/dist/esm/misc/hashValue.d.ts +5 -0
- package/dist/esm/misc/hashValue.js +3 -4
- package/dist/esm/misc/helpers.d.ts +94 -0
- package/dist/esm/misc/helpers.js +48 -10
- package/dist/esm/misc/merge.d.ts +18 -0
- package/dist/esm/misc/merge.js +10 -3
- package/dist/esm/misc/partitionSequence.d.ts +31 -0
- package/dist/esm/misc/partitionSequence.js +1 -1
- package/dist/esm/pagination.d.ts +28 -0
- package/dist/esm/pagination.js +1 -1
- package/dist/esm/routing/helpers.d.ts +45 -0
- package/dist/esm/routing/helpers.js +40 -22
- package/dist/esm/routing/index.d.ts +169 -0
- package/dist/esm/routing/index.js +127 -45
- package/dist/esm/services/apiGateway/index.d.ts +1 -0
- package/dist/esm/services/apiGateway/index.js +2 -0
- package/dist/esm/services/authProvider/index.d.ts +2 -1
- package/dist/esm/services/authProvider/utils/decryptAndVerify.d.ts +9 -0
- package/dist/esm/services/authProvider/utils/decryptAndVerify.js +9 -0
- package/dist/esm/services/logger/console.d.ts +3 -0
- package/dist/esm/services/logger/console.js +3 -0
- package/dist/esm/services/logger/index.d.ts +25 -0
- package/dist/esm/services/logger/index.js +11 -0
- package/dist/esm/services/lrsGateway/attempt-utils.d.ts +7 -10
- package/dist/esm/services/lrsGateway/attempt-utils.js +16 -35
- package/dist/esm/services/lrsGateway/file-system.js +17 -3
- package/dist/esm/services/lrsGateway/index.d.ts +7 -1
- package/dist/esm/services/lrsGateway/index.js +2 -2
- package/dist/esm/tsconfig.without-specs.esm.tsbuildinfo +1 -1
- package/dist/esm/types.d.ts +21 -0
- package/package.json +1 -1
- package/script/bin/copy-from-template.bash +1 -1
- package/script/.build-dist.swo +0 -0
- package/script/.build-dist.swp +0 -0
|
@@ -3,46 +3,63 @@ import queryString from 'query-string';
|
|
|
3
3
|
import { mapFind, memoize } from '../misc/helpers';
|
|
4
4
|
import { createProfile } from '../profile';
|
|
5
5
|
import { createConsoleLogger } from '../services/logger/console';
|
|
6
|
-
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* the
|
|
6
|
+
/**
|
|
7
|
+
* Makes a createRoute function that can be used to create routes (this is a factory factory). The
|
|
8
|
+
* `makeCreateRoute` function is typically called once in the backend and once in the frontend to
|
|
9
|
+
* set the types for the resulting `createRoute` function -- that latter function is called once
|
|
10
|
+
* per route. E.g. for the backend, the call could look like:
|
|
10
11
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
12
|
+
* ```
|
|
13
|
+
* export const createRoute = makeCreateRoute<AppServices, ApiRouteRequest, {
|
|
14
|
+
* method: METHOD;
|
|
15
|
+
* }>();
|
|
16
|
+
* ```
|
|
15
17
|
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
18
|
+
* Notes:
|
|
19
|
+
* * The `{method: METHOD}` defines the `Ex` extension type; here, the `method` property is only
|
|
20
|
+
* relevant to backend routes.
|
|
21
|
+
* * when defining the `createRoute` method, only the request input format is defined, the output
|
|
22
|
+
* format is derived from the routes.
|
|
23
|
+
*
|
|
24
|
+
* When calling the resulting `createRoute` function, the only required params of the route are the
|
|
25
|
+
* name, path, and handler. Other params can be added to the type and then later used in the
|
|
26
|
+
* routeMatcher.
|
|
24
27
|
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
+
* eg when defining requestServiceProvider in line, the types have a hard time, it helps to put in another argument:
|
|
29
|
+
* ```
|
|
30
|
+
* export const exampleRoute = createRoute({
|
|
31
|
+
* name: 'exampleRoute', method: METHOD.GET, path: '/api/example/:key',
|
|
32
|
+
* requestServiceProvider: composeServiceMiddleware({
|
|
33
|
+
* cookieAuthMiddleware,
|
|
34
|
+
* documentStoreMiddleware,
|
|
35
|
+
* }},
|
|
36
|
+
* async(params: {key: string}, services) => {
|
|
37
|
+
* const result = await services.myDocumentStore.getItem(params.key);
|
|
28
38
|
*
|
|
29
|
-
*
|
|
39
|
+
* if (!result) {
|
|
40
|
+
* throw new NotFoundError('requested item not found');
|
|
30
41
|
* }
|
|
31
|
-
* );
|
|
32
42
|
*
|
|
43
|
+
* return apiJsonResponse(200, result);
|
|
44
|
+
* }
|
|
45
|
+
* );
|
|
46
|
+
* ```
|
|
33
47
|
* eg when using a pre-existing provider variable the types work better:
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
* throw new NotFoundError('requested item not found');
|
|
41
|
-
* }
|
|
48
|
+
* ```
|
|
49
|
+
* export const exampleRoute = createRoute({
|
|
50
|
+
* name: 'exampleRoute', method: METHOD.GET, path: '/api/example/:key',
|
|
51
|
+
* requestServiceProvider,
|
|
52
|
+
* handler: async(params: {key: string}, services) => {
|
|
53
|
+
* const result = await services.myDocumentStore.getItem(params.key);
|
|
42
54
|
*
|
|
43
|
-
*
|
|
55
|
+
* if (!result) {
|
|
56
|
+
* throw new NotFoundError('requested item not found');
|
|
44
57
|
* }
|
|
45
|
-
*
|
|
58
|
+
*
|
|
59
|
+
* return apiJsonResponse(200, result);
|
|
60
|
+
* }
|
|
61
|
+
* });
|
|
62
|
+
* ```
|
|
46
63
|
*/
|
|
47
64
|
export const makeCreateRoute = () => (...args) => {
|
|
48
65
|
return (args.length === 1
|
|
@@ -50,12 +67,37 @@ export const makeCreateRoute = () => (...args) => {
|
|
|
50
67
|
: { ...args[0], handler: args[1] });
|
|
51
68
|
};
|
|
52
69
|
/* begin reverse routing utils */
|
|
70
|
+
/**
|
|
71
|
+
* Makes a renderRouteUrl function that can be used to render route paths (this is a factory
|
|
72
|
+
* factory). The returned function takes a `route`, `params`, and `query` and returns a string
|
|
73
|
+
* with the params and query substituted into the route path.
|
|
74
|
+
*
|
|
75
|
+
* this function is initialized using the Ru type which indicates the specific routes wired into
|
|
76
|
+
* the application, which means that if you try to build a url with a route which is not wired
|
|
77
|
+
* into the router you will get a type error. this is a feature to prevent referencing routes that
|
|
78
|
+
* don't exist or aren't handling requests properly.
|
|
79
|
+
*
|
|
80
|
+
* if you are making a helper function or need to render a route outside your application, you
|
|
81
|
+
* can use the `renderAnyRouteUrl` function
|
|
82
|
+
*/
|
|
53
83
|
export const makeRenderRouteUrl = () => (route, params, query = {}) => {
|
|
54
84
|
const getPathForParams = pathToRegexp.compile(route.path, { encode: encodeURIComponent });
|
|
55
85
|
const search = queryString.stringify(query);
|
|
56
86
|
const path = getPathForParams(params) + (search ? `?${search}` : '');
|
|
57
87
|
return path;
|
|
58
88
|
};
|
|
89
|
+
/**
|
|
90
|
+
* A pre-made result from `makeRenderRouteUrl`, this function interpolates parameter and query
|
|
91
|
+
* arguments into a route path.
|
|
92
|
+
*
|
|
93
|
+
* prefer using `renderRouteUrl` initialized with your applications route union
|
|
94
|
+
* when possible to help catch improperly initialized routes.
|
|
95
|
+
*
|
|
96
|
+
* @param route the route that has a `path` to be interpolated
|
|
97
|
+
* @param params the parameters to interpolate into the route path
|
|
98
|
+
* @param query the query parameters to add to the route path
|
|
99
|
+
* @returns the interpolated route path
|
|
100
|
+
*/
|
|
59
101
|
export const renderAnyRouteUrl = makeRenderRouteUrl();
|
|
60
102
|
const bindRoute = (services, appBinder, pathExtractor, matcher) => (route) => {
|
|
61
103
|
const getParamsFromPath = pathToRegexp.match(route.path, { decode: decodeURIComponent });
|
|
@@ -68,24 +110,35 @@ const bindRoute = (services, appBinder, pathExtractor, matcher) => (route) => {
|
|
|
68
110
|
}
|
|
69
111
|
};
|
|
70
112
|
};
|
|
71
|
-
|
|
72
|
-
*
|
|
73
|
-
*
|
|
113
|
+
/**
|
|
114
|
+
* A factory factory for creating request responders (functions that take a request and return a
|
|
115
|
+
* response -- these functions let us implement Lambda `handler` functions).
|
|
74
116
|
*
|
|
75
|
-
*
|
|
76
|
-
*
|
|
117
|
+
* Use it in two steps. First, call it with the general business logic that defines routes, logs,
|
|
118
|
+
* errors, etc:
|
|
119
|
+
* ```
|
|
120
|
+
* const getRequestResponder = makeGetRequestResponder<
|
|
121
|
+
* AppServices, TRoutes, ApiRouteRequest, Promise<ApiRouteResponse>
|
|
122
|
+
* >() // this empty invocation helps typescript mix defined and inferred types
|
|
123
|
+
* ({
|
|
77
124
|
* routes: apiRoutes, // the route definitions
|
|
78
|
-
* pathExtractor,
|
|
79
|
-
* routeMatcher,
|
|
80
|
-
* errorHandler,
|
|
125
|
+
* pathExtractor, // how to get the path out of the request format
|
|
126
|
+
* routeMatcher, // logic for matching route (beyond path matching, optional)
|
|
127
|
+
* errorHandler, // any special error handling
|
|
81
128
|
* });
|
|
129
|
+
* ```
|
|
130
|
+
* Note here that among other things we're specifying a generic response format that the response
|
|
131
|
+
* and error handling middleware can use, if any routes have responses that don't adhere to this
|
|
132
|
+
* it'll complain about it.
|
|
82
133
|
*
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
* )
|
|
134
|
+
* Next, we use the `getRequestResponder` to create a responder for a specific lambda entrypoint:
|
|
135
|
+
* ```
|
|
136
|
+
* export const handler: (request: APIGatewayProxyEventV2): Promise<ApiRouteResponse> =>
|
|
137
|
+
* getRequestResponder(
|
|
138
|
+
* lambdaServices, // the AppServices for this entrypoint
|
|
139
|
+
* lambdaMiddleware // environment specific response middleware (like cors)
|
|
140
|
+
* );
|
|
141
|
+
* ```
|
|
89
142
|
*/
|
|
90
143
|
export const makeGetRequestResponder = () => ({ routes, pathExtractor, routeMatcher, errorHandler, logExtractor }) => (services, responseMiddleware) => {
|
|
91
144
|
const appBinderImpl = (app, middleware) => middleware(app, appBinder);
|
|
@@ -136,9 +189,38 @@ export const makeGetRequestResponder = () => ({ routes, pathExtractor, routeMatc
|
|
|
136
189
|
return undefined;
|
|
137
190
|
};
|
|
138
191
|
};
|
|
192
|
+
/**
|
|
193
|
+
* Returns a JSON response. Handles serializing the data to JSON and setting the content-type header.
|
|
194
|
+
* @param statusCode e.g. 201
|
|
195
|
+
* @param data the object to be serialized to JSON
|
|
196
|
+
* @param headers HTTP headers
|
|
197
|
+
* @example
|
|
198
|
+
* return apiJsonResponse(
|
|
199
|
+
* 200, {
|
|
200
|
+
* message: "hello, world!",
|
|
201
|
+
* foo: "bar",
|
|
202
|
+
* },
|
|
203
|
+
* { 'X-Frame-Options': 'DENY' }
|
|
204
|
+
* );
|
|
205
|
+
*/
|
|
139
206
|
export const apiJsonResponse = (statusCode, data, headers) => ({ statusCode, data, body: JSON.stringify(data), headers: { ...headers, 'content-type': 'application/json' } });
|
|
207
|
+
/**
|
|
208
|
+
* Returns a plain text response. Handles setting the content-type header.
|
|
209
|
+
* @param statusCode e.g. 201
|
|
210
|
+
* @param data some string
|
|
211
|
+
* @param headers HTTP headers
|
|
212
|
+
* @example return apiTextResponse(200, 'some text')
|
|
213
|
+
*/
|
|
140
214
|
export const apiTextResponse = (statusCode, data, headers) => ({ statusCode, data, body: data, headers: { ...headers, 'content-type': 'text/plain' } });
|
|
215
|
+
/**
|
|
216
|
+
* Returns an HTML response. Handles setting the content-type header.
|
|
217
|
+
* @param statusCode e.g. 201
|
|
218
|
+
* @param data some string
|
|
219
|
+
* @param headers HTTP headers
|
|
220
|
+
* @example return apiHtmlResponse(200, '<b>some text</b>')
|
|
221
|
+
*/
|
|
141
222
|
export const apiHtmlResponse = (statusCode, data, headers) => ({ statusCode, data, body: data, headers: { ...headers, 'content-type': 'text/html' } });
|
|
223
|
+
/** HTTP method enum */
|
|
142
224
|
export var METHOD;
|
|
143
225
|
(function (METHOD) {
|
|
144
226
|
METHOD["GET"] = "GET";
|
|
@@ -41,6 +41,7 @@ declare type MapRoutesToConfig<Ru> = [Ru] extends [AnyRoute<Ru>] ? {
|
|
|
41
41
|
method: string;
|
|
42
42
|
};
|
|
43
43
|
} : never;
|
|
44
|
+
/** Pulls the content out of a response based on the content type */
|
|
44
45
|
export declare const loadResponse: (response: Response) => () => Promise<any>;
|
|
45
46
|
interface MakeApiGateway<F> {
|
|
46
47
|
<Ru>(config: ConfigProviderForConfig<{
|
|
@@ -3,6 +3,7 @@ import queryString from 'query-string';
|
|
|
3
3
|
import { merge } from '../..';
|
|
4
4
|
import { resolveConfigValue } from '../../config';
|
|
5
5
|
import { SessionExpiredError, UnauthorizedError } from '../../errors';
|
|
6
|
+
/** Pulls the content out of a response based on the content type */
|
|
6
7
|
export const loadResponse = (response) => () => {
|
|
7
8
|
const [contentType] = (response.headers.get('content-type') || '').split(';');
|
|
8
9
|
switch (contentType) {
|
|
@@ -15,6 +16,7 @@ export const loadResponse = (response) => () => {
|
|
|
15
16
|
}
|
|
16
17
|
};
|
|
17
18
|
const makeRouteClient = (initializer, config, route, authProvider) => {
|
|
19
|
+
/* TODO this duplicates code with makeRenderRouteUrl, reuse that */
|
|
18
20
|
const renderUrl = async ({ params, query }) => {
|
|
19
21
|
const apiBase = await resolveConfigValue(config.apiBase);
|
|
20
22
|
const getPathForParams = pathToRegexp.compile(route.path, { encode: encodeURIComponent });
|
|
@@ -12,13 +12,14 @@ export interface TokenUser {
|
|
|
12
12
|
is_administrator: boolean;
|
|
13
13
|
}
|
|
14
14
|
export interface ApiUser extends TokenUser {
|
|
15
|
-
is_not_gdpr_location: boolean;
|
|
16
15
|
contact_infos: Array<{
|
|
17
16
|
type: string;
|
|
18
17
|
value: string;
|
|
19
18
|
is_verified: boolean;
|
|
20
19
|
is_guessed_preferred: boolean;
|
|
21
20
|
}>;
|
|
21
|
+
external_ids: string[];
|
|
22
|
+
is_not_gdpr_location: boolean;
|
|
22
23
|
signed_contract_names: string[];
|
|
23
24
|
}
|
|
24
25
|
export declare type User = TokenUser | ApiUser;
|
|
@@ -1,2 +1,11 @@
|
|
|
1
1
|
import { User } from '..';
|
|
2
|
+
/**
|
|
3
|
+
* Decrypts and verifies a SSO cookie.
|
|
4
|
+
*
|
|
5
|
+
* @param token the encrypted token
|
|
6
|
+
* @param encryptionPrivateKey the private key used to encrypt the token
|
|
7
|
+
* @param signaturePublicKey the public key used to verify the decrypted token
|
|
8
|
+
* @throws SessionExpiredError if the token is expired
|
|
9
|
+
* @returns User (success) or undefined (failure)
|
|
10
|
+
*/
|
|
2
11
|
export declare const decryptAndVerify: (token: string, encryptionPrivateKey: string, signaturePublicKey: string) => User | undefined;
|
|
@@ -18,6 +18,15 @@ const decrypt = (input, key) => {
|
|
|
18
18
|
]);
|
|
19
19
|
return result.toString('utf-8');
|
|
20
20
|
};
|
|
21
|
+
/**
|
|
22
|
+
* Decrypts and verifies a SSO cookie.
|
|
23
|
+
*
|
|
24
|
+
* @param token the encrypted token
|
|
25
|
+
* @param encryptionPrivateKey the private key used to encrypt the token
|
|
26
|
+
* @param signaturePublicKey the public key used to verify the decrypted token
|
|
27
|
+
* @throws SessionExpiredError if the token is expired
|
|
28
|
+
* @returns User (success) or undefined (failure)
|
|
29
|
+
*/
|
|
21
30
|
export const decryptAndVerify = (token, encryptionPrivateKey, signaturePublicKey) => {
|
|
22
31
|
try {
|
|
23
32
|
// Decrypt SSO cookie
|
|
@@ -1,14 +1,39 @@
|
|
|
1
1
|
import { JsonCompatibleStruct } from '../../routing';
|
|
2
|
+
/**
|
|
3
|
+
* The log level
|
|
4
|
+
*/
|
|
2
5
|
export declare enum Level {
|
|
3
6
|
Info = "info",
|
|
4
7
|
Warn = "warn",
|
|
5
8
|
Error = "error"
|
|
6
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
|
+
*/
|
|
7
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
|
+
*/
|
|
8
25
|
export interface Logger {
|
|
9
26
|
setContext: (obj: JsonCompatibleStruct) => void;
|
|
10
27
|
logEvent: LogEvent;
|
|
11
28
|
log: (message: string, level?: Level) => void;
|
|
12
29
|
createSubContext: () => Logger;
|
|
13
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
|
+
*/
|
|
14
39
|
export declare const createCoreLogger: (driver: LogEvent, getParentContext?: (() => JsonCompatibleStruct) | undefined) => Logger;
|
|
@@ -1,9 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The log level
|
|
3
|
+
*/
|
|
1
4
|
export var Level;
|
|
2
5
|
(function (Level) {
|
|
3
6
|
Level["Info"] = "info";
|
|
4
7
|
Level["Warn"] = "warn";
|
|
5
8
|
Level["Error"] = "error";
|
|
6
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
|
+
*/
|
|
7
18
|
export const createCoreLogger = (driver, getParentContext) => {
|
|
8
19
|
const context = {};
|
|
9
20
|
const getContext = () => ({ ...getParentContext === null || getParentContext === void 0 ? void 0 : getParentContext(), ...context });
|
|
@@ -10,11 +10,15 @@ export declare type ActivityState = {
|
|
|
10
10
|
};
|
|
11
11
|
export declare const matchAttempt: (statement: XapiStatement) => boolean;
|
|
12
12
|
export declare const matchAttemptCompleted: (attempt: XapiStatement) => (statement: XapiStatement) => boolean;
|
|
13
|
-
export declare const
|
|
14
|
-
|
|
13
|
+
export declare const resolveAttempts: (statements: XapiStatement[], options?: {
|
|
14
|
+
activityIRI?: string | undefined;
|
|
15
|
+
parentActivityAttempt?: string | undefined;
|
|
16
|
+
} | undefined) => XapiStatement[];
|
|
17
|
+
export declare const resolveCompletedForAttempt: (statements: XapiStatement[], attempt: XapiStatement, activityIRI?: string | undefined) => XapiStatement | undefined;
|
|
15
18
|
export declare const oldestStatement: (statements: XapiStatement[]) => XapiStatement | undefined;
|
|
16
19
|
export declare const mostRecentStatement: (statements: XapiStatement[]) => XapiStatement | undefined;
|
|
17
|
-
export declare const
|
|
20
|
+
export declare const resolveAttemptInfo: (statements: XapiStatement[], options?: {
|
|
21
|
+
activityIRI?: string | undefined;
|
|
18
22
|
currentAttempt?: string | undefined;
|
|
19
23
|
parentActivityAttempt?: string | undefined;
|
|
20
24
|
currentPreference?: "latest" | "oldest" | undefined;
|
|
@@ -23,13 +27,6 @@ export declare const loadStatementsForActivityAndFirstChildren: (gateway: LrsGat
|
|
|
23
27
|
attempt?: string | undefined;
|
|
24
28
|
ensureSync?: boolean | undefined;
|
|
25
29
|
} | undefined) => Promise<XapiStatement[]>;
|
|
26
|
-
export declare const loadStatementsForAttempt: (gateway: LrsGateway, attempt: string, options?: {
|
|
27
|
-
ensureSync?: boolean | undefined;
|
|
28
|
-
} | undefined) => Promise<XapiStatement[]>;
|
|
29
|
-
export declare const loadStatementsForActivity: (gateway: LrsGateway, activityIRI: string, options?: {
|
|
30
|
-
attempt?: string | undefined;
|
|
31
|
-
ensureSync?: boolean | undefined;
|
|
32
|
-
} | undefined) => Promise<XapiStatement[]>;
|
|
33
30
|
export declare const loadActivityAttemptInfo: (gateway: LrsGateway, activityIRI: string, options?: {
|
|
34
31
|
currentAttempt?: string | undefined;
|
|
35
32
|
parentActivityAttempt?: string | undefined;
|
|
@@ -24,21 +24,21 @@ export const matchAttemptCompleted = (attempt) => (statement) => {
|
|
|
24
24
|
&& ((_a = statement.context.statement) === null || _a === void 0 ? void 0 : _a.id) === attempt.id
|
|
25
25
|
&& statement.context.registration === ((_b = attempt.context) === null || _b === void 0 ? void 0 : _b.registration);
|
|
26
26
|
};
|
|
27
|
-
export const
|
|
27
|
+
export const resolveAttempts = (statements, options) => statements.filter(statement => {
|
|
28
28
|
var _a;
|
|
29
29
|
return matchAttempt(statement)
|
|
30
|
-
&& statement.object.id === activityIRI
|
|
31
|
-
&& (!parentActivityAttempt || ((_a = statement.context) === null || _a === void 0 ? void 0 : _a.registration) === parentActivityAttempt);
|
|
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
32
|
});
|
|
33
|
-
export const resolveCompletedForAttempt = (statements,
|
|
34
|
-
&& statement.object.id === activityIRI);
|
|
33
|
+
export const resolveCompletedForAttempt = (statements, attempt, activityIRI) => statements.find(statement => matchAttemptCompleted(attempt)(statement)
|
|
34
|
+
&& (!activityIRI || statement.object.id === activityIRI));
|
|
35
35
|
export const oldestStatement = (statements) => statements.reduce((result, statement) => result && isBefore(parseISO(result.stored || result.timestamp), parseISO(statement.timestamp)) ? result : statement, statements[0]);
|
|
36
36
|
export const mostRecentStatement = (statements) => statements.reduce((result, statement) => result && isAfter(parseISO(result.stored || result.timestamp), parseISO(statement.timestamp)) ? result : statement, statements[0]);
|
|
37
|
-
export const
|
|
37
|
+
export const resolveAttemptInfo = (statements, options) => {
|
|
38
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 =
|
|
39
|
+
const attempts = resolveAttempts(statements, options);
|
|
40
40
|
/* attempts that have a completed statement */
|
|
41
|
-
const completedAttempts = attempts.filter(attempt => !!resolveCompletedForAttempt(statements,
|
|
41
|
+
const completedAttempts = attempts.filter(attempt => !!resolveCompletedForAttempt(statements, attempt, options === null || options === void 0 ? void 0 : options.activityIRI));
|
|
42
42
|
/* the last attempt sorted by timestamp */
|
|
43
43
|
const currentAttempt = (options === null || options === void 0 ? void 0 : options.currentAttempt)
|
|
44
44
|
? attempts.find(attempt => attempt.id === options.currentAttempt)
|
|
@@ -48,13 +48,13 @@ export const resolveActivityAttemptInfo = (statements, activityIRI, options) =>
|
|
|
48
48
|
/* all statements for the current attempt (doesn't include the attempt or completed statements) */
|
|
49
49
|
const currentAttemptStatements = currentAttempt ? statements.filter(statement => {
|
|
50
50
|
var _a;
|
|
51
|
-
return statement.object.id === activityIRI
|
|
51
|
+
return (!(options === null || options === void 0 ? void 0 : options.activityIRI) || statement.object.id === options.activityIRI)
|
|
52
52
|
&& ((_a = statement.context) === null || _a === void 0 ? void 0 : _a.registration) === currentAttempt.id;
|
|
53
53
|
}) : [];
|
|
54
|
-
const currentAttemptCompleted = currentAttempt && resolveCompletedForAttempt(statements,
|
|
54
|
+
const currentAttemptCompleted = currentAttempt && resolveCompletedForAttempt(statements, currentAttempt, options === null || options === void 0 ? void 0 : options.activityIRI);
|
|
55
55
|
const mostRecentAttemptWithCompleted = completedAttempts.reduce((current, attempt) => current && isAfter(parseISO(current.timestamp), parseISO(attempt.timestamp)) ? current : attempt, completedAttempts[0]);
|
|
56
56
|
const mostRecentAttemptWithCompletedCompleted = mostRecentAttemptWithCompleted
|
|
57
|
-
&& resolveCompletedForAttempt(statements,
|
|
57
|
+
&& resolveCompletedForAttempt(statements, mostRecentAttemptWithCompleted, options === null || options === void 0 ? void 0 : options.activityIRI);
|
|
58
58
|
/*
|
|
59
59
|
* the structure allows for the possibility of multiple incomplete attempts.
|
|
60
60
|
* the implementation can choose at its discretion to ignore the currentAttempt
|
|
@@ -75,8 +75,9 @@ export const resolveActivityAttemptInfo = (statements, activityIRI, options) =>
|
|
|
75
75
|
* loads all statements (for this actor) that have the given activityIRI as the object.id or the context.contextActivities.parent.id
|
|
76
76
|
*
|
|
77
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
|
-
*
|
|
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.
|
|
80
81
|
*/
|
|
81
82
|
export const loadStatementsForActivityAndFirstChildren = (gateway, activityIRI, options) => {
|
|
82
83
|
const { attempt, ...partialOptions } = options ? options : { attempt: undefined };
|
|
@@ -87,30 +88,10 @@ export const loadStatementsForActivityAndFirstChildren = (gateway, activityIRI,
|
|
|
87
88
|
...getOptions,
|
|
88
89
|
});
|
|
89
90
|
};
|
|
90
|
-
/*
|
|
91
|
-
* loads all statements (for this actor) that have the given parent attempt (registration)
|
|
92
|
-
*/
|
|
93
|
-
export const loadStatementsForAttempt = (gateway, attempt, options) => {
|
|
94
|
-
return gateway.getAllXapiStatements({
|
|
95
|
-
registration: attempt,
|
|
96
|
-
...(options ? options : {})
|
|
97
|
-
});
|
|
98
|
-
};
|
|
99
|
-
/*
|
|
100
|
-
* loads all statements (for this actor) that have the given activityIRI as the object.id
|
|
101
|
-
*/
|
|
102
|
-
export const loadStatementsForActivity = (gateway, activityIRI, options) => {
|
|
103
|
-
const { attempt, ...partialOptions } = options ? options : { attempt: undefined };
|
|
104
|
-
const getOptions = attempt ? { registration: attempt, ...partialOptions } : partialOptions;
|
|
105
|
-
return gateway.getAllXapiStatements({
|
|
106
|
-
activity: activityIRI,
|
|
107
|
-
...getOptions,
|
|
108
|
-
});
|
|
109
|
-
};
|
|
110
91
|
export const loadActivityAttemptInfo = async (gateway, activityIRI, options) => {
|
|
111
92
|
const { parentActivityAttempt, ...partialOptions } = options ? options : { parentActivityAttempt: undefined };
|
|
112
|
-
const loadOptions = parentActivityAttempt ? {
|
|
113
|
-
return
|
|
93
|
+
const loadOptions = parentActivityAttempt ? { ...partialOptions, registration: parentActivityAttempt } : partialOptions;
|
|
94
|
+
return resolveAttemptInfo(await gateway.getAllXapiStatements({ ...loadOptions, activity: activityIRI }), { ...options, activityIRI });
|
|
114
95
|
};
|
|
115
96
|
export const createStatement = (verb, activity, attempt, parentActivityIRI) => {
|
|
116
97
|
return {
|
|
@@ -57,19 +57,33 @@ export const fileSystemLrsGateway = (initializer) => (configProvider) => (authPr
|
|
|
57
57
|
await save;
|
|
58
58
|
return statementsWithDefaults;
|
|
59
59
|
};
|
|
60
|
-
const getAllXapiStatements = async ({ user, anyUser, ...options }) => {
|
|
60
|
+
const getAllXapiStatements = async ({ user, anyUser, fetchUntil, ...options }) => {
|
|
61
61
|
const authUser = await authProvider.getUser();
|
|
62
62
|
await load;
|
|
63
|
-
|
|
63
|
+
let filteredData = (data || []).filter(statement => {
|
|
64
64
|
var _a, _b, _c, _d;
|
|
65
|
+
const statementDate = new Date(statement.timestamp);
|
|
66
|
+
const sinceDate = options.since ? new Date(options.since) : null;
|
|
67
|
+
const untilDate = options.until ? new Date(options.until) : null;
|
|
65
68
|
return (anyUser === true || statement.actor.account.name === (user || assertDefined(authUser, new UnauthorizedError()).uuid))
|
|
66
69
|
&& (!options.verb || statement.verb.id === options.verb)
|
|
67
70
|
&& (!options.registration || ((_a = statement.context) === null || _a === void 0 ? void 0 : _a.registration) === options.registration)
|
|
68
71
|
&& (!options.activity || (options.related_activities
|
|
69
72
|
? ((statement.object.id === options.activity && statement.object.objectType === 'Activity')
|
|
70
73
|
|| (!!((_d = (_c = (_b = statement.context) === null || _b === void 0 ? void 0 : _b.contextActivities) === null || _c === void 0 ? void 0 : _c.parent) === null || _d === void 0 ? void 0 : _d.find(parent => parent.id === options.activity && parent.objectType === 'Activity'))))
|
|
71
|
-
: (statement.object.id === options.activity && statement.object.objectType === 'Activity')))
|
|
74
|
+
: (statement.object.id === options.activity && statement.object.objectType === 'Activity')))
|
|
75
|
+
&& (!sinceDate || statementDate >= sinceDate)
|
|
76
|
+
&& (!untilDate || statementDate <= untilDate);
|
|
72
77
|
});
|
|
78
|
+
if (fetchUntil) {
|
|
79
|
+
for (let i = 0; i < filteredData.length; i += pageSize) {
|
|
80
|
+
if (fetchUntil(filteredData.slice(0, i + pageSize))) {
|
|
81
|
+
filteredData = filteredData.slice(0, i + pageSize);
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return filteredData;
|
|
73
87
|
};
|
|
74
88
|
const getMoreXapiStatements = async (more) => {
|
|
75
89
|
const { args, offset } = JSON.parse(more);
|
|
@@ -90,6 +90,8 @@ export declare const lrsGateway: <C extends string = "lrs">(initializer: Initial
|
|
|
90
90
|
related_activities?: boolean | undefined;
|
|
91
91
|
user?: string | undefined;
|
|
92
92
|
anyUser?: boolean | undefined;
|
|
93
|
+
since?: string | undefined;
|
|
94
|
+
until?: string | undefined;
|
|
93
95
|
} & {
|
|
94
96
|
ensureSync?: boolean | undefined;
|
|
95
97
|
}) => Promise<{
|
|
@@ -100,15 +102,19 @@ export declare const lrsGateway: <C extends string = "lrs">(initializer: Initial
|
|
|
100
102
|
more: string;
|
|
101
103
|
statements: XapiStatement[];
|
|
102
104
|
}>;
|
|
103
|
-
getAllXapiStatements: (params: {
|
|
105
|
+
getAllXapiStatements: ({ fetchUntil, ...params }: {
|
|
104
106
|
verb?: string | undefined;
|
|
105
107
|
activity?: string | undefined;
|
|
106
108
|
registration?: string | undefined;
|
|
107
109
|
related_activities?: boolean | undefined;
|
|
108
110
|
user?: string | undefined;
|
|
109
111
|
anyUser?: boolean | undefined;
|
|
112
|
+
since?: string | undefined;
|
|
113
|
+
until?: string | undefined;
|
|
110
114
|
} & {
|
|
111
115
|
ensureSync?: boolean | undefined;
|
|
116
|
+
} & {
|
|
117
|
+
fetchUntil?: ((statements: XapiStatement[]) => boolean) | undefined;
|
|
112
118
|
}) => Promise<XapiStatement[]>;
|
|
113
119
|
};
|
|
114
120
|
export {};
|
|
@@ -94,9 +94,9 @@ ${await response.text()}`);
|
|
|
94
94
|
return formatGetXapiStatementsResponse(fetchXapiStatements(fetchParams));
|
|
95
95
|
}
|
|
96
96
|
};
|
|
97
|
-
const getAllXapiStatements = async (params) => {
|
|
97
|
+
const getAllXapiStatements = async ({ fetchUntil, ...params }) => {
|
|
98
98
|
const loadRemaining = async (result) => {
|
|
99
|
-
if (!result.more) {
|
|
99
|
+
if (!result.more || (fetchUntil && fetchUntil(result.statements))) {
|
|
100
100
|
return result.statements;
|
|
101
101
|
}
|
|
102
102
|
const { more, statements } = await getMoreXapiStatements(result.more);
|