char-fork/llama.cpp

git clone https://git.t4t.associates/char-fork/llama.cpp

Aleksander Grygierui: Constants refactor (#26908)e21152dc9

char/aliceai-t5-moe
11.0 KiB361 linesraw
1/**
2 * Centralized PWA constants to avoid magic strings, regexes, and duplicated
3 * definitions across the codebase.
4 */
5
6import { APP_NAME } from './app.constants';
7
8export const MEDIA_QUERIES = {
9	DISPLAY_MODE_STANDALONE: '(display-mode: standalone)',
10	PREFERS_DARK: '(prefers-color-scheme: dark)',
11	PREFERS_LIGHT: '(prefers-color-scheme: light)'
12} as const;
13
14export const THEME_COLORS = {
15	ACCENT_BLUE: '#2563eb',
16	ACCENT_BLUE_HOVER: '#1d4ed8',
17	BACKGROUND_DARK: '#111111',
18	BACKGROUND_LIGHT: 'white',
19	DARK: '#0d0d0d',
20	LIGHT: '#ffffff',
21	TITLE_UPDATE_ALERT: {
22		BG_DARK: 'zinc-800',
23		BG_LIGHT: 'white',
24		BORDER_DARK: 'zinc-700',
25		BORDER_LIGHT: 'zinc-200',
26		TEXT_DARK: 'zinc-400',
27		TEXT_LIGHT: 'zinc-500'
28	}
29} as const;
30
31export const FAVICON_PATHS = {
32	ICO_DARK: 'favicon-dark.ico',
33	ICO_LIGHT: 'favicon.ico',
34	SVG_DARK: 'favicon-dark.svg',
35	SVG_LIGHT: 'favicon.svg'
36} as const;
37
38// Substituted for `currentColor` in src/lib/assets/logo.svg when generating
39// the light/dark static sources consumed by the PWA asset generator.
40export const FAVICON_COLORS = {
41	DARK: '#fafafa',
42	LIGHT: '#111111'
43} as const;
44
45export const FAVICON_SELECTORS = {
46	ICO_48X48: 'link[rel="icon"][sizes="48x48"]',
47	SVG_ANY: 'link[rel="icon"][type="image/svg+xml"]'
48} as const;
49
50export const APPLE_ASSETS = {
51	TOUCH_ICON: 'apple-touch-icon-180x180.png'
52} as const;
53
54export const PWA_MANIFEST = {
55	background_color: THEME_COLORS.BACKGROUND_LIGHT,
56	description: 'Local AI chat interface powered by llama.cpp',
57	display: 'standalone' as const,
58	icons: [
59		{ sizes: '64x64', src: 'pwa-64x64.png', type: 'image/png' },
60		{ sizes: '192x192', src: 'pwa-192x192.png', type: 'image/png' },
61		{ purpose: 'any' as const, sizes: '512x512', src: 'pwa-512x512.png', type: 'image/png' },
62		{
63			purpose: 'maskable' as const,
64			sizes: '512x512',
65			src: 'maskable-icon-512x512.png',
66			type: 'image/png'
67		}
68	],
69	name: APP_NAME,
70	short_name: APP_NAME,
71	start_url: './',
72	theme_color: THEME_COLORS.BACKGROUND_LIGHT
73};
74
75export const PWA_ICON_PATHS = {
76	MASKABLE_512: '/maskable-icon-512x512.png',
77	PWA_64: '/pwa-64x64.png',
78	PWA_192: '/pwa-192x192.png',
79	PWA_512: '/pwa-512x512.png'
80} as const;
81
82/** Apple device dimensions (logical points) and DPR, from Apple HIG. */
83export const APPLE_DEVICES = {
84	'640x1136': { dpr: 2, height: 568, width: 320 }, // iPhone 6/7/8 Plus
85	'744x1133': { dpr: 2, height: 573, width: 376 }, // iPad mini 8.3"
86	'750x1334': { dpr: 2, height: 667, width: 375 }, // iPhone 6/7/8, 14
87	'1032x1376': { dpr: 2, height: 1376, width: 1032 }, // iPad Air 13"
88	// iPhones (DPR 3)
89	'1170x2532': { dpr: 3, height: 844, width: 390 }, // iPhone 13, 15
90	'1179x2556': { dpr: 3, height: 852, width: 393 }, // iPhone 14, 15 Pro, 16
91	'1206x2622': { dpr: 3, height: 874, width: 402 }, // iPhone 16 Plus, 16e
92	'1284x2778': { dpr: 3, height: 926, width: 428 }, // iPhone 15 Plus
93	'1290x2796': { dpr: 3, height: 932, width: 430 }, // iPhone 15 Pro Max, 16 Pro
94	'1320x2868': { dpr: 3, height: 956, width: 440 }, // iPhone 16 Pro Max
95	'1640x2360': { dpr: 2, height: 1180, width: 820 }, // iPad Air 10.9"
96	// iPads (DPR 2)
97	'1668x2388': { dpr: 2, height: 1194, width: 834 }, // iPad Air 11", iPad 11"
98	'2048x2732': { dpr: 2, height: 1366, width: 1024 } // iPad Pro 12.9"
99} as const;
100
101export type AppleDeviceKey = keyof typeof APPLE_DEVICES;
102
103export const PWA_FILE_PATHS = {
104	MANIFEST: '/manifest.webmanifest',
105	SERVICE_WORKER: '/sw.js',
106	VERSION: '/version.json',
107	WORKBOX: '/workbox-<hash>.js'
108} as const;
109
110// Used by the server middleware to skip API key validation.
111// Keep in sync with tools/server/server-http.cpp public_endpoints list.
112
113export const PUBLIC_ENDPOINTS = [
114	'/health',
115	'/v1/health',
116	'/models',
117	'/v1/models',
118	'/props',
119	'/metrics',
120	'/',
121	'/index.html',
122
123	'/favicon.ico',
124	'/favicon-dark.ico',
125	'/favicon.svg',
126	'/favicon-dark.svg',
127	'/pwa-64x64.png',
128	'/pwa-192x192.png',
129	'/pwa-512x512.png',
130	'/maskable-icon-512x512.png',
131	'/apple-touch-icon-180x180.png',
132	'/apple-splash-portrait-640x1136.png',
133	'/apple-splash-landscape-640x1136.png',
134	'/apple-splash-portrait-750x1334.png',
135	'/apple-splash-landscape-750x1334.png',
136	'/apple-splash-portrait-1170x2532.png',
137	'/apple-splash-landscape-1170x2532.png',
138	'/apple-splash-portrait-1179x2556.png',
139	'/apple-splash-landscape-1179x2556.png',
140	'/apple-splash-portrait-1206x2622.png',
141	'/apple-splash-landscape-1206x2622.png',
142	'/apple-splash-portrait-1284x2778.png',
143	'/apple-splash-landscape-1284x2778.png',
144	'/apple-splash-portrait-1290x2796.png',
145	'/apple-splash-landscape-1290x2796.png',
146	'/apple-splash-portrait-1320x2868.png',
147	'/apple-splash-landscape-1320x2868.png',
148	'/apple-splash-portrait-1488x2266.png',
149	'/apple-splash-landscape-1488x2266.png',
150	'/apple-splash-portrait-1640x2360.png',
151	'/apple-splash-landscape-1640x2360.png',
152	'/apple-splash-portrait-1668x2388.png',
153	'/apple-splash-landscape-1668x2388.png',
154	'/apple-splash-portrait-2048x2732.png',
155	'/apple-splash-landscape-2048x2732.png',
156	'/apple-splash-portrait-dark-640x1136.png',
157	'/apple-splash-landscape-dark-640x1136.png',
158	'/apple-splash-portrait-dark-750x1334.png',
159	'/apple-splash-landscape-dark-750x1334.png',
160	'/apple-splash-portrait-dark-1170x2532.png',
161	'/apple-splash-landscape-dark-1170x2532.png',
162	'/apple-splash-portrait-dark-1179x2556.png',
163	'/apple-splash-landscape-dark-1179x2556.png',
164	'/apple-splash-portrait-dark-1206x2622.png',
165	'/apple-splash-landscape-dark-1206x2622.png',
166	'/apple-splash-portrait-dark-1284x2778.png',
167	'/apple-splash-landscape-dark-1284x2778.png',
168	'/apple-splash-portrait-dark-1290x2796.png',
169	'/apple-splash-landscape-dark-1290x2796.png',
170	'/apple-splash-portrait-dark-1320x2868.png',
171	'/apple-splash-landscape-dark-1320x2868.png',
172	'/apple-splash-portrait-dark-1488x2266.png',
173	'/apple-splash-landscape-dark-1488x2266.png',
174	'/apple-splash-portrait-dark-1640x2360.png',
175	'/apple-splash-landscape-dark-1640x2360.png',
176	'/apple-splash-portrait-dark-1668x2388.png',
177	'/apple-splash-landscape-dark-1668x2388.png',
178	'/apple-splash-portrait-dark-2048x2732.png',
179	'/apple-splash-landscape-dark-2048x2732.png',
180	'/manifest.webmanifest',
181	'/sw.js',
182	'/version.json',
183	'/workbox-<hash>.js'
184] as const;
185export const BUILD_CONFIG = {
186	GUIDE_COMMENT: `
187<!--
188  This is a static build of the frontend.
189  It is automatically generated by the build process.
190  Do not edit this file directly.
191  To make changes, refer to the "Web UI" section in the README.
192-->
193`.trim(),
194	OUTPUT_DIR: './dist'
195} as const;
196
197export const REGEX_PATTERNS = {
198	HEAD_CLOSE: /\t*<\/head>/,
199	SPLASH_FILE: /^apple-splash-(portrait|landscape)-(dark-)?(\d+)x(\d+)\.png$/
200} as const;
201
202// Device names used by @vite-pwa/assets-generator for splash screen generation.
203// Keep in sync with pwa-assets.config.ts.
204export const PWA_GENERATOR_DEVICES = [
205	'iPhone 13',
206	'iPhone 13 Pro',
207	'iPhone 13 Pro Max',
208	'iPhone 14',
209	'iPhone 14 Plus',
210	'iPhone 14 Pro',
211	'iPhone 14 Pro Max',
212	'iPhone 15',
213	'iPhone 15 Plus',
214	'iPhone 15 Pro',
215	'iPhone 15 Pro Max',
216	'iPhone 16',
217	'iPhone 16 Plus',
218	'iPhone 16 Pro',
219	'iPhone 16 Pro Max',
220	'iPhone 16e',
221	'iPhone SE 4"',
222	'iPhone SE 4.7"',
223	'iPad 11"',
224	'iPad Air 10.9"',
225	'iPad Air 11"',
226	'iPad Air 13"',
227	'iPad Pro 11"',
228	'iPad Pro 12.9"',
229	'iPad mini 8.3"'
230] as const;
231
232// PWA assets generator configuration — used by pwa-assets.config.ts
233// FAVICON_PADDING: fraction (0..1) of the icon reserved as equal margin on
234// each side. Applied to icon PNG/ICO outputs by @vite-pwa/assets-generator and
235// post-processed into the static favicon.svg so the in-app logo (which reads
236// src/lib/assets/logo.svg directly) is unaffected.
237export const PWA_ASSET_GENERATOR = {
238	ADD_MEDIA_SCREEN: true,
239	BASE_PATH: './',
240	DARK_PREFIX: 'dark-',
241	FAVICON_PADDING: 0.04,
242	FIT_MODE: 'contain',
243	LINK_PRESET: '2023',
244	PNG_COMPRESSION_LEVEL: 9,
245	PNG_QUALITY: 60,
246	SPLASH_PADDING: 0.75,
247	XHTML: false
248} as const;
249
250export const CACHE_SETTINGS = {
251	API_CACHE_MAX_AGE_SECONDS: 60 * 60 * 24,
252	API_CACHE_MAX_ENTRIES: 50,
253	IMMUTABLE_MAX_AGE_SECONDS: 31536000,
254	MAX_FILE_SIZE_BYTES: 10 * 1024 * 1024
255} as const;
256
257export const GLOB_PATTERNS: string[] = [
258	'**/*.{js,css,html,ico,svg,png,webp,woff,woff2,json,webmanifest}'
259];
260
261export const SW_CONFIG = {
262	CHECK_INTERVAL_MS: 60000,
263	UPDATE_FETCH_OPTIONS: {
264		CACHE: 'no-store',
265		HEADERS: {
266			CACHE: 'no-store',
267			CACHE_CONTROL: 'no-cache'
268		}
269	}
270} as const;
271
272// Runtime caching configuration for Workbox
273export const RUNTIME_CACHING = {
274	CACHE_NAME: 'api-cache',
275	HANDLER: 'NetworkFirst'
276} as const;
277
278// Workbox runtime caching patterns
279export const API_CACHING_PATTERNS = {
280	STATIC_API: /^\/(health|props|models|tools|slots|cors-proxy).*/,
281	V1_API: /^\/v1\/.*/
282} as const;
283
284// SvelteKit PWA plugin options
285export const PWA_KIT_OPTIONS = {} as const;
286
287export const APPLE_META_TAGS = {
288	MOBILE_WEB_APP_CAPABLE: { content: 'yes', name: 'apple-mobile-web-app-capable' },
289	MOBILE_WEB_APP_TITLE: { name: 'apple-mobile-web-app-title' },
290	STATUS_BAR_STYLE: { content: 'black-translucent', name: 'apple-mobile-web-app-status-bar-style' }
291} as const;
292
293// Splash screen HTML link tag prefix used by generateSplashScreenLinks
294export const SPLASH_LINK = {
295	DARK_MEDIA_SUFFIX: ' and (prefers-color-scheme: dark)',
296	HTML: '<link rel="apple-touch-startup-image"'
297} as const;
298
299// SvelteKit PWA plugin configuration — used by @vite.config.ts
300import type { SvelteKitPWAOptions } from '@vite-pwa/sveltekit';
301
302export const SVELTEKIT_PWA_OPTIONS: SvelteKitPWAOptions = {
303	devOptions: {
304		enabled: true,
305		suppressWarnings: true
306	},
307
308	// SvelteKit-specific options
309	kit: {
310		// Include version file for proper cache invalidation
311		includeVersionFile: true
312	},
313
314	// Strategy: generateSW - the plugin generates a service worker automatically
315	// using Workbox. For a custom SW, use 'injectManifest' instead.
316	// Manifest configuration
317	manifest: PWA_MANIFEST,
318
319	// Workbox configuration for generateSW strategy
320	workbox: {
321		// Match all static assets in the build output.
322		// Uses '**/' because SvelteKit outputs files under _app/immutable/
323		// subdirectories.
324		globPatterns: GLOB_PATTERNS,
325		maximumFileSizeToCacheInBytes: CACHE_SETTINGS.MAX_FILE_SIZE_BYTES,
326
327		// Prevent @vite-pwa/sveltekit from auto-adding a NavigationRoute by
328		// setting navigateFallback to empty string. This keeps the service
329		// worker from intercepting direct browser navigation to server API
330		// endpoints (e.g. /slots, /models, /v1/models) which should return
331		// JSON, not the SPA HTML shell. The server's own static-file fallback
332		// handles non-API navigation to index.html for the SPA router.
333		navigateFallback: '',
334
335		// Runtime caching for API calls - use NetworkFirst so APIs are always fresh
336		runtimeCaching: [
337			{
338				handler: RUNTIME_CACHING.HANDLER,
339				options: {
340					cacheName: RUNTIME_CACHING.CACHE_NAME,
341					expiration: {
342						maxAgeSeconds: CACHE_SETTINGS.API_CACHE_MAX_AGE_SECONDS,
343						maxEntries: CACHE_SETTINGS.API_CACHE_MAX_ENTRIES
344					}
345				},
346				urlPattern: API_CACHING_PATTERNS.V1_API
347			},
348			{
349				handler: RUNTIME_CACHING.HANDLER,
350				options: {
351					cacheName: RUNTIME_CACHING.CACHE_NAME,
352					expiration: {
353						maxAgeSeconds: CACHE_SETTINGS.API_CACHE_MAX_AGE_SECONDS,
354						maxEntries: CACHE_SETTINGS.API_CACHE_MAX_ENTRIES
355					}
356				},
357				urlPattern: API_CACHING_PATTERNS.STATIC_API
358			}
359		]
360	}
361};