@flowselections/google-maps-api-installatie-techniek 1.0.4 → 1.1.1

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 (37) hide show
  1. package/README.md +33 -0
  2. package/dist-lib/components/MapsBeheerPage.d.ts.map +1 -1
  3. package/dist-lib/components/MapsBeheerPage.js +27 -2
  4. package/dist-lib/components/maps/MapsDiagnosticsPanel.js +1 -1
  5. package/dist-lib/components/maps/MapsErrorsPanel.d.ts +2 -0
  6. package/dist-lib/components/maps/MapsErrorsPanel.d.ts.map +1 -0
  7. package/dist-lib/components/maps/MapsErrorsPanel.js +26 -0
  8. package/dist-lib/components/maps/MapsStatusPanel.d.ts +1 -1
  9. package/dist-lib/components/maps/MapsStatusPanel.js +1 -1
  10. package/dist-lib/components/settings/MapsSettingsCard.js +1 -1
  11. package/dist-lib/integrations/supabase/client.js +1 -1
  12. package/dist-lib/integrations/supabase/client.server.js +1 -1
  13. package/dist-lib/integrations/supabase/previewAuthStorage.d.ts +11 -5
  14. package/dist-lib/integrations/supabase/previewAuthStorage.d.ts.map +1 -1
  15. package/dist-lib/integrations/supabase/previewAuthStorage.js +59 -24
  16. package/dist-lib/integrations/supabase/types.d.ts +23505 -6704
  17. package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
  18. package/dist-lib/integrations/supabase/types.js +2 -0
  19. package/dist-lib/lib/maps-admin.server.d.ts +9 -1
  20. package/dist-lib/lib/maps-admin.server.d.ts.map +1 -1
  21. package/dist-lib/lib/maps-admin.server.js +60 -6
  22. package/dist-lib/lib/maps-errors.d.ts +24 -0
  23. package/dist-lib/lib/maps-errors.d.ts.map +1 -0
  24. package/dist-lib/lib/maps-errors.js +57 -0
  25. package/dist-lib/lib/maps-errors.test.d.ts +2 -0
  26. package/dist-lib/lib/maps-errors.test.d.ts.map +1 -0
  27. package/dist-lib/lib/maps-errors.test.js +40 -0
  28. package/dist-lib/lib/maps-processor.server.d.ts +2 -0
  29. package/dist-lib/lib/maps-processor.server.d.ts.map +1 -1
  30. package/dist-lib/lib/maps-processor.server.js +117 -22
  31. package/dist-lib/lib/maps-processor.test.d.ts +2 -0
  32. package/dist-lib/lib/maps-processor.test.d.ts.map +1 -0
  33. package/dist-lib/lib/maps-processor.test.js +182 -0
  34. package/dist-lib/lib/maps.functions.d.ts +52 -8
  35. package/dist-lib/lib/maps.functions.d.ts.map +1 -1
  36. package/dist-lib/lib/maps.functions.js +24 -1
  37. package/package.json +8 -6
