@superbuilders/primer-tives 0.9.0 → 1.1.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.
Files changed (41) hide show
  1. package/README.md +298 -63
  2. package/dist/client/choice-state.d.ts.map +1 -1
  3. package/dist/client/extended-text-state.d.ts.map +1 -1
  4. package/dist/client/index.d.ts.map +1 -1
  5. package/dist/client/index.js +338 -179
  6. package/dist/client/index.js.map +13 -11
  7. package/dist/client/match-state.d.ts.map +1 -1
  8. package/dist/client/order-state.d.ts.map +1 -1
  9. package/dist/client/session.d.ts.map +1 -1
  10. package/dist/client/text-entry-state.d.ts.map +1 -1
  11. package/dist/client/transport.d.ts +1 -1
  12. package/dist/client/transport.d.ts.map +1 -1
  13. package/dist/client/types.d.ts +2 -115
  14. package/dist/client/types.d.ts.map +1 -1
  15. package/dist/contracts/index.d.ts +4 -0
  16. package/dist/contracts/index.d.ts.map +1 -0
  17. package/dist/contracts/index.js +305 -0
  18. package/dist/contracts/index.js.map +11 -0
  19. package/dist/contracts/pci-schemas.d.ts +25 -0
  20. package/dist/contracts/pci-schemas.d.ts.map +1 -0
  21. package/dist/contracts/types.d.ts +118 -0
  22. package/dist/contracts/types.d.ts.map +1 -0
  23. package/dist/contracts/validation.d.ts +132 -0
  24. package/dist/contracts/validation.d.ts.map +1 -0
  25. package/dist/errors.d.ts +2 -1
  26. package/dist/errors.d.ts.map +1 -1
  27. package/dist/errors.js +48 -0
  28. package/dist/errors.js.map +10 -0
  29. package/dist/server/create-server.d.ts +21 -19
  30. package/dist/server/create-server.d.ts.map +1 -1
  31. package/dist/server/exchange.d.ts +10 -5
  32. package/dist/server/exchange.d.ts.map +1 -1
  33. package/dist/server/hints.d.ts +25 -0
  34. package/dist/server/hints.d.ts.map +1 -0
  35. package/dist/server/index.d.ts +4 -3
  36. package/dist/server/index.d.ts.map +1 -1
  37. package/dist/server/index.js +355 -83
  38. package/dist/server/index.js.map +9 -8
  39. package/dist/server/students.d.ts +3 -5
  40. package/dist/server/students.d.ts.map +1 -1
  41. package/package.json +17 -4
@@ -1,6 +1,3 @@
1
- // src/server/exchange.ts
2
- import * as errors2 from "@superbuilders/errors";
3
-
4
1
  // src/errors.ts
5
2
  import * as errors from "@superbuilders/errors";
6
3
  var ErrNetwork = errors.new("network");
@@ -15,6 +12,7 @@ var ErrTimeout = errors.new("timeout");
15
12
  var ErrForbidden = errors.new("forbidden");
16
13
  var ErrNotFound = errors.new("not found");
17
14
  var ErrConflict = errors.new("conflict");
15
+ var ErrExternalAuthorityRequired = errors.new("external authority required");
18
16
  var ErrRateLimited = errors.new("rate limited");
19
17
  var ErrServiceUnavailable = errors.new("service unavailable");
20
18
  var ErrNotSerializable = errors.new("PrimerState is live in-memory state and must not be serialized or stored");
@@ -23,17 +21,60 @@ var ErrInvalidSecretKey = errors.new("invalid secret key");
23
21
  var ErrStudentNotFound = errors.new("student not found");
24
22
  var ErrUnsupportedGrade = errors.new("unsupported grade");
25
23
  var ErrTimebackUnavailable = errors.new("timeback unavailable");
26
-
27
24
  // src/server/exchange.ts
