@flowselections/pick-schermen-kwekers 1.0.21 → 1.0.23

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.
Files changed (67) hide show
  1. package/dist-lib/components/pick/PickScherm.d.ts.map +1 -1
  2. package/dist-lib/components/pick/PickScherm.js +56 -27
  3. package/dist-lib/hooks/usePickConfig.d.ts +11 -11
  4. package/dist-lib/hooks/usePickConfig.d.ts.map +1 -1
  5. package/dist-lib/hooks/usePickQueue.d.ts +5 -3
  6. package/dist-lib/hooks/usePickQueue.d.ts.map +1 -1
  7. package/dist-lib/hooks/usePickQueue.js +17 -4
  8. package/dist-lib/hooks/usePickReferenceData.d.ts +1 -1
  9. package/dist-lib/hooks/usePickReferenceData.d.ts.map +1 -1
  10. package/dist-lib/integrations/supabase/auth-middleware.d.ts +4754 -230
  11. package/dist-lib/integrations/supabase/auth-middleware.d.ts.map +1 -1
  12. package/dist-lib/integrations/supabase/client.d.ts +4754 -230
  13. package/dist-lib/integrations/supabase/client.d.ts.map +1 -1
  14. package/dist-lib/integrations/supabase/client.js +1 -1
  15. package/dist-lib/integrations/supabase/client.server.d.ts +4754 -230
  16. package/dist-lib/integrations/supabase/client.server.d.ts.map +1 -1
  17. package/dist-lib/integrations/supabase/client.server.js +1 -1
  18. package/dist-lib/integrations/supabase/previewAuthStorage.d.ts +1 -1
  19. package/dist-lib/integrations/supabase/previewAuthStorage.d.ts.map +1 -1
  20. package/dist-lib/integrations/supabase/previewAuthStorage.js +8 -1
  21. package/dist-lib/integrations/supabase/types.d.ts +4795 -203
  22. package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
  23. package/dist-lib/lib/__tests__/pickRobustness.test.d.ts +2 -0
  24. package/dist-lib/lib/__tests__/pickRobustness.test.d.ts.map +1 -0
  25. package/dist-lib/lib/__tests__/pickRobustness.test.js +68 -0
  26. package/dist-lib/lib/pickApi.d.ts +25 -1
  27. package/dist-lib/lib/pickApi.d.ts.map +1 -1
  28. package/dist-lib/lib/pickApi.js +56 -3
  29. package/dist-lib/lib/pickRetry.d.ts +13 -0
  30. package/dist-lib/lib/pickRetry.d.ts.map +1 -0
  31. package/dist-lib/lib/pickRetry.js +52 -0
  32. package/dist-lib/lib/pickUiText.d.ts.map +1 -1
  33. package/dist-lib/lib/pickUiText.js +5 -3
  34. package/dist-lib/lib/pickVerify.d.ts +15 -0
  35. package/dist-lib/lib/pickVerify.d.ts.map +1 -0
  36. package/dist-lib/lib/pickVerify.js +32 -0
  37. package/package.json +5 -4
  38. package/dist-lib/lib/layoutApi.d.ts +0 -23
  39. package/dist-lib/lib/layoutApi.d.ts.map +0 -1
  40. package/dist-lib/lib/layoutApi.js +0 -94
  41. package/dist-lib/lib/layoutMaker/documentProfiles.d.ts +0 -50
  42. package/dist-lib/lib/layoutMaker/documentProfiles.d.ts.map +0 -1
  43. package/dist-lib/lib/layoutMaker/documentProfiles.js +0 -458
  44. package/dist-lib/lib/layoutMaker/documentTypes.d.ts +0 -123
  45. package/dist-lib/lib/layoutMaker/documentTypes.d.ts.map +0 -1
  46. package/dist-lib/lib/layoutMaker/documentTypes.js +0 -74
  47. package/dist-lib/lib/layoutMaker/logoLibrary.d.ts +0 -13
  48. package/dist-lib/lib/layoutMaker/logoLibrary.d.ts.map +0 -1
  49. package/dist-lib/lib/layoutMaker/logoLibrary.js +0 -54
  50. package/dist-lib/lib/layoutMaker/pakbonBuilder.d.ts +0 -196
  51. package/dist-lib/lib/layoutMaker/pakbonBuilder.d.ts.map +0 -1
  52. package/dist-lib/lib/layoutMaker/pakbonBuilder.js +0 -813
  53. package/dist-lib/lib/layoutMaker/pakbonHtml.d.ts +0 -48
  54. package/dist-lib/lib/layoutMaker/pakbonHtml.d.ts.map +0 -1
  55. package/dist-lib/lib/layoutMaker/pakbonHtml.js +0 -703
  56. package/dist-lib/lib/layoutRenderer.d.ts +0 -7
  57. package/dist-lib/lib/layoutRenderer.d.ts.map +0 -1
  58. package/dist-lib/lib/layoutRenderer.js +0 -233
  59. package/dist-lib/lib/layoutTypes.d.ts +0 -84
  60. package/dist-lib/lib/layoutTypes.d.ts.map +0 -1
  61. package/dist-lib/lib/layoutTypes.js +0 -25
  62. package/dist-lib/lib/orderContext.d.ts +0 -50
  63. package/dist-lib/lib/orderContext.d.ts.map +0 -1
  64. package/dist-lib/lib/orderContext.js +0 -162
  65. package/dist-lib/lib/pakbonOrderInput.d.ts +0 -8
  66. package/dist-lib/lib/pakbonOrderInput.d.ts.map +0 -1
  67. package/dist-lib/lib/pakbonOrderInput.js +0 -150
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=pickRobustness.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pickRobustness.test.d.ts","sourceRoot":"","sources":["../../../src/lib/__tests__/pickRobustness.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,68 @@
1
+ import { describe, expect, it, vi } from "vitest";
2
+ vi.mock("@flowselections/core", () => ({ supabase: {} }));
3
+ import { verifyRowsWith, createRetryingDb } from "../pickApi";
4
+ import { withRetry } from "../pickRetry";
5
+ import { rowsToVerify, rowFingerprint } from "../pickVerify";
6
+ import { friendlyPickError } from "../pickUiText";
7
+ const rows = (n) => Array.from({ length: n }, (_, i) => ({ id: `id-${i}`, updated_at: "t1", payload: {} }));
8
+ const noSleep = { sleep: async () => { } };
9
+ describe("gebundelde controle", () => {
10
+ for (const n of [33, 100]) {
11
+ it(`${n} rijen: 1 aanroep i.p.v. ${n * 2}`, async () => {
12
+ const rpc = vi.fn(async (_fn, args) => ({
13
+ data: args["_rows"].map((r) => ({ id: r.id, plan: null, status: null })),
14
+ error: null,
15
+ }));
16
+ const out = await verifyRowsWith({ rpc }, rows(n).map((r) => ({ id: r.id, ref: r.id })));
17
+ expect(out).toHaveLength(n);
18
+ expect(rpc).toHaveBeenCalledTimes(1);
19
+ console.log(`[test] ${n} rijen → oud ${n * 2} aanroepen, nieuw ${rpc.mock.calls.length}`);
20
+ });
21
+ }
22
+ it("ongewijzigde, printklare rijen: 0 aanroepen in de volgende ronde", () => {
23
+ const items = rows(33);
24
+ const memo = new Map();
25
+ const now = 1000000;
26
+ items.forEach((it) => memo.set(it.id, { fingerprint: rowFingerprint(it), ready: true, checkedAt: now }));
27
+ expect(rowsToVerify(items, memo, now + 15000)).toHaveLength(0);
28
+ // gewijzigde rij gaat wel mee
29
+ const changed = [...items];
30
+ changed[0] = { ...changed[0], updated_at: "t2" };
31
+ expect(rowsToVerify(changed, memo, now + 15000)).toHaveLength(1);
32
+ });
33
+ });
34
+ describe("herhaalpoging", () => {
35
+ it("Failed to fetch bij pick_claim_next_document: herhaalt en slaagt", async () => {
36
+ const rpc = vi
37
+ .fn()
38
+ .mockResolvedValueOnce({ data: null, error: { message: "TypeError: Failed to fetch" } })
39
+ .mockResolvedValueOnce({ data: { id: "ok" }, error: null });
40
+ const res = await withRetry(() => rpc("pick_claim_next_document"), noSleep);
41
+ expect(res.error).toBeNull();
42
+ expect(rpc).toHaveBeenCalledTimes(2);
43
+ });
44
+ it("de gedeelde client herhaalt ook", async () => {
45
+ const base = {
46
+ rpc: vi.fn().mockRejectedValueOnce(new TypeError("Failed to fetch")).mockResolvedValue({ data: 1, error: null }),
47
+ };
48
+ vi.useFakeTimers();
49
+ const p = createRetryingDb(base).rpc("pick_claim_next_document");
50
+ await vi.runAllTimersAsync();
51
+ expect((await p).data).toBe(1);
52
+ expect(base.rpc).toHaveBeenCalledTimes(2);
53
+ vi.useRealTimers();
54
+ });
55
+ it("blijvende netwerkfout: 4 pogingen, dan nette melding", async () => {
56
+ const rpc = vi.fn().mockResolvedValue({ data: null, error: { message: "Failed to fetch" } });
57
+ const res = await withRetry(() => rpc(), noSleep);
58
+ expect(rpc).toHaveBeenCalledTimes(4);
59
+ const f = friendlyPickError(new Error(res.error.message), "nl");
60
+ expect(f.message).toMatch(/Geen verbinding/);
61
+ expect(f.message).not.toMatch(/Failed to fetch/);
62
+ });
63
+ it("databasefout wordt niet herhaald", async () => {
64
+ const rpc = vi.fn().mockResolvedValue({ data: null, error: { message: "Station is niet actief" } });
65
+ await withRetry(() => rpc(), noSleep);
66
+ expect(rpc).toHaveBeenCalledTimes(1);
67
+ });
68
+ });
@@ -1,6 +1,6 @@
1
1
  import { supabase } from "@flowselections/core";
