@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.
Files changed (124) hide show
  1. package/dist/cjs/assertions.d.ts +75 -0
  2. package/dist/cjs/assertions.js +74 -29
  3. package/dist/cjs/aws/ssmService.d.ts +3 -0
  4. package/dist/cjs/aws/ssmService.js +3 -0
  5. package/dist/cjs/config/awsParameterConfig.d.ts +8 -0
  6. package/dist/cjs/config/awsParameterConfig.js +8 -0
  7. package/dist/cjs/config/envConfig.d.ts +21 -0
  8. package/dist/cjs/config/envConfig.js +20 -14
  9. package/dist/cjs/config/index.d.ts +28 -0
  10. package/dist/cjs/config/index.js +3 -6
  11. package/dist/cjs/config/lambdaParameterConfig.d.ts +10 -0
  12. package/dist/cjs/config/lambdaParameterConfig.js +10 -2
  13. package/dist/cjs/config/replaceConfig.d.ts +10 -0
  14. package/dist/cjs/config/replaceConfig.js +10 -0
  15. package/dist/cjs/config/resolveConfigValue.d.ts +3 -0
  16. package/dist/cjs/config/resolveConfigValue.js +2 -2
  17. package/dist/cjs/errors.d.ts +27 -0
  18. package/dist/cjs/errors.js +29 -2
  19. package/dist/cjs/guards.d.ts +24 -0
  20. package/dist/cjs/guards.js +18 -19
  21. package/dist/cjs/middleware/apiErrorHandler.d.ts +8 -0
  22. package/dist/cjs/middleware/apiErrorHandler.js +8 -0
  23. package/dist/cjs/middleware/apiSlowResponseMiddleware.d.ts +12 -0
  24. package/dist/cjs/middleware/apiSlowResponseMiddleware.js +12 -0
  25. package/dist/cjs/middleware/lambdaCorsResponseMiddleware.d.ts +11 -1
  26. package/dist/cjs/middleware/lambdaCorsResponseMiddleware.js +11 -1
  27. package/dist/cjs/middleware/throwNotFoundMiddleware.d.ts +3 -0
  28. package/dist/cjs/middleware/throwNotFoundMiddleware.js +3 -0
  29. package/dist/cjs/middleware.d.ts +38 -0
  30. package/dist/cjs/middleware.js +26 -16
  31. package/dist/cjs/misc/hashValue.d.ts +5 -0
  32. package/dist/cjs/misc/hashValue.js +3 -4
  33. package/dist/cjs/misc/helpers.d.ts +94 -0
  34. package/dist/cjs/misc/helpers.js +52 -14
  35. package/dist/cjs/misc/merge.d.ts +18 -0
  36. package/dist/cjs/misc/merge.js +10 -3
  37. package/dist/cjs/misc/partitionSequence.d.ts +31 -0
  38. package/dist/cjs/misc/partitionSequence.js +1 -1
  39. package/dist/cjs/pagination.d.ts +28 -0
  40. package/dist/cjs/pagination.js +1 -1
  41. package/dist/cjs/routing/helpers.d.ts +45 -0
  42. package/dist/cjs/routing/helpers.js +40 -22
  43. package/dist/cjs/routing/index.d.ts +169 -0
  44. package/dist/cjs/routing/index.js +127 -45
  45. package/dist/cjs/services/apiGateway/index.d.ts +1 -0
  46. package/dist/cjs/services/apiGateway/index.js +2 -0
  47. package/dist/cjs/services/authProvider/index.d.ts +2 -1
  48. package/dist/cjs/services/authProvider/utils/decryptAndVerify.d.ts +9 -0
  49. package/dist/cjs/services/authProvider/utils/decryptAndVerify.js +9 -0
  50. package/dist/cjs/services/logger/console.d.ts +3 -0
  51. package/dist/cjs/services/logger/console.js +3 -0
  52. package/dist/cjs/services/logger/index.d.ts +25 -0
  53. package/dist/cjs/services/logger/index.js +11 -0
  54. package/dist/cjs/services/lrsGateway/attempt-utils.d.ts +7 -10
  55. package/dist/cjs/services/lrsGateway/attempt-utils.js +19 -40
  56. package/dist/cjs/services/lrsGateway/file-system.js +17 -3
  57. package/dist/cjs/services/lrsGateway/index.d.ts +7 -1
  58. package/dist/cjs/services/lrsGateway/index.js +2 -2
  59. package/dist/cjs/tsconfig.without-specs.cjs.tsbuildinfo +1 -1
  60. package/dist/cjs/types.d.ts +21 -0
  61. package/dist/esm/assertions.d.ts +75 -0
  62. package/dist/esm/assertions.js +74 -29
  63. package/dist/esm/aws/ssmService.d.ts +3 -0
  64. package/dist/esm/aws/ssmService.js +3 -0
  65. package/dist/esm/config/awsParameterConfig.d.ts +8 -0
  66. package/dist/esm/config/awsParameterConfig.js +8 -0
  67. package/dist/esm/config/envConfig.d.ts +21 -0
  68. package/dist/esm/config/envConfig.js +20 -14
  69. package/dist/esm/config/index.d.ts +28 -0
  70. package/dist/esm/config/index.js +3 -6
  71. package/dist/esm/config/lambdaParameterConfig.d.ts +10 -0
  72. package/dist/esm/config/lambdaParameterConfig.js +10 -2
  73. package/dist/esm/config/replaceConfig.d.ts +10 -0
  74. package/dist/esm/config/replaceConfig.js +10 -0
  75. package/dist/esm/config/resolveConfigValue.d.ts +3 -0
  76. package/dist/esm/config/resolveConfigValue.js +2 -2
  77. package/dist/esm/errors.d.ts +27 -0
  78. package/dist/esm/errors.js +27 -0
  79. package/dist/esm/guards.d.ts +24 -0
  80. package/dist/esm/guards.js +18 -19
  81. package/dist/esm/middleware/apiErrorHandler.d.ts +8 -0
  82. package/dist/esm/middleware/apiErrorHandler.js +8 -0
  83. package/dist/esm/middleware/apiSlowResponseMiddleware.d.ts +12 -0
  84. package/dist/esm/middleware/apiSlowResponseMiddleware.js +12 -0
  85. package/dist/esm/middleware/lambdaCorsResponseMiddleware.d.ts +11 -1
  86. package/dist/esm/middleware/lambdaCorsResponseMiddleware.js +11 -1
  87. package/dist/esm/middleware/throwNotFoundMiddleware.d.ts +3 -0
  88. package/dist/esm/middleware/throwNotFoundMiddleware.js +3 -0
  89. package/dist/esm/middleware.d.ts +38 -0
  90. package/dist/esm/middleware.js +26 -16
  91. package/dist/esm/misc/hashValue.d.ts +5 -0
  92. package/dist/esm/misc/hashValue.js +3 -4
  93. package/dist/esm/misc/helpers.d.ts +94 -0
  94. package/dist/esm/misc/helpers.js +48 -10
  95. package/dist/esm/misc/merge.d.ts +18 -0
  96. package/dist/esm/misc/merge.js +10 -3
  97. package/dist/esm/misc/partitionSequence.d.ts +31 -0
  98. package/dist/esm/misc/partitionSequence.js +1 -1
  99. package/dist/esm/pagination.d.ts +28 -0
  100. package/dist/esm/pagination.js +1 -1
  101. package/dist/esm/routing/helpers.d.ts +45 -0
  102. package/dist/esm/routing/helpers.js +40 -22
  103. package/dist/esm/routing/index.d.ts +169 -0
  104. package/dist/esm/routing/index.js +127 -45
  105. package/dist/esm/services/apiGateway/index.d.ts +1 -0
  106. package/dist/esm/services/apiGateway/index.js +2 -0
  107. package/dist/esm/services/authProvider/index.d.ts +2 -1
  108. package/dist/esm/services/authProvider/utils/decryptAndVerify.d.ts +9 -0
  109. package/dist/esm/services/authProvider/utils/decryptAndVerify.js +9 -0
  110. package/dist/esm/services/logger/console.d.ts +3 -0
  111. package/dist/esm/services/logger/console.js +3 -0
  112. package/dist/esm/services/logger/index.d.ts +25 -0
  113. package/dist/esm/services/logger/index.js +11 -0
  114. package/dist/esm/services/lrsGateway/attempt-utils.d.ts +7 -10
  115. package/dist/esm/services/lrsGateway/attempt-utils.js +16 -35
  116. package/dist/esm/services/lrsGateway/file-system.js +17 -3
  117. package/dist/esm/services/lrsGateway/index.d.ts +7 -1
  118. package/dist/esm/services/lrsGateway/index.js +2 -2
  119. package/dist/esm/tsconfig.without-specs.esm.tsbuildinfo +1 -1
  120. package/dist/esm/types.d.ts +21 -0
  121. package/package.json +1 -1
  122. package/script/bin/copy-from-template.bash +1 -1
  123. package/script/.build-dist.swo +0 -0
  124. package/script/.build-dist.swp +0 -0
