@flowselections/floriday-verkoop-module 1.0.8 → 1.0.10

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/FlorydaySyncHealthBanner.d.ts +9 -0
  2. package/dist-lib/components/floriday/FlorydaySyncHealthBanner.d.ts.map +1 -0
  3. package/dist-lib/components/floriday/FlorydaySyncHealthBanner.js +26 -0
  4. package/dist-lib/components/verkoop/CreateOrderPage.d.ts.map +1 -1
  5. package/dist-lib/components/verkoop/CreateOrderPage.js +6 -9
  6. package/dist-lib/components/verkoop/VerkoopOrdersPage.d.ts.map +1 -1
  7. package/dist-lib/components/verkoop/VerkoopOrdersPage.js +2 -1
  8. package/dist-lib/integrations/supabase/auth-middleware.d.ts +2797 -144
  9. package/dist-lib/integrations/supabase/auth-middleware.d.ts.map +1 -1
  10. package/dist-lib/integrations/supabase/client.d.ts +2797 -144
  11. package/dist-lib/integrations/supabase/client.d.ts.map +1 -1
  12. package/dist-lib/integrations/supabase/client.server.d.ts +2797 -144
  13. package/dist-lib/integrations/supabase/client.server.d.ts.map +1 -1
  14. package/dist-lib/integrations/supabase/types.d.ts +2870 -134
  15. package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
  16. package/dist-lib/integrations/supabase/types.js +2 -0
  17. package/dist-lib/lib/floriday-gateway.server.d.ts +42 -0
  18. package/dist-lib/lib/floriday-gateway.server.d.ts.map +1 -0
  19. package/dist-lib/lib/floriday-gateway.server.js +217 -0
  20. package/dist-lib/lib/floriday-public.functions.d.ts +65056 -0
  21. package/dist-lib/lib/floriday-public.functions.d.ts.map +1 -0
  22. package/dist-lib/lib/floriday-public.functions.js +210 -0
  23. package/dist-lib/lib/floriday-sync.d.ts.map +1 -1
  24. package/dist-lib/lib/floriday-sync.js +18 -79
  25. package/dist-lib/lib/floriday-writes.functions.d.ts +46453 -0
  26. package/dist-lib/lib/floriday-writes.functions.d.ts.map +1 -0
  27. package/dist-lib/lib/floriday-writes.functions.js +110 -0
  28. package/dist-lib/lib/salesorders.functions.d.ts +17670 -9710
  29. package/dist-lib/lib/salesorders.functions.d.ts.map +1 -1
  30. package/dist-lib/lib/salesorders.functions.js +44 -86
  31. package/dist-lib/lib/tradeitems.functions.d.ts +2797 -144
  32. package/dist-lib/lib/tradeitems.functions.d.ts.map +1 -1
  33. package/dist-lib/lib/useSalesOrdersQuery.d.ts.map +1 -1
  34. package/dist-lib/lib/useSalesOrdersQuery.js +11 -25
  35. package/package.json +2 -2
@@ -8,8 +8,10 @@ export const Constants = {
8
8
  "sales",
9
9
  "developer",
10
10
  "receptie",
11
+ "monteur",
11
12
  ],
12
13
  exact_env: ["staging", "live"],
