@choiceapps/communityservices-sdk 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (294) hide show
  1. package/AGENTS.md +43 -0
  2. package/API.md +86 -0
  3. package/CHANGELOG.md +12 -0
  4. package/LICENSE +201 -0
  5. package/NOTICE +11 -0
  6. package/README.md +100 -0
  7. package/SSVF.md +131 -0
  8. package/browser/attachment-conflict.mjs +6 -0
  9. package/browser/case-plans-ui.mjs +23 -0
  10. package/browser/case-plans.d.mts +20 -0
  11. package/browser/case-plans.mjs +89 -0
  12. package/browser/client-creation.d.mts +16 -0
  13. package/browser/client-creation.mjs +60 -0
  14. package/browser/client-profile-ui.mjs +59 -0
  15. package/browser/client-profile.d.mts +24 -0
  16. package/browser/client-profile.mjs +94 -0
  17. package/browser/client-workflows.mjs +135 -0
  18. package/browser/connection.d.mts +4 -0
  19. package/browser/connection.mjs +41 -0
  20. package/browser/current-living-situation.d.mts +44 -0
  21. package/browser/current-living-situation.mjs +161 -0
  22. package/browser/date-of-birth-ui.mjs +68 -0
  23. package/browser/date-of-birth.d.mts +28 -0
  24. package/browser/date-of-birth.mjs +112 -0
  25. package/browser/enrollment-workflow.d.mts +174 -0
  26. package/browser/enrollment-workflow.mjs +518 -0
  27. package/browser/exit-details.mjs +21 -0
  28. package/browser/file-store.mjs +32 -0
  29. package/browser/gwt-mapped.mjs +46 -0
  30. package/browser/household-exit.d.mts +34 -0
  31. package/browser/household-exit.mjs +102 -0
  32. package/browser/households-ui.mjs +20 -0
  33. package/browser/households.d.mts +22 -0
  34. package/browser/households.mjs +115 -0
  35. package/browser/index.d.mts +78 -0
  36. package/browser/index.mjs +46 -0
  37. package/browser/member-entry-date.d.mts +30 -0
  38. package/browser/member-entry-date.mjs +71 -0
  39. package/browser/need-recording.d.mts +37 -0
  40. package/browser/need-recording.mjs +68 -0
  41. package/browser/need-ui.mjs +138 -0
  42. package/browser/page-lock.mjs +11 -0
  43. package/browser/password-recovery.mjs +49 -0
  44. package/browser/playwright-session.mjs +196 -0
  45. package/browser/program-discovery.d.mts +22 -0
  46. package/browser/program-discovery.mjs +80 -0
  47. package/browser/recovery-diagnostics.mjs +9 -0
  48. package/browser/service-recording.d.mts +45 -0
  49. package/browser/service-recording.mjs +148 -0
  50. package/browser/service-ui.mjs +160 -0
  51. package/browser/session-authentication.mjs +40 -0
  52. package/browser/shelter-inventory.d.mts +103 -0
  53. package/browser/shelter-inventory.mjs +273 -0
  54. package/browser/shelter-ui.mjs +382 -0
  55. package/browser/shelters.d.mts +139 -0
  56. package/browser/shelters.mjs +425 -0
  57. package/browser/ssvf-rules.d.mts +21 -0
  58. package/browser/ssvf-rules.mjs +145 -0
  59. package/browser/ui-login.mjs +135 -0
  60. package/dist/cjs/bulk.d.ts +33 -0
  61. package/dist/cjs/bulk.d.ts.map +1 -0
  62. package/dist/cjs/bulk.js +42 -0
  63. package/dist/cjs/bulk.js.map +1 -0
  64. package/dist/cjs/control.d.ts +35 -0
  65. package/dist/cjs/control.d.ts.map +1 -0
  66. package/dist/cjs/control.js +141 -0
  67. package/dist/cjs/control.js.map +1 -0
  68. package/dist/cjs/effective-date.d.ts +3 -0
  69. package/dist/cjs/effective-date.d.ts.map +1 -0
  70. package/dist/cjs/effective-date.js +27 -0
  71. package/dist/cjs/effective-date.js.map +1 -0
  72. package/dist/cjs/encoding.d.ts +32 -0
  73. package/dist/cjs/encoding.d.ts.map +1 -0
  74. package/dist/cjs/encoding.js +121 -0
  75. package/dist/cjs/encoding.js.map +1 -0
  76. package/dist/cjs/enrollment-verifications.d.ts +39 -0
  77. package/dist/cjs/enrollment-verifications.d.ts.map +1 -0
  78. package/dist/cjs/enrollment-verifications.js +96 -0
  79. package/dist/cjs/enrollment-verifications.js.map +1 -0
  80. package/dist/cjs/errors.d.ts +33 -0
  81. package/dist/cjs/errors.d.ts.map +1 -0
  82. package/dist/cjs/errors.js +45 -0
  83. package/dist/cjs/errors.js.map +1 -0
  84. package/dist/cjs/generated/v2-models.d.ts +1482 -0
  85. package/dist/cjs/generated/v2-models.d.ts.map +1 -0
  86. package/dist/cjs/generated/v2-models.js +3 -0
  87. package/dist/cjs/generated/v2-models.js.map +1 -0
  88. package/dist/cjs/generated/v2.d.ts +1149 -0
  89. package/dist/cjs/generated/v2.d.ts.map +1 -0
  90. package/dist/cjs/generated/v2.js +252 -0
  91. package/dist/cjs/generated/v2.js.map +1 -0
  92. package/dist/cjs/generated/v3-models.d.ts +1420 -0
  93. package/dist/cjs/generated/v3-models.d.ts.map +1 -0
  94. package/dist/cjs/generated/v3-models.js +3 -0
  95. package/dist/cjs/generated/v3-models.js.map +1 -0
  96. package/dist/cjs/generated/v3.d.ts +1149 -0
  97. package/dist/cjs/generated/v3.d.ts.map +1 -0
  98. package/dist/cjs/generated/v3.js +252 -0
  99. package/dist/cjs/generated/v3.js.map +1 -0
  100. package/dist/cjs/gwt-enrollments.d.ts +131 -0
  101. package/dist/cjs/gwt-enrollments.d.ts.map +1 -0
  102. package/dist/cjs/gwt-enrollments.js +280 -0
  103. package/dist/cjs/gwt-enrollments.js.map +1 -0
  104. package/dist/cjs/index.d.ts +3 -0
  105. package/dist/cjs/index.d.ts.map +1 -0
  106. package/dist/cjs/index.js +19 -0
  107. package/dist/cjs/index.js.map +1 -0
  108. package/dist/cjs/metadata.d.ts +100 -0
  109. package/dist/cjs/metadata.d.ts.map +1 -0
  110. package/dist/cjs/metadata.js +165 -0
  111. package/dist/cjs/metadata.js.map +1 -0
  112. package/dist/cjs/package.json +1 -0
  113. package/dist/cjs/program-discovery.d.ts +28 -0
  114. package/dist/cjs/program-discovery.d.ts.map +1 -0
  115. package/dist/cjs/program-discovery.js +58 -0
  116. package/dist/cjs/program-discovery.js.map +1 -0
  117. package/dist/cjs/race.d.ts +4 -0
  118. package/dist/cjs/race.d.ts.map +1 -0
  119. package/dist/cjs/race.js +40 -0
  120. package/dist/cjs/race.js.map +1 -0
  121. package/dist/cjs/runtime.d.ts +108 -0
  122. package/dist/cjs/runtime.d.ts.map +1 -0
  123. package/dist/cjs/runtime.js +38 -0
  124. package/dist/cjs/runtime.js.map +1 -0
  125. package/dist/cjs/subassessments.d.ts +29 -0
  126. package/dist/cjs/subassessments.d.ts.map +1 -0
  127. package/dist/cjs/subassessments.js +107 -0
  128. package/dist/cjs/subassessments.js.map +1 -0
  129. package/dist/cjs/testing.d.ts +45 -0
  130. package/dist/cjs/testing.d.ts.map +1 -0
  131. package/dist/cjs/testing.js +66 -0
  132. package/dist/cjs/testing.js.map +1 -0
  133. package/dist/cjs/transport.d.ts +19 -0
  134. package/dist/cjs/transport.d.ts.map +1 -0
  135. package/dist/cjs/transport.js +373 -0
  136. package/dist/cjs/transport.js.map +1 -0
  137. package/dist/cjs/v2.d.ts +13 -0
  138. package/dist/cjs/v2.d.ts.map +1 -0
  139. package/dist/cjs/v2.js +29 -0
  140. package/dist/cjs/v2.js.map +1 -0
  141. package/dist/cjs/v3.d.ts +13 -0
  142. package/dist/cjs/v3.d.ts.map +1 -0
  143. package/dist/cjs/v3.js +29 -0
  144. package/dist/cjs/v3.js.map +1 -0
  145. package/dist/cjs/validation.d.ts +33 -0
  146. package/dist/cjs/validation.d.ts.map +1 -0
  147. package/dist/cjs/validation.js +77 -0
  148. package/dist/cjs/validation.js.map +1 -0
  149. package/dist/cjs/verification.d.ts +82 -0
  150. package/dist/cjs/verification.d.ts.map +1 -0
  151. package/dist/cjs/verification.js +122 -0
  152. package/dist/cjs/verification.js.map +1 -0
  153. package/dist/esm/bulk.d.ts +33 -0
  154. package/dist/esm/bulk.d.ts.map +1 -0
  155. package/dist/esm/bulk.js +39 -0
  156. package/dist/esm/bulk.js.map +1 -0
  157. package/dist/esm/control.d.ts +35 -0
  158. package/dist/esm/control.d.ts.map +1 -0
  159. package/dist/esm/control.js +132 -0
  160. package/dist/esm/control.js.map +1 -0
  161. package/dist/esm/effective-date.d.ts +3 -0
  162. package/dist/esm/effective-date.d.ts.map +1 -0
  163. package/dist/esm/effective-date.js +24 -0
  164. package/dist/esm/effective-date.js.map +1 -0
  165. package/dist/esm/encoding.d.ts +32 -0
  166. package/dist/esm/encoding.d.ts.map +1 -0
  167. package/dist/esm/encoding.js +117 -0
  168. package/dist/esm/encoding.js.map +1 -0
  169. package/dist/esm/enrollment-verifications.d.ts +39 -0
  170. package/dist/esm/enrollment-verifications.d.ts.map +1 -0
  171. package/dist/esm/enrollment-verifications.js +93 -0
  172. package/dist/esm/enrollment-verifications.js.map +1 -0
  173. package/dist/esm/errors.d.ts +33 -0
  174. package/dist/esm/errors.d.ts.map +1 -0
  175. package/dist/esm/errors.js +33 -0
  176. package/dist/esm/errors.js.map +1 -0
  177. package/dist/esm/generated/v2-models.d.ts +1482 -0
  178. package/dist/esm/generated/v2-models.d.ts.map +1 -0
  179. package/dist/esm/generated/v2-models.js +2 -0
  180. package/dist/esm/generated/v2-models.js.map +1 -0
  181. package/dist/esm/generated/v2.d.ts +1149 -0
  182. package/dist/esm/generated/v2.d.ts.map +1 -0
  183. package/dist/esm/generated/v2.js +247 -0
  184. package/dist/esm/generated/v2.js.map +1 -0
  185. package/dist/esm/generated/v3-models.d.ts +1420 -0
  186. package/dist/esm/generated/v3-models.d.ts.map +1 -0
  187. package/dist/esm/generated/v3-models.js +2 -0
  188. package/dist/esm/generated/v3-models.js.map +1 -0
  189. package/dist/esm/generated/v3.d.ts +1149 -0
  190. package/dist/esm/generated/v3.d.ts.map +1 -0
  191. package/dist/esm/generated/v3.js +247 -0
  192. package/dist/esm/generated/v3.js.map +1 -0
  193. package/dist/esm/gwt-enrollments.d.ts +131 -0
  194. package/dist/esm/gwt-enrollments.d.ts.map +1 -0
  195. package/dist/esm/gwt-enrollments.js +274 -0
  196. package/dist/esm/gwt-enrollments.js.map +1 -0
  197. package/dist/esm/index.d.ts +3 -0
  198. package/dist/esm/index.d.ts.map +1 -0
  199. package/dist/esm/index.js +3 -0
  200. package/dist/esm/index.js.map +1 -0
  201. package/dist/esm/metadata.d.ts +100 -0
  202. package/dist/esm/metadata.d.ts.map +1 -0
  203. package/dist/esm/metadata.js +157 -0
  204. package/dist/esm/metadata.js.map +1 -0
  205. package/dist/esm/program-discovery.d.ts +28 -0
  206. package/dist/esm/program-discovery.d.ts.map +1 -0
  207. package/dist/esm/program-discovery.js +55 -0
  208. package/dist/esm/program-discovery.js.map +1 -0
  209. package/dist/esm/race.d.ts +4 -0
  210. package/dist/esm/race.d.ts.map +1 -0
  211. package/dist/esm/race.js +37 -0
  212. package/dist/esm/race.js.map +1 -0
  213. package/dist/esm/runtime.d.ts +108 -0
  214. package/dist/esm/runtime.d.ts.map +1 -0
  215. package/dist/esm/runtime.js +33 -0
  216. package/dist/esm/runtime.js.map +1 -0
  217. package/dist/esm/subassessments.d.ts +29 -0
  218. package/dist/esm/subassessments.d.ts.map +1 -0
  219. package/dist/esm/subassessments.js +103 -0
  220. package/dist/esm/subassessments.js.map +1 -0
  221. package/dist/esm/testing.d.ts +45 -0
  222. package/dist/esm/testing.d.ts.map +1 -0
  223. package/dist/esm/testing.js +60 -0
  224. package/dist/esm/testing.js.map +1 -0
  225. package/dist/esm/transport.d.ts +19 -0
  226. package/dist/esm/transport.d.ts.map +1 -0
  227. package/dist/esm/transport.js +369 -0
  228. package/dist/esm/transport.js.map +1 -0
  229. package/dist/esm/v2.d.ts +13 -0
  230. package/dist/esm/v2.d.ts.map +1 -0
  231. package/dist/esm/v2.js +13 -0
  232. package/dist/esm/v2.js.map +1 -0
  233. package/dist/esm/v3.d.ts +13 -0
  234. package/dist/esm/v3.d.ts.map +1 -0
  235. package/dist/esm/v3.js +13 -0
  236. package/dist/esm/v3.js.map +1 -0
  237. package/dist/esm/validation.d.ts +33 -0
  238. package/dist/esm/validation.d.ts.map +1 -0
  239. package/dist/esm/validation.js +72 -0
  240. package/dist/esm/validation.js.map +1 -0
  241. package/dist/esm/verification.d.ts +82 -0
  242. package/dist/esm/verification.d.ts.map +1 -0
  243. package/dist/esm/verification.js +117 -0
  244. package/dist/esm/verification.js.map +1 -0
  245. package/docs/README.md +56 -0
  246. package/docs/assessments.md +103 -0
  247. package/docs/browser-session.md +129 -0
  248. package/docs/capabilities.md +75 -0
  249. package/docs/configuration.md +81 -0
  250. package/docs/current-living-situation.md +56 -0
  251. package/docs/dates-and-answers.md +40 -0
  252. package/docs/development.md +81 -0
  253. package/docs/durable-records.md +156 -0
  254. package/docs/enrollments.md +217 -0
  255. package/docs/files-and-notes.md +39 -0
  256. package/docs/getting-started.md +56 -0
  257. package/docs/independent-needs.md +77 -0
  258. package/docs/integration-methods.md +60 -0
  259. package/docs/profiles.md +68 -0
  260. package/docs/reference.md +64 -0
  261. package/docs/rest-client.md +97 -0
  262. package/docs/services.md +66 -0
  263. package/docs/shelter-inventory.md +64 -0
  264. package/docs/shelters.md +75 -0
  265. package/docs/troubleshooting.md +61 -0
  266. package/docs/using-the-sdk.md +203 -0
  267. package/docs/vendor-issues/README.md +46 -0
  268. package/docs/vendor-issues/api-coverage.md +27 -0
  269. package/docs/vendor-issues/attachment-authentication.md +40 -0
  270. package/docs/vendor-issues/date-semantics.md +51 -0
  271. package/docs/vendor-issues/empty-service-list-404.md +51 -0
  272. package/docs/vendor-issues/enrollment-complete-target-error.md +178 -0
  273. package/docs/vendor-issues/enrollment-effective-date-column.md +112 -0
  274. package/docs/vendor-issues/household-head-validation.md +26 -0
  275. package/docs/vendor-issues/write-contracts.md +51 -0
  276. package/examples/README.md +41 -0
  277. package/examples/current-living-situation.mts +27 -0
  278. package/examples/durable-records.mts +78 -0
  279. package/examples/enrollment-workflow.mts +46 -0
  280. package/examples/gwt-enrollment-session.ts +17 -0
  281. package/examples/gwt-file-store.mjs +2 -0
  282. package/examples/household-enrollment-workflow.mts +43 -0
  283. package/examples/household-exit-workflow.mts +35 -0
  284. package/examples/household-lifecycle-workflow.mts +34 -0
  285. package/examples/independent-needs.mts +30 -0
  286. package/examples/program-discovery.ts +19 -0
  287. package/examples/quickstart.mjs +13 -0
  288. package/examples/shelter-inventory.mts +30 -0
  289. package/examples/shelters.mts +33 -0
  290. package/examples/usage.ts +23 -0
  291. package/examples/verification-snapshot.ts +9 -0
  292. package/llms.txt +26 -0
  293. package/package.json +103 -0
  294. package/specs/provenance.json +17 -0