@@ -35,46 +35,63 @@ const query_string_1 = __importDefault(require("query-string"));
35
35
  const helpers_1 = require("../misc/helpers");
36
36
  const profile_1 = require("../profile");
37
37
  const console_1 = require("../services/logger/console");
38
- /*
39
- * route definition helper. the only required params of the route are the name, path, and handler. other params
40
- * can be added to the type and then later used in the routeMatcher. when defining the `createRoute` method, only
41
- * the request input format is defined, the result format is derived from the routes.
38
+ /**
39
+ * Makes a createRoute function that can be used to create routes (this is a factory factory). The
40
+ * `makeCreateRoute` function is typically called once in the backend and once in the frontend to
41
+ * set the types for the resulting `createRoute` function -- that latter function is called once
42
+ * per route. E.g. for the backend, the call could look like:
42
43
  *
43
- * eg:
44
- * export const createRoute = makeCreateRoute<AppServices, ApiRouteRequest, {
45
- * method: METHOD;
46
- * }>();
44
+ * ```
45
+ * export const createRoute = makeCreateRoute<AppServices, ApiRouteRequest, {
46
+ * method: METHOD;
47
+ * }>();
48
+ * ```
47
49
  *
48
- * eg when defining requestServiceProvider in line, the types have a hard time, it helps to put in another argument:
49
- * export const exampleRoute = createRoute({name: 'exampleRoute', method: METHOD.GET, path: '/api/example/:key',
50
- * requestServiceProvider: requestServiceProvider({
51
- * cookieAuthMiddleware,
52
- * documentStoreMiddleware,
53
- * }},
54
- * async(params: {key: string}, services) => {
55
- * const result = await services.myDocumentStore.getItem(params.key);
50
+ * Notes:
51
+ * * The `{method: METHOD}` defines the `Ex` extension type; here, the `method` property is only
52
+ * relevant to backend routes.
53
+ * * when defining the `createRoute` method, only the request input format is defined, the output
54
+ * format is derived from the routes.
55
+ *
56
+ * When calling the resulting `createRoute` function, the only required params of the route are the
57
+ * name, path, and handler. Other params can be added to the type and then later used in the
58
+ * routeMatcher.
56
59
  *
57
- * if (!result) {
58
- * throw new NotFoundError('requested item not found');
59
- * }
60
+ * eg when defining requestServiceProvider in line, the types have a hard time, it helps to put in another argument:
61
+ * ```
62
+ * export const exampleRoute = createRoute({
63
+ * name: 'exampleRoute', method: METHOD.GET, path: '/api/example/:key',
64
+ * requestServiceProvider: composeServiceMiddleware({
65
+ * cookieAuthMiddleware,
66
+ * documentStoreMiddleware,
67
+ * }},
68
+ * async(params: {key: string}, services) => {
69
+ * const result = await services.myDocumentStore.getItem(params.key);
60
70
  *
61
- * return apiJsonResponse(200, result);
71
+ * if (!result) {
72
+ * throw new NotFoundError('requested item not found');
62
73
  * }
63
- * );
64
74
  *
75
+ * return apiJsonResponse(200, result);
76
+ * }
77
+ * );
78
+ * ```
65
79
  * eg when using a pre-existing provider variable the types work better:
66
- * export const exampleRoute = createRoute({name: 'exampleRoute', method: METHOD.GET, path: '/api/example/:key',
67
- * requestServiceProvider,
68
- * handler: async(params: {key: string}, services) => {
69
- * const result = await services.myDocumentStore.getItem(params.key);
70
- *
71
- * if (!result) {
72
- * throw new NotFoundError('requested item not found');
73
- * }
80
+ * ```
81
+ * export const exampleRoute = createRoute({
82
+ * name: 'exampleRoute', method: METHOD.GET, path: '/api/example/:key',
83
+ * requestServiceProvider,
84
+ * handler: async(params: {key: string}, services) => {
85
+ * const result = await services.myDocumentStore.getItem(params.key);
74
86
  *
75
- * return apiJsonResponse(200, result);
87
+ * if (!result) {
88
+ * throw new NotFoundError('requested item not found');
76
89
  * }
77
- * });
90
+ *
91
+ * return apiJsonResponse(200, result);
92
+ * }
93
+ * });
94
+ * ```
78
95
  */
