qlara 0.1.0 → 0.1.2

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/src/types.ts ADDED
@@ -0,0 +1,561 @@
1
+ // ── Metadata Types ───────────────────────────────────────────────
2
+ // Framework-agnostic metadata types. Covers the full range of HTML
3
+ // metadata that modern frameworks (Next.js, etc.) can generate.
4
+ // All fields are optional except `title`.
5
+
6
+ export interface QlaraAuthor {
7
+ name?: string;
8
+ url?: string;
9
+ }
10
+
11
+ export type QlaraReferrer =
12
+ | 'no-referrer'
13
+ | 'origin'
14
+ | 'no-referrer-when-downgrade'
15
+ | 'origin-when-cross-origin'
16
+ | 'same-origin'
17
+ | 'strict-origin'
18
+ | 'strict-origin-when-cross-origin';
19
+
20
+ // ── Robots ───────────────────────────────────────────────────────
21
+
22
+ export interface QlaraRobotsInfo {
23
+ index?: boolean;
24
+ follow?: boolean;
25
+ noarchive?: boolean;
26
+ nosnippet?: boolean;
27
+ noimageindex?: boolean;
28
+ nocache?: boolean;
29
+ notranslate?: boolean;
30
+ indexifembedded?: boolean;
31
+ nositelinkssearchbox?: boolean;
32
+ unavailable_after?: string;
33
+ 'max-video-preview'?: number | string;
34
+ 'max-image-preview'?: 'none' | 'standard' | 'large';
35
+ 'max-snippet'?: number;
36
+ }
37
+
38
+ export type QlaraRobots = string | (QlaraRobotsInfo & {
39
+ googleBot?: string | QlaraRobotsInfo;
40
+ });
41
+
42
+ // ── Alternates ───────────────────────────────────────────────────
43
+
44
+ export interface QlaraAlternateLinkDescriptor {
45
+ title?: string;
46
+ url: string;
47
+ }
48
+
49
+ export interface QlaraAlternateURLs {
50
+ canonical?: string | QlaraAlternateLinkDescriptor;
51
+ languages?: Record<string, string | QlaraAlternateLinkDescriptor[]>;
52
+ media?: Record<string, string | QlaraAlternateLinkDescriptor[]>;
53
+ types?: Record<string, string | QlaraAlternateLinkDescriptor[]>;
54
+ }
55
+
56
+ // ── Icons ────────────────────────────────────────────────────────
57
+
58
+ export interface QlaraIconDescriptor {
59
+ url: string;
60
+ type?: string;
61
+ sizes?: string;
62
+ color?: string;
63
+ rel?: string;
64
+ media?: string;
65
+ fetchPriority?: 'high' | 'low' | 'auto';
66
+ }
67
+
68
+ export type QlaraIcon = string | QlaraIconDescriptor;
69
+
70
+ export interface QlaraIcons {
71
+ icon?: QlaraIcon | QlaraIcon[];
72
+ shortcut?: QlaraIcon | QlaraIcon[];
73
+ apple?: QlaraIcon | QlaraIcon[];
74
+ other?: QlaraIconDescriptor | QlaraIconDescriptor[];
75
+ }
76
+
77
+ // ── Open Graph ───────────────────────────────────────────────────
78
+
79
+ export interface QlaraOGImageDescriptor {
80
+ url: string;
81
+ secureUrl?: string;
82
+ alt?: string;
83
+ type?: string;
84
+ width?: string | number;
85
+ height?: string | number;
86
+ }
87
+
88
+ export type QlaraOGImage = string | QlaraOGImageDescriptor;
89
+
90
+ export interface QlaraOGAudioDescriptor {
91
+ url: string;
92
+ secureUrl?: string;
93
+ type?: string;
94
+ }
95
+
96
+ export type QlaraOGAudio = string | QlaraOGAudioDescriptor;
97
+
98
+ export interface QlaraOGVideoDescriptor {
99
+ url: string;
100
+ secureUrl?: string;
101
+ type?: string;
102
+ width?: string | number;
103
+ height?: string | number;
104
+ }
105
+
106
+ export type QlaraOGVideo = string | QlaraOGVideoDescriptor;
107
+
108
+ export interface QlaraOpenGraphBase {
109
+ title?: string;
110
+ description?: string;
111
+ url?: string;
112
+ siteName?: string;
113
+ locale?: string;
114
+ alternateLocale?: string | string[];
115
+ determiner?: 'a' | 'an' | 'the' | 'auto' | '';
116
+ emails?: string | string[];
117
+ phoneNumbers?: string | string[];
118
+ faxNumbers?: string | string[];
119
+ countryName?: string;
120
+ ttl?: number;
121
+ images?: QlaraOGImage | QlaraOGImage[];
122
+ audio?: QlaraOGAudio | QlaraOGAudio[];
123
+ videos?: QlaraOGVideo | QlaraOGVideo[];
124
+ }
125
+
126
+ export interface QlaraOpenGraphWebsite extends QlaraOpenGraphBase {
127
+ type?: 'website';
128
+ }
129
+
130
+ export interface QlaraOpenGraphArticle extends QlaraOpenGraphBase {
131
+ type: 'article';
132
+ publishedTime?: string;
133
+ modifiedTime?: string;
134
+ expirationTime?: string;
135
+ authors?: string | string[];
136
+ section?: string;
137
+ tags?: string | string[];
138
+ }
139
+
140
+ export interface QlaraOpenGraphBook extends QlaraOpenGraphBase {
141
+ type: 'book';
142
+ isbn?: string;
143
+ releaseDate?: string;
144
+ authors?: string | string[];
145
+ tags?: string | string[];
146
+ }
147
+
148
+ export interface QlaraOpenGraphProfile extends QlaraOpenGraphBase {
149
+ type: 'profile';
150
+ firstName?: string;
151
+ lastName?: string;
152
+ username?: string;
153
+ gender?: string;
154
+ }
155
+
156
+ export interface QlaraOpenGraphMusicSong extends QlaraOpenGraphBase {
157
+ type: 'music.song';
158
+ duration?: number;
159
+ albums?: string | string[];
160
+ musicians?: string | string[];
161
+ }
162
+
163
+ export interface QlaraOpenGraphMusicAlbum extends QlaraOpenGraphBase {
164
+ type: 'music.album';
165
+ songs?: string | string[];
166
+ musicians?: string | string[];
167
+ releaseDate?: string;
168
+ }
169
+
170
+ export interface QlaraOpenGraphMusicPlaylist extends QlaraOpenGraphBase {
171
+ type: 'music.playlist';
172
+ songs?: string | string[];
173
+ creators?: string | string[];
174
+ }
175
+
176
+ export interface QlaraOpenGraphMusicRadioStation extends QlaraOpenGraphBase {
177
+ type: 'music.radio_station';
178
+ creators?: string | string[];
179
+ }
180
+
181
+ export interface QlaraOpenGraphVideoMovie extends QlaraOpenGraphBase {
182
+ type: 'video.movie';
183
+ actors?: string | string[];
184
+ directors?: string | string[];
185
+ writers?: string | string[];
186
+ duration?: number;
187
+ releaseDate?: string;
188
+ tags?: string | string[];
189
+ }
190
+
191
+ export interface QlaraOpenGraphVideoEpisode extends QlaraOpenGraphBase {
192
+ type: 'video.episode';
193
+ actors?: string | string[];
194
+ directors?: string | string[];
195
+ writers?: string | string[];
196
+ duration?: number;
197
+ releaseDate?: string;
198
+ tags?: string | string[];
199
+ series?: string;
200
+ }
201
+
202
+ export interface QlaraOpenGraphVideoTVShow extends QlaraOpenGraphBase {
203
+ type: 'video.tv_show';
204
+ }
205
+
206
+ export interface QlaraOpenGraphVideoOther extends QlaraOpenGraphBase {
207
+ type: 'video.other';
208
+ }
209
+
210
+ export type QlaraOpenGraph =
211
+ | QlaraOpenGraphWebsite
212
+ | QlaraOpenGraphArticle
213
+ | QlaraOpenGraphBook
214
+ | QlaraOpenGraphProfile
215
+ | QlaraOpenGraphMusicSong
216
+ | QlaraOpenGraphMusicAlbum
217
+ | QlaraOpenGraphMusicPlaylist
218
+ | QlaraOpenGraphMusicRadioStation
219
+ | QlaraOpenGraphVideoMovie
220
+ | QlaraOpenGraphVideoEpisode
221
+ | QlaraOpenGraphVideoTVShow
222
+ | QlaraOpenGraphVideoOther;
223
+
224
+ // ── Twitter ──────────────────────────────────────────────────────
225
+
226
+ export interface QlaraTwitterImageDescriptor {
227
+ url: string;
228
+ alt?: string;
229
+ secureUrl?: string;
230
+ type?: string;
231
+ width?: string | number;
232
+ height?: string | number;
233
+ }
234
+
235
+ export type QlaraTwitterImage = string | QlaraTwitterImageDescriptor;
236
+
237
+ export interface QlaraTwitterPlayerDescriptor {
238
+ playerUrl: string;
239
+ streamUrl: string;
240
+ width: number;
241
+ height: number;
242
+ }
243
+
244
+ export interface QlaraTwitterAppDescriptor {
245
+ id: {
246
+ iphone?: string | number;
247
+ ipad?: string | number;
248
+ googleplay?: string;
249
+ };
250
+ url?: {
251
+ iphone?: string;
252
+ ipad?: string;
253
+ googleplay?: string;
254
+ };
255
+ name?: string;
256
+ }
257
+
258
+ export interface QlaraTwitterBase {
259
+ site?: string;
260
+ siteId?: string;
261
+ creator?: string;
262
+ creatorId?: string;
263
+ title?: string;
264
+ description?: string;
265
+ images?: QlaraTwitterImage | QlaraTwitterImage[];
266
+ }
267
+
268
+ export interface QlaraTwitterSummary extends QlaraTwitterBase {
269
+ card: 'summary';
270
+ }
271
+
272
+ export interface QlaraTwitterSummaryLargeImage extends QlaraTwitterBase {
273
+ card: 'summary_large_image';
274
+ }
275
+
276
+ export interface QlaraTwitterPlayer extends QlaraTwitterBase {
277
+ card: 'player';
278
+ players: QlaraTwitterPlayerDescriptor | QlaraTwitterPlayerDescriptor[];
279
+ }
280
+
281
+ export interface QlaraTwitterApp extends QlaraTwitterBase {
282
+ card: 'app';
283
+ app: QlaraTwitterAppDescriptor;
284
+ }
285
+
286
+ export type QlaraTwitter =
287
+ | QlaraTwitterBase
288
+ | QlaraTwitterSummary
289
+ | QlaraTwitterSummaryLargeImage
290
+ | QlaraTwitterPlayer
291
+ | QlaraTwitterApp;
292
+
293
+ // ── Verification ─────────────────────────────────────────────────
294
+
295
+ export interface QlaraVerification {
296
+ google?: string | string[];
297
+ yahoo?: string | string[];
298
+ yandex?: string | string[];
299
+ me?: string | string[];
300
+ other?: Record<string, string | string[]>;
301
+ }
302
+
303
+ // ── Apple Web App ────────────────────────────────────────────────
304
+
305
+ export interface QlaraAppleImageDescriptor {
306
+ url: string;
307
+ media?: string;
308
+ }
309
+
310
+ export type QlaraAppleImage = string | QlaraAppleImageDescriptor;
311
+
312
+ export interface QlaraAppleWebApp {
313
+ capable?: boolean;
314
+ title?: string;
315
+ startupImage?: QlaraAppleImage | QlaraAppleImage[];
316
+ statusBarStyle?: 'default' | 'black' | 'black-translucent';
317
+ }
318
+
319
+ // ── Format Detection ─────────────────────────────────────────────
320
+
321
+ export interface QlaraFormatDetection {
322
+ telephone?: boolean;
323
+ date?: boolean;
324
+ address?: boolean;
325
+ email?: boolean;
326
+ url?: boolean;
327
+ }
328
+
329
+ // ── iTunes App ───────────────────────────────────────────────────
330
+
331
+ export interface QlaraItunesApp {
332
+ appId: string;
333
+ appArgument?: string;
334
+ }
335
+
336
+ // ── Facebook ─────────────────────────────────────────────────────
337
+
338
+ export interface QlaraFacebook {
339
+ appId?: string;
340
+ admins?: string | string[];
341
+ }
342
+
343
+ // ── Pinterest ────────────────────────────────────────────────────
344
+
345
+ export interface QlaraPinterest {
346
+ richPin?: string | boolean;
347
+ }
348
+
349
+ // ── App Links ────────────────────────────────────────────────────
350
+
351
+ export interface QlaraAppLinksApple {
352
+ url: string;
353
+ app_store_id?: string | number;
354
+ app_name?: string;
355
+ }
356
+
357
+ export interface QlaraAppLinksAndroid {
358
+ package: string;
359
+ url?: string;
360
+ class?: string;
361
+ app_name?: string;
362
+ }
363
+
364
+ export interface QlaraAppLinksWindows {
365
+ url: string;
366
+ app_id?: string;
367
+ app_name?: string;
368
+ }
369
+
370
+ export interface QlaraAppLinksWeb {
371
+ url: string;
372
+ should_fallback?: boolean;
373
+ }
374
+
375
+ export interface QlaraAppLinks {
376
+ ios?: QlaraAppLinksApple | QlaraAppLinksApple[];
377
+ iphone?: QlaraAppLinksApple | QlaraAppLinksApple[];
378
+ ipad?: QlaraAppLinksApple | QlaraAppLinksApple[];
379
+ android?: QlaraAppLinksAndroid | QlaraAppLinksAndroid[];
380
+ windows_phone?: QlaraAppLinksWindows | QlaraAppLinksWindows[];
381
+ windows?: QlaraAppLinksWindows | QlaraAppLinksWindows[];
382
+ windows_universal?: QlaraAppLinksWindows | QlaraAppLinksWindows[];
383
+ web?: QlaraAppLinksWeb | QlaraAppLinksWeb[];
384
+ }
385
+
386
+ // ── Main Metadata Interface ──────────────────────────────────────
387
+
388
+ /** Metadata returned by a route's metaDataGenerator function. */
389
+ export interface QlaraMetadata {
390
+ // Basic metadata
391
+ title: string;
392
+ description?: string;
393
+ applicationName?: string;
394
+ authors?: QlaraAuthor | QlaraAuthor[];
395
+ generator?: string;
396
+ keywords?: string | string[];
397
+ referrer?: QlaraReferrer;
398
+ creator?: string;
399
+ publisher?: string;
400
+ category?: string;
401
+ classification?: string;
402
+ abstract?: string;
403
+
404
+ // Robots
405
+ robots?: QlaraRobots;
406
+
407
+ // Alternates (canonical, hreflang, etc.)
408
+ alternates?: QlaraAlternateURLs;
409
+
410
+ // Icons
411
+ icons?: string | QlaraIcon[] | QlaraIcons;
412
+
413
+ // Open Graph
414
+ openGraph?: QlaraOpenGraph;
415
+
416
+ // Twitter
417
+ twitter?: QlaraTwitter;
418
+
419
+ // Verification
420
+ verification?: QlaraVerification;
421
+
422
+ // Apple
423
+ appleWebApp?: boolean | QlaraAppleWebApp;
424
+
425
+ // Format detection
426
+ formatDetection?: QlaraFormatDetection;
427
+
428
+ // iTunes
429
+ itunes?: QlaraItunesApp;
430
+
431
+ // Facebook
432
+ facebook?: QlaraFacebook;
433
+
434
+ // Pinterest
435
+ pinterest?: QlaraPinterest;
436
+
437
+ // App links
438
+ appLinks?: QlaraAppLinks;
439
+
440
+ // Web app manifest
441
+ manifest?: string;
442
+
443
+ // Link tags
444
+ archives?: string | string[];
445
+ assets?: string | string[];
446
+ bookmarks?: string | string[];
447
+
448
+ // Pagination
449
+ pagination?: {
450
+ previous?: string;
451
+ next?: string;
452
+ };
453
+
454
+ // Catch-all for custom meta tags
455
+ other?: Record<string, string | number | (string | number)[]>;
456
+ }
457
+
458
+ /**
459
+ * Function that fetches data for a dynamic route and returns metadata.
460
+ * Equivalent to Next.js `generateMetadata()` — runs in the renderer Lambda
461
+ * with access to the data source.
462
+ *
463
+ * @param params - The route parameters, e.g. { id: '42' } for /product/:id
464
+ * @returns Metadata for the page, or null if the page doesn't exist
465
+ */
466
+ export type QlaraMetaDataGenerator = (params: Record<string, string>) => Promise<QlaraMetadata | null>;
467
+
468
+ /** A single route definition with its pattern and metadata generator. */
469
+ export interface QlaraRouteDefinition {
470
+ /** Dynamic route pattern, e.g. '/product/:id' */
471
+ route: string;
472
+ /** Function that fetches metadata for this route from the data source */
473
+ metaDataGenerator: QlaraMetaDataGenerator;
474
+ }
475
+
476
+ /**
477
+ * The route file default export type: an array of route definitions.
478
+ *
479
+ * Example:
480
+ * ```typescript
481
+ * import type { QlaraRoutes } from 'qlara';
482
+ * const routes: QlaraRoutes = [
483
+ * {
484
+ * route: '/product/:id',
485
+ * metaDataGenerator: async (params) => {
486
+ * const product = await getProduct(params.id);
487
+ * if (!product) return null;
488
+ * return { title: product.name, description: product.description };
489
+ * },
490
+ * },
491
+ * ];
492
+ * export default routes;
493
+ * ```
494
+ */
495
+ export type QlaraRoutes = QlaraRouteDefinition[];
496
+
497
+ export interface QlaraRoute {
498
+ /** Dynamic route pattern, e.g. '/product/:id' */
499
+ pattern: string;
500
+ }
501
+
502
+ export interface QlaraPluginConfig {
503
+ /**
504
+ * Path to a file that defines dynamic routes and their metadata generators.
505
+ * Each entry has a `route` pattern and a `metaDataGenerator` function.
506
+ *
507
+ * The file should `export default` a `QlaraRoutes` array.
508
+ * Route patterns are extracted from the `route` properties automatically.
509
+ *
510
+ * Example: `'./qlara.routes.ts'`
511
+ */
512
+ routeFile: string;
513
+ provider: QlaraProvider;
514
+ /** Env var names to forward to the renderer Lambda (values read from process.env at build time) */
515
+ env?: string[];
516
+ }
517
+
518
+ export interface QlaraProvider {
519
+ name: string;
520
+ /** The serializable config passed to the provider factory (e.g. { region: 'eu-west-1' }) */
521
+ config: Record<string, unknown>;
522
+ setup(config: QlaraDeployConfig): Promise<ProviderResources>;
523
+ deploy(config: QlaraDeployConfig, resources: ProviderResources): Promise<void>;
524
+ exists(config: QlaraDeployConfig): Promise<ProviderResources | null>;
525
+ teardown(resources: ProviderResources): Promise<void>;
526
+ }
527
+
528
+ export interface ProviderResources {
529
+ provider: string;
530
+ [key: string]: unknown;
531
+ }
532
+
533
+ /** Serialized config written to .qlara/config.json by the build plugin. Read by `qlara deploy`. */
534
+ export interface QlaraDeployConfig {
535
+ routes: QlaraRoute[];
536
+ provider: {
537
+ name: string;
538
+ [key: string]: unknown;
539
+ };
540
+ outputDir: string;
541
+ /** Absolute path to the route file. Bundled into the renderer Lambda at deploy time. */
542
+ routeFile: string;
543
+ /** Environment variables for the renderer Lambda (key-value pairs resolved at build time) */
544
+ env?: Record<string, string>;
545
+ }
546
+
547
+ export interface QlaraManifest {
548
+ version: 1;
549
+ routes: ManifestRoute[];
550
+ }
551
+
552
+ export interface ManifestRoute {
553
+ pattern: string;
554
+ paramNames: string[];
555
+ regex: string;
556
+ }
557
+
558
+ export interface RouteMatch {
559
+ route: ManifestRoute;
560
+ params: Record<string, string>;
561
+ }