@flowselections/floriday-authenticatie-module 1.0.88 → 1.0.91

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 (35) hide show
  1. package/dist-lib/components/floriday/FlorydayConnectionPage.d.ts.map +1 -1
  2. package/dist-lib/components/floriday/FlorydayConnectionPage.js +2 -1
  3. package/dist-lib/components/settings/FloricodeHealthBanner.d.ts +5 -0
  4. package/dist-lib/components/settings/FloricodeHealthBanner.d.ts.map +1 -0
  5. package/dist-lib/components/settings/FloricodeHealthBanner.js +27 -0
  6. package/dist-lib/components/settings/FloricodeSettingsCard.d.ts.map +1 -1
  7. package/dist-lib/components/settings/FloricodeSettingsCard.js +17 -2
  8. package/dist-lib/index.d.ts +1 -0
  9. package/dist-lib/index.d.ts.map +1 -1
  10. package/dist-lib/index.js +1 -0
  11. package/dist-lib/integrations/supabase/types.d.ts +419 -0
  12. package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
  13. package/dist-lib/lib/cron/sync-floricode-all.d.ts.map +1 -1
  14. package/dist-lib/lib/cron/sync-floricode-all.js +0 -2
  15. package/dist-lib/lib/customer-sticker-fields.d.ts +5 -0
  16. package/dist-lib/lib/customer-sticker-fields.d.ts.map +1 -1
  17. package/dist-lib/lib/customer-sticker-fields.js +7 -0
  18. package/dist-lib/lib/floricode-regulatory-features.d.ts +1 -0
  19. package/dist-lib/lib/floricode-regulatory-features.d.ts.map +1 -1
  20. package/dist-lib/lib/floricode-regulatory-features.js +27 -12
  21. package/dist-lib/lib/floricode-sync-plan.d.ts +64 -0
  22. package/dist-lib/lib/floricode-sync-plan.d.ts.map +1 -0
  23. package/dist-lib/lib/floricode-sync-plan.js +54 -0
  24. package/dist-lib/lib/floricode-sync.server.d.ts +39 -7
  25. package/dist-lib/lib/floricode-sync.server.d.ts.map +1 -1
  26. package/dist-lib/lib/floricode-sync.server.js +131 -86
  27. package/dist-lib/lib/floricode.functions.d.ts +14 -0
  28. package/dist-lib/lib/floricode.functions.d.ts.map +1 -1
  29. package/dist-lib/lib/floricode.functions.js +26 -9
  30. package/dist-lib/lib/floriday-stickers.functions.js +2 -2
  31. package/dist-lib/lib/gateway/webhook-subscribe.d.ts.map +1 -1
  32. package/dist-lib/lib/gateway/webhook-subscribe.js +11 -1
  33. package/dist-lib/lib/module-version.d.ts +1 -1
  34. package/dist-lib/lib/module-version.js +1 -1
  35. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"sync-floricode-all.d.ts","sourceRoot":"","sources":["../../../src/lib/cron/sync-floricode-all.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAG5D,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,cAAc,GACvB,OAAO,CAAC,QAAQ,CAAC,CAuBnB"}
