persian-data-grid 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/{ERPTableGroupRow-PSAPAHGL.js → ERPTableGroupRow-E5Q6FYDS.js} +4 -4
- package/dist/{ERPTableGroupRow-PSAPAHGL.js.map → ERPTableGroupRow-E5Q6FYDS.js.map} +1 -1
- package/dist/{ERPTableGroupRow-J5Z2LRC5.cjs → ERPTableGroupRow-F2IPDYL5.cjs} +9 -9
- package/dist/{ERPTableGroupRow-J5Z2LRC5.cjs.map → ERPTableGroupRow-F2IPDYL5.cjs.map} +1 -1
- package/dist/{GridPlugin-CJCaYnlw.d.ts → GridPlugin-Bewn0X51.d.ts} +1 -1
- package/dist/{GridPlugin-oxhq8AsM.d.cts → GridPlugin-DewWufGZ.d.cts} +1 -1
- package/dist/{GridSession-Bc7UIawO.d.ts → GridSession-CeIfVFck.d.ts} +142 -9
- package/dist/{GridSession-B-9lLcoB.d.cts → GridSession-CmQn2RnL.d.cts} +142 -9
- package/dist/GridSyncService-3JQLEY65.cjs +12 -0
- package/dist/{GridSyncService-TAPAHABV.cjs.map → GridSyncService-3JQLEY65.cjs.map} +1 -1
- package/dist/GridSyncService-GECXGEKL.js +3 -0
- package/dist/{GridSyncService-KTLB4KP3.js.map → GridSyncService-GECXGEKL.js.map} +1 -1
- package/dist/{PdfRenderer-CBg7hWNS.d.cts → PdfRenderer-B9FJaCo_.d.cts} +1 -1
- package/dist/{PdfRenderer-1HFh6UeR.d.ts → PdfRenderer-bN7ca_Aj.d.ts} +1 -1
- package/dist/{UITableController-DU8RopUM.d.ts → UITableController-C71LXBiX.d.ts} +48 -2
- package/dist/{UITableController-Cuwq481K.d.cts → UITableController-CIwnHIw8.d.cts} +48 -2
- package/dist/{VazirmatnPdfRenderer-BCMpC1zy.d.cts → VazirmatnPdfRenderer-CpCqA-Wh.d.cts} +2 -2
- package/dist/{VazirmatnPdfRenderer-Dz_G-m3c.d.ts → VazirmatnPdfRenderer-D46smncn.d.ts} +2 -2
- package/dist/adapters/arian-erp.cjs +16 -4
- package/dist/adapters/arian-erp.cjs.map +1 -1
- package/dist/adapters/arian-erp.d.cts +3 -1
- package/dist/adapters/arian-erp.d.ts +3 -1
- package/dist/adapters/arian-erp.js +11 -3
- package/dist/adapters/arian-erp.js.map +1 -1
- package/dist/{applyImportedRows-BO6yxoAN.d.cts → applyImportedRows-C2fWYoPy.d.cts} +3 -3
- package/dist/{applyImportedRows-D4zVY8uD.d.ts → applyImportedRows-Cqh_N_0k.d.ts} +3 -3
- package/dist/{applyRowVisibilityHandler-LXCOGESZ.cjs → applyRowVisibilityHandler-Q64ZFC7A.cjs} +7 -6
- package/dist/applyRowVisibilityHandler-Q64ZFC7A.cjs.map +1 -0
- package/dist/{applyRowVisibilityHandler-KS6TMCBN.js → applyRowVisibilityHandler-ZLZXQEGY.js} +6 -5
- package/dist/applyRowVisibilityHandler-ZLZXQEGY.js.map +1 -0
- package/dist/callbackRemoteApi-BYLjmSI6.d.ts +51 -0
- package/dist/callbackRemoteApi-Cv26MmSD.d.cts +51 -0
- package/dist/{cellRenderContext-DB7V_mlu.d.ts → cellRenderContext-BaNh4qn_.d.ts} +2 -2
- package/dist/{cellRenderContext-DG5BOlxK.d.cts → cellRenderContext-DvngkptV.d.cts} +2 -2
- package/dist/{chunk-HTNJT2QU.js → chunk-27ALJSZP.js} +617 -104
- package/dist/chunk-27ALJSZP.js.map +1 -0
- package/dist/{chunk-KUBVDIF7.cjs → chunk-3HP3HQCW.cjs} +52 -17
- package/dist/chunk-3HP3HQCW.cjs.map +1 -0
- package/dist/{chunk-DXRCYW42.cjs → chunk-52LFOPXD.cjs} +43 -23
- package/dist/chunk-52LFOPXD.cjs.map +1 -0
- package/dist/{chunk-VVGYRZ7S.cjs → chunk-72IVAOTK.cjs} +4 -4
- package/dist/{chunk-VVGYRZ7S.cjs.map → chunk-72IVAOTK.cjs.map} +1 -1
- package/dist/{chunk-LJ7LMEXO.js → chunk-7GWV5HGO.js} +3 -3
- package/dist/{chunk-LJ7LMEXO.js.map → chunk-7GWV5HGO.js.map} +1 -1
- package/dist/{chunk-RM6ZWNT3.js → chunk-7T6AWRPU.js} +43 -23
- package/dist/chunk-7T6AWRPU.js.map +1 -0
- package/dist/{chunk-PXCHPZTP.cjs → chunk-CMQ4VLCW.cjs} +8 -7
- package/dist/{chunk-EHHHC5JV.js.map → chunk-CMQ4VLCW.cjs.map} +1 -1
- package/dist/chunk-E2J533UH.cjs +53 -0
- package/dist/chunk-E2J533UH.cjs.map +1 -0
- package/dist/chunk-F6EMC75A.cjs +34 -0
- package/dist/chunk-F6EMC75A.cjs.map +1 -0
- package/dist/chunk-GKE33FOJ.js +32 -0
- package/dist/chunk-GKE33FOJ.js.map +1 -0
- package/dist/{chunk-QQMU44KJ.js → chunk-HLOHWFOA.js} +52 -19
- package/dist/chunk-HLOHWFOA.js.map +1 -0
- package/dist/{chunk-633KP74Z.js → chunk-KCNTKYUY.js} +19 -2
- package/dist/chunk-KCNTKYUY.js.map +1 -0
- package/dist/{chunk-BLYVOV3G.cjs → chunk-LY27YAXE.cjs} +19 -2
- package/dist/chunk-LY27YAXE.cjs.map +1 -0
- package/dist/{chunk-EHHHC5JV.js → chunk-NB5GCGHL.js} +5 -4
- package/dist/chunk-NB5GCGHL.js.map +1 -0
- package/dist/{chunk-6XBXZPBW.js → chunk-NQUVAJQA.js} +3 -3
- package/dist/{chunk-6XBXZPBW.js.map → chunk-NQUVAJQA.js.map} +1 -1
- package/dist/chunk-SVO62ZV2.js +50 -0
- package/dist/chunk-SVO62ZV2.js.map +1 -0
- package/dist/{chunk-MU3RY46O.js → chunk-VBAZ77Q4.js} +3 -3
- package/dist/{chunk-MU3RY46O.js.map → chunk-VBAZ77Q4.js.map} +1 -1
- package/dist/{chunk-H2LESGMX.cjs → chunk-VSAFQTW5.cjs} +4 -4
- package/dist/{chunk-H2LESGMX.cjs.map → chunk-VSAFQTW5.cjs.map} +1 -1
- package/dist/{chunk-2BJCRYOS.cjs → chunk-VYJQ2HTA.cjs} +5 -5
- package/dist/{chunk-2BJCRYOS.cjs.map → chunk-VYJQ2HTA.cjs.map} +1 -1
- package/dist/{chunk-IIISFUW4.cjs → chunk-WTHTVKVI.cjs} +621 -108
- package/dist/chunk-WTHTVKVI.cjs.map +1 -0
- package/dist/{createEngineGridQuery-Mt1hc33m.d.ts → createEngineGridQuery-BBkud5oE.d.ts} +61 -6
- package/dist/{createEngineGridQuery-Dmq3i5v3.d.cts → createEngineGridQuery-D-fgO_jg.d.cts} +61 -6
- package/dist/date-picker-jalali.cjs +17 -17
- package/dist/date-picker-jalali.d.cts +3 -3
- package/dist/date-picker-jalali.d.ts +3 -3
- package/dist/date-picker-jalali.js +1 -1
- package/dist/headless.cjs +102 -102
- package/dist/headless.d.cts +13 -9
- package/dist/headless.d.ts +13 -9
- package/dist/headless.js +4 -4
- package/dist/index.cjs +440 -382
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +34 -14
- package/dist/index.d.ts +34 -14
- package/dist/index.js +200 -143
- package/dist/index.js.map +1 -1
- package/dist/plugins/csv.cjs +3 -3
- package/dist/plugins/csv.d.cts +2 -2
- package/dist/plugins/csv.d.ts +2 -2
- package/dist/plugins/csv.js +2 -2
- package/dist/plugins/excel.cjs +11 -11
- package/dist/plugins/excel.d.cts +4 -4
- package/dist/plugins/excel.d.ts +4 -4
- package/dist/plugins/excel.js +3 -3
- package/dist/plugins/pdf/fonts/vazirmatn.cjs +6 -6
- package/dist/plugins/pdf/fonts/vazirmatn.d.cts +4 -4
- package/dist/plugins/pdf/fonts/vazirmatn.d.ts +4 -4
- package/dist/plugins/pdf/fonts/vazirmatn.js +3 -3
- package/dist/plugins/pdf.cjs +5 -5
- package/dist/plugins/pdf.d.cts +5 -5
- package/dist/plugins/pdf.d.ts +5 -5
- package/dist/plugins/pdf.js +2 -2
- package/dist/presence.d.cts +3 -3
- package/dist/presence.d.ts +3 -3
- package/dist/sync.cjs +2 -2
- package/dist/sync.d.cts +3 -3
- package/dist/sync.d.ts +3 -3
- package/dist/sync.js +1 -1
- package/package.json +3 -3
- package/dist/GridSyncService-KTLB4KP3.js +0 -3
- package/dist/GridSyncService-TAPAHABV.cjs +0 -12
- package/dist/applyRowVisibilityHandler-KS6TMCBN.js.map +0 -1
- package/dist/applyRowVisibilityHandler-LXCOGESZ.cjs.map +0 -1
- package/dist/callbackRemoteApi-BlXO5NJz.d.ts +0 -30
- package/dist/callbackRemoteApi-DgnXH-i0.d.cts +0 -30
- package/dist/chunk-633KP74Z.js.map +0 -1
- package/dist/chunk-ASPTRYRD.cjs +0 -21
- package/dist/chunk-ASPTRYRD.cjs.map +0 -1
- package/dist/chunk-BHDRUZH5.cjs +0 -33
- package/dist/chunk-BHDRUZH5.cjs.map +0 -1
- package/dist/chunk-BLYVOV3G.cjs.map +0 -1
- package/dist/chunk-DXRCYW42.cjs.map +0 -1
- package/dist/chunk-HTNJT2QU.js.map +0 -1
- package/dist/chunk-IIISFUW4.cjs.map +0 -1
- package/dist/chunk-KUBVDIF7.cjs.map +0 -1
- package/dist/chunk-KYAOSBQN.js +0 -31
- package/dist/chunk-KYAOSBQN.js.map +0 -1
- package/dist/chunk-PXCHPZTP.cjs.map +0 -1
- package/dist/chunk-QQMU44KJ.js.map +0 -1
- package/dist/chunk-RM6ZWNT3.js.map +0 -1
- package/dist/chunk-Y6W5V2CI.js +0 -19
- package/dist/chunk-Y6W5V2CI.js.map +0 -1
|
@@ -2,7 +2,7 @@ import { getLocalePack, resolveDirection } from './chunk-SZ7BLAY3.js';
|
|
|
2
2
|
import { jalaliAdapter, pad2, gregorianDateToJalali, jalaliToGregorianDate, jalaliMonthLength } from './chunk-GQEDLUMB.js';
|
|
3
3
|
import { subscribeCatalogHostEvents } from './chunk-MUQQKPWR.js';
|
|
4
4
|
import { normalizeDigits } from './chunk-AU3RDJYQ.js';
|
|
5
|
-
import { createContext, useMemo, useEffect,
|
|
5
|
+
import { createContext, useContext, useMemo, useEffect, useCallback, useState, useRef } from 'react';
|
|
6
6
|
import { jsx } from 'react/jsx-runtime';
|
|
7
7
|
|
|
8
8
|
// infrastructure/date/gregorianAdapter.ts
|
|
@@ -322,18 +322,26 @@ function ERPTableHostProvider({
|
|
|
322
322
|
numberingSystem,
|
|
323
323
|
dateAdapter,
|
|
324
324
|
remoteApi,
|
|
325
|
-
messages,
|
|
326
|
-
onToast,
|
|
325
|
+
messages: messagesProp,
|
|
326
|
+
onToast: onToastProp,
|
|
327
327
|
theme = themeErp,
|
|
328
328
|
themeToggle = true,
|
|
329
329
|
themeLocked = false,
|
|
330
330
|
onToggleTheme,
|
|
331
|
-
components,
|
|
332
|
-
filterComponents,
|
|
333
|
-
columnMenuItems,
|
|
334
|
-
onColumnMenuAction,
|
|
335
|
-
useDependOn
|
|
331
|
+
components: componentsProp,
|
|
332
|
+
filterComponents: filterComponentsProp,
|
|
333
|
+
columnMenuItems: columnMenuItemsProp,
|
|
334
|
+
onColumnMenuAction: onColumnMenuActionProp,
|
|
335
|
+
useDependOn: useDependOnProp
|
|
336
336
|
}) {
|
|
337
|
+
const outer = useContext(ERPTableHostContext);
|
|
338
|
+
const messages = messagesProp ?? outer.messages;
|
|
339
|
+
const onToast = onToastProp ?? outer.onToast;
|
|
340
|
+
const components = componentsProp ?? outer.components;
|
|
341
|
+
const filterComponents = filterComponentsProp ?? outer.filterComponents;
|
|
342
|
+
const columnMenuItems = columnMenuItemsProp ?? outer.columnMenuItems;
|
|
343
|
+
const onColumnMenuAction = onColumnMenuActionProp ?? outer.onColumnMenuAction;
|
|
344
|
+
const useDependOn = useDependOnProp ?? outer.useDependOn;
|
|
337
345
|
const value = useMemo(
|
|
338
346
|
() => ({
|
|
339
347
|
locale,
|
|
@@ -389,10 +397,13 @@ function useThemePortalStyle(extra) {
|
|
|
389
397
|
}
|
|
390
398
|
function useTranslations() {
|
|
391
399
|
const { locale, messages } = useERPTableHost();
|
|
392
|
-
return (
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
400
|
+
return useCallback(
|
|
401
|
+
(key, vars) => {
|
|
402
|
+
const raw = translate(key, locale, messages);
|
|
403
|
+
return vars ? formatMessage(raw, vars) : raw;
|
|
404
|
+
},
|
|
405
|
+
[locale, messages]
|
|
406
|
+
);
|
|
396
407
|
}
|
|
397
408
|
function useLocale() {
|
|
398
409
|
return useERPTableHost().locale;
|
|
@@ -505,16 +516,27 @@ function useMediaQuery(query) {
|
|
|
505
516
|
}, [media]);
|
|
506
517
|
return { match };
|
|
507
518
|
}
|
|
519
|
+
function useLatest(value) {
|
|
520
|
+
const ref = useRef(value);
|
|
521
|
+
ref.current = value;
|
|
522
|
+
return ref;
|
|
523
|
+
}
|
|
524
|
+
function errorMessage(error) {
|
|
525
|
+
return error instanceof Error ? error.message : "Remote request failed";
|
|
526
|
+
}
|
|
508
527
|
function useRemoteQuery(args) {
|
|
509
|
-
const { remoteApi } = useERPTableHost();
|
|
528
|
+
const { remoteApi, onToast } = useERPTableHost();
|
|
529
|
+
const toastRef = useLatest(onToast);
|
|
510
530
|
const [data, setData] = useState(null);
|
|
511
531
|
const [isFetching, setIsFetching] = useState(false);
|
|
532
|
+
const [error, setError] = useState(null);
|
|
512
533
|
const refetch = useCallback(async () => {
|
|
513
534
|
if (!args.url || args.skip || !remoteApi) {
|
|
514
535
|
setData(null);
|
|
515
536
|
return;
|
|
516
537
|
}
|
|
517
538
|
setIsFetching(true);
|
|
539
|
+
setError(null);
|
|
518
540
|
try {
|
|
519
541
|
const response = await remoteApi.request({
|
|
520
542
|
endpoint: args.url,
|
|
@@ -522,6 +544,10 @@ function useRemoteQuery(args) {
|
|
|
522
544
|
method: "POST"
|
|
523
545
|
});
|
|
524
546
|
setData(response ?? null);
|
|
547
|
+
} catch (e) {
|
|
548
|
+
setData(null);
|
|
549
|
+
setError(e);
|
|
550
|
+
toastRef.current?.("error", errorMessage(e), e);
|
|
525
551
|
} finally {
|
|
526
552
|
setIsFetching(false);
|
|
527
553
|
}
|
|
@@ -529,12 +555,14 @@ function useRemoteQuery(args) {
|
|
|
529
555
|
useEffect(() => {
|
|
530
556
|
void refetch();
|
|
531
557
|
}, [refetch]);
|
|
532
|
-
return { data, isFetching, refetch };
|
|
558
|
+
return { data, isFetching, error, refetch };
|
|
533
559
|
}
|
|
534
560
|
function useLazyRemote() {
|
|
535
|
-
const { remoteApi } = useERPTableHost();
|
|
561
|
+
const { remoteApi, onToast } = useERPTableHost();
|
|
562
|
+
const toastRef = useLatest(onToast);
|
|
536
563
|
const [data, setData] = useState(null);
|
|
537
564
|
const [isFetching, setIsFetching] = useState(false);
|
|
565
|
+
const [error, setError] = useState(null);
|
|
538
566
|
const trigger = useCallback(
|
|
539
567
|
async (args) => {
|
|
540
568
|
if (!args.url || !remoteApi) {
|
|
@@ -542,16 +570,21 @@ function useLazyRemote() {
|
|
|
542
570
|
return;
|
|
543
571
|
}
|
|
544
572
|
setIsFetching(true);
|
|
573
|
+
setError(null);
|
|
545
574
|
try {
|
|
546
575
|
const response = await remoteApi.request({ endpoint: args.url, params: args.body, method: "POST" });
|
|
547
576
|
setData(response ?? null);
|
|
577
|
+
} catch (e) {
|
|
578
|
+
setData(null);
|
|
579
|
+
setError(e);
|
|
580
|
+
toastRef.current?.("error", errorMessage(e), e);
|
|
548
581
|
} finally {
|
|
549
582
|
setIsFetching(false);
|
|
550
583
|
}
|
|
551
584
|
},
|
|
552
585
|
[remoteApi]
|
|
553
586
|
);
|
|
554
|
-
return [trigger, { data, isFetching }];
|
|
587
|
+
return [trigger, { data, isFetching, error }];
|
|
555
588
|
}
|
|
556
589
|
|
|
557
590
|
// ui/host/toast.ts
|
|
@@ -607,6 +640,6 @@ function useGridHostEvents(input) {
|
|
|
607
640
|
}, [input.ready, input.controller, input.eventStore, input.tableKey]);
|
|
608
641
|
}
|
|
609
642
|
|
|
610
|
-
export { AR_MESSAGES, EN_MESSAGES, ERPTableHostProvider, FA_MESSAGES, GridTheme, JALALI_WEEKDAY_LABELS_FA, addJalaliMonths, bindGridHostEvents, buildDependencyBody, buildJalaliMonthGrid, compareJalaliDay, gregorianAdapter, hasDependValue, isDateInRange, isStockDarkTheme, jalaliMonthName, resolveActiveTheme, sameJalaliDay, themeDark, themeDefault, themeErp, themeErpDark, themeToStyle, toJalaliYmd, translate, useDateAdapter, useDirection, useERPTableHost, useERPTableTheme, useGridHostEvents, useHostDependOn, useHostToast, useLazyRemote, useLocale, useMediaQuery, useNumberingSystem, useRemoteQuery, useStaticDependOn, useThemePortalStyle, useTranslations };
|
|
611
|
-
//# sourceMappingURL=chunk-
|
|
612
|
-
//# sourceMappingURL=chunk-
|
|
643
|
+
export { AR_MESSAGES, EN_MESSAGES, ERPTableHostProvider, FA_MESSAGES, GridTheme, JALALI_WEEKDAY_LABELS_FA, addJalaliMonths, bindGridHostEvents, buildDependencyBody, buildJalaliMonthGrid, compareJalaliDay, getDependFieldName, getStaticDependValue, gregorianAdapter, hasDependValue, isDateInRange, isStockDarkTheme, jalaliMonthName, resolveActiveTheme, sameJalaliDay, themeDark, themeDefault, themeErp, themeErpDark, themeToStyle, toJalaliYmd, translate, useDateAdapter, useDirection, useERPTableHost, useERPTableTheme, useGridHostEvents, useHostDependOn, useHostToast, useLazyRemote, useLocale, useMediaQuery, useNumberingSystem, useRemoteQuery, useStaticDependOn, useThemePortalStyle, useTranslations };
|
|
644
|
+
//# sourceMappingURL=chunk-HLOHWFOA.js.map
|
|
645
|
+
//# sourceMappingURL=chunk-HLOHWFOA.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../infrastructure/date/gregorianAdapter.ts","../infrastructure/date/jalaliCalendarModel.ts","../ui/theme/GridTheme.ts","../ui/theme/resolveActiveTheme.ts","../ui/theme/applyCssVars.ts","../ui/host/messages.ts","../ui/host/ERPTableHost.tsx","../ui/host/dependOn.ts","../ui/host/bindGridHostEvents.ts","../ui/host/useMediaQuery.ts","../ui/host/useRemoteQuery.ts","../ui/host/toast.ts","../ui/host/useGridHostEvents.ts"],"names":["useEffect","useState","useCallback","useRef"],"mappings":"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","file":"chunk-HLOHWFOA.js","sourcesContent":["import type { DateAdapter } from '../../application/ports/DateAdapter';\r\nimport { normalizeDigits } from '../../engine/dataOps/sortModel';\r\nimport { pad2 } from './jalaliMath';\r\n\r\nconst ISO_RE = /^(\\d{4})-(\\d{2})-(\\d{2})$/;\r\nconst SLASH_RE = /^(\\d{4})[/\\-.](\\d{1,2})[/\\-.](\\d{1,2})$/;\r\n\r\nfunction utcDay(y: number, m: number, d: number): Date {\r\n return new Date(Date.UTC(y, m - 1, d, 12, 0, 0));\r\n}\r\n\r\nfunction asUtcDay(date: Date): Date {\r\n return utcDay(date.getUTCFullYear(), date.getUTCMonth() + 1, date.getUTCDate());\r\n}\r\n\r\n/** Gregorian calendar adapter (PR-128 / D21). */\r\nexport const gregorianAdapter: DateAdapter = {\r\n id: 'gregory',\r\n\r\n parse(input: unknown): Date | null {\r\n if (input == null || input === '') return null;\r\n if (input instanceof Date && !Number.isNaN(input.getTime())) {\r\n return asUtcDay(input);\r\n }\r\n if (typeof input === 'number' && Number.isFinite(input)) {\r\n const d = new Date(input);\r\n return Number.isNaN(d.getTime()) ? null : asUtcDay(d);\r\n }\r\n const text = normalizeDigits(String(input).trim());\r\n const iso = ISO_RE.exec(text);\r\n if (iso) {\r\n return utcDay(Number(iso[1]), Number(iso[2]), Number(iso[3]));\r\n }\r\n const slash = SLASH_RE.exec(text);\r\n if (slash) {\r\n return utcDay(Number(slash[1]), Number(slash[2]), Number(slash[3]));\r\n }\r\n const fallback = new Date(text);\r\n return Number.isNaN(fallback.getTime()) ? null : asUtcDay(fallback);\r\n },\r\n\r\n format(date: Date): string {\r\n const d = asUtcDay(date);\r\n return `${d.getUTCFullYear()}-${pad2(d.getUTCMonth() + 1)}-${pad2(d.getUTCDate())}`;\r\n },\r\n\r\n addDays(date: Date, days: number): Date {\r\n const next = asUtcDay(date);\r\n next.setUTCDate(next.getUTCDate() + days);\r\n return next;\r\n },\r\n\r\n startOfMonth(date: Date): Date {\r\n const d = asUtcDay(date);\r\n return utcDay(d.getUTCFullYear(), d.getUTCMonth() + 1, 1);\r\n },\r\n\r\n compare(a: Date, b: Date): number {\r\n return asUtcDay(a).getTime() - asUtcDay(b).getTime();\r\n },\r\n};\r\n","/**\r\n * Pure Jalali month-grid helpers for the internal picker (PR-140).\r\n */\r\n\r\nimport {\r\n gregorianDateToJalali,\r\n jalaliMonthLength,\r\n jalaliToGregorianDate,\r\n} from './jalaliMath';\r\n\r\nexport type JalaliYmd = { jy: number; jm: number; jd: number };\r\n\r\nexport type CalendarCell = {\r\n ymd: JalaliYmd;\r\n date: Date;\r\n inCurrentMonth: boolean;\r\n /** 0 = Saturday … 6 = Friday (Jalali week starts Saturday). */\r\n weekday: number;\r\n};\r\n\r\nconst MONTH_NAMES_FA = [\r\n 'فروردین',\r\n 'اردیبهشت',\r\n 'خرداد',\r\n 'تیر',\r\n 'مرداد',\r\n 'شهریور',\r\n 'مهر',\r\n 'آبان',\r\n 'آذر',\r\n 'دی',\r\n 'بهمن',\r\n 'اسفند',\r\n] as const;\r\n\r\nexport const JALALI_WEEKDAY_LABELS_FA = [\r\n 'ش',\r\n 'ی',\r\n 'د',\r\n 'س',\r\n 'چ',\r\n 'پ',\r\n 'ج',\r\n] as const;\r\n\r\nexport function jalaliMonthName(jm: number): string {\r\n return MONTH_NAMES_FA[jm - 1] ?? String(jm);\r\n}\r\n\r\nexport function toJalaliYmd(date: Date): JalaliYmd {\r\n return gregorianDateToJalali(utcNoon(date));\r\n}\r\n\r\nexport function fromJalaliYmd(ymd: JalaliYmd): Date {\r\n return jalaliToGregorianDate(ymd.jy, ymd.jm, ymd.jd);\r\n}\r\n\r\nexport function sameJalaliDay(a: Date, b: Date): boolean {\r\n const x = toJalaliYmd(a);\r\n const y = toJalaliYmd(b);\r\n return x.jy === y.jy && x.jm === y.jm && x.jd === y.jd;\r\n}\r\n\r\nexport function compareJalaliDay(a: Date, b: Date): number {\r\n return utcNoon(a).getTime() - utcNoon(b).getTime();\r\n}\r\n\r\nexport function addJalaliMonths(\r\n jy: number,\r\n jm: number,\r\n delta: number,\r\n): { jy: number; jm: number } {\r\n const idx = jy * 12 + (jm - 1) + delta;\r\n return {\r\n jy: Math.floor(idx / 12),\r\n jm: (idx % 12) + 1,\r\n };\r\n}\r\n\r\n/**\r\n * 6×7 grid of days for a Jalali month. Week starts Saturday.\r\n * Leading/trailing cells may belong to adjacent months (`inCurrentMonth: false`).\r\n */\r\nexport function buildJalaliMonthGrid(jy: number, jm: number): CalendarCell[] {\r\n const first = jalaliToGregorianDate(jy, jm, 1);\r\n const jsDow = first.getUTCDay();\r\n const jalaliWeekStart = (jsDow + 1) % 7;\r\n const daysInMonth = jalaliMonthLength(jy, jm);\r\n const cells: CalendarCell[] = [];\r\n\r\n for (let i = 0; i < 42; i += 1) {\r\n const offset = i - jalaliWeekStart;\r\n let cellJy = jy;\r\n let cellJm = jm;\r\n let cellJd: number;\r\n let inCurrentMonth = true;\r\n\r\n if (offset < 0) {\r\n const prev = addJalaliMonths(jy, jm, -1);\r\n cellJy = prev.jy;\r\n cellJm = prev.jm;\r\n cellJd = jalaliMonthLength(cellJy, cellJm) + offset + 1;\r\n inCurrentMonth = false;\r\n } else if (offset >= daysInMonth) {\r\n const next = addJalaliMonths(jy, jm, 1);\r\n cellJy = next.jy;\r\n cellJm = next.jm;\r\n cellJd = offset - daysInMonth + 1;\r\n inCurrentMonth = false;\r\n } else {\r\n cellJd = offset + 1;\r\n }\r\n\r\n const date = jalaliToGregorianDate(cellJy, cellJm, cellJd);\r\n cells.push({\r\n ymd: { jy: cellJy, jm: cellJm, jd: cellJd },\r\n date,\r\n inCurrentMonth,\r\n weekday: i % 7,\r\n });\r\n }\r\n return cells;\r\n}\r\n\r\nexport type DateRangeValue = {\r\n start: Date | null;\r\n end: Date | null;\r\n};\r\n\r\nexport function isDateInRange(date: Date, range: DateRangeValue): boolean {\r\n if (!range.start) return false;\r\n if (!range.end) return sameJalaliDay(date, range.start);\r\n const t = utcNoon(date).getTime();\r\n const a = utcNoon(range.start).getTime();\r\n const b = utcNoon(range.end).getTime();\r\n return t >= Math.min(a, b) && t <= Math.max(a, b);\r\n}\r\n\r\nfunction utcNoon(date: Date): Date {\r\n return new Date(\r\n Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), 12),\r\n );\r\n}\r\n","export type ThemeParams = {\r\n backgroundColor: string;\r\n foregroundColor: string;\r\n accentColor: string;\r\n headerBackgroundColor: string;\r\n rowStripeColor: string;\r\n rowSelectedColor: string;\r\n borderColor: string;\r\n dangerColor: string;\r\n searchMatchColor: string;\r\n fontFamily: string;\r\n rowHeight: number;\r\n cellFontSize: number;\r\n borderRadius: string;\r\n};\r\n\r\nexport type ThemeCssVars = Record<string, string>;\r\n\r\n/** `--erp-*` mirrors `--pdg-*` for one version (PR-87 / D13). */\r\nfunction aliasErpTokens(vars: ThemeCssVars): ThemeCssVars {\r\n const out: ThemeCssVars = {};\r\n for (const [key, value] of Object.entries(vars)) {\r\n if (key.startsWith('--pdg-')) {\r\n out[`--erp-${key.slice('--pdg-'.length)}`] = value;\r\n }\r\n }\r\n return out;\r\n}\r\n\r\nexport class GridTheme {\r\n constructor(\r\n readonly params: ThemeParams,\r\n readonly extraCssVars: ThemeCssVars = {},\r\n ) {}\r\n\r\n withParams(partial: Partial<ThemeParams>): GridTheme {\r\n return new GridTheme({ ...this.params, ...partial }, this.extraCssVars);\r\n }\r\n\r\n withExtraCssVars(extra: ThemeCssVars): GridTheme {\r\n return new GridTheme(this.params, { ...this.extraCssVars, ...extra });\r\n }\r\n\r\n toCssVars(): ThemeCssVars {\r\n const p = this.params;\r\n const roles: ThemeCssVars = {\r\n '--pdg-bg': p.backgroundColor,\r\n '--pdg-fg': p.foregroundColor,\r\n '--pdg-accent': p.accentColor,\r\n '--pdg-header-bg': p.headerBackgroundColor,\r\n '--pdg-row-stripe': p.rowStripeColor,\r\n '--pdg-row-selected': p.rowSelectedColor,\r\n '--pdg-border': p.borderColor,\r\n '--pdg-danger': p.dangerColor,\r\n '--pdg-search-match': p.searchMatchColor,\r\n '--pdg-font': p.fontFamily,\r\n '--pdg-row-height': `${p.rowHeight}px`,\r\n '--pdg-font-size': `${p.cellFontSize}px`,\r\n '--pdg-radius': p.borderRadius,\r\n };\r\n return {\r\n ...roles,\r\n ...aliasErpTokens(roles),\r\n ...this.extraCssVars,\r\n ...aliasErpTokens(this.extraCssVars),\r\n };\r\n }\r\n}\r\n\r\n/** Default grid chrome — same computed colors as the CSS palette aliases. */\r\nexport const themeDefault = new GridTheme({\r\n backgroundColor: '#fff',\r\n foregroundColor: '#292929',\r\n accentColor: '#0658b0',\r\n headerBackgroundColor: '#f4f4f4',\r\n rowStripeColor: '#ddecfd',\r\n rowSelectedColor: '#dbeafe',\r\n borderColor: '#ececec',\r\n dangerColor: '#dc2626',\r\n searchMatchColor: '#facc15',\r\n fontFamily: 'IRANSans, Tahoma, sans-serif',\r\n rowHeight: 40,\r\n cellFontSize: 12,\r\n borderRadius: '0.25rem',\r\n});\r\n\r\n/** @deprecated Use {@link themeDefault}. Removed in 1.0.0. */\r\nexport const themeErp = themeDefault;\r\n\r\n/** Dark chrome. Palette extras keep leftover gray utilities readable. */\r\nconst DARK_PALETTE_VARS: ThemeCssVars = {\r\n '--pdg-main-white': '#171717',\r\n '--pdg-main-black': '#f4f4f4',\r\n '--pdg-gray-3': '#262626',\r\n '--pdg-gray-5': '#404040',\r\n '--pdg-gray-6': '#525252',\r\n '--pdg-gray-7': '#a3a3a3',\r\n '--pdg-gray-8': '#d4d4d4',\r\n '--pdg-gray-85': '#d4d4d4',\r\n '--pdg-gray-9': '#e5e5e5',\r\n '--pdg-gray-10': '#f5f5f5',\r\n '--pdg-gray-11': '#fafafa',\r\n '--pdg-black-6': '#f4f4f4',\r\n '--pdg-blue-6': '#60a5fa',\r\n '--pdg-blue-11': '#1e3a5f',\r\n '--pdg-blue-100': '#1e3a8a',\r\n '--pdg-red-100': '#7f1d1d',\r\n '--pdg-red-300': '#fca5a5',\r\n '--pdg-red-600': '#f87171',\r\n '--pdg-yellow-200': '#854d0e',\r\n '--pdg-yellow-400': '#eab308',\r\n '--pdg-zinc-200': '#3f3f46',\r\n '--pdg-neutral-500': '#a3a3a3',\r\n '--pdg-gray-100': '#27272a',\r\n '--pdg-scrollbar': '#525252',\r\n '--pdg-overlay': 'rgba(0, 0, 0, 0.55)',\r\n};\r\n\r\nexport const themeDark = themeDefault\r\n .withParams({\r\n backgroundColor: '#171717',\r\n foregroundColor: '#f4f4f4',\r\n accentColor: '#60a5fa',\r\n headerBackgroundColor: '#262626',\r\n rowStripeColor: '#1e3a5f',\r\n rowSelectedColor: '#1e3a8a',\r\n borderColor: '#404040',\r\n dangerColor: '#f87171',\r\n searchMatchColor: '#eab308',\r\n })\r\n .withExtraCssVars(DARK_PALETTE_VARS);\r\n\r\n/** @deprecated Use {@link themeDark}. Removed in 1.0.0. */\r\nexport const themeErpDark = themeDark;\r\n","import {\r\n GridTheme,\r\n type ThemeParams,\r\n themeErp,\r\n themeErpDark,\r\n} from './GridTheme';\r\n\r\nexport function themeParamsEqual(a: ThemeParams, b: ThemeParams): boolean {\r\n return (\r\n a.backgroundColor === b.backgroundColor &&\r\n a.foregroundColor === b.foregroundColor &&\r\n a.accentColor === b.accentColor &&\r\n a.headerBackgroundColor === b.headerBackgroundColor &&\r\n a.rowStripeColor === b.rowStripeColor &&\r\n a.rowSelectedColor === b.rowSelectedColor &&\r\n a.borderColor === b.borderColor &&\r\n a.dangerColor === b.dangerColor &&\r\n a.searchMatchColor === b.searchMatchColor &&\r\n a.fontFamily === b.fontFamily &&\r\n a.rowHeight === b.rowHeight &&\r\n a.cellFontSize === b.cellFontSize &&\r\n a.borderRadius === b.borderRadius\r\n );\r\n}\r\n\r\nexport function isStockLightTheme(theme: GridTheme): boolean {\r\n return themeParamsEqual(theme.params, themeErp.params);\r\n}\r\n\r\nexport function isStockDarkTheme(theme: GridTheme): boolean {\r\n return themeParamsEqual(theme.params, themeErpDark.params);\r\n}\r\n\r\n/** Built-in light/dark. Any `withParams` change locks the product toggle. */\r\nexport function isStockTheme(theme: GridTheme): boolean {\r\n return isStockLightTheme(theme) || isStockDarkTheme(theme);\r\n}\r\n\r\nexport function resolveActiveTheme(input: {\r\n requested?: GridTheme;\r\n preferDark: boolean;\r\n}): { theme: GridTheme; locked: boolean } {\r\n const requested = input.requested ?? themeErp;\r\n const locked = !isStockTheme(requested);\r\n if (locked) return { theme: requested, locked: true };\r\n return {\r\n theme: input.preferDark ? themeErpDark : themeErp,\r\n locked: false,\r\n };\r\n}\r\n","import type { CSSProperties } from 'react';\r\n\r\nimport type { GridTheme, ThemeCssVars } from './GridTheme';\r\nimport { themeErp } from './GridTheme';\r\n\r\nlet lastVars: ThemeCssVars = themeErp.toCssVars();\r\n\r\nexport function rememberThemeVars(vars: ThemeCssVars): void {\r\n lastVars = vars;\r\n}\r\n\r\nexport function getRememberedThemeVars(): ThemeCssVars {\r\n return lastVars;\r\n}\r\n\r\nexport function themeToStyle(\r\n theme: GridTheme,\r\n extra?: CSSProperties,\r\n): CSSProperties {\r\n return { ...theme.toCssVars(), ...extra } as CSSProperties;\r\n}\r\n\r\n/** Copy last (or given) theme vars onto an imperative DOM node (toasts). */\r\nexport function assignThemeVars(\r\n el: HTMLElement,\r\n vars: ThemeCssVars = lastVars,\r\n): void {\r\n for (const [key, value] of Object.entries(vars)) {\r\n el.style.setProperty(key, value);\r\n }\r\n}\r\n","import {\r\n getLocalePack,\r\n type ERPTableLocale,\r\n type ERPTableMessages,\r\n} from '../locales';\r\n\r\nexport type { ERPTableLocale, ERPTableMessages } from '../locales';\r\nexport {\r\n arMessages,\r\n enMessages,\r\n faMessages,\r\n formatLocaleDate,\r\n formatLocaleNumber,\r\n getLocalePack,\r\n LOCALE_META,\r\n LOCALE_PACKS,\r\n resolveDirection,\r\n resolveLocaleMeta,\r\n} from '../locales';\r\nexport type { LocaleMeta, NumberingSystem } from '../locales';\r\n\r\n/** @deprecated Prefer `faMessages` from `persian-data-grid/locales/fa`. */\r\nexport const FA_MESSAGES: ERPTableMessages = getLocalePack('fa');\r\n/** @deprecated Prefer `enMessages` from `persian-data-grid/locales/en`. */\r\nexport const EN_MESSAGES: ERPTableMessages = getLocalePack('en');\r\n/** Arabic pack alias (PR-127). */\r\nexport const AR_MESSAGES: ERPTableMessages = getLocalePack('ar');\r\n\r\nexport function translate(\r\n key: string,\r\n locale: ERPTableLocale,\r\n overrides?: Partial<ERPTableMessages>,\r\n): string {\r\n const pack = getLocalePack(locale);\r\n return overrides?.[key] ?? pack[key] ?? key;\r\n}\r\n\r\n/** Replace `{name}` tokens in a message template (PR-125). */\r\nexport function formatMessage(\r\n template: string,\r\n vars: Record<string, string | number>,\r\n): string {\r\n return template.replace(/\\{(\\w+)\\}/g, (_, name: string) => {\r\n const value = vars[name];\r\n return value == null ? `{${name}}` : String(value);\r\n });\r\n}\r\n","\"use client\";\r\n\r\nimport React, {\r\n createContext,\r\n useCallback,\r\n useContext,\r\n useEffect,\r\n useMemo,\r\n type CSSProperties,\r\n type ReactNode,\r\n} from 'react';\r\n\r\nimport type { DateAdapter } from '../../application/ports/DateAdapter';\r\nimport type { UseDependOnHook } from './dependOn';\r\nimport type { RemoteApi } from '../../application/ports/RemoteApi';\r\nimport type { ColumnMenuItemsConfig } from '../../engine/dataOps/columnMenu';\r\nimport {\r\n gregorianAdapter,\r\n jalaliAdapter,\r\n} from '../../infrastructure/date';\r\nimport type { CellComponentMap } from '../cellRenderer/cellRegistry';\r\nimport type { ColumnMenuActionEvent } from '../desktop/ColumnMenuPopover';\r\nimport type { FilterComponentMap } from '../filters';\r\nimport {\r\n GridTheme,\r\n rememberThemeVars,\r\n themeErp,\r\n themeToStyle,\r\n} from '../theme';\r\nimport {\r\n formatMessage,\r\n resolveDirection,\r\n type ERPTableLocale,\r\n type ERPTableMessages,\r\n type NumberingSystem,\r\n translate,\r\n} from './messages';\r\n\r\nexport type ERPTableToastKind = 'success' | 'error';\r\n\r\nexport type ERPTableHostValue = {\r\n locale: ERPTableLocale;\r\n direction: 'rtl' | 'ltr';\r\n /** Intl digit system (PR-127). Default from locale meta. */\r\n numberingSystem?: NumberingSystem;\r\n /**\r\n * Calendar port (PR-128 / D21). Default: `jalaliAdapter` for `fa`,\r\n * otherwise `gregorianAdapter`.\r\n */\r\n dateAdapter?: DateAdapter;\r\n remoteApi?: RemoteApi;\r\n messages?: Partial<ERPTableMessages>;\r\n onToast?: (kind: ERPTableToastKind, message: string, detail?: unknown) => void;\r\n theme?: GridTheme;\r\n themeToggle?: boolean;\r\n themeLocked?: boolean;\r\n onToggleTheme?: () => void;\r\n components?: CellComponentMap;\r\n /** Custom column filter UIs (PR-95). Keys match `ColumnDef.filter`. */\r\n filterComponents?: FilterComponentMap;\r\n /** Column header menu items (PR-114). */\r\n columnMenuItems?: ColumnMenuItemsConfig;\r\n /** Custom column menu action handler (PR-114). */\r\n onColumnMenuAction?: (event: ColumnMenuActionEvent) => void;\r\n /**\r\n * Resolves `dependOn` values for remote lists (e.g. from the form that owns\r\n * the grid — Redux, React context, …). Default: static item values.\r\n */\r\n useDependOn?: UseDependOnHook;\r\n};\r\n\r\nfunction defaultDateAdapter(locale: ERPTableLocale): DateAdapter {\r\n return locale === 'fa' ? jalaliAdapter : gregorianAdapter;\r\n}\r\n\r\nconst ERPTableHostContext = createContext<ERPTableHostValue>({\r\n locale: 'fa',\r\n direction: 'rtl',\r\n dateAdapter: jalaliAdapter,\r\n theme: themeErp,\r\n themeToggle: true,\r\n themeLocked: false,\r\n});\r\n\r\nexport function ERPTableHostProvider({\r\n children,\r\n locale = 'fa',\r\n direction,\r\n numberingSystem,\r\n dateAdapter,\r\n remoteApi,\r\n messages: messagesProp,\r\n onToast: onToastProp,\r\n theme = themeErp,\r\n themeToggle = true,\r\n themeLocked = false,\r\n onToggleTheme,\r\n components: componentsProp,\r\n filterComponents: filterComponentsProp,\r\n columnMenuItems: columnMenuItemsProp,\r\n onColumnMenuAction: onColumnMenuActionProp,\r\n useDependOn: useDependOnProp,\r\n}: ERPTableHostValue & { children: ReactNode }) {\r\n // Host-injection fields fall back to an outer provider (the host app wraps\r\n // the grid); explicit props always win.\r\n const outer = useContext(ERPTableHostContext);\r\n const messages = messagesProp ?? outer.messages;\r\n const onToast = onToastProp ?? outer.onToast;\r\n const components = componentsProp ?? outer.components;\r\n const filterComponents = filterComponentsProp ?? outer.filterComponents;\r\n const columnMenuItems = columnMenuItemsProp ?? outer.columnMenuItems;\r\n const onColumnMenuAction = onColumnMenuActionProp ?? outer.onColumnMenuAction;\r\n const useDependOn = useDependOnProp ?? outer.useDependOn;\r\n const value = useMemo<ERPTableHostValue>(\r\n () => ({\r\n locale,\r\n direction: resolveDirection(locale, direction),\r\n numberingSystem,\r\n dateAdapter: dateAdapter ?? defaultDateAdapter(locale),\r\n remoteApi,\r\n messages,\r\n onToast,\r\n theme,\r\n themeToggle,\r\n themeLocked,\r\n onToggleTheme,\r\n components,\r\n filterComponents,\r\n columnMenuItems,\r\n onColumnMenuAction,\r\n useDependOn,\r\n }),\r\n [\r\n locale,\r\n direction,\r\n numberingSystem,\r\n dateAdapter,\r\n remoteApi,\r\n messages,\r\n onToast,\r\n theme,\r\n themeToggle,\r\n themeLocked,\r\n onToggleTheme,\r\n components,\r\n filterComponents,\r\n columnMenuItems,\r\n onColumnMenuAction,\r\n useDependOn,\r\n ],\r\n );\r\n\r\n useEffect(() => {\r\n rememberThemeVars(theme.toCssVars());\r\n }, [theme]);\r\n\r\n return (\r\n <ERPTableHostContext.Provider value={value}>\r\n {children}\r\n </ERPTableHostContext.Provider>\r\n );\r\n}\r\n\r\nexport function useERPTableHost(): ERPTableHostValue {\r\n return useContext(ERPTableHostContext);\r\n}\r\n\r\nexport function useERPTableTheme(): GridTheme {\r\n return useERPTableHost().theme ?? themeErp;\r\n}\r\n\r\n/** Merge theme CSS vars into a portal node that mounts on `document.body`. */\r\nexport function useThemePortalStyle(extra?: CSSProperties): CSSProperties {\r\n const theme = useERPTableTheme();\r\n return themeToStyle(theme, extra);\r\n}\r\n\r\n/** Stable per locale / messages — safe as an effect dependency. */\r\nexport function useTranslations() {\r\n const { locale, messages } = useERPTableHost();\r\n return useCallback(\r\n (key: string, vars?: Record<string, string | number>) => {\r\n const raw = translate(key, locale, messages);\r\n return vars ? formatMessage(raw, vars) : raw;\r\n },\r\n [locale, messages],\r\n );\r\n}\r\n\r\nexport function useLocale(): ERPTableLocale {\r\n return useERPTableHost().locale;\r\n}\r\n\r\nexport function useNumberingSystem(): NumberingSystem | undefined {\r\n return useERPTableHost().numberingSystem;\r\n}\r\n\r\nexport function useDateAdapter(): DateAdapter {\r\n return useERPTableHost().dateAdapter ?? jalaliAdapter;\r\n}\r\n\r\nexport function useDirection(): 'rtl' | 'ltr' {\r\n return useERPTableHost().direction;\r\n}\r\n","\"use client\";\r\n\r\nimport { useERPTableHost } from './ERPTableHost';\r\n\r\n/** One dependency: a named sibling field and (optionally) its current value. */\r\nexport type DependOnItem =\r\n | string\r\n | { fieldName: string; value?: unknown };\r\nexport type DependOn = DependOnItem | DependOnItem[];\r\n\r\nexport type DependValueResolver = (item: DependOnItem) => unknown;\r\n\r\nexport type UseDependOnOptions = {\r\n /**\r\n * Ask the host to resolve dependency values (e.g. from the form that owns\r\n * the grid). When false/omitted, the `value` carried by each item is used.\r\n */\r\n enabled?: boolean;\r\n /** Send `value.value` when a resolved value is an option-like object. */\r\n unwrapObjectValue?: boolean;\r\n};\r\n\r\nexport type UseDependOnResult = {\r\n /** `{ [fieldName]: value }` to merge into a remote request body. */\r\n dependencyBody: Record<string, unknown>;\r\n /** Every dependency has a value (true when there is no dependOn). */\r\n isReady: boolean;\r\n /** Stable string that changes when the dependencies change. */\r\n dependencyKey: string;\r\n};\r\n\r\n/**\r\n * Host-injectable dependency resolver. The arianERP host implements this on\r\n * top of Redux page data; the default implementation reads the static values\r\n * carried by the `dependOn` items.\r\n */\r\nexport type UseDependOnHook = (\r\n dependOn?: DependOn | null,\r\n options?: UseDependOnOptions,\r\n) => UseDependOnResult;\r\n\r\nconst toList = (dependOn?: DependOn | null): DependOnItem[] =>\r\n !dependOn ? [] : Array.isArray(dependOn) ? dependOn : [dependOn];\r\n\r\nexport const getDependFieldName = (item: DependOnItem): string =>\r\n typeof item === 'string' ? item : item.fieldName;\r\n\r\n/** The value carried by the item itself; a bare field name carries none. */\r\nexport const getStaticDependValue: DependValueResolver = (item) =>\r\n typeof item === 'object' ? item.value : undefined;\r\n\r\n/** True when every dependency resolves to a non-null value (or there are none). */\r\nexport const hasDependValue = (\r\n dependOn?: DependOn | null,\r\n resolve: DependValueResolver = getStaticDependValue,\r\n): boolean => toList(dependOn).every((item) => resolve(item) != null);\r\n\r\n/** Builds the `{ [fieldName]: value }` part of a request body. */\r\nexport const buildDependencyBody = (\r\n dependOn?: DependOn | null,\r\n resolve: DependValueResolver = getStaticDependValue,\r\n): Record<string, unknown> =>\r\n Object.fromEntries(\r\n toList(dependOn).map((item) => [getDependFieldName(item), resolve(item)]),\r\n );\r\n\r\n/** Default `UseDependOnHook`: static values carried by the items. */\r\nexport const useStaticDependOn: UseDependOnHook = (dependOn, options) => {\r\n const unwrap = (value: unknown) =>\r\n options?.unwrapObjectValue &&\r\n value !== null &&\r\n typeof value === 'object' &&\r\n !Array.isArray(value) &&\r\n 'value' in value\r\n ? (value as { value: unknown }).value\r\n : value;\r\n const resolve: DependValueResolver = (item) => unwrap(getStaticDependValue(item));\r\n return {\r\n isReady: hasDependValue(dependOn, resolve),\r\n dependencyBody: buildDependencyBody(dependOn, resolve),\r\n dependencyKey: JSON.stringify(dependOn ?? null),\r\n };\r\n};\r\n\r\n/** Resolve dependency values through the host hook, falling back to static. */\r\nexport const useHostDependOn: UseDependOnHook = (dependOn, options) => {\r\n const host = useERPTableHost();\r\n const hook = host.useDependOn ?? useStaticDependOn;\r\n return hook(dependOn, options);\r\n};\r\n","import type { EventStore } from '../../application/ports/EventStore';\r\nimport {\r\n subscribeCatalogHostEvents,\r\n type CatalogHostEventHandlers,\r\n type CellFocusedEvent,\r\n type SelectionChangedEvent,\r\n} from '../../application/events/hostGridEvents';\r\nimport type { GridApi } from '../../infrastructure/ui/createGridApi';\r\nimport type { UITableController } from '../../infrastructure/ui/UITableController';\r\n\r\nexport type GridReadyEvent<TRow = unknown> = {\r\n api: GridApi<TRow>;\r\n};\r\n\r\nexport type GridHostEventHandlers<TRow = unknown> = CatalogHostEventHandlers<TRow> & {\r\n onSelectionChanged?: (event: SelectionChangedEvent<TRow>) => void;\r\n onCellFocused?: (event: CellFocusedEvent) => void;\r\n onGridReady?: (event: GridReadyEvent<TRow>) => void;\r\n};\r\n\r\nfunction selectedKeysEqual(\r\n a: Record<number, boolean> | null | undefined,\r\n b: Record<number, boolean> | null | undefined,\r\n): boolean {\r\n const left = Object.keys(a ?? {});\r\n const right = Object.keys(b ?? {});\r\n if (left.length !== right.length) return false;\r\n return left.every((key) => {\r\n const id = Number(key);\r\n return Boolean(a?.[id]) === Boolean(b?.[id]);\r\n });\r\n}\r\n\r\nfunction activeCellEqual(\r\n a: { rowId?: number; columnId?: string } | null | undefined,\r\n b: { rowId?: number; columnId?: string } | null | undefined,\r\n): boolean {\r\n return a?.rowId === b?.rowId && a?.columnId === b?.columnId;\r\n}\r\n\r\nfunction selectedRowIds(\r\n selected: Record<number, boolean> | null | undefined,\r\n): number[] {\r\n return Object.keys(selected ?? {})\r\n .map(Number)\r\n .filter((id) => Number.isFinite(id) && Boolean(selected?.[id]));\r\n}\r\n\r\n/**\r\n * Subscribe to EVENT_CATALOG (`EventStore`) plus the existing view store\r\n * (selection / focus). One unsubscribe. Not a second event bus.\r\n */\r\nexport function bindGridHostEvents<TRow = unknown>(\r\n input: {\r\n eventStore: EventStore;\r\n controller: UITableController;\r\n tableKey: string;\r\n handlers: GridHostEventHandlers<TRow>;\r\n },\r\n): () => void {\r\n const { eventStore, controller, tableKey, handlers } = input;\r\n\r\n const unsubCatalog = subscribeCatalogHostEvents(\r\n eventStore,\r\n {\r\n tableId: tableKey,\r\n getRowData: (rowId) =>\r\n controller.getAllRows()?.find((row) => row.id.value === rowId)?.data as\r\n | TRow\r\n | undefined,\r\n getAllRowData: () =>\r\n (controller.getAllRows() ?? [])\r\n .map((row) => row.data)\r\n .filter((data): data is TRow => data !== undefined),\r\n },\r\n handlers,\r\n );\r\n\r\n const unsubSelection = controller.subscribeSelected(\r\n () => controller.getSelectedRows(),\r\n (selected) => {\r\n const ids = selectedRowIds(selected);\r\n const rows = controller.getAllRows() ?? [];\r\n const selectedRows = ids\r\n .map((id) => rows.find((row) => row.id.value === id)?.data)\r\n .filter((data): data is TRow => data !== undefined);\r\n handlers.onSelectionChanged?.({\r\n selectedRowIds: ids,\r\n selectedRows,\r\n });\r\n },\r\n selectedKeysEqual,\r\n );\r\n\r\n const unsubFocus = controller.subscribeSelected(\r\n () => controller.getActiveCell(),\r\n (cell) => {\r\n handlers.onCellFocused?.({\r\n rowId: cell?.rowId ?? null,\r\n colId: cell?.columnId ?? null,\r\n });\r\n },\r\n activeCellEqual,\r\n );\r\n\r\n return () => {\r\n unsubCatalog();\r\n unsubSelection();\r\n unsubFocus();\r\n };\r\n}\r\n","\"use client\";\r\n\r\nimport { useEffect, useState } from 'react';\r\n\r\nconst QUERIES: Record<string, string> = {\r\n XLUP: '(min-width: 1024px)',\r\n XXLUP: '(min-width: 1366px)',\r\n};\r\n\r\nexport function useMediaQuery(query: string): { match: boolean | null } {\r\n const media = QUERIES[query] ?? query;\r\n const [match, setMatch] = useState<boolean | null>(() => {\r\n if (typeof window === 'undefined') return null;\r\n return window.matchMedia(media).matches;\r\n });\r\n\r\n useEffect(() => {\r\n const mql = window.matchMedia(media);\r\n const onChange = () => setMatch(mql.matches);\r\n onChange();\r\n mql.addEventListener('change', onChange);\r\n return () => mql.removeEventListener('change', onChange);\r\n }, [media]);\r\n\r\n return { match };\r\n}\r\n","\"use client\";\r\n\r\nimport { useCallback, useEffect, useRef, useState } from 'react';\r\n\r\nimport { useERPTableHost } from './ERPTableHost';\r\n\r\n/** Latest `onToast` without making callers' callbacks/effects depend on its identity. */\r\nfunction useLatest<T>(value: T) {\r\n const ref = useRef(value);\r\n ref.current = value;\r\n return ref;\r\n}\r\n\r\nfunction errorMessage(error: unknown): string {\r\n return error instanceof Error ? error.message : 'Remote request failed';\r\n}\r\n\r\ntype UseRemoteQueryArgs = {\r\n url?: string;\r\n body?: Record<string, unknown>;\r\n skip?: boolean;\r\n noCache?: boolean;\r\n};\r\n\r\nexport function useRemoteQuery<T = unknown>(args: UseRemoteQueryArgs) {\r\n const { remoteApi, onToast } = useERPTableHost();\r\n const toastRef = useLatest(onToast);\r\n const [data, setData] = useState<{ Data?: T; TotalCount?: number; ReturnCount?: number; Result?: string } | null>(null);\r\n const [isFetching, setIsFetching] = useState(false);\r\n const [error, setError] = useState<unknown>(null);\r\n\r\n const refetch = useCallback(async () => {\r\n if (!args.url || args.skip || !remoteApi) {\r\n setData(null);\r\n return;\r\n }\r\n setIsFetching(true);\r\n setError(null);\r\n try {\r\n const response = await remoteApi.request<{\r\n Data?: T;\r\n TotalCount?: number;\r\n ReturnCount?: number;\r\n Result?: string;\r\n }>({\r\n endpoint: args.url,\r\n params: args.body,\r\n method: 'POST',\r\n });\r\n setData(response ?? null);\r\n } catch (e) {\r\n // Never let a backend failure escape from an effect as an unhandled rejection.\r\n setData(null);\r\n setError(e);\r\n toastRef.current?.('error', errorMessage(e), e);\r\n } finally {\r\n setIsFetching(false);\r\n }\r\n }, [args.url, args.skip, args.noCache, JSON.stringify(args.body ?? {}), remoteApi]);\r\n\r\n useEffect(() => {\r\n void refetch();\r\n }, [refetch]);\r\n\r\n return { data, isFetching, error, refetch };\r\n}\r\n\r\n/**\r\n * Imperative counterpart of {@link useRemoteQuery} (RTK `useGet…Mutation`\r\n * style): nothing is fetched until `trigger` is called, and body/url changes\r\n * never refetch on their own.\r\n */\r\nexport function useLazyRemote<T = unknown>() {\r\n const { remoteApi, onToast } = useERPTableHost();\r\n const toastRef = useLatest(onToast);\r\n const [data, setData] = useState<{ Data?: T; TotalCount?: number; ReturnCount?: number; Result?: string } | null>(null);\r\n const [isFetching, setIsFetching] = useState(false);\r\n const [error, setError] = useState<unknown>(null);\r\n\r\n const trigger = useCallback(\r\n async (args: { url?: string; body?: Record<string, unknown> }) => {\r\n if (!args.url || !remoteApi) {\r\n setData(null);\r\n return;\r\n }\r\n setIsFetching(true);\r\n setError(null);\r\n try {\r\n const response = await remoteApi.request<{\r\n Data?: T;\r\n TotalCount?: number;\r\n ReturnCount?: number;\r\n Result?: string;\r\n }>({ endpoint: args.url, params: args.body, method: 'POST' });\r\n setData(response ?? null);\r\n } catch (e) {\r\n // Resolves (never rejects): failures surface via `error` and `onToast`.\r\n setData(null);\r\n setError(e);\r\n toastRef.current?.('error', errorMessage(e), e);\r\n } finally {\r\n setIsFetching(false);\r\n }\r\n },\r\n [remoteApi],\r\n );\r\n\r\n return [trigger, { data, isFetching, error }] as const;\r\n}\r\n","import { assignThemeVars } from '../theme';\r\nimport { useERPTableHost } from './ERPTableHost';\r\n\r\nexport function showSuccessToast(message?: unknown, _detail?: unknown): void {\r\n const text = String(message ?? '');\r\n emitToast('success', text);\r\n}\r\n\r\nexport function showErrorToast(message?: unknown, _detail?: unknown): void {\r\n const text = String(message ?? '');\r\n emitToast('error', text);\r\n}\r\n\r\nfunction emitToast(kind: 'success' | 'error', message: string): void {\r\n if (typeof document === 'undefined') return;\r\n const existing = document.querySelector('.erp-table-toast');\r\n existing?.remove();\r\n const el = document.createElement('div');\r\n el.className = `erp-table-toast is-${kind}`;\r\n el.textContent = message;\r\n assignThemeVars(el);\r\n document.body.appendChild(el);\r\n window.setTimeout(() => el.remove(), 2800);\r\n}\r\n\r\n/** Host can wrap this if it wants toasts routed through its own UI. */\r\nexport function useHostToast() {\r\n const host = useERPTableHost();\r\n return {\r\n success: (message: string, detail?: unknown) => {\r\n if (host.onToast) host.onToast('success', message, detail);\r\n else showSuccessToast(message, detail);\r\n },\r\n error: (message: string, detail?: unknown) => {\r\n if (host.onToast) host.onToast('error', message, detail);\r\n else showErrorToast(message, detail);\r\n },\r\n };\r\n}\r\n","import { useEffect, useRef } from 'react';\r\n\r\nimport type { EventStore } from '../../application/ports/EventStore';\r\nimport type { UITableController } from '../../infrastructure/ui/UITableController';\r\nimport {\r\n bindGridHostEvents,\r\n type GridHostEventHandlers,\r\n} from './bindGridHostEvents';\r\n\r\nexport type UseGridHostEventsInput<TRow = unknown> = GridHostEventHandlers<TRow> & {\r\n ready: boolean;\r\n controller: UITableController | null;\r\n eventStore: EventStore | null;\r\n tableKey: string;\r\n};\r\n\r\n/**\r\n * ERPTable wiring for PR-85. Handlers are read from a ref so EventStore\r\n * subscribeAll is not torn down when the host passes inline lambdas.\r\n */\r\nexport function useGridHostEvents<TRow = unknown>(\r\n input: UseGridHostEventsInput<TRow>,\r\n): void {\r\n const handlersRef = useRef<GridHostEventHandlers<TRow>>(input);\r\n handlersRef.current = input;\r\n\r\n useEffect(() => {\r\n if (!input.ready || !input.controller || !input.eventStore) return;\r\n return bindGridHostEvents<TRow>({\r\n eventStore: input.eventStore,\r\n controller: input.controller,\r\n tableKey: input.tableKey,\r\n handlers: {\r\n onCellValueChanged: (event) =>\r\n handlersRef.current.onCellValueChanged?.(event),\r\n onRowValueChanged: (event) =>\r\n handlersRef.current.onRowValueChanged?.(event),\r\n onRowDataUpdated: (event) =>\r\n handlersRef.current.onRowDataUpdated?.(event),\r\n onSelectionChanged: (event) =>\r\n handlersRef.current.onSelectionChanged?.(event),\r\n onCellFocused: (event) => handlersRef.current.onCellFocused?.(event),\r\n },\r\n });\r\n }, [input.ready, input.controller, input.eventStore, input.tableKey]);\r\n}\r\n"]}
|
|
@@ -44,6 +44,7 @@ var GridSyncService = class {
|
|
|
44
44
|
this.conflictListeners = /* @__PURE__ */ new Set();
|
|
45
45
|
/** Remote events waiting on manual resolution (by conflict id). */
|
|
46
46
|
this.deferredRemote = /* @__PURE__ */ new Map();
|
|
47
|
+
this.disposed = false;
|
|
47
48
|
this.policy = options.policy ?? "lastWriteWins";
|
|
48
49
|
this.cursor = options.initialCursor ?? 0;
|
|
49
50
|
}
|
|
@@ -57,16 +58,29 @@ var GridSyncService = class {
|
|
|
57
58
|
return this.openConflicts;
|
|
58
59
|
}
|
|
59
60
|
subscribeConflicts(listener) {
|
|
61
|
+
if (this.disposed) return () => void 0;
|
|
60
62
|
this.conflictListeners.add(listener);
|
|
61
63
|
listener(this.openConflicts);
|
|
62
64
|
return () => this.conflictListeners.delete(listener);
|
|
63
65
|
}
|
|
66
|
+
/** Drop listeners and deferred conflicts; later sync() calls are no-ops. */
|
|
67
|
+
dispose() {
|
|
68
|
+
this.disposed = true;
|
|
69
|
+
this.conflictListeners.clear();
|
|
70
|
+
this.deferredRemote.clear();
|
|
71
|
+
this.openConflicts = [];
|
|
72
|
+
}
|
|
73
|
+
emptyResult() {
|
|
74
|
+
return { pushed: 0, pulled: 0, applied: 0, conflicts: [] };
|
|
75
|
+
}
|
|
64
76
|
async sync() {
|
|
77
|
+
if (this.disposed) return this.emptyResult();
|
|
65
78
|
const pending = this.options.offlineStatus.getPendingChanges();
|
|
66
79
|
const pushable = pending.map((p) => p.event).filter(
|
|
67
80
|
(e) => Boolean(e) && e.tableId === this.options.tableId
|
|
68
81
|
);
|
|
69
82
|
const { acceptedIds } = await this.options.transport.push(pushable);
|
|
83
|
+
if (this.disposed) return this.emptyResult();
|
|
70
84
|
if (acceptedIds.length > 0) {
|
|
71
85
|
this.options.offlineStatus.markSynced([...acceptedIds]);
|
|
72
86
|
}
|
|
@@ -86,10 +100,12 @@ var GridSyncService = class {
|
|
|
86
100
|
localByCell.set(cellKeyId(key.rowId, key.columnId), event);
|
|
87
101
|
}
|
|
88
102
|
const pulled = await this.options.transport.pull(this.cursor);
|
|
103
|
+
if (this.disposed) return this.emptyResult();
|
|
89
104
|
this.cursor = pulled.cursor;
|
|
90
105
|
let applied = 0;
|
|
91
106
|
const conflicts = [];
|
|
92
107
|
for (const remote of pulled.events) {
|
|
108
|
+
if (this.disposed) return this.emptyResult();
|
|
93
109
|
if (remote.tableId !== this.options.tableId) continue;
|
|
94
110
|
if (!isCellChanged(remote)) {
|
|
95
111
|
await this.ingestRemote(remote);
|
|
@@ -138,6 +154,7 @@ var GridSyncService = class {
|
|
|
138
154
|
};
|
|
139
155
|
}
|
|
140
156
|
async resolveConflict(conflictId, choice) {
|
|
157
|
+
if (this.disposed) return;
|
|
141
158
|
const conflict = this.openConflicts.find((c) => c.id === conflictId);
|
|
142
159
|
const remote = this.deferredRemote.get(conflictId);
|
|
143
160
|
if (!conflict || !remote) return;
|
|
@@ -185,5 +202,5 @@ var GridSyncService = class {
|
|
|
185
202
|
};
|
|
186
203
|
|
|
187
204
|
export { GridSyncService };
|
|
188
|
-
//# sourceMappingURL=chunk-
|
|
189
|
-
//# sourceMappingURL=chunk-
|
|
205
|
+
//# sourceMappingURL=chunk-KCNTKYUY.js.map
|
|
206
|
+
//# sourceMappingURL=chunk-KCNTKYUY.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../application/sync/resolveCellConflicts.ts","../application/sync/GridSyncService.ts"],"names":[],"mappings":"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","file":"chunk-KCNTKYUY.js","sourcesContent":["import type {\r\n SyncConflict,\r\n SyncConflictPolicy,\r\n ManualResolution,\r\n} from '../ports/SyncPort';\r\n\r\n/**\r\n * Pure conflict resolution (PR-138).\r\n * `manual` always returns unresolved so the UI can choose.\r\n */\r\nexport function resolveConflictChoice(\r\n conflict: SyncConflict,\r\n policy: SyncConflictPolicy,\r\n): ManualResolution | 'unresolved' {\r\n if (policy === 'manual') return 'unresolved';\r\n if (policy === 'serverWins') return 'remote';\r\n // lastWriteWins — tie-break on version then occurredAt\r\n if (conflict.remote.version !== conflict.local.version) {\r\n return conflict.remote.version > conflict.local.version\r\n ? 'remote'\r\n : 'local';\r\n }\r\n if (conflict.remote.occurredAt !== conflict.local.occurredAt) {\r\n return conflict.remote.occurredAt > conflict.local.occurredAt\r\n ? 'remote'\r\n : 'local';\r\n }\r\n return 'remote';\r\n}\r\n\r\nexport function cellKeyFromPayload(\r\n payload: unknown,\r\n): { rowId: number; columnId: string } | null {\r\n if (!payload || typeof payload !== 'object') return null;\r\n const p = payload as Record<string, unknown>;\r\n const columnId = p.columnId;\r\n if (typeof columnId !== 'string' || !columnId) return null;\r\n const rowRaw = p.rowId;\r\n const rowId =\r\n typeof rowRaw === 'number'\r\n ? rowRaw\r\n : typeof rowRaw === 'string'\r\n ? Number(rowRaw)\r\n : NaN;\r\n if (!Number.isFinite(rowId)) return null;\r\n return { rowId, columnId };\r\n}\r\n\r\nexport function cellKeyId(rowId: number, columnId: string): string {\r\n return `${rowId}:${columnId}`;\r\n}\r\n","import type { EventStore } from '../ports/EventStore';\r\nimport type { GridEvent } from '../../domain/types/GridEvent';\r\nimport type { OfflineStatus } from '../offline/OfflineStatus';\r\nimport type {\r\n ManualResolution,\r\n SyncConflict,\r\n SyncConflictPolicy,\r\n SyncPort,\r\n SyncResult,\r\n SyncTransport,\r\n} from '../ports/SyncPort';\r\nimport {\r\n cellKeyFromPayload,\r\n cellKeyId,\r\n resolveConflictChoice,\r\n} from './resolveCellConflicts';\r\n\r\nexport type GridSyncServiceOptions = {\r\n readonly tableId: string;\r\n readonly eventStore: EventStore;\r\n readonly offlineStatus: OfflineStatus;\r\n readonly transport: SyncTransport;\r\n /** Apply a winning remote CELL_CHANGED into the local domain. */\r\n readonly applyCellValue: (\r\n rowId: number,\r\n columnId: string,\r\n value: unknown,\r\n ) => Promise<void>;\r\n /** Initial pull cursor (default 0). */\r\n readonly initialCursor?: number;\r\n readonly policy?: SyncConflictPolicy;\r\n};\r\n\r\nfunction isCellChanged(event: GridEvent): boolean {\r\n return event.type === 'CELL_CHANGED';\r\n}\r\n\r\nfunction toSide(event: GridEvent): SyncConflict['local'] {\r\n const payload = event.payload as { newValue?: unknown };\r\n return {\r\n eventId: event.eventId,\r\n value: payload?.newValue,\r\n occurredAt: event.occurredAt,\r\n version: event.version,\r\n };\r\n}\r\n\r\n/**\r\n * SyncPort implementation over EventStore + OfflineStatus + SyncTransport (PR-138).\r\n */\r\nexport class GridSyncService implements SyncPort {\r\n private policy: SyncConflictPolicy;\r\n private cursor: number;\r\n private openConflicts: SyncConflict[] = [];\r\n private readonly conflictListeners = new Set<\r\n (conflicts: readonly SyncConflict[]) => void\r\n >();\r\n /** Remote events waiting on manual resolution (by conflict id). */\r\n private readonly deferredRemote = new Map<string, GridEvent>();\r\n private disposed = false;\r\n\r\n constructor(private readonly options: GridSyncServiceOptions) {\r\n this.policy = options.policy ?? 'lastWriteWins';\r\n this.cursor = options.initialCursor ?? 0;\r\n }\r\n\r\n getPolicy(): SyncConflictPolicy {\r\n return this.policy;\r\n }\r\n\r\n setPolicy(policy: SyncConflictPolicy): void {\r\n this.policy = policy;\r\n }\r\n\r\n getOpenConflicts(): readonly SyncConflict[] {\r\n return this.openConflicts;\r\n }\r\n\r\n subscribeConflicts(\r\n listener: (conflicts: readonly SyncConflict[]) => void,\r\n ): () => void {\r\n if (this.disposed) return () => undefined;\r\n this.conflictListeners.add(listener);\r\n listener(this.openConflicts);\r\n return () => this.conflictListeners.delete(listener);\r\n }\r\n\r\n /** Drop listeners and deferred conflicts; later sync() calls are no-ops. */\r\n dispose(): void {\r\n this.disposed = true;\r\n this.conflictListeners.clear();\r\n this.deferredRemote.clear();\r\n this.openConflicts = [];\r\n }\r\n\r\n private emptyResult(): SyncResult {\r\n return { pushed: 0, pulled: 0, applied: 0, conflicts: [] };\r\n }\r\n\r\n async sync(): Promise<SyncResult> {\r\n if (this.disposed) return this.emptyResult();\r\n const pending = this.options.offlineStatus.getPendingChanges();\r\n const pushable = pending\r\n .map((p) => p.event)\r\n .filter(\r\n (e): e is GridEvent =>\r\n Boolean(e) && e.tableId === this.options.tableId,\r\n );\r\n\r\n const { acceptedIds } = await this.options.transport.push(pushable);\r\n if (this.disposed) return this.emptyResult();\r\n if (acceptedIds.length > 0) {\r\n this.options.offlineStatus.markSynced([...acceptedIds]);\r\n }\r\n\r\n // Locals just pushed (or still pending) — used to detect cell conflicts on pull.\r\n const localByCell = new Map<string, GridEvent>();\r\n for (const event of pushable) {\r\n if (!isCellChanged(event)) continue;\r\n const key = cellKeyFromPayload(event.payload);\r\n if (!key) continue;\r\n localByCell.set(cellKeyId(key.rowId, key.columnId), event);\r\n }\r\n for (const event of this.options.offlineStatus\r\n .getPendingChanges()\r\n .map((p) => p.event)\r\n .filter((e): e is GridEvent => Boolean(e))) {\r\n if (!isCellChanged(event) || event.tableId !== this.options.tableId) {\r\n continue;\r\n }\r\n const key = cellKeyFromPayload(event.payload);\r\n if (!key) continue;\r\n localByCell.set(cellKeyId(key.rowId, key.columnId), event);\r\n }\r\n\r\n const pulled = await this.options.transport.pull(this.cursor);\r\n if (this.disposed) return this.emptyResult();\r\n this.cursor = pulled.cursor;\r\n\r\n let applied = 0;\r\n const conflicts: SyncConflict[] = [];\r\n\r\n for (const remote of pulled.events) {\r\n // Torn down mid-apply: stop writing into a released event store.\r\n if (this.disposed) return this.emptyResult();\r\n if (remote.tableId !== this.options.tableId) continue;\r\n if (!isCellChanged(remote)) {\r\n await this.ingestRemote(remote);\r\n applied += 1;\r\n continue;\r\n }\r\n const key = cellKeyFromPayload(remote.payload);\r\n if (!key) continue;\r\n const id = cellKeyId(key.rowId, key.columnId);\r\n const local = localByCell.get(id);\r\n if (local && toSide(local).value !== toSide(remote).value) {\r\n const conflict: SyncConflict = {\r\n id: `conflict:${id}:${remote.eventId}`,\r\n key,\r\n local: toSide(local),\r\n remote: toSide(remote),\r\n };\r\n const choice = resolveConflictChoice(conflict, this.policy);\r\n if (choice === 'unresolved') {\r\n conflicts.push(conflict);\r\n this.deferredRemote.set(conflict.id, remote);\r\n continue;\r\n }\r\n if (choice === 'remote') {\r\n await this.applyRemoteCell(remote, key.rowId, key.columnId);\r\n this.options.offlineStatus.markSynced([local.eventId]);\r\n applied += 1;\r\n } else {\r\n // Keep local — acknowledge remote without applying its value\r\n await this.ingestRemote(remote);\r\n }\r\n continue;\r\n }\r\n await this.applyRemoteCell(remote, key.rowId, key.columnId);\r\n applied += 1;\r\n }\r\n\r\n this.openConflicts = [\r\n ...this.openConflicts.filter((c) => this.deferredRemote.has(c.id)),\r\n ...conflicts,\r\n ];\r\n this.emitConflicts();\r\n\r\n return {\r\n pushed: acceptedIds.length,\r\n pulled: pulled.events.length,\r\n applied,\r\n conflicts: this.openConflicts,\r\n };\r\n }\r\n\r\n async resolveConflict(\r\n conflictId: string,\r\n choice: ManualResolution,\r\n ): Promise<void> {\r\n if (this.disposed) return;\r\n const conflict = this.openConflicts.find((c) => c.id === conflictId);\r\n const remote = this.deferredRemote.get(conflictId);\r\n if (!conflict || !remote) return;\r\n\r\n if (choice === 'remote') {\r\n await this.applyRemoteCell(\r\n remote,\r\n conflict.key.rowId,\r\n conflict.key.columnId,\r\n );\r\n this.options.offlineStatus.markSynced([conflict.local.eventId]);\r\n } else {\r\n await this.ingestRemote(remote);\r\n }\r\n\r\n this.deferredRemote.delete(conflictId);\r\n this.openConflicts = this.openConflicts.filter((c) => c.id !== conflictId);\r\n this.emitConflicts();\r\n }\r\n\r\n private async applyRemoteCell(\r\n remote: GridEvent,\r\n rowId: number,\r\n columnId: string,\r\n ): Promise<void> {\r\n await this.ingestRemote(remote);\r\n const before = new Set(\r\n this.options.offlineStatus.getPendingChanges().map((p) => p.eventId),\r\n );\r\n const value = (remote.payload as { newValue?: unknown })?.newValue;\r\n await this.options.applyCellValue(rowId, columnId, value);\r\n // CHANGE_CELL_VALUE may dual-write a new local event — treat as synced.\r\n const created = this.options.offlineStatus\r\n .getPendingChanges()\r\n .filter((p) => !before.has(p.eventId))\r\n .map((p) => p.eventId);\r\n if (created.length > 0) {\r\n this.options.offlineStatus.markSynced(created);\r\n }\r\n }\r\n\r\n private async ingestRemote(remote: GridEvent): Promise<void> {\r\n const streamId = remote.streamId || `table:${remote.tableId}`;\r\n const existing = await this.options.eventStore.read(streamId);\r\n if (existing.some((e) => e.eventId === remote.eventId)) {\r\n this.options.offlineStatus.markSynced([remote.eventId]);\r\n return;\r\n }\r\n await this.options.eventStore.append(streamId, [remote], -1);\r\n // Remote ingest must not look like a local pending mutation.\r\n this.options.offlineStatus.markSynced([remote.eventId]);\r\n }\r\n\r\n private emitConflicts(): void {\r\n for (const listener of this.conflictListeners) {\r\n listener(this.openConflicts);\r\n }\r\n }\r\n}\r\n"]}
|
|
@@ -46,6 +46,7 @@ var GridSyncService = class {
|
|
|
46
46
|
this.conflictListeners = /* @__PURE__ */ new Set();
|
|
47
47
|
/** Remote events waiting on manual resolution (by conflict id). */
|
|
48
48
|
this.deferredRemote = /* @__PURE__ */ new Map();
|
|
49
|
+
this.disposed = false;
|
|
49
50
|
this.policy = options.policy ?? "lastWriteWins";
|
|
50
51
|
this.cursor = options.initialCursor ?? 0;
|
|
51
52
|
}
|
|
@@ -59,16 +60,29 @@ var GridSyncService = class {
|
|
|
59
60
|
return this.openConflicts;
|
|
60
61
|
}
|
|
61
62
|
subscribeConflicts(listener) {
|
|
63
|
+
if (this.disposed) return () => void 0;
|
|
62
64
|
this.conflictListeners.add(listener);
|
|
63
65
|
listener(this.openConflicts);
|
|
64
66
|
return () => this.conflictListeners.delete(listener);
|
|
65
67
|
}
|
|
68
|
+
/** Drop listeners and deferred conflicts; later sync() calls are no-ops. */
|
|
69
|
+
dispose() {
|
|
70
|
+
this.disposed = true;
|
|
71
|
+
this.conflictListeners.clear();
|
|
72
|
+
this.deferredRemote.clear();
|
|
73
|
+
this.openConflicts = [];
|
|
74
|
+
}
|
|
75
|
+
emptyResult() {
|
|
76
|
+
return { pushed: 0, pulled: 0, applied: 0, conflicts: [] };
|
|
77
|
+
}
|
|
66
78
|
async sync() {
|
|
79
|
+
if (this.disposed) return this.emptyResult();
|
|
67
80
|
const pending = this.options.offlineStatus.getPendingChanges();
|
|
68
81
|
const pushable = pending.map((p) => p.event).filter(
|
|
69
82
|
(e) => Boolean(e) && e.tableId === this.options.tableId
|
|
70
83
|
);
|
|
71
84
|
const { acceptedIds } = await this.options.transport.push(pushable);
|
|
85
|
+
if (this.disposed) return this.emptyResult();
|
|
72
86
|
if (acceptedIds.length > 0) {
|
|
73
87
|
this.options.offlineStatus.markSynced([...acceptedIds]);
|
|
74
88
|
}
|
|
@@ -88,10 +102,12 @@ var GridSyncService = class {
|
|
|
88
102
|
localByCell.set(cellKeyId(key.rowId, key.columnId), event);
|
|
89
103
|
}
|
|
90
104
|
const pulled = await this.options.transport.pull(this.cursor);
|
|
105
|
+
if (this.disposed) return this.emptyResult();
|
|
91
106
|
this.cursor = pulled.cursor;
|
|
92
107
|
let applied = 0;
|
|
93
108
|
const conflicts = [];
|
|
94
109
|
for (const remote of pulled.events) {
|
|
110
|
+
if (this.disposed) return this.emptyResult();
|
|
95
111
|
if (remote.tableId !== this.options.tableId) continue;
|
|
96
112
|
if (!isCellChanged(remote)) {
|
|
97
113
|
await this.ingestRemote(remote);
|
|
@@ -140,6 +156,7 @@ var GridSyncService = class {
|
|
|
140
156
|
};
|
|
141
157
|
}
|
|
142
158
|
async resolveConflict(conflictId, choice) {
|
|
159
|
+
if (this.disposed) return;
|
|
143
160
|
const conflict = this.openConflicts.find((c) => c.id === conflictId);
|
|
144
161
|
const remote = this.deferredRemote.get(conflictId);
|
|
145
162
|
if (!conflict || !remote) return;
|
|
@@ -187,5 +204,5 @@ var GridSyncService = class {
|
|
|
187
204
|
};
|
|
188
205
|
|
|
189
206
|
exports.GridSyncService = GridSyncService;
|
|
190
|
-
//# sourceMappingURL=chunk-
|
|
191
|
-
//# sourceMappingURL=chunk-
|
|
207
|
+
//# sourceMappingURL=chunk-LY27YAXE.cjs.map
|
|
208
|
+
//# sourceMappingURL=chunk-LY27YAXE.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../application/sync/resolveCellConflicts.ts","../application/sync/GridSyncService.ts"],"names":[],"mappings":";;;AAUO,SAAS,qBAAA,CACd,UACA,MAAA,EACiC;AACjC,EAAA,IAAI,MAAA,KAAW,UAAU,OAAO,YAAA;AAChC,EAAA,IAAI,MAAA,KAAW,cAAc,OAAO,QAAA;AAEpC,EAAA,IAAI,QAAA,CAAS,MAAA,CAAO,OAAA,KAAY,QAAA,CAAS,MAAM,OAAA,EAAS;AACtD,IAAA,OAAO,SAAS,MAAA,CAAO,OAAA,GAAU,QAAA,CAAS,KAAA,CAAM,UAC5C,QAAA,GACA,OAAA;AAAA,EACN;AACA,EAAA,IAAI,QAAA,CAAS,MAAA,CAAO,UAAA,KAAe,QAAA,CAAS,MAAM,UAAA,EAAY;AAC5D,IAAA,OAAO,SAAS,MAAA,CAAO,UAAA,GAAa,QAAA,CAAS,KAAA,CAAM,aAC/C,QAAA,GACA,OAAA;AAAA,EACN;AACA,EAAA,OAAO,QAAA;AACT;AAEO,SAAS,mBACd,OAAA,EAC4C;AAC5C,EAAA,IAAI,CAAC,OAAA,IAAW,OAAO,OAAA,KAAY,UAAU,OAAO,IAAA;AACpD,EAAA,MAAM,CAAA,GAAI,OAAA;AACV,EAAA,MAAM,WAAW,CAAA,CAAE,QAAA;AACnB,EAAA,IAAI,OAAO,QAAA,KAAa,QAAA,IAAY,CAAC,UAAU,OAAO,IAAA;AACtD,EAAA,MAAM,SAAS,CAAA,CAAE,KAAA;AACjB,EAAA,MAAM,KAAA,GACJ,OAAO,MAAA,KAAW,QAAA,GACd,MAAA,GACA,OAAO,MAAA,KAAW,QAAA,GAChB,MAAA,CAAO,MAAM,CAAA,GACb,GAAA;AACR,EAAA,IAAI,CAAC,MAAA,CAAO,QAAA,CAAS,KAAK,GAAG,OAAO,IAAA;AACpC,EAAA,OAAO,EAAE,OAAO,QAAA,EAAS;AAC3B;AAEO,SAAS,SAAA,CAAU,OAAe,QAAA,EAA0B;AACjE,EAAA,OAAO,CAAA,EAAG,KAAK,CAAA,CAAA,EAAI,QAAQ,CAAA,CAAA;AAC7B;;;ACjBA,SAAS,cAAc,KAAA,EAA2B;AAChD,EAAA,OAAO,MAAM,IAAA,KAAS,cAAA;AACxB;AAEA,SAAS,OAAO,KAAA,EAAyC;AACvD,EAAA,MAAM,UAAU,KAAA,CAAM,OAAA;AACtB,EAAA,OAAO;AAAA,IACL,SAAS,KAAA,CAAM,OAAA;AAAA,IACf,OAAO,OAAA,EAAS,QAAA;AAAA,IAChB,YAAY,KAAA,CAAM,UAAA;AAAA,IAClB,SAAS,KAAA,CAAM;AAAA,GACjB;AACF;AAKO,IAAM,kBAAN,MAA0C;AAAA,EAW/C,YAA6B,OAAA,EAAiC;AAAjC,IAAA,IAAA,CAAA,OAAA,GAAA,OAAA;AAR7B,IAAA,IAAA,CAAQ,gBAAgC,EAAC;AACzC,IAAA,IAAA,CAAiB,iBAAA,uBAAwB,GAAA,EAEvC;AAEF;AAAA,IAAA,IAAA,CAAiB,cAAA,uBAAqB,GAAA,EAAuB;AAC7D,IAAA,IAAA,CAAQ,QAAA,GAAW,KAAA;AAGjB,IAAA,IAAA,CAAK,MAAA,GAAS,QAAQ,MAAA,IAAU,eAAA;AAChC,IAAA,IAAA,CAAK,MAAA,GAAS,QAAQ,aAAA,IAAiB,CAAA;AAAA,EACzC;AAAA,EAEA,SAAA,GAAgC;AAC9B,IAAA,OAAO,IAAA,CAAK,MAAA;AAAA,EACd;AAAA,EAEA,UAAU,MAAA,EAAkC;AAC1C,IAAA,IAAA,CAAK,MAAA,GAAS,MAAA;AAAA,EAChB;AAAA,EAEA,gBAAA,GAA4C;AAC1C,IAAA,OAAO,IAAA,CAAK,aAAA;AAAA,EACd;AAAA,EAEA,mBACE,QAAA,EACY;AACZ,IAAA,IAAI,IAAA,CAAK,QAAA,EAAU,OAAO,MAAM,MAAA;AAChC,IAAA,IAAA,CAAK,iBAAA,CAAkB,IAAI,QAAQ,CAAA;AACnC,IAAA,QAAA,CAAS,KAAK,aAAa,CAAA;AAC3B,IAAA,OAAO,MAAM,IAAA,CAAK,iBAAA,CAAkB,MAAA,CAAO,QAAQ,CAAA;AAAA,EACrD;AAAA;AAAA,EAGA,OAAA,GAAgB;AACd,IAAA,IAAA,CAAK,QAAA,GAAW,IAAA;AAChB,IAAA,IAAA,CAAK,kBAAkB,KAAA,EAAM;AAC7B,IAAA,IAAA,CAAK,eAAe,KAAA,EAAM;AAC1B,IAAA,IAAA,CAAK,gBAAgB,EAAC;AAAA,EACxB;AAAA,EAEQ,WAAA,GAA0B;AAChC,IAAA,OAAO,EAAE,QAAQ,CAAA,EAAG,MAAA,EAAQ,GAAG,OAAA,EAAS,CAAA,EAAG,SAAA,EAAW,EAAC,EAAE;AAAA,EAC3D;AAAA,EAEA,MAAM,IAAA,GAA4B;AAChC,IAAA,IAAI,IAAA,CAAK,QAAA,EAAU,OAAO,IAAA,CAAK,WAAA,EAAY;AAC3C,IAAA,MAAM,OAAA,GAAU,IAAA,CAAK,OAAA,CAAQ,aAAA,CAAc,iBAAA,EAAkB;AAC7D,IAAA,MAAM,WAAW,OAAA,CACd,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAE,KAAK,CAAA,CAClB,MAAA;AAAA,MACC,CAAC,MACC,OAAA,CAAQ,CAAC,KAAK,CAAA,CAAE,OAAA,KAAY,KAAK,OAAA,CAAQ;AAAA,KAC7C;AAEF,IAAA,MAAM,EAAE,aAAY,GAAI,MAAM,KAAK,OAAA,CAAQ,SAAA,CAAU,KAAK,QAAQ,CAAA;AAClE,IAAA,IAAI,IAAA,CAAK,QAAA,EAAU,OAAO,IAAA,CAAK,WAAA,EAAY;AAC3C,IAAA,IAAI,WAAA,CAAY,SAAS,CAAA,EAAG;AAC1B,MAAA,IAAA,CAAK,QAAQ,aAAA,CAAc,UAAA,CAAW,CAAC,GAAG,WAAW,CAAC,CAAA;AAAA,IACxD;AAGA,IAAA,MAAM,WAAA,uBAAkB,GAAA,EAAuB;AAC/C,IAAA,KAAA,MAAW,SAAS,QAAA,EAAU;AAC5B,MAAA,IAAI,CAAC,aAAA,CAAc,KAAK,CAAA,EAAG;AAC3B,MAAA,MAAM,GAAA,GAAM,kBAAA,CAAmB,KAAA,CAAM,OAAO,CAAA;AAC5C,MAAA,IAAI,CAAC,GAAA,EAAK;AACV,MAAA,WAAA,CAAY,IAAI,SAAA,CAAU,GAAA,CAAI,OAAO,GAAA,CAAI,QAAQ,GAAG,KAAK,CAAA;AAAA,IAC3D;AACA,IAAA,KAAA,MAAW,SAAS,IAAA,CAAK,OAAA,CAAQ,cAC9B,iBAAA,EAAkB,CAClB,IAAI,CAAC,CAAA,KAAM,CAAA,CAAE,KAAK,EAClB,MAAA,CAAO,CAAC,MAAsB,OAAA,CAAQ,CAAC,CAAC,CAAA,EAAG;AAC5C,MAAA,IAAI,CAAC,cAAc,KAAK,CAAA,IAAK,MAAM,OAAA,KAAY,IAAA,CAAK,QAAQ,OAAA,EAAS;AACnE,QAAA;AAAA,MACF;AACA,MAAA,MAAM,GAAA,GAAM,kBAAA,CAAmB,KAAA,CAAM,OAAO,CAAA;AAC5C,MAAA,IAAI,CAAC,GAAA,EAAK;AACV,MAAA,WAAA,CAAY,IAAI,SAAA,CAAU,GAAA,CAAI,OAAO,GAAA,CAAI,QAAQ,GAAG,KAAK,CAAA;AAAA,IAC3D;AAEA,IAAA,MAAM,SAAS,MAAM,IAAA,CAAK,QAAQ,SAAA,CAAU,IAAA,CAAK,KAAK,MAAM,CAAA;AAC5D,IAAA,IAAI,IAAA,CAAK,QAAA,EAAU,OAAO,IAAA,CAAK,WAAA,EAAY;AAC3C,IAAA,IAAA,CAAK,SAAS,MAAA,CAAO,MAAA;AAErB,IAAA,IAAI,OAAA,GAAU,CAAA;AACd,IAAA,MAAM,YAA4B,EAAC;AAEnC,IAAA,KAAA,MAAW,MAAA,IAAU,OAAO,MAAA,EAAQ;AAElC,MAAA,IAAI,IAAA,CAAK,QAAA,EAAU,OAAO,IAAA,CAAK,WAAA,EAAY;AAC3C,MAAA,IAAI,MAAA,CAAO,OAAA,KAAY,IAAA,CAAK,OAAA,CAAQ,OAAA,EAAS;AAC7C,MAAA,IAAI,CAAC,aAAA,CAAc,MAAM,CAAA,EAAG;AAC1B,QAAA,MAAM,IAAA,CAAK,aAAa,MAAM,CAAA;AAC9B,QAAA,OAAA,IAAW,CAAA;AACX,QAAA;AAAA,MACF;AACA,MAAA,MAAM,GAAA,GAAM,kBAAA,CAAmB,MAAA,CAAO,OAAO,CAAA;AAC7C,MAAA,IAAI,CAAC,GAAA,EAAK;AACV,MAAA,MAAM,EAAA,GAAK,SAAA,CAAU,GAAA,CAAI,KAAA,EAAO,IAAI,QAAQ,CAAA;AAC5C,MAAA,MAAM,KAAA,GAAQ,WAAA,CAAY,GAAA,CAAI,EAAE,CAAA;AAChC,MAAA,IAAI,KAAA,IAAS,OAAO,KAAK,CAAA,CAAE,UAAU,MAAA,CAAO,MAAM,EAAE,KAAA,EAAO;AACzD,QAAA,MAAM,QAAA,GAAyB;AAAA,UAC7B,EAAA,EAAI,CAAA,SAAA,EAAY,EAAE,CAAA,CAAA,EAAI,OAAO,OAAO,CAAA,CAAA;AAAA,UACpC,GAAA;AAAA,UACA,KAAA,EAAO,OAAO,KAAK,CAAA;AAAA,UACnB,MAAA,EAAQ,OAAO,MAAM;AAAA,SACvB;AACA,QAAA,MAAM,MAAA,GAAS,qBAAA,CAAsB,QAAA,EAAU,IAAA,CAAK,MAAM,CAAA;AAC1D,QAAA,IAAI,WAAW,YAAA,EAAc;AAC3B,UAAA,SAAA,CAAU,KAAK,QAAQ,CAAA;AACvB,UAAA,IAAA,CAAK,cAAA,CAAe,GAAA,CAAI,QAAA,CAAS,EAAA,EAAI,MAAM,CAAA;AAC3C,UAAA;AAAA,QACF;AACA,QAAA,IAAI,WAAW,QAAA,EAAU;AACvB,UAAA,MAAM,KAAK,eAAA,CAAgB,MAAA,EAAQ,GAAA,CAAI,KAAA,EAAO,IAAI,QAAQ,CAAA;AAC1D,UAAA,IAAA,CAAK,QAAQ,aAAA,CAAc,UAAA,CAAW,CAAC,KAAA,CAAM,OAAO,CAAC,CAAA;AACrD,UAAA,OAAA,IAAW,CAAA;AAAA,QACb,CAAA,MAAO;AAEL,UAAA,MAAM,IAAA,CAAK,aAAa,MAAM,CAAA;AAAA,QAChC;AACA,QAAA;AAAA,MACF;AACA,MAAA,MAAM,KAAK,eAAA,CAAgB,MAAA,EAAQ,GAAA,CAAI,KAAA,EAAO,IAAI,QAAQ,CAAA;AAC1D,MAAA,OAAA,IAAW,CAAA;AAAA,IACb;AAEA,IAAA,IAAA,CAAK,aAAA,GAAgB;AAAA,MACnB,GAAG,IAAA,CAAK,aAAA,CAAc,MAAA,CAAO,CAAC,CAAA,KAAM,IAAA,CAAK,cAAA,CAAe,GAAA,CAAI,CAAA,CAAE,EAAE,CAAC,CAAA;AAAA,MACjE,GAAG;AAAA,KACL;AACA,IAAA,IAAA,CAAK,aAAA,EAAc;AAEnB,IAAA,OAAO;AAAA,MACL,QAAQ,WAAA,CAAY,MAAA;AAAA,MACpB,MAAA,EAAQ,OAAO,MAAA,CAAO,MAAA;AAAA,MACtB,OAAA;AAAA,MACA,WAAW,IAAA,CAAK;AAAA,KAClB;AAAA,EACF;AAAA,EAEA,MAAM,eAAA,CACJ,UAAA,EACA,MAAA,EACe;AACf,IAAA,IAAI,KAAK,QAAA,EAAU;AACnB,IAAA,MAAM,QAAA,GAAW,KAAK,aAAA,CAAc,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,OAAO,UAAU,CAAA;AACnE,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,cAAA,CAAe,GAAA,CAAI,UAAU,CAAA;AACjD,IAAA,IAAI,CAAC,QAAA,IAAY,CAAC,MAAA,EAAQ;AAE1B,IAAA,IAAI,WAAW,QAAA,EAAU;AACvB,MAAA,MAAM,IAAA,CAAK,eAAA;AAAA,QACT,MAAA;AAAA,QACA,SAAS,GAAA,CAAI,KAAA;AAAA,QACb,SAAS,GAAA,CAAI;AAAA,OACf;AACA,MAAA,IAAA,CAAK,QAAQ,aAAA,CAAc,UAAA,CAAW,CAAC,QAAA,CAAS,KAAA,CAAM,OAAO,CAAC,CAAA;AAAA,IAChE,CAAA,MAAO;AACL,MAAA,MAAM,IAAA,CAAK,aAAa,MAAM,CAAA;AAAA,IAChC;AAEA,IAAA,IAAA,CAAK,cAAA,CAAe,OAAO,UAAU,CAAA;AACrC,IAAA,IAAA,CAAK,aAAA,GAAgB,KAAK,aAAA,CAAc,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,OAAO,UAAU,CAAA;AACzE,IAAA,IAAA,CAAK,aAAA,EAAc;AAAA,EACrB;AAAA,EAEA,MAAc,eAAA,CACZ,MAAA,EACA,KAAA,EACA,QAAA,EACe;AACf,IAAA,MAAM,IAAA,CAAK,aAAa,MAAM,CAAA;AAC9B,IAAA,MAAM,SAAS,IAAI,GAAA;AAAA,MACjB,IAAA,CAAK,QAAQ,aAAA,CAAc,iBAAA,GAAoB,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAE,OAAO;AAAA,KACrE;AACA,IAAA,MAAM,KAAA,GAAS,OAAO,OAAA,EAAoC,QAAA;AAC1D,IAAA,MAAM,IAAA,CAAK,OAAA,CAAQ,cAAA,CAAe,KAAA,EAAO,UAAU,KAAK,CAAA;AAExD,IAAA,MAAM,OAAA,GAAU,KAAK,OAAA,CAAQ,aAAA,CAC1B,mBAAkB,CAClB,MAAA,CAAO,CAAC,CAAA,KAAM,CAAC,OAAO,GAAA,CAAI,CAAA,CAAE,OAAO,CAAC,CAAA,CACpC,IAAI,CAAC,CAAA,KAAM,EAAE,OAAO,CAAA;AACvB,IAAA,IAAI,OAAA,CAAQ,SAAS,CAAA,EAAG;AACtB,MAAA,IAAA,CAAK,OAAA,CAAQ,aAAA,CAAc,UAAA,CAAW,OAAO,CAAA;AAAA,IAC/C;AAAA,EACF;AAAA,EAEA,MAAc,aAAa,MAAA,EAAkC;AAC3D,IAAA,MAAM,QAAA,GAAW,MAAA,CAAO,QAAA,IAAY,CAAA,MAAA,EAAS,OAAO,OAAO,CAAA,CAAA;AAC3D,IAAA,MAAM,WAAW,MAAM,IAAA,CAAK,OAAA,CAAQ,UAAA,CAAW,KAAK,QAAQ,CAAA;AAC5D,IAAA,IAAI,QAAA,CAAS,KAAK,CAAC,CAAA,KAAM,EAAE,OAAA,KAAY,MAAA,CAAO,OAAO,CAAA,EAAG;AACtD,MAAA,IAAA,CAAK,QAAQ,aAAA,CAAc,UAAA,CAAW,CAAC,MAAA,CAAO,OAAO,CAAC,CAAA;AACtD,MAAA;AAAA,IACF;AACA,IAAA,MAAM,IAAA,CAAK,QAAQ,UAAA,CAAW,MAAA,CAAO,UAAU,CAAC,MAAM,GAAG,EAAE,CAAA;AAE3D,IAAA,IAAA,CAAK,QAAQ,aAAA,CAAc,UAAA,CAAW,CAAC,MAAA,CAAO,OAAO,CAAC,CAAA;AAAA,EACxD;AAAA,EAEQ,aAAA,GAAsB;AAC5B,IAAA,KAAA,MAAW,QAAA,IAAY,KAAK,iBAAA,EAAmB;AAC7C,MAAA,QAAA,CAAS,KAAK,aAAa,CAAA;AAAA,IAC7B;AAAA,EACF;AACF","file":"chunk-LY27YAXE.cjs","sourcesContent":["import type {\r\n SyncConflict,\r\n SyncConflictPolicy,\r\n ManualResolution,\r\n} from '../ports/SyncPort';\r\n\r\n/**\r\n * Pure conflict resolution (PR-138).\r\n * `manual` always returns unresolved so the UI can choose.\r\n */\r\nexport function resolveConflictChoice(\r\n conflict: SyncConflict,\r\n policy: SyncConflictPolicy,\r\n): ManualResolution | 'unresolved' {\r\n if (policy === 'manual') return 'unresolved';\r\n if (policy === 'serverWins') return 'remote';\r\n // lastWriteWins — tie-break on version then occurredAt\r\n if (conflict.remote.version !== conflict.local.version) {\r\n return conflict.remote.version > conflict.local.version\r\n ? 'remote'\r\n : 'local';\r\n }\r\n if (conflict.remote.occurredAt !== conflict.local.occurredAt) {\r\n return conflict.remote.occurredAt > conflict.local.occurredAt\r\n ? 'remote'\r\n : 'local';\r\n }\r\n return 'remote';\r\n}\r\n\r\nexport function cellKeyFromPayload(\r\n payload: unknown,\r\n): { rowId: number; columnId: string } | null {\r\n if (!payload || typeof payload !== 'object') return null;\r\n const p = payload as Record<string, unknown>;\r\n const columnId = p.columnId;\r\n if (typeof columnId !== 'string' || !columnId) return null;\r\n const rowRaw = p.rowId;\r\n const rowId =\r\n typeof rowRaw === 'number'\r\n ? rowRaw\r\n : typeof rowRaw === 'string'\r\n ? Number(rowRaw)\r\n : NaN;\r\n if (!Number.isFinite(rowId)) return null;\r\n return { rowId, columnId };\r\n}\r\n\r\nexport function cellKeyId(rowId: number, columnId: string): string {\r\n return `${rowId}:${columnId}`;\r\n}\r\n","import type { EventStore } from '../ports/EventStore';\r\nimport type { GridEvent } from '../../domain/types/GridEvent';\r\nimport type { OfflineStatus } from '../offline/OfflineStatus';\r\nimport type {\r\n ManualResolution,\r\n SyncConflict,\r\n SyncConflictPolicy,\r\n SyncPort,\r\n SyncResult,\r\n SyncTransport,\r\n} from '../ports/SyncPort';\r\nimport {\r\n cellKeyFromPayload,\r\n cellKeyId,\r\n resolveConflictChoice,\r\n} from './resolveCellConflicts';\r\n\r\nexport type GridSyncServiceOptions = {\r\n readonly tableId: string;\r\n readonly eventStore: EventStore;\r\n readonly offlineStatus: OfflineStatus;\r\n readonly transport: SyncTransport;\r\n /** Apply a winning remote CELL_CHANGED into the local domain. */\r\n readonly applyCellValue: (\r\n rowId: number,\r\n columnId: string,\r\n value: unknown,\r\n ) => Promise<void>;\r\n /** Initial pull cursor (default 0). */\r\n readonly initialCursor?: number;\r\n readonly policy?: SyncConflictPolicy;\r\n};\r\n\r\nfunction isCellChanged(event: GridEvent): boolean {\r\n return event.type === 'CELL_CHANGED';\r\n}\r\n\r\nfunction toSide(event: GridEvent): SyncConflict['local'] {\r\n const payload = event.payload as { newValue?: unknown };\r\n return {\r\n eventId: event.eventId,\r\n value: payload?.newValue,\r\n occurredAt: event.occurredAt,\r\n version: event.version,\r\n };\r\n}\r\n\r\n/**\r\n * SyncPort implementation over EventStore + OfflineStatus + SyncTransport (PR-138).\r\n */\r\nexport class GridSyncService implements SyncPort {\r\n private policy: SyncConflictPolicy;\r\n private cursor: number;\r\n private openConflicts: SyncConflict[] = [];\r\n private readonly conflictListeners = new Set<\r\n (conflicts: readonly SyncConflict[]) => void\r\n >();\r\n /** Remote events waiting on manual resolution (by conflict id). */\r\n private readonly deferredRemote = new Map<string, GridEvent>();\r\n private disposed = false;\r\n\r\n constructor(private readonly options: GridSyncServiceOptions) {\r\n this.policy = options.policy ?? 'lastWriteWins';\r\n this.cursor = options.initialCursor ?? 0;\r\n }\r\n\r\n getPolicy(): SyncConflictPolicy {\r\n return this.policy;\r\n }\r\n\r\n setPolicy(policy: SyncConflictPolicy): void {\r\n this.policy = policy;\r\n }\r\n\r\n getOpenConflicts(): readonly SyncConflict[] {\r\n return this.openConflicts;\r\n }\r\n\r\n subscribeConflicts(\r\n listener: (conflicts: readonly SyncConflict[]) => void,\r\n ): () => void {\r\n if (this.disposed) return () => undefined;\r\n this.conflictListeners.add(listener);\r\n listener(this.openConflicts);\r\n return () => this.conflictListeners.delete(listener);\r\n }\r\n\r\n /** Drop listeners and deferred conflicts; later sync() calls are no-ops. */\r\n dispose(): void {\r\n this.disposed = true;\r\n this.conflictListeners.clear();\r\n this.deferredRemote.clear();\r\n this.openConflicts = [];\r\n }\r\n\r\n private emptyResult(): SyncResult {\r\n return { pushed: 0, pulled: 0, applied: 0, conflicts: [] };\r\n }\r\n\r\n async sync(): Promise<SyncResult> {\r\n if (this.disposed) return this.emptyResult();\r\n const pending = this.options.offlineStatus.getPendingChanges();\r\n const pushable = pending\r\n .map((p) => p.event)\r\n .filter(\r\n (e): e is GridEvent =>\r\n Boolean(e) && e.tableId === this.options.tableId,\r\n );\r\n\r\n const { acceptedIds } = await this.options.transport.push(pushable);\r\n if (this.disposed) return this.emptyResult();\r\n if (acceptedIds.length > 0) {\r\n this.options.offlineStatus.markSynced([...acceptedIds]);\r\n }\r\n\r\n // Locals just pushed (or still pending) — used to detect cell conflicts on pull.\r\n const localByCell = new Map<string, GridEvent>();\r\n for (const event of pushable) {\r\n if (!isCellChanged(event)) continue;\r\n const key = cellKeyFromPayload(event.payload);\r\n if (!key) continue;\r\n localByCell.set(cellKeyId(key.rowId, key.columnId), event);\r\n }\r\n for (const event of this.options.offlineStatus\r\n .getPendingChanges()\r\n .map((p) => p.event)\r\n .filter((e): e is GridEvent => Boolean(e))) {\r\n if (!isCellChanged(event) || event.tableId !== this.options.tableId) {\r\n continue;\r\n }\r\n const key = cellKeyFromPayload(event.payload);\r\n if (!key) continue;\r\n localByCell.set(cellKeyId(key.rowId, key.columnId), event);\r\n }\r\n\r\n const pulled = await this.options.transport.pull(this.cursor);\r\n if (this.disposed) return this.emptyResult();\r\n this.cursor = pulled.cursor;\r\n\r\n let applied = 0;\r\n const conflicts: SyncConflict[] = [];\r\n\r\n for (const remote of pulled.events) {\r\n // Torn down mid-apply: stop writing into a released event store.\r\n if (this.disposed) return this.emptyResult();\r\n if (remote.tableId !== this.options.tableId) continue;\r\n if (!isCellChanged(remote)) {\r\n await this.ingestRemote(remote);\r\n applied += 1;\r\n continue;\r\n }\r\n const key = cellKeyFromPayload(remote.payload);\r\n if (!key) continue;\r\n const id = cellKeyId(key.rowId, key.columnId);\r\n const local = localByCell.get(id);\r\n if (local && toSide(local).value !== toSide(remote).value) {\r\n const conflict: SyncConflict = {\r\n id: `conflict:${id}:${remote.eventId}`,\r\n key,\r\n local: toSide(local),\r\n remote: toSide(remote),\r\n };\r\n const choice = resolveConflictChoice(conflict, this.policy);\r\n if (choice === 'unresolved') {\r\n conflicts.push(conflict);\r\n this.deferredRemote.set(conflict.id, remote);\r\n continue;\r\n }\r\n if (choice === 'remote') {\r\n await this.applyRemoteCell(remote, key.rowId, key.columnId);\r\n this.options.offlineStatus.markSynced([local.eventId]);\r\n applied += 1;\r\n } else {\r\n // Keep local — acknowledge remote without applying its value\r\n await this.ingestRemote(remote);\r\n }\r\n continue;\r\n }\r\n await this.applyRemoteCell(remote, key.rowId, key.columnId);\r\n applied += 1;\r\n }\r\n\r\n this.openConflicts = [\r\n ...this.openConflicts.filter((c) => this.deferredRemote.has(c.id)),\r\n ...conflicts,\r\n ];\r\n this.emitConflicts();\r\n\r\n return {\r\n pushed: acceptedIds.length,\r\n pulled: pulled.events.length,\r\n applied,\r\n conflicts: this.openConflicts,\r\n };\r\n }\r\n\r\n async resolveConflict(\r\n conflictId: string,\r\n choice: ManualResolution,\r\n ): Promise<void> {\r\n if (this.disposed) return;\r\n const conflict = this.openConflicts.find((c) => c.id === conflictId);\r\n const remote = this.deferredRemote.get(conflictId);\r\n if (!conflict || !remote) return;\r\n\r\n if (choice === 'remote') {\r\n await this.applyRemoteCell(\r\n remote,\r\n conflict.key.rowId,\r\n conflict.key.columnId,\r\n );\r\n this.options.offlineStatus.markSynced([conflict.local.eventId]);\r\n } else {\r\n await this.ingestRemote(remote);\r\n }\r\n\r\n this.deferredRemote.delete(conflictId);\r\n this.openConflicts = this.openConflicts.filter((c) => c.id !== conflictId);\r\n this.emitConflicts();\r\n }\r\n\r\n private async applyRemoteCell(\r\n remote: GridEvent,\r\n rowId: number,\r\n columnId: string,\r\n ): Promise<void> {\r\n await this.ingestRemote(remote);\r\n const before = new Set(\r\n this.options.offlineStatus.getPendingChanges().map((p) => p.eventId),\r\n );\r\n const value = (remote.payload as { newValue?: unknown })?.newValue;\r\n await this.options.applyCellValue(rowId, columnId, value);\r\n // CHANGE_CELL_VALUE may dual-write a new local event — treat as synced.\r\n const created = this.options.offlineStatus\r\n .getPendingChanges()\r\n .filter((p) => !before.has(p.eventId))\r\n .map((p) => p.eventId);\r\n if (created.length > 0) {\r\n this.options.offlineStatus.markSynced(created);\r\n }\r\n }\r\n\r\n private async ingestRemote(remote: GridEvent): Promise<void> {\r\n const streamId = remote.streamId || `table:${remote.tableId}`;\r\n const existing = await this.options.eventStore.read(streamId);\r\n if (existing.some((e) => e.eventId === remote.eventId)) {\r\n this.options.offlineStatus.markSynced([remote.eventId]);\r\n return;\r\n }\r\n await this.options.eventStore.append(streamId, [remote], -1);\r\n // Remote ingest must not look like a local pending mutation.\r\n this.options.offlineStatus.markSynced([remote.eventId]);\r\n }\r\n\r\n private emitConflicts(): void {\r\n for (const listener of this.conflictListeners) {\r\n listener(this.openConflicts);\r\n }\r\n }\r\n}\r\n"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { buildExportTable } from './chunk-
|
|
1
|
+
import { buildExportTable } from './chunk-7GWV5HGO.js';
|
|
2
2
|
import { buildXlsxBlob, downloadBlob } from './chunk-PQY54EL5.js';
|
|
3
|
-
import { formatExportValue } from './chunk-
|
|
3
|
+
import { formatExportValue } from './chunk-GKE33FOJ.js';
|
|
4
4
|
import { unzipSync, strFromU8 } from 'fflate';
|
|
5
5
|
|
|
6
6
|
// packages/plugins/excel/src/ExcelExportPlugin.ts
|
|
@@ -775,6 +775,7 @@ async function exportActiveCollectionToExcelStreaming(controller, options) {
|
|
|
775
775
|
// packages/plugins/excel/src/exportActiveCollectionToExcel.ts
|
|
776
776
|
var hasMeaningfulValue2 = (value) => value !== void 0 && value !== null && value !== "";
|
|
777
777
|
async function exportActiveCollectionToExcel(controller, options) {
|
|
778
|
+
await controller.flushCellEdit();
|
|
778
779
|
if (controller.isPagedWindow()) {
|
|
779
780
|
return exportActiveCollectionToExcelStreaming(controller, options);
|
|
780
781
|
}
|
|
@@ -828,5 +829,5 @@ async function exportActiveCollectionToExcel(controller, options) {
|
|
|
828
829
|
}
|
|
829
830
|
|
|
830
831
|
export { ExcelExportPlugin, ExcelImportPlugin, applyImportedRows, exportActiveCollectionToExcel, mapImportedSheet, parseXlsxBlob };
|
|
831
|
-
//# sourceMappingURL=chunk-
|
|
832
|
-
//# sourceMappingURL=chunk-
|
|
832
|
+
//# sourceMappingURL=chunk-NB5GCGHL.js.map
|
|
833
|
+
//# sourceMappingURL=chunk-NB5GCGHL.js.map
|