@inspectorhub/field-ui 0.0.0-stage → 0.2.1

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.
@@ -0,0 +1,612 @@
1
+ import "./chunk-MLKGABMK.js";
2
+
3
+ // src/testing/fake-data-source.ts
4
+ import * as Y from "yjs";
5
+
6
+ // src/testing/fake-resources.ts
7
+ function createFakeTemplateSearch(initial) {
8
+ let result = initial ?? { templates: [], hasMore: false, page: 1, totalPages: 1 };
9
+ const searches = [];
10
+ return {
11
+ get searches() {
12
+ return searches;
13
+ },
14
+ setResult(next) {
15
+ result = next;
16
+ },
17
+ search: async (input) => {
18
+ searches.push(input);
19
+ return result;
20
+ }
21
+ };
22
+ }
23
+ function createFakeCommentsLibrary(initial = []) {
24
+ let rows = initial;
25
+ let saveFailure = null;
26
+ const lists = [];
27
+ const touches = [];
28
+ const saves = [];
29
+ const edits = [];
30
+ return {
31
+ get lists() {
32
+ return lists;
33
+ },
34
+ get touches() {
35
+ return touches;
36
+ },
37
+ saved: () => saves,
38
+ edited: () => edits,
39
+ setRows(next) {
40
+ rows = next;
41
+ },
42
+ failSave(error) {
43
+ saveFailure = error;
44
+ },
45
+ list: async (query) => {
46
+ lists.push(query);
47
+ return rows;
48
+ },
49
+ touch: async (id) => {
50
+ touches.push(id);
51
+ return { ok: true };
52
+ },
53
+ save: async (entry) => {
54
+ if (saveFailure !== null) return { ok: false, error: saveFailure };
55
+ saves.push(entry);
56
+ return { ok: true };
57
+ },
58
+ edit: async (id, entry) => {
59
+ edits.push({ id, entry });
60
+ return { ok: true };
61
+ }
62
+ };
63
+ }
64
+ function createFakeAiAssist() {
65
+ const runs = [];
66
+ let assist = { ok: true, intent: "assist", text: "Improved note", aiCallId: "ai-call-1" };
67
+ let review = { ok: true, intent: "review" };
68
+ let gate = null;
69
+ return {
70
+ get runs() {
71
+ return runs;
72
+ },
73
+ answerAssist(result) {
74
+ assist = result;
75
+ },
76
+ answerReview(result) {
77
+ review = result;
78
+ },
79
+ hold() {
80
+ let release = () => void 0;
81
+ gate = new Promise((resolve) => {
82
+ release = resolve;
83
+ });
84
+ return () => {
85
+ gate = null;
86
+ release();
87
+ };
88
+ },
89
+ run: async (input) => {
90
+ runs.push(input);
91
+ if (gate !== null) await gate;
92
+ return input.intent === "assist" ? assist : review;
93
+ }
94
+ };
95
+ }
96
+ function createFakeCostItems(initial = []) {
97
+ let items = initial;
98
+ let reserveEnabled = false;
99
+ let saveFails = false;
100
+ let gate = null;
101
+ let stored = 0;
102
+ const lists = [];
103
+ const writes = [];
104
+ return {
105
+ get lists() {
106
+ return lists;
107
+ },
108
+ get writes() {
109
+ return writes;
110
+ },
111
+ setItems(next) {
112
+ items = next;
113
+ },
114
+ setReserveEnabled(enabled) {
115
+ reserveEnabled = enabled;
116
+ },
117
+ failSave() {
118
+ saveFails = true;
119
+ },
120
+ hold() {
121
+ let release = () => void 0;
122
+ gate = new Promise((resolve) => {
123
+ release = resolve;
124
+ });
125
+ return () => {
126
+ gate = null;
127
+ release();
128
+ };
129
+ },
130
+ list: async (inspectionId) => {
131
+ lists.push(inspectionId);
132
+ return { items, reserveEnabled };
133
+ },
134
+ save: async (inspectionId, write) => {
135
+ writes.push({ inspectionId, write });
136
+ if (gate !== null) await gate;
137
+ if (saveFails) return { ok: false };
138
+ if (write.intent === "create") {
139
+ stored += 1;
140
+ return { ok: true, data: { id: `stored-${stored}` } };
141
+ }
142
+ return { ok: true };
143
+ }
144
+ };
145
+ }
146
+
147
+ // src/testing/fake-panel-resources.ts
148
+ function notOk(failure) {
149
+ return failure.error === void 0 ? { ok: false } : { ok: false, error: failure.error };
150
+ }
151
+ function createFakeVersionHistory(initial = []) {
152
+ const captures = [];
153
+ const restores = [];
154
+ const gets = [];
155
+ let snapshots = initial;
156
+ let content = { projection: {} };
157
+ let lists = 0;
158
+ let listFailure = null;
159
+ let getFailure = null;
160
+ let captureFailure = null;
161
+ let restoreFailure = null;
162
+ return {
163
+ get captures() {
164
+ return captures;
165
+ },
166
+ get restores() {
167
+ return restores;
168
+ },
169
+ get gets() {
170
+ return gets;
171
+ },
172
+ get lists() {
173
+ return lists;
174
+ },
175
+ setSnapshots(next) {
176
+ snapshots = next;
177
+ },
178
+ setContent(next) {
179
+ content = next;
180
+ },
181
+ failList(error) {
182
+ listFailure = error === void 0 ? {} : { error };
183
+ },
184
+ failGet(error) {
185
+ getFailure = error === void 0 ? {} : { error };
186
+ },
187
+ failCapture(error) {
188
+ captureFailure = error;
189
+ },
190
+ failRestore(error) {
191
+ restoreFailure = error;
192
+ },
193
+ list: async () => {
194
+ lists += 1;
195
+ return listFailure === null ? { ok: true, data: snapshots } : notOk(listFailure);
196
+ },
197
+ get: async (inspectionId, seq) => {
198
+ gets.push({ inspectionId, seq });
199
+ return getFailure === null ? { ok: true, data: content } : notOk(getFailure);
200
+ },
201
+ restore: async (inspectionId, seq) => {
202
+ restores.push({ inspectionId, seq });
203
+ return restoreFailure === null ? { ok: true } : { ok: false, error: restoreFailure };
204
+ },
205
+ capture: async (inspectionId) => {
206
+ captures.push(inspectionId);
207
+ return captureFailure === null ? { ok: true } : { ok: false, error: captureFailure };
208
+ }
209
+ };
210
+ }
211
+ function createFakeVideo() {
212
+ const posters = [];
213
+ const createUploads = [];
214
+ const uploadedFiles = [];
215
+ const finalizes = [];
216
+ let posterUploads = 0;
217
+ let ticket = {
218
+ uploadURL: "https://upload.example/stream",
219
+ provider: "stream",
220
+ ref: { provider: "stream", streamUid: "uid-1" }
221
+ };
222
+ let createFailure = null;
223
+ let fileFailure = null;
224
+ let finalizeFailure = null;
225
+ let createGate = null;
226
+ return {
227
+ get posters() {
228
+ return posters;
229
+ },
230
+ get createUploads() {
231
+ return createUploads;
232
+ },
233
+ get uploadedFiles() {
234
+ return uploadedFiles;
235
+ },
236
+ get posterUploads() {
237
+ return posterUploads;
238
+ },
239
+ get finalizes() {
240
+ return finalizes;
241
+ },
242
+ setTicket(next) {
243
+ ticket = next;
244
+ },
245
+ failCreateUpload(error) {
246
+ createFailure = error === void 0 ? {} : { error };
247
+ },
248
+ failUploadFile(error) {
249
+ fileFailure = error === void 0 ? {} : { error };
250
+ },
251
+ failFinalize(error) {
252
+ finalizeFailure = error === void 0 ? {} : { error };
253
+ },
254
+ holdCreateUpload() {
255
+ let release = () => void 0;
256
+ createGate = new Promise((resolve) => {
257
+ release = resolve;
258
+ });
259
+ return () => {
260
+ createGate = null;
261
+ release();
262
+ };
263
+ },
264
+ createUpload: async (inspectionId, input) => {
265
+ createUploads.push({ inspectionId, input });
266
+ if (createGate !== null) await createGate;
267
+ return createFailure === null ? { ok: true, data: ticket } : notOk(createFailure);
268
+ },
269
+ uploadFile: async (t, file, onProgress) => {
270
+ uploadedFiles.push(file instanceof File ? file.name : "blob");
271
+ onProgress(100);
272
+ if (fileFailure !== null) return notOk(fileFailure);
273
+ return t.provider === "r2" ? { ok: true, data: { mediaId: "media-1", r2Key: "r2/media-1.mp4" } } : { ok: true };
274
+ },
275
+ uploadPoster: async () => {
276
+ posterUploads += 1;
277
+ return { ok: true, data: { posterKey: "poster-1" } };
278
+ },
279
+ setPoster: async (inspectionId, input) => {
280
+ posters.push({ inspectionId, ...input });
281
+ return { ok: true };
282
+ },
283
+ finalize: async (inspectionId, input) => {
284
+ finalizes.push({ inspectionId, input });
285
+ return finalizeFailure === null ? { ok: true, data: { poolId: "pool-1" } } : notOk(finalizeFailure);
286
+ },
287
+ remove: async () => ({ ok: true })
288
+ };
289
+ }
290
+ function createFakeRepairItems(initial = []) {
291
+ let items = initial;
292
+ let lists = 0;
293
+ return {
294
+ get lists() {
295
+ return lists;
296
+ },
297
+ setItems(next) {
298
+ items = next;
299
+ },
300
+ list: async () => {
301
+ lists += 1;
302
+ return items;
303
+ }
304
+ };
305
+ }
306
+ function createFakeMediaPool(initial) {
307
+ let listing = initial ?? { photos: [], answered: true };
308
+ const lists = [];
309
+ return {
310
+ get lists() {
311
+ return lists;
312
+ },
313
+ setListing(next) {
314
+ listing = next;
315
+ },
316
+ list: async (inspectionId) => {
317
+ lists.push(inspectionId);
318
+ return listing;
319
+ }
320
+ };
321
+ }
322
+ function createFakeSettingsSheet(initial) {
323
+ let data = initial === void 0 ? { inspection: null, templates: [], photos: [], profiles: [] } : initial;
324
+ const loads = [];
325
+ return {
326
+ get loads() {
327
+ return loads;
328
+ },
329
+ setData(next) {
330
+ data = next;
331
+ },
332
+ load: async (inspectionId) => {
333
+ loads.push(inspectionId);
334
+ return data;
335
+ }
336
+ };
337
+ }
338
+
339
+ // src/testing/fake-data-source.ts
340
+ var DEFAULT_SESSION = {
341
+ tenantSlug: null,
342
+ videoProvider: "r2",
343
+ streamCustomerSubdomain: null,
344
+ collabEditing: false,
345
+ userId: "fake-user",
346
+ locale: "en-US",
347
+ timeZone: null,
348
+ dateFormat: "us",
349
+ timeFormat: "12h",
350
+ tenantDateFormat: "us",
351
+ tenantTimeFormat: "12h",
352
+ // The package never interprets a role (`SessionInfo.role` is the host's string), so the
353
+ // fake uses a neutral value instead of one of the engine's role names.
354
+ role: "fake-role"
355
+ };
356
+ function pick(value, fallback) {
357
+ return value === void 0 ? fallback : value;
358
+ }
359
+ function commandKey(cmd) {
360
+ return "op" in cmd ? `${cmd.type}:${cmd.op}` : cmd.type;
361
+ }
362
+ var DEFAULT_URLS = {
363
+ photo: (inspectionId, key) => `/fake/photos/${inspectionId}/${key}`,
364
+ reportPreview: () => null,
365
+ reportPdf: () => null,
366
+ costExport: (inspectionId, format) => `/fake/cost-export/${inspectionId}.${format}`,
367
+ statutoryPreviewPdf: () => null,
368
+ videoObject: () => null,
369
+ presenceSocket: (inspectionId) => `ws://fake.invalid/api/inspections/${inspectionId}/presence/ws`,
370
+ editorPath: (inspectionId) => `/inspections/${inspectionId}/edit`,
371
+ inspectionsList: () => "/inspections"
372
+ };
373
+ var EMPTY_PCA_NARRATIVE = {
374
+ transmittalLetter: "",
375
+ summaryGeneralDescription: "",
376
+ summaryPhysicalCondition: "",
377
+ summaryRecommendations: "",
378
+ purpose: "",
379
+ scopeOfWork: "",
380
+ limitationsExceptions: "",
381
+ reconnaissance: "",
382
+ additionalConsiderations: ""
383
+ };
384
+ function createEmptyEditorData(overrides = {}) {
385
+ return {
386
+ inspection: { id: "insp-1", propertyAddress: "1 Main St" },
387
+ schema: { sections: [] },
388
+ results: {},
389
+ ratingLevels: [],
390
+ tagLibrary: [],
391
+ defectCategories: [],
392
+ units: [],
393
+ unitProgress: { units: [], commonRated: 0, total: 0 },
394
+ unitInspectionMode: "tagged",
395
+ templateSnapshot: { schemaVersion: 2, sections: [] },
396
+ revisionStatus: null,
397
+ statutoryDetails: null,
398
+ statutoryCoverage: null,
399
+ compliance: {
400
+ reportSignoffs: [],
401
+ psq: null,
402
+ documentReview: [],
403
+ conformance: { standard: "E2018-24", conforms: false }
404
+ },
405
+ pcaNarrative: { ...EMPTY_PCA_NARRATIVE },
406
+ relianceText: { userReliance: "", pointInTime: "", siteSpecific: "" },
407
+ commercialPresets: {},
408
+ nextPublishIsAmendment: false,
409
+ outboundCoolingWindow: null,
410
+ resultId: null,
411
+ ...overrides
412
+ };
413
+ }
414
+ var DEFAULT_PREFS = {
415
+ cloneDefault: "rating_notes",
416
+ autoAdvance: "always",
417
+ autoAdvanceDelayMs: 200,
418
+ pinnedTagIds: [],
419
+ requireDefectFields: "none",
420
+ agentRepairAccess: "readwrite",
421
+ reportLinkTtl: "never"
422
+ };
423
+ function createFakePrefs(initial = {}) {
424
+ let current = { ...DEFAULT_PREFS, ...initial };
425
+ let failure = null;
426
+ const patches = [];
427
+ return {
428
+ get patches() {
429
+ return patches;
430
+ },
431
+ failPatch(error) {
432
+ failure = error;
433
+ },
434
+ load: async () => ({ ...current, pinnedTagIds: [...current.pinnedTagIds] }),
435
+ patch: async (delta) => {
436
+ if (failure !== null) return { ok: false, error: failure };
437
+ patches.push(delta);
438
+ current = { ...current, ...delta };
439
+ return { ok: true, data: { ...current, pinnedTagIds: [...current.pinnedTagIds] } };
440
+ }
441
+ };
442
+ }
443
+ function createFakeDataSource(seed) {
444
+ const commands = [];
445
+ const purged = [];
446
+ const notifications = [];
447
+ const uploads = [];
448
+ let uploadFailure = null;
449
+ const failures = /* @__PURE__ */ new Map();
450
+ const responses = /* @__PURE__ */ new Map();
451
+ const records = /* @__PURE__ */ new Map();
452
+ const listeners = /* @__PURE__ */ new Set();
453
+ let online = seed.online ?? true;
454
+ let putFailure = null;
455
+ let reloadCount = 0;
456
+ let exitCount = 0;
457
+ let restartCount = 0;
458
+ const openedUrls = [];
459
+ const ds = {
460
+ get commands() {
461
+ return commands;
462
+ },
463
+ get purged() {
464
+ return purged;
465
+ },
466
+ get notifications() {
467
+ return notifications;
468
+ },
469
+ get uploads() {
470
+ return uploads;
471
+ },
472
+ failUpload(error) {
473
+ uploadFailure = error;
474
+ },
475
+ get reloadCount() {
476
+ return reloadCount;
477
+ },
478
+ get restartCount() {
479
+ return restartCount;
480
+ },
481
+ get openedUrls() {
482
+ return openedUrls;
483
+ },
484
+ get exitCount() {
485
+ return exitCount;
486
+ },
487
+ failExecute(type, error) {
488
+ failures.set(type, error);
489
+ },
490
+ failMediaPut(error) {
491
+ putFailure = error;
492
+ },
493
+ respondWith(key, data) {
494
+ responses.set(key, data);
495
+ },
496
+ setOnline(next) {
497
+ online = next;
498
+ for (const cb of [...listeners]) cb(next);
499
+ },
500
+ load: async () => seed.data,
501
+ session: () => {
502
+ const o = seed.session ?? {};
503
+ return {
504
+ tenantSlug: pick(o.tenantSlug, DEFAULT_SESSION.tenantSlug),
505
+ videoProvider: pick(o.videoProvider, DEFAULT_SESSION.videoProvider),
506
+ streamCustomerSubdomain: pick(o.streamCustomerSubdomain, DEFAULT_SESSION.streamCustomerSubdomain),
507
+ collabEditing: pick(o.collabEditing, DEFAULT_SESSION.collabEditing),
508
+ userId: pick(o.userId, DEFAULT_SESSION.userId),
509
+ role: pick(o.role, DEFAULT_SESSION.role),
510
+ locale: pick(o.locale, DEFAULT_SESSION.locale),
511
+ timeZone: pick(o.timeZone, DEFAULT_SESSION.timeZone),
512
+ dateFormat: pick(o.dateFormat, DEFAULT_SESSION.dateFormat),
513
+ timeFormat: pick(o.timeFormat, DEFAULT_SESSION.timeFormat),
514
+ tenantDateFormat: pick(o.tenantDateFormat, DEFAULT_SESSION.tenantDateFormat),
515
+ tenantTimeFormat: pick(o.tenantTimeFormat, DEFAULT_SESSION.tenantTimeFormat)
516
+ };
517
+ },
518
+ execute: async (inspectionId, cmd, opts) => {
519
+ commands.push(
520
+ opts?.idempotencyKey === void 0 ? { inspectionId, cmd } : { inspectionId, cmd, idempotencyKey: opts.idempotencyKey }
521
+ );
522
+ const error = failures.get(cmd.type);
523
+ const data = responses.get(commandKey(cmd));
524
+ const result = error === void 0 ? { ok: true } : { ok: false, error };
525
+ if (data !== void 0) result.data = data;
526
+ return result;
527
+ },
528
+ notify: (message, variant, opts) => {
529
+ notifications.push({
530
+ message,
531
+ variant,
532
+ ...opts?.durationMs === void 0 ? {} : { durationMs: opts.durationMs },
533
+ ...opts?.action === void 0 ? {} : { action: opts.action }
534
+ });
535
+ },
536
+ reload: () => {
537
+ reloadCount += 1;
538
+ },
539
+ ...seed.without?.includes("restartSession") ? {} : { restartSession: () => void (restartCount += 1) },
540
+ ...seed.without?.includes("openUrl") ? {} : { openUrl: (url) => void openedUrls.push(url) },
541
+ exit: () => {
542
+ exitCount += 1;
543
+ },
544
+ isOnline: () => online,
545
+ onOnlineChange: (cb) => {
546
+ listeners.add(cb);
547
+ return () => {
548
+ listeners.delete(cb);
549
+ };
550
+ },
551
+ collab: {
552
+ connect: (_inspectionId, opts) => {
553
+ const doc = new Y.Doc();
554
+ let destroyed = false;
555
+ doc.on("update", () => {
556
+ if (!destroyed) opts.onChange?.();
557
+ });
558
+ queueMicrotask(() => opts.onSynced?.());
559
+ return {
560
+ doc,
561
+ persistenceSynced: Promise.resolve(),
562
+ synced: () => true,
563
+ destroy: () => {
564
+ destroyed = true;
565
+ doc.destroy();
566
+ }
567
+ };
568
+ },
569
+ purge: async (inspectionId) => {
570
+ purged.push(inspectionId);
571
+ }
572
+ },
573
+ media: {
574
+ store: {
575
+ put: async (rec) => {
576
+ if (putFailure) throw putFailure;
577
+ records.set(rec.pendingId, rec);
578
+ },
579
+ get: async (pendingId) => records.get(pendingId) ?? null,
580
+ list: async (inspectionId) => [...records.values()].filter((r) => inspectionId === void 0 || r.inspectionId === inspectionId),
581
+ delete: async (pendingId) => {
582
+ records.delete(pendingId);
583
+ },
584
+ objectUrl: async (pendingId) => records.has(pendingId) ? `blob:fake/${pendingId}` : null
585
+ },
586
+ uploader: (inspectionId, doc) => ({
587
+ upload: async (rec) => {
588
+ uploads.push({ inspectionId, rec, hadDoc: doc !== null });
589
+ return uploadFailure === null ? { ok: true, key: `uploaded/${rec.pendingId}` } : { ok: false, error: uploadFailure };
590
+ }
591
+ })
592
+ },
593
+ urls: { ...DEFAULT_URLS, ...seed.urls },
594
+ resources: { ...seed.resources },
595
+ platform: seed.platform ?? "web"
596
+ };
597
+ return ds;
598
+ }
599
+ export {
600
+ createEmptyEditorData,
601
+ createFakeAiAssist,
602
+ createFakeCommentsLibrary,
603
+ createFakeCostItems,
604
+ createFakeDataSource,
605
+ createFakeMediaPool,
606
+ createFakePrefs,
607
+ createFakeRepairItems,
608
+ createFakeSettingsSheet,
609
+ createFakeTemplateSearch,
610
+ createFakeVersionHistory,
611
+ createFakeVideo
612
+ };