14
+ exact_push_status: ["pending", "sent", "error"],
13
15
  quote_status: [
14
16
  "concept",
15
17
  "verzonden",
@@ -0,0 +1,42 @@
1
+ import type { SupabaseClient } from "@supabase/supabase-js";
2
+ import { type FloridayConnectionRow } from "./floriday-sync";
3
+ export type FlorydayEnvironment = "staging" | "live";
4
+ export declare function apiBaseFor(env: FlorydayEnvironment | string | null | undefined): string;
5
+ export declare function pickActiveConnection(supabase: SupabaseClient, env: FlorydayEnvironment | string): Promise<FloridayConnectionRow & {
6
+ gln_code?: string | null;
7
+ }>;
8
+ export interface FlorydayFetchResult<T = unknown> {
9
+ ok: boolean;
10
+ status: number;
11
+ data: T | null;
12
+ rawText: string;
13
+ connection: FloridayConnectionRow;
14
+ }
15
+ /** Low-level fetch with token-refresh + retry-once on 401/403. */
16
+ export declare function florydayFetch<T = unknown>(supabase: SupabaseClient, conn: FloridayConnectionRow, init: {
17
+ method: string;
18
+ path: string;
19
+ body?: unknown;
20
+ }): Promise<FlorydayFetchResult<T>>;
21
+ export interface EnumCheck {
22
+ field: string;
23
+ listName: string;
24
+ }
25
+ export interface FlorydayWriteArgs {
26
+ module: string;
27
+ action: string;
28
+ method: "POST" | "PUT" | "PATCH" | "DELETE";
29
+ path: string;
30
+ referenceId?: string | null;
31
+ body?: unknown;
32
+ validateEnums?: EnumCheck[];
33
+ }
34
+ export interface FlorydayWriteResult {
35
+ ok: boolean;
36
+ status: number;
37
+ data?: any;
38
+ error?: string;
39
+ attemptId?: string;
40
+ }
41
+ export declare function florydayWrite(supabase: SupabaseClient, env: FlorydayEnvironment | string, args: FlorydayWriteArgs, callerUserId?: string | null): Promise<FlorydayWriteResult>;
42
+ //# sourceMappingURL=floriday-gateway.server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"floriday-gateway.server.d.ts","sourceRoot":"","sources":["../../src/lib/floriday-gateway.server.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAsB,KAAK,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAEjF,MAAM,MAAM,mBAAmB,GAAG,SAAS,GAAG,MAAM,CAAC;AAKrD,wBAAgB,UAAU,CAAC,GAAG,EAAE,mBAAmB,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAIvF;AAMD,wBAAsB,oBAAoB,CACxC,QAAQ,EAAE,cAAc,EACxB,GAAG,EAAE,mBAAmB,GAAG,MAAM,GAChC,OAAO,CAAC,qBAAqB,GAAG;IAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC,CAa/D;AA6BD,MAAM,WAAW,mBAAmB,CAAC,CAAC,GAAG,OAAO;IAC9C,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,qBAAqB,CAAC;CACnC;AAED,kEAAkE;AAClE,wBAAsB,aAAa,CAAC,CAAC,GAAG,OAAO,EAC7C,QAAQ,EAAE,cAAc,EACxB,IAAI,EAAE,qBAAqB,EAC3B,IAAI,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,OAAO,CAAA;CAAE,GACrD,OAAO,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,CA8CjC;AAGD,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB;AA4DD,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,CAAC;IAC5C,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,aAAa,CAAC,EAAE,SAAS,EAAE,CAAC;CAC7B;AAED,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,GAAG,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAkBD,wBAAsB,aAAa,CACjC,QAAQ,EAAE,cAAc,EACxB,GAAG,EAAE,mBAAmB,GAAG,MAAM,EACjC,IAAI,EAAE,iBAAiB,EACvB,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,GAC3B,OAAO,CAAC,mBAAmB,CAAC,CA6D9B"}
@@ -0,0 +1,217 @@
1
+ import { FLORIDAY_API_BASES } from "./floriday-sync";
2
+ const AUTH_MODULE_REFRESH_URL = "https://project--vmicscahrnzpmhagztmx.lovable.app/api/public/cron/refresh-floriday-tokens";
3
+ export function apiBaseFor(env) {
4
+ return env === "live" || env === "production" || env === "prod"
5
+ ? FLORIDAY_API_BASES.production
6
+ : FLORIDAY_API_BASES.staging;
7
+ }
8
+ function normalizeEnvKey(env) {
9
+ return env === "live" || env === "production" || env === "prod" ? "production" : "staging";
10
+ }
11
+ export async function pickActiveConnection(supabase, env) {
12
+ const dbEnv = normalizeEnvKey(env);
13
+ const { data, error } = await supabase
14
+ .from("floriday_connections")
15
+ .select("id, environment, access_token, api_key, is_active, gln_code")
16
+ .eq("environment", dbEnv)
17
+ .eq("is_active", true)
18
+ .order("updated_at", { ascending: false })
19
+ .limit(1)
20
+ .maybeSingle();
21
+ if (error)
22
+ throw new Error(`Floriday connectie ophalen mislukt: ${error.message}`);
23
+ if (!data)
24
+ throw new Error(`Geen actieve Floriday connectie voor "${dbEnv}"`);
25
+ return data;
26
+ }
27
+ async function triggerAuthModuleRefresh() {
28
+ try {
29
+ await fetch(AUTH_MODULE_REFRESH_URL, {
30
+ method: "POST",
31
+ headers: { "Content-Type": "application/json" },
32
+ body: "{}",
33
+ });
34
+ }
35
+ catch {
36
+ // best-effort — caller re-reads the token regardless
37
+ }
38
+ }
39
+ async function reloadConnection(supabase, connectionId) {
40
+ const { data, error } = await supabase
41
+ .from("floriday_connections")
42
+ .select("id, environment, access_token, api_key, is_active")
43
+ .eq("id", connectionId)
44
+ .maybeSingle();
45
+ if (error || !data) {
46
+ throw new Error(`Floriday connectie ${connectionId} herladen mislukt: ${error?.message ?? "not found"}`);
47
+ }
48
+ return data;
49
+ }
50
+ /** Low-level fetch with token-refresh + retry-once on 401/403. */
51
+ export async function florydayFetch(supabase, conn, init) {
52
+ let active = conn;
53
+ let lastRes = null;
54
+ let lastText = "";
55
+ for (let attempt = 0; attempt < 2; attempt += 1) {
56
+ if (!active.access_token) {
57
+ await triggerAuthModuleRefresh();
58
+ active = await reloadConnection(supabase, active.id);
59
+ if (!active.access_token) {
60
+ throw new Error(`Floriday connectie ${active.id} heeft geen access_token`);
61
+ }
62
+ }
63
+ const url = `${apiBaseFor(active.environment)}${init.path}`;
64
+ const res = await fetch(url, {
65
+ method: init.method,
66
+ headers: {
67
+ Accept: "application/json",
68
+ ...(init.body !== undefined ? { "Content-Type": "application/json" } : {}),
69
+ Authorization: `Bearer ${active.access_token}`,
70
+ ...(active.api_key ? { "x-api-key": active.api_key } : {}),
71
+ },
72
+ body: init.body !== undefined ? JSON.stringify(init.body) : undefined,
73
+ });
74
+ const text = await res.text();
75
+ lastRes = res;
76
+ lastText = text;
77
+ if (res.ok) {
78
+ const parsed = text ? JSON.parse(text) : null;
79
+ return { ok: true, status: res.status, data: parsed, rawText: text, connection: active };
80
+ }
81
+ if ((res.status === 401 || res.status === 403) && attempt === 0) {
82
+ await triggerAuthModuleRefresh();
83
+ active = await reloadConnection(supabase, active.id);
84
+ continue;
85
+ }
86
+ break;
87
+ }
88
+ return {
89
+ ok: false,
90
+ status: lastRes?.status ?? 0,
91
+ data: null,
92
+ rawText: lastText,
93
+ connection: active,
94
+ };
95
+ }
96
+ async function fetchAllowedValues(supabase, env, listName) {
97
+ const dbEnv = normalizeEnvKey(env) === "production" ? "live" : "staging";
98
+ const { data, error } = await supabase
99
+ .from("floriday_code_lists_cache")
100
+ .select("code")
101
+ .eq("environment", dbEnv)
102
+ .eq("list_name", listName);
103
+ if (error)
104
+ throw new Error(`code-lists lezen faalde: ${error.message}`);
105
+ return (data ?? []).map((r) => String(r.code));
106
+ }
107
+ function readPathValues(body, path) {
108
+ const parts = path.split(".");
109
+ let nodes = [body];
110
+ for (const part of parts) {
111
+ const next = [];
112
+ const isArray = part.endsWith("[]");
113
+ const key = isArray ? part.slice(0, -2) : part;
114
+ for (const node of nodes) {
115
+ if (node == null || typeof node !== "object")
116
+ continue;
117
+ const v = node[key];
118
+ if (v === undefined)
119
+ continue;
120
+ if (isArray && Array.isArray(v))
121
+ next.push(...v);
122
+ else
123
+ next.push(v);
124
+ }
125
+ nodes = next;
126
+ }
127
+ return nodes;
128
+ }
129
+ async function runEnumChecks(supabase, env, body, checks) {
130
+ for (const check of checks) {
131
+ const values = readPathValues(body, check.field).filter((v) => v != null);
132
+ if (values.length === 0)
133
+ continue;
134
+ const allowed = await fetchAllowedValues(supabase, env, check.listName);
135
+ if (allowed.length === 0)
136
+ continue; // list not cached yet → skip
137
+ const bad = values.find((v) => !allowed.includes(String(v)));
138
+ if (bad !== undefined) {
139
+ return {
140
+ ok: false,
141
+ error: `Veld "${check.field}" heeft ongeldige waarde "${bad}" voor lijst "${check.listName}"`,
142
+ allowed,
143
+ };
144
+ }
145
+ }
146
+ return { ok: true };
147
+ }
148
+ async function computeIdempotencyKey(args) {
149
+ const payload = [
150
+ args.module,
151
+ args.action,
152
+ args.referenceId ?? "",
153
+ JSON.stringify(args.body ?? null),
154
+ ].join("|");
155
+ const buf = await globalThis.crypto.subtle.digest("SHA-256", new TextEncoder().encode(payload));
156
+ return Array.from(new Uint8Array(buf))
157
+ .map((b) => b.toString(16).padStart(2, "0"))
158
+ .join("");
159
+ }
160
+ export async function florydayWrite(supabase, env, args, callerUserId) {
161
+ const idempotencyKey = await computeIdempotencyKey(args);
162
+ // 1) Local pre-flight enum validation (saves a Floriday roundtrip on mismatches).
163
+ if (args.validateEnums && args.validateEnums.length > 0) {
164
+ const v = await runEnumChecks(supabase, env, args.body, args.validateEnums);
165
+ if (!v.ok) {
166
+ const ins = await supabase.from("floriday_write_log")
167
+ .insert({
168
+ module: args.module,
169
+ action: args.action,
170
+ resource: args.path,
171
+ floriday_id: args.referenceId ?? null,
172
+ idempotency_key: idempotencyKey,
173
+ request: { body: args.body ?? null, env },
174
+ response: { allowed: v.allowed ?? null },
175
+ http_status: 0,
176
+ ok: false,
177
+ error: v.error,
178
+ user_id: callerUserId ?? null,
179
+ })
180
+ .select("id")
181
+ .maybeSingle();
182
+ return { ok: false, status: 0, error: v.error, attemptId: ins.data?.id };
183
+ }
184
+ }
185
+ const conn = await pickActiveConnection(supabase, env);
186
+ const res = await florydayFetch(supabase, conn, {
187
+ method: args.method,
188
+ path: args.path,
189
+ body: args.body,
190
+ });
191
+ const ins = await supabase.from("floriday_write_log")
192
+ .insert({
193
+ connection_id: conn.id,
194
+ module: args.module,
195
+ action: args.action,
196
+ resource: args.path,
197
+ floriday_id: args.referenceId ?? null,
198
+ idempotency_key: idempotencyKey,
199
+ request: { body: args.body ?? null, env, method: args.method },
200
+ response: res.rawText ? { body: res.rawText.slice(0, 32000) } : null,
201
+ http_status: res.status,
202
+ ok: res.ok,
203
+ error: res.ok ? null : res.rawText.slice(0, 500),
204
+ user_id: callerUserId ?? null,
205
+ })
206
+ .select("id")
207
+ .maybeSingle();
208
+ if (!res.ok) {
209
+ return {
210
+ ok: false,
211
+ status: res.status,
212
+ error: res.rawText ? res.rawText.slice(0, 400) : `HTTP ${res.status}`,
213
+ attemptId: ins.data?.id,
214
+ };
215
+ }
216
+ return { ok: true, status: res.status, data: res.data, attemptId: ins.data?.id };
217
+ }