@playcademy/sdk 0.16.1-beta.9 → 0.17.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
@@ -122,21 +122,25 @@ Hosted assessments use the same methods locally and when deployed:
122
122
  const attempt = await client.timeback.assessments.start({
123
123
  activityId: 'math-diagnostic',
124
124
  purpose: 'diagnostic',
125
+ diagnosticKey: 'math.grade-5-placement',
125
126
  subject: 'Math',
126
127
  grade: 5,
127
128
  })
128
129
 
129
- const saved = await client.timeback.assessments.save(attempt.attemptId, {
130
- expectedResponseVersion: attempt.responseVersion,
131
- responses: {
132
- [attempt.assessment.items[0].identifier]: { RESPONSE: 'A' },
133
- },
134
- })
130
+ if (attempt.flow !== 'platform-routed-item-submit' || !attempt.routing.next) {
131
+ throw new Error('Expected an active routed diagnostic')
132
+ }
135
133
 
136
- const completed = await client.timeback.assessments.submit(attempt.attemptId, {
137
- expectedResponseVersion: saved.responseVersion,
134
+ const current = attempt.routing.next
135
+ const committed = await client.timeback.assessments.submitItem(attempt.attemptId, {
136
+ expectedResponseVersion: attempt.responseVersion,
138
137
  submissionId: crypto.randomUUID(),
138
+ routingNodeKey: current.nodeKey,
139
+ itemIdentifier: current.itemIdentifier,
140
+ responses: { RESPONSE: 'A' },
139
141
  })
142
+
143
+ // Repeat with committed.routing.next. When routing is ready, submit() only finalizes.
140
144
  ```
141
145
 
142
146
  `start()` resumes a compatible unfinished attempt or selects content for a fixed test or standards
@@ -144,6 +148,25 @@ review. Save payloads merge at both the item and response levels; omitted values
144
148
  and `null` clears one response. Keep the returned `responseVersion` and send it with the next
145
149
  mutation.
146
150
 
151
+ The returned `flow` is authoritative and is derived from the selected assessment; callers do not configure
152
+ navigation, feedback, and submission independently:
153
+
154
+ - `attempt-submit` is used for end-of-course and mastery attempts. Responses remain editable
155
+ through `save()` until `submit()` finalizes the whole attempt and returns feedback.
156
+ - `item-submit` is used for review attempts. Submit each administered item with `submitItem()`.
157
+ That operation atomically saves the item's responses, locks them, and returns safe immediate
158
+ feedback. Give each item request its own stable `submissionId` and reuse that ID for an ambiguous
159
+ retry; the returned canonical `itemSubmissions` ledger identifies committed items after retry or
160
+ resume.
161
+ - `platform-routed-item-submit` is used for adaptive diagnostics. Render only
162
+ `routing.next.itemIdentifier`, submit it with `routing.next.nodeKey`, and replace local state with
163
+ the returned canonical routing snapshot. Diagnostic receipts never reveal correctness or score,
164
+ and `submit()` becomes available only after routing reports `ready-to-complete`.
165
+
166
+ The host rejects the wrong mutation for each flow, rejects premature finalization, and enforces
167
+ `expectedResponseVersion` for every mutation. Hosted and local providers execute the same routing
168
+ manifest contract; game code never selects the provider.
169
+
147
170
  For local development, import the current ordered catalog before starting the dev host:
148
171
 
149
172
  ```bash
@@ -0,0 +1,47 @@
1
+ /**
2
+ * The child-catalog contract: what a child game publishes about its
3
+ * deliverable lessons, per lesson id and level. A parent course authority
4
+ * resolves its lesson references against this document at compile time and
5
+ * fails closed at runtime on anything not `ready` in production.
6
+ *
7
+ * Ownership and flow: each child repo generates `.playcademy/catalog.json`
8
+ * from its own registry (`playcademy catalog generate`); a sync workflow
9
+ * carries copies into parent repos. Children never read the parent's
10
+ * compiled authority — this file and the launch payload are the entire
11
+ * surface between them.
12
+ *
13
+ * The document deliberately carries no app identity. The consuming repo
14
+ * assigns the namespace key (e.g. 'form', 'math-cakes') from sync
15
+ * provenance via its own repo → app map, so a child cannot misdeclare
16
+ * who it is and a typo cannot mint a phantom namespace.
17
+ */
18
+ /** Contract identifier carried by every catalog document. */
19
+ declare const CHILD_CATALOG_CONTRACT: 'playcademy-child-catalog-v1';
20
+ /** The completion-evidence contract a catalog declares its runs report. */
21
+ declare const CHILD_ATTEMPT_CONTRACT: 'playcademy-child-attempt-v1';
22
+ /** Delivery levels a catalog may declare (serving-id dialect, lowercase). */
23
+ declare const CATALOG_LEVELS: readonly ['e1', 'e2', 'e3', 'e4'];
24
+ type CatalogLevel = (typeof CATALOG_LEVELS)[number];
25
+ /**
26
+ * ready: real content. simulated: placeholder — playable for preview and
27
+ * simulation, never creditable in production. unavailable: intentionally
28
+ * absent at this level. Consumers must treat unknown values and missing
29
+ * levels as unavailable (fail closed).
30
+ */
31
+ declare const CATALOG_READINESS: readonly ['ready', 'simulated', 'unavailable'];
32
+ type CatalogReadiness = (typeof CATALOG_READINESS)[number];
33
+ interface ChildCatalog {
34
+ /** The contract identifier. */
35
+ contract: typeof CHILD_CATALOG_CONTRACT;
36
+ /** The completion-evidence contract a catalog declares its runs report. */
37
+ evidence: typeof CHILD_ATTEMPT_CONTRACT;
38
+ /** The tool that generated this document (repo-relative path). */
39
+ generatedBy: string;
40
+ /** The in-repo source of truth the document was derived from. */
41
+ generatedFrom: string;
42
+ /** Lesson id → level → readiness. */
43
+ deliveries: Record<string, Partial<Record<CatalogLevel, CatalogReadiness>>>;
44
+ }
45
+
46
+ export { CATALOG_LEVELS, CATALOG_READINESS, CHILD_ATTEMPT_CONTRACT, CHILD_CATALOG_CONTRACT };
47
+ export type { CatalogLevel, CatalogReadiness, ChildCatalog };
@@ -0,0 +1,23 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __export = (target, all) => {
3
+ for (var name in all)
4
+ __defProp(target, name, {
5
+ get: all[name],
6
+ enumerable: true,
7
+ configurable: true,
8
+ set: (newValue) => all[name] = () => newValue
9
+ });
10
+ };
11
+ var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
12
+
13
+ // src/contracts/child-catalog.ts
14
+ var CHILD_CATALOG_CONTRACT = "playcademy-child-catalog-v1";
15
+ var CHILD_ATTEMPT_CONTRACT = "playcademy-child-attempt-v1";
16
+ var CATALOG_LEVELS = ["e1", "e2", "e3", "e4"];
17
+ var CATALOG_READINESS = ["ready", "simulated", "unavailable"];
18
+ export {
19
+ CHILD_CATALOG_CONTRACT,
20
+ CHILD_ATTEMPT_CONTRACT,
21
+ CATALOG_READINESS,
22
+ CATALOG_LEVELS
23
+ };
package/dist/index.d.ts CHANGED
@@ -1558,7 +1558,11 @@ declare class PlaycademyClient extends PlaycademyBaseClient {
1558
1558
  start: (input: _playcademy_types.StartAssessmentInput) => Promise<_playcademy_types.AssessmentAttemptSnapshot>;
1559
1559
  latest: (options: _playcademy_types.GetLatestAssessmentOptions) => Promise<_playcademy_types.LatestAssessmentResult | null>;
1560
1560
  get: (attemptId: string) => Promise<_playcademy_types.AssessmentAttemptSnapshot>;
1561
+ stop: (attemptId: string) => Promise<{
1562
+ attemptId: string;
1563
+ }>;
1561
1564
  save: (attemptId: string, input: _playcademy_types.SaveAssessmentInput) => Promise<_playcademy_types.AssessmentSaveResult>;
1565
+ submitItem: (attemptId: string, input: _playcademy_types.SubmitAssessmentItemInput) => Promise<_playcademy_types.SubmitAssessmentItemResult>;
1562
1566
  submit: (attemptId: string, input: _playcademy_types.SubmitAssessmentInput) => Promise<_playcademy_types.AssessmentSubmitResult>;
1563
1567
  };
1564
1568
  readonly user: TimebackUser;
@@ -1910,6 +1914,15 @@ type EmbedActivity = EmbedActivityCompleted | EmbedActivityAbandoned | EmbedActi
1910
1914
  /** The child called `endActivity()` and its report was relayed. */
1911
1915
  interface EmbedActivityCompleted {
1912
1916
  status: 'completed';
1917
+ /**
1918
+ * The platform run this completion records under. One run ends in at
1919
+ * most one completion (the server dedupes on it), and a resumed launch
1920
+ * keeps the interrupted run's id — so this doubles as the completion's
1921
+ * attempt identity: feed it to whatever consumes the result and drop
1922
+ * anything you have seen before. Absent only for pure UX embeds
1923
+ * (launched without `timeback`), which record nothing.
1924
+ */
1925
+ runId?: string;
1913
1926
  /** Correct answers, from the child's report. */
1914
1927
  correct: number;
1915
1928
  /** Total questions, from the child's report. */
@@ -1938,6 +1951,12 @@ interface EmbedActivityCompleted {
1938
1951
  */
1939
1952
  interface EmbedActivityAbandoned {
1940
1953
  status: 'abandoned';
1954
+ /**
1955
+ * The platform run the launch was recording under, when one had
1956
+ * opened. Absent when the child never started an activity or the
1957
+ * launch was a pure UX embed.
1958
+ */
1959
+ runId?: string;
1941
1960
  timing: EmbedSessionTiming;
1942
1961
  /**
1943
1962
  * The final resume envelope, when the child checkpointed during the
@@ -1959,6 +1978,13 @@ interface EmbedActivityFailed {
1959
1978
  interface EmbedSession {
1960
1979
  /** The mounted child iframe. Useful for focus management. */
1961
1980
  readonly iframe: HTMLIFrameElement;
1981
+ /**
1982
+ * The platform run this launch records under, or null before the run
1983
+ * opens (the child's first activity) and for pure UX embeds. Stable
1984
+ * once set; also echoed on the finished record, which is where most
1985
+ * callers should read it.
1986
+ */
1987
+ readonly runId: string | null;
1962
1988
  /**
1963
1989
  * The latest resume envelope, live during play; null until the child
1964
1990
  * first checkpoints. Read it on your own cadence to persist