@fayz-ai/forms 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +34 -2
- package/dist/chunk-2KVTEW7I.js +211 -0
- package/dist/chunk-2KVTEW7I.js.map +1 -0
- package/dist/chunk-JO4REIZC.js +429 -0
- package/dist/chunk-JO4REIZC.js.map +1 -0
- package/dist/chunk-L2KPTYH4.js +11 -0
- package/dist/chunk-L2KPTYH4.js.map +1 -0
- package/dist/chunk-LQJONAVT.js +25 -0
- package/dist/chunk-LQJONAVT.js.map +1 -0
- package/dist/data/mock.d.ts +3 -0
- package/dist/data/mock.d.ts.map +1 -0
- package/dist/data/mock.js +4 -0
- package/dist/data/mock.js.map +1 -0
- package/dist/data/provider.d.ts +55 -0
- package/dist/data/provider.d.ts.map +1 -0
- package/dist/data/provider.js +3 -0
- package/dist/data/provider.js.map +1 -0
- package/dist/data/supabase.d.ts +6 -0
- package/dist/data/supabase.d.ts.map +1 -0
- package/dist/data/supabase.js +4 -0
- package/dist/data/supabase.js.map +1 -0
- package/dist/data/tables.d.ts +7 -0
- package/dist/data/tables.d.ts.map +1 -0
- package/dist/data/tables.js +3 -0
- package/dist/data/tables.js.map +1 -0
- package/dist/domain/document.d.ts +84 -0
- package/dist/domain/document.d.ts.map +1 -0
- package/dist/domain/document.js +3 -0
- package/dist/domain/document.js.map +1 -0
- package/dist/domain/requirement.d.ts +27 -0
- package/dist/domain/requirement.d.ts.map +1 -0
- package/dist/domain/requirement.js +3 -0
- package/dist/domain/requirement.js.map +1 -0
- package/dist/domain/template.d.ts +135 -0
- package/dist/domain/template.d.ts.map +1 -0
- package/dist/domain/template.js +3 -0
- package/dist/domain/template.js.map +1 -0
- package/dist/store.d.ts +37 -0
- package/dist/store.d.ts.map +1 -0
- package/dist/store.js +138 -0
- package/dist/store.js.map +1 -0
- package/dist/views/zones.d.ts +75 -0
- package/dist/views/zones.d.ts.map +1 -0
- package/dist/views/zones.js +11 -0
- package/dist/views/zones.js.map +1 -0
- package/package.json +48 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Faya Labs
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,35 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @fayz-ai/forms
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
> The forms bounded context: templates, filled documents and the forms a person must have before being attended — the rules, where they are stored, and the store over them.
|
|
4
|
+
|
|
5
|
+
**Status:** beta — extracted from `@fayz-ai/plugin-forms`, which still exports every name it had and keeps the screens and the migrations. Pre-1.0: minor APIs may change before 1.0.
|
|
6
|
+
|
|
7
|
+
Shaped as [docs/platform/PATTERNS.md](../../docs/platform/PATTERNS.md) describes. There is no entry file: each module is imported by its path.
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install @fayz-ai/forms
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Modules
|
|
16
|
+
|
|
17
|
+
| Import | What it holds |
|
|
18
|
+
|---|---|
|
|
19
|
+
| `@fayz-ai/forms/domain/*` | types and pure rules: `template`, `document`, `requirement` |
|
|
20
|
+
| `@fayz-ai/forms/data/provider` | `FormsDataProvider`, the repository port |
|
|
21
|
+
| `@fayz-ai/forms/data/supabase` | `createSupabaseFormsProvider`, `getPersonFormRequirements` — with `data/tables`, the only modules that name a table |
|
|
22
|
+
| `@fayz-ai/forms/data/mock` | `createMockFormsProvider`, the same contract in memory |
|
|
23
|
+
| `@fayz-ai/forms/store` | `createFormsStore`, `createSafeFormsProvider` |
|
|
24
|
+
| `@fayz-ai/forms/views/zones` | `FORMS_ZONES` and their props: where another plugin renders a forms screen with a `WidgetSlot` |
|
|
25
|
+
|
|
26
|
+
```tsx
|
|
27
|
+
import { WidgetSlot } from '@fayz-ai/admin'
|
|
28
|
+
import { FORMS_ZONES } from '@fayz-ai/forms/views/zones'
|
|
29
|
+
|
|
30
|
+
<WidgetSlot zone={FORMS_ZONES.personChecklist} personId={clientId} onFill={setFilling} />
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
The zones are filled by `@fayz-ai/plugin-forms` (`createCustomFormsPlugin()`). An app that does not mount it gets an empty zone.
|
|
34
|
+
|
|
35
|
+
Words used here are defined in [GLOSSARY.md](./GLOSSARY.md).
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import { personRequirements } from './chunk-LQJONAVT.js';
|
|
2
|
+
|
|
3
|
+
// src/data/mock.ts
|
|
4
|
+
function uuid() {
|
|
5
|
+
return crypto.randomUUID();
|
|
6
|
+
}
|
|
7
|
+
function now() {
|
|
8
|
+
return (/* @__PURE__ */ new Date()).toISOString();
|
|
9
|
+
}
|
|
10
|
+
function createMockFormsProvider() {
|
|
11
|
+
const templates = [];
|
|
12
|
+
const documents = [];
|
|
13
|
+
const files = [];
|
|
14
|
+
return {
|
|
15
|
+
async getTemplates(query) {
|
|
16
|
+
let filtered = templates.filter((t) => !t.isDeleted && t.isCurrent);
|
|
17
|
+
if (query.category) {
|
|
18
|
+
filtered = filtered.filter((t) => t.category === query.category);
|
|
19
|
+
}
|
|
20
|
+
if (query.search) {
|
|
21
|
+
const s = query.search.toLowerCase();
|
|
22
|
+
filtered = filtered.filter((t) => t.name.toLowerCase().includes(s));
|
|
23
|
+
}
|
|
24
|
+
const page = query.page ?? 1;
|
|
25
|
+
const pageSize = query.pageSize ?? 25;
|
|
26
|
+
const start = (page - 1) * pageSize;
|
|
27
|
+
return { data: filtered.slice(start, start + pageSize), total: filtered.length };
|
|
28
|
+
},
|
|
29
|
+
async getTemplateById(id) {
|
|
30
|
+
return templates.find((t) => t.id === id && !t.isDeleted) ?? null;
|
|
31
|
+
},
|
|
32
|
+
async createTemplate(input) {
|
|
33
|
+
const template = {
|
|
34
|
+
id: uuid(),
|
|
35
|
+
tenantId: "mock-tenant",
|
|
36
|
+
name: input.name,
|
|
37
|
+
description: input.description,
|
|
38
|
+
category: input.category,
|
|
39
|
+
version: 1,
|
|
40
|
+
isCurrent: true,
|
|
41
|
+
schema: input.schema,
|
|
42
|
+
specialty: input.specialty,
|
|
43
|
+
tags: input.tags ?? [],
|
|
44
|
+
metadata: input.metadata ?? {},
|
|
45
|
+
isActive: true,
|
|
46
|
+
isDeleted: false,
|
|
47
|
+
requiredOnAttendance: false,
|
|
48
|
+
alertWhenMissing: false,
|
|
49
|
+
validityDays: null,
|
|
50
|
+
createdAt: now(),
|
|
51
|
+
updatedAt: now()
|
|
52
|
+
};
|
|
53
|
+
templates.push(template);
|
|
54
|
+
return template;
|
|
55
|
+
},
|
|
56
|
+
async updateTemplate(id, input) {
|
|
57
|
+
const idx = templates.findIndex((t) => t.id === id);
|
|
58
|
+
if (idx === -1) throw new Error("Template not found");
|
|
59
|
+
const existing = templates[idx];
|
|
60
|
+
const updated = {
|
|
61
|
+
...existing,
|
|
62
|
+
...input,
|
|
63
|
+
tags: input.tags ?? existing.tags,
|
|
64
|
+
metadata: input.metadata ?? existing.metadata,
|
|
65
|
+
schema: input.schema ?? existing.schema,
|
|
66
|
+
updatedAt: now()
|
|
67
|
+
};
|
|
68
|
+
templates[idx] = updated;
|
|
69
|
+
return updated;
|
|
70
|
+
},
|
|
71
|
+
async deleteTemplate(id) {
|
|
72
|
+
const idx = templates.findIndex((t) => t.id === id);
|
|
73
|
+
if (idx !== -1) templates[idx] = { ...templates[idx], isDeleted: true };
|
|
74
|
+
},
|
|
75
|
+
async getTemplateUsage() {
|
|
76
|
+
const usage = {};
|
|
77
|
+
for (const doc of documents) {
|
|
78
|
+
if (doc.isDeleted || !doc.templateId) continue;
|
|
79
|
+
const current = usage[doc.templateId] ?? { documentCount: 0, lastDocumentAt: null };
|
|
80
|
+
current.documentCount += 1;
|
|
81
|
+
if (!current.lastDocumentAt || doc.createdAt > current.lastDocumentAt) {
|
|
82
|
+
current.lastDocumentAt = doc.createdAt;
|
|
83
|
+
}
|
|
84
|
+
usage[doc.templateId] = current;
|
|
85
|
+
}
|
|
86
|
+
return usage;
|
|
87
|
+
},
|
|
88
|
+
async getDocuments(query) {
|
|
89
|
+
let filtered = documents.filter((d) => !d.isDeleted);
|
|
90
|
+
if (query.personId) {
|
|
91
|
+
filtered = filtered.filter((d) => d.personId === query.personId);
|
|
92
|
+
}
|
|
93
|
+
if (query.templateId) {
|
|
94
|
+
filtered = filtered.filter((d) => d.templateId === query.templateId);
|
|
95
|
+
}
|
|
96
|
+
if (query.status) {
|
|
97
|
+
const statuses = Array.isArray(query.status) ? query.status : [query.status];
|
|
98
|
+
filtered = filtered.filter((d) => statuses.includes(d.status));
|
|
99
|
+
}
|
|
100
|
+
if (query.search) {
|
|
101
|
+
const s = query.search.toLowerCase();
|
|
102
|
+
filtered = filtered.filter(
|
|
103
|
+
(d) => d.title?.toLowerCase().includes(s) || d.templateName?.toLowerCase().includes(s)
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
if (query.kinds?.length) {
|
|
107
|
+
filtered = filtered.filter((d) => query.kinds.includes(d.kind ?? "form"));
|
|
108
|
+
}
|
|
109
|
+
if (query.templateCategory) {
|
|
110
|
+
filtered = filtered.filter((d) => (d.templateCategory ?? "general") === query.templateCategory);
|
|
111
|
+
}
|
|
112
|
+
filtered.sort((a, b) => b.createdAt.localeCompare(a.createdAt));
|
|
113
|
+
const page = query.page ?? 1;
|
|
114
|
+
const pageSize = query.pageSize ?? 25;
|
|
115
|
+
const start = (page - 1) * pageSize;
|
|
116
|
+
return { data: filtered.slice(start, start + pageSize), total: filtered.length };
|
|
117
|
+
},
|
|
118
|
+
async getDocumentCounts(query) {
|
|
119
|
+
const counts = {};
|
|
120
|
+
for (const d of documents) {
|
|
121
|
+
if (d.isDeleted || d.status === "archived") continue;
|
|
122
|
+
if (d.personId !== query.personId) continue;
|
|
123
|
+
if (query.kinds?.length && !query.kinds.includes(d.kind ?? "form")) continue;
|
|
124
|
+
const bucket = d.kind === "image" || d.kind === "attachment" ? "file" : d.templateCategory ?? "general";
|
|
125
|
+
counts[bucket] = (counts[bucket] ?? 0) + 1;
|
|
126
|
+
}
|
|
127
|
+
return counts;
|
|
128
|
+
},
|
|
129
|
+
async getDocumentById(id) {
|
|
130
|
+
return documents.find((d) => d.id === id && !d.isDeleted) ?? null;
|
|
131
|
+
},
|
|
132
|
+
async createDocument(input) {
|
|
133
|
+
const template = templates.find((t) => t.id === input.templateId);
|
|
134
|
+
const doc = {
|
|
135
|
+
id: uuid(),
|
|
136
|
+
tenantId: "mock-tenant",
|
|
137
|
+
templateId: input.templateId ?? "",
|
|
138
|
+
templateName: template?.name,
|
|
139
|
+
templateCategory: template?.category,
|
|
140
|
+
personId: input.personId,
|
|
141
|
+
title: input.title,
|
|
142
|
+
data: input.data ?? {},
|
|
143
|
+
kind: input.kind ?? (input.templateId ? "form" : "attachment"),
|
|
144
|
+
status: input.status ?? "draft",
|
|
145
|
+
metadata: {},
|
|
146
|
+
isDeleted: false,
|
|
147
|
+
createdAt: now(),
|
|
148
|
+
updatedAt: now()
|
|
149
|
+
};
|
|
150
|
+
documents.push(doc);
|
|
151
|
+
return doc;
|
|
152
|
+
},
|
|
153
|
+
async updateDocument(id, input) {
|
|
154
|
+
const idx = documents.findIndex((d) => d.id === id);
|
|
155
|
+
if (idx === -1) throw new Error("Document not found");
|
|
156
|
+
const existing = documents[idx];
|
|
157
|
+
const updated = {
|
|
158
|
+
...existing,
|
|
159
|
+
...input,
|
|
160
|
+
data: input.data ?? existing.data,
|
|
161
|
+
updatedAt: now()
|
|
162
|
+
};
|
|
163
|
+
documents[idx] = updated;
|
|
164
|
+
return updated;
|
|
165
|
+
},
|
|
166
|
+
async deleteDocument(id) {
|
|
167
|
+
const idx = documents.findIndex((d) => d.id === id);
|
|
168
|
+
if (idx !== -1) documents[idx] = { ...documents[idx], isDeleted: true };
|
|
169
|
+
},
|
|
170
|
+
async getDocumentFiles(documentId) {
|
|
171
|
+
return files.filter((f) => f.documentId === documentId);
|
|
172
|
+
},
|
|
173
|
+
async uploadFile(documentId, fieldKey, file) {
|
|
174
|
+
const docFile = {
|
|
175
|
+
id: uuid(),
|
|
176
|
+
tenantId: "mock-tenant",
|
|
177
|
+
documentId,
|
|
178
|
+
fieldKey,
|
|
179
|
+
fileUrl: URL.createObjectURL(file),
|
|
180
|
+
fileName: file.name,
|
|
181
|
+
fileSize: file.size,
|
|
182
|
+
mimeType: file.type,
|
|
183
|
+
sortOrder: files.filter((f) => f.documentId === documentId && f.fieldKey === fieldKey).length,
|
|
184
|
+
metadata: {},
|
|
185
|
+
createdAt: now()
|
|
186
|
+
};
|
|
187
|
+
files.push(docFile);
|
|
188
|
+
return docFile;
|
|
189
|
+
},
|
|
190
|
+
async uploadMedia(blob) {
|
|
191
|
+
return { path: URL.createObjectURL(blob) };
|
|
192
|
+
},
|
|
193
|
+
async mediaUrl(path) {
|
|
194
|
+
return path;
|
|
195
|
+
},
|
|
196
|
+
async searchCatalog() {
|
|
197
|
+
return [];
|
|
198
|
+
},
|
|
199
|
+
async deleteFile(fileId) {
|
|
200
|
+
const idx = files.findIndex((f) => f.id === fileId);
|
|
201
|
+
if (idx !== -1) files.splice(idx, 1);
|
|
202
|
+
},
|
|
203
|
+
async getPersonRequirements(personId) {
|
|
204
|
+
return personRequirements(templates, documents, personId, now().slice(0, 10));
|
|
205
|
+
}
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
export { createMockFormsProvider };
|
|
210
|
+
//# sourceMappingURL=chunk-2KVTEW7I.js.map
|
|
211
|
+
//# sourceMappingURL=chunk-2KVTEW7I.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/data/mock.ts"],"names":[],"mappings":"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","file":"chunk-2KVTEW7I.js","sourcesContent":["import type {\n CreateDocumentInput,\n DocumentCounts,\n DocumentFile,\n DocumentQuery,\n FormDocument,\n PaginatedResult,\n UpdateDocumentInput,\n} from '../domain/document'\nimport { personRequirements, type PersonFormRequirement } from '../domain/requirement'\nimport type {\n CreateTemplateInput,\n FormTemplate,\n TemplateQuery,\n TemplateUsage,\n UpdateTemplateInput,\n} from '../domain/template'\nimport type { FormsDataProvider } from './provider'\n\nfunction uuid() {\n return crypto.randomUUID()\n}\n\nfunction now() {\n return new Date().toISOString()\n}\n\nexport function createMockFormsProvider(): FormsDataProvider {\n const templates: FormTemplate[] = []\n const documents: FormDocument[] = []\n const files: DocumentFile[] = []\n\n return {\n async getTemplates(query: TemplateQuery): Promise<PaginatedResult<FormTemplate>> {\n let filtered = templates.filter((t) => !t.isDeleted && t.isCurrent)\n if (query.category) {\n filtered = filtered.filter((t) => t.category === query.category)\n }\n if (query.search) {\n const s = query.search.toLowerCase()\n filtered = filtered.filter((t) => t.name.toLowerCase().includes(s))\n }\n const page = query.page ?? 1\n const pageSize = query.pageSize ?? 25\n const start = (page - 1) * pageSize\n return { data: filtered.slice(start, start + pageSize), total: filtered.length }\n },\n\n async getTemplateById(id: string): Promise<FormTemplate | null> {\n return templates.find((t) => t.id === id && !t.isDeleted) ?? null\n },\n\n async createTemplate(input: CreateTemplateInput): Promise<FormTemplate> {\n const template: FormTemplate = {\n id: uuid(),\n tenantId: 'mock-tenant',\n name: input.name,\n description: input.description,\n category: input.category,\n version: 1,\n isCurrent: true,\n schema: input.schema,\n specialty: input.specialty,\n tags: input.tags ?? [],\n metadata: input.metadata ?? {},\n isActive: true,\n isDeleted: false,\n requiredOnAttendance: false,\n alertWhenMissing: false,\n validityDays: null,\n createdAt: now(),\n updatedAt: now(),\n }\n templates.push(template)\n return template\n },\n\n async updateTemplate(id: string, input: UpdateTemplateInput): Promise<FormTemplate> {\n const idx = templates.findIndex((t) => t.id === id)\n if (idx === -1) throw new Error('Template not found')\n const existing = templates[idx]\n const updated: FormTemplate = {\n ...existing,\n ...input,\n tags: input.tags ?? existing.tags,\n metadata: input.metadata ?? existing.metadata,\n schema: input.schema ?? existing.schema,\n updatedAt: now(),\n }\n templates[idx] = updated\n return updated\n },\n\n async deleteTemplate(id: string): Promise<void> {\n const idx = templates.findIndex((t) => t.id === id)\n if (idx !== -1) templates[idx] = { ...templates[idx], isDeleted: true }\n },\n\n async getTemplateUsage(): Promise<Record<string, TemplateUsage>> {\n const usage: Record<string, TemplateUsage> = {}\n for (const doc of documents) {\n if (doc.isDeleted || !doc.templateId) continue\n const current = usage[doc.templateId] ?? { documentCount: 0, lastDocumentAt: null }\n current.documentCount += 1\n if (!current.lastDocumentAt || doc.createdAt > current.lastDocumentAt) {\n current.lastDocumentAt = doc.createdAt\n }\n usage[doc.templateId] = current\n }\n return usage\n },\n\n async getDocuments(query: DocumentQuery): Promise<PaginatedResult<FormDocument>> {\n let filtered = documents.filter((d) => !d.isDeleted)\n if (query.personId) {\n filtered = filtered.filter((d) => d.personId === query.personId)\n }\n if (query.templateId) {\n filtered = filtered.filter((d) => d.templateId === query.templateId)\n }\n if (query.status) {\n const statuses = Array.isArray(query.status) ? query.status : [query.status]\n filtered = filtered.filter((d) => statuses.includes(d.status))\n }\n if (query.search) {\n const s = query.search.toLowerCase()\n filtered = filtered.filter(\n (d) =>\n d.title?.toLowerCase().includes(s) ||\n d.templateName?.toLowerCase().includes(s),\n )\n }\n if (query.kinds?.length) {\n filtered = filtered.filter((d) => query.kinds!.includes(d.kind ?? 'form'))\n }\n if (query.templateCategory) {\n filtered = filtered.filter((d) => (d.templateCategory ?? 'general') === query.templateCategory)\n }\n filtered.sort((a, b) => b.createdAt.localeCompare(a.createdAt))\n const page = query.page ?? 1\n const pageSize = query.pageSize ?? 25\n const start = (page - 1) * pageSize\n return { data: filtered.slice(start, start + pageSize), total: filtered.length }\n },\n\n async getDocumentCounts(query: { personId: string; kinds?: string[] }): Promise<DocumentCounts> {\n const counts: DocumentCounts = {}\n for (const d of documents) {\n if (d.isDeleted || d.status === 'archived') continue\n if (d.personId !== query.personId) continue\n if (query.kinds?.length && !query.kinds.includes(d.kind ?? 'form')) continue\n const bucket = d.kind === 'image' || d.kind === 'attachment'\n ? 'file'\n : (d.templateCategory ?? 'general')\n counts[bucket] = (counts[bucket] ?? 0) + 1\n }\n return counts\n },\n\n async getDocumentById(id: string): Promise<FormDocument | null> {\n return documents.find((d) => d.id === id && !d.isDeleted) ?? null\n },\n\n async createDocument(input: CreateDocumentInput): Promise<FormDocument> {\n const template = templates.find((t) => t.id === input.templateId)\n const doc: FormDocument = {\n id: uuid(),\n tenantId: 'mock-tenant',\n templateId: input.templateId ?? '',\n templateName: template?.name,\n templateCategory: template?.category,\n personId: input.personId,\n title: input.title,\n data: input.data ?? {},\n kind: input.kind ?? (input.templateId ? 'form' : 'attachment'),\n status: input.status ?? 'draft',\n metadata: {},\n isDeleted: false,\n createdAt: now(),\n updatedAt: now(),\n }\n documents.push(doc)\n return doc\n },\n\n async updateDocument(id: string, input: UpdateDocumentInput): Promise<FormDocument> {\n const idx = documents.findIndex((d) => d.id === id)\n if (idx === -1) throw new Error('Document not found')\n const existing = documents[idx]\n const updated: FormDocument = {\n ...existing,\n ...input,\n data: input.data ?? existing.data,\n updatedAt: now(),\n }\n documents[idx] = updated\n return updated\n },\n\n async deleteDocument(id: string): Promise<void> {\n const idx = documents.findIndex((d) => d.id === id)\n if (idx !== -1) documents[idx] = { ...documents[idx], isDeleted: true }\n },\n\n async getDocumentFiles(documentId: string): Promise<DocumentFile[]> {\n return files.filter((f) => f.documentId === documentId)\n },\n\n async uploadFile(documentId: string, fieldKey: string, file: File): Promise<DocumentFile> {\n const docFile: DocumentFile = {\n id: uuid(),\n tenantId: 'mock-tenant',\n documentId,\n fieldKey,\n fileUrl: URL.createObjectURL(file),\n fileName: file.name,\n fileSize: file.size,\n mimeType: file.type,\n sortOrder: files.filter((f) => f.documentId === documentId && f.fieldKey === fieldKey).length,\n metadata: {},\n createdAt: now(),\n }\n files.push(docFile)\n return docFile\n },\n\n async uploadMedia(blob: Blob) {\n return { path: URL.createObjectURL(blob) }\n },\n\n async mediaUrl(path: string) {\n return path\n },\n\n async searchCatalog() {\n return []\n },\n\n async deleteFile(fileId: string): Promise<void> {\n const idx = files.findIndex((f) => f.id === fileId)\n if (idx !== -1) files.splice(idx, 1)\n },\n\n async getPersonRequirements(personId: string): Promise<PersonFormRequirement[]> {\n return personRequirements(templates, documents, personId, now().slice(0, 10))\n },\n }\n}\n"]}
|