@murumets-ee/yhikas-sync 0.41.0 → 0.43.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/index.d.mts CHANGED
@@ -175,16 +175,49 @@ declare function planDiff<T>(input: PlanDiffInput<T>): DiffPlan<T>;
175
175
  * NOT `.strict()`: unknown keys are stripped rather than rejected, so adding a
176
176
  * third language upstream degrades to "the sync ignores it" instead of "every
177
177
  * run fails".
178
+ *
179
+ * 🔴 **Each locale key is nullable AND optional, and that is the load-bearing
180
+ * clause** (F058, cross-referenced to upstream F031). The column is declared
181
+ * `json(...).notNull()` — and **notNull covers the OBJECT, not its keys**. There
182
+ * is no CHECK constraint, and two of the four public columns
183
+ * (`room_type.name`, `legal_document.title`) have no upstream validation at all:
184
+ * the write is a raw `formData.get(…) as string`, which is `null` the moment a
185
+ * field is absent. So `{"et":"Tuba","en":null}` — and `{"et":"Tuba"}` — are rows
186
+ * yhikas-admin accepts today, through its ordinary admin UI.
187
+ *
188
+ * Requiring both keys would fail the ENTIRE response for one such row, so 32
189
+ * room types would stop syncing because one lacks an English name — every six
190
+ * hours, until somebody edited it upstream. That is exactly the blast-radius
191
+ * mistake `legalDocumentRowSchema.slug` documents below and deliberately
192
+ * avoided; a missing translation belongs at one row, and `projection.ts` is
193
+ * where it is decided (the locale is suppressed, or the row is skipped with a
194
+ * reason).
195
+ *
196
+ * What is NOT relaxed, on purpose:
197
+ *
198
+ * - **The object itself stays required.** A missing translation is DATA; a
199
+ * missing FIELD is a renamed column or a changed envelope. The consequence of
200
+ * tolerating one is caught either way — `assertSomethingSurvived` refuses a
201
+ * snapshot in which no row survived — but refusing here NAMES it
202
+ * (`title: Required`) instead of reporting 32 identical "no 'et' title
203
+ * upstream" skips and leaving the reader to infer the cause.
204
+ * - **A non-string value is still a shape violation.** `{"en":42}` would
205
+ * otherwise be written as a name.
206
+ *
207
+ * Note the asymmetry this leaves, deliberately: a RENAMED key (`et_EE`) is
208
+ * indistinguishable from two absent ones, because unknown keys are stripped by
209
+ * design so a third language degrades gracefully. That case falls through to
210
+ * `assertSomethingSurvived`, which is exactly what it is for.
178
211
  */
179
212
  declare const multilingualTextSchema: z.ZodObject<{
180
- et: z.ZodString;
181
- en: z.ZodString;
213
+ et: z.ZodOptional<z.ZodNullable<z.ZodString>>;
214
+ en: z.ZodOptional<z.ZodNullable<z.ZodString>>;
182
215
  }, "strip", z.ZodTypeAny, {
183
- et: string;
184
- en: string;
216
+ et?: string | null | undefined;
217
+ en?: string | null | undefined;
185
218
  }, {
186
- et: string;
187
- en: string;
219
+ et?: string | null | undefined;
220
+ en?: string | null | undefined;
188
221
  }>;
189
222
  type MultilingualText = z.infer<typeof multilingualTextSchema>;
190
223
  /**
@@ -199,14 +232,14 @@ type MultilingualText = z.infer<typeof multilingualTextSchema>;
199
232
  declare const roomTypeRowSchema: z.ZodObject<{
200
233
  code: z.ZodString;
201
234
  name: z.ZodObject<{
202
- et: z.ZodString;
203
- en: z.ZodString;
235
+ et: z.ZodOptional<z.ZodNullable<z.ZodString>>;
236
+ en: z.ZodOptional<z.ZodNullable<z.ZodString>>;
204
237
  }, "strip", z.ZodTypeAny, {
205
- et: string;
206
- en: string;
238
+ et?: string | null | undefined;
239
+ en?: string | null | undefined;
207
240
  }, {
208
- et: string;
209
- en: string;
241
+ et?: string | null | undefined;
242
+ en?: string | null | undefined;
210
243
  }>;
211
244
  totalArea: z.ZodNullable<z.ZodString>;
212
245
  livingArea: z.ZodNullable<z.ZodString>;
@@ -219,8 +252,8 @@ declare const roomTypeRowSchema: z.ZodObject<{
219
252
  }, "strip", z.ZodTypeAny, {
220
253
  code: string;
221
254
  name: {
222
- et: string;
223
- en: string;
255
+ et?: string | null | undefined;
256
+ en?: string | null | undefined;
224
257
  };
225
258
  totalArea: string | null;
226
259
  livingArea: string | null;
@@ -233,8 +266,8 @@ declare const roomTypeRowSchema: z.ZodObject<{
233
266
  }, {
234
267
  code: string;
235
268
  name: {
236
- et: string;
237
- en: string;
269
+ et?: string | null | undefined;
270
+ en?: string | null | undefined;
238
271
  };
239
272
  totalArea: string | null;
240
273
  livingArea: string | null;
@@ -258,14 +291,14 @@ type RoomTypeRow = z.infer<typeof roomTypeRowSchema>;
258
291
  declare const legalDocumentRowSchema: z.ZodObject<{
259
292
  type: z.ZodString;
260
293
  title: z.ZodObject<{
261
- et: z.ZodString;
262
- en: z.ZodString;
294
+ et: z.ZodOptional<z.ZodNullable<z.ZodString>>;
295
+ en: z.ZodOptional<z.ZodNullable<z.ZodString>>;
263
296
  }, "strip", z.ZodTypeAny, {
264
- et: string;
265
- en: string;
297
+ et?: string | null | undefined;
298
+ en?: string | null | undefined;
266
299
  }, {
267
- et: string;
268
- en: string;
300
+ et?: string | null | undefined;
301
+ en?: string | null | undefined;
269
302
  }>;
270
303
  /**
271
304
  * Accepted as free text HERE, and screened per-row in the projection.
@@ -286,8 +319,8 @@ declare const legalDocumentRowSchema: z.ZodObject<{
286
319
  type: string;
287
320
  slug: string;
288
321
  title: {
289
- et: string;
290
- en: string;
322
+ et?: string | null | undefined;
323
+ en?: string | null | undefined;
291
324
  };
292
325
  order: number;
293
326
  htmlContentEt: string;
@@ -296,8 +329,8 @@ declare const legalDocumentRowSchema: z.ZodObject<{
296
329
  type: string;
297
330
  slug: string;
298
331
  title: {
299
- et: string;
300
- en: string;
332
+ et?: string | null | undefined;
333
+ en?: string | null | undefined;
301
334
  };
302
335
  order: number;
303
336
  htmlContentEt: string;
@@ -319,14 +352,14 @@ declare const roomTypesResponseSchema: z.ZodObject<{
319
352
  roomTypes: z.ZodArray<z.ZodObject<{
320
353
  code: z.ZodString;
321
354
  name: z.ZodObject<{
322
- et: z.ZodString;
323
- en: z.ZodString;
355
+ et: z.ZodOptional<z.ZodNullable<z.ZodString>>;
356
+ en: z.ZodOptional<z.ZodNullable<z.ZodString>>;
324
357
  }, "strip", z.ZodTypeAny, {
325
- et: string;
326
- en: string;
358
+ et?: string | null | undefined;
359
+ en?: string | null | undefined;
327
360
  }, {
328
- et: string;
329
- en: string;
361
+ et?: string | null | undefined;
362
+ en?: string | null | undefined;
330
363
  }>;
331
364
  totalArea: z.ZodNullable<z.ZodString>;
332
365
  livingArea: z.ZodNullable<z.ZodString>;
@@ -339,8 +372,8 @@ declare const roomTypesResponseSchema: z.ZodObject<{
339
372
  }, "strip", z.ZodTypeAny, {
340
373
  code: string;
341
374
  name: {
342
- et: string;
343
- en: string;
375
+ et?: string | null | undefined;
376
+ en?: string | null | undefined;
344
377
  };
345
378
  totalArea: string | null;
346
379
  livingArea: string | null;
@@ -353,8 +386,8 @@ declare const roomTypesResponseSchema: z.ZodObject<{
353
386
  }, {
354
387
  code: string;
355
388
  name: {
356
- et: string;
357
- en: string;
389
+ et?: string | null | undefined;
390
+ en?: string | null | undefined;
358
391
  };
359
392
  totalArea: string | null;
360
393
  livingArea: string | null;
@@ -370,8 +403,8 @@ declare const roomTypesResponseSchema: z.ZodObject<{
370
403
  roomTypes: {
371
404
  code: string;
372
405
  name: {
373
- et: string;
374
- en: string;
406
+ et?: string | null | undefined;
407
+ en?: string | null | undefined;
375
408
  };
376
409
  totalArea: string | null;
377
410
  livingArea: string | null;
@@ -387,8 +420,8 @@ declare const roomTypesResponseSchema: z.ZodObject<{
387
420
  roomTypes: {
388
421
  code: string;
389
422
  name: {
390
- et: string;
391
- en: string;
423
+ et?: string | null | undefined;
424
+ en?: string | null | undefined;
392
425
  };
393
426
  totalArea: string | null;
394
427
  livingArea: string | null;
@@ -405,14 +438,14 @@ declare const legalDocumentsResponseSchema: z.ZodObject<{
405
438
  documents: z.ZodArray<z.ZodObject<{
406
439
  type: z.ZodString;
407
440
  title: z.ZodObject<{
408
- et: z.ZodString;
409
- en: z.ZodString;
441
+ et: z.ZodOptional<z.ZodNullable<z.ZodString>>;
442
+ en: z.ZodOptional<z.ZodNullable<z.ZodString>>;
410
443
  }, "strip", z.ZodTypeAny, {
411
- et: string;
412
- en: string;
444
+ et?: string | null | undefined;
445
+ en?: string | null | undefined;
413
446
  }, {
414
- et: string;
415
- en: string;
447
+ et?: string | null | undefined;
448
+ en?: string | null | undefined;
416
449
  }>;
417
450
  /**
418
451
  * Accepted as free text HERE, and screened per-row in the projection.
@@ -433,8 +466,8 @@ declare const legalDocumentsResponseSchema: z.ZodObject<{
433
466
  type: string;
434
467
  slug: string;
435
468
  title: {
436
- et: string;
437
- en: string;
469
+ et?: string | null | undefined;
470
+ en?: string | null | undefined;
438
471
  };
439
472
  order: number;
440
473
  htmlContentEt: string;
@@ -443,8 +476,8 @@ declare const legalDocumentsResponseSchema: z.ZodObject<{
443
476
  type: string;
444
477
  slug: string;
445
478
  title: {
446
- et: string;
447
- en: string;
479
+ et?: string | null | undefined;
480
+ en?: string | null | undefined;
448
481
  };
449
482
  order: number;
450
483
  htmlContentEt: string;
@@ -456,8 +489,8 @@ declare const legalDocumentsResponseSchema: z.ZodObject<{
456
489
  type: string;
457
490
  slug: string;
458
491
  title: {
459
- et: string;
460
- en: string;
492
+ et?: string | null | undefined;
493
+ en?: string | null | undefined;
461
494
  };
462
495
  order: number;
463
496
  htmlContentEt: string;
@@ -469,8 +502,8 @@ declare const legalDocumentsResponseSchema: z.ZodObject<{
469
502
  type: string;
470
503
  slug: string;
471
504
  title: {
472
- et: string;
473
- en: string;
505
+ et?: string | null | undefined;
506
+ en?: string | null | undefined;
474
507
  };
475
508
  order: number;
476
509
  htmlContentEt: string;
@@ -491,28 +524,28 @@ declare const legalDocumentsResponseSchema: z.ZodObject<{
491
524
  */
