@iyulab/lowline-form 0.10.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,7 +1,8 @@
1
1
  # `<lowline-form>`
2
2
 
3
3
  A formdown form whose decided fields are suggested from the records people confirmed, talking to a Lowline host's
4
- routes (`MapLowline` in .NET).
4
+ routes — the contract at the end of this page, which a host implements over the engine (the .NET reference host is
5
+ [`samples/aspnet`](../../samples/aspnet)).
5
6
 
6
7
  ```html
7
8
  <lowline-form src="/lowline" form="intake" record="r-17"></lowline-form>
@@ -43,3 +44,18 @@ npm ci
43
44
  npm test
44
45
  npm run bundle # one file with Lit and formdown inside, in dist/bundle
45
46
  ```
47
+
48
+ ## The routes a host serves
49
+
50
+ Under the prefix the host mounted them at (`src`):
51
+
52
+ | Route | Takes | Answers |
53
+ |---|---|---|
54
+ | `POST {form}/propose` | `{ "id", "values" }` — the record so far | per open decided field: the suggestion, what it rests on, its `promise`, or why there is none |
55
+ | `POST {form}/settle` | `{ "id", "saved", "draft" }` — no `saved` with `Saved` | `{ "id", "settledAt" }`; 400 for a value the form cannot hold, and nothing is learned |
56
+ | `GET {form}/report` | — | per decided field: the thresholds chosen, how many records they were chosen on (`chosenOn`), and what the replay of the records saw at them |
57
+ | `POST {form}/fill` | `{ "values", "text", "attachments" }` — `attachments`, optional: what the person showed, each `{ "mediaType", "data" (base64), "name" }`; `text` may be empty when something is shown | the model's values as suggestions; 400 for data that is not base64; 404 saying so without a model |
58
+ | `POST {form}/judge` | `{ "id", "values" }` | the model's judgements for the fields the records could not answer; 404 saying so without a model |
59
+
60
+ A form not defined is 404. Each request's memory space and allowed choices come from the host, never from the request
61
+ body. The shapes are the engine's own wire shapes: in .NET, `LowlineJson` serializes them.
@@ -31,8 +31,8 @@ var e = class {
31
31
  inBatch(e) {
32
32
  this.batch = e;
33
33
  }
34
- report(e, { layer: t, promise: n }) {
35
- t ? e.layer = t : delete e.layer, n === void 0 ? delete e.promise : e.promise = n;
34
+ report(e, { layer: t, promise: n, score: r }) {
35
+ t ? e.layer = t : delete e.layer, n === void 0 ? delete e.promise : e.promise = n, r === void 0 ? delete e.score : e.score = r;
36
36
  }
37
37
  decline(e) {
38
38
  let t = this.fields[e];
@@ -207,8 +207,12 @@ var l = class extends Error {
207
207
  draft: n
208
208
  });
209
209
  }
210
- fill(e, t, n) {
211
- return this.post(e, "fill", {
210
+ fill(e, t, n, r) {
211
+ return this.post(e, "fill", r?.length ? {
212
+ values: t,
213
+ text: n,
214
+ attachments: r
215
+ } : {
212
216
  values: t,
213
217
  text: n
214
218
  });
@@ -11274,11 +11278,11 @@ var zl = 300, $ = class extends Je {
11274
11278
  composed: !0
11275
11279
  })), n;
11276
11280
  }
11277
- async fill(e) {
11278
- let t = this.session;
11279
- if (!t || !this.form) return;
11280
- let n = await this.client.fill(this.form, this.values(), e);
11281
- t === this.session && (this.fieldStates = t.applyFill(n), this.formdown && (this.formdown.fieldStates = this.fieldStates));
11281
+ async fill(e, t) {
11282
+ let n = this.session;
11283
+ if (!n || !this.form) return;
11284
+ let r = await this.client.fill(this.form, this.values(), e, t);
11285
+ n === this.session && (this.fieldStates = n.applyFill(r), this.formdown && (this.formdown.fieldStates = this.fieldStates));
11282
11286
  }
11283
11287
  async ask() {
11284
11288
  let e = this.session;
package/dist/client.d.ts CHANGED
@@ -5,6 +5,14 @@ export declare class LowlineError extends Error {
5
5
  readonly status: number;
6
6
  constructor(status: number, message: string);
7
7
  }
8
+ /** Something a person showed rather than wrote — a photo, a scan — sent to the host's model with a fill request. */
9
+ export interface Attachment {
10
+ /** Its media type, such as `image/jpeg` or `application/pdf`. */
11
+ mediaType: string;
12
+ /** Its bytes, base64. */
13
+ data: string;
14
+ name?: string;
15
+ }
8
16
  /** A threshold chosen on a replay of the settled records, and what the replay saw at it. */
9
17
  export interface ThresholdChoice {
10
18
  threshold: number;
@@ -43,6 +51,12 @@ export interface FieldReport {
43
51
  coarseSimilar?: ThresholdChoice;
44
52
  similar?: ThresholdChoice;
45
53
  similarOffered: boolean;
54
+ /**
55
+ * For a judgement from outside the records: the score from which it is trusted, chosen from the cases it answered and
56
+ * people settled (its `promise` is the precision to expect of the next answers at or above it); absent while too few
57
+ * cases are settled for one to stand.
58
+ */
59
+ judgement?: ThresholdChoice;
46
60
  promiseOver: number;
47
61
  /** How many checks — answers held back while a person wrote the value — are among the records. */
48
62
  checks: number;
@@ -68,8 +82,11 @@ export declare class LowlineClient {
68
82
  id: string;
69
83
  settledAt: string;
70
84
  }>;
71
- /** What the host's model makes of `text` for the fields of record values still empty — 404 when the host gave none. */
72
- fill(form: string, values: Values, text: string): Promise<Proposal[]>;
85
+ /**
86
+ * What the host's model makes of `text` and of what the person showed (`attachments`) for the fields of record values
87
+ * still empty — 404 when the host gave no model.
88
+ */
89
+ fill(form: string, values: Values, text: string, attachments?: Attachment[]): Promise<Proposal[]>;
73
90
  /**
74
91
  * What the host's model judged for the decided fields of record `id` the records could not answer
75
92
  * (`needs-judgement`) — 404 when the host gave no model.
package/dist/client.js CHANGED
@@ -27,9 +27,12 @@ export class LowlineClient {
27
27
  settle(form, id, draft, saved) {
28
28
  return this.post(form, 'settle', { id, saved, draft });
29
29
  }
30
- /** What the host's model makes of `text` for the fields of record values still empty — 404 when the host gave none. */
31
- fill(form, values, text) {
32
- return this.post(form, 'fill', { values, text });
30
+ /**
31
+ * What the host's model makes of `text` and of what the person showed (`attachments`) for the fields of record values
32
+ * still empty — 404 when the host gave no model.
33
+ */
34
+ fill(form, values, text, attachments) {
35
+ return this.post(form, 'fill', attachments?.length ? { values, text, attachments } : { values, text });
33
36
  }
34
37
  /**
35
38
  * What the host's model judged for the decided fields of record `id` the records could not answer
package/dist/draft.d.ts CHANGED
@@ -10,10 +10,14 @@ export interface Suggestion {
10
10
  }
11
11
  /** The layer of the decider an answer came from. */
12
12
  export type Layer = 'key' | 'similar' | 'judgement';
13
- /** What the host knows of the answer it shows or holds back, beyond its value: the layer that gave it and what it promised. */
13
+ /**
14
+ * What the host knows of the answer it shows or holds back, beyond its value: the layer that gave it, what it promised,
15
+ * and — for a judgement from outside the records — the score it gave it on its own scale.
16
+ */
14
17
  export interface Reported {
15
18
  layer?: Layer | null;
16
19
  promise?: number;
20
+ score?: number;
17
21
  }
18
22
  interface Track extends Reported {
19
23
  shown?: Suggestion;
@@ -32,7 +36,7 @@ interface Track extends Reported {
32
36
  *
33
37
  * Written as the engine reads it: `{ opened, fields: { field: { shown, declined, held } } }`, and — only what was
34
38
  * reported — `opened_at`, `saved_at` (milliseconds on one steady clock), `arrival` (the fields in the order their values
35
- * arrived), `by` and `batch`, and in a field `layer`, `promise`, `at` and `withheld`.
39
+ * arrived), `by` and `batch`, and in a field `layer`, `promise`, `score`, `at` and `withheld`.
36
40
  */
37
41
  export declare class Draft {
38
42
  readonly opened: Values;
@@ -48,7 +52,7 @@ export declare class Draft {
48
52
  show(field: string, suggestion: Suggestion, reported?: Reported): void;
49
53
  /**
50
54
  * The field's answer is held back for a check, drawn with `probability`: what the person settles is checked.
51
- * `withheld` is the answer not shown, with its layer and promise, for the record to say what was held back.
55
+ * `withheld` is the answer not shown, with its layer, promise and score, for the record to say what was held back.
52
56
  */
53
57
  hold(field: string, probability: number, withheld?: {
54
58
  suggestion: Suggestion;
package/dist/draft.js CHANGED
@@ -6,7 +6,7 @@
6
6
  *
7
7
  * Written as the engine reads it: `{ opened, fields: { field: { shown, declined, held } } }`, and — only what was
8
8
  * reported — `opened_at`, `saved_at` (milliseconds on one steady clock), `arrival` (the fields in the order their values
9
- * arrived), `by` and `batch`, and in a field `layer`, `promise`, `at` and `withheld`.
9
+ * arrived), `by` and `batch`, and in a field `layer`, `promise`, `score`, `at` and `withheld`.
10
10
  */
11
11
  export class Draft {
12
12
  /** A record opened holding `values` — none for a new one. Empty values are left out. */
@@ -27,7 +27,7 @@ export class Draft {
27
27
  }
28
28
  /**
29
29
  * The field's answer is held back for a check, drawn with `probability`: what the person settles is checked.
30
- * `withheld` is the answer not shown, with its layer and promise, for the record to say what was held back.
30
+ * `withheld` is the answer not shown, with its layer, promise and score, for the record to say what was held back.
31
31
  */
32
32
  hold(field, probability, withheld) {
33
33
  if (!(probability > 0 && probability <= 1))
@@ -68,7 +68,7 @@ export class Draft {
68
68
  inBatch(id) {
69
69
  this.batch = id;
70
70
  }
71
- report(track, { layer, promise }) {
71
+ report(track, { layer, promise, score }) {
72
72
  if (layer)
73
73
  track.layer = layer;
74
74
  else
@@ -77,6 +77,10 @@ export class Draft {
77
77
  track.promise = promise;
78
78
  else
79
79
  delete track.promise;
80
+ if (score !== undefined)
81
+ track.score = score;
82
+ else
83
+ delete track.score;
80
84
  }
81
85
  /** The person turned down the suggestion in view; false, changing nothing, when none was shown. */
82
86
  decline(field) {
@@ -1,3 +1,3 @@
1
1
  export { Draft, valuesOf, type Suggestion, type Value, type Values } from './draft.js';
2
2
  export { Session, englishStrings, type Abstain, type Basis, type FieldState, type Proposal, type Round, type Strings } from './session.js';
3
- export { LowlineClient, LowlineError, type FieldReport, type ThresholdChoice } from './client.js';
3
+ export { LowlineClient, LowlineError, type Attachment, type FieldReport, type ThresholdChoice } from './client.js';
@@ -1,5 +1,6 @@
1
1
  import { LitElement } from 'lit';
2
2
  import '@formdown/ui';
3
+ import { type Attachment } from './client.js';
3
4
  import { type Values } from './draft.js';
4
5
  import { type Strings } from './session.js';
5
6
  /**
@@ -61,10 +62,11 @@ export declare class LowlineForm extends LitElement {
61
62
  }>;
62
63
  private settleWith;
63
64
  /**
64
- * Fills the record from `text` — what the person wrote or a picture's description — through the host's model: each
65
- * value it gives is offered in its field for the person to take. Nothing is put in on its own.
65
+ * Fills the record from `text` — what the person wrote — and `attachments` — what they showed: a photo, a scan —
66
+ * through the host's model: each value it gives is offered in its field for the person to take. Nothing is put in
67
+ * on its own.
66
68
  */
67
- fill(text: string): Promise<void>;
69
+ fill(text: string, attachments?: Attachment[]): Promise<void>;
68
70
  /** Asks again what to show for the decided fields still open. */
69
71
  ask(): Promise<void>;
70
72
  /**
@@ -127,14 +127,15 @@ let LowlineForm = class LowlineForm extends LitElement {
127
127
  return saved;
128
128
  }
129
129
  /**
130
- * Fills the record from `text` — what the person wrote or a picture's description — through the host's model: each
131
- * value it gives is offered in its field for the person to take. Nothing is put in on its own.
130
+ * Fills the record from `text` — what the person wrote — and `attachments` — what they showed: a photo, a scan —
131
+ * through the host's model: each value it gives is offered in its field for the person to take. Nothing is put in
132
+ * on its own.
132
133
  */
133
- async fill(text) {
134
+ async fill(text, attachments) {
134
135
  const session = this.session;
135
136
  if (!session || !this.form)
136
137
  return;
137
- const proposals = await this.client.fill(this.form, this.values(), text);
138
+ const proposals = await this.client.fill(this.form, this.values(), text, attachments);
138
139
  if (session !== this.session)
139
140
  return;
140
141
  this.fieldStates = session.applyFill(proposals);
package/dist/session.d.ts CHANGED
@@ -27,10 +27,12 @@ export interface Proposal {
27
27
  together?: string | null;
28
28
  /**
29
29
  * How often an answer of this kind for this field has been right — the replay's precision at the threshold the
30
- * suggestion was held to. Absent with no suggestion, for a judgement or a value from elsewhere, and before thresholds
31
- * were chosen.
30
+ * suggestion was held to. Absent with no suggestion, for a value from elsewhere, for a judgement until the score it
31
+ * is trusted from was chosen from the records, and before thresholds were chosen.
32
32
  */
33
33
  promise?: number;
34
+ /** For a judgement from outside the records: the score it gave the suggestion, on its own scale. The draft keeps it. */
35
+ score?: number;
34
36
  /** Whether the field takes several values: it is settled as a set, which cannot be a check, so none is drawn for it. */
35
37
  several?: boolean;
36
38
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iyulab/lowline-form",
3
- "version": "0.10.0",
3
+ "version": "0.11.0",
4
4
  "description": "The Lowline form element: a formdown form whose decided fields are suggested from the records people confirmed, talking to a Lowline host's routes.",
5
5
  "license": "MIT",
6
6
  "repository": {