1
+ {"version":3,"file":"sync-floricode-all.d.ts","sourceRoot":"","sources":["../../../src/lib/cron/sync-floricode-all.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAG5D,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,cAAc,GACvB,OAAO,CAAC,QAAQ,CAAC,CAqBnB"}
@@ -10,11 +10,9 @@ export async function handleSyncFloricodeAll(request, supabase) {
10
10
  return await withJobLock(supabase, "floricode-sync:all", async () => {
11
11
  const url = new URL(request.url);
12
12
  const batchSize = Number(url.searchParams.get("batchSize") ?? "5000");
13
- const maxBatches = Number(url.searchParams.get("maxBatchesPerResource") ?? "2");
14
13
  const { syncAllFloricodeResources } = await import("../floricode-sync.server.js");
15
14
  const result = await syncAllFloricodeResources({
16
15
  batchSize: Number.isFinite(batchSize) ? batchSize : 5000,
17
- maxBatchesPerResource: Number.isFinite(maxBatches) ? maxBatches : 2,
18
16
  });
19
17
  return Response.json(result);
20
18
  });
@@ -5,4 +5,9 @@ export interface CustomerStickerFields {
5
5
  should_be_printed: boolean | null;
6
6
  }
7
7
  export declare function customerStickerFields(item: any): CustomerStickerFields;
8
+ /**
9
+ * Pad voor GET /customer-stickers/{stickerId}. `duplicatePagesBasedOnNumberOfCopies`
10
+ * is verplicht in 2026v1; altijd false — de Logistiek Engine print het aantal zelf.
11
+ */
12
+ export declare function customerStickerPdfPath(apiVersion: string, stickerId: string): string;
8
13
  //# sourceMappingURL=customer-sticker-fields.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"customer-sticker-fields.d.ts","sourceRoot":"","sources":["../../src/lib/customer-sticker-fields.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,qBAAqB;IACpC,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,iBAAiB,EAAE,OAAO,GAAG,IAAI,CAAC;CACnC;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,GAAG,GAAG,qBAAqB,CAStE"}
1
+ {"version":3,"file":"customer-sticker-fields.d.ts","sourceRoot":"","sources":["../../src/lib/customer-sticker-fields.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,qBAAqB;IACpC,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,iBAAiB,EAAE,OAAO,GAAG,IAAI,CAAC;CACnC;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,GAAG,GAAG,qBAAqB,CAStE;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAEpF"}
@@ -14,3 +14,10 @@ export function customerStickerFields(item) {
14
14
  should_be_printed: typeof spb === "boolean" ? spb : null,
15
15
  };
16
16
  }
17
+ /**
18
+ * Pad voor GET /customer-stickers/{stickerId}. `duplicatePagesBasedOnNumberOfCopies`
19
+ * is verplicht in 2026v1; altijd false — de Logistiek Engine print het aantal zelf.
20
+ */
21
+ export function customerStickerPdfPath(apiVersion, stickerId) {
22
+ return `/${apiVersion}/customer-stickers/${encodeURIComponent(stickerId)}?duplicatePagesBasedOnNumberOfCopies=false`;
23
+ }
@@ -29,6 +29,7 @@ export declare function syncFloricodeRegulatoryFeatures(supabase: SupabaseClient
29
29
  batchSize?: number;
30
30
  maxBatches?: number;
31
31
  resume?: boolean;
32
+ deadline?: number;
32
33
  }): Promise<{
33
34
  ok: true;
34
35
  resource: string;
@@ -1 +1 @@
1
- {"version":3,"file":"floricode-regulatory-features.d.ts","sourceRoot":"","sources":["../../src/lib/floricode-regulatory-features.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAY5D,UAAU,cAAc;IACtB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,EAAE,MAAM,GAAG,MAAM,CAAC;IAC5B,eAAe,EAAE,MAAM,CAAC;IACxB,kBAAkB,EAAE,MAAM,GAAG,MAAM,CAAC;IACpC,kBAAkB,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IAC5C,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAClC;AAED,UAAU,cAAc;IACtB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAClC;AAYD,wBAAsB,0CAA0C,CAC9D,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,cAAc,EAAE,CAAC,CAgB3B;AAiDD,wBAAsB,8BAA8B,CAClD,QAAQ,EAAE,cAAc,EACxB,KAAK,EAAE,cAAc,EAAE,GACtB,OAAO,CAAC,MAAM,CAAC,CAqBjB;AAED,wBAAsB,2BAA2B,CAC/C,QAAQ,EAAE,cAAc,EACxB,KAAK,EAAE,cAAc,EAAE,GACtB,OAAO,CAAC,MAAM,CAAC,CAqBjB;AAiBD,wBAAsB,4BAA4B,CAAC,QAAQ,EAAE,cAAc;;;;;;GA2B1E;AAED,wBAAsB,+BAA+B,CACnD,QAAQ,EAAE,cAAc,EACxB,OAAO,GAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAAO;;;;;;;;;;;;;;;;;;;;;;GAoK5E"}
1
+ {"version":3,"file":"floricode-regulatory-features.d.ts","sourceRoot":"","sources":["../../src/lib/floricode-regulatory-features.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAa5D,UAAU,cAAc;IACtB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,EAAE,MAAM,GAAG,MAAM,CAAC;IAC5B,eAAe,EAAE,MAAM,CAAC;IACxB,kBAAkB,EAAE,MAAM,GAAG,MAAM,CAAC;IACpC,kBAAkB,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IAC5C,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAClC;AAED,UAAU,cAAc;IACtB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAClC;AAYD,wBAAsB,0CAA0C,CAC9D,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,cAAc,EAAE,CAAC,CAgB3B;AAiDD,wBAAsB,8BAA8B,CAClD,QAAQ,EAAE,cAAc,EACxB,KAAK,EAAE,cAAc,EAAE,GACtB,OAAO,CAAC,MAAM,CAAC,CAqBjB;AAED,wBAAsB,2BAA2B,CAC/C,QAAQ,EAAE,cAAc,EACxB,KAAK,EAAE,cAAc,EAAE,GACtB,OAAO,CAAC,MAAM,CAAC,CAqBjB;AAiBD,wBAAsB,4BAA4B,CAAC,QAAQ,EAAE,cAAc;;;;;;GA6B1E;AAED,wBAAsB,+BAA+B,CACnD,QAAQ,EAAE,cAAc,EACxB,OAAO,GAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAO;;;;;;;;;;;;;;;;;;;;;;GAgL/F"}
@@ -1,4 +1,5 @@
1
1
  import { getFloricodeAccessToken } from "./floricode-credentials.server.js";
2
+ import { FLORICODE_ROUND_BUDGET_MS, laterIso, stateAfterPage } from "./floricode-sync-plan.js";
2
3
  const REG_FEATURE_TYPE_URL = "https://api.floricode.com/v2/VBN/RegulatoryFeatureType";
3
4
  const REGULATION_TYPE_URL = "https://api.floricode.com/v2/VBN/RegulationType";
4
5
  const REG_FEATURE_TYPE_RESOURCE = "RegulatoryFeatureType";
@@ -127,6 +128,8 @@ export async function syncFloricodeRegulationTypes(supabase) {
127
128
  error_message: null,
128
129
  last_sequence_number: upserted,
129
130
  last_sync_at: new Date().toISOString(),
131
+ completed_at: new Date().toISOString(),
132
+ total_count: items.length,
130
133
  });
131
134
  return { ok: true, resource: REGULATION_TYPE_RESOURCE, fetched: items.length, upserted, durationMs: Date.now() - startedAt };
132
135
  }
@@ -145,6 +148,9 @@ export async function syncFloricodeRegulatoryFeatures(supabase, options = {}) {
145
148
  const batchSize = Math.min(Math.max(options.batchSize ?? 5000, 1), 5000);
146
149
  const maxBatches = options.maxBatches && options.maxBatches > 0 ? options.maxBatches : Infinity;
147
150
  const resume = options.resume !== false;
151
+ const deadline = options.deadline ?? Date.now() + FLORICODE_ROUND_BUDGET_MS;
152
+ // Datum waarmee een lopende ronde verdergaat; pas bij compleet het nieuwe watermerk.
153
+ let pending = null;
148
154
  // Read cursor from state so we can resume where the previous invocation stopped.
149
155
  let skip = 0;
150
156
  let maxChangeDateTime = null;
@@ -157,14 +163,15 @@ export async function syncFloricodeRegulatoryFeatures(supabase, options = {}) {
157
163
  if (resume) {
158
164
  const { data: state } = await supabase
159
165
  .from("floricode_sync_state")
160
- .select("cursor_skip,last_change_date_time,status")
166
+ .select("cursor_skip,last_change_date_time,pending_change_date_time,status")
161
167
  .eq("resource", REG_FEATURE_TYPE_RESOURCE)
162
168
  .maybeSingle();
163
169
  const s = state;
164
- if (s?.status === "running") {
170
+ if (s?.status === "running" || s?.status === "error") {
165
171
  skip = Number(s.cursor_skip ?? 0) || 0;
166
172
  maxChangeDateTime = s.last_change_date_time ?? null;
167
173
  sinceIso = s.last_change_date_time ?? null;
174
+ pending = s.pending_change_date_time ?? null;
168
175
  }
169
176
  else if (s?.status === "ok" && s.last_change_date_time) {
170
177
  sinceIso = s.last_change_date_time;
@@ -181,12 +188,13 @@ export async function syncFloricodeRegulatoryFeatures(supabase, options = {}) {
181
188
  status: "running",
182
189
  error_message: null,
183
190
  cursor_skip: skip,
184
- last_change_date_time: maxChangeDateTime,
191
+ last_change_date_time: sinceIso,
192
+ pending_change_date_time: pending,
185
193
  last_sync_at: new Date().toISOString(),
186
194
  });
187
195
  try {
188
196
  const token = await getFloricodeToken(REG_FEATURE_TYPE_SCOPE);
189
- while (batches < maxBatches) {
197
+ while (batches < maxBatches && Date.now() < deadline) {
190
198
  const items = await fetchRegFeatureTypePage(token, skip, batchSize, sinceIso);
191
199
  if (items.length === 0) {
192
200
  completed = true;
@@ -194,19 +202,22 @@ export async function syncFloricodeRegulatoryFeatures(supabase, options = {}) {
194
202
  }
195
203
  fetched += items.length;
196
204
  upserted += await upsertRegulatoryFeatureRecords(supabase, items);
197
- for (const item of items) {
198
- const changed = item.change_date_time ?? null;
199
- if (changed && (!maxChangeDateTime || changed > maxChangeDateTime))
200
- maxChangeDateTime = changed;
201
- }
205
+ let pageMax = null;
206
+ for (const item of items)
207
+ pageMax = laterIso(pageMax, item.change_date_time ?? null);
202
208
  batches += 1;
209
+ const next = stateAfterPage({ startWatermark: sinceIso, pending, pageMax, skipBefore: skip, pageSize: items.length, batchSize });
203
210
  skip += items.length;
204
- // Persist cursor after each batch so a crash mid-run resumes correctly.
211
+ pending = next.pending_change_date_time ?? laterIso(pending, pageMax);
212
+ maxChangeDateTime = laterIso(sinceIso, pending);
213
+ // Alleen positie + voorlopige datum; het filter (sinceIso) blijft gelijk
214
+ // tot de bron compleet is — anders sloeg hervatten regels over (lus).
205
215
  await setSyncState(supabase, REG_FEATURE_TYPE_RESOURCE, {
206
216
  status: "running",
207
217
  error_message: null,
208
218
  cursor_skip: skip,
209
- last_change_date_time: maxChangeDateTime,
219
+ last_change_date_time: sinceIso,
220
+ pending_change_date_time: pending,
210
221
  last_sync_at: new Date().toISOString(),
211
222
  });
212
223
  // Lichte per-product projectie: alleen de zojuist geraakte producten
@@ -250,7 +261,10 @@ export async function syncFloricodeRegulatoryFeatures(supabase, options = {}) {
250
261
  cursor_skip: 0,
251
262
  last_sequence_number: skip,
252
263
  last_change_date_time: maxChangeDateTime,
264
+ pending_change_date_time: null,
253
265
  last_sync_at: new Date().toISOString(),
266
+ completed_at: new Date().toISOString(),
267
+ ...(incremental ? {} : { total_count: skip }),
254
268
  });
255
269
  return {
256
270
  ok: true,
@@ -284,7 +298,8 @@ export async function syncFloricodeRegulatoryFeatures(supabase, options = {}) {
284
298
  status: "error",
285
299
  error_message: msg,
286
300
  cursor_skip: skip,
287
- last_change_date_time: maxChangeDateTime,
301
+ last_change_date_time: sinceIso,
302
+ pending_change_date_time: pending,
288
303
  last_sync_at: new Date().toISOString(),
289
304
  });
290
305
  throw e;
@@ -0,0 +1,64 @@
1
+ export declare const FLORICODE_CRON_BUSY = "*/10 * * * *";
2
+ export declare const FLORICODE_CRON_NIGHTLY = "0 2 * * *";
3
+ /** Tijdsbudget per aanroep (Worker); daarna gaat de volgende ronde verder. */
4
+ export declare const FLORICODE_ROUND_BUDGET_MS = 25000;
5
+ export declare const FLORICODE_STALE_MS: number;
6
+ /** Nachtelijke wijzigingenronde: niet vaker dan eens per 20 uur. */
7
+ export declare const FLORICODE_NIGHTLY_MIN_MS: number;
8
+ export declare function laterIso(a: string | null | undefined, b: string | null | undefined): string | null;
9
+ /**
10
+ * Staat na een pagina. De watermerkdatum ("bijgewerkt tot") verschuift alleen
11
+ * als de bron compleet is; tijdens de ronde blijft hij gelijk aan het begin,
12
+ * zodat filter + positie bij hervatten consistent blijven.
13
+ */
14
+ export declare function stateAfterPage(input: {
15
+ startWatermark: string | null;
16
+ pending: string | null;
17
+ pageMax: string | null;
18
+ skipBefore: number;
19
+ pageSize: number;
20
+ batchSize: number;
21
+ }): {
22
+ finished: true;
23
+ status: "ok";
24
+ cursor_skip: number;
25
+ last_change_date_time: string | null;
26
+ pending_change_date_time: null;
27
+ } | {
28
+ finished: false;
29
+ status: "running";
30
+ cursor_skip: number;
31
+ last_change_date_time: string | null;
32
+ pending_change_date_time: string | null;
33
+ };
34
+ export declare function floricodeCronSchedule(anyIncomplete: boolean): string;
35
+ export declare function isIncomplete(status: string | null | undefined): boolean;
36
+ export declare function nightlyDue(lastCompletedAt: string | null, now: number): boolean;
37
+ export type FloricodeSourceView = {
38
+ kind: "complete";
39
+ stale: boolean;
40
+ } | {
41
+ kind: "busy";
42
+ done: number;
43
+ total: number | null;
44
+ stale: boolean;
45
+ } | {
46
+ kind: "stalled";
47
+ since: string | null;
48
+ stale: boolean;
49
+ } | {
50
+ kind: "error";
51
+ stale: boolean;
52
+ } | {
53
+ kind: "never";
54
+ stale: boolean;
55
+ };
56
+ /** "Compleet" / "Bezig (x van y)" / "Staat stil sinds …"; stale = ouder dan 7 dagen. */
57
+ export declare function classifyFloricodeSource(row: {
58
+ status: string | null;
59
+ lastSyncAt: string | null;
60
+ completedAt?: string | null;
61
+ rowCount: number;
62
+ totalCount?: number | null;
63
+ }, now: number): FloricodeSourceView;
64
+ //# sourceMappingURL=floricode-sync-plan.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"floricode-sync-plan.d.ts","sourceRoot":"","sources":["../../src/lib/floricode-sync-plan.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,mBAAmB,iBAAiB,CAAC;AAClD,eAAO,MAAM,sBAAsB,cAAc,CAAC;AAClD,8EAA8E;AAC9E,eAAO,MAAM,yBAAyB,QAAS,CAAC;AAChD,eAAO,MAAM,kBAAkB,QAAuB,CAAC;AACvD,oEAAoE;AACpE,eAAO,MAAM,wBAAwB,QAAmB,CAAC;AAEzD,wBAAgB,QAAQ,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAIlG;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE;IACpC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB;;;;;;;;;;;;EAOA;AAED,wBAAgB,qBAAqB,CAAC,aAAa,EAAE,OAAO,GAAG,MAAM,CAEpE;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAEvE;AAED,wBAAgB,UAAU,CAAC,eAAe,EAAE,MAAM,GAAG,IAAI,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAG/E;AAED,MAAM,MAAM,mBAAmB,GAC3B;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,GACpC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,GACpE;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,GACzD;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,GACjC;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,CAAC;AAEtC,wFAAwF;AACxF,wBAAgB,uBAAuB,CAAC,GAAG,EAAE;IAC3C,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B,EAAE,GAAG,EAAE,MAAM,GAAG,mBAAmB,CASnC"}
@@ -0,0 +1,54 @@
1
+ // Pure beslisregels voor de Floricode-ronde (testbaar, geen I/O).
2
+ export const FLORICODE_CRON_BUSY = "*/10 * * * *";
3
+ export const FLORICODE_CRON_NIGHTLY = "0 2 * * *";
4
+ /** Tijdsbudget per aanroep (Worker); daarna gaat de volgende ronde verder. */
5
+ export const FLORICODE_ROUND_BUDGET_MS = 25000;
6
+ export const FLORICODE_STALE_MS = 7 * 24 * 60 * 60000;
7
+ /** Nachtelijke wijzigingenronde: niet vaker dan eens per 20 uur. */
8
+ export const FLORICODE_NIGHTLY_MIN_MS = 20 * 60 * 60000;
9
+ export function laterIso(a, b) {
10
+ if (!a)
11
+ return b ?? null;
12
+ if (!b)
13
+ return a;
14
+ return new Date(b).getTime() > new Date(a).getTime() ? b : a;
15
+ }
16
+ /**
17
+ * Staat na een pagina. De watermerkdatum ("bijgewerkt tot") verschuift alleen
18
+ * als de bron compleet is; tijdens de ronde blijft hij gelijk aan het begin,
19
+ * zodat filter + positie bij hervatten consistent blijven.
20
+ */
21
+ export function stateAfterPage(input) {
22
+ const pending = laterIso(input.pending, input.pageMax);
23
+ const skip = input.skipBefore + input.pageSize;
24
+ const finished = input.pageSize < input.batchSize;
25
+ return finished
26
+ ? { finished, status: "ok", cursor_skip: 0, last_change_date_time: laterIso(input.startWatermark, pending), pending_change_date_time: null }
27
+ : { finished, status: "running", cursor_skip: skip, last_change_date_time: input.startWatermark, pending_change_date_time: pending };
28
+ }
29
+ export function floricodeCronSchedule(anyIncomplete) {
30
+ return anyIncomplete ? FLORICODE_CRON_BUSY : FLORICODE_CRON_NIGHTLY;
31
+ }
32
+ export function isIncomplete(status) {
33
+ return status !== "ok" && status !== "success";
34
+ }
35
+ export function nightlyDue(lastCompletedAt, now) {
36
+ if (!lastCompletedAt)
37
+ return true;
38
+ return now - new Date(lastCompletedAt).getTime() >= FLORICODE_NIGHTLY_MIN_MS;
39
+ }
40
+ /** "Compleet" / "Bezig (x van y)" / "Staat stil sinds …"; stale = ouder dan 7 dagen. */
41
+ export function classifyFloricodeSource(row, now) {
42
+ const ref = row.completedAt ?? row.lastSyncAt;
43
+ const stale = !ref || now - new Date(ref).getTime() > FLORICODE_STALE_MS;
44
+ if (!row.lastSyncAt && !row.status)
45
+ return { kind: "never", stale: true };
46
+ if (row.status === "error")
47
+ return { kind: "error", stale };
48
+ if (!isIncomplete(row.status))
49
+ return { kind: "complete", stale };
50
+ const idle = !row.lastSyncAt || now - new Date(row.lastSyncAt).getTime() > 60 * 60000;
51
+ if (idle)
52
+ return { kind: "stalled", since: row.lastSyncAt, stale };
53
+ return { kind: "busy", done: row.rowCount, total: row.totalCount ?? null, stale };
54
+ }
@@ -16,20 +16,52 @@ export interface FloricodeSyncResult {
16
16
  nextWatermark: string | null;
17
17
  durationMs: number;
18
18
  }
19
+ /**
20
+ * Haalt pagina's op tot de bron compleet is of het tijdsbudget op is.
21
+ * Positie (cursor_skip) gaat alleen vooruit na een opgeslagen pagina; de
22
+ * watermerkdatum verschuift pas als de bron compleet is (zie stateAfterPage).
23
+ */
19
24
  export declare function syncFloricodeResource(resource: string, opts?: {
20
25
  batchSize?: number;
21
26
  maxBatches?: number;
22
27
  resume?: boolean;
28
+ deadline?: number;
23
29
  }): Promise<FloricodeSyncResult>;
24
- export declare function syncAllFloricodeResources(opts: {
30
+ type AllResult = FloricodeSyncResult | {
31
+ resource: string;
32
+ ok: false;
33
+ error: string;
34
+ } | {
35
+ resource: string;
36
+ ok: true;
37
+ skipped: true;
38
+ };
39
+ /**
40
+ * Eén cron-tik: eerst onvolledige bronnen afmaken binnen het tijdsbudget;
41
+ * zijn alle bronnen compleet, dan hooguit eens per 20 uur alleen wijzigingen.
42
+ * Stelt daarna het cron-schema in (elke 10 min zolang iets bezig is, anders 's nachts).
43
+ */
44
+ export declare function syncAllFloricodeResources(opts?: {
25
45
  batchSize?: number;
26
- maxBatchesPerResource?: number;
46
+ budgetMs?: number;
27
47
  }): Promise<{
28
48
  ok: true;
29
- results: Array<FloricodeSyncResult | {
30
- resource: string;
31
- ok: false;
32
- error: string;
33
- }>;
49
+ results: AllResult[];
50
+ incomplete: string[];
51
+ schedule: string | null;
52
+ }>;
53
+ /**
54
+ * Plant de Floricode-ronde in als die nog niet bestaat (uurlijks aangeroepen).
55
+ * Adres via resolveVerifiedFlorydayCronUrl; ontbreekt het Shell-adres, dan
56
+ * niet inplannen (fail closed) — de stilstand-melding wordt daar vastgelegd.
57
+ */
58
+ export declare function ensureFloricodeSyncCron(opts?: {
59
+ force?: boolean;
60
+ }): Promise<{
61
+ ok: boolean;
62
+ scheduled: boolean;
63
+ schedule: string | null;
64
+ error?: string;
34
65
  }>;
66
+ export {};
35
67
  //# sourceMappingURL=floricode-sync.server.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"floricode-sync.server.d.ts","sourceRoot":"","sources":["../../src/lib/floricode-sync.server.ts"],"names":[],"mappings":"AAiBA,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,4EAA4E;IAC5E,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,eAAO,MAAM,mBAAmB,EAAE,oBAAoB,EAkBrD,CAAC;AA6EF,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,IAAI,CAAC;IACT,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,OAAO,CAAC;IAClB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,wBAAsB,qBAAqB,CACzC,QAAQ,EAAE,MAAM,EAChB,IAAI,GAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAAO,GACvE,OAAO,CAAC,mBAAmB,CAAC,CAmH9B;AAED,wBAAsB,yBAAyB,CAAC,IAAI,EAAE;IACpD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,qBAAqB,CAAC,EAAE,MAAM,CAAC;CAChC,GAAG,OAAO,CAAC;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,OAAO,EAAE,KAAK,CAAC,mBAAmB,GAAG;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,KAAK,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE,CAAC,CAc9G"}
1
+ {"version":3,"file":"floricode-sync.server.d.ts","sourceRoot":"","sources":["../../src/lib/floricode-sync.server.ts"],"names":[],"mappings":"AAyBA,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,4EAA4E;IAC5E,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,eAAO,MAAM,mBAAmB,EAAE,oBAAoB,EAkBrD,CAAC;AAoFF,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,IAAI,CAAC;IACT,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,OAAO,CAAC;IAClB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;;GAIG;AACH,wBAAsB,qBAAqB,CACzC,QAAQ,EAAE,MAAM,EAChB,IAAI,GAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAO,GAC1F,OAAO,CAAC,mBAAmB,CAAC,CAuE9B;AAED,KAAK,SAAS,GAAG,mBAAmB,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,IAAI,CAAC;IAAC,OAAO,EAAE,IAAI,CAAA;CAAE,CAAC;AAEtI;;;;GAIG;AACH,wBAAsB,yBAAyB,CAAC,IAAI,GAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAO,GAAG,OAAO,CAAC;IAC7G,EAAE,EAAE,IAAI,CAAC;IAAC,OAAO,EAAE,SAAS,EAAE,CAAC;IAAC,UAAU,EAAE,MAAM,EAAE,CAAC;IAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/E,CAAC,CAuCD;AAED;;;;GAIG;AACH,wBAAsB,uBAAuB,CAAC,IAAI,GAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,OAAO,CAAC;IACrF,EAAE,EAAE,OAAO,CAAC;IAAC,SAAS,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CAC1E,CAAC,CAkBD"}