@superbuilders/primer-tives 5.1.0 → 6.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -19,7 +19,7 @@ bun add @superbuilders/primer-tives
19
19
 
20
20
  ## Version
21
21
 
22
- The current SDK version is `5.1.0`.
22
+ The current SDK version is `6.0.0`.
23
23
 
24
24
  ## Entrypoints
25
25
 
@@ -50,6 +50,7 @@ import {
50
50
  const options = {
51
51
  publishableKey: "pk_...",
52
52
  subject: "math",
53
+ mode: "drill",
53
54
  supportedPcis: ["urn:primer:pci:fraction-input"],
54
55
  logger
55
56
  } satisfies PrimerOptionsWithManagedAuth<"math", readonly ["urn:primer:pci:fraction-input"]>
@@ -57,6 +58,19 @@ const options = {
57
58
  let state = await start(options)
58
59
  ```
59
60
 
61
+ Primer exposes drill and curriculum as separate product surfaces behind the same SDK state machine. Version 6 callers must pass `mode: "drill"` for practice drill progression or `mode: "curriculum"` for curriculum DAG progression. Older clients that omit mode continue to enter drill behavior on the server.
62
+
63
+ ```ts
64
+ const options = {
65
+ publishableKey: "pk_...",
66
+ subject: "science",
67
+ mode: "curriculum",
68
+ logger
69
+ } satisfies PrimerOptionsWithManagedAuth<"science">
70
+
71
+ let state = await start(options)
72
+ ```
73
+
60
74
  If your application already has a learner access token, pass it directly. `start` uses that token for the learning runtime.
61
75
 
62
76
  ```ts
@@ -64,6 +78,7 @@ const options = {
64
78
  publishableKey: "pk_...",
65
79
  accessToken,
66
80
  subject: "math",
81
+ mode: "drill",
67
82
  supportedPcis: ["urn:primer:pci:fraction-input"],
68
83
  logger
69
84
  } satisfies PrimerOptionsWithAccessToken<"math", readonly ["urn:primer:pci:fraction-input"]>
@@ -98,6 +113,7 @@ Vocabulary and science currently have no required PCI capabilities, so `supporte
98
113
  const options = {
99
114
  publishableKey: "pk_...",
100
115
  subject: "vocabulary",
116
+ mode: "drill",
101
117
  logger
102
118
  } satisfies PrimerOptionsWithManagedAuth<"vocabulary">
103
119
 
@@ -109,6 +125,7 @@ Omitting `subject` means the SDK asks Primer for the all-subject runtime scope.
109
125
  ```ts
110
126
  const options = {
111
127
  publishableKey: "pk_...",
128
+ mode: "drill",
112
129
  supportedPcis: ["urn:primer:pci:fraction-input"],
113
130
  logger
114
131
  } satisfies PrimerOptionsWithManagedAuth<undefined, readonly ["urn:primer:pci:fraction-input"]>
@@ -159,6 +176,7 @@ const options = {
159
176
  publishableKey,
160
177
  accessToken,
161
178
  subject: "math",
179
+ mode: "drill",
162
180
  supportedPcis: ["urn:primer:pci:fraction-input"],
163
181
  logger
164
182
  } satisfies PrimerOptionsWithAccessToken<"math", readonly ["urn:primer:pci:fraction-input"]>
@@ -180,6 +198,7 @@ if (state.phase === "fatal") {
180
198
  type PrimerOptions<S extends Subject | undefined = undefined, Supported extends readonly PciId[] = []> = {
181
199
  readonly publishableKey: string
182
200
  readonly origin?: string
201
+ readonly mode: "drill" | "curriculum"
183
202
  readonly subject?: S
184
203
  readonly supportedPcis: subject-dependent
185
204
  readonly fetch?: typeof globalThis.fetch
@@ -200,6 +219,7 @@ type PrimerOptionsWithManagedAuth<S, Supported> = PrimerOptions<S, Supported> &
200
219
  | --- | --- | --- |
201
220
  | `publishableKey` | Yes | Public key identifying the Primer frontend your runtime belongs to. |
202
221
  | `origin` | No | Primer origin. Defaults to `https://primerlearn.dev`. |
222
+ | `mode` | Yes | Product surface. Use `"drill"` for practice drill progression or `"curriculum"` for curriculum DAG progression and generated support behavior. |
203
223
  | `accessToken` | Mode-dependent | Learner access token. When present, `start` uses access-token mode. When absent, `start` uses managed hosted-auth mode. |
204
224
  | `subject` | No | Public content scope: `"math"`, `"vocabulary"`, or `"science"`. Omitted means all-subject scope. |
205
225
  | `supportedPcis` | Subject-dependent | Renderer capabilities for Portable Custom Interactions. Required when the chosen scope can emit required PCIs. |
@@ -230,7 +250,7 @@ sessionStorage["primer:access-token:<publishableKey>"]
230
250
 
231
251
  This is intentionally zero config. There is no storage selector and no persistence flag. Managed-auth mode always uses `globalThis.sessionStorage`; if `sessionStorage` is unavailable, `start` returns `AuthUnavailableState`.
232
252
 
233
- The cache stores only the final Primer access token returned by hosted Timeback sign-in. OAuth transaction state, nonce, verifier, and callback validation state are not stored in browser storage; those remain server-managed by Primer.
253
+ The cache stores only the final Primer access token returned by hosted sign-in. OAuth transaction state, nonce, verifier, and callback validation state are not stored in browser storage; those remain server-managed by Primer.
234
254
 
235
255
  Managed-auth startup behavior is:
236
256
 
@@ -246,8 +266,6 @@ Access-token mode bypasses this cache entirely. If `accessToken` is present in `
246
266
 
247
267
  The cached value is a bearer credential. Browser-only consumers get reload convenience from this default, but any script that can read the page can read the token. Host applications must maintain normal XSS protections and should use access-token mode if they need to own token storage themselves.
248
268
 
249
- The canonical managed sign-in endpoint is `/api/auth/timeback/start`. Legacy `/auth/timeback` URLs are not part of the PrimerTives 4.0.5 contract.
250
-
251
269
  ## Auth Semantics
252
270
 
253
271
  An access token is expected to be JWS-shaped: it starts with `eyJ` and contains exactly two dots. If a provided token does not match that shape, `start` returns `FatalState` with `ErrMalformedAccessToken`.
@@ -341,6 +359,7 @@ This fails at compile time because math can emit a required PCI:
341
359
  await start({
342
360
  publishableKey,
343
361
  subject: "math",
362
+ mode: "drill",
344
363
  logger
345
364
  })
346
365
  ```
@@ -351,6 +370,7 @@ This passes:
351
370
  const options = {
352
371
  publishableKey,
353
372
  subject: "math",
373
+ mode: "drill",
354
374
  supportedPcis: ["urn:primer:pci:fraction-input"],
355
375
  logger
356
376
  } satisfies PrimerOptionsWithManagedAuth<"math", readonly ["urn:primer:pci:fraction-input"]>
@@ -806,7 +826,7 @@ if (state.phase === "interaction" && state.kind === "portable-custom") {
806
826
  ## `FeedbackState`
807
827
 
808
828
  ```ts
809
- type AssessmentOutcomeValue = "correct" | "incorrect" | "revisionRequested"
829
+ type AssessmentOutcomeValue = "correct" | "incorrect"
810
830
 
811
831
  type AssessmentOutcome = {
812
832
  cardinality: "single"
@@ -1433,6 +1453,7 @@ import { start, type PrimerOptionsWithManagedAuth } from "@superbuilders/primer-
1433
1453
  const options = {
1434
1454
  publishableKey,
1435
1455
  subject: "vocabulary",
1456
+ mode: "drill",
1436
1457
  logger
1437
1458
  } satisfies PrimerOptionsWithManagedAuth<"vocabulary">
1438
1459
 
@@ -1489,6 +1510,7 @@ const options = {
1489
1510
  publishableKey: "pk_test",
1490
1511
  accessToken: "eyJ.test.token",
1491
1512
  subject: "vocabulary",
1513
+ mode: "drill",
1492
1514
  fetch: fetchMock,
1493
1515
  logger
1494
1516
  } satisfies PrimerOptionsWithAccessToken<"vocabulary">
@@ -3,8 +3,13 @@ import type { InteractionFeedback, Journey, PrimerState } from "./types";
3
3
  import type { ContentBlock } from "../contracts/content";
4
4
  import type { PciId } from "../contracts/pci";
5
5
  import type { RendererStimulus, StandardRendererInteraction } from "../contracts/types";
6
+ interface ExtendedTextStateOptions {
7
+ readonly initialValue?: string;
8
+ readonly initialValues?: string[];
9
+ readonly nextSubmissionRole?: "revision";
10
+ }
6
11
  declare function extendedTextState<Pcis extends PciId>(ctx: SessionContext<Pcis>, journey: Journey, body: ContentBlock[], stimulus: RendererStimulus | null, interaction: Extract<StandardRendererInteraction, {
7
12
  type: "extended-text";
8
- }>, feedback: InteractionFeedback | null): PrimerState<Pcis>;
13
+ }>, feedback: InteractionFeedback | null, options?: ExtendedTextStateOptions): PrimerState<Pcis>;
9
14
  export { extendedTextState };
10
15
  //# sourceMappingURL=extended-text-state.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"extended-text-state.d.ts","sourceRoot":"","sources":["../../src/client/extended-text-state.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oDAAoD,CAAA;AACxF,OAAO,KAAK,EACX,mBAAmB,EACnB,OAAO,EACP,WAAW,EACX,MAAM,0CAA0C,CAAA;AAKjD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+CAA+C,CAAA;AACjF,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,2CAA2C,CAAA;AACtE,OAAO,KAAK,EACX,gBAAgB,EAChB,2BAA2B,EAC3B,MAAM,6CAA6C,CAAA;AAGpD,iBAAS,iBAAiB,CAAC,IAAI,SAAS,KAAK,EAC5C,GAAG,EAAE,cAAc,CAAC,IAAI,CAAC,EACzB,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,YAAY,EAAE,EACpB,QAAQ,EAAE,gBAAgB,GAAG,IAAI,EACjC,WAAW,EAAE,OAAO,CAAC,2BAA2B,EAAE;IAAE,IAAI,EAAE,eAAe,CAAA;CAAE,CAAC,EAC5E,QAAQ,EAAE,mBAAmB,GAAG,IAAI,GAClC,WAAW,CAAC,IAAI,CAAC,CA2KnB;AAED,OAAO,EAAE,iBAAiB,EAAE,CAAA"}
1
+ {"version":3,"file":"extended-text-state.d.ts","sourceRoot":"","sources":["../../src/client/extended-text-state.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAc,MAAM,oDAAoD,CAAA;AACpG,OAAO,KAAK,EACX,mBAAmB,EACnB,OAAO,EACP,WAAW,EACX,MAAM,0CAA0C,CAAA;AAKjD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+CAA+C,CAAA;AACjF,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,2CAA2C,CAAA;AACtE,OAAO,KAAK,EAEX,gBAAgB,EAChB,2BAA2B,EAC3B,MAAM,6CAA6C,CAAA;AAGpD,UAAU,wBAAwB;IACjC,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAA;IAC9B,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,EAAE,CAAA;IACjC,QAAQ,CAAC,kBAAkB,CAAC,EAAE,UAAU,CAAA;CACxC;AAYD,iBAAS,iBAAiB,CAAC,IAAI,SAAS,KAAK,EAC5C,GAAG,EAAE,cAAc,CAAC,IAAI,CAAC,EACzB,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,YAAY,EAAE,EACpB,QAAQ,EAAE,gBAAgB,GAAG,IAAI,EACjC,WAAW,EAAE,OAAO,CAAC,2BAA2B,EAAE;IAAE,IAAI,EAAE,eAAe,CAAA;CAAE,CAAC,EAC5E,QAAQ,EAAE,mBAAmB,GAAG,IAAI,EACpC,OAAO,GAAE,wBAA6B,GACpC,WAAW,CAAC,IAAI,CAAC,CAiLnB;AAED,OAAO,EAAE,iBAAiB,EAAE,CAAA"}
@@ -1,10 +1,10 @@
1
1
  import type { SessionContext } from "./session-context";
2
- import type { AssessmentOutcome, Journey, PrimerState } from "./types";
2
+ import type { Journey, PrimerState } from "./types";
3
3
  import type { ContentBlock, ContentInline } from "../contracts/content";
4
4
  import type { PciId } from "../contracts/pci";
5
5
  import type { InteractionReview } from "../contracts/review";
6
6
  import type { RendererInteraction, RendererStimulus, RendererSubmission } from "../contracts/types";
7
- declare function submittedFeedbackState<Pcis extends PciId>(ctx: SessionContext<Pcis>, journey: Journey, body: ContentBlock[], stimulus: RendererStimulus | null, interaction: RendererInteraction<Pcis>, submission: RendererSubmission<Pcis>, assessmentOutcome: AssessmentOutcome, feedbackContent: ContentInline[], review: InteractionReview<Pcis> | null): PrimerState<Pcis>;
7
+ declare function submittedFeedbackState<Pcis extends PciId>(ctx: SessionContext<Pcis>, journey: Journey, body: ContentBlock[], stimulus: RendererStimulus | null, interaction: RendererInteraction<Pcis>, submission: RendererSubmission<Pcis>, isCorrect: boolean, feedbackContent: ContentInline[], review: InteractionReview<Pcis> | null): PrimerState<Pcis>;
8
8
  declare function timedOutFeedbackState<Pcis extends PciId>(ctx: SessionContext<Pcis>, journey: Journey, body: ContentBlock[], stimulus: RendererStimulus | null, interaction: RendererInteraction<Pcis>, feedbackContent: ContentInline[]): PrimerState<Pcis>;
9
9
  export { submittedFeedbackState, timedOutFeedbackState };
10
10
  //# sourceMappingURL=feedback-state.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"feedback-state.d.ts","sourceRoot":"","sources":["../../src/client/feedback-state.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oDAAoD,CAAA;AACxF,OAAO,KAAK,EACX,iBAAiB,EACjB,OAAO,EACP,WAAW,EACX,MAAM,0CAA0C,CAAA;AACjD,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,+CAA+C,CAAA;AAChG,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,2CAA2C,CAAA;AACtE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,8CAA8C,CAAA;AACrF,OAAO,KAAK,EACX,mBAAmB,EACnB,gBAAgB,EAChB,kBAAkB,EAClB,MAAM,6CAA6C,CAAA;AAapD,iBAAS,sBAAsB,CAAC,IAAI,SAAS,KAAK,EACjD,GAAG,EAAE,cAAc,CAAC,IAAI,CAAC,EACzB,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,YAAY,EAAE,EACpB,QAAQ,EAAE,gBAAgB,GAAG,IAAI,EACjC,WAAW,EAAE,mBAAmB,CAAC,IAAI,CAAC,EACtC,UAAU,EAAE,kBAAkB,CAAC,IAAI,CAAC,EACpC,iBAAiB,EAAE,iBAAiB,EACpC,eAAe,EAAE,aAAa,EAAE,EAChC,MAAM,EAAE,iBAAiB,CAAC,IAAI,CAAC,GAAG,IAAI,GACpC,WAAW,CAAC,IAAI,CAAC,CAenB;AAED,iBAAS,qBAAqB,CAAC,IAAI,SAAS,KAAK,EAChD,GAAG,EAAE,cAAc,CAAC,IAAI,CAAC,EACzB,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,YAAY,EAAE,EACpB,QAAQ,EAAE,gBAAgB,GAAG,IAAI,EACjC,WAAW,EAAE,mBAAmB,CAAC,IAAI,CAAC,EACtC,eAAe,EAAE,aAAa,EAAE,GAC9B,WAAW,CAAC,IAAI,CAAC,CAYnB;AAED,OAAO,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,CAAA"}
1
+ {"version":3,"file":"feedback-state.d.ts","sourceRoot":"","sources":["../../src/client/feedback-state.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oDAAoD,CAAA;AACxF,OAAO,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,0CAA0C,CAAA;AACpF,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,+CAA+C,CAAA;AAChG,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,2CAA2C,CAAA;AACtE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,8CAA8C,CAAA;AACrF,OAAO,KAAK,EACX,mBAAmB,EACnB,gBAAgB,EAChB,kBAAkB,EAClB,MAAM,6CAA6C,CAAA;AAapD,iBAAS,sBAAsB,CAAC,IAAI,SAAS,KAAK,EACjD,GAAG,EAAE,cAAc,CAAC,IAAI,CAAC,EACzB,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,YAAY,EAAE,EACpB,QAAQ,EAAE,gBAAgB,GAAG,IAAI,EACjC,WAAW,EAAE,mBAAmB,CAAC,IAAI,CAAC,EACtC,UAAU,EAAE,kBAAkB,CAAC,IAAI,CAAC,EACpC,SAAS,EAAE,OAAO,EAClB,eAAe,EAAE,aAAa,EAAE,EAChC,MAAM,EAAE,iBAAiB,CAAC,IAAI,CAAC,GAAG,IAAI,GACpC,WAAW,CAAC,IAAI,CAAC,CAenB;AAED,iBAAS,qBAAqB,CAAC,IAAI,SAAS,KAAK,EAChD,GAAG,EAAE,cAAc,CAAC,IAAI,CAAC,EACzB,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,YAAY,EAAE,EACpB,QAAQ,EAAE,gBAAgB,GAAG,IAAI,EACjC,WAAW,EAAE,mBAAmB,CAAC,IAAI,CAAC,EACtC,eAAe,EAAE,aAAa,EAAE,GAC9B,WAAW,CAAC,IAAI,CAAC,CAYnB;AAED,OAAO,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,CAAA"}
@@ -1,4 +1,4 @@
1
- export type { PrimerOptions, PrimerOptionsWithAccessToken, PrimerOptionsWithManagedAuth } from "./start";
1
+ export type { AdvanceMode, PrimerOptions, PrimerOptionsWithAccessToken, PrimerOptionsWithManagedAuth } from "./start";
2
2
  export { start } from "./start";
3
- export type { AccessTokenStartState, AssessmentOutcome, AssessmentOutcomeValue, AuthConfigInvalidState, AuthUnavailableState, ChoiceState, CompletedState, ErroredState, ExtendedTextMultipleState, ExtendedTextSingleState, ExtendedTextState, FatalState, FeedbackKind, FeedbackState, InteractionFeedback, InteractionState, ManagedStartState, MatchState, NonRetriableErroredState, NonSerializable, ObservationState, OrderState, PciInteractionState, PciPendingRenderProps, PciRenderProps, PciSubmittedRenderProps, Journey, JourneyProgress, PrimerState, RetriableErroredState, RuntimeState, SignInFailedState, SignInRequiredState, SubmittedFeedbackState, TextEntryState, TimedOutFeedbackState } from "./types";
3
+ export type { AccessTokenStartState, AuthConfigInvalidState, AuthUnavailableState, ChoiceState, CompletedState, ErroredState, ExtendedTextMultipleState, ExtendedTextSingleState, ExtendedTextState, FatalState, FeedbackKind, FeedbackState, InteractionFeedback, InteractionState, ManagedStartState, MatchState, NonRetriableErroredState, NonSerializable, ObservationState, OrderState, PciInteractionState, PciPendingRenderProps, PciRenderProps, PciSubmittedRenderProps, Journey, JourneyProgress, PrimerState, RetriableErroredState, RuntimeState, SignInFailedState, SignInRequiredState, SubmittedFeedbackState, TextEntryState, TimedOutFeedbackState } from "./types";
4
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACX,aAAa,EACb,4BAA4B,EAC5B,4BAA4B,EAC5B,MAAM,0CAA0C,CAAA;AACjD,OAAO,EAAE,KAAK,EAAE,MAAM,0CAA0C,CAAA;AAEhE,YAAY,EACX,qBAAqB,EACrB,iBAAiB,EACjB,sBAAsB,EACtB,sBAAsB,EACtB,oBAAoB,EACpB,WAAW,EACX,cAAc,EACd,YAAY,EACZ,yBAAyB,EACzB,uBAAuB,EACvB,iBAAiB,EACjB,UAAU,EACV,YAAY,EACZ,aAAa,EACb,mBAAmB,EACnB,gBAAgB,EAChB,iBAAiB,EACjB,UAAU,EACV,wBAAwB,EACxB,eAAe,EACf,gBAAgB,EAChB,UAAU,EACV,mBAAmB,EACnB,qBAAqB,EACrB,cAAc,EACd,uBAAuB,EACvB,OAAO,EACP,eAAe,EACf,WAAW,EACX,qBAAqB,EACrB,YAAY,EACZ,iBAAiB,EACjB,mBAAmB,EACnB,sBAAsB,EACtB,cAAc,EACd,qBAAqB,EACrB,MAAM,0CAA0C,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACX,WAAW,EACX,aAAa,EACb,4BAA4B,EAC5B,4BAA4B,EAC5B,MAAM,0CAA0C,CAAA;AACjD,OAAO,EAAE,KAAK,EAAE,MAAM,0CAA0C,CAAA;AAEhE,YAAY,EACX,qBAAqB,EACrB,sBAAsB,EACtB,oBAAoB,EACpB,WAAW,EACX,cAAc,EACd,YAAY,EACZ,yBAAyB,EACzB,uBAAuB,EACvB,iBAAiB,EACjB,UAAU,EACV,YAAY,EACZ,aAAa,EACb,mBAAmB,EACnB,gBAAgB,EAChB,iBAAiB,EACjB,UAAU,EACV,wBAAwB,EACxB,eAAe,EACf,gBAAgB,EAChB,UAAU,EACV,mBAAmB,EACnB,qBAAqB,EACrB,cAAc,EACd,uBAAuB,EACvB,OAAO,EACP,eAAe,EACf,WAAW,EACX,qBAAqB,EACrB,YAAY,EACZ,iBAAiB,EACjB,mBAAmB,EACnB,sBAAsB,EACtB,cAAc,EACd,qBAAqB,EACrB,MAAM,0CAA0C,CAAA"}
@@ -7289,7 +7289,6 @@ var FORBIDDEN_JOURNEY_KEYS = new Set([
7289
7289
  "handle",
7290
7290
  "cursor",
7291
7291
  "delta",
7292
- "revision",
7293
7292
  "standard",
7294
7293
  "prerequisite",
7295
7294
  "theme",
@@ -7518,27 +7517,37 @@ function choiceState(ctx, journey, body, stimulus, interaction, options, maxChoi
7518
7517
 
7519
7518
  // src/client/extended-text-state.ts
7520
7519
  import * as errors6 from "@superbuilders/errors";
7521
- function extendedTextState(ctx, journey, body, stimulus, interaction, feedback) {
7520
+ function extendedTextIntent(submission, nextSubmissionRole) {
7521
+ if (nextSubmissionRole === "revision") {
7522
+ return { kind: "interaction", submission, submissionRole: "revision" };
7523
+ }
7524
+ return { kind: "interaction", submission };
7525
+ }
7526
+ function extendedTextState(ctx, journey, body, stimulus, interaction, feedback, options = {}) {
7522
7527
  if (interaction.cardinality === "single") {
7523
7528
  let submitText = function(value) {
7524
- const submission = { type: "extended-text", values: [value] };
7529
+ const submission = {
7530
+ type: "extended-text",
7531
+ values: [value]
7532
+ };
7533
+ const intent = extendedTextIntent(submission, options.nextSubmissionRole);
7525
7534
  const key = JSON.stringify(submission);
7526
7535
  if (timeoutPending2) {
7527
- return Promise.resolve(ctx.errored(errors6.wrap(ErrConflict, "cannot submit while timeout is in flight"), "interaction", { kind: "interaction", submission }));
7536
+ return Promise.resolve(ctx.errored(errors6.wrap(ErrConflict, "cannot submit while timeout is in flight"), "interaction", intent));
7528
7537
  }
7529
7538
  if (submitPending2) {
7530
7539
  if (submitKey2 === key) {
7531
7540
  return submitPending2;
7532
7541
  }
7533
- return Promise.resolve(ctx.errored(errors6.wrap(ErrConflict, "cannot submit a different extended-text payload while submit is in flight"), "interaction", { kind: "interaction", submission }));
7542
+ return Promise.resolve(ctx.errored(errors6.wrap(ErrConflict, "cannot submit a different extended-text payload while submit is in flight"), "interaction", intent));
7534
7543
  }
7535
7544
  const validation = validateSubmissionForInteraction(interaction, submission);
7536
7545
  if (!validation.ok) {
7537
7546
  ctx.logger.error({ value, issues: validation.issues }, "extended-text submit invalid");
7538
- return Promise.resolve(ctx.errored(errors6.wrap(ErrInvalidSubmission, submissionValidationMessage(validation)), "interaction", { kind: "interaction", submission }));
7547
+ return Promise.resolve(ctx.errored(errors6.wrap(ErrInvalidSubmission, submissionValidationMessage(validation)), "interaction", intent));
7539
7548
  }
7540
7549
  submitKey2 = key;
7541
- submitPending2 = ctx.execute({ kind: "interaction", submission }, "interaction").finally(function clearPending() {
7550
+ submitPending2 = ctx.execute(intent, "interaction").finally(function clearPending() {
7542
7551
  submitPending2 = undefined;
7543
7552
  submitKey2 = undefined;
7544
7553
  });
@@ -7568,6 +7577,7 @@ function extendedTextState(ctx, journey, body, stimulus, interaction, feedback)
7568
7577
  stimulus,
7569
7578
  interaction,
7570
7579
  feedback,
7580
+ initialValue: options.initialValue,
7571
7581
  submitText,
7572
7582
  timeout: timeout2,
7573
7583
  toJSON: poisonToJSON
@@ -7578,24 +7588,28 @@ function extendedTextState(ctx, journey, body, stimulus, interaction, feedback)
7578
7588
  let submitKey;
7579
7589
  let timeoutPending;
7580
7590
  function submitTexts(values) {
7581
- const submission = { type: "extended-text", values };
7591
+ const submission = {
7592
+ type: "extended-text",
7593
+ values
7594
+ };
7595
+ const intent = extendedTextIntent(submission, options.nextSubmissionRole);
7582
7596
  const key = JSON.stringify(submission);
7583
7597
  if (timeoutPending) {
7584
- return Promise.resolve(ctx.errored(errors6.wrap(ErrConflict, "cannot submit while timeout is in flight"), "interaction", { kind: "interaction", submission }));
7598
+ return Promise.resolve(ctx.errored(errors6.wrap(ErrConflict, "cannot submit while timeout is in flight"), "interaction", intent));
7585
7599
  }
7586
7600
  if (submitPending) {
7587
7601
  if (submitKey === key) {
7588
7602
  return submitPending;
7589
7603
  }
7590
- return Promise.resolve(ctx.errored(errors6.wrap(ErrConflict, "cannot submit a different extended-text payload while submit is in flight"), "interaction", { kind: "interaction", submission }));
7604
+ return Promise.resolve(ctx.errored(errors6.wrap(ErrConflict, "cannot submit a different extended-text payload while submit is in flight"), "interaction", intent));
7591
7605
  }
7592
7606
  const validation = validateSubmissionForInteraction(multi, submission);
7593
7607
  if (!validation.ok) {
7594
7608
  ctx.logger.error({ values, issues: validation.issues }, "extended-text submit invalid");
7595
- return Promise.resolve(ctx.errored(errors6.wrap(ErrInvalidSubmission, submissionValidationMessage(validation)), "interaction", { kind: "interaction", submission }));
7609
+ return Promise.resolve(ctx.errored(errors6.wrap(ErrInvalidSubmission, submissionValidationMessage(validation)), "interaction", intent));
7596
7610
  }
7597
7611
  submitKey = key;
7598
- submitPending = ctx.execute({ kind: "interaction", submission }, "interaction").finally(function clearPending() {
7612
+ submitPending = ctx.execute(intent, "interaction").finally(function clearPending() {
7599
7613
  submitPending = undefined;
7600
7614
  submitKey = undefined;
7601
7615
  });
@@ -7623,6 +7637,7 @@ function extendedTextState(ctx, journey, body, stimulus, interaction, feedback)
7623
7637
  stimulus,
7624
7638
  interaction: multi,
7625
7639
  feedback,
7640
+ initialValues: options.initialValues,
7626
7641
  maxStrings: multi.maxStrings,
7627
7642
  minStrings: multi.minStrings,
7628
7643
  submitTexts,
@@ -7642,7 +7657,7 @@ function createAdvance(ctx) {
7642
7657
  return pending;
7643
7658
  };
7644
7659
  }
7645
- function submittedFeedbackState(ctx, journey, body, stimulus, interaction, submission, assessmentOutcome, feedbackContent, review) {
7660
+ function submittedFeedbackState(ctx, journey, body, stimulus, interaction, submission, isCorrect, feedbackContent, review) {
7646
7661
  return {
7647
7662
  phase: "feedback",
7648
7663
  feedbackKind: "submitted",
@@ -7651,7 +7666,7 @@ function submittedFeedbackState(ctx, journey, body, stimulus, interaction, submi
7651
7666
  stimulus,
7652
7667
  interaction,
7653
7668
  submission,
7654
- assessmentOutcome,
7669
+ isCorrect,
7655
7670
  feedbackContent,
7656
7671
  review,
7657
7672
  advance: createAdvance(ctx),
@@ -7871,29 +7886,39 @@ function pciInteractionState(ctx, journey, body, stimulus, interaction, feedback
7871
7886
 
7872
7887
  // src/client/text-entry-state.ts
7873
7888
  import * as errors10 from "@superbuilders/errors";
7874
- function textEntryState(ctx, journey, body, stimulus, interaction, feedback) {
7889
+ function textEntryIntent(submission, nextSubmissionRole) {
7890
+ if (nextSubmissionRole === "revision") {
7891
+ return { kind: "interaction", submission, submissionRole: "revision" };
7892
+ }
7893
+ return { kind: "interaction", submission };
7894
+ }
7895
+ function textEntryState(ctx, journey, body, stimulus, interaction, feedback, options = {}) {
7875
7896
  let submitPending;
7876
7897
  let submitKey;
7877
7898
  let timeoutPending;
7878
7899
  function submitText(value) {
7879
- const submission = { type: "text-entry", value };
7900
+ const submission = {
7901
+ type: "text-entry",
7902
+ value
7903
+ };
7904
+ const intent = textEntryIntent(submission, options.nextSubmissionRole);
7880
7905
  const key = JSON.stringify(submission);
7881
7906
  if (timeoutPending) {
7882
- return Promise.resolve(ctx.errored(errors10.wrap(ErrConflict, "cannot submit while timeout is in flight"), "interaction", { kind: "interaction", submission }));
7907
+ return Promise.resolve(ctx.errored(errors10.wrap(ErrConflict, "cannot submit while timeout is in flight"), "interaction", intent));
7883
7908
  }
7884
7909
  if (submitPending) {
7885
7910
  if (submitKey === key) {
7886
7911
  return submitPending;
7887
7912
  }
7888
- return Promise.resolve(ctx.errored(errors10.wrap(ErrConflict, "cannot submit a different text payload while submit is in flight"), "interaction", { kind: "interaction", submission }));
7913
+ return Promise.resolve(ctx.errored(errors10.wrap(ErrConflict, "cannot submit a different text payload while submit is in flight"), "interaction", intent));
7889
7914
  }
7890
7915
  const validation = validateSubmissionForInteraction(interaction, submission);
7891
7916
  if (!validation.ok) {
7892
7917
  ctx.logger.error({ value, issues: validation.issues }, "text-entry submit invalid");
7893
- return Promise.resolve(ctx.errored(errors10.wrap(ErrInvalidSubmission, submissionValidationMessage(validation)), "interaction", { kind: "interaction", submission }));
7918
+ return Promise.resolve(ctx.errored(errors10.wrap(ErrInvalidSubmission, submissionValidationMessage(validation)), "interaction", intent));
7894
7919
  }
7895
7920
  submitKey = key;
7896
- submitPending = ctx.execute({ kind: "interaction", submission }, "interaction").finally(function clearPending() {
7921
+ submitPending = ctx.execute(intent, "interaction").finally(function clearPending() {
7897
7922
  submitPending = undefined;
7898
7923
  submitKey = undefined;
7899
7924
  });
@@ -7920,6 +7945,7 @@ function textEntryState(ctx, journey, body, stimulus, interaction, feedback) {
7920
7945
  stimulus,
7921
7946
  interaction,
7922
7947
  feedback,
7948
+ initialValue: options.initialValue,
7923
7949
  submitText,
7924
7950
  timeout,
7925
7951
  toJSON: poisonToJSON
@@ -7955,11 +7981,29 @@ function isRetriableError(err) {
7955
7981
  function makeSession(sc) {
7956
7982
  const logger = sc.logger;
7957
7983
  let latestJourney = ONBOARDING_JOURNEY;
7958
- function resolve(result) {
7984
+ function advancedPreservedSubmission(result, intent) {
7985
+ if (result.outcome !== "advanced") {
7986
+ return;
7987
+ }
7988
+ if (result.frame.feedback === null) {
7989
+ return;
7990
+ }
7991
+ if (intent.kind !== "interaction") {
7992
+ return;
7993
+ }
7994
+ if (intent.submission.type === "text-entry" || intent.submission.type === "extended-text") {
7995
+ return intent.submission;
7996
+ }
7997
+ return;
7998
+ }
7999
+ function resolve(result, intent) {
7959
8000
  latestJourney = result.journey;
7960
8001
  switch (result.outcome) {
7961
- case "advanced":
7962
- return fromAdvanced(result.journey, result.frame.body, result.frame.stimulus, result.frame.interaction, result.frame.feedback);
8002
+ case "advanced": {
8003
+ const preservedSubmission = advancedPreservedSubmission(result, intent);
8004
+ const nextSubmissionRole = preservedSubmission === undefined ? undefined : "revision";
8005
+ return fromAdvanced(result.journey, result.frame.body, result.frame.stimulus, result.frame.interaction, result.frame.feedback, preservedSubmission, nextSubmissionRole);
8006
+ }
7963
8007
  case "submitted": {
7964
8008
  const interaction = result.frame.interaction;
7965
8009
  if (interaction === null) {
@@ -7972,14 +8016,7 @@ function makeSession(sc) {
7972
8016
  toJSON: poisonToJSON
7973
8017
  };
7974
8018
  }
7975
- if (result.assessmentOutcome.value === "revisionRequested") {
7976
- const feedback = {
7977
- assessmentOutcome: result.assessmentOutcome,
7978
- feedbackContent: result.feedbackContent
7979
- };
7980
- return fromAdvanced(result.journey, result.frame.body, result.frame.stimulus, interaction, feedback);
7981
- }
7982
- return submittedFeedbackState(ctx, result.journey, result.frame.body, result.frame.stimulus, interaction, result.submission, result.assessmentOutcome, result.feedbackContent, result.review);
8019
+ return submittedFeedbackState(ctx, result.journey, result.frame.body, result.frame.stimulus, interaction, result.submission, result.isCorrect, result.feedbackContent, result.review);
7983
8020
  }
7984
8021
  case "timedOut": {
7985
8022
  const interaction = result.frame.interaction;
@@ -8032,10 +8069,12 @@ function makeSession(sc) {
8032
8069
  logger.debug({
8033
8070
  phase,
8034
8071
  intentKind: intent.kind,
8035
- subject: sc.subject
8072
+ subject: sc.subject,
8073
+ mode: sc.mode
8036
8074
  }, "session execute");
8037
8075
  const body = {
8038
8076
  subject: sc.subject,
8077
+ mode: sc.mode,
8039
8078
  intent
8040
8079
  };
8041
8080
  const result = await sc.transport(body);
@@ -8065,7 +8104,7 @@ function makeSession(sc) {
8065
8104
  }, "retriable transport error");
8066
8105
  return errored(result.error, phase, intent);
8067
8106
  }
8068
- const next = resolve(result.data);
8107
+ const next = resolve(result.data, intent);
8069
8108
  logger.debug({
8070
8109
  phase,
8071
8110
  intentKind: intent.kind,
@@ -8082,7 +8121,7 @@ function makeSession(sc) {
8082
8121
  }
8083
8122
  return false;
8084
8123
  }
8085
- function fromAdvanced(journey, body, stimulus, interaction, feedback) {
8124
+ function fromAdvanced(journey, body, stimulus, interaction, feedback, preservedSubmission, nextSubmissionRole) {
8086
8125
  if (interaction === null) {
8087
8126
  return observationState(ctx, journey, body, stimulus);
8088
8127
  }
@@ -8098,9 +8137,9 @@ function makeSession(sc) {
8098
8137
  };
8099
8138
  }
8100
8139
  }
8101
- return pendingInteractionState(journey, body, stimulus, interaction, feedback);
8140
+ return pendingInteractionState(journey, body, stimulus, interaction, feedback, preservedSubmission, nextSubmissionRole);
8102
8141
  }
8103
- function extendedTextInteractionState(journey, body, stimulus, interaction, feedback) {
8142
+ function extendedTextInteractionState(journey, body, stimulus, interaction, feedback, preservedSubmission, nextSubmissionRole) {
8104
8143
  if (!("cardinality" in interaction)) {
8105
8144
  logger.error("extended-text interaction is unsupported");
8106
8145
  return {
@@ -8112,16 +8151,39 @@ function makeSession(sc) {
8112
8151
  };
8113
8152
  }
8114
8153
  const extendedInteraction = interaction;
8115
- return extendedTextState(ctx, journey, body, stimulus, extendedInteraction, feedback);
8154
+ if (preservedSubmission?.type === "extended-text") {
8155
+ if (extendedInteraction.cardinality === "single") {
8156
+ const [initialValue] = preservedSubmission.values;
8157
+ return extendedTextState(ctx, journey, body, stimulus, extendedInteraction, feedback, {
8158
+ initialValue,
8159
+ nextSubmissionRole
8160
+ });
8161
+ }
8162
+ return extendedTextState(ctx, journey, body, stimulus, extendedInteraction, feedback, {
8163
+ initialValues: preservedSubmission.values,
8164
+ nextSubmissionRole
8165
+ });
8166
+ }
8167
+ return extendedTextState(ctx, journey, body, stimulus, extendedInteraction, feedback, {
8168
+ nextSubmissionRole
8169
+ });
8116
8170
  }
8117
- function pendingInteractionState(journey, body, stimulus, interaction, feedback) {
8171
+ function pendingInteractionState(journey, body, stimulus, interaction, feedback, preservedSubmission, nextSubmissionRole) {
8118
8172
  switch (interaction.type) {
8119
8173
  case "choice":
8120
8174
  return choiceState(ctx, journey, body, stimulus, interaction, interaction.options, interaction.maxChoices, interaction.minChoices, feedback);
8121
8175
  case "text-entry":
8122
- return textEntryState(ctx, journey, body, stimulus, interaction, feedback);
8176
+ if (preservedSubmission?.type === "text-entry") {
8177
+ return textEntryState(ctx, journey, body, stimulus, interaction, feedback, {
8178
+ initialValue: preservedSubmission.value,
8179
+ nextSubmissionRole
8180
+ });
8181
+ }
8182
+ return textEntryState(ctx, journey, body, stimulus, interaction, feedback, {
8183
+ nextSubmissionRole
8184
+ });
8123
8185
  case "extended-text":
8124
- return extendedTextInteractionState(journey, body, stimulus, interaction, feedback);
8186
+ return extendedTextInteractionState(journey, body, stimulus, interaction, feedback, preservedSubmission, nextSubmissionRole);
8125
8187
  case "order":
8126
8188
  return orderState(ctx, journey, body, stimulus, interaction, feedback);
8127
8189
  case "match":
@@ -8138,11 +8200,21 @@ function makeSession(sc) {
8138
8200
  import * as errors12 from "@superbuilders/errors";
8139
8201
 
8140
8202
  // src/version.ts
8141
- var SDK_VERSION = "5.1.0";
8203
+ var SDK_VERSION = "6.0.0";
8142
8204
  var NPM_PACKAGE_URL = "https://www.npmjs.com/package/@superbuilders/primer-tives";
8143
8205
 
8144
8206
  // src/client/transport.ts
8145
8207
  var ADVANCE_PATH = "/api/v0/advance";
8208
+ function readNumberField(value, key) {
8209
+ if (!(key in value)) {
8210
+ return;
8211
+ }
8212
+ const v = Reflect.get(value, key);
8213
+ if (typeof v !== "number") {
8214
+ return;
8215
+ }
8216
+ return v;
8217
+ }
8146
8218
  function readStringField(value, key) {
8147
8219
  if (!(key in value)) {
8148
8220
  return;
@@ -8176,9 +8248,9 @@ function parseAdvanceErrorBody(body) {
8176
8248
  if (detail !== undefined) {
8177
8249
  result.detail = detail;
8178
8250
  }
8179
- const minimumSdkVersion = readStringField(raw, "minimumSdkVersion");
8180
- if (minimumSdkVersion !== undefined) {
8181
- result.minimumSdkVersion = minimumSdkVersion;
8251
+ const minimumSdkMajor = readNumberField(raw, "minimumSdkMajor");
8252
+ if (minimumSdkMajor !== undefined) {
8253
+ result.minimumSdkMajor = minimumSdkMajor;
8182
8254
  }
8183
8255
  const receivedSdkVersion = readStringField(raw, "receivedSdkVersion");
8184
8256
  if (receivedSdkVersion !== undefined) {
@@ -8251,22 +8323,24 @@ function buildSdkUpgradeRequiredError(sentinel, text, logger) {
8251
8323
  if (parsed === null) {
8252
8324
  logger.error({
8253
8325
  receivedSdkVersion: null,
8254
- minimumSdkVersion: "<unknown>",
8326
+ minimumSdkMajor: "<unknown>",
8255
8327
  upgradeUrl: NPM_PACKAGE_URL
8256
8328
  }, "sdk upgrade required");
8257
- const message2 = `<missing> < <unknown>; bump @superbuilders/primer-tives at ${NPM_PACKAGE_URL}`;
8329
+ const message2 = `major < <unknown>; bump @superbuilders/primer-tives at ${NPM_PACKAGE_URL}`;
8258
8330
  return errors12.wrap(sentinel, message2);
8259
8331
  }
8260
- const minimumSdkVersion = parsed.minimumSdkVersion === undefined ? "<unknown>" : parsed.minimumSdkVersion;
8332
+ let minimumSdkMajor = "<unknown>";
8333
+ if (parsed.minimumSdkMajor !== undefined) {
8334
+ minimumSdkMajor = String(parsed.minimumSdkMajor);
8335
+ }
8261
8336
  const receivedSdkVersion = parsed.receivedSdkVersion === undefined ? null : parsed.receivedSdkVersion;
8262
- const receivedDisplay = receivedSdkVersion === null ? "<missing>" : receivedSdkVersion;
8263
8337
  const upgradeUrl = parsed.upgradeUrl === undefined ? NPM_PACKAGE_URL : parsed.upgradeUrl;
8264
8338
  logger.error({
8265
8339
  receivedSdkVersion,
8266
- minimumSdkVersion,
8340
+ minimumSdkMajor,
8267
8341
  upgradeUrl
8268
8342
  }, "sdk upgrade required");
8269
- const message = `${receivedDisplay} < ${minimumSdkVersion}; bump @superbuilders/primer-tives at ${upgradeUrl}`;
8343
+ const message = `major < ${minimumSdkMajor}; bump @superbuilders/primer-tives at ${upgradeUrl}`;
8270
8344
  return errors12.wrap(sentinel, message);
8271
8345
  }
8272
8346
  function isAbortError(err) {
@@ -8291,7 +8365,8 @@ function createTransport(tc) {
8291
8365
  async function transport(body) {
8292
8366
  logger.debug({
8293
8367
  intentKind: body.intent.kind,
8294
- subject: body.subject
8368
+ subject: body.subject,
8369
+ mode: body.mode
8295
8370
  }, "transport request");
8296
8371
  const fetchResult = await fetchFn(advanceUrl, {
8297
8372
  method: "POST",
@@ -8403,6 +8478,7 @@ async function startRuntime(config, resolved) {
8403
8478
  accessToken: resolved.accessToken,
8404
8479
  publishableKey: config.publishableKey,
8405
8480
  subject: config.subject,
8481
+ mode: config.mode,
8406
8482
  origin: config.origin,
8407
8483
  fetch: config.fetch,
8408
8484
  abort: config.abort,
@@ -8410,6 +8486,7 @@ async function startRuntime(config, resolved) {
8410
8486
  });
8411
8487
  const session = makeSession({
8412
8488
  subject: config.subject,
8489
+ mode: config.mode,
8413
8490
  supportedPcis: config.supportedPcis,
8414
8491
  logger: config.logger,
8415
8492
  transport,
@@ -8462,6 +8539,7 @@ async function start(options) {
8462
8539
  publishableKey: options.publishableKey,
8463
8540
  origin,
8464
8541
  authOrigin: primerAuthOrigin(options.authOrigin, origin),
8542
+ mode: options.mode,
8465
8543
  fetch: options.fetch,
8466
8544
  abort: options.abort,
8467
8545
  logger,
@@ -8495,4 +8573,4 @@ export {
8495
8573
  start
8496
8574
  };
8497
8575
 
8498
- //# debugId=5A8CDF1A8AF453E464756E2164756E21
8576
+ //# debugId=E581CF63700F9E9F64756E2164756E21