@voxendar/shared 0.1.0 → 0.3.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/dist/capture/audio.d.ts +16 -0
- package/dist/capture/audio.d.ts.map +1 -0
- package/dist/capture/audio.js +22 -0
- package/dist/capture/audio.js.map +1 -0
- package/dist/capture/fields.d.ts +87 -0
- package/dist/capture/fields.d.ts.map +1 -0
- package/dist/capture/fields.js +171 -0
- package/dist/capture/fields.js.map +1 -0
- package/dist/constants.d.ts +21 -2
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +34 -2
- package/dist/constants.js.map +1 -1
- package/dist/i18n/templates.d.ts +87 -6
- package/dist/i18n/templates.d.ts.map +1 -1
- package/dist/i18n/templates.js +48 -15
- package/dist/i18n/templates.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/schemas/capture.d.ts +8 -0
- package/dist/schemas/capture.d.ts.map +1 -1
- package/dist/schemas/capture.js +6 -0
- package/dist/schemas/capture.js.map +1 -1
- package/package.json +6 -4
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where a member's raw recording lives (Milestone 1.5).
|
|
3
|
+
*
|
|
4
|
+
* Shared because three places have to agree on the shape and only one of them can be
|
|
5
|
+
* checked at compile time: the app builds the path, `transcribeAndExtract` validates
|
|
6
|
+
* it (`^audio/[^/]+/.+$` and its own `audio/{uid}/` ownership prefix), and
|
|
7
|
+
* `storage.rules` grants clients write access to `audio/{uid}/**` and nothing else. A
|
|
8
|
+
* path that disagrees is a capture that fails after the audio has already been
|
|
9
|
+
* uploaded — the worst moment to find out. `tests/functions/update-capture.test.js`
|
|
10
|
+
* feeds this function's output through the callable's schema so the two cannot drift.
|
|
11
|
+
*
|
|
12
|
+
* The recording is deleted by the backend the moment it has been transcribed, so this
|
|
13
|
+
* is a short-lived object, not storage the member can browse.
|
|
14
|
+
*/
|
|
15
|
+
export declare function rawAudioStoragePath(uid: string, fileName: string): string;
|
|
16
|
+
//# sourceMappingURL=audio.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audio.d.ts","sourceRoot":"","sources":["../../src/capture/audio.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;GAaG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEzE"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.rawAudioStoragePath = rawAudioStoragePath;
|
|
4
|
+
const constants_1 = require("../constants");
|
|
5
|
+
/**
|
|
6
|
+
* Where a member's raw recording lives (Milestone 1.5).
|
|
7
|
+
*
|
|
8
|
+
* Shared because three places have to agree on the shape and only one of them can be
|
|
9
|
+
* checked at compile time: the app builds the path, `transcribeAndExtract` validates
|
|
10
|
+
* it (`^audio/[^/]+/.+$` and its own `audio/{uid}/` ownership prefix), and
|
|
11
|
+
* `storage.rules` grants clients write access to `audio/{uid}/**` and nothing else. A
|
|
12
|
+
* path that disagrees is a capture that fails after the audio has already been
|
|
13
|
+
* uploaded — the worst moment to find out. `tests/functions/update-capture.test.js`
|
|
14
|
+
* feeds this function's output through the callable's schema so the two cannot drift.
|
|
15
|
+
*
|
|
16
|
+
* The recording is deleted by the backend the moment it has been transcribed, so this
|
|
17
|
+
* is a short-lived object, not storage the member can browse.
|
|
18
|
+
*/
|
|
19
|
+
function rawAudioStoragePath(uid, fileName) {
|
|
20
|
+
return `${constants_1.STORAGE_PATHS.rawAudio}/${uid}/${fileName}`;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=audio.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audio.js","sourceRoot":"","sources":["../../src/capture/audio.ts"],"names":[],"mappings":";;AAgBA,kDAEC;AAlBD,4CAA6C;AAE7C;;;;;;;;;;;;;GAaG;AACH,SAAgB,mBAAmB,CAAC,GAAW,EAAE,QAAgB;IAC/D,OAAO,GAAG,yBAAa,CAAC,QAAQ,IAAI,GAAG,IAAI,QAAQ,EAAE,CAAC;AACxD,CAAC"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { EventDraft } from "../schemas/event";
|
|
3
|
+
/**
|
|
4
|
+
* The confirmation card's fields (Milestone 1.5), shared by the app and the backend.
|
|
5
|
+
*
|
|
6
|
+
* Why this lives in `shared` rather than in the app: the card edits a draft that the
|
|
7
|
+
* backend must store, and both sides have to agree on exactly two things — what may
|
|
8
|
+
* be edited, and what "edited" means. The `editedFields` list is the accuracy
|
|
9
|
+
* telemetry behind the confirmation-fatigue risk (README §8), so a field name that
|
|
10
|
+
* one side spells differently from the other silently produces a wrong metric, which
|
|
11
|
+
* is the kind of bug nobody notices until the numbers are used to make a decision.
|
|
12
|
+
*
|
|
13
|
+
* The conversion direction matters too. The draft stores absolute instants
|
|
14
|
+
* (`2026-09-27T15:00:00+08:00`), because that is what Google Calendar needs. A person
|
|
15
|
+
* editing a card thinks in wall clock ("3pm"). `fieldsFromEventDraft` converts one
|
|
16
|
+
* way — and deliberately does **no** timezone arithmetic: it reads the offset that is
|
|
17
|
+
* already in the string, since that offset is the one the backend resolved for that
|
|
18
|
+
* very instant. Rebuilding the instant from edited fields is the backend's job
|
|
19
|
+
* (`functions/src/capture/updateCapture.ts`), where the real IANA database lives.
|
|
20
|
+
*/
|
|
21
|
+
/** Field names the confirmation card may change. Stable strings — they are logged. */
|
|
22
|
+
export declare const CAPTURE_EDITABLE_FIELDS: readonly ["title", "date", "startTime", "endTime", "allDay", "location", "notes"];
|
|
23
|
+
export type CaptureEditableField = (typeof CAPTURE_EDITABLE_FIELDS)[number];
|
|
24
|
+
export declare const EditableCaptureFieldsSchema: z.ZodObject<{
|
|
25
|
+
title: z.ZodString;
|
|
26
|
+
date: z.ZodString;
|
|
27
|
+
startTime: z.ZodNullable<z.ZodString>;
|
|
28
|
+
endTime: z.ZodNullable<z.ZodString>;
|
|
29
|
+
allDay: z.ZodBoolean;
|
|
30
|
+
location: z.ZodNullable<z.ZodString>;
|
|
31
|
+
notes: z.ZodNullable<z.ZodString>;
|
|
32
|
+
}, "strip", z.ZodTypeAny, {
|
|
33
|
+
title: string;
|
|
34
|
+
allDay: boolean;
|
|
35
|
+
location: string | null;
|
|
36
|
+
notes: string | null;
|
|
37
|
+
date: string;
|
|
38
|
+
startTime: string | null;
|
|
39
|
+
endTime: string | null;
|
|
40
|
+
}, {
|
|
41
|
+
title: string;
|
|
42
|
+
allDay: boolean;
|
|
43
|
+
location: string | null;
|
|
44
|
+
notes: string | null;
|
|
45
|
+
date: string;
|
|
46
|
+
startTime: string | null;
|
|
47
|
+
endTime: string | null;
|
|
48
|
+
}>;
|
|
49
|
+
export type EditableCaptureFields = z.infer<typeof EditableCaptureFieldsSchema>;
|
|
50
|
+
/**
|
|
51
|
+
* A draft as the card shows it. `endTime` is null for all-day events — the card has
|
|
52
|
+
* no use for the exclusive next-midnight end, and a person never typed it.
|
|
53
|
+
*/
|
|
54
|
+
export declare function fieldsFromEventDraft(draft: EventDraft): EditableCaptureFields;
|
|
55
|
+
/**
|
|
56
|
+
* Which fields the member actually changed — the telemetry the whole card exists to
|
|
57
|
+
* produce (context.md §9's success signal). Only names from
|
|
58
|
+
* `CAPTURE_EDITABLE_FIELDS` can be returned, and only real differences: a card that
|
|
59
|
+
* was opened and confirmed untouched yields `[]`.
|
|
60
|
+
*
|
|
61
|
+
* The all-day toggle is reported as **one** edit: flipping it clears the start and
|
|
62
|
+
* end times as a consequence, and counting those clearings separately would turn a
|
|
63
|
+
* single tap into three "corrections" in the accuracy metric — the metric exists to
|
|
64
|
+
* measure how often the extractor is wrong, not how many fields a control happens to
|
|
65
|
+
* touch.
|
|
66
|
+
*/
|
|
67
|
+
export declare function editedFieldsBetween(original: EditableCaptureFields, edited: EditableCaptureFields): CaptureEditableField[];
|
|
68
|
+
/** True when the draft carries anything the card should flag in amber. */
|
|
69
|
+
export declare function needsAttention(draft: Pick<EventDraft, "confidence" | "ambiguities">): boolean;
|
|
70
|
+
/**
|
|
71
|
+
* The card's time fields into `HH:MM`, or null when it is not a time at all.
|
|
72
|
+
*
|
|
73
|
+
* People type times the way they say them — "3", "3pm", "3:30 pm", "15.00" — and a
|
|
74
|
+
* card that answers "that is not a time" to "3pm" is a card that makes a member feel
|
|
75
|
+
* stupid for writing what they meant. The LLM's own output is always `HH:MM`; this is
|
|
76
|
+
* for the human editing afterwards.
|
|
77
|
+
*
|
|
78
|
+
* Deliberately narrow about what it will *infer*: a **bare** hour 1–11 becomes PM only
|
|
79
|
+
* when the hour has passed (a person editing a card at 16:00 who types "3" means
|
|
80
|
+
* 15:00, not 03:00), a clock reading ("9:05") is taken exactly as written, and
|
|
81
|
+
* anything else returns null so the card can say so instead of guessing.
|
|
82
|
+
*
|
|
83
|
+
* @param value the raw text from the field
|
|
84
|
+
* @param now used only to choose AM/PM for a bare hour; injectable for tests
|
|
85
|
+
*/
|
|
86
|
+
export declare function normaliseTimeInput(value: string, now?: Date): string | null;
|
|
87
|
+
//# sourceMappingURL=fields.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fields.d.ts","sourceRoot":"","sources":["../../src/capture/fields.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnD;;;;;;;;;;;;;;;;;GAiBG;AAEH,sFAAsF;AACtF,eAAO,MAAM,uBAAuB,mFAQ1B,CAAC;AAEX,MAAM,MAAM,oBAAoB,GAAG,CAAC,OAAO,uBAAuB,CAAC,CAAC,MAAM,CAAC,CAAC;AAO5E,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;;;;;;;;;;;;EAQtC,CAAC;AAEH,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,2BAA2B,CAAC,CAAC;AAWhF;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,UAAU,GAAG,qBAAqB,CAY7E;AAOD;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,qBAAqB,EAC/B,MAAM,EAAE,qBAAqB,GAC5B,oBAAoB,EAAE,CAYxB;AAED,0EAA0E;AAC1E,wBAAgB,cAAc,CAAC,KAAK,EAAE,IAAI,CAAC,UAAU,EAAE,YAAY,GAAG,aAAa,CAAC,GAAG,OAAO,CAE7F;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,GAAE,IAAiB,GAAG,MAAM,GAAG,IAAI,CA+BvF"}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.EditableCaptureFieldsSchema = exports.CAPTURE_EDITABLE_FIELDS = void 0;
|
|
4
|
+
exports.fieldsFromEventDraft = fieldsFromEventDraft;
|
|
5
|
+
exports.editedFieldsBetween = editedFieldsBetween;
|
|
6
|
+
exports.needsAttention = needsAttention;
|
|
7
|
+
exports.normaliseTimeInput = normaliseTimeInput;
|
|
8
|
+
const zod_1 = require("zod");
|
|
9
|
+
/**
|
|
10
|
+
* The confirmation card's fields (Milestone 1.5), shared by the app and the backend.
|
|
11
|
+
*
|
|
12
|
+
* Why this lives in `shared` rather than in the app: the card edits a draft that the
|
|
13
|
+
* backend must store, and both sides have to agree on exactly two things — what may
|
|
14
|
+
* be edited, and what "edited" means. The `editedFields` list is the accuracy
|
|
15
|
+
* telemetry behind the confirmation-fatigue risk (README §8), so a field name that
|
|
16
|
+
* one side spells differently from the other silently produces a wrong metric, which
|
|
17
|
+
* is the kind of bug nobody notices until the numbers are used to make a decision.
|
|
18
|
+
*
|
|
19
|
+
* The conversion direction matters too. The draft stores absolute instants
|
|
20
|
+
* (`2026-09-27T15:00:00+08:00`), because that is what Google Calendar needs. A person
|
|
21
|
+
* editing a card thinks in wall clock ("3pm"). `fieldsFromEventDraft` converts one
|
|
22
|
+
* way — and deliberately does **no** timezone arithmetic: it reads the offset that is
|
|
23
|
+
* already in the string, since that offset is the one the backend resolved for that
|
|
24
|
+
* very instant. Rebuilding the instant from edited fields is the backend's job
|
|
25
|
+
* (`functions/src/capture/updateCapture.ts`), where the real IANA database lives.
|
|
26
|
+
*/
|
|
27
|
+
/** Field names the confirmation card may change. Stable strings — they are logged. */
|
|
28
|
+
exports.CAPTURE_EDITABLE_FIELDS = [
|
|
29
|
+
"title",
|
|
30
|
+
"date",
|
|
31
|
+
"startTime",
|
|
32
|
+
"endTime",
|
|
33
|
+
"allDay",
|
|
34
|
+
"location",
|
|
35
|
+
"notes",
|
|
36
|
+
];
|
|
37
|
+
/** `YYYY-MM-DD`, the shape the card and the extractor both use. */
|
|
38
|
+
const localDate = zod_1.z.string().regex(/^\d{4}-\d{2}-\d{2}$/);
|
|
39
|
+
/** `HH:MM`, 24-hour, the shape the card and the extractor both use. */
|
|
40
|
+
const localTime = zod_1.z.string().regex(/^\d{1,2}:\d{2}$/);
|
|
41
|
+
exports.EditableCaptureFieldsSchema = zod_1.z.object({
|
|
42
|
+
title: zod_1.z.string().min(1).max(200),
|
|
43
|
+
date: localDate,
|
|
44
|
+
startTime: localTime.nullable(),
|
|
45
|
+
endTime: localTime.nullable(),
|
|
46
|
+
allDay: zod_1.z.boolean(),
|
|
47
|
+
location: zod_1.z.string().max(500).nullable(),
|
|
48
|
+
notes: zod_1.z.string().max(2000).nullable(),
|
|
49
|
+
});
|
|
50
|
+
/** One RFC3339 timestamp split into the offset it carries and the wall clock it reads. */
|
|
51
|
+
function wallClockFromRfc3339(value) {
|
|
52
|
+
const match = /^(\d{4}-\d{2}-\d{2})T(\d{2}):(\d{2})/.exec(value);
|
|
53
|
+
if (!match)
|
|
54
|
+
return null;
|
|
55
|
+
// The string is already expressed in the member's zone with the right offset (the
|
|
56
|
+
// backend produced it that way), so the wall clock is simply its local part.
|
|
57
|
+
return { date: match[1] ?? "", time: `${match[2]}:${match[3]}` };
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* A draft as the card shows it. `endTime` is null for all-day events — the card has
|
|
61
|
+
* no use for the exclusive next-midnight end, and a person never typed it.
|
|
62
|
+
*/
|
|
63
|
+
function fieldsFromEventDraft(draft) {
|
|
64
|
+
const start = wallClockFromRfc3339(draft.start);
|
|
65
|
+
const end = draft.end ? wallClockFromRfc3339(draft.end) : null;
|
|
66
|
+
return {
|
|
67
|
+
title: draft.title,
|
|
68
|
+
date: start?.date ?? "",
|
|
69
|
+
startTime: draft.allDay ? null : (start?.time ?? null),
|
|
70
|
+
endTime: draft.allDay ? null : (end?.time ?? null),
|
|
71
|
+
allDay: draft.allDay,
|
|
72
|
+
location: draft.location ?? null,
|
|
73
|
+
notes: draft.notes ?? null,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
/** Trimmed comparison, so whitespace is not reported as an edit the member made. */
|
|
77
|
+
function normalise(value) {
|
|
78
|
+
return (value ?? "").trim();
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Which fields the member actually changed — the telemetry the whole card exists to
|
|
82
|
+
* produce (context.md §9's success signal). Only names from
|
|
83
|
+
* `CAPTURE_EDITABLE_FIELDS` can be returned, and only real differences: a card that
|
|
84
|
+
* was opened and confirmed untouched yields `[]`.
|
|
85
|
+
*
|
|
86
|
+
* The all-day toggle is reported as **one** edit: flipping it clears the start and
|
|
87
|
+
* end times as a consequence, and counting those clearings separately would turn a
|
|
88
|
+
* single tap into three "corrections" in the accuracy metric — the metric exists to
|
|
89
|
+
* measure how often the extractor is wrong, not how many fields a control happens to
|
|
90
|
+
* touch.
|
|
91
|
+
*/
|
|
92
|
+
function editedFieldsBetween(original, edited) {
|
|
93
|
+
const changed = [];
|
|
94
|
+
const allDayToggled = original.allDay !== edited.allDay;
|
|
95
|
+
for (const field of exports.CAPTURE_EDITABLE_FIELDS) {
|
|
96
|
+
if (field === "allDay") {
|
|
97
|
+
if (allDayToggled)
|
|
98
|
+
changed.push(field);
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
if ((field === "startTime" || field === "endTime") && allDayToggled)
|
|
102
|
+
continue;
|
|
103
|
+
if (normalise(original[field]) !== normalise(edited[field]))
|
|
104
|
+
changed.push(field);
|
|
105
|
+
}
|
|
106
|
+
return changed;
|
|
107
|
+
}
|
|
108
|
+
/** True when the draft carries anything the card should flag in amber. */
|
|
109
|
+
function needsAttention(draft) {
|
|
110
|
+
return draft.confidence !== "high" || draft.ambiguities.length > 0;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* The card's time fields into `HH:MM`, or null when it is not a time at all.
|
|
114
|
+
*
|
|
115
|
+
* People type times the way they say them — "3", "3pm", "3:30 pm", "15.00" — and a
|
|
116
|
+
* card that answers "that is not a time" to "3pm" is a card that makes a member feel
|
|
117
|
+
* stupid for writing what they meant. The LLM's own output is always `HH:MM`; this is
|
|
118
|
+
* for the human editing afterwards.
|
|
119
|
+
*
|
|
120
|
+
* Deliberately narrow about what it will *infer*: a **bare** hour 1–11 becomes PM only
|
|
121
|
+
* when the hour has passed (a person editing a card at 16:00 who types "3" means
|
|
122
|
+
* 15:00, not 03:00), a clock reading ("9:05") is taken exactly as written, and
|
|
123
|
+
* anything else returns null so the card can say so instead of guessing.
|
|
124
|
+
*
|
|
125
|
+
* @param value the raw text from the field
|
|
126
|
+
* @param now used only to choose AM/PM for a bare hour; injectable for tests
|
|
127
|
+
*/
|
|
128
|
+
function normaliseTimeInput(value, now = new Date()) {
|
|
129
|
+
const text = value.trim().toLowerCase().replace(/\s+/g, "");
|
|
130
|
+
if (text.length === 0)
|
|
131
|
+
return null;
|
|
132
|
+
const match = /^(\d{1,2})(?:[:.](\d{2}))?(am|pm|a\.m\.|p\.m\.)?$/.exec(text);
|
|
133
|
+
if (!match)
|
|
134
|
+
return null;
|
|
135
|
+
const hour = Number(match[1]);
|
|
136
|
+
const minute = match[2] ? Number(match[2]) : 0;
|
|
137
|
+
if (!Number.isFinite(hour) || minute > 59)
|
|
138
|
+
return null;
|
|
139
|
+
const meridiem = match[3]?.[0];
|
|
140
|
+
if (meridiem === "a") {
|
|
141
|
+
// 12am is midnight, and the only 12 that does not keep its number.
|
|
142
|
+
if (hour < 1 || hour > 12)
|
|
143
|
+
return null;
|
|
144
|
+
return format(checked(hour === 12 ? 0 : hour), minute);
|
|
145
|
+
}
|
|
146
|
+
if (meridiem === "p") {
|
|
147
|
+
if (hour < 1 || hour > 12)
|
|
148
|
+
return null;
|
|
149
|
+
return format(checked(hour === 12 ? 12 : hour + 12), minute);
|
|
150
|
+
}
|
|
151
|
+
if (hour > 23)
|
|
152
|
+
return null;
|
|
153
|
+
// A *bare* hour (no minutes) of 1–11 with no meridiem is read as the next time that
|
|
154
|
+
// hour comes round — at 16:00, "3" means 15:00, because someone re-timing a dentist
|
|
155
|
+
// appointment does not mean 03:00. A clock reading ("9:05", "15:00") is read exactly
|
|
156
|
+
// as written, in the morning or not.
|
|
157
|
+
const bareHour = match[2] === undefined;
|
|
158
|
+
if (bareHour && hour >= 1 && hour <= 11 && now.getHours() >= 12) {
|
|
159
|
+
return format(checked(hour + 12), minute);
|
|
160
|
+
}
|
|
161
|
+
return format(checked(hour), minute);
|
|
162
|
+
}
|
|
163
|
+
function checked(hour) {
|
|
164
|
+
return hour >= 0 && hour <= 23 ? hour : null;
|
|
165
|
+
}
|
|
166
|
+
function format(hour, minute) {
|
|
167
|
+
if (hour === null)
|
|
168
|
+
return null;
|
|
169
|
+
return `${String(hour).padStart(2, "0")}:${String(minute).padStart(2, "0")}`;
|
|
170
|
+
}
|
|
171
|
+
//# sourceMappingURL=fields.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fields.js","sourceRoot":"","sources":["../../src/capture/fields.ts"],"names":[],"mappings":"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"}
|
package/dist/constants.d.ts
CHANGED
|
@@ -4,8 +4,27 @@
|
|
|
4
4
|
* channel policy, and provider choices are confirmed by Rob in Phase 0
|
|
5
5
|
* (Implementation_Plan.md Phase 0).
|
|
6
6
|
*/
|
|
7
|
-
/**
|
|
8
|
-
|
|
7
|
+
/**
|
|
8
|
+
* The launch languages (decided by Rob 2026-09-23; Phase 0's last open item).
|
|
9
|
+
*
|
|
10
|
+
* Every entry here is **verified to round-trip**: a reminder sentence is
|
|
11
|
+
* synthesised by the TTS provider and the audio is transcribed back, and the
|
|
12
|
+
* transcript matches what was said (see `daily_development_log.md` →
|
|
13
|
+
* 2026-09-23 "语言集扩容"). That test is the bar for adding a language, because
|
|
14
|
+
* a provider can accept a request for an unsupported language and still
|
|
15
|
+
* mispronounce it — Hebrew failed exactly that way on `eleven_multilingual_v2`.
|
|
16
|
+
*
|
|
17
|
+
* `he-IL` is included because it **passes on `eleven_v3`** (70+ languages); see
|
|
18
|
+
* `ELEVEN_MODEL_BY_LANGUAGE` in `functions/` for the per-language model choice.
|
|
19
|
+
* Arabic and Hebrew are RTL — the *content* renders fine, but app-UI
|
|
20
|
+
* localisation for RTL is a separate, still-open workstream.
|
|
21
|
+
*
|
|
22
|
+
* Adding a language is not one constant: it also needs a reminder template in
|
|
23
|
+
* `i18n/templates.ts` (an unknown language silently falls back to English), a
|
|
24
|
+
* native-name label in the app, and a republish of this package + a functions
|
|
25
|
+
* redeploy, since the backend resolves it from the registry.
|
|
26
|
+
*/
|
|
27
|
+
export declare const SUPPORTED_LANGUAGES: readonly ["en-US", "zh-CN", "es-MX", "fr-FR", "de-DE", "pt-BR", "ru-RU", "ar-SA", "hi-IN", "he-IL", "ja-JP", "ko-KR"];
|
|
9
28
|
/** Google Calendar color ids "1"–"11" (color-to-member assignment decided in Phase 0). */
|
|
10
29
|
export declare const GOOGLE_CALENDAR_COLOR_IDS: readonly ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11"];
|
|
11
30
|
/** Default per-event reminder offsets in minutes (1 day, 2 hours). */
|
package/dist/constants.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,mBAAmB,uHAatB,CAAC;AAEX,0FAA0F;AAC1F,eAAO,MAAM,yBAAyB,oEAY5B,CAAC;AAEX,sEAAsE;AACtE,eAAO,MAAM,gCAAgC,sBAAuB,CAAC;AAErE,qEAAqE;AACrE,eAAO,MAAM,kCAAkC,KAAK,CAAC;AAErD,mEAAmE;AACnE,eAAO,MAAM,wCAAwC,MAAM,CAAC;AAE5D,iCAAiC;AACjC,eAAO,MAAM,qBAAqB;;;;;;;CAOxB,CAAC;AAEX,sCAAsC;AACtC,eAAO,MAAM,aAAa;;;CAGhB,CAAC"}
|
package/dist/constants.js
CHANGED
|
@@ -7,8 +7,40 @@
|
|
|
7
7
|
*/
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
9
|
exports.STORAGE_PATHS = exports.FIRESTORE_COLLECTIONS = exports.SCHEDULER_HORIZON_MARGIN_MINUTES_DEFAULT = exports.SCHEDULER_INTERVAL_MINUTES_DEFAULT = exports.DEFAULT_REMINDER_OFFSETS_MINUTES = exports.GOOGLE_CALENDAR_COLOR_IDS = exports.SUPPORTED_LANGUAGES = void 0;
|
|
10
|
-
/**
|
|
11
|
-
|
|
10
|
+
/**
|
|
11
|
+
* The launch languages (decided by Rob 2026-09-23; Phase 0's last open item).
|
|
12
|
+
*
|
|
13
|
+
* Every entry here is **verified to round-trip**: a reminder sentence is
|
|
14
|
+
* synthesised by the TTS provider and the audio is transcribed back, and the
|
|
15
|
+
* transcript matches what was said (see `daily_development_log.md` →
|
|
16
|
+
* 2026-09-23 "语言集扩容"). That test is the bar for adding a language, because
|
|
17
|
+
* a provider can accept a request for an unsupported language and still
|
|
18
|
+
* mispronounce it — Hebrew failed exactly that way on `eleven_multilingual_v2`.
|
|
19
|
+
*
|
|
20
|
+
* `he-IL` is included because it **passes on `eleven_v3`** (70+ languages); see
|
|
21
|
+
* `ELEVEN_MODEL_BY_LANGUAGE` in `functions/` for the per-language model choice.
|
|
22
|
+
* Arabic and Hebrew are RTL — the *content* renders fine, but app-UI
|
|
23
|
+
* localisation for RTL is a separate, still-open workstream.
|
|
24
|
+
*
|
|
25
|
+
* Adding a language is not one constant: it also needs a reminder template in
|
|
26
|
+
* `i18n/templates.ts` (an unknown language silently falls back to English), a
|
|
27
|
+
* native-name label in the app, and a republish of this package + a functions
|
|
28
|
+
* redeploy, since the backend resolves it from the registry.
|
|
29
|
+
*/
|
|
30
|
+
exports.SUPPORTED_LANGUAGES = [
|
|
31
|
+
"en-US",
|
|
32
|
+
"zh-CN",
|
|
33
|
+
"es-MX",
|
|
34
|
+
"fr-FR",
|
|
35
|
+
"de-DE",
|
|
36
|
+
"pt-BR",
|
|
37
|
+
"ru-RU",
|
|
38
|
+
"ar-SA",
|
|
39
|
+
"hi-IN",
|
|
40
|
+
"he-IL",
|
|
41
|
+
"ja-JP",
|
|
42
|
+
"ko-KR",
|
|
43
|
+
];
|
|
12
44
|
/** Google Calendar color ids "1"–"11" (color-to-member assignment decided in Phase 0). */
|
|
13
45
|
exports.GOOGLE_CALENDAR_COLOR_IDS = [
|
|
14
46
|
"1",
|
package/dist/constants.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AAEH
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AAEH;;;;;;;;;;;;;;;;;;;GAmBG;AACU,QAAA,mBAAmB,GAAG;IACjC,OAAO;IACP,OAAO;IACP,OAAO;IACP,OAAO;IACP,OAAO;IACP,OAAO;IACP,OAAO;IACP,OAAO;IACP,OAAO;IACP,OAAO;IACP,OAAO;IACP,OAAO;CACC,CAAC;AAEX,0FAA0F;AAC7E,QAAA,yBAAyB,GAAG;IACvC,GAAG;IACH,GAAG;IACH,GAAG;IACH,GAAG;IACH,GAAG;IACH,GAAG;IACH,GAAG;IACH,GAAG;IACH,GAAG;IACH,IAAI;IACJ,IAAI;CACI,CAAC;AAEX,sEAAsE;AACzD,QAAA,gCAAgC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAU,CAAC;AAErE,qEAAqE;AACxD,QAAA,kCAAkC,GAAG,EAAE,CAAC;AAErD,mEAAmE;AACtD,QAAA,wCAAwC,GAAG,GAAG,CAAC;AAE5D,iCAAiC;AACpB,QAAA,qBAAqB,GAAG;IACnC,YAAY,EAAE,cAAc;IAC5B,gBAAgB,EAAE,kBAAkB;IACpC,QAAQ,EAAE,UAAU;IACpB,OAAO,EAAE,SAAS;IAClB,QAAQ,EAAE,UAAU;IACpB,aAAa,EAAE,eAAe;CACtB,CAAC;AAEX,sCAAsC;AACzB,QAAA,aAAa,GAAG;IAC3B,QAAQ,EAAE,OAAO,EAAE,gDAAgD;IACnE,QAAQ,EAAE,KAAK,EAAE,6CAA6C;CACtD,CAAC"}
|
package/dist/i18n/templates.d.ts
CHANGED
|
@@ -11,13 +11,94 @@ export interface ReminderMessageParams {
|
|
|
11
11
|
/** Optional location included in the message. */
|
|
12
12
|
location?: string | null;
|
|
13
13
|
}
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
14
|
+
/**
|
|
15
|
+
* Per-language copy, as data rather than one function per language: with 12
|
|
16
|
+
* languages the only thing that varies is punctuation and word order, so the
|
|
17
|
+
* variation belongs in a table a reviewer can scan in one screen.
|
|
18
|
+
*
|
|
19
|
+
* Two things worth knowing when adding a row:
|
|
20
|
+
* - **`lead` + `join` are the whole sentence shape.** `{location}` in `location`
|
|
21
|
+
* is replaced only when the event has one, which is why the parentheses live
|
|
22
|
+
* in the table (Japanese uses full-width ones, English half-width).
|
|
23
|
+
* - **Anything outside GSM-7 costs a second SMS segment.** Latin/Cyrillic-adjacent
|
|
24
|
+
* text is 160 chars per segment on the Latin-1 path, but Arabic, Hebrew, Hindi,
|
|
25
|
+
* Japanese and Korean are UCS-2 — 70 chars per segment — and Chinese already
|
|
26
|
+
* is. So the 9 new languages make a long title likelier to bill as 2 segments;
|
|
27
|
+
* this is exactly why the file header rejects free-form LLM copy.
|
|
28
|
+
*/
|
|
29
|
+
declare const COPY: {
|
|
30
|
+
readonly "en-US": {
|
|
31
|
+
readonly lead: "⏰ Reminder: ";
|
|
32
|
+
readonly join: " — ";
|
|
33
|
+
readonly location: " (📍 {location})";
|
|
34
|
+
};
|
|
35
|
+
readonly "zh-CN": {
|
|
36
|
+
readonly lead: "⏰ 提醒:";
|
|
37
|
+
readonly join: ",";
|
|
38
|
+
readonly location: "(📍 {location})";
|
|
39
|
+
};
|
|
40
|
+
readonly "es-MX": {
|
|
41
|
+
readonly lead: "⏰ Recordatorio: ";
|
|
42
|
+
readonly join: " — ";
|
|
43
|
+
readonly location: " (📍 {location})";
|
|
44
|
+
};
|
|
45
|
+
readonly "fr-FR": {
|
|
46
|
+
readonly lead: "⏰ Rappel : ";
|
|
47
|
+
readonly join: " — ";
|
|
48
|
+
readonly location: " (📍 {location})";
|
|
49
|
+
};
|
|
50
|
+
readonly "de-DE": {
|
|
51
|
+
readonly lead: "⏰ Erinnerung: ";
|
|
52
|
+
readonly join: " — ";
|
|
53
|
+
readonly location: " (📍 {location})";
|
|
54
|
+
};
|
|
55
|
+
readonly "pt-BR": {
|
|
56
|
+
readonly lead: "⏰ Lembrete: ";
|
|
57
|
+
readonly join: " — ";
|
|
58
|
+
readonly location: " (📍 {location})";
|
|
59
|
+
};
|
|
60
|
+
readonly "ru-RU": {
|
|
61
|
+
readonly lead: "⏰ Напоминание: ";
|
|
62
|
+
readonly join: " — ";
|
|
63
|
+
readonly location: " (📍 {location})";
|
|
64
|
+
};
|
|
65
|
+
readonly "ar-SA": {
|
|
66
|
+
readonly lead: "⏰ تذكير: ";
|
|
67
|
+
readonly join: " — ";
|
|
68
|
+
readonly location: " (📍 {location})";
|
|
69
|
+
};
|
|
70
|
+
readonly "hi-IN": {
|
|
71
|
+
readonly lead: "⏰ रिमाइंडर: ";
|
|
72
|
+
readonly join: " — ";
|
|
73
|
+
readonly location: " (📍 {location})";
|
|
74
|
+
};
|
|
75
|
+
readonly "he-IL": {
|
|
76
|
+
readonly lead: "⏰ תזכורת: ";
|
|
77
|
+
readonly join: " — ";
|
|
78
|
+
readonly location: " (📍 {location})";
|
|
79
|
+
};
|
|
80
|
+
readonly "ja-JP": {
|
|
81
|
+
readonly lead: "⏰ リマインダー:";
|
|
82
|
+
readonly join: " — ";
|
|
83
|
+
readonly location: "(📍 {location})";
|
|
84
|
+
};
|
|
85
|
+
readonly "ko-KR": {
|
|
86
|
+
readonly lead: "⏰ 알림: ";
|
|
87
|
+
readonly join: " — ";
|
|
88
|
+
readonly location: " (📍 {location})";
|
|
89
|
+
};
|
|
18
90
|
};
|
|
19
|
-
export type TemplateKey = keyof typeof
|
|
20
|
-
/**
|
|
91
|
+
export type TemplateKey = keyof typeof COPY;
|
|
92
|
+
/**
|
|
93
|
+
* Closest template for a BCP-47 tag: exact → base language ("zh" → "zh-CN") →
|
|
94
|
+
* "en-US".
|
|
95
|
+
*
|
|
96
|
+
* The base-language step now matters more than it did with three languages: a
|
|
97
|
+
* member on `pt-PT` or `ar-EG` gets `pt-BR` / `ar-SA` rather than English. That
|
|
98
|
+
* is the right trade for a message *template* — the times inside `when` are
|
|
99
|
+
* already resolved in the member's own timezone by the caller — but it is a
|
|
100
|
+
* deliberate approximation, not true localisation.
|
|
101
|
+
*/
|
|
21
102
|
export declare function resolveTemplateKey(language: string): TemplateKey;
|
|
22
103
|
/** Build the reminder message text for a member's language. */
|
|
23
104
|
export declare function buildReminderMessage(language: string, params: ReminderMessageParams): string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"templates.d.ts","sourceRoot":"","sources":["../../src/i18n/templates.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,WAAW,qBAAqB;IACpC,mBAAmB;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,+EAA+E;IAC/E,IAAI,EAAE,MAAM,CAAC;IACb,iDAAiD;IACjD,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,QAAA,MAAM,
|
|
1
|
+
{"version":3,"file":"templates.d.ts","sourceRoot":"","sources":["../../src/i18n/templates.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,WAAW,qBAAqB;IACpC,mBAAmB;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,+EAA+E;IAC/E,IAAI,EAAE,MAAM,CAAC;IACb,iDAAiD;IACjD,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED;;;;;;;;;;;;;;GAcG;AACH,QAAA,MAAM,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkB2E,CAAC;AAEtF,MAAM,MAAM,WAAW,GAAG,MAAM,OAAO,IAAI,CAAC;AAE5C;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,WAAW,CAQhE;AAED,+DAA+D;AAC/D,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,qBAAqB,GAAG,MAAM,CAI5F"}
|
package/dist/i18n/templates.js
CHANGED
|
@@ -7,24 +7,56 @@
|
|
|
7
7
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
8
|
exports.resolveTemplateKey = resolveTemplateKey;
|
|
9
9
|
exports.buildReminderMessage = buildReminderMessage;
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
10
|
+
/**
|
|
11
|
+
* Per-language copy, as data rather than one function per language: with 12
|
|
12
|
+
* languages the only thing that varies is punctuation and word order, so the
|
|
13
|
+
* variation belongs in a table a reviewer can scan in one screen.
|
|
14
|
+
*
|
|
15
|
+
* Two things worth knowing when adding a row:
|
|
16
|
+
* - **`lead` + `join` are the whole sentence shape.** `{location}` in `location`
|
|
17
|
+
* is replaced only when the event has one, which is why the parentheses live
|
|
18
|
+
* in the table (Japanese uses full-width ones, English half-width).
|
|
19
|
+
* - **Anything outside GSM-7 costs a second SMS segment.** Latin/Cyrillic-adjacent
|
|
20
|
+
* text is 160 chars per segment on the Latin-1 path, but Arabic, Hebrew, Hindi,
|
|
21
|
+
* Japanese and Korean are UCS-2 — 70 chars per segment — and Chinese already
|
|
22
|
+
* is. So the 9 new languages make a long title likelier to bill as 2 segments;
|
|
23
|
+
* this is exactly why the file header rejects free-form LLM copy.
|
|
24
|
+
*/
|
|
25
|
+
const COPY = {
|
|
26
|
+
"en-US": { lead: "⏰ Reminder: ", join: " — ", location: " (📍 {location})" },
|
|
27
|
+
"zh-CN": { lead: "⏰ 提醒:", join: ",", location: "(📍 {location})" },
|
|
28
|
+
"es-MX": { lead: "⏰ Recordatorio: ", join: " — ", location: " (📍 {location})" },
|
|
29
|
+
// French puts a space before the colon — `Rappel :` — not `Rappel:`.
|
|
30
|
+
"fr-FR": { lead: "⏰ Rappel : ", join: " — ", location: " (📍 {location})" },
|
|
31
|
+
"de-DE": { lead: "⏰ Erinnerung: ", join: " — ", location: " (📍 {location})" },
|
|
32
|
+
"pt-BR": { lead: "⏰ Lembrete: ", join: " — ", location: " (📍 {location})" },
|
|
33
|
+
"ru-RU": { lead: "⏰ Напоминание: ", join: " — ", location: " (📍 {location})" },
|
|
34
|
+
// Arabic is RTL: the whole line renders right-to-left, but `lead` still comes
|
|
35
|
+
// first in logical order, which is what the messaging APIs expect.
|
|
36
|
+
"ar-SA": { lead: "⏰ تذكير: ", join: " — ", location: " (📍 {location})" },
|
|
37
|
+
"hi-IN": { lead: "⏰ रिमाइंडर: ", join: " — ", location: " (📍 {location})" },
|
|
38
|
+
"he-IL": { lead: "⏰ תזכורת: ", join: " — ", location: " (📍 {location})" },
|
|
39
|
+
// Japanese uses `:` after the lead and `、`-style separation; full-width
|
|
40
|
+
// parentheses keep the location visually inside the sentence.
|
|
41
|
+
"ja-JP": { lead: "⏰ リマインダー:", join: " — ", location: "(📍 {location})" },
|
|
42
|
+
"ko-KR": { lead: "⏰ 알림: ", join: " — ", location: " (📍 {location})" },
|
|
20
43
|
};
|
|
21
|
-
/**
|
|
44
|
+
/**
|
|
45
|
+
* Closest template for a BCP-47 tag: exact → base language ("zh" → "zh-CN") →
|
|
46
|
+
* "en-US".
|
|
47
|
+
*
|
|
48
|
+
* The base-language step now matters more than it did with three languages: a
|
|
49
|
+
* member on `pt-PT` or `ar-EG` gets `pt-BR` / `ar-SA` rather than English. That
|
|
50
|
+
* is the right trade for a message *template* — the times inside `when` are
|
|
51
|
+
* already resolved in the member's own timezone by the caller — but it is a
|
|
52
|
+
* deliberate approximation, not true localisation.
|
|
53
|
+
*/
|
|
22
54
|
function resolveTemplateKey(language) {
|
|
23
|
-
if (language in
|
|
55
|
+
if (language in COPY)
|
|
24
56
|
return language;
|
|
25
57
|
const base = language.split("-")[0] ?? "";
|
|
26
58
|
if (base.length >= 2) {
|
|
27
|
-
const baseKey = Object.keys(
|
|
59
|
+
const baseKey = Object.keys(COPY).find((key) => key.startsWith(`${base}-`));
|
|
28
60
|
if (baseKey)
|
|
29
61
|
return baseKey;
|
|
30
62
|
}
|
|
@@ -32,7 +64,8 @@ function resolveTemplateKey(language) {
|
|
|
32
64
|
}
|
|
33
65
|
/** Build the reminder message text for a member's language. */
|
|
34
66
|
function buildReminderMessage(language, params) {
|
|
35
|
-
const
|
|
36
|
-
|
|
67
|
+
const copy = COPY[resolveTemplateKey(language)];
|
|
68
|
+
const body = `${copy.lead}${params.title}${copy.join}${params.when}`;
|
|
69
|
+
return params.location ? body + copy.location.replace("{location}", params.location) : body;
|
|
37
70
|
}
|
|
38
71
|
//# sourceMappingURL=templates.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"templates.js","sourceRoot":"","sources":["../../src/i18n/templates.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;
|
|
1
|
+
{"version":3,"file":"templates.js","sourceRoot":"","sources":["../../src/i18n/templates.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;AA0DH,gDAQC;AAGD,oDAIC;AA9DD;;;;;;;;;;;;;;GAcG;AACH,MAAM,IAAI,GAAG;IACX,OAAO,EAAE,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,kBAAkB,EAAE;IAC5E,OAAO,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,QAAQ,EAAE,iBAAiB,EAAE;IAClE,OAAO,EAAE,EAAE,IAAI,EAAE,kBAAkB,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,kBAAkB,EAAE;IAChF,qEAAqE;IACrE,OAAO,EAAE,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,kBAAkB,EAAE;IAC3E,OAAO,EAAE,EAAE,IAAI,EAAE,gBAAgB,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,kBAAkB,EAAE;IAC9E,OAAO,EAAE,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,kBAAkB,EAAE;IAC5E,OAAO,EAAE,EAAE,IAAI,EAAE,iBAAiB,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,kBAAkB,EAAE;IAC/E,8EAA8E;IAC9E,mEAAmE;IACnE,OAAO,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,kBAAkB,EAAE;IACzE,OAAO,EAAE,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,kBAAkB,EAAE;IAC5E,OAAO,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,kBAAkB,EAAE;IAC1E,wEAAwE;IACxE,8DAA8D;IAC9D,OAAO,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,iBAAiB,EAAE;IACxE,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,kBAAkB,EAAE;CACa,CAAC;AAItF;;;;;;;;;GASG;AACH,SAAgB,kBAAkB,CAAC,QAAgB;IACjD,IAAI,QAAQ,IAAI,IAAI;QAAE,OAAO,QAAuB,CAAC;IACrD,MAAM,IAAI,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAC1C,IAAI,IAAI,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;QACrB,MAAM,OAAO,GAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAmB,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC;QAC/F,IAAI,OAAO;YAAE,OAAO,OAAO,CAAC;IAC9B,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,+DAA+D;AAC/D,SAAgB,oBAAoB,CAAC,QAAgB,EAAE,MAA6B;IAClF,MAAM,IAAI,GAAG,IAAI,CAAC,kBAAkB,CAAC,QAAQ,CAAC,CAAC,CAAC;IAChD,MAAM,IAAI,GAAG,GAAG,IAAI,CAAC,IAAI,GAAG,MAAM,CAAC,KAAK,GAAG,IAAI,CAAC,IAAI,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC;IACrE,OAAO,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,YAAY,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAC9F,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -6,6 +6,8 @@ export * from "./schemas/event";
|
|
|
6
6
|
export * from "./schemas/circle";
|
|
7
7
|
export * from "./schemas/member";
|
|
8
8
|
export * from "./schemas/capture";
|
|
9
|
+
export * from "./capture/fields";
|
|
10
|
+
export * from "./capture/audio";
|
|
9
11
|
export * from "./schemas/reminder";
|
|
10
12
|
export * from "./reminders/math";
|
|
11
13
|
export * from "./i18n/templates";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,sBAAsB,CAAC;AACrC,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,sBAAsB,CAAC;AACrC,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,kBAAkB,CAAC;AACjC,cAAc,iBAAiB,CAAC;AAChC,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -22,6 +22,8 @@ __exportStar(require("./schemas/event"), exports);
|
|
|
22
22
|
__exportStar(require("./schemas/circle"), exports);
|
|
23
23
|
__exportStar(require("./schemas/member"), exports);
|
|
24
24
|
__exportStar(require("./schemas/capture"), exports);
|
|
25
|
+
__exportStar(require("./capture/fields"), exports);
|
|
26
|
+
__exportStar(require("./capture/audio"), exports);
|
|
25
27
|
__exportStar(require("./schemas/reminder"), exports);
|
|
26
28
|
__exportStar(require("./reminders/math"), exports);
|
|
27
29
|
__exportStar(require("./i18n/templates"), exports);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,8CAA4B;AAC5B,kDAAgC;AAChC,uDAAqC;AACrC,kDAAgC;AAChC,kDAAgC;AAChC,mDAAiC;AACjC,mDAAiC;AACjC,oDAAkC;AAClC,qDAAmC;AACnC,mDAAiC;AACjC,mDAAiC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,8CAA4B;AAC5B,kDAAgC;AAChC,uDAAqC;AACrC,kDAAgC;AAChC,kDAAgC;AAChC,mDAAiC;AACjC,mDAAiC;AACjC,oDAAkC;AAClC,mDAAiC;AACjC,kDAAgC;AAChC,qDAAmC;AACnC,mDAAiC;AACjC,mDAAiC"}
|
|
@@ -47,6 +47,12 @@ export declare const CaptureSchema: z.ZodObject<{
|
|
|
47
47
|
editedFields: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
48
48
|
googleEventId: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
49
49
|
createdAt: z.ZodAny;
|
|
50
|
+
/**
|
|
51
|
+
* When the member confirmed or discarded it (M1.5). Optional because captures
|
|
52
|
+
* written before this existed have no such instant, and because a capture sitting
|
|
53
|
+
* in `pending_confirmation` has not been decided at all.
|
|
54
|
+
*/
|
|
55
|
+
decidedAt: z.ZodOptional<z.ZodAny>;
|
|
50
56
|
}, "strip", z.ZodTypeAny, {
|
|
51
57
|
status: "pending_confirmation" | "confirmed" | "discarded";
|
|
52
58
|
memberId: string;
|
|
@@ -67,6 +73,7 @@ export declare const CaptureSchema: z.ZodObject<{
|
|
|
67
73
|
editedFields: string[];
|
|
68
74
|
createdAt?: any;
|
|
69
75
|
googleEventId?: string | null | undefined;
|
|
76
|
+
decidedAt?: any;
|
|
70
77
|
}, {
|
|
71
78
|
status: "pending_confirmation" | "confirmed" | "discarded";
|
|
72
79
|
memberId: string;
|
|
@@ -87,6 +94,7 @@ export declare const CaptureSchema: z.ZodObject<{
|
|
|
87
94
|
createdAt?: any;
|
|
88
95
|
editedFields?: string[] | undefined;
|
|
89
96
|
googleEventId?: string | null | undefined;
|
|
97
|
+
decidedAt?: any;
|
|
90
98
|
}>;
|
|
91
99
|
export type Capture = z.infer<typeof CaptureSchema>;
|
|
92
100
|
//# sourceMappingURL=capture.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"capture.d.ts","sourceRoot":"","sources":["../../src/schemas/capture.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB;;;;GAIG;AACH,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAMxB,0DAA0D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"capture.d.ts","sourceRoot":"","sources":["../../src/schemas/capture.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB;;;;GAIG;AACH,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAMxB,0DAA0D;;;;IAI1D;;;;OAIG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAEH,CAAC;AAEH,MAAM,MAAM,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC"}
|
package/dist/schemas/capture.js
CHANGED
|
@@ -20,5 +20,11 @@ exports.CaptureSchema = zod_1.z.object({
|
|
|
20
20
|
editedFields: zod_1.z.array(zod_1.z.string()).default([]),
|
|
21
21
|
googleEventId: zod_1.z.string().nullish(),
|
|
22
22
|
createdAt: primitives_1.firestoreTimestamp,
|
|
23
|
+
/**
|
|
24
|
+
* When the member confirmed or discarded it (M1.5). Optional because captures
|
|
25
|
+
* written before this existed have no such instant, and because a capture sitting
|
|
26
|
+
* in `pending_confirmation` has not been decided at all.
|
|
27
|
+
*/
|
|
28
|
+
decidedAt: primitives_1.firestoreTimestamp.optional(),
|
|
23
29
|
});
|
|
24
30
|
//# sourceMappingURL=capture.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"capture.js","sourceRoot":"","sources":["../../src/schemas/capture.ts"],"names":[],"mappings":";;;AAAA,6BAAwB;AACxB,mCAA4D;AAC5D,6CAAkD;AAClD,mCAA2C;AAE3C;;;;GAIG;AACU,QAAA,aAAa,GAAG,OAAC,CAAC,MAAM,CAAC;IACpC,QAAQ,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC3B,MAAM,EAAE,OAAC,CAAC,IAAI,CAAC,uBAAe,CAAC;IAC/B,OAAO,EAAE,OAAC,CAAC,MAAM,EAAE;IACnB,cAAc,EAAE,wBAAgB,CAAC,QAAQ,EAAE;IAC3C,MAAM,EAAE,OAAC,CAAC,IAAI,CAAC,wBAAgB,CAAC;IAChC,0DAA0D;IAC1D,YAAY,EAAE,OAAC,CAAC,KAAK,CAAC,OAAC,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;IAC7C,aAAa,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE;IACnC,SAAS,EAAE,+BAAkB;
|
|
1
|
+
{"version":3,"file":"capture.js","sourceRoot":"","sources":["../../src/schemas/capture.ts"],"names":[],"mappings":";;;AAAA,6BAAwB;AACxB,mCAA4D;AAC5D,6CAAkD;AAClD,mCAA2C;AAE3C;;;;GAIG;AACU,QAAA,aAAa,GAAG,OAAC,CAAC,MAAM,CAAC;IACpC,QAAQ,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC3B,MAAM,EAAE,OAAC,CAAC,IAAI,CAAC,uBAAe,CAAC;IAC/B,OAAO,EAAE,OAAC,CAAC,MAAM,EAAE;IACnB,cAAc,EAAE,wBAAgB,CAAC,QAAQ,EAAE;IAC3C,MAAM,EAAE,OAAC,CAAC,IAAI,CAAC,wBAAgB,CAAC;IAChC,0DAA0D;IAC1D,YAAY,EAAE,OAAC,CAAC,KAAK,CAAC,OAAC,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;IAC7C,aAAa,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE;IACnC,SAAS,EAAE,+BAAkB;IAC7B;;;;OAIG;IACH,SAAS,EAAE,+BAAkB,CAAC,QAAQ,EAAE;CACzC,CAAC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@voxendar/shared",
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"private": false,
|
|
5
5
|
"description": "Shared contracts, schemas, constants and pure logic for Voxendar/Tellie (consumed by functions/ and app/)",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
@@ -11,7 +11,9 @@
|
|
|
11
11
|
"scripts": {
|
|
12
12
|
"build": "tsc -p tsconfig.json",
|
|
13
13
|
"typecheck": "tsc --noEmit -p tsconfig.json",
|
|
14
|
-
"test": "vitest run"
|
|
14
|
+
"test": "vitest run",
|
|
15
|
+
"prepare": "npm run build",
|
|
16
|
+
"prepublishOnly": "npm test"
|
|
15
17
|
},
|
|
16
18
|
"dependencies": {
|
|
17
19
|
"zod": "^3.23.8"
|
|
@@ -21,4 +23,4 @@
|
|
|
21
23
|
"typescript": "^5.5.4",
|
|
22
24
|
"vitest": "^2.1.9"
|
|
23
25
|
}
|
|
24
|
-
}
|
|
26
|
+
}
|