@flowselections/floriday-authenticatie-module 1.0.68 → 1.0.72
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist-lib/integrations/supabase/types.d.ts +151 -0
- package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
- package/dist-lib/lib/floriday-order-stage.d.ts +13 -2
- package/dist-lib/lib/floriday-order-stage.d.ts.map +1 -1
- package/dist-lib/lib/floriday-order-stage.js +16 -3
- package/dist-lib/lib/floriday-sync.functions.d.ts +64 -0
- package/dist-lib/lib/floriday-sync.functions.d.ts.map +1 -1
- package/dist-lib/lib/floriday-sync.functions.js +19 -0
- package/dist-lib/lib/floriday.functions.d.ts +7 -0
- package/dist-lib/lib/floriday.functions.d.ts.map +1 -1
- package/dist-lib/lib/floriday.functions.js +9 -1
- package/dist-lib/lib/gateway/fulfillment-order-body.d.ts +3 -0
- package/dist-lib/lib/gateway/fulfillment-order-body.d.ts.map +1 -1
- package/dist-lib/lib/gateway/fulfillment-order-body.js +32 -6
- package/dist-lib/lib/gateway/fulfillment-order-send.d.ts.map +1 -1
- package/dist-lib/lib/gateway/fulfillment-order-send.js +7 -0
- package/dist-lib/lib/gateway/fulfillment-order-status.d.ts +10 -4
- package/dist-lib/lib/gateway/fulfillment-order-status.d.ts.map +1 -1
- package/dist-lib/lib/gateway/fulfillment-order-status.js +195 -68
- package/dist-lib/lib/gateway/load-carrier-checks.d.ts +54 -0
- package/dist-lib/lib/gateway/load-carrier-checks.d.ts.map +1 -0
- package/dist-lib/lib/gateway/load-carrier-checks.js +72 -0
- package/dist-lib/lib/module-version.d.ts +2 -0
- package/dist-lib/lib/module-version.d.ts.map +1 -0
- package/dist-lib/lib/module-version.js +3 -0
- package/dist-lib/lib/status-overview.d.ts +77 -0
- package/dist-lib/lib/status-overview.d.ts.map +1 -0
- package/dist-lib/lib/status-overview.js +141 -0
- package/package.json +1 -1
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
export declare const MAX_SALES_ORDER_IDS = 100;
|
|
2
|
+
/** Grenzen voor één verzoek in de Shell (Cloudflare Worker). */
|
|
3
|
+
export declare const REFRESH_LIMITS: {
|
|
4
|
+
/** Totale tijd voor alle inhaalrondes binnen één verzoek. */
|
|
5
|
+
readonly timeoutMs: 8000;
|
|
6
|
+
/** Pagina's per bron per ronde (Floriday levert max 1000 per pagina). */
|
|
7
|
+
readonly maxBatches: 3;
|
|
8
|
+
/** Minimale tijd tussen twee rondes per bron. */
|
|
9
|
+
readonly cooldownMs: 60000;
|
|
10
|
+
/** Lokaal geldt als actueel als de laatste volledige sync jonger is dan dit (cron elke 5 min, 2x marge). */
|
|
11
|
+
readonly freshMs: number;
|
|
12
|
+
/** Lock-duur in de database; ruim boven timeoutMs zodat een afgebroken worker de lock vanzelf vrijgeeft. */
|
|
13
|
+
readonly lockTtlSeconds: 30;
|
|
14
|
+
/** Wachtinterval voor een tweede aanroep terwijl een ronde loopt. */
|
|
15
|
+
readonly pollMs: 500;
|
|
16
|
+
};
|
|
17
|
+
export type RefreshMode = "auto" | "never";
|
|
18
|
+
export type StatusRequest = {
|
|
19
|
+
kind: "overview";
|
|
20
|
+
salesOrderIds: string[];
|
|
21
|
+
fulfillmentOrderIds: string[] | null;
|
|
22
|
+
refresh: RefreshMode;
|
|
23
|
+
environment?: "staging" | "live";
|
|
24
|
+
} | {
|
|
25
|
+
kind: "single";
|
|
26
|
+
fulfillmentOrderId: string;
|
|
27
|
+
environment?: "staging" | "live";
|
|
28
|
+
};
|
|
29
|
+
export type ParseResult = {
|
|
30
|
+
ok: true;
|
|
31
|
+
value: StatusRequest;
|
|
32
|
+
} | {
|
|
33
|
+
ok: false;
|
|
34
|
+
errors: string[];
|
|
35
|
+
};
|
|
36
|
+
export declare function parseStatusRequest(body: any): ParseResult;
|
|
37
|
+
export type RefreshSource = "sales-orders" | "delivery-orders" | "fulfillment-orders";
|
|
38
|
+
export interface SourceState {
|
|
39
|
+
lastSyncedAt: number | null;
|
|
40
|
+
lastSuccessAt: number | null;
|
|
41
|
+
}
|
|
42
|
+
export interface RefreshDeps {
|
|
43
|
+
now: () => number;
|
|
44
|
+
sleep: (ms: number) => Promise<void>;
|
|
45
|
+
readState: (source: RefreshSource) => Promise<SourceState>;
|
|
46
|
+
tryLock: (source: RefreshSource) => Promise<boolean>;
|
|
47
|
+
unlock: (source: RefreshSource) => Promise<void>;
|
|
48
|
+
/** Voert de begrensde sync uit; moet zelf stoppen bij deadlineMs. */
|
|
49
|
+
runSync: (source: RefreshSource, deadlineMs: number) => Promise<{
|
|
50
|
+
synced: number;
|
|
51
|
+
partial?: boolean;
|
|
52
|
+
}>;
|
|
53
|
+
}
|
|
54
|
+
export type SkipReason = "fresh" | "cooldown" | "in_progress" | "disabled" | "deadline";
|
|
55
|
+
export interface SourceRefreshReport {
|
|
56
|
+
source: RefreshSource;
|
|
57
|
+
attempted: boolean;
|
|
58
|
+
skippedReason: SkipReason | null;
|
|
59
|
+
timedOut: boolean;
|
|
60
|
+
durationMs: number;
|
|
61
|
+
synced: number;
|
|
62
|
+
error: string | null;
|
|
63
|
+
}
|
|
64
|
+
export declare function decideRefresh(state: SourceState, now: number, needed: boolean): {
|
|
65
|
+
run: true;
|
|
66
|
+
} | {
|
|
67
|
+
run: false;
|
|
68
|
+
reason: SkipReason;
|
|
69
|
+
};
|
|
70
|
+
/**
|
|
71
|
+
* Eén bron bijwerken binnen de deadline. Maar één ronde tegelijk per bron
|
|
72
|
+
* (database-lock, gedeeld met de cron). Een tweede aanroep wacht tot de
|
|
73
|
+
* lopende ronde klaar is of de deadline verstrijkt, en leest daarna lokaal.
|
|
74
|
+
* Gooit nooit: fouten komen in het rapport.
|
|
75
|
+
*/
|
|
76
|
+
export declare function refreshSource(deps: RefreshDeps, source: RefreshSource, needed: boolean, deadlineMs: number): Promise<SourceRefreshReport>;
|
|
77
|
+
//# sourceMappingURL=status-overview.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status-overview.d.ts","sourceRoot":"","sources":["../../src/lib/status-overview.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,mBAAmB,MAAM,CAAC;AAEvC,gEAAgE;AAChE,eAAO,MAAM,cAAc;IACzB,6DAA6D;;IAE7D,yEAAyE;;IAEzE,iDAAiD;;IAEjD,4GAA4G;;IAE5G,4GAA4G;;IAE5G,qEAAqE;;CAE7D,CAAC;AAEX,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,OAAO,CAAC;AAE3C,MAAM,MAAM,aAAa,GACrB;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,aAAa,EAAE,MAAM,EAAE,CAAC;IAAC,mBAAmB,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IAAC,OAAO,EAAE,WAAW,CAAC;IAAC,WAAW,CAAC,EAAE,SAAS,GAAG,MAAM,CAAA;CAAE,GAC3I;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,kBAAkB,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,SAAS,GAAG,MAAM,CAAA;CAAE,CAAC;AAErF,MAAM,MAAM,WAAW,GAAG;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,aAAa,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC;AAkB/F,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,GAAG,GAAG,WAAW,CAuBzD;AAMD,MAAM,MAAM,aAAa,GAAG,cAAc,GAAG,iBAAiB,GAAG,oBAAoB,CAAC;AAEtF,MAAM,WAAW,WAAW;IAC1B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAED,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,MAAM,CAAC;IAClB,KAAK,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACrC,SAAS,EAAE,CAAC,MAAM,EAAE,aAAa,KAAK,OAAO,CAAC,WAAW,CAAC,CAAC;IAC3D,OAAO,EAAE,CAAC,MAAM,EAAE,aAAa,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACrD,MAAM,EAAE,CAAC,MAAM,EAAE,aAAa,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACjD,qEAAqE;IACrE,OAAO,EAAE,CAAC,MAAM,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;CACxG;AAED,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,UAAU,GAAG,aAAa,GAAG,UAAU,GAAG,UAAU,CAAC;AAExF,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,aAAa,CAAC;IACtB,SAAS,EAAE,OAAO,CAAC;IACnB,aAAa,EAAE,UAAU,GAAG,IAAI,CAAC;IACjC,QAAQ,EAAE,OAAO,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED,wBAAgB,aAAa,CAC3B,KAAK,EAAE,WAAW,EAClB,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,OAAO,GACd;IAAE,GAAG,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,GAAG,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,UAAU,CAAA;CAAE,CAOpD;AAED;;;;;GAKG;AACH,wBAAsB,aAAa,CACjC,IAAI,EAAE,WAAW,EACjB,MAAM,EAAE,aAAa,EACrB,MAAM,EAAE,OAAO,EACf,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,mBAAmB,CAAC,CAqD9B"}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
// Statusoverzicht per verkooporder (fulfillment-order/status met salesOrderIds).
|
|
2
|
+
// Pure helpers: verzoek-controle en de coördinatie van de inhaalronde.
|
|
3
|
+
// Contract: docs/contract-fulfillment-order-status.md
|
|
4
|
+
export const MAX_SALES_ORDER_IDS = 100;
|
|
5
|
+
/** Grenzen voor één verzoek in de Shell (Cloudflare Worker). */
|
|
6
|
+
export const REFRESH_LIMITS = {
|
|
7
|
+
/** Totale tijd voor alle inhaalrondes binnen één verzoek. */
|
|
8
|
+
timeoutMs: 8000,
|
|
9
|
+
/** Pagina's per bron per ronde (Floriday levert max 1000 per pagina). */
|
|
10
|
+
maxBatches: 3,
|
|
11
|
+
/** Minimale tijd tussen twee rondes per bron. */
|
|
12
|
+
cooldownMs: 60000,
|
|
13
|
+
/** Lokaal geldt als actueel als de laatste volledige sync jonger is dan dit (cron elke 5 min, 2x marge). */
|
|
14
|
+
freshMs: 10 * 60000,
|
|
15
|
+
/** Lock-duur in de database; ruim boven timeoutMs zodat een afgebroken worker de lock vanzelf vrijgeeft. */
|
|
16
|
+
lockTtlSeconds: 30,
|
|
17
|
+
/** Wachtinterval voor een tweede aanroep terwijl een ronde loopt. */
|
|
18
|
+
pollMs: 500,
|
|
19
|
+
};
|
|
20
|
+
function stringList(v, name, errors, max) {
|
|
21
|
+
if (!Array.isArray(v)) {
|
|
22
|
+
errors.push(`${name} moet een lijst met tekst zijn`);
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
const out = [];
|
|
26
|
+
v.forEach((x, i) => {
|
|
27
|
+
if (typeof x !== "string" || !x.trim())
|
|
28
|
+
errors.push(`${name}[${i}] moet niet-lege tekst zijn`);
|
|
29
|
+
else
|
|
30
|
+
out.push(x.trim());
|
|
31
|
+
});
|
|
32
|
+
const uniq = Array.from(new Set(out));
|
|
33
|
+
if (v.length === 0)
|
|
34
|
+
errors.push(`${name} mag niet leeg zijn`);
|
|
35
|
+
if (max !== undefined && uniq.length > max)
|
|
36
|
+
errors.push(`${name}: maximaal ${max} id's (ontvangen ${uniq.length})`);
|
|
37
|
+
return uniq;
|
|
38
|
+
}
|
|
39
|
+
export function parseStatusRequest(body) {
|
|
40
|
+
const errors = [];
|
|
41
|
+
if (!body || typeof body !== "object" || Array.isArray(body)) {
|
|
42
|
+
return { ok: false, errors: ["Body moet een JSON-object zijn"] };
|
|
43
|
+
}
|
|
44
|
+
const env = body.environment;
|
|
45
|
+
if (env !== undefined && env !== "staging" && env !== "live")
|
|
46
|
+
errors.push("environment moet 'staging' of 'live' zijn");
|
|
47
|
+
if (body.salesOrderIds !== undefined) {
|
|
48
|
+
const ids = stringList(body.salesOrderIds, "salesOrderIds", errors, MAX_SALES_ORDER_IDS);
|
|
49
|
+
let foIds = null;
|
|
50
|
+
if (body.fulfillmentOrderIds !== undefined)
|
|
51
|
+
foIds = stringList(body.fulfillmentOrderIds, "fulfillmentOrderIds", errors);
|
|
52
|
+
const refresh = body.refresh ?? "auto";
|
|
53
|
+
if (refresh !== "auto" && refresh !== "never")
|
|
54
|
+
errors.push("refresh moet 'auto' of 'never' zijn");
|
|
55
|
+
if (errors.length)
|
|
56
|
+
return { ok: false, errors };
|
|
57
|
+
return { ok: true, value: { kind: "overview", salesOrderIds: ids, fulfillmentOrderIds: foIds, refresh, environment: env } };
|
|
58
|
+
}
|
|
59
|
+
const fo = body.fulfillmentOrderId;
|
|
60
|
+
if (fo === undefined)
|
|
61
|
+
errors.push("salesOrderIds (overzicht) of fulfillmentOrderId (één uitlevering) is verplicht");
|
|
62
|
+
else if (typeof fo !== "string" || !fo.trim())
|
|
63
|
+
errors.push("fulfillmentOrderId moet niet-lege tekst zijn");
|
|
64
|
+
if (errors.length)
|
|
65
|
+
return { ok: false, errors };
|
|
66
|
+
return { ok: true, value: { kind: "single", fulfillmentOrderId: String(fo).trim(), environment: env } };
|
|
67
|
+
}
|
|
68
|
+
export function decideRefresh(state, now, needed) {
|
|
69
|
+
const fresh = state.lastSuccessAt !== null && now - state.lastSuccessAt < REFRESH_LIMITS.freshMs;
|
|
70
|
+
if (fresh && !needed)
|
|
71
|
+
return { run: false, reason: "fresh" };
|
|
72
|
+
if (state.lastSyncedAt !== null && now - state.lastSyncedAt < REFRESH_LIMITS.cooldownMs) {
|
|
73
|
+
return { run: false, reason: "cooldown" };
|
|
74
|
+
}
|
|
75
|
+
return { run: true };
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Eén bron bijwerken binnen de deadline. Maar één ronde tegelijk per bron
|
|
79
|
+
* (database-lock, gedeeld met de cron). Een tweede aanroep wacht tot de
|
|
80
|
+
* lopende ronde klaar is of de deadline verstrijkt, en leest daarna lokaal.
|
|
81
|
+
* Gooit nooit: fouten komen in het rapport.
|
|
82
|
+
*/
|
|
83
|
+
export async function refreshSource(deps, source, needed, deadlineMs) {
|
|
84
|
+
const t0 = deps.now();
|
|
85
|
+
const report = {
|
|
86
|
+
source, attempted: false, skippedReason: null, timedOut: false, durationMs: 0, synced: 0, error: null,
|
|
87
|
+
};
|
|
88
|
+
const done = () => ({ ...report, durationMs: deps.now() - t0 });
|
|
89
|
+
try {
|
|
90
|
+
if (deps.now() >= deadlineMs) {
|
|
91
|
+
report.skippedReason = "deadline";
|
|
92
|
+
report.timedOut = true;
|
|
93
|
+
return done();
|
|
94
|
+
}
|
|
95
|
+
const state = await deps.readState(source);
|
|
96
|
+
const d = decideRefresh(state, deps.now(), needed);
|
|
97
|
+
if (!d.run) {
|
|
98
|
+
report.skippedReason = d.reason;
|
|
99
|
+
return done();
|
|
100
|
+
}
|
|
101
|
+
if (!(await deps.tryLock(source))) {
|
|
102
|
+
report.skippedReason = "in_progress";
|
|
103
|
+
const before = state.lastSyncedAt;
|
|
104
|
+
while (deps.now() < deadlineMs) {
|
|
105
|
+
await deps.sleep(REFRESH_LIMITS.pollMs);
|
|
106
|
+
const s = await deps.readState(source);
|
|
107
|
+
if (s.lastSyncedAt !== before)
|
|
108
|
+
return done();
|
|
109
|
+
}
|
|
110
|
+
report.timedOut = true;
|
|
111
|
+
return done();
|
|
112
|
+
}
|
|
113
|
+
report.attempted = true;
|
|
114
|
+
let release = true;
|
|
115
|
+
try {
|
|
116
|
+
const remaining = Math.max(0, deadlineMs - deps.now());
|
|
117
|
+
let timer;
|
|
118
|
+
const timeout = new Promise((r) => { timer = setTimeout(() => r("timeout"), remaining); });
|
|
119
|
+
const out = await Promise.race([deps.runSync(source, deadlineMs), timeout]);
|
|
120
|
+
clearTimeout(timer);
|
|
121
|
+
if (out === "timeout") {
|
|
122
|
+
// Ronde loopt nog tot zijn eigen deadline; lock vervalt via TTL.
|
|
123
|
+
report.timedOut = true;
|
|
124
|
+
release = false;
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
report.synced = out.synced;
|
|
128
|
+
if (out.partial)
|
|
129
|
+
report.timedOut = deps.now() >= deadlineMs;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
finally {
|
|
133
|
+
if (release)
|
|
134
|
+
await deps.unlock(source);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
catch (e) {
|
|
138
|
+
report.error = String(e?.message ?? e).slice(0, 300);
|
|
139
|
+
}
|
|
140
|
+
return done();
|
|
141
|
+
}
|