492
525
  declare const siteNoticeRowSchema: z.ZodObject<{
493
526
  text: z.ZodObject<{
494
- et: z.ZodString;
495
- en: z.ZodString;
527
+ et: z.ZodOptional<z.ZodNullable<z.ZodString>>;
528
+ en: z.ZodOptional<z.ZodNullable<z.ZodString>>;
496
529
  }, "strip", z.ZodTypeAny, {
497
- et: string;
498
- en: string;
530
+ et?: string | null | undefined;
531
+ en?: string | null | undefined;
499
532
  }, {
500
- et: string;
501
- en: string;
533
+ et?: string | null | undefined;
534
+ en?: string | null | undefined;
502
535
  }>;
503
536
  isActive: z.ZodBoolean;
504
537
  order: z.ZodNumber;
505
538
  }, "strip", z.ZodTypeAny, {
506
539
  text: {
507
- et: string;
508
- en: string;
540
+ et?: string | null | undefined;
541
+ en?: string | null | undefined;
509
542
  };
510
543
  order: number;
511
544
  isActive: boolean;
512
545
  }, {
513
546
  text: {
514
- et: string;
515
- en: string;
547
+ et?: string | null | undefined;
548
+ en?: string | null | undefined;
516
549
  };
517
550
  order: number;
518
551
  isActive: boolean;
@@ -536,52 +569,52 @@ type SiteNoticeRow = z.infer<typeof siteNoticeRowSchema>;
536
569
  declare const siteInfoResponseSchema: z.ZodObject<{
537
570
  success: z.ZodLiteral<true>;
538
571
  receptionHours: z.ZodObject<{
539
- et: z.ZodString;
540
- en: z.ZodString;
572
+ et: z.ZodOptional<z.ZodNullable<z.ZodString>>;
573
+ en: z.ZodOptional<z.ZodNullable<z.ZodString>>;
541
574
  }, "strip", z.ZodTypeAny, {
542
- et: string;
543
- en: string;
575
+ et?: string | null | undefined;
576
+ en?: string | null | undefined;
544
577
  }, {
545
- et: string;
546
- en: string;
578
+ et?: string | null | undefined;
579
+ en?: string | null | undefined;
547
580
  }>;
548
581
  notices: z.ZodArray<z.ZodObject<{
549
582
  text: z.ZodObject<{
550
- et: z.ZodString;
551
- en: z.ZodString;
583
+ et: z.ZodOptional<z.ZodNullable<z.ZodString>>;
584
+ en: z.ZodOptional<z.ZodNullable<z.ZodString>>;
552
585
  }, "strip", z.ZodTypeAny, {
553
- et: string;
554
- en: string;
586
+ et?: string | null | undefined;
587
+ en?: string | null | undefined;
555
588
  }, {
556
- et: string;
557
- en: string;
589
+ et?: string | null | undefined;
590
+ en?: string | null | undefined;
558
591
  }>;
559
592
  isActive: z.ZodBoolean;
560
593
  order: z.ZodNumber;
561
594
  }, "strip", z.ZodTypeAny, {
562
595
  text: {
563
- et: string;
564
- en: string;
596
+ et?: string | null | undefined;
597
+ en?: string | null | undefined;
565
598
  };
566
599
  order: number;
567
600
  isActive: boolean;
568
601
  }, {
569
602
  text: {
570
- et: string;
571
- en: string;
603
+ et?: string | null | undefined;
604
+ en?: string | null | undefined;
572
605
  };
573
606
  order: number;
574
607
  isActive: boolean;
575
608
  }>, "many">;
576
609
  }, "strip", z.ZodTypeAny, {
577
610
  receptionHours: {
578
- et: string;
579
- en: string;
611
+ et?: string | null | undefined;
612
+ en?: string | null | undefined;
580
613
  };
581
614
  notices: {
582
615
  text: {
583
- et: string;
584
- en: string;
616
+ et?: string | null | undefined;
617
+ en?: string | null | undefined;
585
618
  };
586
619
  order: number;
587
620
  isActive: boolean;
@@ -589,13 +622,13 @@ declare const siteInfoResponseSchema: z.ZodObject<{
589
622
  success: true;
590
623
  }, {
591
624
  receptionHours: {
592
- et: string;
593
- en: string;
625
+ et?: string | null | undefined;
626
+ en?: string | null | undefined;
594
627
  };
595
628
  notices: {
596
629
  text: {
597
- et: string;
598
- en: string;
630
+ et?: string | null | undefined;
631
+ en?: string | null | undefined;
599
632
  };
600
633
  order: number;
601
634
  isActive: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/constants.ts","../src/diff.ts","../src/upstream/wire.ts","../src/projection.ts","../src/apply.ts","../src/entities/guard.ts","../src/entities/index.ts","../src/entities/legal-document.ts","../src/entities/room-type.ts","../src/entities/site-info.ts","../src/entity-client.ts","../src/sync-state-table.ts","../src/sync-state.ts","../src/upstream/client.ts","../src/run-sync.ts","../src/upstream/errors.ts","../src/watchdog.ts"],"mappings":"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"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/constants.ts","../src/diff.ts","../src/upstream/wire.ts","../src/projection.ts","../src/apply.ts","../src/entities/guard.ts","../src/entities/index.ts","../src/entities/legal-document.ts","../src/entities/room-type.ts","../src/entities/site-info.ts","../src/entity-client.ts","../src/sync-state-table.ts","../src/sync-state.ts","../src/upstream/client.ts","../src/run-sync.ts","../src/upstream/errors.ts","../src/watchdog.ts"],"mappings":"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"}
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- import{C as e,D as t,E as n,O as r,S as i,T as a,_ as o,a as s,b as c,c as l,d as u,f as d,h as f,i as p,l as m,m as h,n as g,o as _,p as v,r as y,s as b,t as x,u as S,v as C,w,x as T,y as E}from"./watchdog-BVf1F4sR.mjs";import{A as D,D as O,M as k,O as A,S as j,T as M,_ as N,a as P,c as F,d as I,f as L,g as R,h as z,i as B,j as V,k as H,l as U,m as W,n as G,o as K,p as q,r as J,s as Y,t as X,u as Z,v as Q,w as $,x as ee,y as te}from"./sync-state-table-CM6eL5W9.mjs";export{W as API_KEY_ENV_VAR,z as BASE_URL_ENV_VAR,R as DECLARED_CURRENCY,N as DECLARED_VAT_TREATMENT,Q as EN_LOCALE,te as ET_LOCALE,ee as LEGAL_DOCUMENTS_RESOURCE,j as MAX_SITE_NOTICES,$ as ROOM_TYPES_RESOURCE,M as SITE_INFO_KEY,O as SITE_INFO_RESOURCE,G as SYNCED_ENTITIES,A as SYNC_JOB_NAME,H as SYNC_RESOURCES,P as VAT_TREATMENTS,D as WATCHDOG_JOB_NAME,F as YHIKAS_LEGAL_DOCUMENT_ENTITY,K as YHIKAS_ROOM_TYPE_ENTITY,J as YHIKAS_SITE_INFO_ENTITY,V as YHIKAS_SYNC_ACTOR_ID,k as YHIKAS_SYNC_PLUGIN_NAME,n as YhikasApplyPartialError,U as YhikasLegalDocument,Y as YhikasRoomType,B as YhikasSiteInfo,L as YhikasSyncConfigError,w as YhikasSyncRefusedError,h as YhikasSyncRunError,x as YhikasSyncStaleError,Z as YhikasSyncedContentReadOnlyError,p as YhikasUpstreamClient,a as YhikasUpstreamError,t as applyPlan,g as assertNotStale,y as assessStaleness,d as createSyncStateStore,s as legalDocumentRowSchema,_ as legalDocumentsResponseSchema,I as machineWritten,b as multilingualTextSchema,i as planDiff,o as projectLegalDocuments,C as projectRoomTypes,E as projectSiteInfo,r as readLocalRows,q as resolveYhikasSyncConfig,l as roomTypeRowSchema,m as roomTypesResponseSchema,f as runYhikasSync,c as secondaryLocaleOf,S as siteInfoResponseSchema,u as siteNoticeRowSchema,e as stableHash,T as toSyncEntityClient,v as truncateError,X as yhikasSyncStateTable};
1
+ import{C as e,D as t,E as n,O as r,S as i,T as a,_ as o,a as s,b as c,c as l,d as u,f as d,h as f,i as p,l as m,m as h,n as g,o as _,p as v,r as y,s as b,t as x,u as S,v as C,w,x as T,y as E}from"./watchdog-Dy3ExN2p.mjs";import{A as D,D as O,M as k,O as A,S as j,T as M,_ as N,a as P,c as F,d as I,f as L,g as R,h as z,i as B,j as V,k as H,l as U,m as W,n as G,o as K,p as q,r as J,s as Y,t as X,u as Z,v as Q,w as $,x as ee,y as te}from"./sync-state-table-CNkHbvbV.mjs";export{W as API_KEY_ENV_VAR,z as BASE_URL_ENV_VAR,R as DECLARED_CURRENCY,N as DECLARED_VAT_TREATMENT,Q as EN_LOCALE,te as ET_LOCALE,ee as LEGAL_DOCUMENTS_RESOURCE,j as MAX_SITE_NOTICES,$ as ROOM_TYPES_RESOURCE,M as SITE_INFO_KEY,O as SITE_INFO_RESOURCE,G as SYNCED_ENTITIES,A as SYNC_JOB_NAME,H as SYNC_RESOURCES,P as VAT_TREATMENTS,D as WATCHDOG_JOB_NAME,F as YHIKAS_LEGAL_DOCUMENT_ENTITY,K as YHIKAS_ROOM_TYPE_ENTITY,J as YHIKAS_SITE_INFO_ENTITY,V as YHIKAS_SYNC_ACTOR_ID,k as YHIKAS_SYNC_PLUGIN_NAME,n as YhikasApplyPartialError,U as YhikasLegalDocument,Y as YhikasRoomType,B as YhikasSiteInfo,L as YhikasSyncConfigError,w as YhikasSyncRefusedError,h as YhikasSyncRunError,x as YhikasSyncStaleError,Z as YhikasSyncedContentReadOnlyError,p as YhikasUpstreamClient,a as YhikasUpstreamError,t as applyPlan,g as assertNotStale,y as assessStaleness,d as createSyncStateStore,s as legalDocumentRowSchema,_ as legalDocumentsResponseSchema,I as machineWritten,b as multilingualTextSchema,i as planDiff,o as projectLegalDocuments,C as projectRoomTypes,E as projectSiteInfo,r as readLocalRows,q as resolveYhikasSyncConfig,l as roomTypeRowSchema,m as roomTypesResponseSchema,f as runYhikasSync,c as secondaryLocaleOf,S as siteInfoResponseSchema,u as siteNoticeRowSchema,e as stableHash,T as toSyncEntityClient,v as truncateError,X as yhikasSyncStateTable};
@@ -1,2 +1,2 @@
1
- import{b as e,f as t,g as n,h as r,i,n as a,x as o}from"./watchdog-BVf1F4sR.mjs";import{h as s,i as c,j as l,k as u,l as d,m as f,s as p,t as m}from"./sync-state-table-CM6eL5W9.mjs";import{elevateRequestContext as h,runWithContextAsync as g}from"@murumets-ee/core";var _=class extends Error{constructor(e){super(`yhikas-sync is enabled but ${e.join(` and `)} ${e.length===1?`is`:`are`} not set. Failing loudly rather than skipping quietly: an unconfigured sync is a broken sync, and a broken sync must be visibly broken. Set the variable, or pass \`enabled: false\` to yhikasSync() if this install has no yhikas-admin.`),this.name=`YhikasSyncNotConfiguredError`}};function v(){return h({user:{id:l,groups:[`admin`]}})}function y(e){return e.logger}async function b(t){let{resolveI18nConfig:r}=await import(`@murumets-ee/content`),{defaultLocale:i}=await r(t);if(!n.includes(i))throw new x(`The app's default locale is '${i}', but yhikas-admin carries content in 'et' and 'en' only. The sync has nothing to write to the base row, so it refuses rather than publishing one language under another's name.`);return{defaultLocale:i,secondaryLocale:e(i)}}var x=class extends Error{constructor(e){super(e),this.name=`YhikasSyncLocaleError`}};function S(e,t){let n=t[f],r=[];if(e.baseUrl||r.push(s),n||r.push(f),!e.baseUrl||!n)throw new _(r);return{baseUrl:e.baseUrl,apiKey:n}}async function C(e,n,a=process.env){let{baseUrl:s,apiKey:l}=S(n,a),{sanitizeHtml:u}=await import(`@murumets-ee/blocks`);return g(v(),async()=>{let{defaultLocale:a}=await b(e);return r({upstream:new i({baseUrl:s,apiKey:l,timeoutMs:n.requestTimeoutMs}),roomTypeClient:o(e.getClient(p),a),legalDocumentClient:o(e.getClient(d),a),siteInfoClient:o(e.getClient(c),a),state:t(m.makeClient(e.db.readWrite)),sanitizeHtml:u,logger:y(e),defaultLocale:a,floor:{maxRows:n.maxRowsPerResource,maxRetireFraction:n.maxRetireFraction,minRowsForFraction:n.minRowsForRetireFloor}})})}async function w(e,n,r=new Date){let i=t(m.makeClient(e.db.readWrite));await T(e,r);let o=a(await i.readAll(),r,n.staleAfterMs);return e.logger.debug({window:n.staleAfterMs,resources:o.map(e=>({resource:e.resource,lastSuccessAt:e.lastSuccessAt}))},`yhikas-sync: staleness check passed`),o}async function T(e,n=new Date){let r=t(m.makeClient(e.db.readWrite));for(let e of u)await r.ensure(e,n)}export{C as runSyncJob,w as runWatchdogJob};
2
- //# sourceMappingURL=jobs-DrMLTUFm.mjs.map
1
+ import{b as e,f as t,g as n,h as r,i,n as a,x as o}from"./watchdog-Dy3ExN2p.mjs";import{h as s,i as c,j as l,k as u,l as d,m as f,s as p,t as m}from"./sync-state-table-CNkHbvbV.mjs";import{elevateRequestContext as h,runWithContextAsync as g}from"@murumets-ee/core";var _=class extends Error{constructor(e){super(`yhikas-sync is enabled but ${e.join(` and `)} ${e.length===1?`is`:`are`} not set. Failing loudly rather than skipping quietly: an unconfigured sync is a broken sync, and a broken sync must be visibly broken. Set the variable, or pass \`enabled: false\` to yhikasSync() if this install has no yhikas-admin.`),this.name=`YhikasSyncNotConfiguredError`}};function v(){return h({user:{id:l,groups:[`admin`]}})}function y(e){return e.logger}async function b(t){let{resolveI18nConfig:r}=await import(`@murumets-ee/content`),{defaultLocale:i}=await r(t);if(!n.includes(i))throw new x(`The app's default locale is '${i}', but yhikas-admin carries content in 'et' and 'en' only. The sync has nothing to write to the base row, so it refuses rather than publishing one language under another's name.`);return{defaultLocale:i,secondaryLocale:e(i)}}var x=class extends Error{constructor(e){super(e),this.name=`YhikasSyncLocaleError`}};function S(e,t){let n=t[f],r=[];if(e.baseUrl||r.push(s),n||r.push(f),!e.baseUrl||!n)throw new _(r);return{baseUrl:e.baseUrl,apiKey:n}}async function C(e,n,a=process.env){let{baseUrl:s,apiKey:l}=S(n,a),{sanitizeHtml:u}=await import(`@murumets-ee/blocks`);return g(v(),async()=>{let{defaultLocale:a}=await b(e);return r({upstream:new i({baseUrl:s,apiKey:l,timeoutMs:n.requestTimeoutMs}),roomTypeClient:o(e.getClient(p),a),legalDocumentClient:o(e.getClient(d),a),siteInfoClient:o(e.getClient(c),a),state:t(m.makeClient(e.db.readWrite)),sanitizeHtml:u,logger:y(e),defaultLocale:a,floor:{maxRows:n.maxRowsPerResource,maxRetireFraction:n.maxRetireFraction,minRowsForFraction:n.minRowsForRetireFloor}})})}async function w(e,n,r=new Date){let i=t(m.makeClient(e.db.readWrite));await T(e,r);let o=a(await i.readAll(),r,n.staleAfterMs);return e.logger.debug({window:n.staleAfterMs,resources:o.map(e=>({resource:e.resource,lastSuccessAt:e.lastSuccessAt}))},`yhikas-sync: staleness check passed`),o}async function T(e,n=new Date){let r=t(m.makeClient(e.db.readWrite));for(let e of u)await r.ensure(e,n)}export{C as runSyncJob,w as runWatchdogJob};
2
+ //# sourceMappingURL=jobs-CvSKn8C5.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"jobs-DrMLTUFm.mjs","names":[],"sources":["../src/jobs.ts"],"sourcesContent":["/**\n * The two job handlers, bound to a live `ToolkitApp`.\n *\n * This module is reached ONLY through a dynamic `import()` from the plugin's\n * `init` (see `plugin.ts`). It statically imports `@murumets-ee/core` and\n * `@murumets-ee/blocks`, either of which would be evaluated at\n * `lumi.config.ts`-load time under the CLI's jiti loader if the plugin entry\n * reached it statically — and `@murumets-ee/blocks`' root export evaluates\n * React's `createContext` at module scope.\n */\n\nimport { elevateRequestContext, runWithContextAsync, type ToolkitApp } from '@murumets-ee/core'\nimport type { SyncLogger } from './apply.js'\nimport type { ResolvedYhikasSyncConfig } from './config.js'\nimport {\n API_KEY_ENV_VAR,\n BASE_URL_ENV_VAR,\n EN_LOCALE,\n ET_LOCALE,\n LEGAL_DOCUMENTS_RESOURCE,\n ROOM_TYPES_RESOURCE,\n SYNC_RESOURCES,\n YHIKAS_SYNC_ACTOR_ID,\n} from './constants.js'\nimport { YhikasLegalDocument } from './entities/legal-document.js'\nimport { YhikasRoomType } from './entities/room-type.js'\nimport { YhikasSiteInfo } from './entities/site-info.js'\nimport { toSyncEntityClient } from './entity-client.js'\nimport { SUPPORTED_LOCALES, secondaryLocaleOf } from './projection.js'\nimport { runYhikasSync, type SyncRunSummary } from './run-sync.js'\nimport { createSyncStateStore } from './sync-state.js'\nimport { yhikasSyncStateTable } from './sync-state-table.js'\nimport { YhikasUpstreamClient } from './upstream/client.js'\nimport { assertNotStale, type ResourceStaleness } from './watchdog.js'\n\n/** Thrown when the sync is enabled but has no credential or no origin to talk to. */\nexport class YhikasSyncNotConfiguredError extends Error {\n constructor(missing: readonly string[]) {\n super(\n `yhikas-sync is enabled but ${missing.join(' and ')} ${missing.length === 1 ? 'is' : 'are'} ` +\n `not set. Failing loudly rather than skipping quietly: an unconfigured sync is a broken ` +\n `sync, and a broken sync must be visibly broken. Set the variable, or pass ` +\n `\\`enabled: false\\` to yhikasSync() if this install has no yhikas-admin.`,\n )\n this.name = 'YhikasSyncNotConfiguredError'\n }\n}\n\n/**\n * Every entity write runs as this identity.\n *\n * `elevateRequestContext` rather than `runAsCli`: both replace the permission\n * checker, but this one carries a NAMED actor, so `auditable()` records\n * `yhikas-sync` in `created_by`/`updated_by` instead of a generic `cli`. That\n * makes the sync's writes attributable — worth having precisely because the\n * upstream writes are not (F006) — and it is what the machine-written guard\n * recognises when it refuses every other writer.\n *\n * Built per run rather than at module scope: `elevateRequestContext` reads the\n * ambient context at CALL time, and a module-scope constant would bake in\n * whatever context happened to exist when the module first loaded.\n */\nfunction syncContext() {\n return elevateRequestContext({\n user: { id: YHIKAS_SYNC_ACTOR_ID, groups: ['admin'] },\n })\n}\n\n/** Narrow `app.logger` to the shape the sync uses, without importing a logger type. */\nfunction toSyncLogger(app: ToolkitApp): SyncLogger {\n return app.logger\n}\n\n/**\n * The app's REAL default locale, read from the content plugin rather than\n * configured here.\n *\n * A configured copy could disagree with the app's actual default, and the\n * failure would be silent in both directions: `updateForLocale` would take its\n * `isDefault` branch for what this package thought was the secondary locale\n * and overwrite the base row with the wrong language, while no translation was\n * ever written for the real secondary. `resolveI18nConfig` is the authoritative\n * answer — it merges the runtime `i18n` override over the shipped config — so\n * there is nothing to keep in sync.\n */\nasync function resolveLocales(\n app: ToolkitApp,\n): Promise<{ defaultLocale: string; secondaryLocale: string }> {\n const { resolveI18nConfig } = await import('@murumets-ee/content')\n const { defaultLocale } = await resolveI18nConfig(app)\n\n if (!SUPPORTED_LOCALES.includes(defaultLocale)) {\n throw new YhikasSyncLocaleError(\n `The app's default locale is '${defaultLocale}', but yhikas-admin carries content in ` +\n `'${ET_LOCALE}' and '${EN_LOCALE}' only. The sync has nothing to write to the base row, ` +\n `so it refuses rather than publishing one language under another's name.`,\n )\n }\n // `secondaryLocaleOf` asserts the same thing, so the two can never disagree.\n return { defaultLocale, secondaryLocale: secondaryLocaleOf(defaultLocale) }\n}\n\n/** Thrown when the app's locale configuration cannot carry the synced content. */\nexport class YhikasSyncLocaleError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'YhikasSyncLocaleError'\n }\n}\n\n/**\n * Resolve the bearer credential at RUN time, from the environment.\n *\n * Deliberately not part of the plugin's declared config: resolved config lands\n * in the framework's `PluginConfigRegistry`, a process-global any plugin can\n * read, and a secret does not belong there (mirroring `@murumets-ee/merit`'s\n * D003). Reading it here also means rotating the key needs a restart rather\n * than a rebuild.\n */\nfunction resolveCredentials(\n config: ResolvedYhikasSyncConfig,\n env: NodeJS.ProcessEnv,\n): { baseUrl: string; apiKey: string } {\n const apiKey = env[API_KEY_ENV_VAR]\n const missing: string[] = []\n if (!config.baseUrl) missing.push(BASE_URL_ENV_VAR)\n if (!apiKey) missing.push(API_KEY_ENV_VAR)\n if (!config.baseUrl || !apiKey) throw new YhikasSyncNotConfiguredError(missing)\n return { baseUrl: config.baseUrl, apiKey }\n}\n\n/** One full sync run. Throws on any resource failure, so the queue retries and alerts. */\nexport async function runSyncJob(\n app: ToolkitApp,\n config: ResolvedYhikasSyncConfig,\n env: NodeJS.ProcessEnv = process.env,\n): Promise<SyncRunSummary> {\n const { baseUrl, apiKey } = resolveCredentials(config, env)\n const { sanitizeHtml } = await import('@murumets-ee/blocks')\n\n return runWithContextAsync(syncContext(), async () => {\n const { defaultLocale } = await resolveLocales(app)\n return runYhikasSync({\n upstream: new YhikasUpstreamClient({\n baseUrl,\n apiKey,\n timeoutMs: config.requestTimeoutMs,\n }),\n // The clients are built HERE, inside the job, not in the plugin's\n // `init`. That is load-bearing and easy to \"tidy\" into a bug:\n // `createAdminClient` reads the locale-status writer ONCE at\n // construction, and `@murumets-ee/content` installs that writer from its\n // own `init`. `Plugin.requires` guarantees content is CONFIGURED, not\n // that it initialised first — so a client constructed during init could\n // capture no writer, and `updateForLocale` would then silently assign\n // the requested status to the BASE row. Constructing at job-run time is\n // after every plugin's init, unconditionally.\n roomTypeClient: toSyncEntityClient(app.getClient(YhikasRoomType), defaultLocale),\n legalDocumentClient: toSyncEntityClient(app.getClient(YhikasLegalDocument), defaultLocale),\n siteInfoClient: toSyncEntityClient(app.getClient(YhikasSiteInfo), defaultLocale),\n state: createSyncStateStore(yhikasSyncStateTable.makeClient(app.db.readWrite)),\n sanitizeHtml,\n logger: toSyncLogger(app),\n defaultLocale,\n floor: {\n maxRows: config.maxRowsPerResource,\n maxRetireFraction: config.maxRetireFraction,\n minRowsForFraction: config.minRowsForRetireFloor,\n },\n })\n })\n}\n\n/**\n * The staleness check. Throws when any resource is past the window, which is\n * how it reaches the queue's dead-letter alerting — the detection is new, the\n * delivery is not.\n */\nexport async function runWatchdogJob(\n app: ToolkitApp,\n config: ResolvedYhikasSyncConfig,\n now: Date = new Date(),\n): Promise<ResourceStaleness[]> {\n const store = createSyncStateStore(yhikasSyncStateTable.makeClient(app.db.readWrite))\n // Seed before assessing, so a fresh install gets a `firstSeenAt` to be\n // measured from rather than reading as \"no tracking row at all\" — which is\n // correct but alarming on an app that simply has not reached its first sync\n // tick yet.\n //\n // The cost, stated: `assessStaleness`'s missing-row branch is therefore\n // unreachable from here, so a tracking row DELETED by hand while the sync is\n // broken resets the clock instead of alerting. That needs deliberate DB\n // surgery to reach, and the alternative — alerting on every fresh install's\n // first tick — trains people to ignore the one channel that has to stay\n // trustworthy.\n await ensureSyncState(app, now)\n const records = await store.readAll()\n const assessed = assertNotStale(records, now, config.staleAfterMs)\n app.logger.debug(\n {\n window: config.staleAfterMs,\n resources: assessed.map((entry) => ({\n resource: entry.resource,\n lastSuccessAt: entry.lastSuccessAt,\n })),\n },\n 'yhikas-sync: staleness check passed',\n )\n return assessed\n}\n\n/**\n * Seed a tracking row per resource, so a fresh install has a clock to be\n * measured against before its first sync tick.\n *\n * Called from the WATCHDOG, not from the plugin's `init`. Doing DB I/O during\n * `init` runs it in every process that builds a `ToolkitApp` — web included —\n * and would fail app boot outright on a database blip, or on any boot that\n * precedes `lumi migrate` creating the table, in exchange for two bookkeeping\n * rows.\n */\nexport async function ensureSyncState(app: ToolkitApp, now: Date = new Date()): Promise<void> {\n const store = createSyncStateStore(yhikasSyncStateTable.makeClient(app.db.readWrite))\n for (const resource of SYNC_RESOURCES) {\n await store.ensure(resource, now)\n }\n}\n\nexport { LEGAL_DOCUMENTS_RESOURCE, ROOM_TYPES_RESOURCE }\n"],"mappings":"yQAoCA,IAAa,EAAb,cAAkD,KAAM,CACtD,YAAY,EAA4B,CACtC,MACE,8BAA8B,EAAQ,KAAK,OAAO,EAAE,GAAG,EAAQ,SAAW,EAAI,KAAO,MAAM,0OAI7F,EACA,KAAK,KAAO,8BACd,CACF,EAgBA,SAAS,GAAc,CACrB,OAAO,EAAsB,CAC3B,KAAM,CAAE,GAAI,EAAsB,OAAQ,CAAC,OAAO,CAAE,CACtD,CAAC,CACH,CAGA,SAAS,EAAa,EAA6B,CACjD,OAAO,EAAI,MACb,CAcA,eAAe,EACb,EAC6D,CAC7D,GAAM,CAAE,qBAAsB,MAAM,OAAO,wBACrC,CAAE,iBAAkB,MAAM,EAAkB,CAAG,EAErD,GAAI,CAAC,EAAkB,SAAS,CAAa,EAC3C,MAAM,IAAI,EACR,gCAAgC,EAAc,kLAGhD,EAGF,MAAO,CAAE,gBAAe,gBAAiB,EAAkB,CAAa,CAAE,CAC5E,CAGA,IAAa,EAAb,cAA2C,KAAM,CAC/C,YAAY,EAAiB,CAC3B,MAAM,CAAO,EACb,KAAK,KAAO,uBACd,CACF,EAWA,SAAS,EACP,EACA,EACqC,CACrC,IAAM,EAAS,EAAI,GACb,EAAoB,CAAC,EAG3B,GAFK,EAAO,SAAS,EAAQ,KAAK,CAAgB,EAC7C,GAAQ,EAAQ,KAAK,CAAe,EACrC,CAAC,EAAO,SAAW,CAAC,EAAQ,MAAM,IAAI,EAA6B,CAAO,EAC9E,MAAO,CAAE,QAAS,EAAO,QAAS,QAAO,CAC3C,CAGA,eAAsB,EACpB,EACA,EACA,EAAyB,QAAQ,IACR,CACzB,GAAM,CAAE,UAAS,UAAW,EAAmB,EAAQ,CAAG,EACpD,CAAE,gBAAiB,MAAM,OAAO,uBAEtC,OAAO,EAAoB,EAAY,EAAG,SAAY,CACpD,GAAM,CAAE,iBAAkB,MAAM,EAAe,CAAG,EAClD,OAAO,EAAc,CACnB,SAAU,IAAI,EAAqB,CACjC,UACA,SACA,UAAW,EAAO,gBACpB,CAAC,EAUD,eAAgB,EAAmB,EAAI,UAAU,CAAc,EAAG,CAAa,EAC/E,oBAAqB,EAAmB,EAAI,UAAU,CAAmB,EAAG,CAAa,EACzF,eAAgB,EAAmB,EAAI,UAAU,CAAc,EAAG,CAAa,EAC/E,MAAO,EAAqB,EAAqB,WAAW,EAAI,GAAG,SAAS,CAAC,EAC7E,eACA,OAAQ,EAAa,CAAG,EACxB,gBACA,MAAO,CACL,QAAS,EAAO,mBAChB,kBAAmB,EAAO,kBAC1B,mBAAoB,EAAO,qBAC7B,CACF,CAAC,CACH,CAAC,CACH,CAOA,eAAsB,EACpB,EACA,EACA,EAAY,IAAI,KACc,CAC9B,IAAM,EAAQ,EAAqB,EAAqB,WAAW,EAAI,GAAG,SAAS,CAAC,EAYpF,MAAM,EAAgB,EAAK,CAAG,EAE9B,IAAM,EAAW,EAAe,MADV,EAAM,QAAQ,EACK,EAAK,EAAO,YAAY,EAWjE,OAVA,EAAI,OAAO,MACT,CACE,OAAQ,EAAO,aACf,UAAW,EAAS,IAAK,IAAW,CAClC,SAAU,EAAM,SAChB,cAAe,EAAM,aACvB,EAAE,CACJ,EACA,qCACF,EACO,CACT,CAYA,eAAsB,EAAgB,EAAiB,EAAY,IAAI,KAAuB,CAC5F,IAAM,EAAQ,EAAqB,EAAqB,WAAW,EAAI,GAAG,SAAS,CAAC,EACpF,IAAK,IAAM,KAAY,EACrB,MAAM,EAAM,OAAO,EAAU,CAAG,CAEpC"}
1
+ {"version":3,"file":"jobs-CvSKn8C5.mjs","names":[],"sources":["../src/jobs.ts"],"sourcesContent":["/**\n * The two job handlers, bound to a live `ToolkitApp`.\n *\n * This module is reached ONLY through a dynamic `import()` from the plugin's\n * `init` (see `plugin.ts`). It statically imports `@murumets-ee/core` and\n * `@murumets-ee/blocks`, either of which would be evaluated at\n * `lumi.config.ts`-load time under the CLI's jiti loader if the plugin entry\n * reached it statically — and `@murumets-ee/blocks`' root export evaluates\n * React's `createContext` at module scope.\n */\n\nimport { elevateRequestContext, runWithContextAsync, type ToolkitApp } from '@murumets-ee/core'\nimport type { SyncLogger } from './apply.js'\nimport type { ResolvedYhikasSyncConfig } from './config.js'\nimport {\n API_KEY_ENV_VAR,\n BASE_URL_ENV_VAR,\n EN_LOCALE,\n ET_LOCALE,\n LEGAL_DOCUMENTS_RESOURCE,\n ROOM_TYPES_RESOURCE,\n SYNC_RESOURCES,\n YHIKAS_SYNC_ACTOR_ID,\n} from './constants.js'\nimport { YhikasLegalDocument } from './entities/legal-document.js'\nimport { YhikasRoomType } from './entities/room-type.js'\nimport { YhikasSiteInfo } from './entities/site-info.js'\nimport { toSyncEntityClient } from './entity-client.js'\nimport { SUPPORTED_LOCALES, secondaryLocaleOf } from './projection.js'\nimport { runYhikasSync, type SyncRunSummary } from './run-sync.js'\nimport { createSyncStateStore } from './sync-state.js'\nimport { yhikasSyncStateTable } from './sync-state-table.js'\nimport { YhikasUpstreamClient } from './upstream/client.js'\nimport { assertNotStale, type ResourceStaleness } from './watchdog.js'\n\n/** Thrown when the sync is enabled but has no credential or no origin to talk to. */\nexport class YhikasSyncNotConfiguredError extends Error {\n constructor(missing: readonly string[]) {\n super(\n `yhikas-sync is enabled but ${missing.join(' and ')} ${missing.length === 1 ? 'is' : 'are'} ` +\n `not set. Failing loudly rather than skipping quietly: an unconfigured sync is a broken ` +\n `sync, and a broken sync must be visibly broken. Set the variable, or pass ` +\n `\\`enabled: false\\` to yhikasSync() if this install has no yhikas-admin.`,\n )\n this.name = 'YhikasSyncNotConfiguredError'\n }\n}\n\n/**\n * Every entity write runs as this identity.\n *\n * `elevateRequestContext` rather than `runAsCli`: both replace the permission\n * checker, but this one carries a NAMED actor, so `auditable()` records\n * `yhikas-sync` in `created_by`/`updated_by` instead of a generic `cli`. That\n * makes the sync's writes attributable — worth having precisely because the\n * upstream writes are not (F006) — and it is what the machine-written guard\n * recognises when it refuses every other writer.\n *\n * Built per run rather than at module scope: `elevateRequestContext` reads the\n * ambient context at CALL time, and a module-scope constant would bake in\n * whatever context happened to exist when the module first loaded.\n */\nfunction syncContext() {\n return elevateRequestContext({\n user: { id: YHIKAS_SYNC_ACTOR_ID, groups: ['admin'] },\n })\n}\n\n/** Narrow `app.logger` to the shape the sync uses, without importing a logger type. */\nfunction toSyncLogger(app: ToolkitApp): SyncLogger {\n return app.logger\n}\n\n/**\n * The app's REAL default locale, read from the content plugin rather than\n * configured here.\n *\n * A configured copy could disagree with the app's actual default, and the\n * failure would be silent in both directions: `updateForLocale` would take its\n * `isDefault` branch for what this package thought was the secondary locale\n * and overwrite the base row with the wrong language, while no translation was\n * ever written for the real secondary. `resolveI18nConfig` is the authoritative\n * answer — it merges the runtime `i18n` override over the shipped config — so\n * there is nothing to keep in sync.\n */\nasync function resolveLocales(\n app: ToolkitApp,\n): Promise<{ defaultLocale: string; secondaryLocale: string }> {\n const { resolveI18nConfig } = await import('@murumets-ee/content')\n const { defaultLocale } = await resolveI18nConfig(app)\n\n if (!SUPPORTED_LOCALES.includes(defaultLocale)) {\n throw new YhikasSyncLocaleError(\n `The app's default locale is '${defaultLocale}', but yhikas-admin carries content in ` +\n `'${ET_LOCALE}' and '${EN_LOCALE}' only. The sync has nothing to write to the base row, ` +\n `so it refuses rather than publishing one language under another's name.`,\n )\n }\n // `secondaryLocaleOf` asserts the same thing, so the two can never disagree.\n return { defaultLocale, secondaryLocale: secondaryLocaleOf(defaultLocale) }\n}\n\n/** Thrown when the app's locale configuration cannot carry the synced content. */\nexport class YhikasSyncLocaleError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'YhikasSyncLocaleError'\n }\n}\n\n/**\n * Resolve the bearer credential at RUN time, from the environment.\n *\n * Deliberately not part of the plugin's declared config: resolved config lands\n * in the framework's `PluginConfigRegistry`, a process-global any plugin can\n * read, and a secret does not belong there (mirroring `@murumets-ee/merit`'s\n * D003). Reading it here also means rotating the key needs a restart rather\n * than a rebuild.\n */\nfunction resolveCredentials(\n config: ResolvedYhikasSyncConfig,\n env: NodeJS.ProcessEnv,\n): { baseUrl: string; apiKey: string } {\n const apiKey = env[API_KEY_ENV_VAR]\n const missing: string[] = []\n if (!config.baseUrl) missing.push(BASE_URL_ENV_VAR)\n if (!apiKey) missing.push(API_KEY_ENV_VAR)\n if (!config.baseUrl || !apiKey) throw new YhikasSyncNotConfiguredError(missing)\n return { baseUrl: config.baseUrl, apiKey }\n}\n\n/** One full sync run. Throws on any resource failure, so the queue retries and alerts. */\nexport async function runSyncJob(\n app: ToolkitApp,\n config: ResolvedYhikasSyncConfig,\n env: NodeJS.ProcessEnv = process.env,\n): Promise<SyncRunSummary> {\n const { baseUrl, apiKey } = resolveCredentials(config, env)\n const { sanitizeHtml } = await import('@murumets-ee/blocks')\n\n return runWithContextAsync(syncContext(), async () => {\n const { defaultLocale } = await resolveLocales(app)\n return runYhikasSync({\n upstream: new YhikasUpstreamClient({\n baseUrl,\n apiKey,\n timeoutMs: config.requestTimeoutMs,\n }),\n // The clients are built HERE, inside the job, not in the plugin's\n // `init`. That is load-bearing and easy to \"tidy\" into a bug:\n // `createAdminClient` reads the locale-status writer ONCE at\n // construction, and `@murumets-ee/content` installs that writer from its\n // own `init`. `Plugin.requires` guarantees content is CONFIGURED, not\n // that it initialised first — so a client constructed during init could\n // capture no writer, and `updateForLocale` would then silently assign\n // the requested status to the BASE row. Constructing at job-run time is\n // after every plugin's init, unconditionally.\n roomTypeClient: toSyncEntityClient(app.getClient(YhikasRoomType), defaultLocale),\n legalDocumentClient: toSyncEntityClient(app.getClient(YhikasLegalDocument), defaultLocale),\n siteInfoClient: toSyncEntityClient(app.getClient(YhikasSiteInfo), defaultLocale),\n state: createSyncStateStore(yhikasSyncStateTable.makeClient(app.db.readWrite)),\n sanitizeHtml,\n logger: toSyncLogger(app),\n defaultLocale,\n floor: {\n maxRows: config.maxRowsPerResource,\n maxRetireFraction: config.maxRetireFraction,\n minRowsForFraction: config.minRowsForRetireFloor,\n },\n })\n })\n}\n\n/**\n * The staleness check. Throws when any resource is past the window, which is\n * how it reaches the queue's dead-letter alerting — the detection is new, the\n * delivery is not.\n */\nexport async function runWatchdogJob(\n app: ToolkitApp,\n config: ResolvedYhikasSyncConfig,\n now: Date = new Date(),\n): Promise<ResourceStaleness[]> {\n const store = createSyncStateStore(yhikasSyncStateTable.makeClient(app.db.readWrite))\n // Seed before assessing, so a fresh install gets a `firstSeenAt` to be\n // measured from rather than reading as \"no tracking row at all\" — which is\n // correct but alarming on an app that simply has not reached its first sync\n // tick yet.\n //\n // The cost, stated: `assessStaleness`'s missing-row branch is therefore\n // unreachable from here, so a tracking row DELETED by hand while the sync is\n // broken resets the clock instead of alerting. That needs deliberate DB\n // surgery to reach, and the alternative — alerting on every fresh install's\n // first tick — trains people to ignore the one channel that has to stay\n // trustworthy.\n await ensureSyncState(app, now)\n const records = await store.readAll()\n const assessed = assertNotStale(records, now, config.staleAfterMs)\n app.logger.debug(\n {\n window: config.staleAfterMs,\n resources: assessed.map((entry) => ({\n resource: entry.resource,\n lastSuccessAt: entry.lastSuccessAt,\n })),\n },\n 'yhikas-sync: staleness check passed',\n )\n return assessed\n}\n\n/**\n * Seed a tracking row per resource, so a fresh install has a clock to be\n * measured against before its first sync tick.\n *\n * Called from the WATCHDOG, not from the plugin's `init`. Doing DB I/O during\n * `init` runs it in every process that builds a `ToolkitApp` — web included —\n * and would fail app boot outright on a database blip, or on any boot that\n * precedes `lumi migrate` creating the table, in exchange for two bookkeeping\n * rows.\n */\nexport async function ensureSyncState(app: ToolkitApp, now: Date = new Date()): Promise<void> {\n const store = createSyncStateStore(yhikasSyncStateTable.makeClient(app.db.readWrite))\n for (const resource of SYNC_RESOURCES) {\n await store.ensure(resource, now)\n }\n}\n\nexport { LEGAL_DOCUMENTS_RESOURCE, ROOM_TYPES_RESOURCE }\n"],"mappings":"yQAoCA,IAAa,EAAb,cAAkD,KAAM,CACtD,YAAY,EAA4B,CACtC,MACE,8BAA8B,EAAQ,KAAK,OAAO,EAAE,GAAG,EAAQ,SAAW,EAAI,KAAO,MAAM,0OAI7F,EACA,KAAK,KAAO,8BACd,CACF,EAgBA,SAAS,GAAc,CACrB,OAAO,EAAsB,CAC3B,KAAM,CAAE,GAAI,EAAsB,OAAQ,CAAC,OAAO,CAAE,CACtD,CAAC,CACH,CAGA,SAAS,EAAa,EAA6B,CACjD,OAAO,EAAI,MACb,CAcA,eAAe,EACb,EAC6D,CAC7D,GAAM,CAAE,qBAAsB,MAAM,OAAO,wBACrC,CAAE,iBAAkB,MAAM,EAAkB,CAAG,EAErD,GAAI,CAAC,EAAkB,SAAS,CAAa,EAC3C,MAAM,IAAI,EACR,gCAAgC,EAAc,kLAGhD,EAGF,MAAO,CAAE,gBAAe,gBAAiB,EAAkB,CAAa,CAAE,CAC5E,CAGA,IAAa,EAAb,cAA2C,KAAM,CAC/C,YAAY,EAAiB,CAC3B,MAAM,CAAO,EACb,KAAK,KAAO,uBACd,CACF,EAWA,SAAS,EACP,EACA,EACqC,CACrC,IAAM,EAAS,EAAI,GACb,EAAoB,CAAC,EAG3B,GAFK,EAAO,SAAS,EAAQ,KAAK,CAAgB,EAC7C,GAAQ,EAAQ,KAAK,CAAe,EACrC,CAAC,EAAO,SAAW,CAAC,EAAQ,MAAM,IAAI,EAA6B,CAAO,EAC9E,MAAO,CAAE,QAAS,EAAO,QAAS,QAAO,CAC3C,CAGA,eAAsB,EACpB,EACA,EACA,EAAyB,QAAQ,IACR,CACzB,GAAM,CAAE,UAAS,UAAW,EAAmB,EAAQ,CAAG,EACpD,CAAE,gBAAiB,MAAM,OAAO,uBAEtC,OAAO,EAAoB,EAAY,EAAG,SAAY,CACpD,GAAM,CAAE,iBAAkB,MAAM,EAAe,CAAG,EAClD,OAAO,EAAc,CACnB,SAAU,IAAI,EAAqB,CACjC,UACA,SACA,UAAW,EAAO,gBACpB,CAAC,EAUD,eAAgB,EAAmB,EAAI,UAAU,CAAc,EAAG,CAAa,EAC/E,oBAAqB,EAAmB,EAAI,UAAU,CAAmB,EAAG,CAAa,EACzF,eAAgB,EAAmB,EAAI,UAAU,CAAc,EAAG,CAAa,EAC/E,MAAO,EAAqB,EAAqB,WAAW,EAAI,GAAG,SAAS,CAAC,EAC7E,eACA,OAAQ,EAAa,CAAG,EACxB,gBACA,MAAO,CACL,QAAS,EAAO,mBAChB,kBAAmB,EAAO,kBAC1B,mBAAoB,EAAO,qBAC7B,CACF,CAAC,CACH,CAAC,CACH,CAOA,eAAsB,EACpB,EACA,EACA,EAAY,IAAI,KACc,CAC9B,IAAM,EAAQ,EAAqB,EAAqB,WAAW,EAAI,GAAG,SAAS,CAAC,EAYpF,MAAM,EAAgB,EAAK,CAAG,EAE9B,IAAM,EAAW,EAAe,MADV,EAAM,QAAQ,EACK,EAAK,EAAO,YAAY,EAWjE,OAVA,EAAI,OAAO,MACT,CACE,OAAQ,EAAO,aACf,UAAW,EAAS,IAAK,IAAW,CAClC,SAAU,EAAM,SAChB,cAAe,EAAM,aACvB,EAAE,CACJ,EACA,qCACF,EACO,CACT,CAYA,eAAsB,EAAgB,EAAiB,EAAY,IAAI,KAAuB,CAC5F,IAAM,EAAQ,EAAqB,EAAqB,WAAW,EAAI,GAAG,SAAS,CAAC,EACpF,IAAK,IAAM,KAAY,EACrB,MAAM,EAAM,OAAO,EAAU,CAAG,CAEpC"}
package/dist/plugin.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import{A as e,M as t,O as n,n as r,p as i,t as a}from"./sync-state-table-CM6eL5W9.mjs";import{definePlugin as o}from"@murumets-ee/core";function s(s){let c=i(s);return o({name:t,requires:[`@murumets-ee/content`,`@murumets-ee/queue`],server:{config:c,entities:[...r],tables:{yhikas_sync_state:a.table},init:async r=>{if(!c.enabled){r.logger.warn({plugin:t},`yhikas-sync is disabled by config — no scheduled pull, and no staleness alerting`);return}let{defineJob:i,registerJob:a}=await import(`@murumets-ee/queue/client`);a(i({name:n,description:`Pull room types and legal documents from yhikas-admin and apply a full-snapshot diff.`,schedule:c.schedule}),async()=>{let{runSyncJob:e}=await import(`./jobs-DrMLTUFm.mjs`);await e(r,c)}),a(i({name:e,description:`Alert when the newest successful yhikas-admin sync is older than the staleness window.`,schedule:c.watchdogSchedule}),async()=>{let{runWatchdogJob:e}=await import(`./jobs-DrMLTUFm.mjs`);await e(r,c)})}}})}export{s as yhikasSync};
1
+ import{A as e,M as t,O as n,n as r,p as i,t as a}from"./sync-state-table-CNkHbvbV.mjs";import{definePlugin as o}from"@murumets-ee/core";function s(s){let c=i(s);return o({name:t,requires:[`@murumets-ee/content`,`@murumets-ee/queue`],server:{config:c,entities:[...r],tables:{yhikas_sync_state:a.table},init:async r=>{if(!c.enabled){r.logger.warn({plugin:t},`yhikas-sync is disabled by config — no scheduled pull, and no staleness alerting`);return}let{defineJob:i,registerJob:a}=await import(`@murumets-ee/queue/client`);a(i({name:n,description:`Pull room types and legal documents from yhikas-admin and apply a full-snapshot diff.`,schedule:c.schedule}),async()=>{let{runSyncJob:e}=await import(`./jobs-CvSKn8C5.mjs`);await e(r,c)}),a(i({name:e,description:`Alert when the newest successful yhikas-admin sync is older than the staleness window.`,schedule:c.watchdogSchedule}),async()=>{let{runWatchdogJob:e}=await import(`./jobs-CvSKn8C5.mjs`);await e(r,c)})}}})}export{s as yhikasSync};
2
2
  //# sourceMappingURL=plugin.mjs.map
@@ -1,2 +1,2 @@
1
- import{auditable as e,defineEntity as t,field as n,publishable as r}from"@murumets-ee/entity";import{column as i,defineTable as a}from"@murumets-ee/db";const o=`@murumets-ee/yhikas-sync`,s=`yhikas-sync`,c=`yhikas-sync:pull`,l=`yhikas-sync:staleness-watchdog`,u=`room_types`,d=`legal_documents`,f=`site_info`,p=[u,d,f],m=`default`,h=`et`,g=`en`,_=`EUR`,v=`net`,y=`/api/public/room-types`,b=`/api/public/legal-documents`,x=`/api/public/site-info`,S=25,C=`YHIKAS_SYNC_API_KEY`,w=`YHIKAS_ADMIN_BASE_URL`;var T=class extends Error{constructor(e){super(e),this.name=`YhikasSyncConfigError`}};function E(e,t){if(!Number.isSafeInteger(e)||e<=0)throw new T(`${t} must be a positive integer, got ${e}`);return e}function D(e,t){if(!Number.isFinite(e)||e<=0)throw new T(`${t} must be a finite positive number, got ${e}`);return e}function O(e={},t=process.env){let n=e.maxRetireFraction??.5;if(!Number.isFinite(n)||n<=0||n>1)throw new T(`maxRetireFraction must be in (0, 1], got ${n}. A value of 1 disables the fraction rule; the empty-snapshot rule still applies.`);let r=e.baseUrl??t.YHIKAS_ADMIN_BASE_URL;return Object.freeze({baseUrl:r&&r.length>0?r:void 0,schedule:e.schedule??`@every 6h`,watchdogSchedule:e.watchdogSchedule??`@every 1h`,staleAfterMs:D(e.staleAfterMs??864e5,`staleAfterMs`),requestTimeoutMs:D(e.requestTimeoutMs??15e3,`requestTimeoutMs`),maxRowsPerResource:E(e.maxRowsPerResource??500,`maxRowsPerResource`),maxRetireFraction:n,minRowsForRetireFloor:E(e.minRowsForRetireFloor??3,`minRowsForRetireFloor`),enabled:e.enabled??!0})}var k=class extends Error{constructor(e,t,n){super(`'${e}' is written only by the yhikas-admin sync. Refusing ${t} by '${n}': ${t===`translation write`||t===`locale publish change`?`a change here would NOT be reverted on the next sync run — it does not alter sourceHash, so the differ reports the row unchanged and the divergence from yhikas-admin stands permanently, with no alert and no staleness`:`an edit here would be silently reverted on the next sync run, which is worse than no editor at all`}. Change the value in yhikas-admin instead.`),this.name=`YhikasSyncedContentReadOnlyError`}};function A(e,t,n){let r=n?.user?.id;if(r!==`yhikas-sync`)throw new k(e,t,r??`<unattributed>`)}function j(e){return{name:`yhikas-sync:machine-written:${e}`,hooks:{beforeCreate:async(t,n)=>(A(e,`create`,n),t),beforeUpdate:async(t,n,r)=>(A(e,`update`,r),n),beforeDelete:async(t,n)=>{A(e,`delete`,n)}},assertBulkUpdate:()=>{throw new k(e,`bulk update`,`<bulk>`)},assertTranslationWrite:(t,n)=>{A(e,t.action===`locale-status`?`locale publish change`:`translation write`,n)}}}const M=`yhikas_legal_document`,N=t({name:M,scope:`global`,fields:{type:n.text({required:!0,unique:!0,indexed:!0,maxLength:190}),title:n.text({required:!0,translatable:!0}),sourceSlug:n.text({required:!0,indexed:!0,maxLength:190}),body:n.richtext({required:!0,translatable:!0}),order:n.number({integer:!0,required:!0,default:0}),hasEnglish:n.boolean({required:!0,default:!1}),sourceHash:n.text({maxLength:64})},behaviors:[e(),r(),j(M)],access:{view:`group.admin`,create:`group.admin`,update:`group.admin`,delete:`group.admin`},admin:{group:`yhikas`,label:`Legal documents`,labelSingular:`Legal document`,titleField:`type`,icon:`file-text`,description:`Synced from yhikas-admin every 6 hours. Read-only here — an edit would be reverted on the next run. Change the text in yhikas-admin.`,defaultSort:`order`,defaultSortDirection:`asc`,disableCreate:!0,hideFromDashboard:!0,hiddenFields:[`sourceHash`],hiddenColumns:[`sourceHash`]}}),P=`yhikas_room_type`,F=[`net`,`gross`],I=t({name:P,scope:`global`,fields:{code:n.text({required:!0,unique:!0,indexed:!0,maxLength:190}),name:n.text({required:!0,translatable:!0}),totalArea:n.text({maxLength:32}),livingArea:n.text({maxLength:32}),commonArea:n.text({maxLength:32}),capacity:n.number({integer:!0}),placesOccupied:n.number({integer:!0}),monthlyRent:n.text({maxLength:32}),discountedMonthlyRent:n.text({maxLength:32}),dailyRent:n.text({maxLength:32}),currency:n.text({required:!0,maxLength:3,default:`EUR`}),vatTreatment:n.select({options:F,required:!0,default:`net`}),hasEnglish:n.boolean({required:!0,default:!1}),sourceHash:n.text({maxLength:64})},behaviors:[e(),r(),j(P)],access:{view:`group.admin`,create:`group.admin`,update:`group.admin`,delete:`group.admin`},admin:{group:`yhikas`,label:`Room types`,labelSingular:`Room type`,titleField:`code`,icon:`bed-double`,description:`Synced from yhikas-admin every 6 hours. Read-only here — an edit would be reverted on the next run. Change prices in yhikas-admin.`,defaultSort:`code`,defaultSortDirection:`asc`,disableCreate:!0,hideFromDashboard:!0,hiddenFields:[`sourceHash`],hiddenColumns:[`sourceHash`]}}),L=`yhikas_site_info`,R=t({name:L,scope:`global`,fields:{key:n.text({required:!0,unique:!0,indexed:!0,maxLength:32}),receptionHours:n.text({translatable:!0,maxLength:500}),notices:n.json({translatable:!0}),hasEnglish:n.boolean({default:!1,required:!0}),sourceHash:n.text({maxLength:64})},behaviors:[e(),r(),j(L)],access:{view:`group.admin`,create:`group.admin`,update:`group.admin`,delete:`group.admin`},admin:{group:`yhikas`,label:`Site info`,titleField:`key`,disableCreate:!0,hideFromDashboard:!0,hiddenFields:[`sourceHash`],hiddenColumns:[`sourceHash`]}}),z=[I,N,R],B=a({name:`yhikas_sync_state`,columns:{resource:i.varchar({length:64,notNull:!0}),firstSeenAt:i.timestamp({notNull:!0,withTimezone:!0,defaultNow:!0,pgName:`first_seen_at`}),lastAttemptAt:i.timestamp({withTimezone:!0,pgName:`last_attempt_at`}),lastSuccessAt:i.timestamp({withTimezone:!0,pgName:`last_success_at`}),lastError:i.varchar({length:1024,pgName:`last_error`}),lastCreated:i.integer({notNull:!0,default:0,pgName:`last_created`}),lastUpdated:i.integer({notNull:!0,default:0,pgName:`last_updated`}),lastRetired:i.integer({notNull:!0,default:0,pgName:`last_retired`}),lastUnchanged:i.integer({notNull:!0,default:0,pgName:`last_unchanged`})},primaryKey:`resource`});export{l as A,y as C,f as D,x as E,o as M,c as O,S,m as T,v as _,F as a,b,M as c,j as d,T as f,_ as g,w as h,R as i,s as j,p as k,N as l,C as m,z as n,P as o,O as p,L as r,I as s,B as t,k as u,g as v,u as w,d as x,h as y};
2
- //# sourceMappingURL=sync-state-table-CM6eL5W9.mjs.map
1
+ import{auditable as e,defineEntity as t,field as n,publishable as r}from"@murumets-ee/entity";import{column as i,defineTable as a}from"@murumets-ee/db";const o=`@murumets-ee/yhikas-sync`,s=`yhikas-sync`,c=`yhikas-sync:pull`,l=`yhikas-sync:staleness-watchdog`,u=`room_types`,d=`legal_documents`,f=`site_info`,p=[u,d,f],m=`default`,h=`et`,g=`en`,_=`EUR`,v=`net`,y=`/api/public/room-types`,b=`/api/public/legal-documents`,x=`/api/public/site-info`,S=25,C=`YHIKAS_SYNC_API_KEY`,w=`YHIKAS_ADMIN_BASE_URL`;var T=class extends Error{constructor(e){super(e),this.name=`YhikasSyncConfigError`}};function E(e,t){if(!Number.isSafeInteger(e)||e<=0)throw new T(`${t} must be a positive integer, got ${e}`);return e}function D(e,t){if(!Number.isFinite(e)||e<=0)throw new T(`${t} must be a finite positive number, got ${e}`);return e}function O(e={},t=process.env){let n=e.maxRetireFraction??.5;if(!Number.isFinite(n)||n<=0||n>1)throw new T(`maxRetireFraction must be in (0, 1], got ${n}. A value of 1 disables the fraction rule; the empty-snapshot rule still applies.`);let r=e.baseUrl??t.YHIKAS_ADMIN_BASE_URL;return Object.freeze({baseUrl:r&&r.length>0?r:void 0,schedule:e.schedule??`@every 6h`,watchdogSchedule:e.watchdogSchedule??`@every 1h`,staleAfterMs:D(e.staleAfterMs??864e5,`staleAfterMs`),requestTimeoutMs:D(e.requestTimeoutMs??15e3,`requestTimeoutMs`),maxRowsPerResource:E(e.maxRowsPerResource??500,`maxRowsPerResource`),maxRetireFraction:n,minRowsForRetireFloor:E(e.minRowsForRetireFloor??3,`minRowsForRetireFloor`),enabled:e.enabled??!0})}var k=class extends Error{constructor(e,t,n){super(`'${e}' is written only by the yhikas-admin sync. Refusing ${t} by '${n}': ${t===`translation write`||t===`locale publish change`?`a change here would NOT be reverted on the next sync run — it does not alter sourceHash, so the differ reports the row unchanged and the divergence from yhikas-admin stands permanently, with no alert and no staleness`:`an edit here would be silently reverted on the next sync run, which is worse than no editor at all`}. Change the value in yhikas-admin instead.`),this.name=`YhikasSyncedContentReadOnlyError`}};function A(e,t,n){let r=n?.user?.id;if(r!==`yhikas-sync`)throw new k(e,t,r??`<unattributed>`)}function j(e){return{name:`yhikas-sync:machine-written:${e}`,hooks:{beforeCreate:async(t,n)=>(A(e,`create`,n),t),beforeUpdate:async(t,n,r)=>(A(e,`update`,r),n),beforeDelete:async(t,n)=>{A(e,`delete`,n)}},assertBulkUpdate:()=>{throw new k(e,`bulk update`,`<bulk>`)},assertTranslationWrite:(t,n)=>{A(e,t.action===`locale-status`?`locale publish change`:`translation write`,n)}}}const M=`yhikas_legal_document`,N=t({name:M,scope:`global`,fields:{type:n.text({required:!0,unique:!0,indexed:!0,maxLength:190}),title:n.text({required:!0,translatable:!0}),sourceSlug:n.text({required:!0,indexed:!0,maxLength:190}),body:n.richtext({required:!0,translatable:!0}),order:n.number({integer:!0,required:!0,default:0}),hasEnglish:n.boolean({required:!0,default:!1}),sourceHash:n.text({maxLength:64})},behaviors:[e(),r(),j(M)],access:{view:`group.admin`,create:`group.admin`,update:`group.admin`,delete:`group.admin`},admin:{group:`yhikas`,label:`Legal documents`,labelSingular:`Legal document`,titleField:`type`,icon:`file-text`,description:`Synced from yhikas-admin every 6 hours. Read-only here — an edit would be reverted on the next run. Change the text in yhikas-admin.`,defaultSort:`order`,defaultSortDirection:`asc`,disableCreate:!0,hideFromDashboard:!0,hiddenFields:[`sourceHash`],hiddenColumns:[`sourceHash`]}}),P=`yhikas_room_type`,F=[`net`,`gross`],I=t({name:P,scope:`global`,fields:{code:n.text({required:!0,unique:!0,indexed:!0,maxLength:190}),name:n.text({required:!0,translatable:!0}),totalArea:n.text({maxLength:32}),livingArea:n.text({maxLength:32}),commonArea:n.text({maxLength:32}),capacity:n.number({integer:!0}),placesOccupied:n.number({integer:!0}),monthlyRent:n.text({maxLength:32}),discountedMonthlyRent:n.text({maxLength:32}),dailyRent:n.text({maxLength:32}),currency:n.text({required:!0,maxLength:3,default:`EUR`}),vatTreatment:n.select({options:F,required:!0,default:`net`}),hasEnglish:n.boolean({required:!0,default:!1}),sourceHash:n.text({maxLength:64})},behaviors:[e(),r(),j(P)],access:{view:`group.admin`,create:`group.admin`,update:`group.admin`,delete:`group.admin`},admin:{group:`yhikas`,label:`Room types`,labelSingular:`Room type`,titleField:`code`,icon:`bed-double`,description:`Synced from yhikas-admin every 6 hours. Read-only here — an edit would be reverted on the next run. Change prices in yhikas-admin.`,defaultSort:`code`,defaultSortDirection:`asc`,disableCreate:!0,hideFromDashboard:!0,hiddenFields:[`sourceHash`],hiddenColumns:[`sourceHash`]}}),L=`yhikas_site_info`,R=t({name:L,kind:`singleton`,scope:`global`,fields:{key:n.text({required:!0,unique:!0,indexed:!0,maxLength:32}),receptionHours:n.text({translatable:!0,maxLength:500}),notices:n.json({translatable:!0}),hasEnglish:n.boolean({default:!1,required:!0}),sourceHash:n.text({maxLength:64})},behaviors:[e(),r(),j(L)],access:{view:`group.admin`,create:`group.admin`,update:`group.admin`,delete:`group.admin`},admin:{group:`yhikas`,label:`Site info`,titleField:`key`,disableCreate:!0,hideFromDashboard:!0,hiddenFields:[`sourceHash`],hiddenColumns:[`sourceHash`]}}),z=[I,N,R],B=a({name:`yhikas_sync_state`,columns:{resource:i.varchar({length:64,notNull:!0}),firstSeenAt:i.timestamp({notNull:!0,withTimezone:!0,defaultNow:!0,pgName:`first_seen_at`}),lastAttemptAt:i.timestamp({withTimezone:!0,pgName:`last_attempt_at`}),lastSuccessAt:i.timestamp({withTimezone:!0,pgName:`last_success_at`}),lastError:i.varchar({length:1024,pgName:`last_error`}),lastCreated:i.integer({notNull:!0,default:0,pgName:`last_created`}),lastUpdated:i.integer({notNull:!0,default:0,pgName:`last_updated`}),lastRetired:i.integer({notNull:!0,default:0,pgName:`last_retired`}),lastUnchanged:i.integer({notNull:!0,default:0,pgName:`last_unchanged`})},primaryKey:`resource`});export{l as A,y as C,f as D,x as E,o as M,c as O,S,m as T,v as _,F as a,b,M as c,j as d,T as f,_ as g,w as h,R as i,s as j,p as k,N as l,C as m,z as n,P as o,O as p,L as r,I as s,B as t,k as u,g as v,u as w,d as x,h as y};
2
+ //# sourceMappingURL=sync-state-table-CNkHbvbV.mjs.map