79
96
  const makeCreateRoute = () => (...args) => {
80
97
  return (args.length === 1
@@ -83,6 +100,19 @@ const makeCreateRoute = () => (...args) => {
83
100
  };
84
101
  exports.makeCreateRoute = makeCreateRoute;
85
102
  /* begin reverse routing utils */
103
+ /**
104
+ * Makes a renderRouteUrl function that can be used to render route paths (this is a factory
105
+ * factory). The returned function takes a `route`, `params`, and `query` and returns a string
106
+ * with the params and query substituted into the route path.
107
+ *
108
+ * this function is initialized using the Ru type which indicates the specific routes wired into
109
+ * the application, which means that if you try to build a url with a route which is not wired
110
+ * into the router you will get a type error. this is a feature to prevent referencing routes that
111
+ * don't exist or aren't handling requests properly.
112
+ *
113
+ * if you are making a helper function or need to render a route outside your application, you
114
+ * can use the `renderAnyRouteUrl` function
115
+ */
86
116
  const makeRenderRouteUrl = () => (route, params, query = {}) => {
87
117
  const getPathForParams = pathToRegexp.compile(route.path, { encode: encodeURIComponent });
88
118
  const search = query_string_1.default.stringify(query);
@@ -90,6 +120,18 @@ const makeRenderRouteUrl = () => (route, params, query = {}) => {
90
120
  return path;
91
121
  };
92
122
  exports.makeRenderRouteUrl = makeRenderRouteUrl;
123
+ /**
124
+ * A pre-made result from `makeRenderRouteUrl`, this function interpolates parameter and query
125
+ * arguments into a route path.
126
+ *
127
+ * prefer using `renderRouteUrl` initialized with your applications route union
128
+ * when possible to help catch improperly initialized routes.
129
+ *
130
+ * @param route the route that has a `path` to be interpolated
131
+ * @param params the parameters to interpolate into the route path
132
+ * @param query the query parameters to add to the route path
133
+ * @returns the interpolated route path
134
+ */
93
135
  exports.renderAnyRouteUrl = (0, exports.makeRenderRouteUrl)();
94
136
  const bindRoute = (services, appBinder, pathExtractor, matcher) => (route) => {
95
137
  const getParamsFromPath = pathToRegexp.match(route.path, { decode: decodeURIComponent });
@@ -102,24 +144,35 @@ const bindRoute = (services, appBinder, pathExtractor, matcher) => (route) => {
102
144
  }
103
145
  };
104
146
  };
105
- /*
106
- * here among other things we're specifying a generic response format that the response and error handling middleware can use,
107
- * if any routes have responses that don't adhere to this it'll complain about it.
147
+ /**
148
+ * A factory factory for creating request responders (functions that take a request and return a
149
+ * response -- these functions let us implement Lambda `handler` functions).
108
150
  *
109
- * eg:
110
- * export const getRequestResponder = makeGetRequestResponder<AppServices, TRoutes, ApiRouteRequest, Promise<ApiRouteResponse>>()({
151
+ * Use it in two steps. First, call it with the general business logic that defines routes, logs,
152
+ * errors, etc:
153
+ * ```
154
+ * const getRequestResponder = makeGetRequestResponder<
155
+ * AppServices, TRoutes, ApiRouteRequest, Promise<ApiRouteResponse>
156
+ * >() // this empty invocation helps typescript mix defined and inferred types
157
+ * ({
111
158
  * routes: apiRoutes, // the route definitions
112
- * pathExtractor, // how to get the path out of the request format
113
- * routeMatcher, // logic for matching route (if there is any in addition to the path matching)
114
- * errorHandler, // any special error handling
159
+ * pathExtractor, // how to get the path out of the request format
160
+ * routeMatcher, // logic for matching route (beyond path matching, optional)
161
+ * errorHandler, // any special error handling
115
162
  * });
163
+ * ```
164
+ * Note here that among other things we're specifying a generic response format that the response
165
+ * and error handling middleware can use, if any routes have responses that don't adhere to this
166
+ * it'll complain about it.
116
167
  *
117
- * eg an lambda entrypoint:
118
- * export const handler: (request: APIGatewayProxyEventV2) => Promise<ApiRouteResponse> =
119
- * getRequestResponder(
120
- * lambdaServices, // the AppServices for this entrypoint
121
- * lambdaMiddleware // environment specific response middleware (like cors)
122
- * );
168
+ * Next, we use the `getRequestResponder` to create a responder for a specific lambda entrypoint:
169
+ * ```
170
+ * export const handler: (request: APIGatewayProxyEventV2): Promise<ApiRouteResponse> =>
171
+ * getRequestResponder(
172
+ * lambdaServices, // the AppServices for this entrypoint
173
+ * lambdaMiddleware // environment specific response middleware (like cors)
174
+ * );
175
+ * ```
123
176
  */
124
177
  const makeGetRequestResponder = () => ({ routes, pathExtractor, routeMatcher, errorHandler, logExtractor }) => (services, responseMiddleware) => {
125
178
  const appBinderImpl = (app, middleware) => middleware(app, appBinder);
@@ -171,12 +224,41 @@ const makeGetRequestResponder = () => ({ routes, pathExtractor, routeMatcher, er
171
224
  };
172
225
  };
173
226
  exports.makeGetRequestResponder = makeGetRequestResponder;
227
+ /**
228
+ * Returns a JSON response. Handles serializing the data to JSON and setting the content-type header.
229
+ * @param statusCode e.g. 201
230
+ * @param data the object to be serialized to JSON
231
+ * @param headers HTTP headers
232
+ * @example
233
+ * return apiJsonResponse(
234
+ * 200, {
235
+ * message: "hello, world!",
236
+ * foo: "bar",
237
+ * },
238
+ * { 'X-Frame-Options': 'DENY' }
239
+ * );
240
+ */
174
241
  const apiJsonResponse = (statusCode, data, headers) => ({ statusCode, data, body: JSON.stringify(data), headers: { ...headers, 'content-type': 'application/json' } });
175
242
  exports.apiJsonResponse = apiJsonResponse;
243
+ /**
244
+ * Returns a plain text response. Handles setting the content-type header.
245
+ * @param statusCode e.g. 201
246
+ * @param data some string
247
+ * @param headers HTTP headers
248
+ * @example return apiTextResponse(200, 'some text')
249
+ */
176
250
  const apiTextResponse = (statusCode, data, headers) => ({ statusCode, data, body: data, headers: { ...headers, 'content-type': 'text/plain' } });
177
251
  exports.apiTextResponse = apiTextResponse;
252
+ /**
253
+ * Returns an HTML response. Handles setting the content-type header.
254
+ * @param statusCode e.g. 201
255
+ * @param data some string
256
+ * @param headers HTTP headers
257
+ * @example return apiHtmlResponse(200, '<b>some text</b>')
258
+ */
178
259
  const apiHtmlResponse = (statusCode, data, headers) => ({ statusCode, data, body: data, headers: { ...headers, 'content-type': 'text/html' } });
179
260
  exports.apiHtmlResponse = apiHtmlResponse;
261
+ /** HTTP method enum */
180
262
  var METHOD;
181
263
  (function (METHOD) {
182
264
  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<{
@@ -32,6 +32,7 @@ const query_string_1 = __importDefault(require("query-string"));
32
32
  const __1 = require("../..");
33
33
  const config_1 = require("../../config");
34
34
  const errors_1 = require("../../errors");
35
+ /** Pulls the content out of a response based on the content type */
35
36
  const loadResponse = (response) => () => {
36
37
  const [contentType] = (response.headers.get('content-type') || '').split(';');
37
38
  switch (contentType) {
@@ -45,6 +46,7 @@ const loadResponse = (response) => () => {
45
46
  };
46
47
  exports.loadResponse = loadResponse;
47
48
  const makeRouteClient = (initializer, config, route, authProvider) => {
49
+ /* TODO this duplicates code with makeRenderRouteUrl, reuse that */
48
50
  const renderUrl = async ({ params, query }) => {
49
51
  const apiBase = await (0, config_1.resolveConfigValue)(config.apiBase);
50
52
  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;
@@ -47,6 +47,15 @@ const decrypt = (input, key) => {
47
47
  ]);
48
48
  return result.toString('utf-8');
49
49
  };
50
+ /**
51
+ * Decrypts and verifies a SSO cookie.
52
+ *
53
+ * @param token the encrypted token
54
+ * @param encryptionPrivateKey the private key used to encrypt the token
55
+ * @param signaturePublicKey the public key used to verify the decrypted token
56
+ * @throws SessionExpiredError if the token is expired
57
+ * @returns User (success) or undefined (failure)
58
+ */
50
59
  const decryptAndVerify = (token, encryptionPrivateKey, signaturePublicKey) => {
51
60
  try {
52
61
  // Decrypt SSO cookie
@@ -1 +1,4 @@
1
+ /**
2
+ * Creates a logger that logs to the console.
3
+ */
1
4
  export declare const createConsoleLogger: () => import(".").Logger;
@@ -2,6 +2,9 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createConsoleLogger = void 0;
4
4
  const _1 = require(".");
5
+ /**
6
+ * Creates a logger that logs to the console.
7
+ */
5
8
  const createConsoleLogger = () => (0, _1.createCoreLogger)((level, event) => console[level](JSON.stringify({
6
9
  eventType: level.toUpperCase(),
7
10
  ...event,
@@ -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,12 +1,23 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createCoreLogger = exports.Level = void 0;
4
+ /**
5
+ * The log level
6
+ */
4
7
  var Level;
5
8
  (function (Level) {
6
9
  Level["Info"] = "info";
7
10
  Level["Warn"] = "warn";
8
11
  Level["Error"] = "error";
9
12
  })(Level = exports.Level || (exports.Level = {}));
13
+ /**
14
+ * Creates a logger that logs events using the given driver and context provider.
15
+ *
16
+ * @param driver the driver that logs events
17
+ * @param getParentContext a provider that returns the context to use for this logger
18
+ * (the context is returned when messages are logged with the logger)
19
+ * @returns a Logger
20
+ */
10
21
  const createCoreLogger = (driver, getParentContext) => {
11
22
  const context = {};
12
23
  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 resolveActivityAttempts: (statements: XapiStatement[], activityIRI: string, parentActivityAttempt?: string | undefined) => XapiStatement[];
14
- export declare const resolveCompletedForAttempt: (statements: XapiStatement[], activityIRI: string, attempt: XapiStatement) => XapiStatement | undefined;
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 resolveActivityAttemptInfo: (statements: XapiStatement[], activityIRI: string, options?: {
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;
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.putCompletedStatement = exports.createCompletedStatement = exports.putAttemptActivityStatement = exports.createAttemptActivityStatement = exports.putAttemptStatement = exports.createAttemptStatement = exports.createStatement = exports.loadActivityAttemptInfo = exports.loadStatementsForActivity = exports.loadStatementsForAttempt = exports.loadStatementsForActivityAndFirstChildren = exports.resolveActivityAttemptInfo = exports.mostRecentStatement = exports.oldestStatement = exports.resolveCompletedForAttempt = exports.resolveActivityAttempts = exports.matchAttemptCompleted = exports.matchAttempt = void 0;
6
+ exports.putCompletedStatement = exports.createCompletedStatement = exports.putAttemptActivityStatement = exports.createAttemptActivityStatement = exports.putAttemptStatement = exports.createAttemptStatement = exports.createStatement = exports.loadActivityAttemptInfo = exports.loadStatementsForActivityAndFirstChildren = exports.resolveAttemptInfo = exports.mostRecentStatement = exports.oldestStatement = exports.resolveCompletedForAttempt = exports.resolveAttempts = exports.matchAttemptCompleted = exports.matchAttempt = void 0;
7
7
  /*
8
8
  * the structure of xapi statements for handling multiple attempts of an activity
9
9
  * including the option of a parent activity/attempt such that a new attempt
@@ -32,25 +32,25 @@ const matchAttemptCompleted = (attempt) => (statement) => {
32
32
  && statement.context.registration === ((_b = attempt.context) === null || _b === void 0 ? void 0 : _b.registration);
33
33
  };
34
34
  exports.matchAttemptCompleted = matchAttemptCompleted;
35
- const resolveActivityAttempts = (statements, activityIRI, parentActivityAttempt) => statements.filter(statement => {
35
+ const resolveAttempts = (statements, options) => statements.filter(statement => {
36
36
  var _a;
37
37
  return (0, exports.matchAttempt)(statement)
38
- && statement.object.id === activityIRI
39
- && (!parentActivityAttempt || ((_a = statement.context) === null || _a === void 0 ? void 0 : _a.registration) === parentActivityAttempt);
38
+ && (!(options === null || options === void 0 ? void 0 : options.activityIRI) || statement.object.id === options.activityIRI)
39
+ && (!(options === null || options === void 0 ? void 0 : options.parentActivityAttempt) || ((_a = statement.context) === null || _a === void 0 ? void 0 : _a.registration) === options.parentActivityAttempt);
40
40
  });
41
- exports.resolveActivityAttempts = resolveActivityAttempts;
42
- const resolveCompletedForAttempt = (statements, activityIRI, attempt) => statements.find(statement => (0, exports.matchAttemptCompleted)(attempt)(statement)
43
- && statement.object.id === activityIRI);
41
+ exports.resolveAttempts = resolveAttempts;
42
+ const resolveCompletedForAttempt = (statements, attempt, activityIRI) => statements.find(statement => (0, exports.matchAttemptCompleted)(attempt)(statement)
43
+ && (!activityIRI || statement.object.id === activityIRI));
44
44
  exports.resolveCompletedForAttempt = resolveCompletedForAttempt;
45
45
  const oldestStatement = (statements) => statements.reduce((result, statement) => result && (0, isBefore_1.default)((0, parseISO_1.default)(result.stored || result.timestamp), (0, parseISO_1.default)(statement.timestamp)) ? result : statement, statements[0]);
46
46
  exports.oldestStatement = oldestStatement;
47
47
  const mostRecentStatement = (statements) => statements.reduce((result, statement) => result && (0, isAfter_1.default)((0, parseISO_1.default)(result.stored || result.timestamp), (0, parseISO_1.default)(statement.timestamp)) ? result : statement, statements[0]);
48
48
  exports.mostRecentStatement = mostRecentStatement;
49
- const resolveActivityAttemptInfo = (statements, activityIRI, options) => {
49
+ const resolveAttemptInfo = (statements, options) => {
50
50
  // TODO optimize. i'm 100% that this could all be done in one iteration but i'm not messing around with that for now.
51
- const attempts = (0, exports.resolveActivityAttempts)(statements, activityIRI, options === null || options === void 0 ? void 0 : options.parentActivityAttempt);
51
+ const attempts = (0, exports.resolveAttempts)(statements, options);
52
52
  /* attempts that have a completed statement */
53
- const completedAttempts = attempts.filter(attempt => !!(0, exports.resolveCompletedForAttempt)(statements, activityIRI, attempt));
53
+ const completedAttempts = attempts.filter(attempt => !!(0, exports.resolveCompletedForAttempt)(statements, attempt, options === null || options === void 0 ? void 0 : options.activityIRI));
54
54
  /* the last attempt sorted by timestamp */
55
55
  const currentAttempt = (options === null || options === void 0 ? void 0 : options.currentAttempt)
56
56
  ? attempts.find(attempt => attempt.id === options.currentAttempt)
@@ -60,13 +60,13 @@ const resolveActivityAttemptInfo = (statements, activityIRI, options) => {
60
60
  /* all statements for the current attempt (doesn't include the attempt or completed statements) */
61
61
  const currentAttemptStatements = currentAttempt ? statements.filter(statement => {
62
62
  var _a;
63
- return statement.object.id === activityIRI
63
+ return (!(options === null || options === void 0 ? void 0 : options.activityIRI) || statement.object.id === options.activityIRI)
64
64
  && ((_a = statement.context) === null || _a === void 0 ? void 0 : _a.registration) === currentAttempt.id;
65
65
  }) : [];
66
- const currentAttemptCompleted = currentAttempt && (0, exports.resolveCompletedForAttempt)(statements, activityIRI, currentAttempt);
66
+ const currentAttemptCompleted = currentAttempt && (0, exports.resolveCompletedForAttempt)(statements, currentAttempt, options === null || options === void 0 ? void 0 : options.activityIRI);
67
67
  const mostRecentAttemptWithCompleted = completedAttempts.reduce((current, attempt) => current && (0, isAfter_1.default)((0, parseISO_1.default)(current.timestamp), (0, parseISO_1.default)(attempt.timestamp)) ? current : attempt, completedAttempts[0]);
68
68
  const mostRecentAttemptWithCompletedCompleted = mostRecentAttemptWithCompleted
69
- && (0, exports.resolveCompletedForAttempt)(statements, activityIRI, mostRecentAttemptWithCompleted);
69
+ && (0, exports.resolveCompletedForAttempt)(statements, mostRecentAttemptWithCompleted, options === null || options === void 0 ? void 0 : options.activityIRI);
70
70
  /*
71
71
  * the structure allows for the possibility of multiple incomplete attempts.
72
72
  * the implementation can choose at its discretion to ignore the currentAttempt
@@ -83,13 +83,14 @@ const resolveActivityAttemptInfo = (statements, activityIRI, options) => {
83
83
  mostRecentAttemptWithCompletedCompleted,
84
84
  };
85
85
  };
86
- exports.resolveActivityAttemptInfo = resolveActivityAttemptInfo;
86
+ exports.resolveAttemptInfo = resolveAttemptInfo;
87
87
  /*
88
88
  * loads all statements (for this actor) that have the given activityIRI as the object.id or the context.contextActivities.parent.id
89
89
  *
90
90
  * note: if you filter on attempt you're only gonna get the `Attempted` statements from the child activities, subsequent child activity
91
- * statements would then have to be fetched using `loadStatementsForActivity(gateway, childActivityIRI, childAttemptStatementID)`. this
92
- * is because child activities could have multiple attempts under one attempt on the parent activity.
91
+ * statements would then have to be fetched using
92
+ * `gateway.getAllXapiStatements({ activity: childActivityIRI, registration: childAttemptStatementID })`.
93
+ * this is because child activities could have multiple attempts under one attempt on the parent activity.
93
94
  */
94
95
  const loadStatementsForActivityAndFirstChildren = (gateway, activityIRI, options) => {
95
96
  const { attempt, ...partialOptions } = options ? options : { attempt: undefined };
@@ -101,32 +102,10 @@ const loadStatementsForActivityAndFirstChildren = (gateway, activityIRI, options
101
102
  });
102
103
  };
103
104
  exports.loadStatementsForActivityAndFirstChildren = loadStatementsForActivityAndFirstChildren;
104
- /*
105
- * loads all statements (for this actor) that have the given parent attempt (registration)
106
- */
107
- const loadStatementsForAttempt = (gateway, attempt, options) => {
108
- return gateway.getAllXapiStatements({
109
- registration: attempt,
110
- ...(options ? options : {})
111
- });
112
- };
113
- exports.loadStatementsForAttempt = loadStatementsForAttempt;
114
- /*
115
- * loads all statements (for this actor) that have the given activityIRI as the object.id
116
- */
117
- const loadStatementsForActivity = (gateway, activityIRI, options) => {
118
- const { attempt, ...partialOptions } = options ? options : { attempt: undefined };
119
- const getOptions = attempt ? { registration: attempt, ...partialOptions } : partialOptions;
120
- return gateway.getAllXapiStatements({
121
- activity: activityIRI,
122
- ...getOptions,
123
- });
124
- };
125
- exports.loadStatementsForActivity = loadStatementsForActivity;
126
105
  const loadActivityAttemptInfo = async (gateway, activityIRI, options) => {
127
106
  const { parentActivityAttempt, ...partialOptions } = options ? options : { parentActivityAttempt: undefined };
128
- const loadOptions = parentActivityAttempt ? { attempt: parentActivityAttempt } : partialOptions;
129
- return (0, exports.resolveActivityAttemptInfo)(await (0, exports.loadStatementsForActivity)(gateway, activityIRI, loadOptions), activityIRI, options);
107
+ const loadOptions = parentActivityAttempt ? { ...partialOptions, registration: parentActivityAttempt } : partialOptions;
108
+ return (0, exports.resolveAttemptInfo)(await gateway.getAllXapiStatements({ ...loadOptions, activity: activityIRI }), { ...options, activityIRI });
130
109
  };
131
110
  exports.loadActivityAttemptInfo = loadActivityAttemptInfo;
132
111
  const createStatement = (verb, activity, attempt, parentActivityIRI) => {
@@ -86,19 +86,33 @@ const fileSystemLrsGateway = (initializer) => (configProvider) => (authProvider)
86
86
  await save;
87
87
  return statementsWithDefaults;
88
88
  };
89
- const getAllXapiStatements = async ({ user, anyUser, ...options }) => {
89
+ const getAllXapiStatements = async ({ user, anyUser, fetchUntil, ...options }) => {
90
90
  const authUser = await authProvider.getUser();
91
91
  await load;
92
- return (data || []).filter(statement => {
92
+ let filteredData = (data || []).filter(statement => {
93
93
  var _a, _b, _c, _d;
94
+ const statementDate = new Date(statement.timestamp);
95
+ const sinceDate = options.since ? new Date(options.since) : null;
96
+ const untilDate = options.until ? new Date(options.until) : null;
94
97
  return (anyUser === true || statement.actor.account.name === (user || (0, assertions_1.assertDefined)(authUser, new errors_1.UnauthorizedError()).uuid))
95
98
  && (!options.verb || statement.verb.id === options.verb)
96
99
  && (!options.registration || ((_a = statement.context) === null || _a === void 0 ? void 0 : _a.registration) === options.registration)
97
100
  && (!options.activity || (options.related_activities
98
101
  ? ((statement.object.id === options.activity && statement.object.objectType === 'Activity')
99
102
  || (!!((_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'))))
100
- : (statement.object.id === options.activity && statement.object.objectType === 'Activity')));
103
+ : (statement.object.id === options.activity && statement.object.objectType === 'Activity')))
104
+ && (!sinceDate || statementDate >= sinceDate)
105
+ && (!untilDate || statementDate <= untilDate);
101
106
  });
107
+ if (fetchUntil) {
108
+ for (let i = 0; i < filteredData.length; i += pageSize) {
109
+ if (fetchUntil(filteredData.slice(0, i + pageSize))) {
110
+ filteredData = filteredData.slice(0, i + pageSize);
111
+ break;
112
+ }
113
+ }
114
+ }
115
+ return filteredData;
102
116
  };
103
117
  const getMoreXapiStatements = async (more) => {
104
118
  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 {};
@@ -123,9 +123,9 @@ ${await response.text()}`);
123
123
  return formatGetXapiStatementsResponse(fetchXapiStatements(fetchParams));
124
124
  }
125
125
  };
126
- const getAllXapiStatements = async (params) => {
126
+ const getAllXapiStatements = async ({ fetchUntil, ...params }) => {
127
127
  const loadRemaining = async (result) => {
128
- if (!result.more) {
128
+ if (!result.more || (fetchUntil && fetchUntil(result.statements))) {
129
129
  return result.statements;
130
130
  }
131
131
  const { more, statements } = await getMoreXapiStatements(result.more);