2
2
  import type { PickCartPlan, PickCountry, PickDashboardRow, PickDocumentType, PickLock, PickActivePrinter, PickPrintJob, PickPrintPlek, PickStationPrintPlek, PickStationPrintPlekRow, PickPrinter, PickQueueItem, PickScreen, PickSortRule, PickStation, PickStationType, PickStatus, PickTask } from "./pickTypes";
3
- declare const db: {
3
+ type PickDbClient = {
4
4
  from: (t: string) => any;
5
5
  rpc: (fn: string, args?: Record<string, unknown>) => Promise<{
6
6
  data: any;
@@ -10,7 +10,25 @@ declare const db: {
10
10
  removeChannel: (c: any) => void;
11
11
  auth: typeof supabase.auth;
12
12
  };
13
+ /** Zelfde client, maar RPC-aanroepen vangen tijdelijke netwerkhaperingen op. */
14
+ export declare function createRetryingDb(base: PickDbClient): PickDbClient;
15
+ declare const db: PickDbClient;
13
16
  export { db as pickDb };
17
+ export interface VerifiedRow {
18
+ id: string;
19
+ plan: PickCartPlan | null;
20
+ status: {
21
+ ready: boolean;
22
+ released: boolean;
23
+ reason: string | null;
24
+ } | null;
25
+ error: string | null;
26
+ }
27
+ /** Eén aanroep per blok van max. 200 regels i.p.v. twee per regel. */
28
+ export declare function verifyRowsWith(client: Pick<PickDbClient, "rpc">, rows: {
29
+ id: string;
30
+ ref: string | null;
31
+ }[]): Promise<VerifiedRow[]>;
14
32
  export interface PickBatchPrintJob {
15
33
  cartId: string;
16
34
  cartLabel: string | null;
@@ -61,6 +79,7 @@ export declare const pickApi: {
61
79
  * De database knijpt de aanroep af (max. 1x per minuut voor alle schermen
62
80
  * samen), zodat tien geopende pickschermen niet tien keer synchroniseren.
63
81
  */
82
+ /** Gooit een fout als de synchronisatie (of de laatst bekende ronde) een fout meldde. */
64
83
  syncQueue(): Promise<void>;
65
84
  /** Aantallen van de actuele pickdag: nog printen versus geprint (in de database geteld). */
66
85
  dayCounts(args: {
@@ -158,6 +177,11 @@ export declare const pickApi: {
158
177
  * Karplan van de hele pick-eenheid: bij een bufferorder alle karren van alle
159
178
  * orders in de buffer samen. Nummers en totalen komen uit de Engine.
160
179
  */
180
+ /** Gebundelde gereedheidscontrole voor meerdere regels. */
181
+ verifyRows(rows: {
182
+ id: string;
183
+ ref: string | null;
184
+ }[]): Promise<VerifiedRow[]>;
161
185
  queueCartPlan(queueItemId: string): Promise<PickCartPlan | null>;
162
186
  /** Zet één kar in de printopdracht en rondt alleen deze kar af. */
163
187
  completePrintCart(itemId: string, sessionId: string, cartId: string): Promise<PickQueueItem>;
@@ -1 +1 @@
1
- {"version":3,"file":"pickApi.d.ts","sourceRoot":"","sources":["../../src/lib/pickApi.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"pickApi.d.ts","sourceRoot":"","sources":["../../src/lib/pickApi.ts"],"names":[],"mappings":"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"}
@@ -1,9 +1,51 @@
1
1
  import { supabase } from "@flowselections/core";
2
2
  import { parsePickCartPlan } from "./pickTypes";
3
3
  import { safeArray } from "./pickTypes";
4
- // De core-client is getypeerd op het core-schema; deze module gebruikt eigen tabellen.
5
- const db = supabase;
4
+ import { withRetry } from "./pickRetry";
5
+ const raw = supabase;
6
+ /** Zelfde client, maar RPC-aanroepen vangen tijdelijke netwerkhaperingen op. */
7
+ export function createRetryingDb(base) {
8
+ return {
9
+ from: (t) => base.from(t),
10
+ rpc: (fn, args) => withRetry(() => base.rpc(fn, args)),
11
+ channel: (name) => base.channel(name),
12
+ removeChannel: (c) => base.removeChannel(c),
13
+ get auth() {
14
+ return base.auth;
15
+ },
16
+ };
17
+ }
18
+ const db = createRetryingDb(raw);
6
19
  export { db as pickDb };
20
+ function parsePlanStatus(data) {
21
+ if (!data || typeof data !== "object")
22
+ return null;
23
+ const row = data;
24
+ return {
25
+ ready: row["ready"] === true,
26
+ released: row["released"] === true,
27
+ reason: typeof row["reason"] === "string" ? row["reason"] : null,
28
+ };
29
+ }
30
+ /** Eén aanroep per blok van max. 200 regels i.p.v. twee per regel. */
31
+ export async function verifyRowsWith(client, rows) {
32
+ const out = [];
33
+ for (let i = 0; i < rows.length; i += 200) {
34
+ const chunk = rows.slice(i, i + 200);
35
+ const { data, error } = await client.rpc("pick_verify_rows", { _rows: chunk });
36
+ if (error)
37
+ throw new Error(error.message);
38
+ for (const r of safeArray(data)) {
39
+ out.push({
40
+ id: String(r["id"]),
41
+ plan: parsePickCartPlan(r["plan"]),
42
+ status: parsePlanStatus(r["status"]),
43
+ error: typeof r["error"] === "string" ? r["error"] : null,
44
+ });
45
+ }
46
+ }
47
+ return out;
48
+ }
7
49
  function unwrap(res) {
8
50
  if (res.error)
9
51
  throw new Error(res.error.message);
@@ -143,10 +185,17 @@ export const pickApi = {
143
185
  * De database knijpt de aanroep af (max. 1x per minuut voor alle schermen
144
186
  * samen), zodat tien geopende pickschermen niet tien keer synchroniseren.
145
187
  */
188
+ /** Gooit een fout als de synchronisatie (of de laatst bekende ronde) een fout meldde. */
146
189
  async syncQueue() {
147
- const { error } = await db.rpc("pick_sync_queue_throttled", { _min_seconds: 60 });
190
+ const { data, error } = await db.rpc("pick_sync_queue_throttled", { _min_seconds: 60 });
148
191
  if (error)
149
192
  throw new Error(error.message);
193
+ const row = (data && typeof data === "object" ? data : {});
194
+ const syncError = typeof row["error"] === "string" && row["error"] ? row["error"] : null;
195
+ if (syncError) {
196
+ console.error("[pick] Synchronisatie pickwachtrij mislukt:", syncError);
197
+ throw new Error(syncError);
198
+ }
150
199
  },
151
200
  /** Aantallen van de actuele pickdag: nog printen versus geprint (in de database geteld). */
152
201
  async dayCounts(args) {
@@ -354,6 +403,10 @@ export const pickApi = {
354
403
  * Karplan van de hele pick-eenheid: bij een bufferorder alle karren van alle
355
404
  * orders in de buffer samen. Nummers en totalen komen uit de Engine.
356
405
  */
406
+ /** Gebundelde gereedheidscontrole voor meerdere regels. */
407
+ verifyRows(rows) {
408
+ return verifyRowsWith(db, rows);
409
+ },
357
410
  async queueCartPlan(queueItemId) {
358
411
  const { data, error } = await db.rpc("pick_queue_cart_plan", { _queue_item_id: queueItemId });
359
412
  if (error)
@@ -0,0 +1,13 @@
1
+ export declare const RETRY_DELAYS_MS: readonly [300, 900, 2000];
2
+ export declare function isNetworkError(error: unknown): boolean;
3
+ type RpcResult = {
4
+ data: unknown;
5
+ error: unknown;
6
+ };
7
+ /** Voert een Supabase-aanroep uit; herhaalt alleen bij netwerkfouten. */
8
+ export declare function withRetry<T extends RpcResult>(call: () => PromiseLike<T>, opts?: {
9
+ delays?: readonly number[];
10
+ sleep?: (ms: number) => Promise<void>;
11
+ }): Promise<T>;
12
+ export {};
13
+ //# sourceMappingURL=pickRetry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pickRetry.d.ts","sourceRoot":"","sources":["../../src/lib/pickRetry.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,eAAe,2BAA4B,CAAC;AAmBzD,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAOtD;AAED,KAAK,SAAS,GAAG;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,CAAC;AAEnD,yEAAyE;AACzE,wBAAsB,SAAS,CAAC,CAAC,SAAS,SAAS,EACjD,IAAI,EAAE,MAAM,WAAW,CAAC,CAAC,CAAC,EAC1B,IAAI,GAAE;IAAE,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAAC,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;CAAO,GAC/E,OAAO,CAAC,CAAC,CAAC,CAmBZ"}
@@ -0,0 +1,52 @@
1
+ // Herhaalpogingen voor tijdelijke netwerkhaperingen. Databasefouten
2
+ // (bijv. "niet actief", "andere sessie") worden nooit herhaald.
3
+ export const RETRY_DELAYS_MS = [300, 900, 2000];
4
+ const NETWORK_PATTERNS = [
5
+ "failed to fetch",
6
+ "networkerror",
7
+ "network request failed",
8
+ "load failed",
9
+ "fetch failed",
10
+ "timeout",
11
+ "timed out",
12
+ "econnreset",
13
+ "502",
14
+ "503",
15
+ "504",
16
+ "bad gateway",
17
+ "service unavailable",
18
+ "gateway timeout",
19
+ ];
20
+ export function isNetworkError(error) {
21
+ if (!error)
22
+ return false;
23
+ const e = error;
24
+ const status = Number(e.status);
25
+ if (status === 502 || status === 503 || status === 504)
26
+ return true;
27
+ const msg = (typeof e.message === "string" ? e.message : String(error)).toLowerCase();
28
+ return NETWORK_PATTERNS.some((p) => msg.includes(p));
29
+ }
30
+ /** Voert een Supabase-aanroep uit; herhaalt alleen bij netwerkfouten. */
31
+ export async function withRetry(call, opts = {}) {
32
+ const delays = opts.delays ?? RETRY_DELAYS_MS;
33
+ const sleep = opts.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
34
+ for (let attempt = 0;; attempt += 1) {
35
+ let result = null;
36
+ let thrown = null;
37
+ try {
38
+ result = await call();
39
+ }
40
+ catch (e) {
41
+ thrown = e;
42
+ }
43
+ const err = thrown ?? result?.error;
44
+ if (!err || !isNetworkError(err) || attempt >= delays.length) {
45
+ if (thrown)
46
+ throw thrown;
47
+ return result;
48
+ }
49
+ const base = delays[attempt];
50
+ await sleep(base + Math.round(Math.random() * base * 0.25));
51
+ }
52
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"pickUiText.d.ts","sourceRoot":"","sources":["../../src/lib/pickUiText.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,WAAW;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,EAAE,MAAM,CAAC;IACzB,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,gBAAgB,EAAE,MAAM,CAAC;IACzB,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,kBAAkB,EAAE,MAAM,CAAC;CAC5B;AA4DD,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAExD;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,OAAO,EACd,IAAI,EAAE,MAAM,GACX;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,OAAO,CAAA;CAAE,CAkC7D"}
1
+ {"version":3,"file":"pickUiText.d.ts","sourceRoot":"","sources":["../../src/lib/pickUiText.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,WAAW;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,EAAE,MAAM,CAAC;IACzB,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,gBAAgB,EAAE,MAAM,CAAC;IACzB,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,kBAAkB,EAAE,MAAM,CAAC;CAC5B;AA4DD,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAExD;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,OAAO,EACd,IAAI,EAAE,MAAM,GACX;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,OAAO,CAAA;CAAE,CAsC7D"}
@@ -1,6 +1,4 @@
1
- // Extra schermteksten voor de pickomgeving (filters, scanner, meldingen).
2
- // Bewust los van pickI18n: die dictionaries zijn volledig per taal gevuld,
3
- // hier volstaat Nederlands met Engels als terugval.
1
+ import { isNetworkError } from "./pickRetry";
4
2
  const nl = {
5
3
  onlyPending: "Alleen nog printen",
6
4
  onlyUrgent: "Alleen spoed",
@@ -65,6 +63,10 @@ export function friendlyPickError(error, lang) {
65
63
  const texts = getPickUiTexts(lang);
66
64
  const raw = error instanceof Error ? error.message : typeof error === "string" ? error : "";
67
65
  const low = raw.toLowerCase();
66
+ // Netwerkhapering die na alle herhaalpogingen blijft: nooit rauw tonen.
67
+ if (isNetworkError(error) || isNetworkError(raw)) {
68
+ return { message: texts.connectionLost, detail: raw || undefined, expiredClaim: false };
69
+ }
68
70
  // Een botsing op de idempotentiesleutel van de printdienst is géén race:
69
71
  // er is dan geen ander scherm bezig met dit document.
70
72
  if (low.includes("idempotentie_sleutel") || low.includes("idempotentiesleutel")) {
@@ -0,0 +1,15 @@
1
+ import type { PickQueueItem } from "./pickTypes";
2
+ export interface VerifyMemo {
3
+ fingerprint: string;
4
+ ready: boolean;
5
+ checkedAt: number;
6
+ }
7
+ export declare const VERIFY_MAX_AGE_MS = 60000;
8
+ /** Alles wat aangeeft dat een regel in de wachtrij veranderd is. */
9
+ export declare function rowFingerprint(item: PickQueueItem): string;
10
+ /**
11
+ * Kiest welke regels deze ronde opnieuw bij de bron gecontroleerd moeten worden:
12
+ * gewijzigd, nog niet printklaar, of langer dan maxAge niet gecontroleerd.
13
+ */
14
+ export declare function rowsToVerify(items: PickQueueItem[], memo: Map<string, VerifyMemo>, now: number, maxAge?: number): PickQueueItem[];
15
+ //# sourceMappingURL=pickVerify.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pickVerify.d.ts","sourceRoot":"","sources":["../../src/lib/pickVerify.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD,MAAM,WAAW,UAAU;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,OAAO,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,eAAO,MAAM,iBAAiB,QAAS,CAAC;AAExC,oEAAoE;AACpE,wBAAgB,cAAc,CAAC,IAAI,EAAE,aAAa,GAAG,MAAM,CAgB1D;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAC1B,KAAK,EAAE,aAAa,EAAE,EACtB,IAAI,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,EAC7B,GAAG,EAAE,MAAM,EACX,MAAM,SAAoB,GACzB,aAAa,EAAE,CAQjB"}
@@ -0,0 +1,32 @@
1
+ export const VERIFY_MAX_AGE_MS = 60000;
2
+ /** Alles wat aangeeft dat een regel in de wachtrij veranderd is. */
3
+ export function rowFingerprint(item) {
4
+ const r = item;
5
+ const p = (r["payload"] && typeof r["payload"] === "object" ? r["payload"] : {});
6
+ return JSON.stringify([
7
+ r["status_id"] ?? r["status"] ?? null,
8
+ r["printed_at"] ?? null,
9
+ r["updated_at"] ?? null,
10
+ p["cartPlanReady"] ?? null,
11
+ p["cartPlanReleased"] ?? null,
12
+ p["cartPlanReason"] ?? null,
13
+ p["totalCarts"] ?? p["cartTotal"] ?? null,
14
+ p["cartRowFor"] ?? null,
15
+ ]);
16
+ }
17
+ /**
18
+ * Kiest welke regels deze ronde opnieuw bij de bron gecontroleerd moeten worden:
19
+ * gewijzigd, nog niet printklaar, of langer dan maxAge niet gecontroleerd.
20
+ */
21
+ export function rowsToVerify(items, memo, now, maxAge = VERIFY_MAX_AGE_MS) {
22
+ return items.filter((item) => {
23
+ const m = memo.get(item.id);
24
+ if (!m)
25
+ return true;
26
+ if (m.fingerprint !== rowFingerprint(item))
27
+ return true;
28
+ if (!m.ready)
29
+ return true;
30
+ return now - m.checkedAt >= maxAge;
31
+ });
32
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flowselections/pick-schermen-kwekers",
3
- "version": "1.0.21",
3
+ "version": "1.0.23",
4
4
  "flowselections": {
5
5
  "moduleId": "pick-schermen",
6
6
  "pages": [
@@ -64,8 +64,8 @@
64
64
  "devDependencies": {
65
65
  "@cloudflare/vite-plugin": "^1.25.5",
66
66
  "@eslint/js": "^9.32.0",
67
- "@flowselections/core": "1.0.21",
68
- "@lovable.dev/vite-tanstack-config": "2.13.1",
67
+ "@flowselections/core": "1.0.28",
68
+ "@lovable.dev/vite-tanstack-config": "2.23.1",
69
69
  "@rsbuild/core": "^1.0.0",
70
70
  "@tailwindcss/vite": "^4.2.1",
71
71
  "@tanstack/react-query": "^5.83.0",
@@ -91,6 +91,7 @@
91
91
  "typescript": "^5.8.3",
92
92
  "typescript-eslint": "^8.56.1",
93
93
  "vite": "^7.3.1",
94
- "vite-tsconfig-paths": "^6.0.2"
94
+ "vite-tsconfig-paths": "^6.0.2",
95
+ "vitest": "5.0.3"
95
96
  }
96
97
  }
@@ -1,23 +0,0 @@
1
- import { type LayoutLogoRow, type LayoutRef, type ResolvedLayout } from "./layoutTypes";
2
- /** Vraagt de actieve layout voor een documentsoort op bij de Logistiek Engine. */
3
- export declare function fetchLayoutRef(documentType: string): Promise<LayoutRef | null>;
4
- /** Haalt de layoutrij plus elementen, variabelen en logo's op. */
5
- export declare function fetchLayout(layoutId: string, documentType: string): Promise<ResolvedLayout>;
6
- /**
7
- * Bepaalt en laadt de layout voor een documentsoort. Gebruikt bij voorkeur de
8
- * layoutId die de Engine in de wachtrijregel heeft meegegeven.
9
- */
10
- export declare function resolveLayout(args: {
11
- documentType: string;
12
- layoutId?: string | null;
13
- }): Promise<ResolvedLayout>;
14
- /**
15
- * Zet de logo-records uit de layout om in de vorm die de layout-module
16
- * verwacht: een publiek bereikbare `viewUrl` per logo.
17
- */
18
- export declare function logosMetViewUrl(logos: Record<string, LayoutLogoRow>): Promise<{
19
- id: string;
20
- naam: string;
21
- viewUrl: string | null;
22
- }[]>;
23
- //# sourceMappingURL=layoutApi.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"layoutApi.d.ts","sourceRoot":"","sources":["../../src/lib/layoutApi.ts"],"names":[],"mappings":"AAIA,OAAO,EAKL,KAAK,aAAa,EAClB,KAAK,SAAS,EACd,KAAK,cAAc,EACpB,MAAM,eAAe,CAAC;AAEvB,kFAAkF;AAClF,wBAAsB,cAAc,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAOpF;AAED,kEAAkE;AAClE,wBAAsB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAmBjG;AAED;;;GAGG;AACH,wBAAsB,aAAa,CAAC,IAAI,EAAE;IACxC,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B,GAAG,OAAO,CAAC,cAAc,CAAC,CAS1B;AAID;;;GAGG;AACH,wBAAsB,eAAe,CACnC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,GACnC,OAAO,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,EAAE,CAAC,CAgCjE"}
@@ -1,94 +0,0 @@
1
- // Leest documentlayouts uit de gedeelde database. De module bepaalt zelf nooit
2
- // welke layout bij een documentsoort hoort: dat doet logistics_document_layout.
3
- import { pickDb } from "./pickApi";
4
- import { safeArray } from "./pickTypes";
5
- import { MissingLayoutError, } from "./layoutTypes";
6
- /** Vraagt de actieve layout voor een documentsoort op bij de Logistiek Engine. */
7
- export async function fetchLayoutRef(documentType) {
8
- const { data, error } = await pickDb.rpc("logistics_document_layout", {
9
- _document_code: documentType,
10
- });
11
- if (error)
12
- throw new Error(error.message);
13
- const ref = data;
14
- return ref && ref.layoutId ? ref : null;
15
- }
16
- /** Haalt de layoutrij plus elementen, variabelen en logo's op. */
17
- export async function fetchLayout(layoutId, documentType) {
18
- // Het pickscherm is openbaar. Lees daarom via de beperkte SECURITY DEFINER
19
- // functie in plaats van rechtstreeks door de RLS van de Layout maker heen.
20
- const { data, error } = await pickDb.rpc("pick_document_layout_data", {
21
- _layout_id: layoutId,
22
- });
23
- if (error)
24
- throw new Error(error.message);
25
- const bundle = data && typeof data === "object" && !Array.isArray(data)
26
- ? data
27
- : {};
28
- const layout = bundle["layout"];
29
- if (!layout || layout.actief === false)
30
- throw new MissingLayoutError(documentType);
31
- const elements = safeArray(bundle["elements"]);
32
- const variables = safeArray(bundle["variables"]);
33
- const logos = {};
34
- for (const logo of safeArray(bundle["logos"]))
35
- logos[logo.id] = logo;
36
- return { layout, elements, variables, logos };
37
- }
38
- /**
39
- * Bepaalt en laadt de layout voor een documentsoort. Gebruikt bij voorkeur de
40
- * layoutId die de Engine in de wachtrijregel heeft meegegeven.
41
- */
42
- export async function resolveLayout(args) {
43
- const documentType = args.documentType || "pakbon";
44
- let layoutId = args.layoutId ?? null;
45
- if (!layoutId) {
46
- const ref = await fetchLayoutRef(documentType);
47
- if (!ref)
48
- throw new MissingLayoutError(documentType);
49
- layoutId = ref.layoutId;
50
- }
51
- return fetchLayout(layoutId, documentType);
52
- }
53
- const LOGO_BUCKET = "layout-logos";
54
- /**
55
- * Zet de logo-records uit de layout om in de vorm die de layout-module
56
- * verwacht: een publiek bereikbare `viewUrl` per logo.
57
- */
58
- export async function logosMetViewUrl(logos) {
59
- const rijen = Object.values(logos ?? {});
60
- if (!rijen.length)
61
- return [];
62
- const storage = pickDb.storage;
63
- const paden = rijen.map((l) => l.bestandspad ?? l.bestand_url).filter(Boolean);
64
- const map = new Map();
65
- if (storage && paden.length) {
66
- try {
67
- const { data } = await storage.from(LOGO_BUCKET).createSignedUrls(paden, 60 * 60);
68
- for (const r of safeArray(data)) {
69
- if (r.path && r.signedUrl)
70
- map.set(r.path, r.signedUrl);
71
- }
72
- }
73
- catch {
74
- // geen leesrechten op ondertekende URL's: hieronder valt de publieke URL in
75
- }
76
- for (const pad of paden) {
77
- if (map.has(pad))
78
- continue;
79
- try {
80
- const { data } = storage.from(LOGO_BUCKET).getPublicUrl(pad);
81
- if (data?.publicUrl)
82
- map.set(pad, data.publicUrl);
83
- }
84
- catch {
85
- // logo blijft leeg
86
- }
87
- }
88
- }
89
- return rijen.map((l) => {
90
- const pad = l.bestandspad ?? l.bestand_url ?? "";
91
- const url = map.get(pad) ?? (/^https?:\/\//.test(pad) ? pad : null);
92
- return { id: l.id, naam: l.naam, viewUrl: url };
93
- });
94
- }
@@ -1,50 +0,0 @@
1
- import type { PapierFormaatDef } from "./documentTypes";
2
- export type InstellingType = "schakelaar" | "keuze" | "meerkeuze" | "tekst" | "getal" | "kleur";
3
- export interface InstellingDef {
4
- key: string;
5
- label: string;
6
- type: InstellingType;
7
- hint?: string;
8
- /** opties voor keuze / meerkeuze */
9
- opties?: {
10
- value: string;
11
- label: string;
12
- }[];
13
- standaard?: unknown;
14
- }
15
- export interface InstellingGroep {
16
- key: string;
17
- label: string;
18
- omschrijving?: string;
19
- instellingen: InstellingDef[];
20
- }
21
- export interface DocumentProfiel {
22
- /** komt overeen met document_layouts.documenttype */
23
- id: string;
24
- label: string;
25
- omschrijving: string;
26
- /** getoond in stap 1 van de wizard */
27
- primair?: boolean;
28
- /** formaten die bij dit documenttype horen */
29
- formaten: PapierFormaatDef[];
30
- standaardFormaat: string;
31
- standaardOrientatie: "portrait" | "landscape";
32
- /** entiteiten uit het veldregister die relevant zijn */
33
- entiteiten: string[];
34
- /** extra aanwijzing voor de AI-layoutimport */
35
- aiHint: string;
36
- /** kan per formaat een standaardprinter krijgen */
37
- printerPerFormaat?: boolean;
38
- groepen: InstellingGroep[];
39
- }
40
- export declare const STICKER_FORMATEN: PapierFormaatDef[];
41
- export declare const VERZENDLABEL_FORMATEN: PapierFormaatDef[];
42
- export declare const DOCUMENT_PROFIELEN: DocumentProfiel[];
43
- export declare function documentProfiel(id: string): DocumentProfiel;
44
- export declare function primaireProfielen(): DocumentProfiel[];
45
- export type DocumentConfig = Record<string, Record<string, unknown>>;
46
- /** Standaardwaarden van een profiel als opslagbaar configuratieobject. */
47
- export declare function standaardConfig(profiel: DocumentProfiel): DocumentConfig;
48
- /** Waarde uit de opgeslagen config, met terugval op de profielstandaard. */
49
- export declare function configWaarde(config: DocumentConfig | null | undefined, groep: InstellingGroep, inst: InstellingDef): unknown;
50
- //# sourceMappingURL=documentProfiles.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"documentProfiles.d.ts","sourceRoot":"","sources":["../../../src/lib/layoutMaker/documentProfiles.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAExD,MAAM,MAAM,cAAc,GAAG,YAAY,GAAG,OAAO,GAAG,WAAW,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,CAAC;AAEhG,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,cAAc,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,oCAAoC;IACpC,MAAM,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC5C,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,aAAa,EAAE,CAAC;CAC/B;AAED,MAAM,WAAW,eAAe;IAC9B,qDAAqD;IACrD,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;IACrB,sCAAsC;IACtC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,8CAA8C;IAC9C,QAAQ,EAAE,gBAAgB,EAAE,CAAC;IAC7B,gBAAgB,EAAE,MAAM,CAAC;IACzB,mBAAmB,EAAE,UAAU,GAAG,WAAW,CAAC;IAC9C,wDAAwD;IACxD,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,+CAA+C;IAC/C,MAAM,EAAE,MAAM,CAAC;IACf,mDAAmD;IACnD,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,OAAO,EAAE,eAAe,EAAE,CAAC;CAC5B;AAyBD,eAAO,MAAM,gBAAgB,EAAE,gBAAgB,EAO9C,CAAC;AAEF,eAAO,MAAM,qBAAqB,EAAE,gBAAgB,EAOnD,CAAC;AA4YF,eAAO,MAAM,kBAAkB,EAAE,eAAe,EAe/C,CAAC;AAEF,wBAAgB,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,eAAe,CAK3D;AAED,wBAAgB,iBAAiB,IAAI,eAAe,EAAE,CAErD;AAED,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;AAErE,0EAA0E;AAC1E,wBAAgB,eAAe,CAAC,OAAO,EAAE,eAAe,GAAG,cAAc,CAUxE;AAED,4EAA4E;AAC5E,wBAAgB,YAAY,CAC1B,MAAM,EAAE,cAAc,GAAG,IAAI,GAAG,SAAS,EACzC,KAAK,EAAE,eAAe,EACtB,IAAI,EAAE,aAAa,GAClB,OAAO,CAIT"}