28
- var EXCHANGE_PATH = "/api/v0/auth/exchange";
29
- function isAbortError(err) {
30
- if (err instanceof DOMException && err.name === "AbortError") {
31
- return true;
25
+ import * as errors2 from "@superbuilders/errors";
26
+ var STUDENT_EXCHANGE_PATH = "/api/v0/auth/exchange";
27
+ var TIMEBACK_EXCHANGE_PATH = "/api/v0/auth/exchange/timeback";
28
+ function isObjectRecord(value) {
29
+ return typeof value === "object" && value !== null;
30
+ }
31
+ function isFiniteNumber(value) {
32
+ return typeof value === "number" && Number.isFinite(value);
33
+ }
34
+ function toExchangeErrorBody(data) {
35
+ if (!isObjectRecord(data)) {
36
+ return {};
32
37
  }
33
- if (err instanceof DOMException && err.name === "TimeoutError") {
34
- return true;
38
+ return typeof data.error === "string" ? { error: data.error } : {};
39
+ }
40
+ function parseSessionTokenSuccessBody(data) {
41
+ if (!isObjectRecord(data)) {
42
+ return;
35
43
  }
36
- return false;
44
+ if (typeof data.access_token !== "string") {
45
+ return;
46
+ }
47
+ if (data.token_type !== "Bearer") {
48
+ return;
49
+ }
50
+ if (!isFiniteNumber(data.expires_in)) {
51
+ return;
52
+ }
53
+ if (typeof data.scope !== "string") {
54
+ return;
55
+ }
56
+ return {
57
+ access_token: data.access_token,
58
+ token_type: data.token_type,
59
+ expires_in: data.expires_in,
60
+ scope: data.scope
61
+ };
62
+ }
63
+ function parseTimebackExchangeSuccessBody(data) {
64
+ const session = parseSessionTokenSuccessBody(data);
65
+ if (!session || !isObjectRecord(data) || typeof data.student_id !== "string") {
66
+ return;
67
+ }
68
+ return {
69
+ student_id: data.student_id,
70
+ access_token: session.access_token,
71
+ token_type: session.token_type,
72
+ expires_in: session.expires_in,
73
+ scope: session.scope
74
+ };
75
+ }
76
+ function isAbortError(err) {
77
+ return err.name === "AbortError" || err.name === "TimeoutError";
37
78
  }
38
79
  function mapBadRequest(body) {
39
80
  if (body.error === "unsupported_grade") {
@@ -51,12 +92,15 @@ function httpSentinel(status, body) {
51
92
  if (status === 404) {
52
93
  return ErrStudentNotFound;
53
94
  }
95
+ if (status === 409) {
96
+ if (body.error === "external_authority_required") {
97
+ return ErrExternalAuthorityRequired;
98
+ }
99
+ return ErrConflict;
100
+ }
54
101
  if (status === 502) {
55
102
  return ErrTimebackUnavailable;
56
103
  }
57
- if (status >= 500 && status < 600) {
58
- return ErrServerError;
59
- }
60
104
  return ErrServerError;
61
105
  }
62
106
  async function readErrorBody(res) {
@@ -68,70 +112,155 @@ async function readErrorBody(res) {
68
112
  if (!parsed.ok) {
69
113
  return {};
70
114
  }
71
- return parsed.data;
115
+ return toExchangeErrorBody(parsed.data);
72
116
  }
73
- async function exchangeToken(config, provider, studentId) {
74
- const log = config.logger;
117
+ async function sendExchangeRequest(config, path, body, logContext) {
118
+ const logger = config.logger;
75
119
  const fetchFn = config.fetch ? config.fetch : globalThis.fetch;
76
120
  const signal = config.abort ? config.abort.signal : undefined;
77
- log?.debug("exchange request", { provider });
78
- const url = `${config.origin}${EXCHANGE_PATH}`;
121
+ const url = `${config.origin}${path}`;
79
122
  const fetchResult = await fetchFn(url, {
80
123
  method: "POST",
81
124
  headers: {
82
125
  "Content-Type": "application/json",
83
126
  Authorization: `Bearer ${config.secretKey}`
84
127
  },
85
- body: JSON.stringify({ provider, student_id: studentId }),
128
+ body: JSON.stringify(body),
86
129
  signal
87
- }).then(function ok(r) {
88
- return { ok: true, response: r };
130
+ }).then(function ok(response) {
131
+ return { ok: true, response };
89
132
  }, function fail(err) {
90
133
  return { ok: false, error: err };
91
134
  });
92
135
  if (!fetchResult.ok) {
93
136
  if (isAbortError(fetchResult.error)) {
94
- log?.error("exchange timeout", { provider });
137
+ logger.error("exchange timeout", { path, ...logContext });
95
138
  throw errors2.wrap(ErrTimeout, fetchResult.error.message);
96
139
  }
97
- log?.error("exchange network error", { provider, error: fetchResult.error });
140
+ logger.error("exchange network error", { path, ...logContext, error: fetchResult.error });
98
141
  throw errors2.wrap(ErrNetwork, fetchResult.error.message);
99
142
  }
100
- const res = fetchResult.response;
101
- if (!res.ok) {
102
- const body = await readErrorBody(res);
103
- const sentinel = httpSentinel(res.status, body);
104
- const detail = body.error ? `${res.status} ${body.error}` : `${res.status}`;
105
- log?.error("exchange http error", { provider, status: res.status, body });
106
- throw errors2.wrap(sentinel, detail);
143
+ return fetchResult.response;
144
+ }
145
+ async function parseSessionTokenSuccess(config, res, logContext) {
146
+ const logger = config.logger;
147
+ const jsonResult = await res.json().then(function ok(data) {
148
+ return { ok: true, data };
149
+ }, function fail(err) {
150
+ return { ok: false, error: err };
151
+ });
152
+ if (!jsonResult.ok) {
153
+ logger.error("exchange json parse failed", { ...logContext, error: jsonResult.error });
154
+ throw errors2.wrap(ErrJsonParse, jsonResult.error.message);
107
155
  }
156
+ const body = parseSessionTokenSuccessBody(jsonResult.data);
157
+ if (!body) {
158
+ logger.error("exchange success body had invalid shape", {
159
+ ...logContext,
160
+ body: jsonResult.data
161
+ });
162
+ throw errors2.wrap(ErrJsonParse, "exchange success body had invalid shape");
163
+ }
164
+ logger.debug("exchange success", {
165
+ ...logContext,
166
+ expiresIn: body.expires_in
167
+ });
168
+ return {
169
+ accessToken: body.access_token,
170
+ expiresInSeconds: body.expires_in
171
+ };
172
+ }
173
+ async function parseTimebackSessionSuccess(config, res, sourcedId) {
174
+ const logger = config.logger;
108
175
  const jsonResult = await res.json().then(function ok(data) {
109
176
  return { ok: true, data };
110
177
  }, function fail(err) {
111
178
  return { ok: false, error: err };
112
179
  });
113
180
  if (!jsonResult.ok) {
114
- log?.error("exchange json parse failed", { provider, error: jsonResult.error });
181
+ logger.error("timeback exchange json parse failed", { sourcedId, error: jsonResult.error });
115
182
  throw errors2.wrap(ErrJsonParse, jsonResult.error.message);
116
183
  }
117
- log?.debug("exchange success", { provider, expiresIn: jsonResult.data.expires_in });
184
+ const body = parseTimebackExchangeSuccessBody(jsonResult.data);
185
+ if (!body) {
186
+ logger.error("timeback exchange success body had invalid shape", {
187
+ sourcedId,
188
+ body: jsonResult.data
189
+ });
190
+ throw errors2.wrap(ErrJsonParse, "timeback exchange success body had invalid shape");
191
+ }
192
+ logger.debug("timeback exchange success", {
193
+ sourcedId,
194
+ studentId: body.student_id,
195
+ expiresIn: body.expires_in
196
+ });
118
197
  return {
119
- accessToken: jsonResult.data.access_token,
120
- expiresInSeconds: jsonResult.data.expires_in
198
+ studentId: body.student_id,
199
+ accessToken: body.access_token,
200
+ expiresInSeconds: body.expires_in
121
201
  };
122
202
  }
203
+ async function exchangeStudent(config, studentId) {
204
+ const logger = config.logger;
205
+ logger.debug("exchange student request", { studentId });
206
+ const res = await sendExchangeRequest(config, STUDENT_EXCHANGE_PATH, { student_id: studentId }, { studentId, exchangeKind: "student_id" });
207
+ if (!res.ok) {
208
+ const body = await readErrorBody(res);
209
+ const sentinel = httpSentinel(res.status, body);
210
+ const detail = body.error ? `${res.status} ${body.error}` : `${res.status}`;
211
+ logger.error("exchange student http error", { status: res.status, body, studentId });
212
+ throw errors2.wrap(sentinel, detail);
213
+ }
214
+ return parseSessionTokenSuccess(config, res, { studentId, exchangeKind: "student_id" });
215
+ }
216
+ async function exchangeTimebackStudent(config, sourcedId) {
217
+ const logger = config.logger;
218
+ logger.debug("exchange timeback student request", { sourcedId });
219
+ const res = await sendExchangeRequest(config, TIMEBACK_EXCHANGE_PATH, { sourced_id: sourcedId }, { sourcedId, exchangeKind: "timeback" });
220
+ if (!res.ok) {
221
+ const body = await readErrorBody(res);
222
+ const sentinel = httpSentinel(res.status, body);
223
+ const detail = body.error ? `${res.status} ${body.error}` : `${res.status}`;
224
+ logger.error("exchange timeback student http error", { status: res.status, body, sourcedId });
225
+ throw errors2.wrap(sentinel, detail);
226
+ }
227
+ return parseTimebackSessionSuccess(config, res, sourcedId);
228
+ }
123
229
 
124
- // src/server/students.ts
230
+ // src/server/hints.ts
125
231
  import * as errors3 from "@superbuilders/errors";
232
+
233
+ // src/grade-level.ts
234
+ var GRADE_LEVELS = ["K", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"];
235
+
236
+ // src/server/hints.ts
126
237
  var STUDENTS_PATH = "/api/v0/students";
127
- function isAbortError2(err) {
128
- if (err instanceof DOMException && err.name === "AbortError") {
129
- return true;
238
+ function isObjectRecord2(value) {
239
+ return typeof value === "object" && value !== null;
240
+ }
241
+ function toHintsErrorBody(data) {
242
+ if (!isObjectRecord2(data)) {
243
+ return {};
244
+ }
245
+ return typeof data.error === "string" ? { error: data.error } : {};
246
+ }
247
+ function parseHintsSuccess(data) {
248
+ if (!isObjectRecord2(data)) {
249
+ return;
130
250
  }
131
- if (err instanceof DOMException && err.name === "TimeoutError") {
132
- return true;
251
+ if (typeof data.student_id !== "string") {
252
+ return;
133
253
  }
134
- return false;
254
+ if (data.grade_level !== null && typeof data.grade_level !== "string") {
255
+ return;
256
+ }
257
+ return {
258
+ student_id: data.student_id,
259
+ grade_level: data.grade_level
260
+ };
261
+ }
262
+ function isAbortError2(err) {
263
+ return err.name === "AbortError" || err.name === "TimeoutError";
135
264
  }
136
265
  function httpSentinel2(status) {
137
266
  if (status === 400) {
@@ -154,94 +283,235 @@ async function readErrorBody2(res) {
154
283
  if (!parsed.ok) {
155
284
  return {};
156
285
  }
157
- return parsed.data;
286
+ return toHintsErrorBody(parsed.data);
287
+ }
288
+ function buildRequestBody(hints) {
289
+ const body = {};
290
+ if (hints.gradeLevel !== undefined) {
291
+ body.grade_level = hints.gradeLevel;
292
+ }
293
+ return JSON.stringify(body);
158
294
  }
159
- async function sendStudentsRequest(config, path, method, body) {
160
- const log = config.logger;
295
+ async function sendSetHintsRequest(config, studentId, hints) {
296
+ const logger = config.logger;
161
297
  const fetchFn = config.fetch ? config.fetch : globalThis.fetch;
162
298
  const signal = config.abort ? config.abort.signal : undefined;
163
- const url = `${config.origin}${path}`;
299
+ const url = `${config.origin}${STUDENTS_PATH}/${encodeURIComponent(studentId)}/hints`;
164
300
  const fetchResult = await fetchFn(url, {
165
- method,
301
+ method: "PATCH",
166
302
  headers: {
167
- "Content-Type": "application/json",
168
- Authorization: `Bearer ${config.secretKey}`
303
+ Authorization: `Bearer ${config.secretKey}`,
304
+ "Content-Type": "application/json"
169
305
  },
170
- body: JSON.stringify(body),
306
+ body: buildRequestBody(hints),
171
307
  signal
172
- }).then(function ok(r) {
173
- return { ok: true, response: r };
308
+ }).then(function ok(response) {
309
+ return { ok: true, response };
174
310
  }, function fail(err) {
175
311
  return { ok: false, error: err };
176
312
  });
177
313
  if (!fetchResult.ok) {
178
314
  if (isAbortError2(fetchResult.error)) {
179
- log?.error("students timeout", { path, method });
315
+ logger.error("set student hints timeout", { studentId });
180
316
  throw errors3.wrap(ErrTimeout, fetchResult.error.message);
181
317
  }
182
- log?.error("students network error", { path, method, error: fetchResult.error });
318
+ logger.error("set student hints network error", {
319
+ studentId,
320
+ error: fetchResult.error
321
+ });
183
322
  throw errors3.wrap(ErrNetwork, fetchResult.error.message);
184
323
  }
185
324
  return fetchResult.response;
186
325
  }
187
- async function createStudent(config, gradeLevel) {
188
- const log = config.logger;
189
- log?.debug("create student request", { gradeLevel });
190
- const res = await sendStudentsRequest(config, STUDENTS_PATH, "POST", {
191
- grade_level: gradeLevel
326
+ async function parseHintsSuccessResponse(config, res) {
327
+ const logger = config.logger;
328
+ const jsonResult = await res.json().then(function ok(data) {
329
+ return { ok: true, data };
330
+ }, function fail(err) {
331
+ return { ok: false, error: err };
192
332
  });
333
+ if (!jsonResult.ok) {
334
+ logger.error("set hints response parse failed", { error: jsonResult.error });
335
+ throw errors3.wrap(ErrJsonParse, jsonResult.error.message);
336
+ }
337
+ const body = parseHintsSuccess(jsonResult.data);
338
+ if (!body) {
339
+ logger.error("set hints response had invalid shape", { body: jsonResult.data });
340
+ throw errors3.wrap(ErrJsonParse, "set hints success body had invalid shape");
341
+ }
342
+ logger.debug("set hints response success", {
343
+ studentId: body.student_id,
344
+ gradeLevel: body.grade_level
345
+ });
346
+ return {
347
+ studentId: body.student_id,
348
+ gradeLevel: coerceGradeLevel(body.grade_level)
349
+ };
350
+ }
351
+ function coerceGradeLevel(value) {
352
+ if (value === null) {
353
+ return null;
354
+ }
355
+ for (const g of GRADE_LEVELS) {
356
+ if (g === value) {
357
+ return g;
358
+ }
359
+ }
360
+ return null;
361
+ }
362
+ async function setStudentHints(config, studentId, hints) {
363
+ const logger = config.logger;
364
+ logger.debug("set student hints request", { studentId, hints });
365
+ const res = await sendSetHintsRequest(config, studentId, hints);
193
366
  if (!res.ok) {
194
367
  const body = await readErrorBody2(res);
195
368
  const sentinel = httpSentinel2(res.status);
196
369
  const detail = body.error ? `${res.status} ${body.error}` : `${res.status}`;
197
- log?.error("create student http error", { status: res.status, body });
370
+ logger.error("set student hints http error", {
371
+ studentId,
372
+ status: res.status,
373
+ body
374
+ });
198
375
  throw errors3.wrap(sentinel, detail);
199
376
  }
377
+ return parseHintsSuccessResponse(config, res);
378
+ }
379
+
380
+ // src/server/students.ts
381
+ import * as errors4 from "@superbuilders/errors";
382
+ var STUDENTS_PATH2 = "/api/v0/students";
383
+ function isObjectRecord3(value) {
384
+ return typeof value === "object" && value !== null;
385
+ }
386
+ function toStudentsErrorBody(data) {
387
+ if (!isObjectRecord3(data)) {
388
+ return {};
389
+ }
390
+ return typeof data.error === "string" ? { error: data.error } : {};
391
+ }
392
+ function parseStudentIdSuccessBody(data) {
393
+ if (!isObjectRecord3(data)) {
394
+ return;
395
+ }
396
+ if (typeof data.student_id !== "string") {
397
+ return;
398
+ }
399
+ return { student_id: data.student_id };
400
+ }
401
+ function isAbortError3(err) {
402
+ return err.name === "AbortError" || err.name === "TimeoutError";
403
+ }
404
+ function httpSentinel3(status) {
405
+ if (status === 400) {
406
+ return ErrBadRequest;
407
+ }
408
+ if (status === 401) {
409
+ return ErrInvalidSecretKey;
410
+ }
411
+ if (status === 409) {
412
+ return ErrConflict;
413
+ }
414
+ return ErrServerError;
415
+ }
416
+ async function readErrorBody3(res) {
417
+ const parsed = await res.json().then(function ok(data) {
418
+ return { ok: true, data };
419
+ }, function fail() {
420
+ return { ok: false };
421
+ });
422
+ if (!parsed.ok) {
423
+ return {};
424
+ }
425
+ return toStudentsErrorBody(parsed.data);
426
+ }
427
+ async function sendCreateStudentRequest(config) {
428
+ const logger = config.logger;
429
+ const fetchFn = config.fetch ? config.fetch : globalThis.fetch;
430
+ const signal = config.abort ? config.abort.signal : undefined;
431
+ const url = `${config.origin}${STUDENTS_PATH2}`;
432
+ const fetchResult = await fetchFn(url, {
433
+ method: "POST",
434
+ headers: {
435
+ Authorization: `Bearer ${config.secretKey}`
436
+ },
437
+ signal
438
+ }).then(function ok(response) {
439
+ return { ok: true, response };
440
+ }, function fail(err) {
441
+ return { ok: false, error: err };
442
+ });
443
+ if (!fetchResult.ok) {
444
+ if (isAbortError3(fetchResult.error)) {
445
+ logger.error("students timeout", { path: STUDENTS_PATH2 });
446
+ throw errors4.wrap(ErrTimeout, fetchResult.error.message);
447
+ }
448
+ logger.error("students network error", {
449
+ path: STUDENTS_PATH2,
450
+ error: fetchResult.error
451
+ });
452
+ throw errors4.wrap(ErrNetwork, fetchResult.error.message);
453
+ }
454
+ return fetchResult.response;
455
+ }
456
+ async function parseStudentIdSuccess(config, res) {
457
+ const logger = config.logger;
200
458
  const jsonResult = await res.json().then(function ok(data) {
201
459
  return { ok: true, data };
202
460
  }, function fail(err) {
203
461
  return { ok: false, error: err };
204
462
  });
205
463
  if (!jsonResult.ok) {
206
- log?.error("create student json parse failed", { error: jsonResult.error });
207
- throw errors3.wrap(ErrJsonParse, jsonResult.error.message);
464
+ logger.error("student id response parse failed", {
465
+ operation: "create student",
466
+ error: jsonResult.error
467
+ });
468
+ throw errors4.wrap(ErrJsonParse, jsonResult.error.message);
469
+ }
470
+ const body = parseStudentIdSuccessBody(jsonResult.data);
471
+ if (!body) {
472
+ logger.error("student id response had invalid shape", {
473
+ operation: "create student",
474
+ body: jsonResult.data
475
+ });
476
+ throw errors4.wrap(ErrJsonParse, "create student success body had invalid shape");
208
477
  }
209
- log?.debug("create student success", { studentId: jsonResult.data.student_id });
210
- return jsonResult.data.student_id;
478
+ logger.debug("student id response success", {
479
+ operation: "create student",
480
+ studentId: body.student_id
481
+ });
482
+ return body.student_id;
211
483
  }
212
- async function updateStudentGradeLevel(config, studentId, gradeLevel) {
213
- const log = config.logger;
214
- log?.debug("update student grade request", { studentId, gradeLevel });
215
- const res = await sendStudentsRequest(config, `${STUDENTS_PATH}/${encodeURIComponent(studentId)}`, "PATCH", { gradeLevel });
484
+ async function createStudent(config) {
485
+ const logger = config.logger;
486
+ logger.debug("create student request");
487
+ const res = await sendCreateStudentRequest(config);
216
488
  if (!res.ok) {
217
- const body = await readErrorBody2(res);
218
- const sentinel = httpSentinel2(res.status);
489
+ const body = await readErrorBody3(res);
490
+ const sentinel = httpSentinel3(res.status);
219
491
  const detail = body.error ? `${res.status} ${body.error}` : `${res.status}`;
220
- log?.error("update student http error", { status: res.status, body });
221
- throw errors3.wrap(sentinel, detail);
492
+ logger.error("create student http error", { status: res.status, body });
493
+ throw errors4.wrap(sentinel, detail);
222
494
  }
223
- log?.debug("update student success", { studentId });
495
+ return parseStudentIdSuccess(config, res);
224
496
  }
225
497
 
226
498
  // src/server/create-server.ts
227
499
  function createPrimerServer(config) {
228
500
  return {
229
- createNativeStudent(gradeLevel) {
230
- return createStudent(config, gradeLevel);
501
+ createStudent() {
502
+ return createStudent(config);
231
503
  },
232
- updateNativeStudentGradeLevel(studentId, gradeLevel) {
233
- return updateStudentGradeLevel(config, studentId, gradeLevel);
504
+ setStudentHints(studentId, hints) {
505
+ return setStudentHints(config, studentId, hints);
234
506
  },
235
- exchangeNativeStudentForAccessToken(studentId) {
236
- return exchangeToken(config, "native", studentId);
507
+ exchangeStudentForAccessToken(studentId) {
508
+ return exchangeStudent(config, studentId);
237
509
  },
238
510
  exchangeTimebackStudentForAccessToken(sourcedId) {
239
- return exchangeToken(config, "timeback", sourcedId);
511
+ return exchangeTimebackStudent(config, sourcedId);
240
512
  }
241
513
  };
242
514
  }
243
- // src/grade-level.ts
244
- var GRADE_LEVELS = ["K", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"];
245
515
  export {
246
516
  createPrimerServer,
247
517
  GRADE_LEVELS,
@@ -253,7 +523,9 @@ export {
253
523
  ErrNetwork,
254
524
  ErrJsonParse,
255
525
  ErrInvalidSecretKey,
526
+ ErrExternalAuthorityRequired,
527
+ ErrConflict,
256
528
  ErrBadRequest
257
529
  };
258
530
 
259
- //# debugId=3128BCEC46D85F5764756E2164756E21
531
+ //# debugId=36162738F428CAE464756E2164756E21