@choiceapps/communityservices-sdk 0.1.1 → 0.2.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 (59) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/browser/coordinated-entry-event.d.mts +78 -0
  3. package/browser/coordinated-entry-event.mjs +175 -0
  4. package/browser/current-living-situation.mjs +11 -120
  5. package/browser/enrollment-workflow.d.mts +10 -2
  6. package/browser/enrollment-workflow.mjs +63 -11
  7. package/browser/index.d.mts +1 -0
  8. package/browser/index.mjs +1 -0
  9. package/browser/subassessment-row-recorder.mjs +154 -0
  10. package/dist/cjs/encoding.d.ts.map +1 -1
  11. package/dist/cjs/encoding.js +2 -1
  12. package/dist/cjs/encoding.js.map +1 -1
  13. package/dist/cjs/errors.d.ts +4 -1
  14. package/dist/cjs/errors.d.ts.map +1 -1
  15. package/dist/cjs/errors.js +9 -1
  16. package/dist/cjs/errors.js.map +1 -1
  17. package/dist/cjs/runtime.d.ts +5 -1
  18. package/dist/cjs/runtime.d.ts.map +1 -1
  19. package/dist/cjs/runtime.js +1 -1
  20. package/dist/cjs/runtime.js.map +1 -1
  21. package/dist/cjs/subassessments.d.ts.map +1 -1
  22. package/dist/cjs/subassessments.js +8 -15
  23. package/dist/cjs/subassessments.js.map +1 -1
  24. package/dist/cjs/transport.d.ts.map +1 -1
  25. package/dist/cjs/transport.js +15 -3
  26. package/dist/cjs/transport.js.map +1 -1
  27. package/dist/esm/encoding.d.ts.map +1 -1
  28. package/dist/esm/encoding.js +2 -1
  29. package/dist/esm/encoding.js.map +1 -1
  30. package/dist/esm/errors.d.ts +4 -1
  31. package/dist/esm/errors.d.ts.map +1 -1
  32. package/dist/esm/errors.js +9 -1
  33. package/dist/esm/errors.js.map +1 -1
  34. package/dist/esm/runtime.d.ts +5 -1
  35. package/dist/esm/runtime.d.ts.map +1 -1
  36. package/dist/esm/runtime.js +1 -1
  37. package/dist/esm/runtime.js.map +1 -1
  38. package/dist/esm/subassessments.d.ts.map +1 -1
  39. package/dist/esm/subassessments.js +8 -15
  40. package/dist/esm/subassessments.js.map +1 -1
  41. package/dist/esm/transport.d.ts.map +1 -1
  42. package/dist/esm/transport.js +15 -3
  43. package/dist/esm/transport.js.map +1 -1
  44. package/docs/README.md +1 -0
  45. package/docs/assessments.md +21 -3
  46. package/docs/capabilities.md +2 -0
  47. package/docs/configuration.md +1 -0
  48. package/docs/coordinated-entry-events.md +88 -0
  49. package/docs/current-living-situation.md +1 -1
  50. package/docs/dates-and-answers.md +3 -1
  51. package/docs/enrollments.md +21 -0
  52. package/docs/reference.md +5 -1
  53. package/docs/troubleshooting.md +25 -0
  54. package/docs/vendor-issues/README.md +2 -0
  55. package/docs/vendor-issues/date-semantics.md +2 -0
  56. package/docs/vendor-issues/yes-no-answers.md +35 -0
  57. package/examples/README.md +2 -0
  58. package/examples/coordinated-entry-events.mts +37 -0
  59. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../src/runtime.ts"],"names":[],"mappings":"AAqFA,MAAM,UAAU,OAAO,CAAI,QAAwB;IACjD,IAAI,QAAQ,KAAK,IAAI;QAAE,OAAO,EAAE,CAAC;IACjC,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC;QAAE,OAAO,QAAQ,CAAC;IAC7C,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,OAAO,IAAI,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QACzF,OAAO,QAAQ,CAAC,KAAK,CAAC;IACxB,CAAC;IACD,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,OAAO,IAAI,QAAQ,IAAI,QAAQ,IAAI,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QAClH,OAAO,QAAQ,CAAC,MAAM,CAAC;IACzB,CAAC;IACD,8DAA8D;IAC9D,OAAO,CAAC,QAAa,CAAC,CAAC;AACzB,CAAC;AAID,0FAA0F;AAC1F,MAAM,OAAO,YAAa,SAAQ,KAAK;IAC5B,IAAI,CAAY;IAChB,MAAM,CAAqB;IAC3B,SAAS,CAAS;IAClB,SAAS,CAAqB;IAC9B,YAAY,CAAqB;IAC1C,aAAa,CAAqB;IAElC,YAAY,IAAe,EAAE,SAAiB,EAAE,UAA0E,EAAE;QAC1H,KAAK,CAAC,WAAW,SAAS,KAAK,IAAI,GAAG,OAAO,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,OAAO,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;QACzG,IAAI,CAAC,IAAI,GAAG,cAAc,CAAC;QAC3B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC3B,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;QAC7B,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC;QACnC,IAAI,CAAC,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC;IAC3C,CAAC;CACF","sourcesContent":["/** Matching credentials/providers share cached authentication in-process. No environment or disk reads. */\nexport type Authentication =\n | { kind: \"credentials\"; username: string; password: string }\n | { kind: \"token\"; token: string }\n | { kind: \"provider\"; getToken: (context: { forceRefresh: boolean; signal: AbortSignal }) => string | Promise<string> }\n | { kind: \"none\" };\n\nexport interface ClientOptions {\n tenant: string;\n auth: Authentication;\n\n maxConcurrency?: number;\n cooldown?: { threshold: number; windowMs: number; durationMs: number };\n hooks?: ClientHooks;\n /** Receives the same allowlisted events as hooks. No raw request/response data. */\n logger?: (event: ClientEvent) => void;\n metadataCacheTtlMs?: number;\n metadataCacheMaxEntries?: number;\n /** Opt-in correction for a measured upstream mobile assessment dateEffective shift.\n * Added to the requested instant on POST AddAssessmentAnswer only. No default timezone is assumed.\n * Revalidate against saved effective dates when the server's offset changes. */\n mobileAssessmentDateCorrectionMinutes?: number;\n /** Defaults to the public production API URL. Supply the target environment explicitly when needed. */\n baseUrl?: string;\n /** Inject a fetch-compatible transport for tests or network routing. */\n fetch?: typeof globalThis.fetch;\n /** Total request deadline including auth, read retries, and backoff. Default 30 seconds. */\n timeoutMs?: number;\n /** Additional attempts for GET only. Default 2; writes are never replayed. */\n maxReadRetries?: number;\n retryBaseDelayMs?: number;\n maxRetryDelayMs?: number;\n}\n\nexport interface RequestOptions {\n signal?: AbortSignal;\n timeoutMs?: number;\n correlationId?: string;\n}\n\nexport interface ClientEvent {\n type: \"request\" | \"response\" | \"tokenMint\" | \"throttle\" | \"cooldown\";\n operation: string;\n correlationId: string;\n retryCount: number;\n durationMs?: number;\n status?: number;\n retryAfterMs?: number;\n until?: string;\n}\nexport interface ClientHooks {\n onRequest?: (event: ClientEvent) => void;\n onResponse?: (event: ClientEvent) => void;\n onTokenMint?: (event: ClientEvent) => void;\n onThrottle?: (event: ClientEvent) => void;\n onCooldown?: (event: ClientEvent) => void;\n}\nexport interface ClientHealth {\n state: \"closed\" | \"open\";\n until: string | null;\n activeRequests: number;\n queuedRequests: number;\n tokenMintCount: number;\n}\n\nexport interface PaginationOptions {\n /** Safety limit. Reaching it throws rather than silently returning partial data. Default 10,000. */\n maxPages?: number;\n}\n\nexport interface ODataCollection<T> {\n value: T[];\n \"@odata.count\"?: number;\n \"@odata.nextLink\"?: string;\n}\n\n/** WellSky's total_count response. Count covers the result set, not just this page. */\nexport interface CountedCollection<T> {\n count: number;\n values: T[];\n}\n\n/** WellSky may return an object, an array, or either collection envelope for the same model. */\nexport type ApiResponse<T> = T | T[] | ODataCollection<T> | CountedCollection<T> | null;\n\nexport function toItems<T>(response: ApiResponse<T>): T[] {\n if (response === null) return [];\n if (Array.isArray(response)) return response;\n if (typeof response === \"object\" && \"value\" in response && Array.isArray(response.value)) {\n return response.value;\n }\n if (typeof response === \"object\" && \"count\" in response && \"values\" in response && Array.isArray(response.values)) {\n return response.values;\n }\n // The envelope branch above has been checked at the boundary.\n return [response as T];\n}\n\nexport type ErrorKind = \"http\" | \"network\" | \"timeout\" | \"aborted\" | \"validation\" | \"protocol\" | \"pagination\" | \"tenant_mismatch\" | \"auth\" | \"throttled\" | \"cooldown\" | \"ambiguous_commit\" | \"definition_drift\" | \"unknown_picklist_value\";\n\n/** Deliberately contains no credentials, query values, response bodies, or client IDs. */\nexport class WellSkyError extends Error {\n readonly kind: ErrorKind;\n readonly status: number | undefined;\n readonly operation: string;\n readonly requestId: string | undefined;\n readonly retryAfterMs: number | undefined;\n correlationId: string | undefined;\n\n constructor(kind: ErrorKind, operation: string, details: { status?: number; requestId?: string; retryAfterMs?: number } = {}) {\n super(`WellSky ${operation}: ${kind}${details.status === undefined ? \"\" : ` (HTTP ${details.status})`}`);\n this.name = \"WellSkyError\";\n this.kind = kind;\n this.operation = operation;\n this.status = details.status;\n this.requestId = details.requestId;\n this.retryAfterMs = details.retryAfterMs;\n }\n}\n"]}
