@flowselections/google-maps-api-installatie-techniek 1.0.4 → 1.0.5
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/components/MapsBeheerPage.js +1 -1
- package/dist-lib/components/maps/MapsDiagnosticsPanel.js +1 -1
- package/dist-lib/components/maps/MapsStatusPanel.d.ts +1 -1
- package/dist-lib/components/maps/MapsStatusPanel.js +1 -1
- package/dist-lib/components/settings/MapsSettingsCard.js +1 -1
- package/dist-lib/integrations/supabase/client.js +1 -1
- package/dist-lib/integrations/supabase/client.server.js +1 -1
- package/dist-lib/integrations/supabase/previewAuthStorage.d.ts +11 -5
- package/dist-lib/integrations/supabase/previewAuthStorage.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/previewAuthStorage.js +59 -24
- package/dist-lib/integrations/supabase/types.d.ts +9752 -61
- package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/types.js +1 -0
- package/dist-lib/lib/maps.functions.d.ts +8 -8
- package/dist-lib/lib/maps.functions.js +1 -1
- package/package.json +3 -3
|
@@ -4,7 +4,7 @@ import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
|
|
4
4
|
import { useServerFn } from "@tanstack/react-start";
|
|
5
5
|
import { Badge, Button, Card, CardContent, CardDescription, CardHeader, CardTitle, Input, Label, Switch, Tabs, TabsContent, TabsList, TabsTrigger, toast, } from "@flowselections/core";
|
|
6
6
|
import { MapPin, RefreshCw, Trash2, Timer } from "lucide-react";
|
|
7
|
-
import { clearMapsCache, getMapsOverview, getMapsStatus, processMapsQueue, purgeExpiredTravelTimes, updateMapsSettings, } from "../lib/maps.functions";
|
|
7
|
+
import { clearMapsCache, getMapsOverview, getMapsStatus, processMapsQueue, purgeExpiredTravelTimes, updateMapsSettings, } from "../lib/maps.functions.js";
|
|
8
8
|
import { MapsStatusPanel } from "./maps/MapsStatusPanel";
|
|
9
9
|
import { MapsDiagnosticsPanel } from "./maps/MapsDiagnosticsPanel";
|
|
10
10
|
function Stat({ label, value }) {
|
|
@@ -5,7 +5,7 @@ import { useState } from "react";
|
|
|
5
5
|
import { useServerFn } from "@tanstack/react-start";
|
|
6
6
|
import { Badge, Button, Card, CardContent, CardDescription, CardHeader, CardTitle, } from "@flowselections/core";
|
|
7
7
|
import { AlertTriangle, CheckCircle2, ClipboardCopy, Loader2, XCircle, } from "lucide-react";
|
|
8
|
-
import { getMapsDiagnostics } from "../../lib/maps.functions";
|
|
8
|
+
import { getMapsDiagnostics } from "../../lib/maps.functions.js";
|
|
9
9
|
function formatDateTime(value) {
|
|
10
10
|
const parsed = Date.parse(value);
|
|
11
11
|
if (Number.isNaN(parsed))
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { MapsConnectionStatus } from "../../lib/central-auth.server";
|
|
1
|
+
import type { MapsConnectionStatus } from "../../lib/central-auth.server.js";
|
|
2
2
|
export declare function MapsStatusPanel({ status, }: {
|
|
3
3
|
status: MapsConnectionStatus | null;
|
|
4
4
|
}): import("react").JSX.Element;
|
|
@@ -6,7 +6,7 @@ import { useServerFn } from "@tanstack/react-start";
|
|
|
6
6
|
import { useQuery } from "@tanstack/react-query";
|
|
7
7
|
import { Badge, Button, Card, CardContent, CardDescription, CardHeader, CardTitle, toast, } from "@flowselections/core";
|
|
8
8
|
import { AlertTriangle, CheckCircle2, RefreshCw, ShieldCheck, XCircle, } from "lucide-react";
|
|
9
|
-
import { getMapsOverview, testMapsConnection } from "../../lib/maps.functions";
|
|
9
|
+
import { getMapsOverview, testMapsConnection } from "../../lib/maps.functions.js";
|
|
10
10
|
function formatDateTime(value) {
|
|
11
11
|
if (!value)
|
|
12
12
|
return "onbekend";
|
|
@@ -4,7 +4,7 @@ import { useServerFn } from "@tanstack/react-start";
|
|
|
4
4
|
import { Badge, Button, Card, CardContent, CardDescription, CardHeader, CardTitle, } from "@flowselections/core";
|
|
5
5
|
import { Link } from "@tanstack/react-router";
|
|
6
6
|
import { MapPin } from "lucide-react";
|
|
7
|
-
import { getMapsOverview } from "../../lib/maps.functions";
|
|
7
|
+
import { getMapsOverview } from "../../lib/maps.functions.js";
|
|
8
8
|
export function MapsSettingsCard() {
|
|
9
9
|
const fetchOverview = useServerFn(getMapsOverview);
|
|
10
10
|
const { data } = useQuery({
|
|
@@ -19,7 +19,7 @@ function createSupabaseClient() {
|
|
|
19
19
|
}
|
|
20
20
|
let _supabase;
|
|
21
21
|
// Import the supabase client like this:
|
|
22
|
-
// import { supabase } from "
|
|
22
|
+
// import { supabase } from "./client.js";
|
|
23
23
|
export const supabase = new Proxy({}, {
|
|
24
24
|
get(_, prop, receiver) {
|
|
25
25
|
if (!_supabase)
|
|
@@ -20,7 +20,7 @@ function createSupabaseAdminClient() {
|
|
|
20
20
|
let _supabaseAdmin;
|
|
21
21
|
// Server-side Supabase client with service role - bypasses RLS
|
|
22
22
|
// SECURITY: Only use this for trusted server-side operations, never expose to client code
|
|
23
|
-
// Import like: import { supabaseAdmin } from "
|
|
23
|
+
// Import like: import { supabaseAdmin } from "./client.server.js";
|
|
24
24
|
export const supabaseAdmin = new Proxy({}, {
|
|
25
25
|
get(_, prop, receiver) {
|
|
26
26
|
if (!_supabaseAdmin)
|
|
@@ -1,6 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
/** Storage accepted by Supabase's `auth.storage` option; `localStorage` and the editor broker both satisfy it. */
|
|
2
|
+
export interface PreviewAuthStorage {
|
|
3
|
+
getItem: (key: string) => string | null | Promise<string | null>;
|
|
4
|
+
setItem: (key: string, value: string) => void | Promise<void>;
|
|
5
|
+
removeItem: (key: string) => void | Promise<void>;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* On a Lovable preview surface, broker the auth session to the editor over
|
|
9
|
+
* postMessage so the project's preview surfaces share one login; else localStorage.
|
|
10
|
+
*/
|
|
11
|
+
export declare function brokeredPreviewStorage(): PreviewAuthStorage | undefined;
|
|
6
12
|
//# sourceMappingURL=previewAuthStorage.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"previewAuthStorage.d.ts","sourceRoot":"","sources":["../../../src/integrations/supabase/previewAuthStorage.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"previewAuthStorage.d.ts","sourceRoot":"","sources":["../../../src/integrations/supabase/previewAuthStorage.ts"],"names":[],"mappings":"AAEA,kHAAkH;AAClH,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACjE,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9D,UAAU,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACnD;AA6BD;;;GAGG;AACH,wBAAgB,sBAAsB,IAAI,kBAAkB,GAAG,SAAS,CAsGvE"}
|
|
@@ -1,6 +1,21 @@
|
|
|
1
1
|
// This file is automatically generated. Do not edit it directly.
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
const RESULT = 'lovable-preview-auth:result';
|
|
3
|
+
function readBrokerReply(data, requestId) {
|
|
4
|
+
if (typeof data !== 'object' || data === null)
|
|
5
|
+
return null;
|
|
6
|
+
if (!('type' in data) || data.type !== RESULT)
|
|
7
|
+
return null;
|
|
8
|
+
if (!('requestId' in data) || data.requestId !== requestId)
|
|
9
|
+
return null;
|
|
10
|
+
return {
|
|
11
|
+
ok: 'ok' in data && Boolean(data.ok),
|
|
12
|
+
value: 'value' in data && typeof data.value === 'string' ? data.value : null,
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* On a Lovable preview surface, broker the auth session to the editor over
|
|
17
|
+
* postMessage so the project's preview surfaces share one login; else localStorage.
|
|
18
|
+
*/
|
|
4
19
|
export function brokeredPreviewStorage() {
|
|
5
20
|
if (typeof window === 'undefined')
|
|
6
21
|
return undefined;
|
|
@@ -11,10 +26,13 @@ export function brokeredPreviewStorage() {
|
|
|
11
26
|
// preview--<name> host can't smuggle another project's id.
|
|
12
27
|
const UUID = '[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}';
|
|
13
28
|
const projectId = onPreviewZone
|
|
14
|
-
? (
|
|
15
|
-
??
|
|
29
|
+
? (new RegExp('^(?:id-preview(?:-[a-z0-9]+)?|project)--(' + UUID + ')(?:-dev)?(?=\\.|$)', 'i').exec(host)?.[1]
|
|
30
|
+
?? new RegExp('^(' + UUID + ')(?=[.-])', 'i').exec(host)?.[1])
|
|
16
31
|
: undefined;
|
|
17
|
-
|
|
32
|
+
// lib.dom types window.parent and location.ancestorOrigins as always set, but a
|
|
33
|
+
// detached frame has no parent and not every browser implements ancestorOrigins.
|
|
34
|
+
const parentWindow = window.parent;
|
|
35
|
+
const framed = parentWindow !== null && parentWindow !== window;
|
|
18
36
|
if (!projectId || !framed)
|
|
19
37
|
return localStorage;
|
|
20
38
|
// Post only to the real editor ancestor, validated as a Lovable origin, so the
|
|
@@ -23,59 +41,75 @@ export function brokeredPreviewStorage() {
|
|
|
23
41
|
const EDITOR = dev
|
|
24
42
|
? /^https:\/\/([a-z0-9-]+\.)*(lovable\.dev|gptengineer\.app)$|^http:\/\/localhost:3000$/
|
|
25
43
|
: /^https:\/\/([a-z0-9-]+\.)*(lovable\.dev|gptengineer\.app)$/;
|
|
26
|
-
const
|
|
44
|
+
const ancestorOrigins = location.ancestorOrigins;
|
|
45
|
+
const ancestor = ancestorOrigins?.[0] ?? (document.referrer ? new URL(document.referrer).origin : '');
|
|
27
46
|
const editorOrigins = ancestor && EDITOR.test(ancestor)
|
|
28
47
|
? [ancestor]
|
|
29
48
|
: (dev ? ['https://lovable.dev', 'http://localhost:3000'] : ['https://lovable.dev']);
|
|
30
|
-
const RESULT = 'lovable-preview-auth:result';
|
|
31
49
|
const TIMEOUT = 2000;
|
|
32
50
|
const newId = () => Math.random().toString(36).slice(2) + Date.now().toString(36);
|
|
33
51
|
const request = (type, key, value) => new Promise((resolve) => {
|
|
34
52
|
const requestId = newId();
|
|
35
53
|
let done = false;
|
|
36
|
-
|
|
37
|
-
const finish = (r) => {
|
|
54
|
+
const finish = (reply) => {
|
|
38
55
|
if (done)
|
|
39
56
|
return;
|
|
40
57
|
done = true;
|
|
41
58
|
clearTimeout(timer);
|
|
42
59
|
window.removeEventListener('message', onMessage);
|
|
43
|
-
resolve(
|
|
60
|
+
resolve(reply);
|
|
44
61
|
};
|
|
45
62
|
const onMessage = (e) => {
|
|
46
|
-
if (editorOrigins.
|
|
63
|
+
if (!editorOrigins.includes(e.origin))
|
|
47
64
|
return;
|
|
48
|
-
const
|
|
49
|
-
if (
|
|
50
|
-
finish(
|
|
65
|
+
const reply = readBrokerReply(e.data, requestId);
|
|
66
|
+
if (reply)
|
|
67
|
+
finish(reply);
|
|
51
68
|
};
|
|
52
69
|
window.addEventListener('message', onMessage);
|
|
70
|
+
const timer = setTimeout(() => { finish(null); }, TIMEOUT);
|
|
53
71
|
const msg = { type, requestId, projectId, key };
|
|
54
72
|
if (value !== undefined)
|
|
55
|
-
msg
|
|
73
|
+
msg.value = value;
|
|
56
74
|
// targetOrigin per trusted editor origin, so a session token never reaches an arbitrary embedder.
|
|
57
75
|
for (const origin of editorOrigins)
|
|
58
76
|
window.parent.postMessage(msg, origin);
|
|
59
|
-
timer = setTimeout(() => finish(null), TIMEOUT);
|
|
60
77
|
});
|
|
61
78
|
// The editor may not be listening yet at the first getItem, so retry once.
|
|
62
79
|
let firstGet = true;
|
|
63
80
|
const RETRY_DELAY = 250;
|
|
81
|
+
// Blocked third-party storage throws here; seeding must not break broker reads.
|
|
82
|
+
const readLocal = (key) => { try {
|
|
83
|
+
return localStorage.getItem(key);
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
return undefined;
|
|
87
|
+
} };
|
|
64
88
|
return {
|
|
65
89
|
getItem: async (key) => {
|
|
66
|
-
|
|
90
|
+
// Sent with GET and REMOVE so an editor that never cached this session can check or revoke it.
|
|
91
|
+
const local = readLocal(key);
|
|
92
|
+
let res = await request('lovable-preview-auth:get', key, local ?? undefined);
|
|
67
93
|
if (!res && firstGet) {
|
|
68
|
-
await new Promise((
|
|
69
|
-
res = await request('lovable-preview-auth:get', key);
|
|
94
|
+
await new Promise((resolve) => setTimeout(resolve, RETRY_DELAY));
|
|
95
|
+
res = await request('lovable-preview-auth:get', key, local ?? undefined);
|
|
70
96
|
}
|
|
71
97
|
firstGet = false;
|
|
72
98
|
// '' is the logout tombstone: clear the local copy too so it can't resurrect if
|
|
73
|
-
// the broker later goes silent. A null
|
|
74
|
-
if (res
|
|
99
|
+
// the broker later goes silent. A null value means never-synced -> keep local.
|
|
100
|
+
if (res?.ok && res.value !== null) {
|
|
75
101
|
if (res.value === '') {
|
|
76
|
-
|
|
102
|
+
if (local !== undefined && readLocal(key) === local)
|
|
103
|
+
localStorage.removeItem(key);
|
|
77
104
|
return null;
|
|
78
105
|
}
|
|
106
|
+
// Seed this origin so a new tab, whose editor holds no session, stays signed in.
|
|
107
|
+
if (local === null && readLocal(key) === null) {
|
|
108
|
+
try {
|
|
109
|
+
localStorage.setItem(key, res.value);
|
|
110
|
+
}
|
|
111
|
+
catch { /* storage full: still return the editor's session */ }
|
|
112
|
+
}
|
|
79
113
|
return res.value;
|
|
80
114
|
}
|
|
81
115
|
return localStorage.getItem(key);
|
|
@@ -83,7 +117,7 @@ export function brokeredPreviewStorage() {
|
|
|
83
117
|
setItem: (key, value) => {
|
|
84
118
|
localStorage.setItem(key, value);
|
|
85
119
|
return request('lovable-preview-auth:set', key, value).then((res) => {
|
|
86
|
-
if (res
|
|
120
|
+
if (res?.ok && res.value !== null && localStorage.getItem(key) === value) {
|
|
87
121
|
if (res.value === '')
|
|
88
122
|
localStorage.removeItem(key);
|
|
89
123
|
else
|
|
@@ -92,8 +126,9 @@ export function brokeredPreviewStorage() {
|
|
|
92
126
|
});
|
|
93
127
|
},
|
|
94
128
|
removeItem: (key) => {
|
|
129
|
+
const local = readLocal(key);
|
|
95
130
|
localStorage.removeItem(key);
|
|
96
|
-
return request('lovable-preview-auth:remove', key).then(() =>
|
|
131
|
+
return request('lovable-preview-auth:remove', key, local ?? undefined).then(() => { });
|
|
97
132
|
},
|
|
98
133
|
};
|
|
99
134
|
}
|