@@ -0,0 +1,165 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AssessmentMetadata = void 0;
4
+ exports.flattenQuestions = flattenQuestions;
5
+ exports.buildAssessmentDefinition = buildAssessmentDefinition;
6
+ exports.compareDefinition = compareDefinition;
7
+ exports.resolvePicklistOption = resolvePicklistOption;
8
+ const runtime_js_1 = require("./runtime.js");
9
+ const errors_js_1 = require("./errors.js");
10
+ const validation_js_1 = require("./validation.js");
11
+ function numberOrNull(value) { return typeof value === "number" && Number.isSafeInteger(value) ? value : null; }
12
+ function stringOrNull(value) { return typeof value === "string" ? value : null; }
13
+ function boolOrNull(value) { return typeof value === "boolean" ? value : null; }
14
+ function rows(value) {
15
+ const items = (0, validation_js_1.isRecord)(value) && Array.isArray(value.value) ? value.value : Array.isArray(value) ? value : value === null ? [] : [value];
16
+ if (!Array.isArray(items) || items.some(item => !(0, validation_js_1.isRecord)(item)))
17
+ throw new runtime_js_1.WellSkyError("protocol", "assessment metadata");
18
+ return items.filter(validation_js_1.isRecord);
19
+ }
20
+ function options(value) {
21
+ if (value === undefined || value === null)
22
+ return [];
23
+ return rows(value).map(raw => {
24
+ const id = numberOrNull(raw.picklist_value_id);
25
+ if (id === null)
26
+ throw new runtime_js_1.WellSkyError("protocol", "picklist metadata");
27
+ return { id, picklistId: numberOrNull(raw.picklist_id), code: stringOrNull(raw.code), picklistCode: stringOrNull(raw.picklist_code), name: stringOrNull(raw.name), displayOrder: numberOrNull(raw.disp_order), hudVisibility: numberOrNull(raw.show_on_hud_nonhud_site) };
28
+ });
29
+ }
30
+ function mergeQuestions(documents, depth = 0) {
31
+ if (depth > 30)
32
+ throw new runtime_js_1.WellSkyError("protocol", "assessment metadata");
33
+ const merged = new Map();
34
+ const childSources = new Map();
35
+ for (const document of documents)
36
+ for (const raw of rows(document)) {
37
+ const id = numberOrNull(raw.question_id);
38
+ const kind = stringOrNull(raw.question_type);
39
+ if (id === null || !kind)
40
+ throw new runtime_js_1.WellSkyError("protocol", "assessment metadata");
41
+ const fieldName = stringOrNull(raw.virt_field_name);
42
+ const key = fieldName ?? `#${id}`;
43
+ const prior = merged.get(key);
44
+ const picklistId = numberOrNull(raw.picklist_id);
45
+ if (prior && (prior.questionId !== id || prior.questionType !== kind || (prior.picklistId !== null && picklistId !== null && prior.picklistId !== picklistId)))
46
+ throw new errors_js_1.DefinitionDriftError([key]);
47
+ const optionMap = new Map((prior?.options ?? []).map(option => [option.id, option]));
48
+ for (const option of options(raw.picklist_value_list)) {
49
+ const previous = optionMap.get(option.id);
50
+ if (previous && JSON.stringify(previous) !== JSON.stringify(option))
51
+ throw new errors_js_1.DefinitionDriftError([key]);
52
+ if (picklistId !== null && option.picklistId !== null && option.picklistId !== picklistId)
53
+ throw new errors_js_1.DefinitionDriftError([key]);
54
+ optionMap.set(option.id, option);
55
+ }
56
+ merged.set(key, {
57
+ questionId: id, fieldName, questionType: kind,
58
+ description: stringOrNull(raw.description) ?? prior?.description ?? null,
59
+ displayOrder: numberOrNull(raw.disp_order) ?? prior?.displayOrder ?? null,
60
+ mandatory: boolOrNull(raw.mandatory_flag) ?? boolOrNull(raw.manditory_flag) ?? prior?.mandatory ?? null,
61
+ showOnPrevious: boolOrNull(raw.show_on_prev) ?? prior?.showOnPrevious ?? null,
62
+ picklistId: picklistId ?? prior?.picklistId ?? null,
63
+ options: [...optionMap.values()].sort((a, b) => (a.displayOrder ?? Infinity) - (b.displayOrder ?? Infinity) || a.id - b.id),
64
+ children: [],
65
+ });
66
+ const children = childSources.get(key) ?? [];
67
+ if (raw.sub_assessment_question_list != null)
68
+ children.push(raw.sub_assessment_question_list);
69
+ for (const record of rows(raw.sub_assessment_answer_list ?? []))
70
+ if (record.sub_assessment_list != null)
71
+ children.push(record.sub_assessment_list);
72
+ childSources.set(key, children);
73
+ }
74
+ for (const [key, question] of merged)
75
+ question.children = mergeQuestions(childSources.get(key) ?? [], depth + 1);
76
+ return [...merged.values()].sort((a, b) => (a.displayOrder ?? Infinity) - (b.displayOrder ?? Infinity) || a.questionId - b.questionId);
77
+ }
78
+ function flattenQuestions(questions, parent = []) {
79
+ return questions.flatMap(question => {
80
+ const path = [...parent, question.fieldName ?? `#${question.questionId}`];
81
+ return [{ path, question }, ...flattenQuestions(question.children, path)];
82
+ });
83
+ }
84
+ /** Only metadata fields are copied; no answers, client IDs, recordsets, or staff IDs survive. */
85
+ function buildAssessmentDefinition(input) {
86
+ const questions = mergeQuestions([input.mobile, input.generic]);
87
+ if (!questions.length)
88
+ throw new runtime_js_1.WellSkyError("protocol", "assessment metadata");
89
+ return { tenant: input.tenant, assessmentCode: input.assessmentCode, effectiveDate: input.effectiveDate ?? null, retrievedAt: new Date().toISOString(), picklistEffectiveDate: "current", questions, unresolvedPicklists: flattenQuestions(questions).filter(({ question }) => question.questionType === "lookup" && !question.options.length).map(({ path }) => path.join("/")) };
90
+ }
91
+ function compareDefinition(expected, definition) {
92
+ const old = new Map(expected.questions.map(q => [JSON.stringify(q.path), q]));
93
+ const current = new Map(flattenQuestions(definition.questions).map(q => [JSON.stringify(q.path), q]));
94
+ const added = [], removed = [], retyped = [], newlyMandatory = [];
95
+ for (const [key, entry] of current) {
96
+ const previous = old.get(key);
97
+ if (!previous)
98
+ added.push(entry.path.join("/"));
99
+ if (previous && previous.questionType !== entry.question.questionType)
100
+ retyped.push(entry.path.join("/"));
101
+ if (entry.question.mandatory === true && previous?.mandatory !== true)
102
+ newlyMandatory.push(entry.path.join("/"));
103
+ }
104
+ for (const [key, entry] of old)
105
+ if (!current.has(key))
106
+ removed.push(entry.path.join("/"));
107
+ return { breaking: Boolean(removed.length || retyped.length || newlyMandatory.length), added, removed, retyped, newlyMandatory };
108
+ }
109
+ function resolvePicklistOption(question, selector) {
110
+ let found = selector.code === undefined ? [] : question.options.filter(option => option.code === selector.code);
111
+ if (!found.length && selector.name !== undefined)
112
+ found = question.options.filter(option => option.name?.trim() === selector.name?.trim());
113
+ if (found.length !== 1 || !found[0])
114
+ throw new errors_js_1.UnknownPicklistValueError(question.fieldName ?? `#${question.questionId}`);
115
+ return structuredClone(found[0]);
116
+ }
117
+ class AssessmentMetadata {
118
+ #source;
119
+ #tenant;
120
+ #ttl;
121
+ #max;
122
+ #cache = new Map();
123
+ constructor(tenant, source, ttlMs = 60_000, maxEntries = 100) {
124
+ if (!Number.isSafeInteger(ttlMs) || ttlMs < 0 || !Number.isSafeInteger(maxEntries) || maxEntries < 1)
125
+ throw new errors_js_1.ValidationError("metadata configuration");
126
+ this.#tenant = tenant;
127
+ this.#source = source;
128
+ this.#ttl = ttlMs;
129
+ this.#max = maxEntries;
130
+ }
131
+ async getDefinition(context) {
132
+ context.signal?.throwIfAborted();
133
+ if (!Number.isSafeInteger(context.clientId) || context.clientId < 1 || !context.assessmentCode)
134
+ throw new errors_js_1.ValidationError("assessment metadata", ["clientId", "assessmentCode"]);
135
+ const key = JSON.stringify([context.clientId, context.assessmentCode, context.effectiveDate ?? null]);
136
+ const cached = this.#cache.get(key);
137
+ if (!context.refresh && cached && cached.expires > Date.now())
138
+ return structuredClone(cached.value);
139
+ const [mobile, generic] = await Promise.all([this.#source.mobile(context), this.#source.generic(context)]);
140
+ context.signal?.throwIfAborted();
141
+ const value = buildAssessmentDefinition({ tenant: this.#tenant, assessmentCode: context.assessmentCode, ...(context.effectiveDate === undefined ? {} : { effectiveDate: context.effectiveDate }), mobile, generic });
142
+ this.#cache.delete(key);
143
+ if (this.#cache.size >= this.#max) {
144
+ const first = this.#cache.keys().next().value;
145
+ if (first !== undefined)
146
+ this.#cache.delete(first);
147
+ }
148
+ this.#cache.set(key, { expires: Date.now() + this.#ttl, value });
149
+ return structuredClone(value);
150
+ }
151
+ async listQuestions(context) { return flattenQuestions((await this.getDefinition(context)).questions); }
152
+ async getQuestion(context) {
153
+ const matches = (await this.listQuestions(context)).filter(entry => entry.question.fieldName === context.fieldName && (context.parentPath === undefined || JSON.stringify(entry.path.slice(0, -1)) === JSON.stringify(context.parentPath)));
154
+ if (matches.length !== 1 || !matches[0])
155
+ throw new errors_js_1.ValidationError("question resolution", [context.fieldName]);
156
+ return matches[0].question;
157
+ }
158
+ async listPicklists(context) {
159
+ return (await this.listQuestions(context)).filter(({ question }) => question.questionType === "lookup" || question.options.length).map(({ path, question }) => ({ picklistId: question.picklistId, questionPath: path, options: question.options, status: question.options.length ? "enumerated" : "unresolved" }));
160
+ }
161
+ async resolve(context) { return resolvePicklistOption(await this.getQuestion(context), context); }
162
+ clearCache() { this.#cache.clear(); }
163
+ }
164
+ exports.AssessmentMetadata = AssessmentMetadata;
165
+ //# sourceMappingURL=metadata.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metadata.js","sourceRoot":"","sources":["../../src/metadata.ts"],"names":[],"mappings":"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","sourcesContent":["import { WellSkyError } from \"./runtime.js\";\nimport type { RequestOptions } from \"./runtime.js\";\nimport { DefinitionDriftError, UnknownPicklistValueError, ValidationError } from \"./errors.js\";\nimport { isRecord } from \"./validation.js\";\n\nexport interface AssessmentContext extends RequestOptions {\n clientId: number;\n assessmentCode: string;\n effectiveDate?: string;\n refresh?: boolean;\n}\nexport interface PicklistOption {\n id: number;\n picklistId: number | null;\n code: string | null;\n picklistCode: string | null;\n /** Raw metadata name. Not proof of a valid standalone/enrollment write label. */\n name: string | null;\n displayOrder: number | null;\n hudVisibility: number | null;\n}\nexport interface QuestionDefinition {\n questionId: number;\n fieldName: string | null;\n description: string | null;\n questionType: string;\n displayOrder: number | null;\n mandatory: boolean | null;\n showOnPrevious: boolean | null;\n picklistId: number | null;\n options: PicklistOption[];\n children: QuestionDefinition[];\n}\nexport interface AssessmentDefinition {\n tenant: string;\n assessmentCode: string;\n effectiveDate: string | null;\n retrievedAt: string;\n /** The mobile metadata endpoint cannot filter its option catalog by date. */\n picklistEffectiveDate: \"current\";\n questions: QuestionDefinition[];\n unresolvedPicklists: string[];\n}\nexport interface QuestionReference { fieldName: string; parentPath?: readonly string[] }\nexport interface QuestionEntry { path: string[]; question: QuestionDefinition }\nexport interface PicklistDefinition {\n picklistId: number | null;\n questionPath: string[];\n options: PicklistOption[];\n status: \"enumerated\" | \"unresolved\";\n}\nexport type PicklistSelector = { code: string; name?: string } | { name: string; code?: never };\nexport interface MetadataSource {\n generic: (context: AssessmentContext) => Promise<unknown>;\n mobile: (context: AssessmentContext) => Promise<unknown>;\n}\nexport interface DefinitionExpectation { questions: ReadonlyArray<{ path: readonly string[]; questionType: string; mandatory?: boolean | null }> }\nexport interface DefinitionDrift {\n breaking: boolean;\n added: string[];\n removed: string[];\n retyped: string[];\n newlyMandatory: string[];\n}\n\nfunction numberOrNull(value: unknown): number | null { return typeof value === \"number\" && Number.isSafeInteger(value) ? value : null; }\nfunction stringOrNull(value: unknown): string | null { return typeof value === \"string\" ? value : null; }\nfunction boolOrNull(value: unknown): boolean | null { return typeof value === \"boolean\" ? value : null; }\nfunction rows(value: unknown): Record<string, unknown>[] {\n const items: unknown = isRecord(value) && Array.isArray(value.value) ? value.value : Array.isArray(value) ? value : value === null ? [] : [value];\n if (!Array.isArray(items) || items.some(item => !isRecord(item))) throw new WellSkyError(\"protocol\", \"assessment metadata\");\n return items.filter(isRecord);\n}\n\nfunction options(value: unknown): PicklistOption[] {\n if (value === undefined || value === null) return [];\n return rows(value).map(raw => {\n const id = numberOrNull(raw.picklist_value_id);\n if (id === null) throw new WellSkyError(\"protocol\", \"picklist metadata\");\n return { id, picklistId: numberOrNull(raw.picklist_id), code: stringOrNull(raw.code), picklistCode: stringOrNull(raw.picklist_code), name: stringOrNull(raw.name), displayOrder: numberOrNull(raw.disp_order), hudVisibility: numberOrNull(raw.show_on_hud_nonhud_site) };\n });\n}\n\nfunction mergeQuestions(documents: unknown[], depth = 0): QuestionDefinition[] {\n if (depth > 30) throw new WellSkyError(\"protocol\", \"assessment metadata\");\n const merged = new Map<string, QuestionDefinition>();\n const childSources = new Map<string, unknown[]>();\n for (const document of documents) for (const raw of rows(document)) {\n const id = numberOrNull(raw.question_id);\n const kind = stringOrNull(raw.question_type);\n if (id === null || !kind) throw new WellSkyError(\"protocol\", \"assessment metadata\");\n const fieldName = stringOrNull(raw.virt_field_name);\n const key = fieldName ?? `#${id}`;\n const prior = merged.get(key);\n const picklistId = numberOrNull(raw.picklist_id);\n if (prior && (prior.questionId !== id || prior.questionType !== kind || (prior.picklistId !== null && picklistId !== null && prior.picklistId !== picklistId))) throw new DefinitionDriftError([key]);\n const optionMap = new Map((prior?.options ?? []).map(option => [option.id, option]));\n for (const option of options(raw.picklist_value_list)) {\n const previous = optionMap.get(option.id);\n if (previous && JSON.stringify(previous) !== JSON.stringify(option)) throw new DefinitionDriftError([key]);\n if (picklistId !== null && option.picklistId !== null && option.picklistId !== picklistId) throw new DefinitionDriftError([key]);\n optionMap.set(option.id, option);\n }\n merged.set(key, {\n questionId: id, fieldName, questionType: kind,\n description: stringOrNull(raw.description) ?? prior?.description ?? null,\n displayOrder: numberOrNull(raw.disp_order) ?? prior?.displayOrder ?? null,\n mandatory: boolOrNull(raw.mandatory_flag) ?? boolOrNull(raw.manditory_flag) ?? prior?.mandatory ?? null,\n showOnPrevious: boolOrNull(raw.show_on_prev) ?? prior?.showOnPrevious ?? null,\n picklistId: picklistId ?? prior?.picklistId ?? null,\n options: [...optionMap.values()].sort((a, b) => (a.displayOrder ?? Infinity) - (b.displayOrder ?? Infinity) || a.id - b.id),\n children: [],\n });\n const children = childSources.get(key) ?? [];\n if (raw.sub_assessment_question_list != null) children.push(raw.sub_assessment_question_list);\n for (const record of rows(raw.sub_assessment_answer_list ?? [])) if (record.sub_assessment_list != null) children.push(record.sub_assessment_list);\n childSources.set(key, children);\n }\n for (const [key, question] of merged) question.children = mergeQuestions(childSources.get(key) ?? [], depth + 1);\n return [...merged.values()].sort((a, b) => (a.displayOrder ?? Infinity) - (b.displayOrder ?? Infinity) || a.questionId - b.questionId);\n}\n\nexport function flattenQuestions(questions: readonly QuestionDefinition[], parent: readonly string[] = []): QuestionEntry[] {\n return questions.flatMap(question => {\n const path = [...parent, question.fieldName ?? `#${question.questionId}`];\n return [{ path, question }, ...flattenQuestions(question.children, path)];\n });\n}\n\n/** Only metadata fields are copied; no answers, client IDs, recordsets, or staff IDs survive. */\nexport function buildAssessmentDefinition(input: { tenant: string; assessmentCode: string; effectiveDate?: string; mobile: unknown; generic: unknown }): AssessmentDefinition {\n const questions = mergeQuestions([input.mobile, input.generic]);\n if (!questions.length) throw new WellSkyError(\"protocol\", \"assessment metadata\");\n return { tenant: input.tenant, assessmentCode: input.assessmentCode, effectiveDate: input.effectiveDate ?? null, retrievedAt: new Date().toISOString(), picklistEffectiveDate: \"current\", questions, unresolvedPicklists: flattenQuestions(questions).filter(({ question }) => question.questionType === \"lookup\" && !question.options.length).map(({ path }) => path.join(\"/\")) };\n}\n\nexport function compareDefinition(expected: DefinitionExpectation, definition: AssessmentDefinition): DefinitionDrift {\n const old = new Map(expected.questions.map(q => [JSON.stringify(q.path), q]));\n const current = new Map(flattenQuestions(definition.questions).map(q => [JSON.stringify(q.path), q]));\n const added: string[] = [], removed: string[] = [], retyped: string[] = [], newlyMandatory: string[] = [];\n for (const [key, entry] of current) {\n const previous = old.get(key);\n if (!previous) added.push(entry.path.join(\"/\"));\n if (previous && previous.questionType !== entry.question.questionType) retyped.push(entry.path.join(\"/\"));\n if (entry.question.mandatory === true && previous?.mandatory !== true) newlyMandatory.push(entry.path.join(\"/\"));\n }\n for (const [key, entry] of old) if (!current.has(key)) removed.push(entry.path.join(\"/\"));\n return { breaking: Boolean(removed.length || retyped.length || newlyMandatory.length), added, removed, retyped, newlyMandatory };\n}\n\nexport function resolvePicklistOption(question: QuestionDefinition, selector: PicklistSelector): PicklistOption {\n let found = selector.code === undefined ? [] : question.options.filter(option => option.code === selector.code);\n if (!found.length && selector.name !== undefined) found = question.options.filter(option => option.name?.trim() === selector.name?.trim());\n if (found.length !== 1 || !found[0]) throw new UnknownPicklistValueError(question.fieldName ?? `#${question.questionId}`);\n return structuredClone(found[0]);\n}\n\nexport class AssessmentMetadata {\n readonly #source: MetadataSource;\n readonly #tenant: string;\n readonly #ttl: number;\n readonly #max: number;\n readonly #cache = new Map<string, { expires: number; value: AssessmentDefinition }>();\n constructor(tenant: string, source: MetadataSource, ttlMs = 60_000, maxEntries = 100) {\n if (!Number.isSafeInteger(ttlMs) || ttlMs < 0 || !Number.isSafeInteger(maxEntries) || maxEntries < 1) throw new ValidationError(\"metadata configuration\");\n this.#tenant = tenant; this.#source = source; this.#ttl = ttlMs; this.#max = maxEntries;\n }\n async getDefinition(context: AssessmentContext): Promise<AssessmentDefinition> {\n context.signal?.throwIfAborted();\n if (!Number.isSafeInteger(context.clientId) || context.clientId < 1 || !context.assessmentCode) throw new ValidationError(\"assessment metadata\", [\"clientId\", \"assessmentCode\"]);\n const key = JSON.stringify([context.clientId, context.assessmentCode, context.effectiveDate ?? null]);\n const cached = this.#cache.get(key);\n if (!context.refresh && cached && cached.expires > Date.now()) return structuredClone(cached.value);\n const [mobile, generic] = await Promise.all([this.#source.mobile(context), this.#source.generic(context)]);\n context.signal?.throwIfAborted();\n const value = buildAssessmentDefinition({ tenant: this.#tenant, assessmentCode: context.assessmentCode, ...(context.effectiveDate === undefined ? {} : { effectiveDate: context.effectiveDate }), mobile, generic });\n this.#cache.delete(key);\n if (this.#cache.size >= this.#max) { const first = this.#cache.keys().next().value; if (first !== undefined) this.#cache.delete(first); }\n this.#cache.set(key, { expires: Date.now() + this.#ttl, value });\n return structuredClone(value);\n }\n async listQuestions(context: AssessmentContext): Promise<QuestionEntry[]> { return flattenQuestions((await this.getDefinition(context)).questions); }\n async getQuestion(context: AssessmentContext & QuestionReference): Promise<QuestionDefinition> {\n const matches = (await this.listQuestions(context)).filter(entry => entry.question.fieldName === context.fieldName && (context.parentPath === undefined || JSON.stringify(entry.path.slice(0, -1)) === JSON.stringify(context.parentPath)));\n if (matches.length !== 1 || !matches[0]) throw new ValidationError(\"question resolution\", [context.fieldName]);\n return matches[0].question;\n }\n async listPicklists(context: AssessmentContext): Promise<PicklistDefinition[]> {\n return (await this.listQuestions(context)).filter(({ question }) => question.questionType === \"lookup\" || question.options.length).map(({ path, question }) => ({ picklistId: question.picklistId, questionPath: path, options: question.options, status: question.options.length ? \"enumerated\" : \"unresolved\" }));\n }\n async resolve(context: AssessmentContext & QuestionReference & PicklistSelector): Promise<PicklistOption> { return resolvePicklistOption(await this.getQuestion(context), context); }\n clearCache(): void { this.#cache.clear(); }\n}\n"]}
@@ -0,0 +1 @@
1
+ {"type":"commonjs"}
@@ -0,0 +1,28 @@
1
+ import type { WellSkyClient } from "./generated/v3.js";
2
+ import type { Provider } from "./generated/v3-models.js";
3
+ import type { RequestOptions } from "./runtime.js";
4
+ export interface ProgramCatalogReader {
5
+ providers: Pick<WellSkyClient["providers"], "list">;
6
+ }
7
+ export interface ProgramCatalogRequest extends RequestOptions {
8
+ /** Optional immediate parent filter; this does not recursively include descendants. */
9
+ parentProviderId?: number;
10
+ /** Default true. Inactive/nonoperational records are omitted even if the server ignores filters. */
11
+ availableOnly?: boolean;
12
+ /** Stop with an error rather than return an incomplete catalog. Default 100 pages. */
13
+ maxPages?: number;
14
+ }
15
+ export interface ProgramCatalog {
16
+ source: "rest-providers";
17
+ /** Providers include agencies and parent organizations, not only enrollable programs.
18
+ * Visibility here does not prove the caller may enroll or record services at a provider. */
19
+ providers: Provider[];
20
+ /** Provider 0 is the vendor/system record, not an application program choice. */
21
+ excludedSystemProviderIds: number[];
22
+ retrievedAt: string;
23
+ assessmentAssignments: "requires-browser-discovery";
24
+ }
25
+ /** Uses the provider route's counted {count, values} envelope. That route returns 404
26
+ * beyond its final page, so generic empty-page pagination cannot prove completion. */
27
+ export declare function readProgramCatalog(client: ProgramCatalogReader, options?: ProgramCatalogRequest): Promise<ProgramCatalog>;
28
+ //# sourceMappingURL=program-discovery.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"program-discovery.d.ts","sourceRoot":"","sources":["../../src/program-discovery.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAKnD,MAAM,WAAW,oBAAoB;IAAG,SAAS,EAAE,IAAI,CAAC,aAAa,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC,CAAA;CAAE;AAC7F,MAAM,WAAW,qBAAsB,SAAQ,cAAc;IAC3D,uFAAuF;IACvF,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,oGAAoG;IACpG,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,sFAAsF;IACtF,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AACD,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,gBAAgB,CAAC;IACzB;gGAC4F;IAC5F,SAAS,EAAE,QAAQ,EAAE,CAAC;IACtB,iFAAiF;IACjF,yBAAyB,EAAE,MAAM,EAAE,CAAC;IACpC,WAAW,EAAE,MAAM,CAAC;IACpB,qBAAqB,EAAE,4BAA4B,CAAC;CACrD;AAWD;sFACsF;AACtF,wBAAsB,kBAAkB,CAAC,MAAM,EAAE,oBAAoB,EAAE,OAAO,GAAE,qBAA0B,GAAG,OAAO,CAAC,cAAc,CAAC,CA4BnI"}
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.readProgramCatalog = readProgramCatalog;
4
+ const runtime_js_1 = require("./runtime.js");
5
+ const errors_js_1 = require("./errors.js");
6
+ const validation_js_1 = require("./validation.js");
7
+ function catalogProvider(value) {
8
+ if (!(0, validation_js_1.isRecord)(value) || typeof value.providerId !== "number" || !Number.isSafeInteger(value.providerId) || value.providerId < 0 ||
9
+ typeof value.providerName !== "string" || typeof value.active !== "boolean" || typeof value.operational !== "boolean" || typeof value.hudCompliant !== "boolean" ||
10
+ !(value.parentProviderID === null || (typeof value.parentProviderID === "number" && Number.isSafeInteger(value.parentProviderID) && value.parentProviderID >= 0)) ||
11
+ !(value.providerGrantType === null || typeof value.providerGrantType === "string") || typeof value.dateAdded !== "string" || typeof value.dateUpdated !== "string")
12
+ throw new runtime_js_1.WellSkyError("protocol", "program catalog");
13
+ return { providerId: value.providerId, providerName: value.providerName, active: value.active, operational: value.operational, hudCompliant: value.hudCompliant,
14
+ parentProviderID: value.parentProviderID, providerGrantType: value.providerGrantType, dateAdded: value.dateAdded, dateUpdated: value.dateUpdated };
15
+ }
16
+ /** Uses the provider route's counted {count, values} envelope. That route returns 404
17
+ * beyond its final page, so generic empty-page pagination cannot prove completion. */
18
+ async function readProgramCatalog(client, options = {}) {
19
+ const { parentProviderId, availableOnly = true, maxPages = 100, ...request } = options;
20
+ if ((parentProviderId !== undefined && (!Number.isSafeInteger(parentProviderId) || parentProviderId < 1)) ||
21
+ typeof availableOnly !== "boolean" || !Number.isSafeInteger(maxPages) || maxPages < 1)
22
+ throw new errors_js_1.ValidationError("program catalog");
23
+ request.signal?.throwIfAborted();
24
+ // The live providerId sort and parentProviderID query aliases are broken upstream.
25
+ // Retain the server default order and filter the immediate parent locally.
26
+ const providers = [], ids = new Set(), excludedSystemProviderIds = [];
27
+ let expectedCount;
28
+ for (let page = 1; page <= maxPages; page++) {
29
+ const response = await client.providers.list({ ...request, query: { perPage: 100, startPage: page, total_count: true, ...(availableOnly ? { query: "active eq true and operational eq true" } : {}) } });
30
+ request.signal?.throwIfAborted();
31
+ if (!(0, validation_js_1.isRecord)(response) || typeof response.count !== "number" || !Number.isSafeInteger(response.count) || response.count < 0 || !Array.isArray(response.values))
32
+ throw new runtime_js_1.WellSkyError("protocol", "program catalog");
33
+ if (expectedCount !== undefined && response.count !== expectedCount)
34
+ throw new runtime_js_1.WellSkyError("protocol", "program catalog changed during pagination");
35
+ expectedCount = response.count;
36
+ for (const raw of response.values) {
37
+ const provider = catalogProvider(raw);
38
+ if (ids.has(provider.providerId))
39
+ throw new runtime_js_1.WellSkyError("protocol", "program catalog duplicate provider");
40
+ ids.add(provider.providerId);
41
+ if (provider.providerId === 0) {
42
+ excludedSystemProviderIds.push(0);
43
+ continue;
44
+ }
45
+ if (availableOnly && (provider.active !== true || provider.operational !== true))
46
+ continue;
47
+ if (parentProviderId !== undefined && provider.parentProviderID !== parentProviderId)
48
+ continue;
49
+ providers.push(provider);
50
+ }
51
+ if (ids.size > expectedCount || (!response.values.length && ids.size !== expectedCount))
52
+ throw new runtime_js_1.WellSkyError("protocol", "program catalog incomplete");
53
+ if (ids.size === expectedCount)
54
+ return { source: "rest-providers", providers, excludedSystemProviderIds, retrievedAt: new Date().toISOString(), assessmentAssignments: "requires-browser-discovery" };
55
+ }
56
+ throw new runtime_js_1.WellSkyError("pagination", "program catalog");
57
+ }
58
+ //# sourceMappingURL=program-discovery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"program-discovery.js","sourceRoot":"","sources":["../../src/program-discovery.ts"],"names":[],"mappings":"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","sourcesContent":["import type { WellSkyClient } from \"./generated/v3.js\";\nimport type { Provider } from \"./generated/v3-models.js\";\nimport type { RequestOptions } from \"./runtime.js\";\nimport { WellSkyError } from \"./runtime.js\";\nimport { ValidationError } from \"./errors.js\";\nimport { isRecord } from \"./validation.js\";\n\nexport interface ProgramCatalogReader { providers: Pick<WellSkyClient[\"providers\"], \"list\"> }\nexport interface ProgramCatalogRequest extends RequestOptions {\n /** Optional immediate parent filter; this does not recursively include descendants. */\n parentProviderId?: number;\n /** Default true. Inactive/nonoperational records are omitted even if the server ignores filters. */\n availableOnly?: boolean;\n /** Stop with an error rather than return an incomplete catalog. Default 100 pages. */\n maxPages?: number;\n}\nexport interface ProgramCatalog {\n source: \"rest-providers\";\n /** Providers include agencies and parent organizations, not only enrollable programs.\n * Visibility here does not prove the caller may enroll or record services at a provider. */\n providers: Provider[];\n /** Provider 0 is the vendor/system record, not an application program choice. */\n excludedSystemProviderIds: number[];\n retrievedAt: string;\n assessmentAssignments: \"requires-browser-discovery\";\n}\n\nfunction catalogProvider(value: unknown): Provider & { providerId: number } {\n if (!isRecord(value) || typeof value.providerId !== \"number\" || !Number.isSafeInteger(value.providerId) || value.providerId < 0 ||\n typeof value.providerName !== \"string\" || typeof value.active !== \"boolean\" || typeof value.operational !== \"boolean\" || typeof value.hudCompliant !== \"boolean\" ||\n !(value.parentProviderID === null || (typeof value.parentProviderID === \"number\" && Number.isSafeInteger(value.parentProviderID) && value.parentProviderID >= 0)) ||\n !(value.providerGrantType === null || typeof value.providerGrantType === \"string\") || typeof value.dateAdded !== \"string\" || typeof value.dateUpdated !== \"string\") throw new WellSkyError(\"protocol\", \"program catalog\");\n return {providerId:value.providerId, providerName:value.providerName, active:value.active, operational:value.operational, hudCompliant:value.hudCompliant,\n parentProviderID:value.parentProviderID, providerGrantType:value.providerGrantType, dateAdded:value.dateAdded, dateUpdated:value.dateUpdated};\n}\n\n/** Uses the provider route's counted {count, values} envelope. That route returns 404\n * beyond its final page, so generic empty-page pagination cannot prove completion. */\nexport async function readProgramCatalog(client: ProgramCatalogReader, options: ProgramCatalogRequest = {}): Promise<ProgramCatalog> {\n const { parentProviderId, availableOnly = true, maxPages = 100, ...request } = options;\n if ((parentProviderId !== undefined && (!Number.isSafeInteger(parentProviderId) || parentProviderId < 1)) ||\n typeof availableOnly !== \"boolean\" || !Number.isSafeInteger(maxPages) || maxPages < 1) throw new ValidationError(\"program catalog\");\n request.signal?.throwIfAborted();\n // The live providerId sort and parentProviderID query aliases are broken upstream.\n // Retain the server default order and filter the immediate parent locally.\n const providers: Provider[] = [], ids = new Set<number>(), excludedSystemProviderIds: number[] = [];\n let expectedCount: number | undefined;\n for (let page = 1; page <= maxPages; page++) {\n const response: unknown = await client.providers.list({...request, query:{perPage:100,startPage:page,total_count:true,...(availableOnly?{query:\"active eq true and operational eq true\"}:{})}});\n request.signal?.throwIfAborted();\n if (!isRecord(response) || typeof response.count !== \"number\" || !Number.isSafeInteger(response.count) || response.count < 0 || !Array.isArray(response.values)) throw new WellSkyError(\"protocol\", \"program catalog\");\n if (expectedCount !== undefined && response.count !== expectedCount) throw new WellSkyError(\"protocol\", \"program catalog changed during pagination\");\n expectedCount = response.count;\n for (const raw of response.values) {\n const provider = catalogProvider(raw);\n if (ids.has(provider.providerId)) throw new WellSkyError(\"protocol\", \"program catalog duplicate provider\");\n ids.add(provider.providerId);\n if (provider.providerId === 0) { excludedSystemProviderIds.push(0); continue; }\n if (availableOnly && (provider.active !== true || provider.operational !== true)) continue;\n if (parentProviderId !== undefined && provider.parentProviderID !== parentProviderId) continue;\n providers.push(provider);\n }\n if (ids.size > expectedCount || (!response.values.length && ids.size !== expectedCount)) throw new WellSkyError(\"protocol\", \"program catalog incomplete\");\n if (ids.size === expectedCount) return {source:\"rest-providers\", providers, excludedSystemProviderIds, retrievedAt:new Date().toISOString(), assessmentAssignments:\"requires-browser-discovery\"};\n }\n throw new WellSkyError(\"pagination\", \"program catalog\");\n}\n"]}
@@ -0,0 +1,4 @@
1
+ import type { PicklistOption, PicklistSelector, QuestionDefinition } from "./metadata.js";
2
+ /** HUD race is stored as one combination option, including single-category answers. */
3
+ export declare function resolveRaceCombination(question: QuestionDefinition, selectors: readonly PicklistSelector[]): PicklistOption;
4
+ //# sourceMappingURL=race.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"race.d.ts","sourceRoot":"","sources":["../../src/race.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAO1F,uFAAuF;AACvF,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,kBAAkB,EAAE,SAAS,EAAE,SAAS,gBAAgB,EAAE,GAAG,cAAc,CAwB3H"}
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolveRaceCombination = resolveRaceCombination;
4
+ const metadata_js_1 = require("./metadata.js");
5
+ const errors_js_1 = require("./errors.js");
6
+ const categories = ["AIAN", "ASN", "AFR", "HSP", "MES", "PI", "WHI"];
7
+ const missing = new Map([["DONTKNOW", "DK"], ["REFUSE", "R"], ["DNC", "DNC"], ["DK", "DK"], ["R", "R"]]);
8
+ /** HUD race is stored as one combination option, including single-category answers. */
9
+ function resolveRaceCombination(question, selectors) {
10
+ const field = question.fieldName ?? "HUD_RACEETHNICITY";
11
+ if (!selectors.length)
12
+ throw new errors_js_1.ValidationError("race selection must not be empty", [field]);
13
+ const combinations = question.options.filter(option => option.code?.startsWith("RACE_ETH_COMBO_"));
14
+ const selected = new Set();
15
+ for (const selector of selectors) {
16
+ // Names can occur twice in metadata. Only the combination entry is a writable answer.
17
+ const option = selector.code === undefined
18
+ ? (0, metadata_js_1.resolvePicklistOption)({ ...question, options: combinations }, selector)
19
+ : (0, metadata_js_1.resolvePicklistOption)(question, { code: selector.code });
20
+ const code = option.code;
21
+ if (!code?.startsWith("RACE_ETH_"))
22
+ throw new errors_js_1.ValidationError("unsupported race option", [field]);
23
+ const suffix = code.slice(code.startsWith("RACE_ETH_COMBO_") ? "RACE_ETH_COMBO_".length : "RACE_ETH_".length);
24
+ const missingCode = missing.get(suffix);
25
+ if (missingCode)
26
+ selected.add(missingCode);
27
+ else
28
+ for (const category of suffix.split("_")) {
29
+ if (!categories.includes(category))
30
+ throw new errors_js_1.ValidationError("unsupported race option", [field]);
31
+ selected.add(category);
32
+ }
33
+ }
34
+ const absent = [...selected].filter(code => !categories.includes(code));
35
+ if (absent.length && selected.size !== 1)
36
+ throw new errors_js_1.ValidationError("race categories cannot be mixed with missing-answer states", [field]);
37
+ const suffix = absent.length ? absent[0] : categories.filter(code => selected.has(code)).join("_");
38
+ return (0, metadata_js_1.resolvePicklistOption)({ ...question, options: combinations }, { code: `RACE_ETH_COMBO_${suffix}` });
39
+ }
40
+ //# sourceMappingURL=race.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"race.js","sourceRoot":"","sources":["../../src/race.ts"],"names":[],"mappings":"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","sourcesContent":["import type { PicklistOption, PicklistSelector, QuestionDefinition } from \"./metadata.js\";\nimport { resolvePicklistOption } from \"./metadata.js\";\nimport { ValidationError } from \"./errors.js\";\n\nconst categories = [\"AIAN\", \"ASN\", \"AFR\", \"HSP\", \"MES\", \"PI\", \"WHI\"];\nconst missing = new Map([[\"DONTKNOW\", \"DK\"], [\"REFUSE\", \"R\"], [\"DNC\", \"DNC\"], [\"DK\", \"DK\"], [\"R\", \"R\"]]);\n\n/** HUD race is stored as one combination option, including single-category answers. */\nexport function resolveRaceCombination(question: QuestionDefinition, selectors: readonly PicklistSelector[]): PicklistOption {\n const field = question.fieldName ?? \"HUD_RACEETHNICITY\";\n if (!selectors.length) throw new ValidationError(\"race selection must not be empty\", [field]);\n const combinations = question.options.filter(option => option.code?.startsWith(\"RACE_ETH_COMBO_\"));\n const selected = new Set<string>();\n for (const selector of selectors) {\n // Names can occur twice in metadata. Only the combination entry is a writable answer.\n const option = selector.code === undefined\n ? resolvePicklistOption({ ...question, options: combinations }, selector)\n : resolvePicklistOption(question, { code: selector.code });\n const code = option.code;\n if (!code?.startsWith(\"RACE_ETH_\")) throw new ValidationError(\"unsupported race option\", [field]);\n const suffix = code.slice(code.startsWith(\"RACE_ETH_COMBO_\") ? \"RACE_ETH_COMBO_\".length : \"RACE_ETH_\".length);\n const missingCode = missing.get(suffix);\n if (missingCode) selected.add(missingCode);\n else for (const category of suffix.split(\"_\")) {\n if (!categories.includes(category)) throw new ValidationError(\"unsupported race option\", [field]);\n selected.add(category);\n }\n }\n const absent = [...selected].filter(code => !categories.includes(code));\n if (absent.length && selected.size !== 1) throw new ValidationError(\"race categories cannot be mixed with missing-answer states\", [field]);\n const suffix = absent.length ? absent[0] : categories.filter(code => selected.has(code)).join(\"_\");\n return resolvePicklistOption({ ...question, options: combinations }, { code: `RACE_ETH_COMBO_${suffix}` });\n}\n"]}
@@ -0,0 +1,108 @@
1
+ /** Matching credentials/providers share cached authentication in-process. No environment or disk reads. */
2
+ export type Authentication = {
3
+ kind: "credentials";
4
+ username: string;
5
+ password: string;
6
+ } | {
7
+ kind: "token";
8
+ token: string;
9
+ } | {
10
+ kind: "provider";
11
+ getToken: (context: {
12
+ forceRefresh: boolean;
13
+ signal: AbortSignal;
14
+ }) => string | Promise<string>;
15
+ } | {
16
+ kind: "none";
17
+ };
18
+ export interface ClientOptions {
19
+ tenant: string;
20
+ auth: Authentication;
21
+ maxConcurrency?: number;
22
+ cooldown?: {
23
+ threshold: number;
24
+ windowMs: number;
25
+ durationMs: number;
26
+ };
27
+ hooks?: ClientHooks;
28
+ /** Receives the same allowlisted events as hooks. No raw request/response data. */
29
+ logger?: (event: ClientEvent) => void;
30
+ metadataCacheTtlMs?: number;
31
+ metadataCacheMaxEntries?: number;
32
+ /** Opt-in correction for a measured upstream mobile assessment dateEffective shift.
33
+ * Added to the requested instant on POST AddAssessmentAnswer only. No default timezone is assumed.
34
+ * Revalidate against saved effective dates when the server's offset changes. */
35
+ mobileAssessmentDateCorrectionMinutes?: number;
36
+ /** Defaults to the public production API URL. Supply the target environment explicitly when needed. */
37
+ baseUrl?: string;
38
+ /** Inject a fetch-compatible transport for tests or network routing. */
39
+ fetch?: typeof globalThis.fetch;
40
+ /** Total request deadline including auth, read retries, and backoff. Default 30 seconds. */
41
+ timeoutMs?: number;
42
+ /** Additional attempts for GET only. Default 2; writes are never replayed. */
43
+ maxReadRetries?: number;
44
+ retryBaseDelayMs?: number;
45
+ maxRetryDelayMs?: number;
46
+ }
47
+ export interface RequestOptions {
48
+ signal?: AbortSignal;
49
+ timeoutMs?: number;
50
+ correlationId?: string;
51
+ }
52
+ export interface ClientEvent {
53
+ type: "request" | "response" | "tokenMint" | "throttle" | "cooldown";
54
+ operation: string;
55
+ correlationId: string;
56
+ retryCount: number;
57
+ durationMs?: number;
58
+ status?: number;
59
+ retryAfterMs?: number;
60
+ until?: string;
61
+ }
62
+ export interface ClientHooks {
63
+ onRequest?: (event: ClientEvent) => void;
64
+ onResponse?: (event: ClientEvent) => void;
65
+ onTokenMint?: (event: ClientEvent) => void;
66
+ onThrottle?: (event: ClientEvent) => void;
67
+ onCooldown?: (event: ClientEvent) => void;
68
+ }
69
+ export interface ClientHealth {
70
+ state: "closed" | "open";
71
+ until: string | null;
72
+ activeRequests: number;
73
+ queuedRequests: number;
74
+ tokenMintCount: number;
75
+ }
76
+ export interface PaginationOptions {
77
+ /** Safety limit. Reaching it throws rather than silently returning partial data. Default 10,000. */
78
+ maxPages?: number;
79
+ }
80
+ export interface ODataCollection<T> {
81
+ value: T[];
82
+ "@odata.count"?: number;
83
+ "@odata.nextLink"?: string;
84
+ }
85
+ /** WellSky's total_count response. Count covers the result set, not just this page. */
86
+ export interface CountedCollection<T> {
87
+ count: number;
88
+ values: T[];
89
+ }
90
+ /** WellSky may return an object, an array, or either collection envelope for the same model. */
91
+ export type ApiResponse<T> = T | T[] | ODataCollection<T> | CountedCollection<T> | null;
92
+ export declare function toItems<T>(response: ApiResponse<T>): T[];
93
+ export type ErrorKind = "http" | "network" | "timeout" | "aborted" | "validation" | "protocol" | "pagination" | "tenant_mismatch" | "auth" | "throttled" | "cooldown" | "ambiguous_commit" | "definition_drift" | "unknown_picklist_value";
94
+ /** Deliberately contains no credentials, query values, response bodies, or client IDs. */
95
+ export declare class WellSkyError extends Error {
96
+ readonly kind: ErrorKind;
97
+ readonly status: number | undefined;
98
+ readonly operation: string;
99
+ readonly requestId: string | undefined;
100
+ readonly retryAfterMs: number | undefined;
101
+ correlationId: string | undefined;
102
+ constructor(kind: ErrorKind, operation: string, details?: {
103
+ status?: number;
104
+ requestId?: string;
105
+ retryAfterMs?: number;
106
+ });
107
+ }
108
+ //# sourceMappingURL=runtime.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../src/runtime.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.WellSkyError = void 0;
4
+ exports.toItems = toItems;
5
+ function toItems(response) {
6
+ if (response === null)
7
+ return [];
8
+ if (Array.isArray(response))
9
+ return response;
10
+ if (typeof response === "object" && "value" in response && Array.isArray(response.value)) {
11
+ return response.value;
12
+ }
13
+ if (typeof response === "object" && "count" in response && "values" in response && Array.isArray(response.values)) {
14
+ return response.values;
15
+ }
16
+ // The envelope branch above has been checked at the boundary.
17
+ return [response];
18
+ }
19
+ /** Deliberately contains no credentials, query values, response bodies, or client IDs. */
20
+ class WellSkyError extends Error {
21
+ kind;
22
+ status;
23
+ operation;
24
+ requestId;
25
+ retryAfterMs;
26
+ correlationId;
27
+ constructor(kind, operation, details = {}) {
28
+ super(`WellSky ${operation}: ${kind}${details.status === undefined ? "" : ` (HTTP ${details.status})`}`);
29
+ this.name = "WellSkyError";
30
+ this.kind = kind;
31
+ this.operation = operation;
32
+ this.status = details.status;
33
+ this.requestId = details.requestId;
34
+ this.retryAfterMs = details.retryAfterMs;
35
+ }
36
+ }
37
+ exports.WellSkyError = WellSkyError;
38
+ //# sourceMappingURL=runtime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../src/runtime.ts"],"names":[],"mappings":";;;AAqFA,0BAWC;AAXD,SAAgB,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,MAAa,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;AAjBD,oCAiBC","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"]}
@@ -0,0 +1,29 @@
1
+ import type { RequestOptions } from "./runtime.js";
2
+ import type { WriteResult } from "./verification.js";
3
+ import type { AddSubAssessmentQuestionWithAnswerViewModel } from "./generated/v3-models.js";
4
+ export interface SubassessmentContext extends RequestOptions {
5
+ clientId: number;
6
+ assessmentCode: string;
7
+ effectiveDate?: string;
8
+ }
9
+ export interface EndDateRequest extends SubassessmentContext {
10
+ parentField: string;
11
+ recordsetId: number;
12
+ endDateField: string;
13
+ endDate: string;
14
+ /** Optional caller preflight for program-specific review-date or other policies. */
15
+ preflight?: (options: RequestOptions) => Promise<void>;
16
+ }
17
+ export interface SubassessmentSource {
18
+ read: (context: SubassessmentContext) => Promise<unknown>;
19
+ write: (context: SubassessmentContext, body: AddSubAssessmentQuestionWithAnswerViewModel[]) => Promise<unknown>;
20
+ }
21
+ /** Generic recordset editing; no program names, assessment codes, or replacement policy. */
22
+ export declare class SubassessmentEditor {
23
+ #private;
24
+ constructor(tenant: string, source: SubassessmentSource);
25
+ setEndDate(input: EndDateRequest): Promise<WriteResult<{
26
+ recordsetId: number;
27
+ }>>;
28
+ }
29
+ //# sourceMappingURL=subassessments.d.ts.map
@@ -0,0 +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"}