1
+ {"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../src/runtime.ts"],"names":[],"mappings":"AAyFA,MAAM,UAAU,OAAO,CAAI,QAAwB;IACjD,IAAI,QAAQ,KAAK,IAAI;QAAE,OAAO,EAAE,CAAC;IACjC,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC;QAAE,OAAO,QAAQ,CAAC;IAC7C,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,OAAO,IAAI,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QACzF,OAAO,QAAQ,CAAC,KAAK,CAAC;IACxB,CAAC;IACD,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,OAAO,IAAI,QAAQ,IAAI,QAAQ,IAAI,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QAClH,OAAO,QAAQ,CAAC,MAAM,CAAC;IACzB,CAAC;IACD,8DAA8D;IAC9D,OAAO,CAAC,QAAa,CAAC,CAAC;AACzB,CAAC;AAID,0JAA0J;AAC1J,MAAM,OAAO,YAAa,SAAQ,KAAK;IAC5B,IAAI,CAAY;IAChB,MAAM,CAAqB;IAC3B,SAAS,CAAS;IAClB,SAAS,CAAqB;IAC9B,YAAY,CAAqB;IAC1C,aAAa,CAAqB;IAElC,YAAY,IAAe,EAAE,SAAiB,EAAE,UAA0E,EAAE;QAC1H,KAAK,CAAC,WAAW,SAAS,KAAK,IAAI,GAAG,OAAO,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,OAAO,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;QACzG,IAAI,CAAC,IAAI,GAAG,cAAc,CAAC;QAC3B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC3B,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;QAC7B,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC;QACnC,IAAI,CAAC,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC;IAC3C,CAAC;CACF","sourcesContent":["/** Matching credentials/providers share cached authentication in-process. No environment or disk reads. */\nexport type Authentication =\n | { kind: \"credentials\"; username: string; password: string }\n | { kind: \"token\"; token: string }\n | { kind: \"provider\"; getToken: (context: { forceRefresh: boolean; signal: AbortSignal }) => string | Promise<string> }\n | { kind: \"none\" };\n\nexport interface ClientOptions {\n tenant: string;\n auth: Authentication;\n\n maxConcurrency?: number;\n cooldown?: { threshold: number; windowMs: number; durationMs: number };\n hooks?: ClientHooks;\n /** Receives the same allowlisted events as hooks. No raw request/response data. */\n logger?: (event: ClientEvent) => void;\n metadataCacheTtlMs?: number;\n metadataCacheMaxEntries?: number;\n /** Opt-in correction for a measured upstream mobile assessment dateEffective shift.\n * Added to the requested instant on POST AddAssessmentAnswer only. No default timezone is assumed.\n * Revalidate against saved effective dates when the server's offset changes. */\n mobileAssessmentDateCorrectionMinutes?: number;\n /** Opt in to retaining up to 16384 characters of an UpstreamError response body.\n * May contain private data. Excluded from JSON serialization and ordinary telemetry.\n * Authentication and throttle error bodies are never retained. */\n captureErrorBody?: boolean;\n /** Defaults to the public production API URL. Supply the target environment explicitly when needed. */\n baseUrl?: string;\n /** Inject a fetch-compatible transport for tests or network routing. */\n fetch?: typeof globalThis.fetch;\n /** Total request deadline including auth, read retries, and backoff. Default 30 seconds. */\n timeoutMs?: number;\n /** Additional attempts for GET only. Default 2; writes are never replayed. */\n maxReadRetries?: number;\n retryBaseDelayMs?: number;\n maxRetryDelayMs?: number;\n}\n\nexport interface RequestOptions {\n signal?: AbortSignal;\n timeoutMs?: number;\n correlationId?: string;\n}\n\nexport interface ClientEvent {\n type: \"request\" | \"response\" | \"tokenMint\" | \"throttle\" | \"cooldown\";\n operation: string;\n correlationId: string;\n retryCount: number;\n durationMs?: number;\n status?: number;\n retryAfterMs?: number;\n until?: string;\n}\nexport interface ClientHooks {\n onRequest?: (event: ClientEvent) => void;\n onResponse?: (event: ClientEvent) => void;\n onTokenMint?: (event: ClientEvent) => void;\n onThrottle?: (event: ClientEvent) => void;\n onCooldown?: (event: ClientEvent) => void;\n}\nexport interface ClientHealth {\n state: \"closed\" | \"open\";\n until: string | null;\n activeRequests: number;\n queuedRequests: number;\n tokenMintCount: number;\n}\n\nexport interface PaginationOptions {\n /** Safety limit. Reaching it throws rather than silently returning partial data. Default 10,000. */\n maxPages?: number;\n}\n\nexport interface ODataCollection<T> {\n value: T[];\n \"@odata.count\"?: number;\n \"@odata.nextLink\"?: string;\n}\n\n/** WellSky's total_count response. Count covers the result set, not just this page. */\nexport interface CountedCollection<T> {\n count: number;\n values: T[];\n}\n\n/** WellSky may return an object, an array, or either collection envelope for the same model. */\nexport type ApiResponse<T> = T | T[] | ODataCollection<T> | CountedCollection<T> | null;\n\nexport function toItems<T>(response: ApiResponse<T>): T[] {\n if (response === null) return [];\n if (Array.isArray(response)) return response;\n if (typeof response === \"object\" && \"value\" in response && Array.isArray(response.value)) {\n return response.value;\n }\n if (typeof response === \"object\" && \"count\" in response && \"values\" in response && Array.isArray(response.values)) {\n return response.values;\n }\n // The envelope branch above has been checked at the boundary.\n return [response as T];\n}\n\nexport type ErrorKind = \"http\" | \"network\" | \"timeout\" | \"aborted\" | \"validation\" | \"protocol\" | \"pagination\" | \"tenant_mismatch\" | \"auth\" | \"throttled\" | \"cooldown\" | \"ambiguous_commit\" | \"definition_drift\" | \"unknown_picklist_value\";\n\n/** Deliberately contains no credentials, query values, or client IDs, and no response body unless `captureErrorBody` is enabled (then non-enumerable). */\nexport class WellSkyError extends Error {\n readonly kind: ErrorKind;\n readonly status: number | undefined;\n readonly operation: string;\n readonly requestId: string | undefined;\n readonly retryAfterMs: number | undefined;\n correlationId: string | undefined;\n\n constructor(kind: ErrorKind, operation: string, details: { status?: number; requestId?: string; retryAfterMs?: number } = {}) {\n super(`WellSky ${operation}: ${kind}${details.status === undefined ? \"\" : ` (HTTP ${details.status})`}`);\n this.name = \"WellSkyError\";\n this.kind = kind;\n this.operation = operation;\n this.status = details.status;\n this.requestId = details.requestId;\n this.retryAfterMs = details.retryAfterMs;\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"subassessments.d.ts","sourceRoot":"","sources":["../../src/subassessments.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAGnD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,KAAK,EAAE,2CAA2C,EAAE,MAAM,0BAA0B,CAAC;AAE5F,MAAM,WAAW,oBAAqB,SAAQ,cAAc;IAC1D,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AACD,MAAM,WAAW,cAAe,SAAQ,oBAAoB;IAC1D,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,oFAAoF;IACpF,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACxD;AACD,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,CAAC,OAAO,EAAE,oBAAoB,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1D,KAAK,EAAE,CAAC,OAAO,EAAE,oBAAoB,EAAE,IAAI,EAAE,2CAA2C,EAAE,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CACjH;AA8BD,4FAA4F;AAC5F,qBAAa,mBAAmB;;gBAGlB,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,mBAAmB;IAEjD,UAAU,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAAC,WAAW,CAAC;QAAE,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CA8CvF"}
1
+ {"version":3,"file":"subassessments.d.ts","sourceRoot":"","sources":["../../src/subassessments.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAGnD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,KAAK,EAAE,2CAA2C,EAAE,MAAM,0BAA0B,CAAC;AAE5F,MAAM,WAAW,oBAAqB,SAAQ,cAAc;IAC1D,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AACD,MAAM,WAAW,cAAe,SAAQ,oBAAoB;IAC1D,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,oFAAoF;IACpF,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACxD;AACD,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,CAAC,OAAO,EAAE,oBAAoB,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1D,KAAK,EAAE,CAAC,OAAO,EAAE,oBAAoB,EAAE,IAAI,EAAE,2CAA2C,EAAE,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CACjH;AA8BD,4FAA4F;AAC5F,qBAAa,mBAAmB;;gBAGlB,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,mBAAmB;IAEjD,UAAU,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAAC,WAAW,CAAC;QAAE,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CA2CvF"}
@@ -69,22 +69,15 @@ export class SubassessmentEditor {
69
69
  const selected = records.filter(r => r.recordset_id === input.recordsetId);
70
70
  if (selected.length !== 1 || !selected[0])
71
71
  throw new ValidationError(operation, ["recordsetId"]);
72
- const questions = objectRows(selected[0].sub_assessment_list ?? []);
73
- const end = questions.filter(q => q.virt_field_name === input.endDateField && q.question_type === "date");
74
- if (end.length !== 1 || typeof parent.question_id !== "number")
72
+ // A row read omits cells never answered, so fall back to the parent's question list.
73
+ const isEnd = (q) => q.virt_field_name === input.endDateField && q.question_type === "date" && typeof q.question_id === "number";
74
+ const inRow = objectRows(selected[0].sub_assessment_list ?? []).filter(isEnd);
75
+ const end = inRow.length ? inRow : objectRows(parent.sub_assessment_question_list ?? []).filter(isEnd);
76
+ if (end.length !== 1 || !end[0] || typeof parent.question_id !== "number")
75
77
  throw new ValidationError(operation, [input.endDateField]);
76
- const encoded = questions.filter(q => !["label", "blank"].includes(String(q.question_type))).flatMap(q => {
77
- if (q.question_type === "provider")
78
- throw new ValidationError("mobile provider answers are unsupported", [String(q.virt_field_name)]);
79
- if (typeof q.question_id !== "number" || typeof q.question_type !== "string" || typeof q.virt_field_name !== "string")
80
- throw new WellSkyError("protocol", readEndpoint);
81
- const value = q.virt_field_name === input.endDateField ? input.endDate : q.answer_value ?? "";
82
- if (typeof value !== "string")
83
- throw new WellSkyError("protocol", readEndpoint);
84
- if (q.question_type === "yes_no" && value === "")
85
- return [];
86
- return [{ question_id: q.question_id, question_type: q.question_type, virt_field_name: q.virt_field_name, answer_value: value }];
87
- });
78
+ // Send only the end-date cell. Mobile updates the sent cells of the recordset and keeps the
79
+ // rest, including provider and yes/no answers it cannot write itself (live, November 2, 2026).
80
+ const encoded = [{ question_id: end[0].question_id, question_type: "date", virt_field_name: input.endDateField, answer_value: input.endDate }];
88
81
  Object.assign(expected, snapshot(parent, input.endDateField, calendarOnly));
89
82
  expected[`${input.recordsetId}/${input.endDateField}`] = dateValue(input.endDate, calendarOnly);
90
83
  body = [{ question_id: parent.question_id, question_type: "sub_assessment", virt_field_name: input.parentField, answer_value: "", subAssessmentQuestionAnswers: [{ recordset_id: input.recordsetId, isDeleted: false, subAssessments: encoded }] }];
@@ -1 +1 @@
1
- {"version":3,"file":"subassessments.js","sourceRoot":"","sources":["../../src/subassessments.ts"],"names":[],"mappings":"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","sourcesContent":["import { isRecord } from \"./validation.js\";\nimport { WellSkyError } from \"./runtime.js\";\nimport type { RequestOptions } from \"./runtime.js\";\nimport { ValidationError } from \"./errors.js\";\nimport { verifyWrite } from \"./verification.js\";\nimport type { WriteResult } from \"./verification.js\";\nimport type { AddSubAssessmentQuestionWithAnswerViewModel } from \"./generated/v3-models.js\";\n\nexport interface SubassessmentContext extends RequestOptions {\n clientId: number;\n assessmentCode: string;\n effectiveDate?: string;\n}\nexport interface EndDateRequest extends SubassessmentContext {\n parentField: string;\n recordsetId: number;\n endDateField: string;\n endDate: string;\n /** Optional caller preflight for program-specific review-date or other policies. */\n preflight?: (options: RequestOptions) => Promise<void>;\n}\nexport interface SubassessmentSource {\n read: (context: SubassessmentContext) => Promise<unknown>;\n write: (context: SubassessmentContext, body: AddSubAssessmentQuestionWithAnswerViewModel[]) => Promise<unknown>;\n}\nfunction objectRows(value: unknown): Record<string, unknown>[] {\n const rows = isRecord(value) && Array.isArray(value.value) ? value.value : Array.isArray(value) ? value : value === null ? [] : [value];\n if (!rows.every(isRecord)) throw new WellSkyError(\"protocol\", \"subassessment read\");\n return rows;\n}\nfunction parentFrom(value: unknown, field: string): Record<string, unknown> {\n const matches = objectRows(value).filter(q => q.virt_field_name === field);\n if (matches.length !== 1 || !matches[0] || matches[0].question_type !== \"sub_assessment\") throw new ValidationError(\"subassessment resolution\", [field]);\n return matches[0];\n}\nfunction dateValue(value: unknown, calendarOnly = false): unknown {\n if (value === null || value === \"\" || value === undefined) return null;\n if (typeof value !== \"string\") return value;\n if (calendarOnly || /^\\d{4}-\\d{2}-\\d{2}$/.test(value)) return value.slice(0, 10);\n const iso = value.replace(\" \", \"T\").replace(/([+-]\\d{2})$/, \"$1:00\");\n if (!/(?:Z|[+-]\\d{2}:\\d{2})$/.test(iso)) return value;\n const millis = Date.parse(iso);\n return Number.isFinite(millis) ? new Date(millis).toISOString() : value;\n}\nfunction snapshot(parent: Record<string, unknown>, endDateField: string, calendarOnly: boolean): Record<string, unknown> {\n const records = objectRows(parent.sub_assessment_answer_list ?? []);\n const fields: Record<string, unknown> = { \"$recordsets\": records.map(r => r.recordset_id).sort((a, b) => Number(a) - Number(b)) };\n for (const record of records) for (const q of objectRows(record.sub_assessment_list ?? [])) {\n if (typeof q.virt_field_name !== \"string\" || typeof record.recordset_id !== \"number\") throw new WellSkyError(\"protocol\", \"subassessment read\");\n fields[`${record.recordset_id}/${q.virt_field_name}`] = q.question_type === \"date\" ? dateValue(q.answer_value, calendarOnly && q.virt_field_name === endDateField) : q.answer_value ?? null;\n }\n return fields;\n}\n\n/** Generic recordset editing; no program names, assessment codes, or replacement policy. */\nexport class SubassessmentEditor {\n readonly #tenant: string;\n readonly #source: SubassessmentSource;\n constructor(tenant: string, source: SubassessmentSource) { this.#tenant = tenant; this.#source = source; }\n\n async setEndDate(input: EndDateRequest): Promise<WriteResult<{ recordsetId: number }>> {\n const operation = \"POST /assessmentsmobile/AddAssessmentAnswer/{clientId}/{assessmentCode}\";\n const readEndpoint = \"GET /assessmentsmobile/GetAssessmentAnswers/{clientId}/{assessmentCode}\";\n const expected: Record<string, unknown> = {};\n let body: AddSubAssessmentQuestionWithAnswerViewModel[] = [];\n const calendarOnly = /^\\d{4}-\\d{2}-\\d{2}$/.test(input.endDate);\n const semanticPayload = { tenant: this.#tenant, operation, clientId: input.clientId, assessmentCode: input.assessmentCode, parentField: input.parentField, recordsetId: input.recordsetId, endDateField: input.endDateField, endDate: input.endDate, effectiveDate: input.effectiveDate ?? null };\n return verifyWrite({\n operation, readEndpoint, semanticPayload, expectedFields: expected,\n ...(input.signal ? { signal: input.signal } : {}), ...(input.correlationId === undefined ? {} : { correlationId: input.correlationId }),\n ...(input.timeoutMs === undefined ? {} : { timeoutMs: input.timeoutMs }),\n preflight: async options => {\n if (!Number.isSafeInteger(input.recordsetId) || input.recordsetId < 1 || !/^\\d{4}-\\d{2}-\\d{2}(?:$|[T ])/.test(input.endDate)) throw new ValidationError(operation, [\"recordsetId\", \"endDate\"]);\n const calendar = input.endDate.slice(0, 10);\n const day = new Date(`${calendar}T00:00:00Z`);\n if (!Number.isFinite(day.getTime()) || day.toISOString().slice(0, 10) !== calendar) throw new ValidationError(operation, [\"endDate\"]);\n if (!calendarOnly && !Number.isFinite(Date.parse(input.endDate.replace(\" \", \"T\").replace(/([+-]\\d{2})$/, \"$1:00\")))) throw new ValidationError(operation, [\"endDate\"]);\n await input.preflight?.(options);\n const parent = parentFrom(await this.#source.read({ ...input, ...options }), input.parentField);\n const records = objectRows(parent.sub_assessment_answer_list ?? []);\n const selected = records.filter(r => r.recordset_id === input.recordsetId);\n if (selected.length !== 1 || !selected[0]) throw new ValidationError(operation, [\"recordsetId\"]);\n const questions = objectRows(selected[0].sub_assessment_list ?? []);\n const end = questions.filter(q => q.virt_field_name === input.endDateField && q.question_type === \"date\");\n if (end.length !== 1 || typeof parent.question_id !== \"number\") throw new ValidationError(operation, [input.endDateField]);\n const encoded = questions.filter(q => ![\"label\", \"blank\"].includes(String(q.question_type))).flatMap(q => {\n if (q.question_type === \"provider\") throw new ValidationError(\"mobile provider answers are unsupported\", [String(q.virt_field_name)]);\n if (typeof q.question_id !== \"number\" || typeof q.question_type !== \"string\" || typeof q.virt_field_name !== \"string\") throw new WellSkyError(\"protocol\", readEndpoint);\n const value = q.virt_field_name === input.endDateField ? input.endDate : q.answer_value ?? \"\";\n if (typeof value !== \"string\") throw new WellSkyError(\"protocol\", readEndpoint);\n if (q.question_type === \"yes_no\" && value === \"\") return [];\n return [{ question_id: q.question_id, question_type: q.question_type, virt_field_name: q.virt_field_name, answer_value: value }];\n });\n Object.assign(expected, snapshot(parent, input.endDateField, calendarOnly));\n expected[`${input.recordsetId}/${input.endDateField}`] = dateValue(input.endDate, calendarOnly);\n body = [{ question_id: parent.question_id, question_type: \"sub_assessment\", virt_field_name: input.parentField, answer_value: \"\", subAssessmentQuestionAnswers: [{ recordset_id: input.recordsetId, isDeleted: false, subAssessments: encoded }] }];\n },\n submit: options => this.#source.write({ ...input, ...options }, body),\n readBack: async options => {\n const parent = parentFrom(await this.#source.read({ ...input, ...options }), input.parentField);\n const records = objectRows(parent.sub_assessment_answer_list ?? []);\n if (!records.some(r => r.recordset_id === input.recordsetId)) return { kind: \"absent\" };\n return { kind: \"found\", value: { data: { recordsetId: input.recordsetId }, ids: { clientId: input.clientId, recordsetId: input.recordsetId }, fields: snapshot(parent, input.endDateField, calendarOnly) } };\n },\n });\n }\n}\n"]}
1
+ {"version":3,"file":"subassessments.js","sourceRoot":"","sources":["../../src/subassessments.ts"],"names":[],"mappings":"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","sourcesContent":["import { isRecord } from \"./validation.js\";\nimport { WellSkyError } from \"./runtime.js\";\nimport type { RequestOptions } from \"./runtime.js\";\nimport { ValidationError } from \"./errors.js\";\nimport { verifyWrite } from \"./verification.js\";\nimport type { WriteResult } from \"./verification.js\";\nimport type { AddSubAssessmentQuestionWithAnswerViewModel } from \"./generated/v3-models.js\";\n\nexport interface SubassessmentContext extends RequestOptions {\n clientId: number;\n assessmentCode: string;\n effectiveDate?: string;\n}\nexport interface EndDateRequest extends SubassessmentContext {\n parentField: string;\n recordsetId: number;\n endDateField: string;\n endDate: string;\n /** Optional caller preflight for program-specific review-date or other policies. */\n preflight?: (options: RequestOptions) => Promise<void>;\n}\nexport interface SubassessmentSource {\n read: (context: SubassessmentContext) => Promise<unknown>;\n write: (context: SubassessmentContext, body: AddSubAssessmentQuestionWithAnswerViewModel[]) => Promise<unknown>;\n}\nfunction objectRows(value: unknown): Record<string, unknown>[] {\n const rows = isRecord(value) && Array.isArray(value.value) ? value.value : Array.isArray(value) ? value : value === null ? [] : [value];\n if (!rows.every(isRecord)) throw new WellSkyError(\"protocol\", \"subassessment read\");\n return rows;\n}\nfunction parentFrom(value: unknown, field: string): Record<string, unknown> {\n const matches = objectRows(value).filter(q => q.virt_field_name === field);\n if (matches.length !== 1 || !matches[0] || matches[0].question_type !== \"sub_assessment\") throw new ValidationError(\"subassessment resolution\", [field]);\n return matches[0];\n}\nfunction dateValue(value: unknown, calendarOnly = false): unknown {\n if (value === null || value === \"\" || value === undefined) return null;\n if (typeof value !== \"string\") return value;\n if (calendarOnly || /^\\d{4}-\\d{2}-\\d{2}$/.test(value)) return value.slice(0, 10);\n const iso = value.replace(\" \", \"T\").replace(/([+-]\\d{2})$/, \"$1:00\");\n if (!/(?:Z|[+-]\\d{2}:\\d{2})$/.test(iso)) return value;\n const millis = Date.parse(iso);\n return Number.isFinite(millis) ? new Date(millis).toISOString() : value;\n}\nfunction snapshot(parent: Record<string, unknown>, endDateField: string, calendarOnly: boolean): Record<string, unknown> {\n const records = objectRows(parent.sub_assessment_answer_list ?? []);\n const fields: Record<string, unknown> = { \"$recordsets\": records.map(r => r.recordset_id).sort((a, b) => Number(a) - Number(b)) };\n for (const record of records) for (const q of objectRows(record.sub_assessment_list ?? [])) {\n if (typeof q.virt_field_name !== \"string\" || typeof record.recordset_id !== \"number\") throw new WellSkyError(\"protocol\", \"subassessment read\");\n fields[`${record.recordset_id}/${q.virt_field_name}`] = q.question_type === \"date\" ? dateValue(q.answer_value, calendarOnly && q.virt_field_name === endDateField) : q.answer_value ?? null;\n }\n return fields;\n}\n\n/** Generic recordset editing; no program names, assessment codes, or replacement policy. */\nexport class SubassessmentEditor {\n readonly #tenant: string;\n readonly #source: SubassessmentSource;\n constructor(tenant: string, source: SubassessmentSource) { this.#tenant = tenant; this.#source = source; }\n\n async setEndDate(input: EndDateRequest): Promise<WriteResult<{ recordsetId: number }>> {\n const operation = \"POST /assessmentsmobile/AddAssessmentAnswer/{clientId}/{assessmentCode}\";\n const readEndpoint = \"GET /assessmentsmobile/GetAssessmentAnswers/{clientId}/{assessmentCode}\";\n const expected: Record<string, unknown> = {};\n let body: AddSubAssessmentQuestionWithAnswerViewModel[] = [];\n const calendarOnly = /^\\d{4}-\\d{2}-\\d{2}$/.test(input.endDate);\n const semanticPayload = { tenant: this.#tenant, operation, clientId: input.clientId, assessmentCode: input.assessmentCode, parentField: input.parentField, recordsetId: input.recordsetId, endDateField: input.endDateField, endDate: input.endDate, effectiveDate: input.effectiveDate ?? null };\n return verifyWrite({\n operation, readEndpoint, semanticPayload, expectedFields: expected,\n ...(input.signal ? { signal: input.signal } : {}), ...(input.correlationId === undefined ? {} : { correlationId: input.correlationId }),\n ...(input.timeoutMs === undefined ? {} : { timeoutMs: input.timeoutMs }),\n preflight: async options => {\n if (!Number.isSafeInteger(input.recordsetId) || input.recordsetId < 1 || !/^\\d{4}-\\d{2}-\\d{2}(?:$|[T ])/.test(input.endDate)) throw new ValidationError(operation, [\"recordsetId\", \"endDate\"]);\n const calendar = input.endDate.slice(0, 10);\n const day = new Date(`${calendar}T00:00:00Z`);\n if (!Number.isFinite(day.getTime()) || day.toISOString().slice(0, 10) !== calendar) throw new ValidationError(operation, [\"endDate\"]);\n if (!calendarOnly && !Number.isFinite(Date.parse(input.endDate.replace(\" \", \"T\").replace(/([+-]\\d{2})$/, \"$1:00\")))) throw new ValidationError(operation, [\"endDate\"]);\n await input.preflight?.(options);\n const parent = parentFrom(await this.#source.read({ ...input, ...options }), input.parentField);\n const records = objectRows(parent.sub_assessment_answer_list ?? []);\n const selected = records.filter(r => r.recordset_id === input.recordsetId);\n if (selected.length !== 1 || !selected[0]) throw new ValidationError(operation, [\"recordsetId\"]);\n // A row read omits cells never answered, so fall back to the parent's question list.\n const isEnd = (q: Record<string, unknown>) => q.virt_field_name === input.endDateField && q.question_type === \"date\" && typeof q.question_id === \"number\";\n const inRow = objectRows(selected[0].sub_assessment_list ?? []).filter(isEnd);\n const end = inRow.length ? inRow : objectRows(parent.sub_assessment_question_list ?? []).filter(isEnd);\n if (end.length !== 1 || !end[0] || typeof parent.question_id !== \"number\") throw new ValidationError(operation, [input.endDateField]);\n // Send only the end-date cell. Mobile updates the sent cells of the recordset and keeps the\n // rest, including provider and yes/no answers it cannot write itself (live, November 2, 2026).\n const encoded = [{ question_id: end[0].question_id as number, question_type: \"date\", virt_field_name: input.endDateField, answer_value: input.endDate }];\n Object.assign(expected, snapshot(parent, input.endDateField, calendarOnly));\n expected[`${input.recordsetId}/${input.endDateField}`] = dateValue(input.endDate, calendarOnly);\n body = [{ question_id: parent.question_id, question_type: \"sub_assessment\", virt_field_name: input.parentField, answer_value: \"\", subAssessmentQuestionAnswers: [{ recordset_id: input.recordsetId, isDeleted: false, subAssessments: encoded }] }];\n },\n submit: options => this.#source.write({ ...input, ...options }, body),\n readBack: async options => {\n const parent = parentFrom(await this.#source.read({ ...input, ...options }), input.parentField);\n const records = objectRows(parent.sub_assessment_answer_list ?? []);\n if (!records.some(r => r.recordset_id === input.recordsetId)) return { kind: \"absent\" };\n return { kind: \"found\", value: { data: { recordsetId: input.recordsetId }, ids: { clientId: input.clientId, recordsetId: input.recordsetId }, fields: snapshot(parent, input.endDateField, calendarOnly) } };\n },\n });\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../../src/transport.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAA+B,aAAa,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAElH,OAAO,KAAK,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAI3E,OAAO,KAAK,EAAe,YAAY,EAAE,MAAM,cAAc,CAAC;AAG9D,UAAU,SAAU,SAAQ,cAAc;IACxC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAiDD,qBAAa,SAAS;;gBAgBR,OAAO,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc;IA4B5E,IAAI,MAAM,IAAI,MAAM,CAAyB;IAC7C,IAAI,OAAO,IAAI,MAAM,CAA0B;IAC/C,MAAM,IAAI,YAAY;IAyHhB,OAAO,CAAC,CAAC,EAAE,UAAU,EAAE,mBAAmB,EAAE,IAAI,EAAE,SAAS,GAAG,OAAO,CAAC,CAAC,CAAC;IAwEvE,QAAQ,CAAC,CAAC,EAAE,UAAU,EAAE,mBAAmB,EAAE,IAAI,EAAE,SAAS,GAAG,iBAAiB,GAAG,cAAc,CAAC,CAAC,CAAC;CAe5G"}
1
+ {"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../../src/transport.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAA+B,aAAa,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAElH,OAAO,KAAK,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAI3E,OAAO,KAAK,EAAe,YAAY,EAAE,MAAM,cAAc,CAAC;AAG9D,UAAU,SAAU,SAAQ,cAAc;IACxC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAiDD,qBAAa,SAAS;;gBAiBR,OAAO,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc;IA8B5E,IAAI,MAAM,IAAI,MAAM,CAAyB;IAC7C,IAAI,OAAO,IAAI,MAAM,CAA0B;IAC/C,MAAM,IAAI,YAAY;IA4HhB,OAAO,CAAC,CAAC,EAAE,UAAU,EAAE,mBAAmB,EAAE,IAAI,EAAE,SAAS,GAAG,OAAO,CAAC,CAAC,CAAC;IAwEvE,QAAQ,CAAC,CAAC,EAAE,UAAU,EAAE,mBAAmB,EAAE,IAAI,EAAE,SAAS,GAAG,iBAAiB,GAAG,cAAc,CAAC,CAAC,CAAC;CAe5G"}
@@ -70,6 +70,7 @@ export class Transport {
70
70
  #control;
71
71
  #observers;
72
72
  #mobileDateCorrection;
73
+ #captureErrorBody;
73
74
  constructor(options, version, schemas) {
74
75
  if (typeof window !== "undefined" || !("process" in globalThis))
75
76
  throw new TypeError("WellSky SDK requires a server-side Node.js runtime");
@@ -94,6 +95,9 @@ export class Transport {
94
95
  if (correction !== undefined && (!Number.isSafeInteger(correction) || Math.abs(correction) > 840))
95
96
  throw new ValidationError("client configuration", ["mobileAssessmentDateCorrectionMinutes"]);
96
97
  this.#mobileDateCorrection = correction;
98
+ if (options.captureErrorBody !== undefined && typeof options.captureErrorBody !== "boolean")
99
+ throw new ValidationError("client configuration", ["captureErrorBody"]);
100
+ this.#captureErrorBody = options.captureErrorBody === true;
97
101
  this.#timeout = positiveInteger(options.timeoutMs ?? 30_000, "timeoutMs");
98
102
  this.#retries = positiveInteger(options.maxReadRetries ?? 2, "maxReadRetries", 0);
99
103
  this.#retryBase = positiveInteger(options.retryBaseDelayMs ?? 250, "retryBaseDelayMs", 0);
@@ -168,15 +172,23 @@ export class Transport {
168
172
  }
169
173
  async #read(response, operation, allowText = false) {
170
174
  if (!response.ok) {
171
- // Discard upstream error content; it may contain client data or credentials.
172
- await response.body?.cancel();
173
175
  const requestId = response.headers.get("x-request-id") ?? response.headers.get("request-id") ?? undefined;
174
176
  const wait = retryAfter(response.headers);
177
+ let responseBody;
178
+ // Retain raw content only by explicit opt-in, never for authentication or throttling.
179
+ if (this.#captureErrorBody && operation !== "POST /authentication/SetAuthKey" && ![401, 403, 429].includes(response.status)) {
180
+ try {
181
+ responseBody = await response.text();
182
+ }
183
+ catch { /* Keep the HTTP failure if diagnostic reading fails. */ }
184
+ }
185
+ else
186
+ await response.body?.cancel();
175
187
  if (response.status === 429)
176
188
  throw new ThrottledError(operation, wait ?? this.#retryBase, response.status, requestId);
177
189
  if (response.status === 401 || response.status === 403)
178
190
  throw new AuthError(operation, response.status);
179
- throw new UpstreamError(operation, response.status, requestId, wait);
191
+ throw new UpstreamError(operation, response.status, requestId, wait, responseBody);
180
192
  }
181
193
  const text = await response.text();
182
194
  if (!text.trim())
@@ -1 +1 @@
1
- {"version":3,"file":"transport.js","sourceRoot":"","sources":["../../src/transport.ts"],"names":[],"mappings":"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","sourcesContent":["import { WellSkyError, toItems } from \"./runtime.js\";\nimport type { ApiResponse, Authentication, ClientOptions, PaginationOptions, RequestOptions } from \"./runtime.js\";\nimport { decodeResponse, isRecord, matches } from \"./validation.js\";\nimport type { OperationDefinition, SchemaRegistry } from \"./validation.js\";\nimport { AuthError, TenantMismatchError, ThrottledError, UpstreamError, ValidationError } from \"./errors.js\";\nimport { emit, identity, requestControl, sharedAuthentication, tokenMintQueue } from \"./control.js\";\nimport type { RequestControl, SharedAuthentication } from \"./control.js\";\nimport type { ClientEvent, ClientHealth } from \"./runtime.js\";\nimport { correctMobileEffectiveDate } from \"./effective-date.js\";\n\ninterface Arguments extends RequestOptions {\n path?: object;\n query?: object;\n body?: unknown;\n}\nconst retryStatuses = new Set([408, 429, 500, 502, 503, 504]);\n\nfunction positiveInteger(value: number, name: string, minimum = 1): number {\n if (!Number.isSafeInteger(value) || value < minimum) throw new TypeError(`${name} must be an integer >= ${minimum}`);\n return value;\n}\n\nfunction expiry(token: string): number {\n try {\n const part = token.split(\".\")[1];\n if (!part) return 0;\n const base64 = part.replaceAll(\"-\", \"+\").replaceAll(\"_\", \"/\");\n const parsed: unknown = JSON.parse(atob(base64.padEnd(Math.ceil(base64.length / 4) * 4, \"=\")));\n return isRecord(parsed) && typeof parsed.exp === \"number\" && Number.isFinite(parsed.exp) ? parsed.exp * 1000 : 0;\n } catch { return 0; }\n}\n\nfunction retryAfter(headers: Headers): number | undefined {\n const raw = headers.get(\"retry-after\");\n if (!raw) return undefined;\n const seconds = Number(raw);\n const delay = Number.isFinite(seconds) ? seconds * 1000 : Date.parse(raw) - Date.now();\n return Number.isFinite(delay) ? Math.max(0, delay) : undefined;\n}\n\nfunction abortError(signal: AbortSignal, operation: string): WellSkyError {\n return new WellSkyError(signal.reason instanceof DOMException && signal.reason.name === \"TimeoutError\" ? \"timeout\" : \"aborted\", operation);\n}\n\n/** A caller can cancel its wait without cancelling authentication shared by other callers. */\nfunction withSignal<T>(promise: Promise<T>, signal: AbortSignal, operation: string): Promise<T> {\n return new Promise((resolve, reject) => {\n const abort = () => reject(abortError(signal, operation));\n if (signal.aborted) abort();\n else signal.addEventListener(\"abort\", abort, { once: true });\n promise.then(resolve, reject).finally(() => signal.removeEventListener(\"abort\", abort));\n });\n}\n\nfunction delay(ms: number, signal: AbortSignal, operation: string): Promise<void> {\n return new Promise((resolve, reject) => {\n if (signal.aborted) { reject(abortError(signal, operation)); return; }\n const abort = () => { clearTimeout(timer); reject(abortError(signal, operation)); };\n const timer = setTimeout(() => { signal.removeEventListener(\"abort\", abort); resolve(); }, ms);\n signal.addEventListener(\"abort\", abort, { once: true });\n });\n}\n\nexport class Transport {\n readonly #baseUrl: string;\n readonly #tenant: string;\n readonly #version: string;\n readonly #auth: Authentication;\n readonly #fetch: typeof globalThis.fetch;\n readonly #schemas: SchemaRegistry;\n readonly #timeout: number;\n readonly #retries: number;\n readonly #retryBase: number;\n readonly #retryMax: number;\n readonly #shared: Promise<SharedAuthentication>;\n readonly #control: RequestControl;\n readonly #observers: Pick<ClientOptions, \"hooks\" | \"logger\">;\n readonly #mobileDateCorrection: number | undefined;\n\n constructor(options: ClientOptions, version: string, schemas: SchemaRegistry) {\n if (typeof window !== \"undefined\" || !(\"process\" in globalThis)) throw new TypeError(\"WellSky SDK requires a server-side Node.js runtime\");\n if (!options.tenant.trim() || /[\\r\\n]/.test(options.tenant)) throw new TypeError(\"tenant is required and must be a valid header value\");\n const url = new URL(options.baseUrl ?? \"https://csclientapi.wellsky.com/client-api-prod\");\n if (!['https:', 'http:'].includes(url.protocol) || url.username || url.password || url.search || url.hash) throw new TypeError(\"baseUrl must be an HTTP(S) URL without credentials, query, or fragment\");\n if (url.protocol === 'http:' && !['localhost', '127.0.0.1', '[::1]'].includes(url.hostname)) throw new TypeError(\"Use HTTPS except for loopback testing\");\n if (options.auth.kind === \"credentials\" && (!options.auth.username.trim() || !options.auth.password)) throw new TypeError(\"username and password are required\");\n if (options.auth.kind === \"token\" && (!options.auth.token.trim() || /\\s/.test(options.auth.token))) throw new TypeError(\"token must be a non-empty bearer token\");\n this.#baseUrl = url.toString().replace(/\\/$/, \"\");\n this.#tenant = options.tenant;\n this.#version = version;\n this.#auth = { ...options.auth };\n this.#fetch = options.fetch ?? globalThis.fetch;\n this.#schemas = schemas;\n const correction = options.mobileAssessmentDateCorrectionMinutes;\n if (correction !== undefined && (!Number.isSafeInteger(correction) || Math.abs(correction) > 840)) throw new ValidationError(\"client configuration\", [\"mobileAssessmentDateCorrectionMinutes\"]);\n this.#mobileDateCorrection = correction;\n this.#timeout = positiveInteger(options.timeoutMs ?? 30_000, \"timeoutMs\");\n this.#retries = positiveInteger(options.maxReadRetries ?? 2, \"maxReadRetries\", 0);\n this.#retryBase = positiveInteger(options.retryBaseDelayMs ?? 250, \"retryBaseDelayMs\", 0);\n this.#retryMax = positiveInteger(options.maxRetryDelayMs ?? 30_000, \"maxRetryDelayMs\", 0);\n const scope = JSON.stringify([this.#baseUrl, this.#tenant, identity(this.#fetch)]);\n this.#control = requestControl(scope, options);\n this.#shared = sharedAuthentication(scope, this.#auth);\n this.#observers = { ...(options.hooks ? { hooks: { ...options.hooks } } : {}), ...(options.logger ? { logger: options.logger } : {}) };\n if (this.#auth.kind === \"token\") this.#checkTokenTenant(this.#auth.token);\n }\n\n get tenant(): string { return this.#tenant; }\n get baseUrl(): string { return this.#baseUrl; }\n health(): ClientHealth { return this.#control.health(); }\n\n #checkTenant(value: unknown, operation: string): void {\n if (!isRecord(value)) return;\n for (const key of [\"tenant\", \"tenantCode\", \"tenant_code\", \"x-tenant\"]) {\n if (value[key] !== undefined && value[key] !== null && value[key] !== this.#tenant) throw new TenantMismatchError(operation);\n }\n }\n #checkTokenTenant(token: string): void {\n let payload: unknown;\n try {\n const segment = token.split(\".\")[1];\n if (!segment) return;\n const base64 = segment.replaceAll(\"-\", \"+\").replaceAll(\"_\", \"/\");\n payload = JSON.parse(atob(base64.padEnd(Math.ceil(base64.length / 4) * 4, \"=\")));\n } catch { return; }\n this.#checkTenant(payload, \"authentication token\");\n }\n\n async #send(url: string | URL, init: RequestInit & { signal: AbortSignal }, operation: string, correlationId: string, retryCount: number): Promise<Response> {\n this.#control.check(operation);\n const release = await this.#control.semaphore.acquire(init.signal, operation);\n const started = Date.now();\n const base = { operation, correlationId, retryCount };\n try {\n this.#control.check(operation);\n const headers = new Headers(init.headers);\n headers.set(\"x-correlation-id\", correlationId);\n emit(this.#observers, { ...base, type: \"request\" });\n const response = await this.#fetch(url, { ...init, headers });\n const event: ClientEvent = { ...base, type: \"response\", status: response.status, durationMs: Date.now() - started };\n emit(this.#observers, event);\n if (response.status === 429) emit(this.#observers, { ...event, type: \"throttle\", retryAfterMs: retryAfter(response.headers) ?? this.#retryBase });\n const until = this.#control.failed(response.status);\n if (until !== undefined) emit(this.#observers, { ...base, type: \"cooldown\", until: new Date(until).toISOString() });\n if (response.headers.has(\"x-tenant\") && response.headers.get(\"x-tenant\") !== this.#tenant) {\n await response.body?.cancel(); throw new TenantMismatchError(operation);\n }\n // Hold the concurrency slot through body consumption, not merely until headers arrive.\n const body = await response.arrayBuffer();\n return new Response(response.status === 204 || response.status === 205 || response.status === 304 ? null : body, { status: response.status, statusText: response.statusText, headers: response.headers });\n } finally { release(); }\n }\n\n #headers(token?: string): Headers {\n const headers = new Headers({ Accept: \"application/json\", \"x-tenant\": this.#tenant, \"x-version\": this.#version });\n if (token) headers.set(\"Authorization\", `Bearer ${token}`);\n return headers;\n }\n\n async #read(response: Response, operation: string, allowText = false): Promise<unknown> {\n if (!response.ok) {\n // Discard upstream error content; it may contain client data or credentials.\n await response.body?.cancel();\n const requestId = response.headers.get(\"x-request-id\") ?? response.headers.get(\"request-id\") ?? undefined;\n const wait = retryAfter(response.headers);\n if (response.status === 429) throw new ThrottledError(operation, wait ?? this.#retryBase, response.status, requestId);\n if (response.status === 401 || response.status === 403) throw new AuthError(operation, response.status);\n throw new UpstreamError(operation, response.status, requestId, wait);\n }\n const text = await response.text();\n if (!text.trim()) return null;\n let value: unknown;\n try { value = JSON.parse(text); }\n catch {\n if (allowText) return text;\n throw new WellSkyError(\"protocol\", operation);\n }\n this.#checkTenant(value, operation);\n return value;\n }\n\n async #mint(forceRefresh: boolean, shared: SharedAuthentication): Promise<string> {\n const operation = \"POST /authentication/SetAuthKey\";\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(new DOMException(\"Deadline exceeded\", \"TimeoutError\")), this.#timeout);\n const signal = controller.signal;\n let release: (() => void) | undefined;\n try {\n release = await tokenMintQueue.acquire(signal, operation);\n this.#control.check(operation);\n const correlationId = crypto.randomUUID();\n this.#control.tokenMintCount++;\n emit(this.#observers, { type: \"tokenMint\", operation, correlationId, retryCount: 0 });\n let token: unknown;\n if (this.#auth.kind === \"provider\") token = await withSignal(Promise.resolve().then(() => this.#auth.kind === \"provider\" ? this.#auth.getToken({ forceRefresh, signal }) : \"\"), signal, operation);\n else if (this.#auth.kind === \"credentials\") {\n const headers = this.#headers();\n headers.set(\"Content-Type\", \"application/json\");\n const response = await this.#send(`${this.#baseUrl}/authentication/SetAuthKey`, {\n method: \"POST\", headers, body: JSON.stringify({ username: this.#auth.username, password: this.#auth.password }), signal, redirect: \"error\", cache: \"no-store\",\n }, operation, correlationId, 0);\n const result = await this.#read(response, operation);\n token = isRecord(result) ? result.token : undefined;\n }\n if (typeof token !== \"string\" || !token || /\\s/.test(token)) throw new WellSkyError(\"protocol\", operation);\n this.#checkTokenTenant(token);\n const expiresAt = expiry(token);\n if (expiresAt !== 0 && expiresAt <= Date.now()) throw new WellSkyError(\"protocol\", operation);\n shared.cached = { token, expiresAt };\n return token;\n } catch (error) {\n if (signal.aborted) throw abortError(signal, operation);\n if (error instanceof WellSkyError) throw error;\n throw new WellSkyError(\"network\", operation);\n } finally { release?.(); clearTimeout(timer); }\n }\n\n async #token(rejectedToken?: string): Promise<string | undefined> {\n if (this.#auth.kind === \"none\") return Promise.resolve(undefined);\n if (this.#auth.kind === \"token\") return Promise.resolve(this.#auth.token);\n const shared = await this.#shared;\n // An older request's late 401 must not evict a newer token.\n if (rejectedToken && shared.cached?.token !== rejectedToken && shared.cached) return shared.cached.token;\n if (shared.inFlight) return shared.inFlight;\n if (!rejectedToken && shared.cached && shared.cached.expiresAt > Date.now() + 120_000) return shared.cached.token;\n shared.cached = undefined;\n shared.inFlight = this.#mint(Boolean(rejectedToken), shared).finally(() => { shared.inFlight = undefined; });\n return shared.inFlight;\n }\n\n async execute<T>(definition: OperationDefinition, args: Arguments): Promise<T> {\n const operation = `${definition.method} ${definition.path}`;\n const correlationId = args.correlationId ?? crypto.randomUUID();\n if (!/^[A-Za-z0-9_.:-]{1,128}$/.test(correlationId)) throw new ValidationError(operation, [\"correlationId\"]);\n const timeout = positiveInteger(args.timeoutMs ?? this.#timeout, \"timeoutMs\");\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(new DOMException(\"Deadline exceeded\", \"TimeoutError\")), timeout);\n const signal = args.signal ? AbortSignal.any([args.signal, controller.signal]) : controller.signal;\n try {\n if (signal.aborted) throw abortError(signal, operation);\n this.#control.check(operation);\n if (!matches(args.path ?? {}, definition.pathSchema, this.#schemas, \"request\") || !matches(args.query ?? {}, definition.querySchema, this.#schemas, \"request\") || (definition.bodySchema && !matches(args.body, definition.bodySchema, this.#schemas, \"request\"))) throw new ValidationError(operation);\n // Check file bytes before multipart construction or credential authentication.\n if (definition.multipart && isRecord(args.body) && args.body.fileData instanceof Blob && args.body.fileData.size > 10_000_000) throw new ValidationError(operation, [\"fileData\"]);\n const pathValues = new Map(Object.entries(args.path ?? {}));\n const path = definition.path.replace(/\\{([^}]+)\\}/g, (_, name: string) => {\n const value = String(pathValues.get(name));\n if (value === \".\" || value === \"..\") throw new WellSkyError(\"validation\", operation);\n return encodeURIComponent(value);\n });\n const url = new URL(this.#baseUrl + path);\n for (const [name, value] of Object.entries(args.query ?? {})) {\n if (value !== undefined && value !== null) {\n const encoded = this.#mobileDateCorrection !== undefined && name === \"dateEffective\" && operation === \"POST /assessmentsmobile/AddAssessmentAnswer/{clientId}/{assessmentCode}\"\n ? correctMobileEffectiveDate(value, this.#mobileDateCorrection, operation) : String(value);\n url.searchParams.set(name, encoded);\n }\n }\n let body: string | FormData | undefined;\n if (definition.multipart && isRecord(args.body)) {\n body = new FormData();\n for (const [name, value] of Object.entries(args.body)) {\n if (value !== undefined && value !== null) body.append(name, value instanceof Blob ? value : String(value));\n }\n } else if (args.body !== undefined) body = JSON.stringify(args.body);\n let token = definition.authenticated ? await withSignal(this.#token(), signal, operation) : undefined;\n let refreshed = false;\n let attempts = 0;\n while (true) {\n try {\n const headers = this.#headers(token);\n if (typeof body === \"string\") headers.set(\"Content-Type\", \"application/json\");\n const response = await this.#send(url, { method: definition.method, headers, ...(body === undefined ? {} : { body }), signal, redirect: \"error\", cache: \"no-store\" }, operation, correlationId, attempts);\n // Reads can refresh once. Writes are never automatically sent twice, even after a 401.\n if (response.status === 401 && definition.method === \"GET\" && definition.authenticated && !refreshed && (this.#auth.kind === \"credentials\" || this.#auth.kind === \"provider\")) {\n await response.body?.cancel();\n refreshed = true;\n token = await withSignal(this.#token(token), signal, operation);\n continue;\n }\n const result = await this.#read(response, operation, definition.responseSchema === undefined);\n return decodeResponse<T>(result, definition.responseSchema, this.#schemas, operation);\n } catch (error) {\n if (signal.aborted) throw abortError(signal, operation);\n const failure = error instanceof WellSkyError ? error : new WellSkyError(\"network\", operation);\n const retryable = failure.kind === \"network\" || ((failure.kind === \"http\" || failure.kind === \"throttled\") && retryStatuses.has(failure.status ?? 0));\n if (definition.method !== \"GET\" || failure.operation !== operation || !retryable || attempts >= this.#retries) throw failure;\n const wait = failure.retryAfterMs ?? Math.min(this.#retryMax, this.#retryBase * 2 ** attempts * (1 + Math.random() * 0.2));\n // Never retry earlier than Retry-After. Return the error if the delay exceeds our bound.\n if (wait > this.#retryMax) throw failure;\n attempts++;\n await delay(wait, signal, operation);\n }\n }\n } catch (error) {\n if (signal.aborted) { const error = abortError(signal, operation); error.correlationId = correlationId; throw error; }\n if (error instanceof WellSkyError) error.correlationId = correlationId;\n if (error instanceof WellSkyError || error instanceof TypeError) throw error;\n throw new WellSkyError(\"network\", operation);\n } finally { clearTimeout(timer); }\n }\n\n async *paginate<T>(definition: OperationDefinition, args: Arguments & PaginationOptions): AsyncGenerator<T> {\n const operation = `${definition.method} ${definition.path}`;\n const query = Object.fromEntries(Object.entries(args.query ?? {}));\n const start = positiveInteger(typeof query.startPage === \"number\" ? query.startPage : 1, \"startPage\");\n positiveInteger(typeof query.perPage === \"number\" ? query.perPage : 30, \"perPage\");\n const maxPages = positiveInteger(args.maxPages ?? 10_000, \"maxPages\");\n for (let page = 0; page < maxPages; page++) {\n const response = await this.execute<ApiResponse<T>>(definition, { ...args, query: { perPage: 30, ...query, startPage: start + page } });\n const items = toItems(response);\n if (!items.length) return;\n yield* items;\n // Continue through short pages: some tenants cap perPage below the requested size.\n }\n throw new WellSkyError(\"pagination\", operation);\n }\n}\n"]}
1
+ {"version":3,"file":"transport.js","sourceRoot":"","sources":["../../src/transport.ts"],"names":[],"mappings":"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","sourcesContent":["import { WellSkyError, toItems } from \"./runtime.js\";\nimport type { ApiResponse, Authentication, ClientOptions, PaginationOptions, RequestOptions } from \"./runtime.js\";\nimport { decodeResponse, isRecord, matches } from \"./validation.js\";\nimport type { OperationDefinition, SchemaRegistry } from \"./validation.js\";\nimport { AuthError, TenantMismatchError, ThrottledError, UpstreamError, ValidationError } from \"./errors.js\";\nimport { emit, identity, requestControl, sharedAuthentication, tokenMintQueue } from \"./control.js\";\nimport type { RequestControl, SharedAuthentication } from \"./control.js\";\nimport type { ClientEvent, ClientHealth } from \"./runtime.js\";\nimport { correctMobileEffectiveDate } from \"./effective-date.js\";\n\ninterface Arguments extends RequestOptions {\n path?: object;\n query?: object;\n body?: unknown;\n}\nconst retryStatuses = new Set([408, 429, 500, 502, 503, 504]);\n\nfunction positiveInteger(value: number, name: string, minimum = 1): number {\n if (!Number.isSafeInteger(value) || value < minimum) throw new TypeError(`${name} must be an integer >= ${minimum}`);\n return value;\n}\n\nfunction expiry(token: string): number {\n try {\n const part = token.split(\".\")[1];\n if (!part) return 0;\n const base64 = part.replaceAll(\"-\", \"+\").replaceAll(\"_\", \"/\");\n const parsed: unknown = JSON.parse(atob(base64.padEnd(Math.ceil(base64.length / 4) * 4, \"=\")));\n return isRecord(parsed) && typeof parsed.exp === \"number\" && Number.isFinite(parsed.exp) ? parsed.exp * 1000 : 0;\n } catch { return 0; }\n}\n\nfunction retryAfter(headers: Headers): number | undefined {\n const raw = headers.get(\"retry-after\");\n if (!raw) return undefined;\n const seconds = Number(raw);\n const delay = Number.isFinite(seconds) ? seconds * 1000 : Date.parse(raw) - Date.now();\n return Number.isFinite(delay) ? Math.max(0, delay) : undefined;\n}\n\nfunction abortError(signal: AbortSignal, operation: string): WellSkyError {\n return new WellSkyError(signal.reason instanceof DOMException && signal.reason.name === \"TimeoutError\" ? \"timeout\" : \"aborted\", operation);\n}\n\n/** A caller can cancel its wait without cancelling authentication shared by other callers. */\nfunction withSignal<T>(promise: Promise<T>, signal: AbortSignal, operation: string): Promise<T> {\n return new Promise((resolve, reject) => {\n const abort = () => reject(abortError(signal, operation));\n if (signal.aborted) abort();\n else signal.addEventListener(\"abort\", abort, { once: true });\n promise.then(resolve, reject).finally(() => signal.removeEventListener(\"abort\", abort));\n });\n}\n\nfunction delay(ms: number, signal: AbortSignal, operation: string): Promise<void> {\n return new Promise((resolve, reject) => {\n if (signal.aborted) { reject(abortError(signal, operation)); return; }\n const abort = () => { clearTimeout(timer); reject(abortError(signal, operation)); };\n const timer = setTimeout(() => { signal.removeEventListener(\"abort\", abort); resolve(); }, ms);\n signal.addEventListener(\"abort\", abort, { once: true });\n });\n}\n\nexport class Transport {\n readonly #baseUrl: string;\n readonly #tenant: string;\n readonly #version: string;\n readonly #auth: Authentication;\n readonly #fetch: typeof globalThis.fetch;\n readonly #schemas: SchemaRegistry;\n readonly #timeout: number;\n readonly #retries: number;\n readonly #retryBase: number;\n readonly #retryMax: number;\n readonly #shared: Promise<SharedAuthentication>;\n readonly #control: RequestControl;\n readonly #observers: Pick<ClientOptions, \"hooks\" | \"logger\">;\n readonly #mobileDateCorrection: number | undefined;\n readonly #captureErrorBody: boolean;\n\n constructor(options: ClientOptions, version: string, schemas: SchemaRegistry) {\n if (typeof window !== \"undefined\" || !(\"process\" in globalThis)) throw new TypeError(\"WellSky SDK requires a server-side Node.js runtime\");\n if (!options.tenant.trim() || /[\\r\\n]/.test(options.tenant)) throw new TypeError(\"tenant is required and must be a valid header value\");\n const url = new URL(options.baseUrl ?? \"https://csclientapi.wellsky.com/client-api-prod\");\n if (!['https:', 'http:'].includes(url.protocol) || url.username || url.password || url.search || url.hash) throw new TypeError(\"baseUrl must be an HTTP(S) URL without credentials, query, or fragment\");\n if (url.protocol === 'http:' && !['localhost', '127.0.0.1', '[::1]'].includes(url.hostname)) throw new TypeError(\"Use HTTPS except for loopback testing\");\n if (options.auth.kind === \"credentials\" && (!options.auth.username.trim() || !options.auth.password)) throw new TypeError(\"username and password are required\");\n if (options.auth.kind === \"token\" && (!options.auth.token.trim() || /\\s/.test(options.auth.token))) throw new TypeError(\"token must be a non-empty bearer token\");\n this.#baseUrl = url.toString().replace(/\\/$/, \"\");\n this.#tenant = options.tenant;\n this.#version = version;\n this.#auth = { ...options.auth };\n this.#fetch = options.fetch ?? globalThis.fetch;\n this.#schemas = schemas;\n const correction = options.mobileAssessmentDateCorrectionMinutes;\n if (correction !== undefined && (!Number.isSafeInteger(correction) || Math.abs(correction) > 840)) throw new ValidationError(\"client configuration\", [\"mobileAssessmentDateCorrectionMinutes\"]);\n this.#mobileDateCorrection = correction;\n if (options.captureErrorBody !== undefined && typeof options.captureErrorBody !== \"boolean\") throw new ValidationError(\"client configuration\", [\"captureErrorBody\"]);\n this.#captureErrorBody = options.captureErrorBody === true;\n this.#timeout = positiveInteger(options.timeoutMs ?? 30_000, \"timeoutMs\");\n this.#retries = positiveInteger(options.maxReadRetries ?? 2, \"maxReadRetries\", 0);\n this.#retryBase = positiveInteger(options.retryBaseDelayMs ?? 250, \"retryBaseDelayMs\", 0);\n this.#retryMax = positiveInteger(options.maxRetryDelayMs ?? 30_000, \"maxRetryDelayMs\", 0);\n const scope = JSON.stringify([this.#baseUrl, this.#tenant, identity(this.#fetch)]);\n this.#control = requestControl(scope, options);\n this.#shared = sharedAuthentication(scope, this.#auth);\n this.#observers = { ...(options.hooks ? { hooks: { ...options.hooks } } : {}), ...(options.logger ? { logger: options.logger } : {}) };\n if (this.#auth.kind === \"token\") this.#checkTokenTenant(this.#auth.token);\n }\n\n get tenant(): string { return this.#tenant; }\n get baseUrl(): string { return this.#baseUrl; }\n health(): ClientHealth { return this.#control.health(); }\n\n #checkTenant(value: unknown, operation: string): void {\n if (!isRecord(value)) return;\n for (const key of [\"tenant\", \"tenantCode\", \"tenant_code\", \"x-tenant\"]) {\n if (value[key] !== undefined && value[key] !== null && value[key] !== this.#tenant) throw new TenantMismatchError(operation);\n }\n }\n #checkTokenTenant(token: string): void {\n let payload: unknown;\n try {\n const segment = token.split(\".\")[1];\n if (!segment) return;\n const base64 = segment.replaceAll(\"-\", \"+\").replaceAll(\"_\", \"/\");\n payload = JSON.parse(atob(base64.padEnd(Math.ceil(base64.length / 4) * 4, \"=\")));\n } catch { return; }\n this.#checkTenant(payload, \"authentication token\");\n }\n\n async #send(url: string | URL, init: RequestInit & { signal: AbortSignal }, operation: string, correlationId: string, retryCount: number): Promise<Response> {\n this.#control.check(operation);\n const release = await this.#control.semaphore.acquire(init.signal, operation);\n const started = Date.now();\n const base = { operation, correlationId, retryCount };\n try {\n this.#control.check(operation);\n const headers = new Headers(init.headers);\n headers.set(\"x-correlation-id\", correlationId);\n emit(this.#observers, { ...base, type: \"request\" });\n const response = await this.#fetch(url, { ...init, headers });\n const event: ClientEvent = { ...base, type: \"response\", status: response.status, durationMs: Date.now() - started };\n emit(this.#observers, event);\n if (response.status === 429) emit(this.#observers, { ...event, type: \"throttle\", retryAfterMs: retryAfter(response.headers) ?? this.#retryBase });\n const until = this.#control.failed(response.status);\n if (until !== undefined) emit(this.#observers, { ...base, type: \"cooldown\", until: new Date(until).toISOString() });\n if (response.headers.has(\"x-tenant\") && response.headers.get(\"x-tenant\") !== this.#tenant) {\n await response.body?.cancel(); throw new TenantMismatchError(operation);\n }\n // Hold the concurrency slot through body consumption, not merely until headers arrive.\n const body = await response.arrayBuffer();\n return new Response(response.status === 204 || response.status === 205 || response.status === 304 ? null : body, { status: response.status, statusText: response.statusText, headers: response.headers });\n } finally { release(); }\n }\n\n #headers(token?: string): Headers {\n const headers = new Headers({ Accept: \"application/json\", \"x-tenant\": this.#tenant, \"x-version\": this.#version });\n if (token) headers.set(\"Authorization\", `Bearer ${token}`);\n return headers;\n }\n\n async #read(response: Response, operation: string, allowText = false): Promise<unknown> {\n if (!response.ok) {\n const requestId = response.headers.get(\"x-request-id\") ?? response.headers.get(\"request-id\") ?? undefined;\n const wait = retryAfter(response.headers);\n let responseBody: string | undefined;\n // Retain raw content only by explicit opt-in, never for authentication or throttling.\n if (this.#captureErrorBody && operation !== \"POST /authentication/SetAuthKey\" && ![401, 403, 429].includes(response.status)) {\n try { responseBody = await response.text(); } catch { /* Keep the HTTP failure if diagnostic reading fails. */ }\n } else await response.body?.cancel();\n if (response.status === 429) throw new ThrottledError(operation, wait ?? this.#retryBase, response.status, requestId);\n if (response.status === 401 || response.status === 403) throw new AuthError(operation, response.status);\n throw new UpstreamError(operation, response.status, requestId, wait, responseBody);\n }\n const text = await response.text();\n if (!text.trim()) return null;\n let value: unknown;\n try { value = JSON.parse(text); }\n catch {\n if (allowText) return text;\n throw new WellSkyError(\"protocol\", operation);\n }\n this.#checkTenant(value, operation);\n return value;\n }\n\n async #mint(forceRefresh: boolean, shared: SharedAuthentication): Promise<string> {\n const operation = \"POST /authentication/SetAuthKey\";\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(new DOMException(\"Deadline exceeded\", \"TimeoutError\")), this.#timeout);\n const signal = controller.signal;\n let release: (() => void) | undefined;\n try {\n release = await tokenMintQueue.acquire(signal, operation);\n this.#control.check(operation);\n const correlationId = crypto.randomUUID();\n this.#control.tokenMintCount++;\n emit(this.#observers, { type: \"tokenMint\", operation, correlationId, retryCount: 0 });\n let token: unknown;\n if (this.#auth.kind === \"provider\") token = await withSignal(Promise.resolve().then(() => this.#auth.kind === \"provider\" ? this.#auth.getToken({ forceRefresh, signal }) : \"\"), signal, operation);\n else if (this.#auth.kind === \"credentials\") {\n const headers = this.#headers();\n headers.set(\"Content-Type\", \"application/json\");\n const response = await this.#send(`${this.#baseUrl}/authentication/SetAuthKey`, {\n method: \"POST\", headers, body: JSON.stringify({ username: this.#auth.username, password: this.#auth.password }), signal, redirect: \"error\", cache: \"no-store\",\n }, operation, correlationId, 0);\n const result = await this.#read(response, operation);\n token = isRecord(result) ? result.token : undefined;\n }\n if (typeof token !== \"string\" || !token || /\\s/.test(token)) throw new WellSkyError(\"protocol\", operation);\n this.#checkTokenTenant(token);\n const expiresAt = expiry(token);\n if (expiresAt !== 0 && expiresAt <= Date.now()) throw new WellSkyError(\"protocol\", operation);\n shared.cached = { token, expiresAt };\n return token;\n } catch (error) {\n if (signal.aborted) throw abortError(signal, operation);\n if (error instanceof WellSkyError) throw error;\n throw new WellSkyError(\"network\", operation);\n } finally { release?.(); clearTimeout(timer); }\n }\n\n async #token(rejectedToken?: string): Promise<string | undefined> {\n if (this.#auth.kind === \"none\") return Promise.resolve(undefined);\n if (this.#auth.kind === \"token\") return Promise.resolve(this.#auth.token);\n const shared = await this.#shared;\n // An older request's late 401 must not evict a newer token.\n if (rejectedToken && shared.cached?.token !== rejectedToken && shared.cached) return shared.cached.token;\n if (shared.inFlight) return shared.inFlight;\n if (!rejectedToken && shared.cached && shared.cached.expiresAt > Date.now() + 120_000) return shared.cached.token;\n shared.cached = undefined;\n shared.inFlight = this.#mint(Boolean(rejectedToken), shared).finally(() => { shared.inFlight = undefined; });\n return shared.inFlight;\n }\n\n async execute<T>(definition: OperationDefinition, args: Arguments): Promise<T> {\n const operation = `${definition.method} ${definition.path}`;\n const correlationId = args.correlationId ?? crypto.randomUUID();\n if (!/^[A-Za-z0-9_.:-]{1,128}$/.test(correlationId)) throw new ValidationError(operation, [\"correlationId\"]);\n const timeout = positiveInteger(args.timeoutMs ?? this.#timeout, \"timeoutMs\");\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(new DOMException(\"Deadline exceeded\", \"TimeoutError\")), timeout);\n const signal = args.signal ? AbortSignal.any([args.signal, controller.signal]) : controller.signal;\n try {\n if (signal.aborted) throw abortError(signal, operation);\n this.#control.check(operation);\n if (!matches(args.path ?? {}, definition.pathSchema, this.#schemas, \"request\") || !matches(args.query ?? {}, definition.querySchema, this.#schemas, \"request\") || (definition.bodySchema && !matches(args.body, definition.bodySchema, this.#schemas, \"request\"))) throw new ValidationError(operation);\n // Check file bytes before multipart construction or credential authentication.\n if (definition.multipart && isRecord(args.body) && args.body.fileData instanceof Blob && args.body.fileData.size > 10_000_000) throw new ValidationError(operation, [\"fileData\"]);\n const pathValues = new Map(Object.entries(args.path ?? {}));\n const path = definition.path.replace(/\\{([^}]+)\\}/g, (_, name: string) => {\n const value = String(pathValues.get(name));\n if (value === \".\" || value === \"..\") throw new WellSkyError(\"validation\", operation);\n return encodeURIComponent(value);\n });\n const url = new URL(this.#baseUrl + path);\n for (const [name, value] of Object.entries(args.query ?? {})) {\n if (value !== undefined && value !== null) {\n const encoded = this.#mobileDateCorrection !== undefined && name === \"dateEffective\" && operation === \"POST /assessmentsmobile/AddAssessmentAnswer/{clientId}/{assessmentCode}\"\n ? correctMobileEffectiveDate(value, this.#mobileDateCorrection, operation) : String(value);\n url.searchParams.set(name, encoded);\n }\n }\n let body: string | FormData | undefined;\n if (definition.multipart && isRecord(args.body)) {\n body = new FormData();\n for (const [name, value] of Object.entries(args.body)) {\n if (value !== undefined && value !== null) body.append(name, value instanceof Blob ? value : String(value));\n }\n } else if (args.body !== undefined) body = JSON.stringify(args.body);\n let token = definition.authenticated ? await withSignal(this.#token(), signal, operation) : undefined;\n let refreshed = false;\n let attempts = 0;\n while (true) {\n try {\n const headers = this.#headers(token);\n if (typeof body === \"string\") headers.set(\"Content-Type\", \"application/json\");\n const response = await this.#send(url, { method: definition.method, headers, ...(body === undefined ? {} : { body }), signal, redirect: \"error\", cache: \"no-store\" }, operation, correlationId, attempts);\n // Reads can refresh once. Writes are never automatically sent twice, even after a 401.\n if (response.status === 401 && definition.method === \"GET\" && definition.authenticated && !refreshed && (this.#auth.kind === \"credentials\" || this.#auth.kind === \"provider\")) {\n await response.body?.cancel();\n refreshed = true;\n token = await withSignal(this.#token(token), signal, operation);\n continue;\n }\n const result = await this.#read(response, operation, definition.responseSchema === undefined);\n return decodeResponse<T>(result, definition.responseSchema, this.#schemas, operation);\n } catch (error) {\n if (signal.aborted) throw abortError(signal, operation);\n const failure = error instanceof WellSkyError ? error : new WellSkyError(\"network\", operation);\n const retryable = failure.kind === \"network\" || ((failure.kind === \"http\" || failure.kind === \"throttled\") && retryStatuses.has(failure.status ?? 0));\n if (definition.method !== \"GET\" || failure.operation !== operation || !retryable || attempts >= this.#retries) throw failure;\n const wait = failure.retryAfterMs ?? Math.min(this.#retryMax, this.#retryBase * 2 ** attempts * (1 + Math.random() * 0.2));\n // Never retry earlier than Retry-After. Return the error if the delay exceeds our bound.\n if (wait > this.#retryMax) throw failure;\n attempts++;\n await delay(wait, signal, operation);\n }\n }\n } catch (error) {\n if (signal.aborted) { const error = abortError(signal, operation); error.correlationId = correlationId; throw error; }\n if (error instanceof WellSkyError) error.correlationId = correlationId;\n if (error instanceof WellSkyError || error instanceof TypeError) throw error;\n throw new WellSkyError(\"network\", operation);\n } finally { clearTimeout(timer); }\n }\n\n async *paginate<T>(definition: OperationDefinition, args: Arguments & PaginationOptions): AsyncGenerator<T> {\n const operation = `${definition.method} ${definition.path}`;\n const query = Object.fromEntries(Object.entries(args.query ?? {}));\n const start = positiveInteger(typeof query.startPage === \"number\" ? query.startPage : 1, \"startPage\");\n positiveInteger(typeof query.perPage === \"number\" ? query.perPage : 30, \"perPage\");\n const maxPages = positiveInteger(args.maxPages ?? 10_000, \"maxPages\");\n for (let page = 0; page < maxPages; page++) {\n const response = await this.execute<ApiResponse<T>>(definition, { ...args, query: { perPage: 30, ...query, startPage: start + page } });\n const items = toItems(response);\n if (!items.length) return;\n yield* items;\n // Continue through short pages: some tenants cap perPage below the requested size.\n }\n throw new WellSkyError(\"pagination\", operation);\n }\n}\n"]}
package/docs/README.md CHANGED
@@ -28,6 +28,7 @@ Then read [REST configuration](rest-client.md) for authentication and tenant con
28
28
  | Record services, SSVF details, or Funding Sources | [Services](services.md), [SSVF rules](../SSVF.md) | [Service contract](../browser/service-recording.d.mts) |
29
29
  | Record a need without a service | [Independent needs](independent-needs.md) | [Need discovery and recording](../examples/independent-needs.mts) |
30
30
  | Record outreach or shelter contacts | [Current Living Situation](current-living-situation.md) | Program-entry starts, contact dates, and distinct event identities |
31
+ | Record coordinated entry referrals and events | [Coordinated Entry Events](coordinated-entry-events.md) | [Event recording](../examples/coordinated-entry-events.mts) |
31
32
  | Understand shelter stays and enrollment coverage | [Shelters](shelters.md) | Household check-in/checkout, enrollment guards, and retry protection |
32
33
  | Report shelter inventory and vacancies | [Shelter inventory](shelter-inventory.md) | Unit lists, named beds, occupants, holds, overflow, and bounded complete snapshots |
33
34
  | Upload attachments or write goal case notes | [Files and notes](files-and-notes.md) | [Browser contracts](../browser/index.d.mts) |
@@ -31,6 +31,22 @@ WellSky requires a client context and known assessment code for these reads. The
31
31
 
32
32
  Use the raw `assessments.get`, `assessmentsMobile.getAnswers`, and `enrollments.getAssessment` methods for recorded answers. Use `encodeAnswers` and `encodeNewSubassessmentRow` for endpoint-specific encoding. Mobile lookups use option IDs; standalone/enrollment lookups require an explicit `writeLabel` resolver with tenant-verified labels. Raw option names are not assumed to be valid write labels. Provider answers are refused for mobile writes because that endpoint can silently discard them. Answer-state code mappings and multi-value serialization are caller-supplied; a refusal is never converted to `No`.
33
33
 
34
+ ## Yes/no answer acceptance
35
+
36
+ `encodeAnswers` encodes a `yes_no` value of `true` or `"Yes"` as `"Yes"`, and `false` or `"No"` as `"No"`. Which endpoint persists that value matters more than the encoding.
37
+
38
+ Reproduced on November 2, 2026 in a sandbox tenant with synthetic clients:
39
+
40
+ - **Mobile `AddAssessmentAnswer` does not store yes/no values.** Requests with `"Yes"`, `"1"`/`"0"`, and `"true"`/`"false"` returned success and created a row at the intended effective date, but its value read back empty through both the generic and mobile reads. An integrator's 30-answer entry batch showed the same result.
41
+ - **Mobile writes are insert-only per question and effective date.** A second mobile write to any question that already has a row at that date returned HTTP 400 `An error occurred while saving the entity changes`. This affected yes/no and integer questions alike, so a mobile retry cannot repair an empty yes/no row.
42
+ - **Standard `assessments.create` stores `"Yes"`/`"No"`.** It rejects `"true"`/`"false"`. It updates existing rows at the same effective date, including empty yes/no rows created by mobile writes, and changed only the answers it was sent in a full before/after comparison.
43
+ - **Every standard write must include every mandatory answer**, even one already recorded at that date; otherwise it returns `All mandatory answers are not provided`. A conditionally mandatory lookup that does not apply can be sent as `""`; it is stored empty at that date.
44
+ - **Generic reads omit yes/no answers at exactly their effective instant.** `assessments.get` with `dateEffective` equal to the saved instant returns `null` for those yes/no answers while other types read normally. One second later returns the saved value. The standard create response has the same omission. Mobile reads return the value, but they have no date filter and show only the latest row, so a later record hides the date being checked.
45
+ - **Mobile row writes drop yes/no and provider answers too.** In new Coordinated Entry Event rows, a yes/no result and a provider location were missing after a successful mobile write, while the standard endpoint saved both. `encodeNewSubassessmentRow` refuses answered provider children for mobile and omits unanswered ones. See [Coordinated Entry Events](coordinated-entry-events.md).
46
+ - **The mobile date correction does not apply to standard writes.** A standard create sent the uncorrected instant and stored it unchanged.
47
+
48
+ The enrollment workflow writes yes/no answers through the mobile batch by default. That keeps their stage pending because the saved values never verify. Construct it with `yesNoWrites: 'standard'` and a `writeLabel` resolver to send them through `assessments.create` instead; see [the enrollment workflow](enrollments.md#yesno-answers). It never treats an empty yes/no answer as `No`, skips a requested field, or switches endpoints for a stage that was already attempted. For a minimal reproduction, [enable private error diagnostics](troubleshooting.md#inspect-an-upstream-error-privately) and retain the question's current metadata.
49
+
34
50
  ## Race and ethnicity combinations
35
51
 
36
52
  `encodeAnswers` recognizes the standard `HUD_RACEETHNICITY` field. It resolves single-category and multiple-category answers to the tenant's `RACE_ETH_COMBO_*` option IDs. A single White answer uses `RACE_ETH_COMBO_WHI`, even when the caller supplies `RACE_ETH_WHI`. Atomic option IDs can read back with a label while appearing blank in the UI.
@@ -47,13 +63,13 @@ Category order is normalized and duplicates are removed. Missing combinations an
47
63
 
48
64
  ## Mobile effective-date correction
49
65
 
50
- Live testing found that `POST /assessmentsmobile/AddAssessmentAnswer` recorded effective dates seven hours earlier than the requested instant, with `Z`, explicit offsets, and no suffix. Winter and summer test dates both shifted seven hours in that session. Standalone assessment writes preserved the requested instant. This does not establish the upstream timezone or guarantee that its offset stays constant.
66
+ Live testing found that `POST /assessmentsmobile/AddAssessmentAnswer` recorded effective dates seven hours earlier than the requested instant, with `Z`, explicit offsets, and no suffix. Winter and summer test dates both shifted seven hours in that session. Standalone assessment writes preserved the requested instant. The project maintainers report that WellSky servers run on Mountain Standard Time (UTC−7, no daylight saving), which matches the constant seven-hour shift and the UTC−7 DOB conversion. WellSky has not documented this as an API contract, so the SDK still does not infer the correction.
51
67
 
52
68
  For a deployment with a measured mobile shift, configure `mobileAssessmentDateCorrectionMinutes` on `WellSkyClient`. For example, **420 adds seven hours to the outgoing mobile query**, compensating for a verified upstream subtraction of seven hours. The default is unset and preserves raw behavior; the SDK never infers a correction from the host timezone or tenant name.
53
69
 
54
70
  With correction enabled, supply an ISO timestamp with `Z` or an explicit numeric offset. Invalid calendar dates, ambiguous timestamps, and correction values outside integer minutes from -840 to 840 are rejected before authentication/network activity. Only the mobile write's `dateEffective` query is corrected. Read queries, standalone/enrollment writes, and date values inside answer bodies are unchanged. Do not pre-adjust dates as well as configuring the client.
55
71
 
56
- Verify `date_effective` through a generic assessment read and check UI history after writes. Revalidate the correction when upstream behavior changes, including seasonal clock changes; it is a measured compatibility setting, not automatic timezone handling. Mobile reads can omit UI-visible combination answers, so an empty mobile answer alone does not prove absence. Standard standalone writes are preferable for scalar answers when that endpoint fits the application; mobile remains necessary for verified in-place recordset updates.
72
+ Verify `date_effective` through a generic assessment read and check UI history after writes. Revalidate the correction when upstream behavior changes, including seasonal clock changes; it is a measured compatibility setting, not automatic timezone handling. Mobile reads can omit UI-visible combination answers, so an empty mobile answer alone does not prove absence. Standard standalone writes are preferable for scalar answers when that endpoint fits the application; mobile remains necessary for verified in-place recordset updates. Mobile scalar writes only insert a row for a question and date; see [yes/no answer acceptance](#yesno-answer-acceptance).
57
73
 
58
74
  ## Read verification records at enrollment
59
75
 
@@ -94,7 +110,9 @@ const result = await client.subassessments.setEndDate({
94
110
  });
95
111
  ```
96
112
 
97
- This is generic recordset handling. It reads the current row, targets its existing `recordset_id` with `isDeleted: false`, preserves the other returned values, and verifies the end date, preserved values, and recordset list. It never deletes/recreates the row or retries the write. The result is a `WriteResult`, including `unverified` if the server silently ignores the update. Rows containing provider questions are refused because mobile writes cannot preserve those values reliably.
113
+ This is generic recordset handling. It reads the current row and sends only the end-date cell to its existing `recordset_id` with `isDeleted: false`. When the row has never had an end date, the cell's question comes from the parent's question list. It then verifies the end date, every other row and cell of the subassessment, and the recordset list. It never deletes/recreates the row or retries the write. The result is a `WriteResult`, including `unverified` if the server silently ignores the update or changes another value.
114
+
115
+ On November 2, 2026, sandbox mobile updates that sent only the end-date cell kept the row's other answers, including provider-valued locations and yes/no answers that mobile cannot write itself, so rows with provider questions, such as Coordinated Entry Events, can be end-dated. Earlier versions resent every cell and refused those rows.
98
116
 
99
117
  An October 22, 2026 sandbox probe confirmed that an existing recordset could be end-dated in place and retained the same ID. Application policy decides when historical records should end or be replaced; the SDK verifies the requested operation.
100
118
 
@@ -13,6 +13,8 @@ The generated client covers the pinned V2/V3 Swagger operations. The following f
13
13
  | Programs | `readProgramCatalog` | Counted active/operational providers; includes organizations, not just enrollable programs; no permission/eligibility guarantee |
14
14
  | Program assessment defaults | `createProgramDiscovery` | Read-only admin UI/GWT discovery of entry/interim/exit defaults; requires administrative access |
15
15
  | Enrollment and assessment answers | `createEnrollmentWorkflow` | Discovers defaults, saves per-client answers/rows, verifies and reconciles; existing clients required |
16
+ | Yes/no answer writes | `assessments.create`, `createEnrollmentWorkflow` with `yesNoWrites: 'standard'` | Standard writes store Yes/No with every mandatory answer; mobile writes store them empty (reproduced November 2, 2026). Generic reads need a query one second after the effective instant. See [yes/no acceptance](assessments.md#yesno-answer-acceptance). |
17
+ | Coordinated Entry Events | `createCoordinatedEntryEventRecorder` | One journaled row per event through the standard endpoint, keeping provider locations and yes/no results that mobile writes drop; live sandbox acceptance November 2, 2026. Requires an instrument without mandatory questions. |
16
18
  | Client creation | `createClientCreator` | Durable source mapping; candidate detection without merging; lost receipt requires explicit verified ID |
17
19
  | Household creation and membership | `createHouseholds` | Stable keys, preserved history, later members, non-head departures and relationship changes; no head replacement or household closure |
18
20
  | Household enrollment | `createHouseholdEnrollment` | Existing household and at least two initial clients including head; per-member plans and IDs |
@@ -21,6 +21,7 @@ The root export selects V3. `/v2` and `/v3` fix their own `x-version` headers. O
21
21
  | `metadataCacheTtlMs` | `60000` | Definition cache lifetime |
22
22
  | `metadataCacheMaxEntries` | `100` | Per-client metadata cache bound |
23
23
  | `mobileAssessmentDateCorrectionMinutes` | Unset | Measured integer offset from -840 to 840, applied only to AddAssessmentAnswer's effective-date query |
24
+ | `captureErrorBody` | `false` | Opt-in `UpstreamError.responseBody`, capped at 16,384 characters and excluded from JSON serialization and telemetry; authentication and throttle bodies remain discarded. See [private diagnostics](troubleshooting.md#inspect-an-upstream-error-privately). |
24
25
  | `hooks`, `logger` | Unset | Allowlisted events without bodies, credentials, filters, or tokens |
25
26
 
26
27
  Matching tenant/base URL/transport clients share scheduling state and must use consistent scheduler settings. Coordination is within one process. Tenant consistency checks are described in [REST configuration](rest-client.md#configure-a-client).
@@ -0,0 +1,88 @@
1
+ # Record Coordinated Entry Events
2
+
3
+ [Documentation index](README.md) · [Assessment guide](assessments.md) · [Public contract](../browser/coordinated-entry-event.d.mts) · [Example](../examples/coordinated-entry-events.mts)
4
+
5
+ A Coordinated Entry Event records an access event, such as a referral to a crisis needs assessment, or a referral with its result, such as an emergency shelter or rapid rehousing referral. Each event is its own subassessment row. Recording another event does not close or replace an earlier one.
6
+
7
+ `createCoordinatedEntryEventRecorder` writes one row per event key through the standard assessment endpoint. The mobile answer endpoint is not used because it drops two kinds of answers in these rows without returning an error; see [the evidence](#why-the-standard-endpoint).
8
+
9
+ ## Fields
10
+
11
+ Read `api.assessments.getDefinition({clientId, assessmentCode, refresh: true})` and supply the exact virtual fields. Readback queries one second after the later of now and the event date, because a read at exactly the event instant omits yes/no answers. A November 2, 2026 sandbox instrument exposed:
12
+
13
+ | Role | Virtual field | Type |
14
+ | --- | --- | --- |
15
+ | Parent | `SVP_COORDINATEDENTRYEVENT_SUBA` | sub_assessment |
16
+ | Start | `SVP_COORDINATEDENTRYEVENT_SUBASTART` | date |
17
+ | End | `SVP_COORDINATEDENTRYEVENT_SUBAEND` | date |
18
+ | Date of event | `SVP_COORDINATEDENTRYEVENT_DATE_EVENT` | date |
19
+ | Event | `SVP_COORDINATEDENTRYEVENT_EVENT` | lookup |
20
+ | Diversion result: client housed safely | `SVP_COORDINATEDENTRYEVENT_CLIENTHOUSEDSAFE` | yes_no |
21
+ | Follow-up result: enrolled in aftercare | `SVP_COORDINATEDENTRYEVENT_ENROLLEDAFTERCARE` | yes_no |
22
+ | Location of crisis or permanent housing referral | `SVP_COORDINATEDENTRYEVENT_LOCATIONCRISISPHPROJID` | provider |
23
+ | Referral result | `SVP_COORDINATEDENTRYEVENT_REFERRALRESULT` | lookup |
24
+ | Date of result | `SVP_COORDINATEDENTRY_DATE_RESULT` | date |
25
+
26
+ Map every role in `fields`. The recorder writes the start, event date and event, and takes the follow-up answers as named inputs. It checks them against the selected Event before any write:
27
+
28
+ | Event option code (`COORDINATEDENTRYEVENT_EVENT_…`) | `housedSafely` | `enrolledInAftercare` | `location` | `referralResult` + `resultDate` |
29
+ | --- | --- | --- | --- | --- |
30
+ | `PROBSOLV` | Optional | — | — | — |
31
+ | `POSTPLACEFOLLOWUP` | — | Optional | — | — |
32
+ | `EMERGSHELTER`, `TRANSITHOUSING`, `JOINTTHRRH`, `RRH`, `PSH`, `OTHERPH` | — | — | **Required** | Optional, both or neither |
33
+ | `PREVASSIST`, `CRISISNEEDS`, `HOUSINGNEEDS`, `STREETOUTREACH`, `HOUSINGNAVIGATION`, `NONCONT_INELIG`, `NONCONT_NOAVAIL` | — | — | — | — |
34
+
35
+ A dash means the answer is refused for that event. The mapping follows the form's own dependency labels for these fields. Requiring a location for placement referrals is the SDK's choice; HUD's data standards list it as a dependent field to collect. HUD also defines referral events for emergency assistance or flex funds, Emergency Housing Vouchers and Housing Stability Vouchers, which take a result but no location. The tested tenant's Event picklist had no options for them, so they are not in the table; their codes are refused as `unsupported-event` until verified and added. The result answers are optional because a referral's result is usually known only after the referral, and the result date cannot precede the event. Header options and any other Event code are refused as `unsupported-event`, so a tenant with different codes fails before writing rather than being guessed. Supply `location` as a provider ID; the recorder checks that it is a positive ID and that it reads back, not that the provider exists in the tenant. Use `additionalAnswers` only for other questions in the row; it cannot set the mapped fields. Malformed answers and lookups without a `writeLabel` result are rejected with the encoder's `ValidationError` before any write.
36
+
37
+ ## Record and retry
38
+
39
+ ```ts
40
+ const recorder = createCoordinatedEntryEventRecorder({
41
+ api, store, fields,
42
+ writeLabel: (question, option) => verifiedLabels.get(`${question.fieldName}:${option.code}`),
43
+ });
44
+ await recorder.record({
45
+ key: `${sourceEventId}`, clientId, enrollmentId, assessmentCode,
46
+ eventDate: '2026-11-02T12:20:00Z',
47
+ event: {option: {code: 'COORDINATEDENTRYEVENT_EVENT_EMERGSHELTER'}},
48
+ location: shelterProviderId,
49
+ referralResult: {option: {code: 'COORDINATEDENTRYEVENT_REFERRALRESULT_SUCCESS'}},
50
+ resultDate: '2026-11-02T12:30:00Z',
51
+ });
52
+ ```
53
+
54
+ - The standard endpoint takes lookup **labels**, so `writeLabel` must return tenant-verified labels for the Event, the referral result and any other lookup answered. Readback compares the option IDs.
55
+ - The row start is the selected enrollment's entry date. The end is left empty. Events before entry or after a recorded exit are refused.
56
+ - The standard endpoint rejects a request that omits any mandatory answer of the instrument. The recorder sends only the event row, so it refuses an instrument with mandatory questions instead of resending other answers, which would create new dated rows for them. Use an instrument that contains the CE Event subassessment and has no mandatory questions; in the tested program that was the Standard interim instrument. Rows belong to the client, so they appear in the entry and interim assessments alike.
57
+ - The journal, snapshot and reconciliation rules match the [Current Living Situation recorder](current-living-situation.md#record-and-retry): each key gets one row, earlier rows must be unchanged, exactly one new matching row must appear, and an uncertain save blocks later event keys for that client until it reconciles. Same-key retries verify the original recordset ID and never submit again.
58
+
59
+ Use timezone-qualified whole-second instants for event and result dates.
60
+
61
+ ## Add a referral result later
62
+
63
+ ```ts
64
+ await recorder.recordResult({
65
+ key: `${sourceEventId}`, clientId, assessmentCode,
66
+ referralResult: {option: {code: 'COORDINATEDENTRYEVENT_REFERRALRESULT_SUCCESS'}},
67
+ resultDate: '2026-11-05T15:00:00Z',
68
+ });
69
+ ```
70
+
71
+ `recordResult` adds a result to a placement referral that `record` already verified under the same key and store. The standard endpoint can only create rows, so it sends just the result and result date to the event's `recordset_id` through the mobile endpoint, which changes those cells and keeps the rest of the row, including the location. Before sending, it journals a snapshot of every row. Afterwards it requires the result to read back, every earlier answer in the row to be unchanged, every other row to be unchanged and no row to be added. A lost acknowledgement reconciles; an unknown outcome leaves the update pending, blocks other event keys for the client, and is never resent. A row that already has the same result returns `already-present`; a different result already in the row is a `result-conflict`. Once a result has been attempted or recorded under a key, a different result for that key is refused as `result-intent-changed`. The result date cannot precede the event date; it may follow the client's exit, because a referral's outcome can arrive after the client leaves the program. Mobile writes use the client's configured date correction for their effective date; the result date inside the row is not shifted.
72
+
73
+ Yes/no results cannot be added later: the mobile endpoint drops yes/no answers in row updates as it does in new rows. Record a Problem Solving/Diversion or post-placement follow-up event once its result is known, with `housedSafely` or `enrolledInAftercare`, or record it without one. The standard endpoint stores the requested instant; the mobile date correction does not apply.
74
+
75
+ ## Why the standard endpoint
76
+
77
+ On November 2, 2026, synthetic CE Event rows were written in a sandbox tenant through both endpoints:
78
+
79
+ | Row | Mobile `AddAssessmentAnswer` | Standard `assessments.create` |
80
+ | --- | --- | --- |
81
+ | Dates and event lookup | Saved | Saved |
82
+ | Yes/no result | Dropped, success response | Saved |
83
+ | Provider location | Dropped, success response | Saved |
84
+ | Referral result and date | Saved | Saved |
85
+
86
+ The standard request uses the row shape `{subAssessments: [...]}` without `recordset_id`/`isDeleted`. Other subassessment rows were unchanged afterwards. The recorder, before its event-type checks were added, then created an access event, a diversion with its yes/no result, and an emergency shelter referral with location and result through the interim instrument; all three verified and same-key retries made no writes. The UI's assessment table showed the referral's location and result. A mobile update of an existing row's `recordset_id` with only the result and result date added both and kept the location, with or without the location cell in the request; the same update with a yes/no result returned success and stored nothing. The yes/no result is not a table column, so it was confirmed through REST reads only.
87
+
88
+ Apart from adding a referral result, the recorder does not edit or delete events. End-date an event row with [`client.subassessments.setEndDate`](assessments.md#end-date-an-existing-subassessment) and the recorded `recordsetId`; it sends only the end-date cell, keeps the location and yes/no results, and verifies the whole subassessment. A later end date does not stop `record` from returning `already-present` for the event's key.