@choiceapps/communityservices-sdk 0.1.0 → 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.
- package/CHANGELOG.md +16 -0
- package/README.md +0 -17
- package/browser/coordinated-entry-event.d.mts +78 -0
- package/browser/coordinated-entry-event.mjs +175 -0
- package/browser/current-living-situation.mjs +11 -120
- package/browser/enrollment-workflow.d.mts +17 -3
- package/browser/enrollment-workflow.mjs +78 -17
- package/browser/index.d.mts +1 -0
- package/browser/index.mjs +1 -0
- package/browser/subassessment-row-recorder.mjs +154 -0
- package/dist/cjs/encoding.d.ts.map +1 -1
- package/dist/cjs/encoding.js +2 -1
- package/dist/cjs/encoding.js.map +1 -1
- package/dist/cjs/errors.d.ts +4 -1
- package/dist/cjs/errors.d.ts.map +1 -1
- package/dist/cjs/errors.js +9 -1
- package/dist/cjs/errors.js.map +1 -1
- package/dist/cjs/runtime.d.ts +5 -1
- package/dist/cjs/runtime.d.ts.map +1 -1
- package/dist/cjs/runtime.js +1 -1
- package/dist/cjs/runtime.js.map +1 -1
- package/dist/cjs/subassessments.d.ts.map +1 -1
- package/dist/cjs/subassessments.js +8 -15
- package/dist/cjs/subassessments.js.map +1 -1
- package/dist/cjs/transport.d.ts.map +1 -1
- package/dist/cjs/transport.js +15 -3
- package/dist/cjs/transport.js.map +1 -1
- package/dist/esm/encoding.d.ts.map +1 -1
- package/dist/esm/encoding.js +2 -1
- package/dist/esm/encoding.js.map +1 -1
- package/dist/esm/errors.d.ts +4 -1
- package/dist/esm/errors.d.ts.map +1 -1
- package/dist/esm/errors.js +9 -1
- package/dist/esm/errors.js.map +1 -1
- package/dist/esm/runtime.d.ts +5 -1
- package/dist/esm/runtime.d.ts.map +1 -1
- package/dist/esm/runtime.js +1 -1
- package/dist/esm/runtime.js.map +1 -1
- package/dist/esm/subassessments.d.ts.map +1 -1
- package/dist/esm/subassessments.js +8 -15
- package/dist/esm/subassessments.js.map +1 -1
- package/dist/esm/transport.d.ts.map +1 -1
- package/dist/esm/transport.js +15 -3
- package/dist/esm/transport.js.map +1 -1
- package/docs/README.md +1 -0
- package/docs/assessments.md +21 -3
- package/docs/capabilities.md +2 -0
- package/docs/configuration.md +1 -0
- package/docs/coordinated-entry-events.md +88 -0
- package/docs/current-living-situation.md +1 -1
- package/docs/dates-and-answers.md +3 -1
- package/docs/enrollments.md +41 -1
- package/docs/reference.md +6 -2
- package/docs/troubleshooting.md +25 -0
- package/docs/using-the-sdk.md +2 -3
- package/docs/vendor-issues/README.md +2 -0
- package/docs/vendor-issues/date-semantics.md +2 -0
- package/docs/vendor-issues/yes-no-answers.md +35 -0
- package/examples/README.md +2 -0
- package/examples/coordinated-entry-events.mts +37 -0
- package/examples/enrollment-workflow.mts +5 -2
- package/package.json +1 -1
|
@@ -6,10 +6,11 @@ import {readProgramCatalog,encodeAnswers,encodeNewSubassessmentRow,toItems} from
|
|
|
6
6
|
|
|
7
7
|
const object=v=>v!==null&&typeof v==='object'&&!Array.isArray(v);
|
|
8
8
|
const positive=v=>Number.isSafeInteger(v)&&v>0;
|
|
9
|
+
const entryExitTypes=['HUD','Basic','Standard','RHY','VA','Basic Center Program Entry/Exit','PATH','Quick Call','Transitional Living Program Entry/Exit'];
|
|
9
10
|
const canonical=v=>JSON.stringify(v,(_,x)=>object(x)?Object.fromEntries(Object.keys(x).sort().map(k=>[k,x[k]])):x);
|
|
10
11
|
const hash=v=>createHash('sha256').update(canonical(v)).digest('hex');
|
|
11
12
|
const fail=message=>{throw new EnrollmentWorkflowError(message);};
|
|
12
|
-
export class EnrollmentWorkflowError extends Error {constructor(reason){super(`Enrollment workflow: ${reason}
|
|
13
|
+
export class EnrollmentWorkflowError extends Error {constructor(reason,options){super(`Enrollment workflow: ${reason}`,options);this.name='EnrollmentWorkflowError';this.reason=reason;if(options?.step!==undefined)this.step=options.step;}}
|
|
13
14
|
function date(value){
|
|
14
15
|
if(typeof value!=='string'||!/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.000)?(?:Z|[+-]\d{2}:\d{2})$/.test(value)||!Number.isFinite(Date.parse(value))||new Date(value.slice(0,19)+'Z').toISOString().slice(0,19)!==value.slice(0,19))fail('timezone-qualified whole-second date required');
|
|
15
16
|
return new Date(value).toISOString();
|
|
@@ -25,11 +26,13 @@ function sameAnswer(expected,actual){
|
|
|
25
26
|
return String(actual)===expected.answer_value;
|
|
26
27
|
}
|
|
27
28
|
function questions(response){const rows=toItems(response);if(!Array.isArray(rows)||rows.some(q=>!object(q)||typeof q.virt_field_name!=='string')||new Set(rows.map(q=>q.virt_field_name)).size!==rows.length)fail('ambiguous assessment read');return rows;}
|
|
28
|
-
function compile(definition,input){
|
|
29
|
+
function compile(definition,input,{yesNoWrites,writeLabel}={}){
|
|
29
30
|
fields(input,['answers','subassessments','endDates','notApplicable','carryForward']);
|
|
30
31
|
const answers=input.answers??{},excluded=input.notApplicable??{},carry=input.carryForward??[],rows=input.subassessments??[],ends=input.endDates??[];
|
|
31
32
|
if(!object(answers)||!object(excluded)||!Array.isArray(carry)||!Array.isArray(rows)||!Array.isArray(ends)||new Set(carry).size!==carry.length)fail('invalid assessment plan');
|
|
32
|
-
const
|
|
33
|
+
const encoded=encodeAnswers(definition.questions,answers,{endpoint:'mobile'}),index=new Map(definition.questions.map(q=>[q.fieldName,q]));
|
|
34
|
+
// Mobile writes store empty yes/no values, so the standard endpoint can own them instead.
|
|
35
|
+
const yesNo=yesNoWrites==='standard'?encoded.filter(q=>q.question_type==='yes_no'):[],scalar=encoded.filter(q=>!yesNo.includes(q));
|
|
33
36
|
for(const [field,reason]of Object.entries(excluded))if(!index.has(field)||typeof reason!=='string'||!reason.trim())fail('not-applicable explanation required');
|
|
34
37
|
for(const field of carry)if(typeof field!=='string'||!index.has(field))fail('unknown carry-forward field');
|
|
35
38
|
const keys=new Set(),semantics=new Set();
|
|
@@ -57,7 +60,23 @@ function compile(definition,input){
|
|
|
57
60
|
const birthDate=scalar.find(q=>q.virt_field_name==='SVPPROFDOB');
|
|
58
61
|
if(birthDate){if(birthDate.question_type!=='date')fail('DOB question type changed');validateBirthDate(birthDate.answer_value);}
|
|
59
62
|
for(const q of scalar)if(q.virt_field_name!=='SVPPROFDOB'&&q.question_type==='date'&&q.answer_value)date(q.answer_value);
|
|
60
|
-
|
|
63
|
+
// The standard endpoint rejects a request that omits any mandatory answer, even one already
|
|
64
|
+
// recorded at that date. Resolve every label now so no write precedes a missing label.
|
|
65
|
+
const mandatory=[];
|
|
66
|
+
if(yesNo.length)for(const q of definition.questions){
|
|
67
|
+
if(!q.mandatory||['blank','label','sub_assessment'].includes(q.questionType)||yesNo.some(y=>y.virt_field_name===q.fieldName))continue;
|
|
68
|
+
// Only mandatory lookups were verified live; this also keeps DOB inside its own helper.
|
|
69
|
+
if(q.questionType!=='lookup')fail(`standard yes/no writes support mandatory lookups only; ${q.fieldName} is ${q.questionType}`);
|
|
70
|
+
const base={question_id:q.questionId,question_type:q.questionType,virt_field_name:q.fieldName};
|
|
71
|
+
if(q.fieldName in answers){
|
|
72
|
+
const [label]=encodeAnswers(definition.questions,{[q.fieldName]:answers[q.fieldName]},{endpoint:'standalone',writeLabel});
|
|
73
|
+
const [stored]=encodeAnswers(definition.questions,{[q.fieldName]:answers[q.fieldName]},{endpoint:'mobile'});
|
|
74
|
+
if(!label||!stored)fail(`mandatory answer ${q.fieldName} has no standard encoding`);
|
|
75
|
+
mandatory.push({...base,answer_value:label.answer_value,expected:stored.answer_value});
|
|
76
|
+
}else if(q.fieldName in excluded)mandatory.push({...base,answer_value:'',expected:''});
|
|
77
|
+
else if(carry.includes(q.fieldName))mandatory.push({...base,carry:true});
|
|
78
|
+
}
|
|
79
|
+
return {scalar:scalar.filter(q=>q.virt_field_name!=='SVPPROFDOB'),yesNo,mandatory,dateOfBirth:birthDate?.answer_value,rows:compiledRows,ends:compiledEnds,carry,excluded};
|
|
61
80
|
}
|
|
62
81
|
async function enrollments(api,clientId){
|
|
63
82
|
const all=[],ids=new Set();let count;
|
|
@@ -71,17 +90,26 @@ async function enrollments(api,clientId){
|
|
|
71
90
|
|
|
72
91
|
/** Explicit orchestration for an existing client. All writers must share the durable store.
|
|
73
92
|
* No automatic retries of uncertain REST writes. This is not a cross-system transaction. */
|
|
74
|
-
export function createEnrollmentWorkflow({api,discovery,helpers,store,enrollmentSession,exitUi,memberEntryDatePort,birthDates}){
|
|
93
|
+
export function createEnrollmentWorkflow({api,discovery,helpers,store,enrollmentSession,exitUi,memberEntryDatePort,birthDates,assessmentLocations={},yesNoWrites='mobile',writeLabel}){
|
|
75
94
|
const tenantScope=apiScope(api, discovery, helpers, enrollmentSession, exitUi);
|
|
76
95
|
if(typeof discovery?.getProviderAssessments!=='function'||typeof helpers?.createInterimUpdate!=='function'||!store)fail('REST API, discovery, enrollment helpers and durable store required');
|
|
96
|
+
if(!['mobile','standard'].includes(yesNoWrites)||yesNoWrites==='standard'&&(typeof writeLabel!=='function'||typeof api.assessments?.create!=='function'))fail('yesNoWrites must be mobile, or standard with writeLabel and assessments.create');
|
|
97
|
+
if(!object(assessmentLocations))fail('assessment locations must be a map by Entry/Exit type');
|
|
98
|
+
for(const [type,locations]of Object.entries(assessmentLocations)){
|
|
99
|
+
if(!entryExitTypes.includes(type))fail('unsupported Entry/Exit type in assessment locations');
|
|
100
|
+
fields(locations,['entry','interim','exit']);
|
|
101
|
+
if(['entry','interim'].some(phase=>typeof locations[phase]!=='string'||!locations[phase].trim())||Object.values(locations).some(location=>typeof location!=='string'||!location.trim()))fail('entry and interim assessment locations required; exit location must be nonempty when supplied');
|
|
102
|
+
}
|
|
103
|
+
const locationsByType={HUD:{entry:'showHudEntry',interim:'showHudInterim',exit:'showHudExit'},VA:{entry:'showVaEntry',interim:'showVaInterim',exit:'showVaExit'},...structuredClone(assessmentLocations)};
|
|
77
104
|
const discover=async(input,includeExit=false)=>{
|
|
78
|
-
fields(input,['clientId','providerId','type','entryDate']);if(!positive(input.clientId)||!positive(input.providerId)||!
|
|
105
|
+
fields(input,['clientId','providerId','type','entryDate']);if(!positive(input.clientId)||!positive(input.providerId)||!entryExitTypes.includes(input.type))fail('client, provider and supported Entry/Exit type required');const at=date(input.entryDate);
|
|
106
|
+
const locations=locationsByType[input.type];if(!locations||includeExit&&!locations.exit)fail(`assessment locations required for ${input.type}${includeExit?' including exit':''}`);
|
|
79
107
|
const client=toItems(await api.clients.get({path:{clientId:input.clientId}}));if(client.length!==1||client[0].clientId!==input.clientId||client[0].isActive===false)fail('active client required');
|
|
80
108
|
const catalog=await readProgramCatalog(api);const providers=catalog.providers.filter(p=>p.providerId===input.providerId);if(providers.length!==1)fail('active operational program required');
|
|
81
109
|
const configuration=await discovery.getProviderAssessments({providerId:input.providerId});if(configuration.providerId!==input.providerId)fail('provider discovery mismatch');
|
|
82
|
-
const
|
|
83
|
-
for(const
|
|
84
|
-
const matches=configuration.defaults.filter(d=>d.location===
|
|
110
|
+
const resolved={};
|
|
111
|
+
for(const phase of ['entry','interim',...(includeExit?['exit']:[])]){
|
|
112
|
+
const matches=configuration.defaults.filter(d=>d.location===locations[phase]);if(matches.length!==1||matches[0].resolution!=='resolved'||!matches[0].assessment?.code)fail('program assessment default unresolved');
|
|
85
113
|
const assessment=matches[0].assessment;const definition=await api.assessments.getDefinition({clientId:input.clientId,assessmentCode:assessment.code,effectiveDate:at,refresh:true});
|
|
86
114
|
if(definition.tenant!==api.tenant||definition.assessmentCode!==assessment.code||definition.unresolvedPicklists.length)fail('assessment metadata incomplete');
|
|
87
115
|
resolved[phase]={assessment,definition};
|
|
@@ -93,7 +121,7 @@ export function createEnrollmentWorkflow({api,discovery,helpers,store,enrollment
|
|
|
93
121
|
const run=async(kind,raw,internal={})=>{
|
|
94
122
|
fields(raw,kind==='entry'?['key','clientId','providerId','type','entryDate','assessment']:['key','enrollmentKey','clientId',kind==='exit'?'exitDate':'reviewDate','assessment']);
|
|
95
123
|
const input=structuredClone(raw);key(input.key);if(!positive(input.clientId))fail('client ID required');
|
|
96
|
-
if(kind==='entry'){if(!positive(input.providerId)||!
|
|
124
|
+
if(kind==='entry'){if(!positive(input.providerId)||!entryExitTypes.includes(input.type))fail('program and supported Entry/Exit type required');input.entryDate=date(input.entryDate);}else{key(input.enrollmentKey);if(kind==='addition')input.entryDate=date(input.entryDate);else if(kind==='exit')input.exitDate=date(input.exitDate);else input.reviewDate=date(input.reviewDate);}
|
|
97
125
|
if(!object(input.assessment))fail('assessment plan required');
|
|
98
126
|
const locked=internal.locked?async(_scope,work)=>work():store.withLock.bind(store);
|
|
99
127
|
return locked(scope(input.clientId),async()=>{
|
|
@@ -103,6 +131,8 @@ export function createEnrollmentWorkflow({api,discovery,helpers,store,enrollment
|
|
|
103
131
|
if(records.some(r=>r.stage!=='verified'&&r.key!==input.key))fail('another unfinished workflow must be reconciled first');
|
|
104
132
|
const matches=records.filter(r=>r.key===input.key);if(matches.length>1)fail('duplicate journal keys');let record=matches[0];
|
|
105
133
|
const intentHash=hash({kind,input,...(internal.owner?{household:internal.owner}:{})});if(record&&record.intentHash!==intentHash)fail('key conflicts with previous intent');
|
|
134
|
+
// Changing the yes/no endpoint after an attempt would be an endpoint switch, not reconciliation.
|
|
135
|
+
if(record&&record.stage!=='verified'&&(record.yesNoWrites??'mobile')!==yesNoWrites)fail('yes/no write mode changed since this workflow started');
|
|
106
136
|
const entry=kind!=='entry'?records.find(r=>r.key===input.enrollmentKey&&r.kind==='entry'&&r.stage==='verified'):null;
|
|
107
137
|
if(kind!=='entry'&&!entry)fail('verified enrollment workflow required');
|
|
108
138
|
const context=kind==='entry'?input:kind==='addition'?{...entry.context,entryDate:input.entryDate}:entry.context;
|
|
@@ -113,7 +143,7 @@ export function createEnrollmentWorkflow({api,discovery,helpers,store,enrollment
|
|
|
113
143
|
const definition=discovered[kind].definition,code=definition.assessmentCode,at=kind==='entry'?input.entryDate:(input.exitDate??input.reviewDate);
|
|
114
144
|
const exitSchemaHash=kind==='exit'?hash({assessment:discovered.exit.assessment,questions:definition.questions}):undefined;
|
|
115
145
|
if(record&&kind==='exit'&&record.exitSchemaHash!==exitSchemaHash)fail('exit assessment configuration changed');
|
|
116
|
-
const plan=compile(definition,input.assessment);
|
|
146
|
+
const plan=compile(definition,input.assessment,{yesNoWrites,writeLabel});
|
|
117
147
|
const carriesBirthDate=plan.carry.includes('SVPPROFDOB'),hasBirthDate=plan.dateOfBirth!==undefined||carriesBirthDate;
|
|
118
148
|
let carriedBirthDate;
|
|
119
149
|
if(hasBirthDate){
|
|
@@ -142,10 +172,28 @@ export function createEnrollmentWorkflow({api,discovery,helpers,store,enrollment
|
|
|
142
172
|
if(proposedHead)checkHeadAnswer(proposedHead.answer_value);
|
|
143
173
|
if(plan.ends.length&&(kind==='entry'||plan.ends.some(e=>Date.parse(e.endDate)>=Date.parse(at)||Date.parse(e.endDate)<Date.parse(context.entryDate))))fail('row closure must fall between entry and assessment');
|
|
144
174
|
const read=async()=>questions(await api.assessments.get({path:{clientId:input.clientId,assessmentCode:code},query:{dateEffective:at}}));
|
|
145
|
-
|
|
175
|
+
// An undated read omits rows dated after the server's current time, which can include this
|
|
176
|
+
// assessment's own rows. Read at the later of now and the assessment instant.
|
|
177
|
+
const readCurrent=async()=>questions(await api.assessments.get({path:{clientId:input.clientId,assessmentCode:code},query:{dateEffective:new Date(Math.max(Date.now(),Date.parse(at))).toISOString().slice(0,19)+'Z'}}));
|
|
178
|
+
// A generic read at exactly the effective instant returns null for yes/no answers saved at
|
|
179
|
+
// that instant; one second later returns them. Only the yes/no step needs this.
|
|
180
|
+
const readSaved=async()=>questions(await api.assessments.get({path:{clientId:input.clientId,assessmentCode:code},query:{dateEffective:new Date(Date.parse(at)+1000).toISOString()}}));
|
|
146
181
|
const initial=await read();
|
|
147
182
|
if(expectedHead===input.clientId&&headQuestion)checkHeadAnswer(proposedHead?.answer_value??initial.find(q=>q.virt_field_name==='HUD_RELATIONTOHOH')?.answer_value);
|
|
148
183
|
for(const field of plan.carry.filter(field=>field!=='SVPPROFDOB')){const q=initial.find(q=>q.virt_field_name===field);if(!q||(q.question_type==='sub_assessment'?!q.sub_assessment_answer_list?.length:!q.answer_value))fail('carry-forward field is empty');}
|
|
184
|
+
// Resend mandatory answers with the standard yes/no write. A blank write must not hide a recorded value.
|
|
185
|
+
const mandatory=plan.mandatory.map(m=>{
|
|
186
|
+
const recorded=initial.find(q=>q.virt_field_name===m.virt_field_name)?.answer_value;
|
|
187
|
+
if(m.carry){
|
|
188
|
+
const question=definition.questions.find(q=>q.fieldName===m.virt_field_name),options=question.options.filter(o=>String(o.id)===String(recorded));
|
|
189
|
+
const label=options.length===1?writeLabel(question,options[0]):undefined;
|
|
190
|
+
if(!label)fail(`carried mandatory answer ${m.virt_field_name} has no verified write label`);
|
|
191
|
+
if(m.virt_field_name==='HUD_RELATIONTOHOH')checkHeadAnswer(recorded);
|
|
192
|
+
return {question_id:m.question_id,question_type:m.question_type,virt_field_name:m.virt_field_name,answer_value:label,expected:String(recorded)};
|
|
193
|
+
}
|
|
194
|
+
if(m.expected===''&&recorded!==null&&recorded!==undefined&&recorded!=='')fail(`not-applicable mandatory field ${m.virt_field_name} has a recorded value; answer it explicitly`);
|
|
195
|
+
return m;
|
|
196
|
+
});
|
|
149
197
|
// Validate closure targets before creating enrollment/review or submitting any answers.
|
|
150
198
|
const current=await readCurrent();
|
|
151
199
|
const currentHead=current.find(q=>q.virt_field_name==='HUD_RELATIONTOHOH');
|
|
@@ -161,15 +209,22 @@ export function createEnrollmentWorkflow({api,discovery,helpers,store,enrollment
|
|
|
161
209
|
}
|
|
162
210
|
if(internal.preflight)return {assessmentCode:code,...(internal.pinSchema?{schemaHash}:{}),...(exitSchemaHash?{exitSchemaHash}:{})};
|
|
163
211
|
const wasVerified=record?.stage==='verified';
|
|
164
|
-
if(!record){record={version:1,key:input.key,kind,intentHash,schemaHash,...(exitSchemaHash?{exitSchemaHash}:{}),context:{clientId:input.clientId,providerId:context.providerId,type:context.type,entryDate:context.entryDate},assessmentCode:code,stage:'pending',steps:{},rows:{},ends:plan.ends};records.push(record);}
|
|
212
|
+
if(!record){record={version:1,key:input.key,kind,intentHash,schemaHash,...(exitSchemaHash?{exitSchemaHash}:{}),context:{clientId:input.clientId,providerId:context.providerId,type:context.type,entryDate:context.entryDate},assessmentCode:code,...(yesNoWrites==='standard'?{yesNoWrites}:{}),stage:'pending',steps:{},rows:{},ends:plan.ends};records.push(record);}
|
|
165
213
|
const persist=()=>store.write(scope(input.clientId),structuredClone(records));await persist();
|
|
166
214
|
const step=async(name,inspect,submit)=>{
|
|
167
215
|
let result=await inspect();const previous=record.steps[name];
|
|
168
216
|
if(result.found){record.steps[name]={state:'verified',value:result.value};await persist();return result.value;}
|
|
169
|
-
if(previous)
|
|
217
|
+
if(previous)throw new EnrollmentWorkflowError(previous.state==='verified'?'verified step changed':'uncertain write requires reconciliation',{step:name});
|
|
170
218
|
record.steps[name]={state:'attempted'};await persist();
|
|
171
|
-
|
|
172
|
-
|
|
219
|
+
let writeError;
|
|
220
|
+
try{await submit(result);}catch(error){writeError=error;}
|
|
221
|
+
// A write response alone never establishes success or absence. Preserve its
|
|
222
|
+
// diagnostic cause in memory while reconciliation remains authoritative.
|
|
223
|
+
try{result=await inspect();}catch(readError){
|
|
224
|
+
if(writeError===undefined)throw readError;
|
|
225
|
+
throw new EnrollmentWorkflowError(readError instanceof EnrollmentWorkflowError?readError.reason:'uncertain write requires reconciliation',{step:name,cause:new AggregateError([writeError,readError],'Write and reconciliation failed')});
|
|
226
|
+
}
|
|
227
|
+
if(!result.found)throw new EnrollmentWorkflowError('uncertain write requires reconciliation',{step:name,...(writeError===undefined?{}:{cause:writeError})});
|
|
173
228
|
record.steps[name]={state:'verified',value:result.value};await persist();return result.value;
|
|
174
229
|
};
|
|
175
230
|
const findEnrollment=async()=>{
|
|
@@ -217,6 +272,12 @@ export function createEnrollmentWorkflow({api,discovery,helpers,store,enrollment
|
|
|
217
272
|
if(plan.scalar.length)await step('scalars',async()=>{
|
|
218
273
|
const source=await read();return {found:plan.scalar.every(q=>{const r=source.find(r=>r.virt_field_name===q.virt_field_name);return r&&sameAnswer(q,r.answer_value)&&restDate(r.date_effective)===restDate(at);}),value:plan.scalar.map(q=>q.virt_field_name)};
|
|
219
274
|
},()=>api.assessmentsMobile.addAnswer({path:{clientId:input.clientId,assessmentCode:code},query:{dateEffective:at},body:plan.scalar}));
|
|
275
|
+
// Standard writes update existing dated rows and change only the answers sent.
|
|
276
|
+
if(plan.yesNo.length){const body=[...plan.yesNo,...mandatory.map(({expected,...q})=>q)],expected=[...plan.yesNo,...mandatory.map(({expected,...q})=>({...q,answer_value:expected}))];
|
|
277
|
+
await step('yesno',async()=>{
|
|
278
|
+
const source=await readSaved();return {found:expected.every(q=>{const r=source.find(r=>r.virt_field_name===q.virt_field_name);return r&&sameAnswer(q,r.answer_value)&&restDate(r.date_effective)===restDate(at);}),value:plan.yesNo.map(q=>q.virt_field_name)};
|
|
279
|
+
},()=>api.assessments.create({path:{clientId:input.clientId,assessmentCode:code},query:{dateEffective:at},body}));
|
|
280
|
+
}
|
|
220
281
|
// Group rows into one creation request. Partial success blocks resubmission until all rows reconcile.
|
|
221
282
|
if(plan.rows.length){const rowIds=await step('rows',async()=>{
|
|
222
283
|
const source=await readCurrent(),matched=Object.create(null),missing=[],matchedIds=new Set();
|
|
@@ -263,7 +324,7 @@ export function createEnrollmentWorkflow({api,discovery,helpers,store,enrollment
|
|
|
263
324
|
for(const member of input.members){fields(member,['clientId','assessment']);if(!positive(member.clientId)||!object(member.assessment))fail('member client and assessment required');}
|
|
264
325
|
input.members.sort((a,b)=>a.clientId-b.clientId);const ids=input.members.map(m=>m.clientId);
|
|
265
326
|
if(new Set(ids).size!==ids.length||kind==='entry'&&!ids.includes(input.headClientId))fail('unique members including head required');
|
|
266
|
-
if(kind==='entry'){if(!positive(input.householdId)||!positive(input.providerId)||!
|
|
327
|
+
if(kind==='entry'){if(!positive(input.householdId)||!positive(input.providerId)||!entryExitTypes.includes(input.type))fail('household, program and supported Entry/Exit type required');input.entryDate=date(input.entryDate);}
|
|
267
328
|
else{key(input.enrollmentKey);if(kind==='addition')input.entryDate=date(input.entryDate);else if(kind==='exit')input.exitDate=date(input.exitDate);else input.reviewDate=date(input.reviewDate);}
|
|
268
329
|
// Read the cohort under its journal lock, then acquire all client locks in order.
|
|
269
330
|
// Recheck under both locks so concurrent membership growth cannot escape protection.
|
package/browser/index.d.mts
CHANGED
|
@@ -73,6 +73,7 @@ export * from './shelters.mjs';
|
|
|
73
73
|
export * from './shelter-inventory.mjs';
|
|
74
74
|
|
|
75
75
|
export * from './current-living-situation.mjs';
|
|
76
|
+
export * from './coordinated-entry-event.mjs';
|
|
76
77
|
|
|
77
78
|
export {resolveUiConnection} from './connection.mjs';
|
|
78
79
|
export type {UiConnection,UiConnectionOptions} from './connection.mjs';
|
package/browser/index.mjs
CHANGED
|
@@ -42,5 +42,6 @@ export {createShelterUi} from './shelter-ui.mjs';
|
|
|
42
42
|
export {createShelterInventory, ShelterInventoryError} from './shelter-inventory.mjs';
|
|
43
43
|
|
|
44
44
|
export * from './current-living-situation.mjs';
|
|
45
|
+
export * from './coordinated-entry-event.mjs';
|
|
45
46
|
|
|
46
47
|
export {resolveUiConnection} from './connection.mjs';
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
// Internal: shared journal, snapshot and reconciliation flow for recorders that add one
|
|
2
|
+
// subassessment row per upstream event key. Not a public entry point.
|
|
3
|
+
import {apiScope} from './connection.mjs';
|
|
4
|
+
import {toItems, semanticHash} from '../dist/esm/index.js';
|
|
5
|
+
|
|
6
|
+
export const object = value => value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
7
|
+
export const positive = value => Number.isSafeInteger(value) && value > 0;
|
|
8
|
+
export function nonempty(value) { return typeof value === 'string' && value.trim().length > 0 && value.length <= 200; }
|
|
9
|
+
|
|
10
|
+
/** Shape check for a recorder journal, including an optional in-place row update. */
|
|
11
|
+
export function checkJournal(entries, fail) {
|
|
12
|
+
const update = u => u === undefined || object(u) && ['attempted', 'verified'].includes(u.stage) && typeof u.intentHash === 'string' && (u.stage === 'attempted') === Array.isArray(u.before);
|
|
13
|
+
if (!Array.isArray(entries) || new Set(entries.map(e => e?.key)).size !== entries.length || entries.some(e => !object(e) || e.version !== 1 || !nonempty(e.key) || !['attempted', 'verified'].includes(e.stage) || typeof e.intentHash !== 'string' || !Array.isArray(e.baseline) || e.stage === 'verified' && !positive(e.recordsetId) || !update(e.update))) fail('invalid-journal');
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function rowHelpers(fail) {
|
|
17
|
+
function instant(value, stored = false) {
|
|
18
|
+
if (typeof value !== 'string') fail('invalid-date');
|
|
19
|
+
// Enrollment/assessment reads emit UTC without a suffix or with a numeric hour offset.
|
|
20
|
+
const text = stored ? value.replace(' ', 'T').replace(/([+-]\d\d)$/, '$1:00') + (/(?:Z|[+-]\d\d(?::\d\d)?)$/.test(value) ? '' : 'Z') : value;
|
|
21
|
+
if (!/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.000)?(?:Z|[+-]\d{2}:\d{2})$/.test(text) || !Number.isFinite(Date.parse(text)) || new Date(text.slice(0, 19) + 'Z').toISOString().slice(0, 19) !== text.slice(0, 19)) fail('invalid-date');
|
|
22
|
+
return new Date(text).toISOString();
|
|
23
|
+
}
|
|
24
|
+
function exactFields(value, allowed) {
|
|
25
|
+
if (!object(value) || Object.keys(value).some(key => !allowed.includes(key))) fail('invalid-input');
|
|
26
|
+
}
|
|
27
|
+
function valueOf(question) {
|
|
28
|
+
if (question.answer_value === null || question.answer_value === undefined || question.answer_value === '') return null;
|
|
29
|
+
if (question.question_type === 'date') return instant(question.answer_value, true);
|
|
30
|
+
if (typeof question.answer_value !== 'string') fail('invalid-answer-read');
|
|
31
|
+
return question.answer_value;
|
|
32
|
+
}
|
|
33
|
+
/** Every non-label child of the mapped parent, by field name, or a conflict. */
|
|
34
|
+
function childIndex(definition, assessmentCode, parentField, tenant) {
|
|
35
|
+
if (definition?.tenant !== tenant || definition.assessmentCode !== assessmentCode || !Array.isArray(definition.questions)) fail('invalid-definition');
|
|
36
|
+
const parents = definition.questions.filter(q => q.fieldName === parentField && q.questionType === 'sub_assessment');
|
|
37
|
+
if (parents.length !== 1 || !positive(parents[0].questionId) || !Array.isArray(parents[0].children)) fail('parent-unavailable');
|
|
38
|
+
const parent = parents[0], index = new Map();
|
|
39
|
+
for (const q of parent.children) {
|
|
40
|
+
if (['label', 'blank'].includes(q.questionType)) continue;
|
|
41
|
+
if (!nonempty(q.fieldName) || !positive(q.questionId) || index.has(q.fieldName)) fail('ambiguous-definition');
|
|
42
|
+
index.set(q.fieldName, q);
|
|
43
|
+
}
|
|
44
|
+
return {parent, index};
|
|
45
|
+
}
|
|
46
|
+
return {instant, exactFields, valueOf, childIndex};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* kind: journal scope name; noun: used in event-specific conflict reasons; dateKey: the input's
|
|
51
|
+
* event instant. compile(definition, input, enrollment) returns {expected, empty, intent, body}:
|
|
52
|
+
* answers that must read back, fields that must read back empty, extra intent-hash content and
|
|
53
|
+
* the write request. write(input, body) sends it once.
|
|
54
|
+
*/
|
|
55
|
+
export function createRowRecorder({api, store, fail, kind, noun, dateKey, parentField, normalize, compile, write}) {
|
|
56
|
+
const tenantScope = apiScope(api);
|
|
57
|
+
const {instant, valueOf} = rowHelpers(fail);
|
|
58
|
+
async function readEnrollment(input) {
|
|
59
|
+
const rows = [], ids = new Set(); let total;
|
|
60
|
+
for (let page = 1; page <= 100; page++) {
|
|
61
|
+
const response = await api.enrollments.listForClient({path: {clientId: input.clientId}, query: {perPage: 100, startPage: page, total_count: true}});
|
|
62
|
+
if (!Number.isSafeInteger(response?.count) || response.count < 0 || !Array.isArray(response.values) || total !== undefined && total !== response.count) fail('enrollment-count-unavailable');
|
|
63
|
+
total = response.count;
|
|
64
|
+
for (const row of response.values) {
|
|
65
|
+
if (!object(row) || !positive(row.enrollmentId) || row.clientId !== input.clientId || ids.has(row.enrollmentId)) fail('invalid-enrollment-read');
|
|
66
|
+
ids.add(row.enrollmentId); rows.push(row);
|
|
67
|
+
}
|
|
68
|
+
if (rows.length === total) {
|
|
69
|
+
const row = rows.find(row => row.enrollmentId === input.enrollmentId);
|
|
70
|
+
if (!row || row.isActive !== true || !positive(row.enrollmentProvider)) fail('enrollment-unavailable');
|
|
71
|
+
const entryDate = instant(row.projectStartDate, true);
|
|
72
|
+
if (input[dateKey] < entryDate || row.projectExitDate && input[dateKey] > instant(row.projectExitDate, true)) fail(`${noun}-outside-enrollment`);
|
|
73
|
+
return {entryDate, providerId: row.enrollmentProvider};
|
|
74
|
+
}
|
|
75
|
+
if (rows.length > total || !response.values.length) fail('incomplete-enrollment-read');
|
|
76
|
+
}
|
|
77
|
+
fail('enrollment-page-limit');
|
|
78
|
+
}
|
|
79
|
+
async function readRows(input, instant = input[dateKey]) {
|
|
80
|
+
// An undated read omits rows dated after the server's current time, and a read at exactly
|
|
81
|
+
// a row's instant omits its yes/no answers. Read one second after the later of the two.
|
|
82
|
+
const at = new Date(Math.max(Date.now(), Date.parse(instant)) + 1000).toISOString().slice(0, 19) + 'Z';
|
|
83
|
+
const response = await api.assessments.get({path: {clientId: input.clientId, assessmentCode: input.assessmentCode}, query: {dateEffective: at}});
|
|
84
|
+
const questions = toItems(response);
|
|
85
|
+
if (!Array.isArray(questions) || object(response) && 'count' in response && response.count !== questions.length) fail('incomplete-assessment-read');
|
|
86
|
+
const parents = questions.filter(q => q?.virt_field_name === parentField && q.question_type === 'sub_assessment');
|
|
87
|
+
if (parents.length !== 1 || !Array.isArray(parents[0].sub_assessment_answer_list)) fail('rows-unavailable');
|
|
88
|
+
const rows = parents[0].sub_assessment_answer_list, ids = new Set();
|
|
89
|
+
if (rows.length > 10000) fail('row-limit');
|
|
90
|
+
return rows.map(row => {
|
|
91
|
+
if (!positive(row.recordset_id) || ids.has(row.recordset_id) || !Array.isArray(row.sub_assessment_list)) fail('ambiguous-row-read');
|
|
92
|
+
ids.add(row.recordset_id);
|
|
93
|
+
const fields = {};
|
|
94
|
+
for (const q of row.sub_assessment_list) {
|
|
95
|
+
if (['label', 'blank'].includes(q.question_type)) continue;
|
|
96
|
+
if (!nonempty(q.virt_field_name) || Object.hasOwn(fields, q.virt_field_name) || typeof q.question_type !== 'string') fail('ambiguous-answer-read');
|
|
97
|
+
Object.defineProperty(fields, q.virt_field_name, {value: {type: q.question_type, value: valueOf(q)}, enumerable: true});
|
|
98
|
+
}
|
|
99
|
+
return {id: row.recordset_id, fields};
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
const answered = (row, {expected}) => expected.every(q => row.fields[q.virt_field_name]?.type === q.question_type && row.fields[q.virt_field_name]?.value === valueOf(q));
|
|
103
|
+
// `empty` fields must be empty only on the new row; a later end date does not undo the event.
|
|
104
|
+
const matches = (row, compiled) => compiled.empty.every(field => (row.fields[field]?.value ?? null) === null) && answered(row, compiled);
|
|
105
|
+
|
|
106
|
+
const scopeOf = clientId => JSON.stringify([tenantScope, kind, clientId]);
|
|
107
|
+
return {readRows, scopeOf, async record(raw) {
|
|
108
|
+
const input = normalize(raw), scope = scopeOf(input.clientId);
|
|
109
|
+
return store.withLock(scope, async () => {
|
|
110
|
+
const entries = await store.read(scope);
|
|
111
|
+
checkJournal(entries, fail);
|
|
112
|
+
let entry = entries.find(e => e.key === input.key);
|
|
113
|
+
// A pending in-place update of an earlier row is unfinished work too.
|
|
114
|
+
if (entries.some(e => (e.stage === 'attempted' || e.update?.stage === 'attempted') && e.key !== input.key)) fail(`unfinished-${noun}`);
|
|
115
|
+
const enrollment = await readEnrollment(input);
|
|
116
|
+
const definition = await api.assessments.getDefinition({clientId: input.clientId, assessmentCode: input.assessmentCode, effectiveDate: input[dateKey], refresh: true});
|
|
117
|
+
const compiled = compile(definition, input, enrollment);
|
|
118
|
+
const intentHash = await semanticHash({input, enrollment, ...compiled.intent});
|
|
119
|
+
if (entry && entry.intentHash !== intentHash) fail('intent-or-schema-changed');
|
|
120
|
+
let rows = await readRows(input);
|
|
121
|
+
const result = (row, outcome) => ({key: input.key, clientId: input.clientId, enrollmentId: input.enrollmentId, recordsetId: row.id, startDate: enrollment.entryDate, endDate: null, [dateKey]: input[dateKey], outcome});
|
|
122
|
+
if (entry?.stage === 'verified') {
|
|
123
|
+
const row = rows.find(row => row.id === entry.recordsetId);
|
|
124
|
+
if (!row || !answered(row, compiled)) fail(`verified-${noun}-changed`);
|
|
125
|
+
return result(row, 'already-present');
|
|
126
|
+
}
|
|
127
|
+
const reconcile = async () => {
|
|
128
|
+
for (const before of entry.baseline) {
|
|
129
|
+
const after = rows.find(row => row.id === before.id);
|
|
130
|
+
if (!after || await semanticHash(after) !== await semanticHash(before)) fail(`existing-${noun}-changed`);
|
|
131
|
+
}
|
|
132
|
+
const added = rows.filter(row => !entry.baseline.some(before => before.id === row.id));
|
|
133
|
+
if (added.length !== 1 || !matches(added[0], compiled)) fail(`uncertain-${noun}-save`);
|
|
134
|
+
return added[0];
|
|
135
|
+
};
|
|
136
|
+
if (entry) {
|
|
137
|
+
const row = await reconcile();
|
|
138
|
+
entry.stage = 'verified'; entry.recordsetId = row.id;
|
|
139
|
+
await store.write(scope, structuredClone(entries));
|
|
140
|
+
return result(row, 'reconciled');
|
|
141
|
+
}
|
|
142
|
+
entry = {version: 1, key: input.key, intentHash, stage: 'attempted', baseline: rows};
|
|
143
|
+
entries.push(entry);
|
|
144
|
+
await store.write(scope, structuredClone(entries));
|
|
145
|
+
let failed = false;
|
|
146
|
+
try { await write(input, compiled.body); } catch { failed = true; }
|
|
147
|
+
rows = await readRows(input);
|
|
148
|
+
const row = await reconcile();
|
|
149
|
+
entry.stage = 'verified'; entry.recordsetId = row.id;
|
|
150
|
+
await store.write(scope, structuredClone(entries));
|
|
151
|
+
return result(row, failed ? 'reconciled' : 'verified');
|
|
152
|
+
});
|
|
153
|
+
}};
|
|
154
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"encoding.d.ts","sourceRoot":"","sources":["../../src/encoding.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAK1F,MAAM,MAAM,WAAW,GAAG,oBAAoB,GAAG,gBAAgB,GAAG,oBAAoB,CAAC;AACzF,MAAM,MAAM,WAAW,GAAG;IAAE,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,EAAE,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,WAAW,CAAA;CAAE,GAAG;IAAE,MAAM,EAAE,gBAAgB,CAAA;CAAE,GAAG;IAAE,OAAO,EAAE,SAAS,gBAAgB,EAAE,CAAA;CAAE,CAAC;AAC7K,MAAM,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;AAClD,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,YAAY,GAAG,YAAY,GAAG,QAAQ,CAAC;IACjD,0GAA0G;IAC1G,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,kBAAkB,EAAE,MAAM,EAAE,cAAc,KAAK,MAAM,GAAG,SAAS,CAAC;IAC1F,wGAAwG;IACxG,UAAU,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC,CAAC,CAAC;IAC7D,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,kBAAkB,EAAE,MAAM,EAAE,SAAS,MAAM,EAAE,KAAK,MAAM,CAAC;CAClF;AACD,MAAM,WAAW,eAAe;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;CACtB;AA2DD,wBAAgB,aAAa,CAAC,SAAS,EAAE,SAAS,kBAAkB,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,eAAe,GAAG,eAAe,EAAE,CAgBrI;AAED,iFAAiF;AACjF,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,kBAAkB,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,eAAe,GAAG;IAAE,cAAc,EAAE,eAAe,EAAE,CAAA;CAAE,
|
|
1
|
+
{"version":3,"file":"encoding.d.ts","sourceRoot":"","sources":["../../src/encoding.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAK1F,MAAM,MAAM,WAAW,GAAG,oBAAoB,GAAG,gBAAgB,GAAG,oBAAoB,CAAC;AACzF,MAAM,MAAM,WAAW,GAAG;IAAE,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,EAAE,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,WAAW,CAAA;CAAE,GAAG;IAAE,MAAM,EAAE,gBAAgB,CAAA;CAAE,GAAG;IAAE,OAAO,EAAE,SAAS,gBAAgB,EAAE,CAAA;CAAE,CAAC;AAC7K,MAAM,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;AAClD,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,YAAY,GAAG,YAAY,GAAG,QAAQ,CAAC;IACjD,0GAA0G;IAC1G,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,kBAAkB,EAAE,MAAM,EAAE,cAAc,KAAK,MAAM,GAAG,SAAS,CAAC;IAC1F,wGAAwG;IACxG,UAAU,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC,CAAC,CAAC;IAC7D,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,kBAAkB,EAAE,MAAM,EAAE,SAAS,MAAM,EAAE,KAAK,MAAM,CAAC;CAClF;AACD,MAAM,WAAW,eAAe;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;CACtB;AA2DD,wBAAgB,aAAa,CAAC,SAAS,EAAE,SAAS,kBAAkB,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,eAAe,GAAG,eAAe,EAAE,CAgBrI;AAED,iFAAiF;AACjF,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,kBAAkB,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,eAAe,GAAG;IAAE,cAAc,EAAE,eAAe,EAAE,CAAA;CAAE,CAWvJ"}
|
package/dist/cjs/encoding.js
CHANGED
|
@@ -110,10 +110,11 @@ function encodeNewSubassessmentRow(parent, answers, options) {
|
|
|
110
110
|
const encoded = encodeAnswers(parent.children, answers, options);
|
|
111
111
|
const included = new Set(encoded.map(q => q.virt_field_name));
|
|
112
112
|
for (const question of parent.children) {
|
|
113
|
+
// An unanswered provider child is omitted; answered ones are still refused for mobile in encodeValue.
|
|
113
114
|
if (!question.fieldName || included.has(question.fieldName) || ["label", "blank", "yes_no"].includes(question.questionType))
|
|
114
115
|
continue;
|
|
115
116
|
if (question.questionType === "provider" && options.endpoint === "mobile")
|
|
116
|
-
|
|
117
|
+
continue;
|
|
117
118
|
encoded.push({ question_id: question.questionId, question_type: question.questionType, virt_field_name: question.fieldName, answer_value: "" });
|
|
118
119
|
}
|
|
119
120
|
return { subAssessments: encoded };
|
package/dist/cjs/encoding.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"encoding.js","sourceRoot":"","sources":["../../src/encoding.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\";\nimport { resolveRaceCombination } from \"./race.js\";\n\nexport type AnswerState = \"client_doesnt_know\" | \"client_refused\" | \"data_not_collected\";\nexport type AnswerValue = { value: string | number | boolean | string[] } | { state: AnswerState } | { option: PicklistSelector } | { options: readonly PicklistSelector[] };\nexport type Answers = Record<string, AnswerValue>;\nexport interface EncodingOptions {\n endpoint: \"standalone\" | \"enrollment\" | \"mobile\";\n /** Tenant-verified display labels, including exact whitespace/HUD suffixes, for label-based endpoints. */\n writeLabel?: (question: QuestionDefinition, option: PicklistOption) => string | undefined;\n /** Application configuration supplies the relevant option codes. No answer-state labels are guessed. */\n stateCodes?: Partial<Record<AnswerState, readonly string[]>>;\n multiValue?: (question: QuestionDefinition, values: readonly string[]) => string;\n}\nexport interface EncodedQuestion {\n question_id: number;\n question_type: string;\n virt_field_name: string;\n answer_value: string;\n}\n\nfunction encodeValue(question: QuestionDefinition, answer: AnswerValue, options: EncodingOptions): string | undefined {\n const field = question.fieldName ?? `#${question.questionId}`;\n if ([\"label\", \"blank\", \"sub_assessment\"].includes(question.questionType)) throw new ValidationError(\"assessment encoding\", [field]);\n if (question.questionType === \"provider\" && options.endpoint === \"mobile\") throw new ValidationError(\"mobile provider answers are unsupported\", [field]);\n if (\"state\" in answer) {\n if (question.questionType !== \"lookup\") return undefined;\n const codes = options.stateCodes?.[answer.state];\n if (!codes) throw new ValidationError(\"answer-state code configuration required\", [field]);\n const found = question.options.filter(option => option.code !== null && codes.includes(option.code));\n if (!found.length) return undefined;\n if (found.length !== 1 || !found[0]) throw new ValidationError(\"ambiguous answer-state option\", [field]);\n const option = question.fieldName === \"HUD_RACEETHNICITY\" && found[0].code !== null\n ? resolveRaceCombination(question, [{ code: found[0].code }]) : found[0];\n return lookupLabel(question, option, options);\n }\n if (question.questionType === \"lookup\") {\n if (question.fieldName === \"HUD_RACEETHNICITY\") {\n const selectors = \"options\" in answer ? answer.options : \"option\" in answer ? [answer.option]\n : typeof answer.value === \"string\" ? [{ name: answer.value }]\n : Array.isArray(answer.value) ? answer.value.map(name => ({ name })) : undefined;\n if (!selectors) throw new ValidationError(\"race requires category selectors\", [field]);\n return lookupLabel(question, resolveRaceCombination(question, selectors), options);\n }\n if (\"options\" in answer) throw new ValidationError(\"multiple options require a supported combination field\", [field]);\n if (\"option\" in answer) return lookupLabel(question, resolvePicklistOption(question, answer.option), options);\n if (typeof answer.value !== \"string\") throw new ValidationError(\"lookup requires a code or name selector\", [field]);\n return lookupLabel(question, resolvePicklistOption(question, { name: answer.value }), options);\n }\n if (!(\"value\" in answer)) throw new ValidationError(\"picklist selector on a non-lookup question\", [field]);\n const value = answer.value;\n if (Array.isArray(value)) {\n if (!options.multiValue) throw new ValidationError(\"multi-value encoding requires an explicit encoder\", [field]);\n return options.multiValue(question, value);\n }\n switch (question.questionType) {\n case \"yes_no\":\n if (value === true || value === \"Yes\") return \"Yes\";\n if (value === false || value === \"No\") return \"No\";\n throw new ValidationError(\"yes_no encoding\", [field]);\n case \"int\": case \"provider\":\n if ((typeof value !== \"number\" && typeof value !== \"string\") || value === \"\" || !Number.isSafeInteger(Number(value))) throw new ValidationError(\"integer encoding\", [field]);\n return String(value);\n case \"money\":\n if ((typeof value !== \"number\" && typeof value !== \"string\") || value === \"\" || !Number.isFinite(Number(value))) throw new ValidationError(\"money encoding\", [field]);\n return String(value);\n case \"date\": case \"textbox\": case \"textarea\": return String(value);\n default: throw new ValidationError(\"unsupported question type\", [field]);\n }\n}\n\nfunction lookupLabel(question: QuestionDefinition, option: PicklistOption, options: EncodingOptions): string {\n if (options.endpoint === \"mobile\") return String(option.id);\n const label = options.writeLabel?.(question, option);\n if (!label) throw new ValidationError(\"verified lookup write label required\", [question.fieldName ?? `#${question.questionId}`]);\n return label;\n}\n\nexport function encodeAnswers(questions: readonly QuestionDefinition[], answers: Answers, options: EncodingOptions): EncodedQuestion[] {\n const index = new Map<string, QuestionDefinition>();\n for (const question of questions) if (question.fieldName) {\n if (index.has(question.fieldName)) throw new ValidationError(\"ambiguous question field\", [question.fieldName]);\n index.set(question.fieldName, question);\n }\n const unknown = Object.keys(answers).filter(field => !index.has(field));\n if (unknown.length) throw new ValidationError(\"unknown assessment fields\", unknown);\n const result: EncodedQuestion[] = [];\n for (const [field, answer] of Object.entries(answers)) {\n const question = index.get(field);\n if (!question) throw new ValidationError(\"unknown assessment fields\", [field]);\n const value = encodeValue(question, answer, options);\n if (value !== undefined) result.push({ question_id: question.questionId, question_type: question.questionType, virt_field_name: field, answer_value: value });\n }\n return result;\n}\n\n/** Builds one new row only. Never accepts or echoes an existing recordset ID. */\nexport function encodeNewSubassessmentRow(parent: QuestionDefinition, answers: Answers, options: EncodingOptions): { subAssessments: EncodedQuestion[] } {\n if (parent.questionType !== \"sub_assessment\") throw new ValidationError(\"subassessment parent required\");\n const encoded = encodeAnswers(parent.children, answers, options);\n const included = new Set(encoded.map(q => q.virt_field_name));\n for (const question of parent.children) {\n if (!question.fieldName || included.has(question.fieldName) || [\"label\", \"blank\", \"yes_no\"].includes(question.questionType)) continue;\n if (question.questionType === \"provider\" && options.endpoint === \"mobile\") throw new ValidationError(\"mobile provider answers are unsupported\", [question.fieldName]);\n encoded.push({ question_id: question.questionId, question_type: question.questionType, virt_field_name: question.fieldName, answer_value: \"\" });\n }\n return { subAssessments: encoded };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"encoding.js","sourceRoot":"","sources":["../../src/encoding.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\";\nimport { resolveRaceCombination } from \"./race.js\";\n\nexport type AnswerState = \"client_doesnt_know\" | \"client_refused\" | \"data_not_collected\";\nexport type AnswerValue = { value: string | number | boolean | string[] } | { state: AnswerState } | { option: PicklistSelector } | { options: readonly PicklistSelector[] };\nexport type Answers = Record<string, AnswerValue>;\nexport interface EncodingOptions {\n endpoint: \"standalone\" | \"enrollment\" | \"mobile\";\n /** Tenant-verified display labels, including exact whitespace/HUD suffixes, for label-based endpoints. */\n writeLabel?: (question: QuestionDefinition, option: PicklistOption) => string | undefined;\n /** Application configuration supplies the relevant option codes. No answer-state labels are guessed. */\n stateCodes?: Partial<Record<AnswerState, readonly string[]>>;\n multiValue?: (question: QuestionDefinition, values: readonly string[]) => string;\n}\nexport interface EncodedQuestion {\n question_id: number;\n question_type: string;\n virt_field_name: string;\n answer_value: string;\n}\n\nfunction encodeValue(question: QuestionDefinition, answer: AnswerValue, options: EncodingOptions): string | undefined {\n const field = question.fieldName ?? `#${question.questionId}`;\n if ([\"label\", \"blank\", \"sub_assessment\"].includes(question.questionType)) throw new ValidationError(\"assessment encoding\", [field]);\n if (question.questionType === \"provider\" && options.endpoint === \"mobile\") throw new ValidationError(\"mobile provider answers are unsupported\", [field]);\n if (\"state\" in answer) {\n if (question.questionType !== \"lookup\") return undefined;\n const codes = options.stateCodes?.[answer.state];\n if (!codes) throw new ValidationError(\"answer-state code configuration required\", [field]);\n const found = question.options.filter(option => option.code !== null && codes.includes(option.code));\n if (!found.length) return undefined;\n if (found.length !== 1 || !found[0]) throw new ValidationError(\"ambiguous answer-state option\", [field]);\n const option = question.fieldName === \"HUD_RACEETHNICITY\" && found[0].code !== null\n ? resolveRaceCombination(question, [{ code: found[0].code }]) : found[0];\n return lookupLabel(question, option, options);\n }\n if (question.questionType === \"lookup\") {\n if (question.fieldName === \"HUD_RACEETHNICITY\") {\n const selectors = \"options\" in answer ? answer.options : \"option\" in answer ? [answer.option]\n : typeof answer.value === \"string\" ? [{ name: answer.value }]\n : Array.isArray(answer.value) ? answer.value.map(name => ({ name })) : undefined;\n if (!selectors) throw new ValidationError(\"race requires category selectors\", [field]);\n return lookupLabel(question, resolveRaceCombination(question, selectors), options);\n }\n if (\"options\" in answer) throw new ValidationError(\"multiple options require a supported combination field\", [field]);\n if (\"option\" in answer) return lookupLabel(question, resolvePicklistOption(question, answer.option), options);\n if (typeof answer.value !== \"string\") throw new ValidationError(\"lookup requires a code or name selector\", [field]);\n return lookupLabel(question, resolvePicklistOption(question, { name: answer.value }), options);\n }\n if (!(\"value\" in answer)) throw new ValidationError(\"picklist selector on a non-lookup question\", [field]);\n const value = answer.value;\n if (Array.isArray(value)) {\n if (!options.multiValue) throw new ValidationError(\"multi-value encoding requires an explicit encoder\", [field]);\n return options.multiValue(question, value);\n }\n switch (question.questionType) {\n case \"yes_no\":\n if (value === true || value === \"Yes\") return \"Yes\";\n if (value === false || value === \"No\") return \"No\";\n throw new ValidationError(\"yes_no encoding\", [field]);\n case \"int\": case \"provider\":\n if ((typeof value !== \"number\" && typeof value !== \"string\") || value === \"\" || !Number.isSafeInteger(Number(value))) throw new ValidationError(\"integer encoding\", [field]);\n return String(value);\n case \"money\":\n if ((typeof value !== \"number\" && typeof value !== \"string\") || value === \"\" || !Number.isFinite(Number(value))) throw new ValidationError(\"money encoding\", [field]);\n return String(value);\n case \"date\": case \"textbox\": case \"textarea\": return String(value);\n default: throw new ValidationError(\"unsupported question type\", [field]);\n }\n}\n\nfunction lookupLabel(question: QuestionDefinition, option: PicklistOption, options: EncodingOptions): string {\n if (options.endpoint === \"mobile\") return String(option.id);\n const label = options.writeLabel?.(question, option);\n if (!label) throw new ValidationError(\"verified lookup write label required\", [question.fieldName ?? `#${question.questionId}`]);\n return label;\n}\n\nexport function encodeAnswers(questions: readonly QuestionDefinition[], answers: Answers, options: EncodingOptions): EncodedQuestion[] {\n const index = new Map<string, QuestionDefinition>();\n for (const question of questions) if (question.fieldName) {\n if (index.has(question.fieldName)) throw new ValidationError(\"ambiguous question field\", [question.fieldName]);\n index.set(question.fieldName, question);\n }\n const unknown = Object.keys(answers).filter(field => !index.has(field));\n if (unknown.length) throw new ValidationError(\"unknown assessment fields\", unknown);\n const result: EncodedQuestion[] = [];\n for (const [field, answer] of Object.entries(answers)) {\n const question = index.get(field);\n if (!question) throw new ValidationError(\"unknown assessment fields\", [field]);\n const value = encodeValue(question, answer, options);\n if (value !== undefined) result.push({ question_id: question.questionId, question_type: question.questionType, virt_field_name: field, answer_value: value });\n }\n return result;\n}\n\n/** Builds one new row only. Never accepts or echoes an existing recordset ID. */\nexport function encodeNewSubassessmentRow(parent: QuestionDefinition, answers: Answers, options: EncodingOptions): { subAssessments: EncodedQuestion[] } {\n if (parent.questionType !== \"sub_assessment\") throw new ValidationError(\"subassessment parent required\");\n const encoded = encodeAnswers(parent.children, answers, options);\n const included = new Set(encoded.map(q => q.virt_field_name));\n for (const question of parent.children) {\n // An unanswered provider child is omitted; answered ones are still refused for mobile in encodeValue.\n if (!question.fieldName || included.has(question.fieldName) || [\"label\", \"blank\", \"yes_no\"].includes(question.questionType)) continue;\n if (question.questionType === \"provider\" && options.endpoint === \"mobile\") continue;\n encoded.push({ question_id: question.questionId, question_type: question.questionType, virt_field_name: question.fieldName, answer_value: \"\" });\n }\n return { subAssessments: encoded };\n}\n"]}
|
package/dist/cjs/errors.d.ts
CHANGED
|
@@ -17,7 +17,10 @@ export declare class ValidationError extends WellSkyError {
|
|
|
17
17
|
constructor(operation: string, fields?: readonly string[]);
|
|
18
18
|
}
|
|
19
19
|
export declare class UpstreamError extends WellSkyError {
|
|
20
|
-
|
|
20
|
+
/** Opt-in private diagnostics; non-enumerable and absent by default. */
|
|
21
|
+
readonly responseBody?: string;
|
|
22
|
+
readonly responseBodyTruncated?: boolean;
|
|
23
|
+
constructor(operation: string, status: number, requestId?: string, retryAfterMs?: number, responseBody?: string);
|
|
21
24
|
}
|
|
22
25
|
export declare class AmbiguousCommitError extends WellSkyError {
|
|
23
26
|
constructor(operation: string);
|
package/dist/cjs/errors.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE5C,qBAAa,mBAAoB,SAAQ,YAAY;gBACvC,SAAS,EAAE,MAAM;CAC9B;AACD,qBAAa,SAAU,SAAQ,YAAY;gBAC7B,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM;CAC/C;AACD,qBAAa,cAAe,SAAQ,YAAY;gBAClC,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,SAAM,EAAE,SAAS,CAAC,EAAE,MAAM;CACtF;AACD,qBAAa,aAAc,SAAQ,YAAY;IAC7C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;gBACX,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM;CAC7C;AACD,qBAAa,eAAgB,SAAQ,YAAY;IAC/C,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;gBACvB,SAAS,EAAE,MAAM,EAAE,MAAM,GAAE,SAAS,MAAM,EAAO;CAC9D;AACD,qBAAa,aAAc,SAAQ,YAAY;
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE5C,qBAAa,mBAAoB,SAAQ,YAAY;gBACvC,SAAS,EAAE,MAAM;CAC9B;AACD,qBAAa,SAAU,SAAQ,YAAY;gBAC7B,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM;CAC/C;AACD,qBAAa,cAAe,SAAQ,YAAY;gBAClC,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,SAAM,EAAE,SAAS,CAAC,EAAE,MAAM;CACtF;AACD,qBAAa,aAAc,SAAQ,YAAY;IAC7C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;gBACX,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM;CAC7C;AACD,qBAAa,eAAgB,SAAQ,YAAY;IAC/C,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;gBACvB,SAAS,EAAE,MAAM,EAAE,MAAM,GAAE,SAAS,MAAM,EAAO;CAC9D;AACD,qBAAa,aAAc,SAAQ,YAAY;IAC7C,wEAAwE;IACxE,SAAiB,YAAY,CAAC,EAAE,MAAM,CAAC;IACvC,SAAiB,qBAAqB,CAAC,EAAE,OAAO,CAAC;gBACrC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM;CAOhH;AACD,qBAAa,oBAAqB,SAAQ,YAAY;gBACxC,SAAS,EAAE,MAAM;CAC9B;AACD,qBAAa,oBAAqB,SAAQ,YAAY;IACpD,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;gBACvB,MAAM,EAAE,SAAS,MAAM,EAAE;CACtC;AACD,qBAAa,yBAA0B,SAAQ,YAAY;IACzD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;gBACX,KAAK,EAAE,MAAM;CAC1B"}
|
package/dist/cjs/errors.js
CHANGED
|
@@ -25,7 +25,15 @@ class ValidationError extends runtime_js_1.WellSkyError {
|
|
|
25
25
|
}
|
|
26
26
|
exports.ValidationError = ValidationError;
|
|
27
27
|
class UpstreamError extends runtime_js_1.WellSkyError {
|
|
28
|
-
constructor(operation, status, requestId, retryAfterMs
|
|
28
|
+
constructor(operation, status, requestId, retryAfterMs, responseBody) {
|
|
29
|
+
super("http", operation, { status, ...(requestId === undefined ? {} : { requestId }), ...(retryAfterMs === undefined ? {} : { retryAfterMs }) });
|
|
30
|
+
this.name = "UpstreamError";
|
|
31
|
+
if (responseBody !== undefined)
|
|
32
|
+
Object.defineProperties(this, {
|
|
33
|
+
responseBody: { value: responseBody.slice(0, 16384), enumerable: false },
|
|
34
|
+
responseBodyTruncated: { value: responseBody.length > 16384, enumerable: false },
|
|
35
|
+
});
|
|
36
|
+
}
|
|
29
37
|
}
|
|
30
38
|
exports.UpstreamError = UpstreamError;
|
|
31
39
|
class AmbiguousCommitError extends runtime_js_1.WellSkyError {
|
package/dist/cjs/errors.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/errors.ts"],"names":[],"mappings":";;;AAAA,6CAA4C;AAE5C,MAAa,mBAAoB,SAAQ,yBAAY;IACnD,YAAY,SAAiB,IAAI,KAAK,CAAC,iBAAiB,EAAE,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAC,CAAC,CAAC;CAC3G;AAFD,kDAEC;AACD,MAAa,SAAU,SAAQ,yBAAY;IACzC,YAAY,SAAiB,EAAE,MAAe,IAAI,KAAK,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,GAAG,WAAW,CAAC,CAAC,CAAC;CAC/I;AAFD,8BAEC;AACD,MAAa,cAAe,SAAQ,yBAAY;IAC9C,YAAY,SAAiB,EAAE,YAAoB,EAAE,MAAM,GAAG,GAAG,EAAE,SAAkB,IAAI,KAAK,CAAC,WAAW,EAAE,SAAS,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,GAAG,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC,CAAC,CAAC;CACrO;AAFD,wCAEC;AACD,MAAa,aAAc,SAAQ,yBAAY;IACpC,KAAK,CAAS;IACvB,YAAY,SAAiB,EAAE,KAAa,IAAI,KAAK,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,GAAG,eAAe,CAAC,CAAC,IAAI,CAAC,KAAK,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;CACzJ;AAHD,sCAGC;AACD,MAAa,eAAgB,SAAQ,yBAAY;IACtC,MAAM,CAAoB;IACnC,YAAY,SAAiB,EAAE,SAA4B,EAAE,IAAI,KAAK,CAAC,YAAY,EAAE,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAC,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;CAC7J;AAHD,0CAGC;AACD,MAAa,aAAc,SAAQ,yBAAY;
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/errors.ts"],"names":[],"mappings":"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","sourcesContent":["import { WellSkyError } from \"./runtime.js\";\n\nexport class TenantMismatchError extends WellSkyError {\n constructor(operation: string) { super(\"tenant_mismatch\", operation); this.name = \"TenantMismatchError\"; }\n}\nexport class AuthError extends WellSkyError {\n constructor(operation: string, status?: number) { super(\"auth\", operation, status === undefined ? {} : { status }); this.name = \"AuthError\"; }\n}\nexport class ThrottledError extends WellSkyError {\n constructor(operation: string, retryAfterMs: number, status = 429, requestId?: string) { super(\"throttled\", operation, { status, retryAfterMs, ...(requestId === undefined ? {} : { requestId }) }); this.name = \"ThrottledError\"; }\n}\nexport class CooldownError extends WellSkyError {\n readonly until: string;\n constructor(operation: string, until: number) { super(\"cooldown\", operation); this.name = \"CooldownError\"; this.until = new Date(until).toISOString(); }\n}\nexport class ValidationError extends WellSkyError {\n readonly fields: readonly string[];\n constructor(operation: string, fields: readonly string[] = []) { super(\"validation\", operation); this.name = \"ValidationError\"; this.fields = [...fields]; }\n}\nexport class UpstreamError extends WellSkyError {\n /** Opt-in private diagnostics; non-enumerable and absent by default. */\n declare readonly responseBody?: string;\n declare readonly responseBodyTruncated?: boolean;\n constructor(operation: string, status: number, requestId?: string, retryAfterMs?: number, responseBody?: string) {\n super(\"http\", operation, { status, ...(requestId === undefined ? {} : { requestId }), ...(retryAfterMs === undefined ? {} : { retryAfterMs }) }); this.name = \"UpstreamError\";\n if (responseBody !== undefined) Object.defineProperties(this, {\n responseBody: { value: responseBody.slice(0, 16384), enumerable: false },\n responseBodyTruncated: { value: responseBody.length > 16384, enumerable: false },\n });\n }\n}\nexport class AmbiguousCommitError extends WellSkyError {\n constructor(operation: string) { super(\"ambiguous_commit\", operation); this.name = \"AmbiguousCommitError\"; }\n}\nexport class DefinitionDriftError extends WellSkyError {\n readonly fields: readonly string[];\n constructor(fields: readonly string[]) { super(\"definition_drift\", \"assessment metadata\"); this.name = \"DefinitionDriftError\"; this.fields = [...fields]; }\n}\nexport class UnknownPicklistValueError extends WellSkyError {\n readonly field: string;\n constructor(field: string) { super(\"unknown_picklist_value\", \"picklist resolution\"); this.name = \"UnknownPicklistValueError\"; this.field = field; }\n}\n"]}
|
package/dist/cjs/runtime.d.ts
CHANGED
|
@@ -33,6 +33,10 @@ export interface ClientOptions {
|
|
|
33
33
|
* Added to the requested instant on POST AddAssessmentAnswer only. No default timezone is assumed.
|
|
34
34
|
* Revalidate against saved effective dates when the server's offset changes. */
|
|
35
35
|
mobileAssessmentDateCorrectionMinutes?: number;
|
|
36
|
+
/** Opt in to retaining up to 16384 characters of an UpstreamError response body.
|
|
37
|
+
* May contain private data. Excluded from JSON serialization and ordinary telemetry.
|
|
38
|
+
* Authentication and throttle error bodies are never retained. */
|
|
39
|
+
captureErrorBody?: boolean;
|
|
36
40
|
/** Defaults to the public production API URL. Supply the target environment explicitly when needed. */
|
|
37
41
|
baseUrl?: string;
|
|
38
42
|
/** Inject a fetch-compatible transport for tests or network routing. */
|
|
@@ -91,7 +95,7 @@ export interface CountedCollection<T> {
|
|
|
91
95
|
export type ApiResponse<T> = T | T[] | ODataCollection<T> | CountedCollection<T> | null;
|
|
92
96
|
export declare function toItems<T>(response: ApiResponse<T>): T[];
|
|
93
97
|
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,
|
|
98
|
+
/** Deliberately contains no credentials, query values, or client IDs, and no response body unless `captureErrorBody` is enabled (then non-enumerable). */
|
|
95
99
|
export declare class WellSkyError extends Error {
|
|
96
100
|
readonly kind: ErrorKind;
|
|
97
101
|
readonly status: number | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../src/runtime.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../src/runtime.ts"],"names":[],"mappings":"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"}
|
package/dist/cjs/runtime.js
CHANGED
|
@@ -16,7 +16,7 @@ function toItems(response) {
|
|
|
16
16
|
// The envelope branch above has been checked at the boundary.
|
|
17
17
|
return [response];
|
|
18
18
|
}
|
|
19
|
-
/** Deliberately contains no credentials, query values,
|
|
19
|
+
/** Deliberately contains no credentials, query values, or client IDs, and no response body unless `captureErrorBody` is enabled (then non-enumerable). */
|
|
20
20
|
class WellSkyError extends Error {
|
|
21
21
|
kind;
|
|
22
22
|
status;
|