@@ -0,0 +1,182 @@
1
+ // Tests met een nep-database en nep-Google: er worden geen echte aanroepen gedaan.
2
+ import { beforeEach, describe, expect, it, vi } from "vitest";
3
+ const google = vi.hoisted(() => ({
4
+ geocodeAddress: vi.fn(),
5
+ computeRouteMatrix: vi.fn(),
6
+ }));
7
+ vi.mock("./google-maps.server", () => google);
8
+ let state;
9
+ function makeBuilder(table) {
10
+ const ops = [];
11
+ const builder = new Proxy({}, {
12
+ get(_t, prop) {
13
+ if (prop === "then") {
14
+ return (resolve, reject) => {
15
+ state.log.push({ table, ops });
16
+ Promise.resolve(execute(table, ops)).then(resolve, reject);
17
+ };
18
+ }
19
+ return (...args) => {
20
+ ops.push([prop, args]);
21
+ return builder;
22
+ };
23
+ },
24
+ });
25
+ return builder;
26
+ }
27
+ function arg(ops, name) {
28
+ return ops.filter(([n]) => n === name).map(([, a]) => a);
29
+ }
30
+ function execute(table, ops) {
31
+ const kind = ops[0][0];
32
+ if (table === "maps_settings")
33
+ return { data: { id: "s1", ...state.settings }, error: null };
34
+ if (table === "maps_usage_log")
35
+ return { data: [], error: null };
36
+ if (table === "maps_addresses") {
37
+ if (kind === "select") {
38
+ const hash = arg(ops, "eq")[0]?.[1];
39
+ return { data: state.addresses.find((a) => a.address_hash === hash) ?? null, error: null };
40
+ }
41
+ if (kind === "insert") {
42
+ const row = { id: `a${state.addresses.length + 1}`, ...ops[0][1][0] };
43
+ state.addresses.push(row);
44
+ return { data: { id: row.id }, error: null };
45
+ }
46
+ if (kind === "update") {
47
+ const id = arg(ops, "eq")[0]?.[1];
48
+ const row = state.addresses.find((a) => a.id === id);
49
+ if (row)
50
+ Object.assign(row, ops[0][1][0]);
51
+ return { data: null, error: null };
52
+ }
53
+ }
54
+ if (table === "maps_request_queue") {
55
+ if (kind === "select") {
56
+ const max = arg(ops, "lt")[0]?.[1];
57
+ return { data: state.queue.filter((q) => q.status === "pending" && q.attempts < max).map((q) => ({ ...q })), error: null };
58
+ }
59
+ if (kind === "update") {
60
+ const patch = ops[0][1][0];
61
+ const ids = arg(ops, "in")[0]?.[1] ?? [arg(ops, "eq")[0]?.[1]];
62
+ for (const q of state.queue)
63
+ if (ids.includes(q.id))
64
+ Object.assign(q, patch);
65
+ return { data: null, error: null };
66
+ }
67
+ }
68
+ return { data: null, error: null };
69
+ }
70
+ const fakeDb = {
71
+ from: (table) => makeBuilder(table),
72
+ rpc: async (name, params) => {
73
+ state.rpcCalls.push(name);
74
+ if (name === "maps_claim_queue_items") {
75
+ // Simuleert FOR UPDATE SKIP LOCKED: atomair pending → processing.
76
+ const picked = state.queue
77
+ .filter((q) => q.status === "pending" && q.attempts < params.p_max_attempts)
78
+ .slice(0, params.p_limit);
79
+ for (const q of picked)
80
+ q.status = "processing";
81
+ return { data: picked.map((q) => ({ ...q })), error: null };
82
+ }
83
+ if (name === "maps_try_consume_call") {
84
+ const cur = state.counter[params.p_day] ?? params.p_initial;
85
+ if (cur >= params.p_limit) {
86
+ state.counter[params.p_day] = cur;
87
+ return { data: null, error: null };
88
+ }
89
+ state.counter[params.p_day] = cur + 1;
90
+ return { data: cur + 1, error: null };
91
+ }
92
+ return { data: null, error: null };
93
+ },
94
+ };
95
+ vi.mock("@supabase/supabase-js", () => ({ createClient: () => fakeDb }));
96
+ const { processMapsQueueBatch } = await import("./maps-processor.server");
97
+ function geocodeItems(n) {
98
+ return Array.from({ length: n }, (_, i) => ({
99
+ id: `q${i}`,
100
+ kind: "geocode",
101
+ raw_origin: `Straat ${i}, Plaats`,
102
+ raw_destination: null,
103
+ mode: "drive",
104
+ status: "pending",
105
+ attempts: 0,
106
+ }));
107
+ }
108
+ beforeEach(() => {
109
+ process.env.SUPABASE_URL = "http://fake";
110
+ process.env.SERVICE_ROLE_KEY = "fake";
111
+ google.geocodeAddress.mockReset();
112
+ google.computeRouteMatrix.mockReset();
113
+ google.geocodeAddress.mockImplementation(async (raw) => {
114
+ await new Promise((r) => setTimeout(r, 1));
115
+ return { formattedAddress: raw, lat: 52, lng: 5, placeId: "p" };
116
+ });
117
+ });
118
+ function reset(settings, items = geocodeItems(3)) {
119
+ state = { settings, queue: items, addresses: [], counter: {}, log: [], rpcCalls: [] };
120
+ }
121
+ describe("processMapsQueueBatch — schakelaars uit = huidig gedrag", () => {
122
+ it("oude instellingen (zonder nieuwe kolommen) en nieuwe kolommen op uit geven exact hetzelfde", async () => {
123
+ reset({ daily_call_limit: 2000, cache_ttl_days: 30 });
124
+ const oud = await processMapsQueueBatch();
125
+ const oudOps = JSON.stringify(state.log.map((l) => [l.table, l.ops.map(([n]) => n)]));
126
+ const oudQueue = state.queue.map((q) => [q.id, q.status, q.attempts]);
127
+ expect(state.rpcCalls).toEqual([]);
128
+ reset({
129
+ daily_call_limit: 2000, cache_ttl_days: 30,
130
+ claim_via_rpc_enabled: false, per_call_limit_enabled: false,
131
+ max_attempts_enabled: false, stop_bij_sleutelfout_enabled: false,
132
+ max_attempts: 9, timezone: "Europe/Amsterdam",
133
+ });
134
+ const nieuw = await processMapsQueueBatch();
135
+ expect(nieuw).toEqual(oud);
136
+ expect(nieuw).toEqual({ processed: 3, geocoded: 3, travelTimes: 0, failed: 0, skipped: null });
137
+ expect(JSON.stringify(state.log.map((l) => [l.table, l.ops.map(([n]) => n)]))).toBe(oudOps);
138
+ expect(state.queue.map((q) => [q.id, q.status, q.attempts])).toEqual(oudQueue);
139
+ expect(state.rpcCalls).toEqual([]);
140
+ });
141
+ it("zonder schakelaar loopt de batch door na een sleutelfout", async () => {
142
+ reset({ daily_call_limit: 2000 });
143
+ google.geocodeAddress.mockRejectedValue(new Error("API key not valid"));
144
+ const r = await processMapsQueueBatch();
145
+ expect(google.geocodeAddress).toHaveBeenCalledTimes(3);
146
+ expect(r.failed).toBe(3);
147
+ });
148
+ });
149
+ describe("processMapsQueueBatch — nieuwe schakelaars", () => {
150
+ it("twee gelijktijdige verwerkingen roepen Google maximaal één keer per item aan", async () => {
151
+ reset({ daily_call_limit: 2000, claim_via_rpc_enabled: true }, geocodeItems(10));
152
+ await Promise.all([processMapsQueueBatch(), processMapsQueueBatch()]);
153
+ const calls = google.geocodeAddress.mock.calls.map((c) => c[0]);
154
+ expect(calls).toHaveLength(10);
155
+ expect(new Set(calls).size).toBe(10);
156
+ });
157
+ it("de daglimiet wordt nooit overschreden (limiet 2)", async () => {
158
+ reset({ daily_call_limit: 2, per_call_limit_enabled: true, claim_via_rpc_enabled: true }, geocodeItems(5));
159
+ const r = await processMapsQueueBatch();
160
+ expect(google.geocodeAddress).toHaveBeenCalledTimes(2);
161
+ expect(Object.values(state.counter)).toEqual([2]);
162
+ expect(r.skipped).toBe("Daglimiet bereikt");
163
+ // Niet-verwerkte items staan weer op pending zonder extra poging.
164
+ expect(state.queue.filter((q) => q.status === "pending" && q.attempts === 0)).toHaveLength(3);
165
+ });
166
+ it("met stop_bij_sleutelfout_enabled stopt de batch na de eerste sleutelfout", async () => {
167
+ reset({ daily_call_limit: 2000, stop_bij_sleutelfout_enabled: true });
168
+ google.geocodeAddress.mockRejectedValue(new Error("API key not valid"));
169
+ await processMapsQueueBatch();
170
+ expect(google.geocodeAddress).toHaveBeenCalledTimes(1);
171
+ expect(state.queue.filter((q) => q.status === "pending" && q.attempts === 0)).toHaveLength(2);
172
+ });
173
+ it("max_attempts uit de instellingen wordt alleen gebruikt als de schakelaar aan staat", async () => {
174
+ const items = geocodeItems(1).map((q) => ({ ...q, attempts: 3 }));
175
+ reset({ daily_call_limit: 2000, max_attempts: 5 }, items);
176
+ await processMapsQueueBatch();
177
+ expect(google.geocodeAddress).not.toHaveBeenCalled();
178
+ reset({ daily_call_limit: 2000, max_attempts: 5, max_attempts_enabled: true }, geocodeItems(1).map((q) => ({ ...q, attempts: 3 })));
179
+ await processMapsQueueBatch();
180
+ expect(google.geocodeAddress).toHaveBeenCalledTimes(1);
181
+ });
182
+ });
@@ -7,6 +7,13 @@ export interface MapsOverview {
7
7
  dailyCallLimit: number;
8
8
  allowEstimateFallback: boolean;
9
9
  provider: "free" | "google";
10
+ claimViaRpcEnabled: boolean;
11
+ perCallLimitEnabled: boolean;
12
+ maxAttemptsEnabled: boolean;
13
+ stopBijSleutelfoutEnabled: boolean;
14
+ maxAttempts: number;
15
+ timezone: string;
16
+ updatedAt: string | null;
10
17
  lastSuccessAt: string | null;
11
18
  lastErrorAt: string | null;
12
19
  lastError: string | null;
@@ -23,18 +30,41 @@ export interface MapsOverview {
23
30
  errorsMonth: number;
24
31
  estimatedCostMonth: number | null;
25
32
  }
33
+ export interface MapsErrorPage {
34
+ total: number;
35
+ page: number;
36
+ pageSize: number;
37
+ items: Array<{
38
+ id: string;
39
+ at: string;
40
+ callType: string;
41
+ kind: "quota" | "invalid_key" | "not_found" | "token" | "other";
42
+ message: string;
43
+ }>;
44
+ }
45
+ export declare const getMapsErrors: import("@tanstack/start-client-core").RequiredFetcher<readonly [import("@tanstack/start-client-core").FunctionMiddlewareAfterServer<{}, unknown, undefined, {
46
+ supabase: import("../integrations/supabase/auth-middleware.js").AuthedSupabaseClient;
47
+ userId: string;
48
+ claims: import("@supabase/auth-js").JwtPayload;
49
+ }, undefined, undefined, undefined>], (input: {
50
+ page?: number;
51
+ pageSize?: number;
52
+ }) => {
53
+ page: number;
54
+ pageSize: number;
55
+ }, Promise<MapsErrorPage>>;
26
56
  export declare const getMapsOverview: import("@tanstack/start-client-core").OptionalFetcher<readonly [import("@tanstack/start-client-core").FunctionMiddlewareAfterServer<{}, unknown, undefined, {
27
- supabase: import("../integrations/supabase/auth-middleware").AuthedSupabaseClient;
57
+ supabase: import("../integrations/supabase/auth-middleware.js").AuthedSupabaseClient;
28
58
  userId: string;
29
59
  claims: import("@supabase/auth-js").JwtPayload;
30
60
  }, undefined, undefined, undefined>], undefined, Promise<MapsOverview>>;
31
61
  export declare const processMapsQueue: import("@tanstack/start-client-core").OptionalFetcher<readonly [import("@tanstack/start-client-core").FunctionMiddlewareAfterServer<{}, unknown, undefined, {
32
- supabase: import("../integrations/supabase/auth-middleware").AuthedSupabaseClient;
62
+ supabase: import("../integrations/supabase/auth-middleware.js").AuthedSupabaseClient;
33
63
  userId: string;
34
64
  claims: import("@supabase/auth-js").JwtPayload;
35
65
  }, undefined, undefined, undefined>], undefined, Promise<import("./maps-processor.server").ProcessResult>>;
36
66
  export declare const updateMapsSettings: import("@tanstack/start-client-core").RequiredFetcher<readonly [import("@tanstack/start-client-core").FunctionMiddlewareAfterServer<{}, unknown, undefined, {
37
- supabase: import("../integrations/supabase/auth-middleware").AuthedSupabaseClient;
67
+ supabase: import("../integrations/supabase/auth-middleware.js").AuthedSupabaseClient;
38
68
  userId: string;
39
69
  claims: import("@supabase/auth-js").JwtPayload;
40
70
  }, undefined, undefined, undefined>], (input: {
@@ -42,7 +72,21 @@ export declare const updateMapsSettings: import("@tanstack/start-client-core").R
42
72
  dailyCallLimit: number;
43
73
  allowEstimateFallback: boolean;
44
74
  provider: "free" | "google";
75
+ claimViaRpcEnabled?: boolean;
76
+ perCallLimitEnabled?: boolean;
77
+ maxAttemptsEnabled?: boolean;
78
+ stopBijSleutelfoutEnabled?: boolean;
79
+ maxAttempts?: number;
80
+ timezone?: string;
81
+ expectedUpdatedAt?: string | null;
45
82
  }) => {
83
+ expectedUpdatedAt: string | null;
84
+ timezone?: string | undefined;
85
+ maxAttempts?: number | undefined;
86
+ stopBijSleutelfoutEnabled?: boolean | undefined;
87
+ maxAttemptsEnabled?: boolean | undefined;
88
+ perCallLimitEnabled?: boolean | undefined;
89
+ claimViaRpcEnabled?: boolean | undefined;
46
90
  cacheTtlDays: number;
47
91
  dailyCallLimit: number;
48
92
  allowEstimateFallback: boolean;
@@ -51,26 +95,26 @@ export declare const updateMapsSettings: import("@tanstack/start-client-core").R
51
95
  ok: boolean;
52
96
  }>>;
53
97
  export declare const clearMapsCache: import("@tanstack/start-client-core").OptionalFetcher<readonly [import("@tanstack/start-client-core").FunctionMiddlewareAfterServer<{}, unknown, undefined, {
54
- supabase: import("../integrations/supabase/auth-middleware").AuthedSupabaseClient;
98
+ supabase: import("../integrations/supabase/auth-middleware.js").AuthedSupabaseClient;
55
99
  userId: string;
56
100
  claims: import("@supabase/auth-js").JwtPayload;
57
101
  }, undefined, undefined, undefined>], undefined, Promise<{
58
102
  ok: boolean;
59
103
  }>>;
60
104
  export declare const purgeExpiredTravelTimes: import("@tanstack/start-client-core").OptionalFetcher<readonly [import("@tanstack/start-client-core").FunctionMiddlewareAfterServer<{}, unknown, undefined, {
61
- supabase: import("../integrations/supabase/auth-middleware").AuthedSupabaseClient;
105
+ supabase: import("../integrations/supabase/auth-middleware.js").AuthedSupabaseClient;
62
106
  userId: string;
63
107
  claims: import("@supabase/auth-js").JwtPayload;
64
108
  }, undefined, undefined, undefined>], undefined, Promise<{
65
109
  ok: boolean;
66
110
  }>>;
67
111
  export declare const getMapsStatus: import("@tanstack/start-client-core").OptionalFetcher<readonly [import("@tanstack/start-client-core").FunctionMiddlewareAfterServer<{}, unknown, undefined, {
68
- supabase: import("../integrations/supabase/auth-middleware").AuthedSupabaseClient;
112
+ supabase: import("../integrations/supabase/auth-middleware.js").AuthedSupabaseClient;
69
113
  userId: string;
70
114
  claims: import("@supabase/auth-js").JwtPayload;
71
115
  }, undefined, undefined, undefined>], undefined, Promise<import("./central-auth.server").MapsConnectionStatus>>;
72
116
  export declare const testMapsConnection: import("@tanstack/start-client-core").OptionalFetcher<readonly [import("@tanstack/start-client-core").FunctionMiddlewareAfterServer<{}, unknown, undefined, {
73
- supabase: import("../integrations/supabase/auth-middleware").AuthedSupabaseClient;
117
+ supabase: import("../integrations/supabase/auth-middleware.js").AuthedSupabaseClient;
74
118
  userId: string;
75
119
  claims: import("@supabase/auth-js").JwtPayload;
76
120
  }, undefined, undefined, undefined>], undefined, Promise<{
@@ -79,7 +123,7 @@ export declare const testMapsConnection: import("@tanstack/start-client-core").O
79
123
  detail: string | null;
80
124
  }>>;
81
125
  export declare const getMapsDiagnostics: import("@tanstack/start-client-core").OptionalFetcher<readonly [import("@tanstack/start-client-core").FunctionMiddlewareAfterServer<{}, unknown, undefined, {
82
- supabase: import("../integrations/supabase/auth-middleware").AuthedSupabaseClient;
126
+ supabase: import("../integrations/supabase/auth-middleware.js").AuthedSupabaseClient;
83
127
  userId: string;
84
128
  claims: import("@supabase/auth-js").JwtPayload;
85
129
  }, undefined, undefined, undefined>], undefined, Promise<import("./central-auth.server").MapsDiagnosticsReport>>;
@@ -1 +1 @@
1
- {"version":3,"file":"maps.functions.d.ts","sourceRoot":"","sources":["../../src/lib/maps.functions.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,OAAO,CAAC;IACnB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,QAAQ,EAAE;QACR,EAAE,EAAE,MAAM,CAAC;QACX,YAAY,EAAE,MAAM,CAAC;QACrB,cAAc,EAAE,MAAM,CAAC;QACvB,qBAAqB,EAAE,OAAO,CAAC;QAC/B,QAAQ,EAAE,MAAM,GAAG,QAAQ,CAAC;QAC5B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;QAC7B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;QAC3B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;KAC1B,GAAG,IAAI,CAAC;IACT,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;CACnC;AAED,eAAO,MAAM,eAAe;;;;uEAKxB,CAAC;AAEL,eAAO,MAAM,gBAAgB;;;;0GAKzB,CAAC;AAEL,eAAO,MAAM,kBAAkB;;;;8CAEL;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,qBAAqB,EAAE,OAAO,CAAC;IAC/B,QAAQ,EAAE,MAAM,GAAG,QAAQ,CAAC;CAC7B;;;;;;;GAgBC,CAAC;AAEL,eAAO,MAAM,cAAc;;;;;;GAKvB,CAAC;AAEL,eAAO,MAAM,uBAAuB;;;;;;GAKhC,CAAC;AAEL,eAAO,MAAM,aAAa;;;;+GAKtB,CAAC;AAEL,eAAO,MAAM,kBAAkB;;;;;;;;GAK3B,CAAC;AAEL,eAAO,MAAM,kBAAkB;;;;gHAK3B,CAAC"}
1
+ {"version":3,"file":"maps.functions.d.ts","sourceRoot":"","sources":["../../src/lib/maps.functions.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,OAAO,CAAC;IACnB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,QAAQ,EAAE;QACR,EAAE,EAAE,MAAM,CAAC;QACX,YAAY,EAAE,MAAM,CAAC;QACrB,cAAc,EAAE,MAAM,CAAC;QACvB,qBAAqB,EAAE,OAAO,CAAC;QAC/B,QAAQ,EAAE,MAAM,GAAG,QAAQ,CAAC;QAC5B,kBAAkB,EAAE,OAAO,CAAC;QAC5B,mBAAmB,EAAE,OAAO,CAAC;QAC7B,kBAAkB,EAAE,OAAO,CAAC;QAC5B,yBAAyB,EAAE,OAAO,CAAC;QACnC,WAAW,EAAE,MAAM,CAAC;QACpB,QAAQ,EAAE,MAAM,CAAC;QACjB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;QACzB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;QAC7B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;QAC3B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;KAC1B,GAAG,IAAI,CAAC;IACT,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;CACnC;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,KAAK,CAAC;QACX,EAAE,EAAE,MAAM,CAAC;QACX,EAAE,EAAE,MAAM,CAAC;QACX,QAAQ,EAAE,MAAM,CAAC;QACjB,IAAI,EAAE,OAAO,GAAG,aAAa,GAAG,WAAW,GAAG,OAAO,GAAG,OAAO,CAAC;QAChE,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC,CAAC;CACJ;AAED,eAAO,MAAM,aAAa;;;;8CAEA;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE;;;0BAO1D,CAAC;AAEL,eAAO,MAAM,eAAe;;;;uEAKxB,CAAC;AAEL,eAAO,MAAM,gBAAgB;;;;0GAKzB,CAAC;AAEL,eAAO,MAAM,kBAAkB;;;;8CAEL;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,qBAAqB,EAAE,OAAO,CAAC;IAC/B,QAAQ,EAAE,MAAM,GAAG,QAAQ,CAAC;IAC5B,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,yBAAyB,CAAC,EAAE,OAAO,CAAC;IACpC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACnC;;;;;;;;;;;;;;GA6BC,CAAC;AAEL,eAAO,MAAM,cAAc;;;;;;GAKvB,CAAC;AAEL,eAAO,MAAM,uBAAuB;;;;;;GAKhC,CAAC;AAEL,eAAO,MAAM,aAAa;;;;+GAKtB,CAAC;AAEL,eAAO,MAAM,kBAAkB;;;;;;;;GAK3B,CAAC;AAEL,eAAO,MAAM,kBAAkB;;;;gHAK3B,CAAC"}
@@ -1,5 +1,15 @@
1
1
  import { createServerFn } from "@tanstack/react-start";
2
- import { requireSupabaseAuth } from "../integrations/supabase/auth-middleware";
2
+ import { requireSupabaseAuth } from "../integrations/supabase/auth-middleware.js";
3
+ export const getMapsErrors = createServerFn({ method: "GET" })
4
+ .middleware([requireSupabaseAuth])
5
+ .inputValidator((input) => ({
6
+ page: Math.max(0, Math.floor(Number(input?.page ?? 0)) || 0),
7
+ pageSize: Math.min(100, Math.max(1, Math.floor(Number(input?.pageSize ?? 10)) || 10)),
8
+ }))
9
+ .handler(async ({ data }) => {
10
+ const { listMapsErrors } = await import("./maps-admin.server");
11
+ return listMapsErrors(data.page, data.pageSize);
12
+ });
3
13
  export const getMapsOverview = createServerFn({ method: "GET" })
4
14
  .middleware([requireSupabaseAuth])
5
15
  .handler(async () => {
@@ -25,6 +35,19 @@ export const updateMapsSettings = createServerFn({ method: "POST" })
25
35
  dailyCallLimit: limit,
26
36
  allowEstimateFallback: Boolean(input.allowEstimateFallback),
27
37
  provider: input.provider === "google" ? "google" : "free",
38
+ ...(input.claimViaRpcEnabled !== undefined && { claimViaRpcEnabled: Boolean(input.claimViaRpcEnabled) }),
39
+ ...(input.perCallLimitEnabled !== undefined && { perCallLimitEnabled: Boolean(input.perCallLimitEnabled) }),
40
+ ...(input.maxAttemptsEnabled !== undefined && { maxAttemptsEnabled: Boolean(input.maxAttemptsEnabled) }),
41
+ ...(input.stopBijSleutelfoutEnabled !== undefined && {
42
+ stopBijSleutelfoutEnabled: Boolean(input.stopBijSleutelfoutEnabled),
43
+ }),
44
+ ...(input.maxAttempts !== undefined && {
45
+ maxAttempts: Math.min(100, Math.max(1, Math.round(Number(input.maxAttempts)) || 3)),
46
+ }),
47
+ ...(typeof input.timezone === "string" && input.timezone.trim() && {
48
+ timezone: input.timezone.trim().slice(0, 64),
49
+ }),
50
+ expectedUpdatedAt: typeof input.expectedUpdatedAt === "string" ? input.expectedUpdatedAt : null,
28
51
  };
29
52
  })
30
53
  .handler(async ({ data }) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flowselections/google-maps-api-installatie-techniek",
3
- "version": "1.0.4",
3
+ "version": "1.1.1",
4
4
  "flowselections": {
5
5
  "moduleId": "maps-installatie",
6
6
  "pages": [
@@ -37,7 +37,8 @@
37
37
  "build:lib:watch": "tsc -p tsconfig.build.json --watch",
38
38
  "build:dev": "vite build --mode development",
39
39
  "preview": "vite preview",
40
- "lint": "eslint ."
40
+ "lint": "eslint .",
41
+ "test": "vitest run --dir src"
41
42
  },
42
43
  "peerDependencies": {
43
44
  "@flowselections/core": "*",
@@ -55,8 +56,8 @@
55
56
  "devDependencies": {
56
57
  "@cloudflare/vite-plugin": "^1.25.5",
57
58
  "@eslint/js": "^9.32.0",
58
- "@flowselections/core": "1.0.29",
59
- "@lovable.dev/vite-tanstack-config": "2.25.2",
59
+ "@flowselections/core": "1.0.37",
60
+ "@lovable.dev/vite-tanstack-config": "2.26.5",
60
61
  "@rsbuild/core": "^1.0.0",
61
62
  "@tailwindcss/vite": "^4.2.1",
62
63
  "@tanstack/react-query": "^5.83.0",
@@ -72,16 +73,17 @@
72
73
  "eslint-plugin-react-refresh": "^0.4.20",
73
74
  "globals": "^15.15.0",
74
75
  "lucide-react": "^0.575.0",
76
+ "nitro": "3.0.260603-beta",
75
77
  "react": "^19.2.0",
76
78
  "react-dom": "^19.2.0",
77
79
  "sonner": "^2.0.7",
78
80
  "tailwindcss": "^4.2.1",
81
+ "tsc-alias": "^1.8.10",
79
82
  "tw-animate-css": "^1.3.4",
80
83
  "typescript": "^5.8.3",
81
- "tsc-alias": "^1.8.10",
82
84
  "typescript-eslint": "^8.56.1",
83
85
  "vite": "^7.3.1",
84
86
  "vite-tsconfig-paths": "^6.0.2",
85
- "nitro": "3.0.260603-beta"
87
+ "vitest": "^3"
86
88
  }
87
89
  }