@creezio/shell-ui 0.22.0
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/README.md +336 -0
- package/dist/adapters/nav-shell.d.ts +54 -0
- package/dist/adapters/nav-shell.d.ts.map +1 -0
- package/dist/adapters/nav-shell.js +112 -0
- package/dist/adapters/nav-shell.js.map +1 -0
- package/dist/brand.d.ts +64 -0
- package/dist/brand.d.ts.map +1 -0
- package/dist/brand.js +59 -0
- package/dist/brand.js.map +1 -0
- package/dist/core-nav.d.ts +17 -0
- package/dist/core-nav.d.ts.map +1 -0
- package/dist/core-nav.js +40 -0
- package/dist/core-nav.js.map +1 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +24 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/api-scopes.d.ts +24 -0
- package/dist/lib/api-scopes.d.ts.map +1 -0
- package/dist/lib/api-scopes.js +78 -0
- package/dist/lib/api-scopes.js.map +1 -0
- package/dist/lib/catalog-suspense-key.d.ts +3 -0
- package/dist/lib/catalog-suspense-key.d.ts.map +1 -0
- package/dist/lib/catalog-suspense-key.js +12 -0
- package/dist/lib/catalog-suspense-key.js.map +1 -0
- package/dist/lib/data-changed.d.ts +51 -0
- package/dist/lib/data-changed.d.ts.map +1 -0
- package/dist/lib/data-changed.js +227 -0
- package/dist/lib/data-changed.js.map +1 -0
- package/dist/lib/desktop-home-path.d.ts +14 -0
- package/dist/lib/desktop-home-path.d.ts.map +1 -0
- package/dist/lib/desktop-home-path.js +29 -0
- package/dist/lib/desktop-home-path.js.map +1 -0
- package/dist/lib/geo-distance.d.ts +6 -0
- package/dist/lib/geo-distance.d.ts.map +1 -0
- package/dist/lib/geo-distance.js +27 -0
- package/dist/lib/geo-distance.js.map +1 -0
- package/dist/lib/img.d.ts +2 -0
- package/dist/lib/img.d.ts.map +1 -0
- package/dist/lib/img.js +40 -0
- package/dist/lib/img.js.map +1 -0
- package/dist/lib/keepalive-eviction.d.ts +14 -0
- package/dist/lib/keepalive-eviction.d.ts.map +1 -0
- package/dist/lib/keepalive-eviction.js +44 -0
- package/dist/lib/keepalive-eviction.js.map +1 -0
- package/dist/lib/ops-track.d.ts +29 -0
- package/dist/lib/ops-track.d.ts.map +1 -0
- package/dist/lib/ops-track.js +37 -0
- package/dist/lib/ops-track.js.map +1 -0
- package/dist/lib/optimize-cover-url.d.ts +10 -0
- package/dist/lib/optimize-cover-url.d.ts.map +1 -0
- package/dist/lib/optimize-cover-url.js +80 -0
- package/dist/lib/optimize-cover-url.js.map +1 -0
- package/dist/lib/page-trails.d.ts +9 -0
- package/dist/lib/page-trails.d.ts.map +1 -0
- package/dist/lib/page-trails.js +20 -0
- package/dist/lib/page-trails.js.map +1 -0
- package/dist/lib/public-origin.d.ts +32 -0
- package/dist/lib/public-origin.d.ts.map +1 -0
- package/dist/lib/public-origin.js +125 -0
- package/dist/lib/public-origin.js.map +1 -0
- package/dist/lib/server-incident.d.ts +12 -0
- package/dist/lib/server-incident.d.ts.map +1 -0
- package/dist/lib/server-incident.js +72 -0
- package/dist/lib/server-incident.js.map +1 -0
- package/dist/lib/tab-document-url.d.ts +13 -0
- package/dist/lib/tab-document-url.d.ts.map +1 -0
- package/dist/lib/tab-document-url.js +60 -0
- package/dist/lib/tab-document-url.js.map +1 -0
- package/dist/lib/utils.d.ts +20 -0
- package/dist/lib/utils.d.ts.map +1 -0
- package/dist/lib/utils.js +87 -0
- package/dist/lib/utils.js.map +1 -0
- package/dist/nav-catalog.d.ts +97 -0
- package/dist/nav-catalog.d.ts.map +1 -0
- package/dist/nav-catalog.js +282 -0
- package/dist/nav-catalog.js.map +1 -0
- package/dist/registry.d.ts +11 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +60 -0
- package/dist/registry.js.map +1 -0
- package/dist/types.d.ts +22 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist-cjs/adapters/nav-shell.js +115 -0
- package/dist-cjs/adapters/nav-shell.js.map +1 -0
- package/dist-cjs/brand.js +66 -0
- package/dist-cjs/brand.js.map +1 -0
- package/dist-cjs/core-nav.js +43 -0
- package/dist-cjs/core-nav.js.map +1 -0
- package/dist-cjs/index.js +95 -0
- package/dist-cjs/index.js.map +1 -0
- package/dist-cjs/lib/api-scopes.js +86 -0
- package/dist-cjs/lib/api-scopes.js.map +1 -0
- package/dist-cjs/lib/catalog-suspense-key.js +15 -0
- package/dist-cjs/lib/catalog-suspense-key.js.map +1 -0
- package/dist-cjs/lib/data-changed.js +236 -0
- package/dist-cjs/lib/data-changed.js.map +1 -0
- package/dist-cjs/lib/desktop-home-path.js +34 -0
- package/dist-cjs/lib/desktop-home-path.js.map +1 -0
- package/dist-cjs/lib/geo-distance.js +30 -0
- package/dist-cjs/lib/geo-distance.js.map +1 -0
- package/dist-cjs/lib/img.js +43 -0
- package/dist-cjs/lib/img.js.map +1 -0
- package/dist-cjs/lib/keepalive-eviction.js +49 -0
- package/dist-cjs/lib/keepalive-eviction.js.map +1 -0
- package/dist-cjs/lib/ops-track.js +41 -0
- package/dist-cjs/lib/ops-track.js.map +1 -0
- package/dist-cjs/lib/optimize-cover-url.js +83 -0
- package/dist-cjs/lib/optimize-cover-url.js.map +1 -0
- package/dist-cjs/lib/page-trails.js +25 -0
- package/dist-cjs/lib/page-trails.js.map +1 -0
- package/dist-cjs/lib/public-origin.js +130 -0
- package/dist-cjs/lib/public-origin.js.map +1 -0
- package/dist-cjs/lib/server-incident.js +75 -0
- package/dist-cjs/lib/server-incident.js.map +1 -0
- package/dist-cjs/lib/tab-document-url.js +65 -0
- package/dist-cjs/lib/tab-document-url.js.map +1 -0
- package/dist-cjs/lib/utils.js +97 -0
- package/dist-cjs/lib/utils.js.map +1 -0
- package/dist-cjs/nav-catalog.js +293 -0
- package/dist-cjs/nav-catalog.js.map +1 -0
- package/dist-cjs/package.json +3 -0
- package/dist-cjs/registry.js +64 -0
- package/dist-cjs/registry.js.map +1 -0
- package/dist-cjs/types.js +3 -0
- package/dist-cjs/types.js.map +1 -0
- package/package.json +163 -0
- package/ui/app-error-boundary.tsx +59 -0
- package/ui/data-table.tsx +121 -0
- package/ui/desktop/auth-window-chrome.tsx +51 -0
- package/ui/desktop/desktop-bridge.tsx +87 -0
- package/ui/desktop/external-site-slot.tsx +313 -0
- package/ui/desktop/external-site-surface.ts +58 -0
- package/ui/desktop/site-link.tsx +105 -0
- package/ui/desktop/window-chrome-controls.tsx +5 -0
- package/ui/desktop-types.ts +30 -0
- package/ui/faceted-filters.tsx +119 -0
- package/ui/global-search-host.ts +20 -0
- package/ui/global-search.tsx +66 -0
- package/ui/index.ts +178 -0
- package/ui/kit.ts +30 -0
- package/ui/layout/app-shell.tsx +58 -0
- package/ui/layout/desktop-update-banner.tsx +100 -0
- package/ui/layout/entity-header.tsx +44 -0
- package/ui/layout/native-os-nav.ts +104 -0
- package/ui/layout/nav-catalog-loader.tsx +98 -0
- package/ui/layout/nav-icons.ts +67 -0
- package/ui/layout/page-chrome.tsx +90 -0
- package/ui/layout/page-toolbar-context.tsx +82 -0
- package/ui/layout/sandbox-banner.tsx +38 -0
- package/ui/layout/section-view-shell.tsx +73 -0
- package/ui/layout/sidebar-host.ts +144 -0
- package/ui/layout/sidebar.tsx +1150 -0
- package/ui/lib/ai-screencast-hub.ts +127 -0
- package/ui/lib/ai-workspace-client.ts +46 -0
- package/ui/lib/aid.ts +22 -0
- package/ui/lib/desktop-host.ts +114 -0
- package/ui/lib/fleet-tracker-client.ts +237 -0
- package/ui/lib/hermes-ui.ts +114 -0
- package/ui/lib/n8n-ui.ts +115 -0
- package/ui/lib/use-creezio-resource.tsx +121 -0
- package/ui/lib/use-shell-ui-brand.ts +22 -0
- package/ui/list-toolbar.tsx +309 -0
- package/ui/os-pages/desktop-settings-page.tsx +158 -0
- package/ui/os-pages/index.ts +8 -0
- package/ui/page-loading/entity-page-loading.tsx +59 -0
- package/ui/page-loading/list-page-loading.tsx +61 -0
- package/ui/pagination.tsx +56 -0
- package/ui/primitives/avatar.tsx +33 -0
- package/ui/primitives/badge.tsx +36 -0
- package/ui/primitives/breadcrumb.tsx +93 -0
- package/ui/primitives/button.tsx +44 -0
- package/ui/primitives/card.tsx +44 -0
- package/ui/primitives/chart.tsx +317 -0
- package/ui/primitives/command.tsx +111 -0
- package/ui/primitives/dialog.tsx +100 -0
- package/ui/primitives/dropdown-menu.tsx +187 -0
- package/ui/primitives/input.tsx +19 -0
- package/ui/primitives/label.tsx +17 -0
- package/ui/primitives/resizable.tsx +45 -0
- package/ui/primitives/scroll-area.tsx +41 -0
- package/ui/primitives/select.tsx +73 -0
- package/ui/primitives/separator.tsx +26 -0
- package/ui/primitives/sheet.tsx +90 -0
- package/ui/primitives/skeleton.tsx +7 -0
- package/ui/primitives/sonner.tsx +22 -0
- package/ui/primitives/tabs.tsx +51 -0
- package/ui/primitives/textarea.tsx +22 -0
- package/ui/primitives/tooltip.tsx +31 -0
- package/ui/pwa/client-error-reporter.tsx +62 -0
- package/ui/pwa/register-sw.tsx +50 -0
- package/ui/range-filters.tsx +174 -0
- package/ui/search/global-search-config.ts +32 -0
- package/ui/search/global-search-provider.tsx +528 -0
- package/ui/search/search-history.ts +74 -0
- package/ui/search-input.tsx +146 -0
- package/ui/settings/account-settings.tsx +140 -0
- package/ui/settings/agent-profile-settings.tsx +184 -0
- package/ui/settings/api-keys-settings.tsx +349 -0
- package/ui/settings/desktop-background-settings.tsx +128 -0
- package/ui/settings/desktop-connection-settings.tsx +251 -0
- package/ui/settings/desktop-embed-env-panel.tsx +257 -0
- package/ui/settings/desktop-fleet-telemetry-settings.tsx +269 -0
- package/ui/settings/desktop-hermes-settings.tsx +341 -0
- package/ui/settings/desktop-llm-keys.tsx +192 -0
- package/ui/settings/desktop-n8n-settings.tsx +306 -0
- package/ui/settings/desktop-tunnel.tsx +264 -0
- package/ui/settings/desktop-update-settings.tsx +175 -0
- package/ui/settings/factory-reset-settings.tsx +89 -0
- package/ui/settings/host-only-settings.tsx +62 -0
- package/ui/settings/locked-config-field.tsx +30 -0
- package/ui/settings/ops-diagnostic-settings.tsx +242 -0
- package/ui/settings/search-reindex-settings.tsx +158 -0
- package/ui/settings/server-mode-cards.tsx +801 -0
- package/ui/theme/tailwind-preset.cjs +82 -0
- package/ui/theme/theme.css +328 -0
- package/ui/workspace/ai-activity-panel-host.tsx +19 -0
- package/ui/workspace/ai-workspace-agent-host.tsx +54 -0
- package/ui/workspace/ai-workspace-banner.tsx +168 -0
- package/ui/workspace/impersonation-banner.tsx +39 -0
- package/ui/workspace/keep-alive.tsx +220 -0
- package/ui/workspace/tab-workspace-context.tsx +1172 -0
- package/ui/workspace/tab-workspace-host.ts +89 -0
- package/ui/workspace/types.ts +500 -0
- package/ui/workspace/use-location-search.tsx +50 -0
- package/ui/workspace/window-chrome-controls.tsx +116 -0
- package/ui/workspace/workspace-config.ts +47 -0
- package/ui/workspace/workspace-root.tsx +147 -0
- package/ui/workspace/workspace-shell.tsx +292 -0
- package/ui/workspace/workspace-tab-bar.tsx +572 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Distance géodésique (haversine) — logique pure, testable.
|
|
3
|
+
*/
|
|
4
|
+
const EARTH_RADIUS_KM = 6371;
|
|
5
|
+
function toRad(deg) {
|
|
6
|
+
return (deg * Math.PI) / 180;
|
|
7
|
+
}
|
|
8
|
+
/** Distance en km entre deux points WGS84. Retourne null si coords invalides. */
|
|
9
|
+
export function haversineKm(lat1, lng1, lat2, lng2) {
|
|
10
|
+
if (lat1 == null ||
|
|
11
|
+
lng1 == null ||
|
|
12
|
+
lat2 == null ||
|
|
13
|
+
lng2 == null ||
|
|
14
|
+
!Number.isFinite(lat1) ||
|
|
15
|
+
!Number.isFinite(lng1) ||
|
|
16
|
+
!Number.isFinite(lat2) ||
|
|
17
|
+
!Number.isFinite(lng2)) {
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
const dLat = toRad(lat2 - lat1);
|
|
21
|
+
const dLng = toRad(lng2 - lng1);
|
|
22
|
+
const a = Math.sin(dLat / 2) ** 2 +
|
|
23
|
+
Math.cos(toRad(lat1)) * Math.cos(toRad(lat2)) * Math.sin(dLng / 2) ** 2;
|
|
24
|
+
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
|
|
25
|
+
return Math.round(EARTH_RADIUS_KM * c * 10) / 10;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=geo-distance.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"geo-distance.js","sourceRoot":"","sources":["../../src/lib/geo-distance.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,eAAe,GAAG,IAAI,CAAC;AAE7B,SAAS,KAAK,CAAC,GAAW;IACxB,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC;AAC/B,CAAC;AAED,iFAAiF;AACjF,MAAM,UAAU,WAAW,CACzB,IAA+B,EAC/B,IAA+B,EAC/B,IAA+B,EAC/B,IAA+B;IAE/B,IACE,IAAI,IAAI,IAAI;QACZ,IAAI,IAAI,IAAI;QACZ,IAAI,IAAI,IAAI;QACZ,IAAI,IAAI,IAAI;QACZ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC;QACtB,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC;QACtB,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC;QACtB,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,EACtB,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC;IAChC,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC;IAChC,MAAM,CAAC,GACL,IAAI,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC;QACvB,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC;IAC1E,MAAM,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IACzD,OAAO,IAAI,CAAC,KAAK,CAAC,eAAe,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,EAAE,CAAC;AACnD,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"img.d.ts","sourceRoot":"","sources":["../../src/lib/img.ts"],"names":[],"mappings":"AAMA,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAAE,KAAK,SAAM,GAAG,MAAM,GAAG,IAAI,CAuCnF"}
|
package/dist/lib/img.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Réécrit les URLs d'images externes vers leur variante miniature CDN.
|
|
3
|
+
* Évite de charger des originaux de 20+ Mpx dans des cartes de 300 px.
|
|
4
|
+
*/
|
|
5
|
+
const WIKIMEDIA_SIZES = [330, 500, 960]; // seules tailles acceptées par upload.wikimedia.org
|
|
6
|
+
export function thumbUrl(url, width = 500) {
|
|
7
|
+
if (!url)
|
|
8
|
+
return null;
|
|
9
|
+
let u;
|
|
10
|
+
try {
|
|
11
|
+
u = new URL(url);
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
return url;
|
|
15
|
+
}
|
|
16
|
+
if (u.host === "upload.wikimedia.org" &&
|
|
17
|
+
u.pathname.includes("/commons/") &&
|
|
18
|
+
!u.pathname.includes("/thumb/")) {
|
|
19
|
+
const size = WIKIMEDIA_SIZES.find((s) => s >= width) ?? 960;
|
|
20
|
+
const file = u.pathname.split("/").pop();
|
|
21
|
+
if (!file)
|
|
22
|
+
return url;
|
|
23
|
+
return `https://upload.wikimedia.org${u.pathname.replace("/commons/", "/commons/thumb/")}/${size}px-${file}`;
|
|
24
|
+
}
|
|
25
|
+
if (u.host === "images.pexels.com") {
|
|
26
|
+
u.search = "";
|
|
27
|
+
u.searchParams.set("auto", "compress");
|
|
28
|
+
u.searchParams.set("cs", "tinysrgb");
|
|
29
|
+
u.searchParams.set("w", String(width));
|
|
30
|
+
return u.toString();
|
|
31
|
+
}
|
|
32
|
+
if (u.host === "images.unsplash.com") {
|
|
33
|
+
u.searchParams.set("auto", "format");
|
|
34
|
+
u.searchParams.set("w", String(width));
|
|
35
|
+
u.searchParams.set("q", "70");
|
|
36
|
+
return u.toString();
|
|
37
|
+
}
|
|
38
|
+
return url; // S3 fournisseur et autres : inchangé
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=img.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"img.js","sourceRoot":"","sources":["../../src/lib/img.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,eAAe,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAU,CAAC,CAAC,oDAAoD;AAEtG,MAAM,UAAU,QAAQ,CAAC,GAA8B,EAAE,KAAK,GAAG,GAAG;IAClE,IAAI,CAAC,GAAG;QAAE,OAAO,IAAI,CAAC;IACtB,IAAI,CAAM,CAAC;IACX,IAAI,CAAC;QACH,CAAC,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;IACnB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,GAAG,CAAC;IACb,CAAC;IAED,IACE,CAAC,CAAC,IAAI,KAAK,sBAAsB;QACjC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,WAAW,CAAC;QAChC,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,SAAS,CAAC,EAC/B,CAAC;QACD,MAAM,IAAI,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,KAAK,CAAC,IAAI,GAAG,CAAC;QAC5D,MAAM,IAAI,GAAG,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC;QACzC,IAAI,CAAC,IAAI;YAAE,OAAO,GAAG,CAAC;QACtB,OAAO,+BAA+B,CAAC,CAAC,QAAQ,CAAC,OAAO,CACtD,WAAW,EACX,iBAAiB,CAClB,IAAI,IAAI,MAAM,IAAI,EAAE,CAAC;IACxB,CAAC;IAED,IAAI,CAAC,CAAC,IAAI,KAAK,mBAAmB,EAAE,CAAC;QACnC,CAAC,CAAC,MAAM,GAAG,EAAE,CAAC;QACd,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;QACvC,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;QACrC,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QACvC,OAAO,CAAC,CAAC,QAAQ,EAAE,CAAC;IACtB,CAAC;IAED,IAAI,CAAC,CAAC,IAAI,KAAK,qBAAqB,EAAE,CAAC;QACrC,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QACrC,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QACvC,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QAC9B,OAAO,CAAC,CAAC,QAAQ,EAAE,CAAC;IACtB,CAAC;IAED,OAAO,GAAG,CAAC,CAAC,sCAAsC;AACpD,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Politique d'éviction keep-alive (pur / testable).
|
|
3
|
+
* Les panes fullscreen (`/site/*` + matchers marque) ne sont jamais évincées.
|
|
4
|
+
*/
|
|
5
|
+
export declare function configureKeepAliveFullscreenMatchers(matchers: Array<(href: string) => boolean>): void;
|
|
6
|
+
export declare function isKeepAliveProtectedKey(key: string): boolean;
|
|
7
|
+
/**
|
|
8
|
+
* Clés évinçables (plus anciennes d'abord), hors display/route et hors protégées.
|
|
9
|
+
*/
|
|
10
|
+
export declare function rankKeepAliveEvictionKeys(keys: string[], lastActiveAt: Record<string, number>, opts: {
|
|
11
|
+
displayKey: string;
|
|
12
|
+
routeKey: string;
|
|
13
|
+
}): string[];
|
|
14
|
+
//# sourceMappingURL=keepalive-eviction.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keepalive-eviction.d.ts","sourceRoot":"","sources":["../../src/lib/keepalive-eviction.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAOH,wBAAgB,oCAAoC,CAClD,QAAQ,EAAE,KAAK,CAAC,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,GACzC,IAAI,CAEN;AAuBD,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAE5D;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CACvC,IAAI,EAAE,MAAM,EAAE,EACd,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EACpC,IAAI,EAAE;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAC7C,MAAM,EAAE,CASV"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Politique d'éviction keep-alive (pur / testable).
|
|
3
|
+
* Les panes fullscreen (`/site/*` + matchers marque) ne sont jamais évincées.
|
|
4
|
+
*/
|
|
5
|
+
const DASHBOARD_PATH = "/dashboard";
|
|
6
|
+
/** Matchers fullscreen injectables (marque) — ex. canvas Optimiser TF. */
|
|
7
|
+
let fullscreenMatchers = [];
|
|
8
|
+
export function configureKeepAliveFullscreenMatchers(matchers) {
|
|
9
|
+
fullscreenMatchers = matchers;
|
|
10
|
+
}
|
|
11
|
+
function normalizeHref(href) {
|
|
12
|
+
try {
|
|
13
|
+
const url = new URL(href, "http://local.invalid");
|
|
14
|
+
const path = url.pathname === "/" ? DASHBOARD_PATH : url.pathname || "/";
|
|
15
|
+
const search = url.search || "";
|
|
16
|
+
return `${path}${search}`;
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
return href.split("#")[0] || "/";
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
function isExternalSiteHref(href) {
|
|
23
|
+
const path = normalizeHref(href).split("?")[0] || "/";
|
|
24
|
+
return path === "/site" || path.startsWith("/site/");
|
|
25
|
+
}
|
|
26
|
+
function isFullscreenHref(href) {
|
|
27
|
+
if (isExternalSiteHref(href))
|
|
28
|
+
return true;
|
|
29
|
+
return fullscreenMatchers.some((m) => m(href));
|
|
30
|
+
}
|
|
31
|
+
export function isKeepAliveProtectedKey(key) {
|
|
32
|
+
return isFullscreenHref(normalizeHref(key));
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Clés évinçables (plus anciennes d'abord), hors display/route et hors protégées.
|
|
36
|
+
*/
|
|
37
|
+
export function rankKeepAliveEvictionKeys(keys, lastActiveAt, opts) {
|
|
38
|
+
return keys
|
|
39
|
+
.filter((key) => key !== opts.displayKey &&
|
|
40
|
+
key !== opts.routeKey &&
|
|
41
|
+
!isKeepAliveProtectedKey(key))
|
|
42
|
+
.sort((a, b) => (lastActiveAt[a] || 0) - (lastActiveAt[b] || 0));
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=keepalive-eviction.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keepalive-eviction.js","sourceRoot":"","sources":["../../src/lib/keepalive-eviction.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,cAAc,GAAG,YAAY,CAAC;AAEpC,0EAA0E;AAC1E,IAAI,kBAAkB,GAAqC,EAAE,CAAC;AAE9D,MAAM,UAAU,oCAAoC,CAClD,QAA0C;IAE1C,kBAAkB,GAAG,QAAQ,CAAC;AAChC,CAAC;AAED,SAAS,aAAa,CAAC,IAAY;IACjC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,IAAI,EAAE,sBAAsB,CAAC,CAAC;QAClD,MAAM,IAAI,GAAG,GAAG,CAAC,QAAQ,KAAK,GAAG,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,IAAI,GAAG,CAAC;QACzE,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,IAAI,EAAE,CAAC;QAChC,OAAO,GAAG,IAAI,GAAG,MAAM,EAAE,CAAC;IAC5B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC;IACnC,CAAC;AACH,CAAC;AAED,SAAS,kBAAkB,CAAC,IAAY;IACtC,MAAM,IAAI,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC;IACtD,OAAO,IAAI,KAAK,OAAO,IAAI,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;AACvD,CAAC;AAED,SAAS,gBAAgB,CAAC,IAAY;IACpC,IAAI,kBAAkB,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IAC1C,OAAO,kBAAkB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AACjD,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,GAAW;IACjD,OAAO,gBAAgB,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC;AAC9C,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,yBAAyB,CACvC,IAAc,EACd,YAAoC,EACpC,IAA8C;IAE9C,OAAO,IAAI;SACR,MAAM,CACL,CAAC,GAAG,EAAE,EAAE,CACN,GAAG,KAAK,IAAI,CAAC,UAAU;QACvB,GAAG,KAAK,IAAI,CAAC,QAAQ;QACrB,CAAC,uBAAuB,CAAC,GAAG,CAAC,CAChC;SACA,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACrE,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Boîte noire — émission d'événements ops depuis le SERVEUR Next.
|
|
3
|
+
*
|
|
4
|
+
* Le serveur tourne en sous-process du main Electron : une ligne
|
|
5
|
+
* `TF2EVENT {json}` sur stdout est captée par le hook logger du main
|
|
6
|
+
* (voir `@creezio/observability` initOpsJournal). En mode serveur pur (Docker), la ligne
|
|
7
|
+
* reste un simple log console — inoffensif.
|
|
8
|
+
*
|
|
9
|
+
* Volontairement autonome (pas d'import electron/) pour respecter la
|
|
10
|
+
* frontière de build Next.
|
|
11
|
+
*/
|
|
12
|
+
export type ServerOpsLevel = "decision" | "event" | "anomaly" | "error";
|
|
13
|
+
export type ServerOpsEvent = {
|
|
14
|
+
level: ServerOpsLevel;
|
|
15
|
+
/** Taxonomie `domaine.action` — ex. search.fallback, api.error. */
|
|
16
|
+
kind: string;
|
|
17
|
+
outcome?: string;
|
|
18
|
+
reason?: string;
|
|
19
|
+
durationMs?: number;
|
|
20
|
+
ctx?: Record<string, unknown>;
|
|
21
|
+
};
|
|
22
|
+
export declare function trackServer(evt: ServerOpsEvent): void;
|
|
23
|
+
/**
|
|
24
|
+
* Variante anti-spam : au plus un événement par `kind+outcome` toutes les
|
|
25
|
+
* `intervalMs` (5 min par défaut) — pour les chemins chauds (fallback SQL
|
|
26
|
+
* appelé à chaque recherche quand Meili est down).
|
|
27
|
+
*/
|
|
28
|
+
export declare function trackServerDebounced(evt: ServerOpsEvent, intervalMs?: number): void;
|
|
29
|
+
//# sourceMappingURL=ops-track.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ops-track.d.ts","sourceRoot":"","sources":["../../src/lib/ops-track.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,MAAM,MAAM,cAAc,GAAG,UAAU,GAAG,OAAO,GAAG,SAAS,GAAG,OAAO,CAAC;AAExE,MAAM,MAAM,cAAc,GAAG;IAC3B,KAAK,EAAE,cAAc,CAAC;IACtB,mEAAmE;IACnE,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC/B,CAAC;AAEF,wBAAgB,WAAW,CAAC,GAAG,EAAE,cAAc,GAAG,IAAI,CAOrD;AAID;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,cAAc,EAAE,UAAU,SAAa,GAAG,IAAI,CAOvF"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Boîte noire — émission d'événements ops depuis le SERVEUR Next.
|
|
3
|
+
*
|
|
4
|
+
* Le serveur tourne en sous-process du main Electron : une ligne
|
|
5
|
+
* `TF2EVENT {json}` sur stdout est captée par le hook logger du main
|
|
6
|
+
* (voir `@creezio/observability` initOpsJournal). En mode serveur pur (Docker), la ligne
|
|
7
|
+
* reste un simple log console — inoffensif.
|
|
8
|
+
*
|
|
9
|
+
* Volontairement autonome (pas d'import electron/) pour respecter la
|
|
10
|
+
* frontière de build Next.
|
|
11
|
+
*/
|
|
12
|
+
const TF2EVENT_PREFIX = "TF2EVENT ";
|
|
13
|
+
export function trackServer(evt) {
|
|
14
|
+
try {
|
|
15
|
+
// eslint-disable-next-line no-console
|
|
16
|
+
console.log(`${TF2EVENT_PREFIX}${JSON.stringify({ ...evt, source: "next" })}`);
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
/* best-effort : jamais de throw depuis l'instrumentation */
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
const lastSentByKey = new Map();
|
|
23
|
+
/**
|
|
24
|
+
* Variante anti-spam : au plus un événement par `kind+outcome` toutes les
|
|
25
|
+
* `intervalMs` (5 min par défaut) — pour les chemins chauds (fallback SQL
|
|
26
|
+
* appelé à chaque recherche quand Meili est down).
|
|
27
|
+
*/
|
|
28
|
+
export function trackServerDebounced(evt, intervalMs = 5 * 60_000) {
|
|
29
|
+
const key = `${evt.kind}|${evt.outcome || ""}`;
|
|
30
|
+
const now = Date.now();
|
|
31
|
+
const last = lastSentByKey.get(key) || 0;
|
|
32
|
+
if (now - last < intervalMs)
|
|
33
|
+
return;
|
|
34
|
+
lastSentByKey.set(key, now);
|
|
35
|
+
trackServer(evt);
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=ops-track.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ops-track.js","sourceRoot":"","sources":["../../src/lib/ops-track.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,MAAM,eAAe,GAAG,WAAW,CAAC;AAcpC,MAAM,UAAU,WAAW,CAAC,GAAmB;IAC7C,IAAI,CAAC;QACH,sCAAsC;QACtC,OAAO,CAAC,GAAG,CAAC,GAAG,eAAe,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,GAAG,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC;IACjF,CAAC;IAAC,MAAM,CAAC;QACP,4DAA4D;IAC9D,CAAC;AACH,CAAC;AAED,MAAM,aAAa,GAAG,IAAI,GAAG,EAAkB,CAAC;AAEhD;;;;GAIG;AACH,MAAM,UAAU,oBAAoB,CAAC,GAAmB,EAAE,UAAU,GAAG,CAAC,GAAG,MAAM;IAC/E,MAAM,GAAG,GAAG,GAAG,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,OAAO,IAAI,EAAE,EAAE,CAAC;IAC/C,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACvB,MAAM,IAAI,GAAG,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACzC,IAAI,GAAG,GAAG,IAAI,GAAG,UAAU;QAAE,OAAO;IACpC,aAAa,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IAC5B,WAAW,CAAC,GAAG,CAAC,CAAC;AACnB,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Réécrit les URLs de covers (secteurs / catégories) vers une taille vignette.
|
|
3
|
+
* Les /img/familles/*.webp locaux sont déjà optimisés — pass-through.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Retourne une URL adaptée à une vignette ~width CSS pixels (×2 DPR géré par le navigateur
|
|
7
|
+
* sur les CDNs qui le supportent ; Wikimedia/Pexels reçoivent width logique).
|
|
8
|
+
*/
|
|
9
|
+
export declare function optimizeCoverUrl(url: string | null | undefined, width?: number): string | null;
|
|
10
|
+
//# sourceMappingURL=optimize-cover-url.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"optimize-cover-url.d.ts","sourceRoot":"","sources":["../../src/lib/optimize-cover-url.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAyDH;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAC9B,KAAK,SAAgB,GACpB,MAAM,GAAG,IAAI,CAcf"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Réécrit les URLs de covers (secteurs / catégories) vers une taille vignette.
|
|
3
|
+
* Les /img/familles/*.webp locaux sont déjà optimisés — pass-through.
|
|
4
|
+
*/
|
|
5
|
+
const DEFAULT_WIDTH = 640;
|
|
6
|
+
/** Wikimedia Commons : fichier full → thumb 640px. */
|
|
7
|
+
function wikimediaThumb(url, width) {
|
|
8
|
+
try {
|
|
9
|
+
const u = new URL(url);
|
|
10
|
+
if (!u.hostname.endsWith("wikimedia.org") && !u.hostname.endsWith("wikipedia.org")) {
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
// Déjà un thumb
|
|
14
|
+
if (u.pathname.includes("/thumb/")) {
|
|
15
|
+
// Remplacer la largeur du thumb si présente (…/640px-Foo.jpg)
|
|
16
|
+
return url.replace(/\/\d+px-([^/]+)$/, `/${width}px-$1`);
|
|
17
|
+
}
|
|
18
|
+
// /wikipedia/commons/a/ab/File.jpg → /wikipedia/commons/thumb/a/ab/File.jpg/640px-File.jpg
|
|
19
|
+
const m = u.pathname.match(/^(\/wikipedia\/commons\/)([0-9a-f]\/[0-9a-f]{2}\/)([^/]+)$/i);
|
|
20
|
+
if (!m)
|
|
21
|
+
return null;
|
|
22
|
+
const file = m[3];
|
|
23
|
+
u.pathname = `${m[1]}thumb/${m[2]}${file}/${width}px-${file}`;
|
|
24
|
+
return u.toString();
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
function pexelsSized(url, width) {
|
|
31
|
+
try {
|
|
32
|
+
const u = new URL(url);
|
|
33
|
+
if (!u.hostname.includes("pexels.com"))
|
|
34
|
+
return null;
|
|
35
|
+
u.searchParams.set("auto", "compress");
|
|
36
|
+
u.searchParams.set("cs", "tinysrgb");
|
|
37
|
+
u.searchParams.set("w", String(width));
|
|
38
|
+
u.searchParams.set("fit", "crop");
|
|
39
|
+
return u.toString();
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
function unsplashSized(url, width) {
|
|
46
|
+
try {
|
|
47
|
+
const u = new URL(url);
|
|
48
|
+
if (!u.hostname.includes("unsplash.com"))
|
|
49
|
+
return null;
|
|
50
|
+
u.searchParams.set("w", String(width));
|
|
51
|
+
u.searchParams.set("q", "75");
|
|
52
|
+
u.searchParams.set("auto", "format");
|
|
53
|
+
u.searchParams.set("fit", "crop");
|
|
54
|
+
return u.toString();
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Retourne une URL adaptée à une vignette ~width CSS pixels (×2 DPR géré par le navigateur
|
|
62
|
+
* sur les CDNs qui le supportent ; Wikimedia/Pexels reçoivent width logique).
|
|
63
|
+
*/
|
|
64
|
+
export function optimizeCoverUrl(url, width = DEFAULT_WIDTH) {
|
|
65
|
+
if (!url)
|
|
66
|
+
return null;
|
|
67
|
+
const trimmed = url.trim();
|
|
68
|
+
if (!trimmed)
|
|
69
|
+
return null;
|
|
70
|
+
// Assets locaux déjà compressés
|
|
71
|
+
if (trimmed.startsWith("/img/"))
|
|
72
|
+
return trimmed;
|
|
73
|
+
if (!/^https?:\/\//i.test(trimmed))
|
|
74
|
+
return trimmed;
|
|
75
|
+
return (wikimediaThumb(trimmed, width) ||
|
|
76
|
+
pexelsSized(trimmed, width) ||
|
|
77
|
+
unsplashSized(trimmed, width) ||
|
|
78
|
+
trimmed);
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=optimize-cover-url.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"optimize-cover-url.js","sourceRoot":"","sources":["../../src/lib/optimize-cover-url.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/** Trails admin / loading plateforme (O9) — trails métier restent marque. */
|
|
2
|
+
export type TrailCrumb = {
|
|
3
|
+
href?: string;
|
|
4
|
+
label: string;
|
|
5
|
+
};
|
|
6
|
+
export declare function trailForRequestLogs(): TrailCrumb[];
|
|
7
|
+
export declare function trailForAnalytics(): TrailCrumb[];
|
|
8
|
+
export declare function trailForLoading(listHref: string, listLabel: string): TrailCrumb[];
|
|
9
|
+
//# sourceMappingURL=page-trails.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"page-trails.d.ts","sourceRoot":"","sources":["../../src/lib/page-trails.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAE7E,MAAM,MAAM,UAAU,GAAG;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAE1D,wBAAgB,mBAAmB,IAAI,UAAU,EAAE,CAKlD;AAED,wBAAgB,iBAAiB,IAAI,UAAU,EAAE,CAKhD;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,UAAU,EAAE,CAKjF"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/** Trails admin / loading plateforme (O9) — trails métier restent marque. */
|
|
2
|
+
export function trailForRequestLogs() {
|
|
3
|
+
return [
|
|
4
|
+
{ href: "/admin/request-logs", label: "Admin" },
|
|
5
|
+
{ label: "Logs API / MCP" },
|
|
6
|
+
];
|
|
7
|
+
}
|
|
8
|
+
export function trailForAnalytics() {
|
|
9
|
+
return [
|
|
10
|
+
{ href: "/admin/analytics", label: "Admin" },
|
|
11
|
+
{ label: "Analytics" },
|
|
12
|
+
];
|
|
13
|
+
}
|
|
14
|
+
export function trailForLoading(listHref, listLabel) {
|
|
15
|
+
return [
|
|
16
|
+
{ href: listHref, label: listLabel },
|
|
17
|
+
{ label: "Chargement…" },
|
|
18
|
+
];
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=page-trails.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"page-trails.js","sourceRoot":"","sources":["../../src/lib/page-trails.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAI7E,MAAM,UAAU,mBAAmB;IACjC,OAAO;QACL,EAAE,IAAI,EAAE,qBAAqB,EAAE,KAAK,EAAE,OAAO,EAAE;QAC/C,EAAE,KAAK,EAAE,gBAAgB,EAAE;KAC5B,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,iBAAiB;IAC/B,OAAO;QACL,EAAE,IAAI,EAAE,kBAAkB,EAAE,KAAK,EAAE,OAAO,EAAE;QAC5C,EAAE,KAAK,EAAE,WAAW,EAAE;KACvB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,QAAgB,EAAE,SAAiB;IACjE,OAAO;QACL,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE;QACpC,EAAE,KAAK,EAAE,aAAa,EAAE;KACzB,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Origine publique pour redirects / liens absolus derrière un reverse-proxy
|
|
3
|
+
* (Cloudflare Tunnel) ou en local desktop (Electron sur 127.0.0.1).
|
|
4
|
+
*
|
|
5
|
+
* Priorité :
|
|
6
|
+
* 1. X-Forwarded-Host non-loopback (+ X-Forwarded-Proto)
|
|
7
|
+
* 2. Host non-loopback
|
|
8
|
+
* 3. APP_PUBLIC_URL si la requête vient du tunnel (CF / proto https)
|
|
9
|
+
* alors que Host a été réécrit en localhost/127.0.0.1
|
|
10
|
+
* 4. URL de la requête / APP_BASE_URL (accès local Electron)
|
|
11
|
+
*/
|
|
12
|
+
export type HeaderReader = {
|
|
13
|
+
get(name: string): string | null;
|
|
14
|
+
};
|
|
15
|
+
export type ResolvedOrigin = {
|
|
16
|
+
origin: string;
|
|
17
|
+
proto: "http" | "https";
|
|
18
|
+
host: string;
|
|
19
|
+
source: "x-forwarded-host" | "host" | "app-public-url" | "request-url" | "app-base-url" | "default";
|
|
20
|
+
};
|
|
21
|
+
export declare function isLoopbackHost(host: string): boolean;
|
|
22
|
+
export declare function resolvePublicOrigin(headers: HeaderReader, opts?: {
|
|
23
|
+
fallbackUrl?: string | URL;
|
|
24
|
+
appPublicUrl?: string | null;
|
|
25
|
+
appBaseUrl?: string | null;
|
|
26
|
+
}): ResolvedOrigin;
|
|
27
|
+
/** Cookie Secure : https public / tunnel ; false sur loopback desktop HTTP. */
|
|
28
|
+
export declare function resolveCookieSecure(headers: HeaderReader, opts?: {
|
|
29
|
+
appPublicUrl?: string | null;
|
|
30
|
+
appBaseUrl?: string | null;
|
|
31
|
+
}): boolean;
|
|
32
|
+
//# sourceMappingURL=public-origin.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"public-origin.d.ts","sourceRoot":"","sources":["../../src/lib/public-origin.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;GAUG;AAEH,MAAM,MAAM,YAAY,GAAG;IACzB,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;CAClC,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EACF,kBAAkB,GAClB,MAAM,GACN,gBAAgB,GAChB,aAAa,GACb,cAAc,GACd,SAAS,CAAC;CACf,CAAC;AAOF,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAUpD;AAiBD,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,YAAY,EACrB,IAAI,CAAC,EAAE;IACL,WAAW,CAAC,EAAE,MAAM,GAAG,GAAG,CAAC;IAC3B,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B,GACA,cAAc,CAwFhB;AAED,+EAA+E;AAC/E,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,YAAY,EACrB,IAAI,CAAC,EAAE;IAAE,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GAClE,OAAO,CAQT"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { getShellUiBrand } from "../brand.js";
|
|
2
|
+
function firstHeader(value) {
|
|
3
|
+
if (!value)
|
|
4
|
+
return "";
|
|
5
|
+
return value.split(",")[0]?.trim() || "";
|
|
6
|
+
}
|
|
7
|
+
export function isLoopbackHost(host) {
|
|
8
|
+
const raw = (host || "").toLowerCase().trim();
|
|
9
|
+
let bare;
|
|
10
|
+
if (raw.startsWith("[")) {
|
|
11
|
+
const end = raw.indexOf("]");
|
|
12
|
+
bare = end >= 0 ? raw.slice(1, end) : raw.replace(/[\[\]]/g, "");
|
|
13
|
+
}
|
|
14
|
+
else {
|
|
15
|
+
bare = raw.split(":")[0] || "";
|
|
16
|
+
}
|
|
17
|
+
return bare === "127.0.0.1" || bare === "localhost" || bare === "::1";
|
|
18
|
+
}
|
|
19
|
+
function hasCloudflareHints(headers) {
|
|
20
|
+
if (headers.get("cf-connecting-ip") || headers.get("cf-ray"))
|
|
21
|
+
return true;
|
|
22
|
+
const visitor = headers.get("cf-visitor") || "";
|
|
23
|
+
return /"scheme"\s*:\s*"https"/i.test(visitor) || /https/i.test(visitor);
|
|
24
|
+
}
|
|
25
|
+
function normalizeProto(raw, fallback) {
|
|
26
|
+
const p = raw.toLowerCase();
|
|
27
|
+
if (p === "http" || p === "https")
|
|
28
|
+
return p;
|
|
29
|
+
return fallback;
|
|
30
|
+
}
|
|
31
|
+
export function resolvePublicOrigin(headers, opts) {
|
|
32
|
+
const xfHost = firstHeader(headers.get("x-forwarded-host"));
|
|
33
|
+
const hostHeader = firstHeader(headers.get("host"));
|
|
34
|
+
const xfProto = firstHeader(headers.get("x-forwarded-proto")).toLowerCase();
|
|
35
|
+
const fromTunnel = xfProto === "https" || hasCloudflareHints(headers);
|
|
36
|
+
const appPublic = (opts?.appPublicUrl || "").trim().replace(/\/+$/, "");
|
|
37
|
+
if (xfHost && !isLoopbackHost(xfHost)) {
|
|
38
|
+
const proto = normalizeProto(xfProto, "https");
|
|
39
|
+
return {
|
|
40
|
+
origin: `${proto}://${xfHost}`,
|
|
41
|
+
proto,
|
|
42
|
+
host: xfHost,
|
|
43
|
+
source: "x-forwarded-host",
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
if (hostHeader && !isLoopbackHost(hostHeader)) {
|
|
47
|
+
const proto = normalizeProto(xfProto, hostHeader.toLowerCase().endsWith("." + getShellUiBrand().publicHostSuffix) || fromTunnel
|
|
48
|
+
? "https"
|
|
49
|
+
: "http");
|
|
50
|
+
return {
|
|
51
|
+
origin: `${proto}://${hostHeader}`,
|
|
52
|
+
proto,
|
|
53
|
+
host: hostHeader,
|
|
54
|
+
source: "host",
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
// Tunnel actif mais Host réécrit vers localhost:PORT par cloudflared.
|
|
58
|
+
if (appPublic && fromTunnel) {
|
|
59
|
+
try {
|
|
60
|
+
const u = new URL(appPublic);
|
|
61
|
+
const proto = u.protocol === "http:" ? "http" : "https";
|
|
62
|
+
return {
|
|
63
|
+
origin: u.origin,
|
|
64
|
+
proto,
|
|
65
|
+
host: u.host,
|
|
66
|
+
source: "app-public-url",
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
/* ignore */
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
if (opts?.fallbackUrl) {
|
|
74
|
+
try {
|
|
75
|
+
const u = typeof opts.fallbackUrl === "string"
|
|
76
|
+
? new URL(opts.fallbackUrl)
|
|
77
|
+
: new URL(opts.fallbackUrl.toString());
|
|
78
|
+
const proto = u.protocol === "https:" ? "https" : "http";
|
|
79
|
+
return {
|
|
80
|
+
origin: u.origin,
|
|
81
|
+
proto,
|
|
82
|
+
host: u.host,
|
|
83
|
+
source: "request-url",
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
/* ignore */
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
const base = (opts?.appBaseUrl || "").trim().replace(/\/+$/, "");
|
|
91
|
+
if (base) {
|
|
92
|
+
try {
|
|
93
|
+
const u = new URL(base);
|
|
94
|
+
const proto = u.protocol === "https:" ? "https" : "http";
|
|
95
|
+
return {
|
|
96
|
+
origin: u.origin,
|
|
97
|
+
proto,
|
|
98
|
+
host: u.host,
|
|
99
|
+
source: "app-base-url",
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
/* ignore */
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return {
|
|
107
|
+
origin: "http://127.0.0.1",
|
|
108
|
+
proto: "http",
|
|
109
|
+
host: "127.0.0.1",
|
|
110
|
+
source: "default",
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
/** Cookie Secure : https public / tunnel ; false sur loopback desktop HTTP. */
|
|
114
|
+
export function resolveCookieSecure(headers, opts) {
|
|
115
|
+
const resolved = resolvePublicOrigin(headers, {
|
|
116
|
+
appPublicUrl: opts?.appPublicUrl ?? process.env.APP_PUBLIC_URL,
|
|
117
|
+
appBaseUrl: opts?.appBaseUrl ?? process.env.APP_BASE_URL,
|
|
118
|
+
});
|
|
119
|
+
if (resolved.proto === "https")
|
|
120
|
+
return true;
|
|
121
|
+
if (isLoopbackHost(resolved.host))
|
|
122
|
+
return false;
|
|
123
|
+
return process.env.NODE_ENV === "production";
|
|
124
|
+
}
|
|
125
|
+
//# sourceMappingURL=public-origin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"public-origin.js","sourceRoot":"","sources":["../../src/lib/public-origin.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Remontée d'incidents serveur (app desktop) vers le collecteur de crash de
|
|
3
|
+
* l'éditeur — ex. « Meilisearch indisponible alors que la recherche est
|
|
4
|
+
* sollicitée ». Best-effort, jamais bloquant, dédupliqué (1 envoi max par
|
|
5
|
+
* type d'incident par heure) pour ne pas inonder le collecteur.
|
|
6
|
+
*
|
|
7
|
+
* Actif uniquement si `{PREFIX}_CRASH_ENDPOINT` (ou `CREEZIO_CRASH_ENDPOINT`)
|
|
8
|
+
* est injecté dans l'environnement (fait par brand-host-stack / server-launcher).
|
|
9
|
+
* En déploiement web classique, cette fonction est un no-op.
|
|
10
|
+
*/
|
|
11
|
+
export declare function reportServerIncident(kind: string, detail: Record<string, unknown>): void;
|
|
12
|
+
//# sourceMappingURL=server-incident.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-incident.d.ts","sourceRoot":"","sources":["../../src/lib/server-incident.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AA8DH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAwBxF"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Remontée d'incidents serveur (app desktop) vers le collecteur de crash de
|
|
3
|
+
* l'éditeur — ex. « Meilisearch indisponible alors que la recherche est
|
|
4
|
+
* sollicitée ». Best-effort, jamais bloquant, dédupliqué (1 envoi max par
|
|
5
|
+
* type d'incident par heure) pour ne pas inonder le collecteur.
|
|
6
|
+
*
|
|
7
|
+
* Actif uniquement si `{PREFIX}_CRASH_ENDPOINT` (ou `CREEZIO_CRASH_ENDPOINT`)
|
|
8
|
+
* est injecté dans l'environnement (fait par brand-host-stack / server-launcher).
|
|
9
|
+
* En déploiement web classique, cette fonction est un no-op.
|
|
10
|
+
*/
|
|
11
|
+
const DEDUP_MS = 3600_000;
|
|
12
|
+
const lastSent = new Map();
|
|
13
|
+
function firstEnv(...keys) {
|
|
14
|
+
for (const k of keys) {
|
|
15
|
+
const v = (process.env[k] || "").trim();
|
|
16
|
+
if (v)
|
|
17
|
+
return v;
|
|
18
|
+
}
|
|
19
|
+
return "";
|
|
20
|
+
}
|
|
21
|
+
/** Prefixe marque (ex. TEMPOFLOW3) si injecté, sinon scan `*_CRASH_ENDPOINT`. */
|
|
22
|
+
function resolveCrashEndpoint() {
|
|
23
|
+
const direct = firstEnv("CREEZIO_CRASH_ENDPOINT", "TEMPOFLOW3_CRASH_ENDPOINT", "TF2_CRASH_ENDPOINT", "CERTIVAN_CRASH_ENDPOINT", "FIDU_CRASH_ENDPOINT");
|
|
24
|
+
if (direct)
|
|
25
|
+
return direct;
|
|
26
|
+
for (const [k, v] of Object.entries(process.env)) {
|
|
27
|
+
if (k.endsWith("_CRASH_ENDPOINT") && (v || "").trim()) {
|
|
28
|
+
return v.trim();
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return "";
|
|
32
|
+
}
|
|
33
|
+
function resolveInstallId() {
|
|
34
|
+
return (firstEnv("CREEZIO_INSTALL_ID", "TEMPOFLOW3_INSTALL_ID", "TF2_INSTALL_ID", "CERTIVAN_INSTALL_ID", "FIDU_INSTALL_ID") ||
|
|
35
|
+
(() => {
|
|
36
|
+
for (const [k, v] of Object.entries(process.env)) {
|
|
37
|
+
if (k.endsWith("_INSTALL_ID") && (v || "").trim())
|
|
38
|
+
return v.trim();
|
|
39
|
+
}
|
|
40
|
+
return "server";
|
|
41
|
+
})());
|
|
42
|
+
}
|
|
43
|
+
function resolveAppVersion() {
|
|
44
|
+
return (firstEnv("CREEZIO_APP_VERSION", "TEMPOFLOW3_APP_VERSION", "TF2_APP_VERSION", "CERTIVAN_APP_VERSION", "FIDU_APP_VERSION", "npm_package_version") || "unknown");
|
|
45
|
+
}
|
|
46
|
+
export function reportServerIncident(kind, detail) {
|
|
47
|
+
const endpoint = resolveCrashEndpoint();
|
|
48
|
+
if (!endpoint)
|
|
49
|
+
return;
|
|
50
|
+
const now = Date.now();
|
|
51
|
+
const prev = lastSent.get(kind) || 0;
|
|
52
|
+
if (now - prev < DEDUP_MS)
|
|
53
|
+
return;
|
|
54
|
+
lastSent.set(kind, now);
|
|
55
|
+
console.error(`[incident] ${kind}: ${JSON.stringify(detail).slice(0, 300)}`);
|
|
56
|
+
void fetch(endpoint, {
|
|
57
|
+
method: "POST",
|
|
58
|
+
headers: { "Content-Type": "application/json" },
|
|
59
|
+
body: JSON.stringify({
|
|
60
|
+
kind: `server-${kind}`,
|
|
61
|
+
brandId: firstEnv("CREEZIO_BRAND_ID", "CREEZIO_BRAND") || null,
|
|
62
|
+
installId: resolveInstallId(),
|
|
63
|
+
appVersion: resolveAppVersion(),
|
|
64
|
+
platform: process.platform,
|
|
65
|
+
bootStage: "running",
|
|
66
|
+
timestamp: new Date().toISOString(),
|
|
67
|
+
detail,
|
|
68
|
+
}),
|
|
69
|
+
signal: AbortSignal.timeout(5000),
|
|
70
|
+
}).catch(() => { });
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=server-incident.js.map
|