@openstax/ts-utils 1.40.2 → 1.41.2

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 (31) hide show
  1. package/dist/cjs/services/accountsGateway/index.d.ts +3 -0
  2. package/dist/cjs/services/accountsGateway/index.js +1 -0
  3. package/dist/cjs/services/documentStore/dynamoEncoding.js +2 -2
  4. package/dist/cjs/services/documentStore/unversioned/file-system.d.ts +0 -1
  5. package/dist/cjs/services/documentStore/unversioned/file-system.js +0 -19
  6. package/dist/cjs/services/documentStore/versioned/file-system.d.ts +0 -1
  7. package/dist/cjs/services/documentStore/versioned/file-system.js +1 -12
  8. package/dist/cjs/services/lrsGateway/batching.d.ts +46 -0
  9. package/dist/cjs/services/lrsGateway/batching.js +106 -0
  10. package/dist/cjs/services/lrsGateway/file-system.js +52 -2
  11. package/dist/cjs/services/lrsGateway/index.d.ts +13 -0
  12. package/dist/cjs/services/lrsGateway/index.js +151 -55
  13. package/dist/cjs/tsconfig.without-specs.cjs.tsbuildinfo +1 -1
  14. package/dist/esm/services/accountsGateway/index.d.ts +3 -0
  15. package/dist/esm/services/accountsGateway/index.js +1 -0
  16. package/dist/esm/services/documentStore/dynamoEncoding.js +2 -2
  17. package/dist/esm/services/documentStore/unversioned/file-system.d.ts +0 -1
  18. package/dist/esm/services/documentStore/unversioned/file-system.js +0 -19
  19. package/dist/esm/services/documentStore/versioned/file-system.d.ts +0 -1
  20. package/dist/esm/services/documentStore/versioned/file-system.js +1 -12
  21. package/dist/esm/services/lrsGateway/batching.d.ts +46 -0
  22. package/dist/esm/services/lrsGateway/batching.js +102 -0
  23. package/dist/esm/services/lrsGateway/file-system.js +52 -2
  24. package/dist/esm/services/lrsGateway/index.d.ts +13 -0
  25. package/dist/esm/services/lrsGateway/index.js +151 -22
  26. package/dist/esm/tsconfig.without-specs.esm.tsbuildinfo +1 -1
  27. package/package.json +1 -1
  28. package/dist/cjs/services/documentStore/fileSystemAssert.d.ts +0 -1
  29. package/dist/cjs/services/documentStore/fileSystemAssert.js +0 -14
  30. package/dist/esm/services/documentStore/fileSystemAssert.d.ts +0 -1
  31. package/dist/esm/services/documentStore/fileSystemAssert.js +0 -10
@@ -1,40 +1,6 @@
1
1
  "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
2
  Object.defineProperty(exports, "__esModule", { value: true });
36
3
  exports.lrsGateway = void 0;
37
- const queryString = __importStar(require("query-string"));
38
4
  const __1 = require("../..");
39
5
  const assertions_1 = require("../../assertions");
40
6
  const config_1 = require("../../config");
@@ -44,6 +10,7 @@ const guards_1 = require("../../guards");
44
10
  const helpers_1 = require("../../misc/helpers");
45
11
  const routing_1 = require("../../routing");
46
12
  const addStatementDefaultFields_1 = require("./addStatementDefaultFields");
13
+ const batching_1 = require("./batching");
47
14
  const lrsGateway = (initializer) => (configProvider) => {
48
15
  const config = configProvider[(0, guards_1.ifDefined)(initializer.configSpace, 'lrs')];
49
16
  const lrsHost = (0, __1.once)(() => (0, config_1.resolveConfigValue)(config.lrsHost));
@@ -55,20 +22,51 @@ const lrsGateway = (initializer) => (configProvider) => {
55
22
  wait: 1000,
56
23
  status: [502]
57
24
  });
25
+ // Initialize request batcher if batching is enabled
26
+ const enableBatching = initializer.enableBatching !== false;
27
+ const batcher = new batching_1.RequestBatcher(fetcher, {
28
+ batchEndpoint: '/api/batch',
29
+ getAuthHeader: lrsAuthorization,
30
+ getHost: lrsHost,
31
+ });
32
+ /**
33
+ * Makes a fetch request, optionally through the request batcher.
34
+ * Automatically batches concurrent requests when batching is enabled.
35
+ */
36
+ const makeFetch = async (options) => {
37
+ return enableBatching ? batcher.queueRequest(options) : batcher.singleRequest(options);
38
+ };
39
+ /**
40
+ * Formats an agent parameter into a full XapiAgent object.
41
+ * Accepts either a UUID string or a full XapiAgent object.
42
+ */
43
+ const formatAgent = (agent) => {
44
+ if (typeof agent === 'string') {
45
+ return {
46
+ objectType: 'Agent',
47
+ account: {
48
+ homePage: 'https://openstax.org',
49
+ name: agent,
50
+ },
51
+ };
52
+ }
53
+ return agent;
54
+ };
58
55
  // Note: This method actually uses POST
59
56
  const putXapiStatements = async (statements, user) => {
60
57
  const userObj = user
61
58
  ? { uuid: user }
62
59
  : (0, assertions_1.assertDefined)(await authProvider.getUser(), new errors_1.UnauthorizedError);
63
60
  const statementsWithDefaults = statements.map(statement => (0, addStatementDefaultFields_1.addStatementDefaultFields)(statement, userObj));
64
- const response = await fetcher((await lrsHost()).replace(/\/+$/, '') + '/data/xAPI/statements', {
65
- body: JSON.stringify(statementsWithDefaults),
61
+ const response = await makeFetch({
62
+ path: '/data/xAPI/statements',
63
+ method: routing_1.METHOD.POST,
66
64
  headers: {
67
65
  Authorization: await lrsAuthorization(),
68
66
  'Content-Type': 'application/json',
69
67
  'X-Experience-API-Version': '1.0.0',
70
68
  },
71
- method: routing_1.METHOD.POST,
69
+ body: JSON.stringify(statementsWithDefaults),
72
70
  });
73
71
  if (![200, 201].includes(response.status)) {
74
72
  throw new Error(`Unexpected LRS POST statements response code ${response.status} with body:
@@ -88,29 +86,51 @@ ${await response.text()}`);
88
86
  }
89
87
  return response.json();
90
88
  };
91
- const getMoreXapiStatements = async (more) => fetcher((await lrsHost()).replace(/\/+$/, '') + more, {
92
- headers: {
93
- Authorization: await lrsAuthorization(),
94
- 'X-Experience-API-Version': '1.0.0',
95
- },
96
- }).then(formatGetXapiStatementsResponse);
97
- const fetchXapiStatements = async ({ user, anyUser, ...options }) => fetcher((await lrsHost()).replace(/\/+$/, '') + '/data/xAPI/statements?' + queryString.stringify({
98
- ...options,
99
- ...(anyUser === true ? {} : {
100
- agent: JSON.stringify({
89
+ const getMoreXapiStatements = async (more) => {
90
+ // 'more' is a full path with query string, so we don't use makeFetch batching here
91
+ const host = await lrsHost();
92
+ return fetcher(host.replace(/\/+$/, '') + more, {
93
+ headers: {
94
+ Authorization: await lrsAuthorization(),
95
+ 'X-Experience-API-Version': '1.0.0',
96
+ },
97
+ }).then(formatGetXapiStatementsResponse);
98
+ };
99
+ const fetchXapiStatements = async ({ user, anyUser, ...options }) => {
100
+ const queryParams = {};
101
+ // Add filter params
102
+ if (options.verb)
103
+ queryParams.verb = options.verb;
104
+ if (options.activity)
105
+ queryParams.activity = options.activity;
106
+ if (options.registration)
107
+ queryParams.registration = options.registration;
108
+ if (options.related_activities !== undefined)
109
+ queryParams.related_activities = String(options.related_activities);
110
+ if (options.since)
111
+ queryParams.since = options.since;
112
+ if (options.until)
113
+ queryParams.until = options.until;
114
+ // Add agent unless anyUser is true
115
+ if (anyUser !== true) {
116
+ queryParams.agent = JSON.stringify({
101
117
  account: {
102
118
  homePage: 'https://openstax.org',
103
119
  name: user || (0, assertions_1.assertDefined)(await authProvider.getUser(), new errors_1.UnauthorizedError()).uuid,
104
120
  },
105
121
  objectType: 'Agent',
106
- }),
107
- })
108
- }), {
109
- headers: {
110
- Authorization: await lrsAuthorization(),
111
- 'X-Experience-API-Version': '1.0.0',
112
- },
113
- });
122
+ });
123
+ }
124
+ return makeFetch({
125
+ path: '/data/xAPI/statements',
126
+ method: routing_1.METHOD.GET,
127
+ queryParams,
128
+ headers: {
129
+ Authorization: await lrsAuthorization(),
130
+ 'X-Experience-API-Version': '1.0.0',
131
+ },
132
+ });
133
+ };
114
134
  const getXapiStatements = async (params) => {
115
135
  const { ensureSync, ...fetchParams } = params;
116
136
  if (ensureSync) {
@@ -139,11 +159,87 @@ ${await response.text()}`);
139
159
  };
140
160
  return loadRemaining(await getXapiStatements(params));
141
161
  };
162
+ /**
163
+ * Get a single state document from the xAPI State API.
164
+ *
165
+ * @param activityId - The activity ID
166
+ * @param agent - The agent (UUID string or full XapiAgent object)
167
+ * @param stateId - The state document identifier
168
+ * @param registration - Optional registration UUID
169
+ * @returns The state document as a JSON object, or null if not found
170
+ */
171
+ const getState = async (activityId, agent, stateId, registration) => {
172
+ const agentObj = formatAgent(agent);
173
+ const queryParams = {
174
+ activityId,
175
+ agent: JSON.stringify(agentObj),
176
+ stateId,
177
+ };
178
+ if (registration) {
179
+ queryParams.registration = registration;
180
+ }
181
+ const response = await makeFetch({
182
+ path: '/data/xAPI/activities/state',
183
+ method: routing_1.METHOD.GET,
184
+ queryParams,
185
+ headers: {
186
+ Authorization: await lrsAuthorization(),
187
+ 'X-Experience-API-Version': '1.0.0',
188
+ },
189
+ });
190
+ if (response.status === 404) {
191
+ return null;
192
+ }
193
+ if (response.status !== 200) {
194
+ throw new Error(`Unexpected LRS GET state response code ${response.status} with body:
195
+
196
+ ${await response.text()}`);
197
+ }
198
+ return response.json();
199
+ };
200
+ /**
201
+ * Create or update a state document in the xAPI State API.
202
+ *
203
+ * @param activityId - The activity ID
204
+ * @param agent - The agent (UUID string or full XapiAgent object)
205
+ * @param stateId - The state document identifier
206
+ * @param body - The state document content (JSON object)
207
+ * @param registration - Optional registration UUID
208
+ */
209
+ const setState = async (activityId, agent, stateId, body, registration) => {
210
+ const agentObj = formatAgent(agent);
211
+ const queryParams = {
212
+ activityId,
213
+ agent: JSON.stringify(agentObj),
214
+ stateId,
215
+ };
216
+ if (registration) {
217
+ queryParams.registration = registration;
218
+ }
219
+ const response = await makeFetch({
220
+ path: '/data/xAPI/activities/state',
221
+ method: routing_1.METHOD.PUT,
222
+ queryParams,
223
+ headers: {
224
+ Authorization: await lrsAuthorization(),
225
+ 'Content-Type': 'application/json',
226
+ 'X-Experience-API-Version': '1.0.0',
227
+ },
228
+ body: JSON.stringify(body),
229
+ });
230
+ if (response.status !== 204) {
231
+ throw new Error(`Unexpected LRS PUT state response code ${response.status} with body:
232
+
233
+ ${await response.text()}`);
234
+ }
235
+ };
142
236
  return {
143
237
  putXapiStatements,
144
238
  getXapiStatements,
145
239
  getMoreXapiStatements,
146
240
  getAllXapiStatements,
241
+ getState,
242
+ setState,
147
243
  };
148
244
  };
149
245
  };