spooder 5.0.1 → 5.0.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/README.md +159 -3
- package/package.json +1 -1
- package/src/api.ts +28 -5
package/README.md
CHANGED
|
@@ -526,7 +526,7 @@ pipe.off(event: string): void;
|
|
|
526
526
|
|
|
527
527
|
// templates
|
|
528
528
|
parse_template(template: string, replacements: Record<string, string>, drop_missing?: boolean): Promise<string>;
|
|
529
|
-
generate_hash_subs(length?: number, prefix?: string, hashes?: Record<string, string
|
|
529
|
+
generate_hash_subs(length?: number, prefix?: string, hashes?: Record<string, string>, format?: string): Promise<Record<string, string>>;
|
|
530
530
|
get_git_hashes(length: number): Promise<Record<string, string>>;
|
|
531
531
|
|
|
532
532
|
// database interface
|
|
@@ -1300,7 +1300,7 @@ server.bootstrap({
|
|
|
1300
1300
|
error_page: Bun.file('./html/error.html')
|
|
1301
1301
|
},
|
|
1302
1302
|
|
|
1303
|
-
|
|
1303
|
+
hash_subs: true,
|
|
1304
1304
|
|
|
1305
1305
|
static: {
|
|
1306
1306
|
directory: './static',
|
|
@@ -1341,6 +1341,143 @@ server.bootstrap({
|
|
|
1341
1341
|
});
|
|
1342
1342
|
```
|
|
1343
1343
|
|
|
1344
|
+
#### Bootstrap Options
|
|
1345
|
+
|
|
1346
|
+
The `BootstrapOptions` object accepts the following properties:
|
|
1347
|
+
|
|
1348
|
+
##### `base?: string | BunFile`
|
|
1349
|
+
Optional base template that wraps all route content. The base template should include `{{content}}` where the route content will be inserted.
|
|
1350
|
+
|
|
1351
|
+
```ts
|
|
1352
|
+
// Base template: base.html
|
|
1353
|
+
<html>
|
|
1354
|
+
<head><title>{{title}}</title></head>
|
|
1355
|
+
<body>{{content}}</body>
|
|
1356
|
+
</html>
|
|
1357
|
+
|
|
1358
|
+
// Usage
|
|
1359
|
+
server.bootstrap({
|
|
1360
|
+
base: Bun.file('./templates/base.html'),
|
|
1361
|
+
routes: {
|
|
1362
|
+
'/': {
|
|
1363
|
+
content: '<h1>Welcome</h1>',
|
|
1364
|
+
subs: { title: 'Home' }
|
|
1365
|
+
}
|
|
1366
|
+
}
|
|
1367
|
+
});
|
|
1368
|
+
```
|
|
1369
|
+
|
|
1370
|
+
##### `routes: Record<string, BootstrapRoute>`
|
|
1371
|
+
**Required.** Defines the routes and their content. Each route can have:
|
|
1372
|
+
- `content`: The page content (string or BunFile)
|
|
1373
|
+
- `subs?`: Template substitutions specific to this route
|
|
1374
|
+
|
|
1375
|
+
```ts
|
|
1376
|
+
routes: {
|
|
1377
|
+
'/about': {
|
|
1378
|
+
content: Bun.file('./pages/about.html'),
|
|
1379
|
+
subs: {
|
|
1380
|
+
title: 'About Us',
|
|
1381
|
+
description: 'Learn more about our company'
|
|
1382
|
+
}
|
|
1383
|
+
}
|
|
1384
|
+
}
|
|
1385
|
+
```
|
|
1386
|
+
|
|
1387
|
+
##### `cache?: CacheOptions | ReturnType<typeof cache_http>`
|
|
1388
|
+
Optional HTTP caching configuration. Can be:
|
|
1389
|
+
- A `CacheOptions` object (creates new cache instance)
|
|
1390
|
+
- An existing cache instance from `cache_http()`
|
|
1391
|
+
- Omitted to disable caching
|
|
1392
|
+
|
|
1393
|
+
```ts
|
|
1394
|
+
cache: {
|
|
1395
|
+
ttl: 5 * 60 * 1000, // 5 minutes
|
|
1396
|
+
max_size: 10 * 1024 * 1024, // 10 MB
|
|
1397
|
+
use_etags: true,
|
|
1398
|
+
use_canary_reporting: true
|
|
1399
|
+
}
|
|
1400
|
+
```
|
|
1401
|
+
|
|
1402
|
+
##### `hash_subs?: boolean | object`
|
|
1403
|
+
When enabled, automatically generates git hash-based substitutions. Can be a boolean for defaults or an object for custom options.
|
|
1404
|
+
|
|
1405
|
+
**Boolean usage (uses defaults):**
|
|
1406
|
+
```ts
|
|
1407
|
+
hash_subs: true // Equivalent to { length: 7, prefix: 'hash=' }
|
|
1408
|
+
```
|
|
1409
|
+
|
|
1410
|
+
**Object usage (custom options):**
|
|
1411
|
+
```ts
|
|
1412
|
+
hash_subs: {
|
|
1413
|
+
length: 7, // Hash length (default: 7)
|
|
1414
|
+
prefix: 'asset=', // Substitution prefix (default: 'hash=')
|
|
1415
|
+
format: '$file?v=$hash', // Custom format (default: just hash)
|
|
1416
|
+
hashes: { ... } // Pre-generated hash map from get_git_hashes (optional)
|
|
1417
|
+
}
|
|
1418
|
+
```
|
|
1419
|
+
|
|
1420
|
+
**Examples:**
|
|
1421
|
+
```ts
|
|
1422
|
+
// Default hash substitutions
|
|
1423
|
+
hash_subs: true
|
|
1424
|
+
// Creates: {{hash=static/css/style.css}} -> "a1b2c3d"
|
|
1425
|
+
// Usage: <link href="/css/style.css?v={{hash=static/css/style.css}}">
|
|
1426
|
+
|
|
1427
|
+
// Asset-style substitutions (reduces verbosity)
|
|
1428
|
+
hash_subs: { prefix: 'asset=', format: '$file?v=$hash' }
|
|
1429
|
+
// Creates: {{asset=static/css/style.css}} -> "static/css/style.css?v=a1b2c3d"
|
|
1430
|
+
// Usage: <link href="{{asset=static/css/style.css}}">
|
|
1431
|
+
```
|
|
1432
|
+
|
|
1433
|
+
##### `error?: object`
|
|
1434
|
+
Optional error page configuration:
|
|
1435
|
+
- `error_page`: Template for error pages (string or BunFile)
|
|
1436
|
+
- `use_canary_reporting?`: Whether to report errors via canary
|
|
1437
|
+
|
|
1438
|
+
Error templates receive `{{error_code}}` and `{{error_text}}` substitutions.
|
|
1439
|
+
|
|
1440
|
+
```ts
|
|
1441
|
+
error: {
|
|
1442
|
+
error_page: Bun.file('./templates/error.html'),
|
|
1443
|
+
use_canary_reporting: true
|
|
1444
|
+
}
|
|
1445
|
+
```
|
|
1446
|
+
|
|
1447
|
+
##### `static?: object`
|
|
1448
|
+
Optional static file serving configuration:
|
|
1449
|
+
- `route`: URL path prefix for static files
|
|
1450
|
+
- `directory`: Local directory containing static files
|
|
1451
|
+
- `sub_ext?`: Array of file extensions that should have template substitution applied
|
|
1452
|
+
|
|
1453
|
+
```ts
|
|
1454
|
+
static: {
|
|
1455
|
+
route: '/assets',
|
|
1456
|
+
directory: './public',
|
|
1457
|
+
sub_ext: ['.css', '.js'] // These files get template processing
|
|
1458
|
+
}
|
|
1459
|
+
```
|
|
1460
|
+
|
|
1461
|
+
Files with extensions in `sub_ext` will have template substitutions applied before serving.
|
|
1462
|
+
|
|
1463
|
+
##### `global_subs?: Record<string, BootstrapSub>`
|
|
1464
|
+
Optional global template substitutions available to all routes, error pages, and static files with `sub_ext`.
|
|
1465
|
+
|
|
1466
|
+
```ts
|
|
1467
|
+
global_subs: {
|
|
1468
|
+
site_name: 'My Website',
|
|
1469
|
+
version: '1.0.0',
|
|
1470
|
+
api_url: 'https://api.example.com'
|
|
1471
|
+
}
|
|
1472
|
+
```
|
|
1473
|
+
|
|
1474
|
+
#### Template Processing Order
|
|
1475
|
+
|
|
1476
|
+
1. Route content is loaded
|
|
1477
|
+
2. If `base` is defined, content is wrapped using `{{content}}` substitution
|
|
1478
|
+
3. Route-specific `subs` and `global_subs` are applied
|
|
1479
|
+
4. Hash substitutions (if enabled) are applied
|
|
1480
|
+
|
|
1344
1481
|
<a id="api-error-handling"></a>
|
|
1345
1482
|
## API > Error Handling
|
|
1346
1483
|
|
|
@@ -1803,7 +1940,7 @@ await parse_template(..., {
|
|
|
1803
1940
|
</t-for>
|
|
1804
1941
|
```
|
|
1805
1942
|
|
|
1806
|
-
### 🔧 `generate_hash_subs(length: number, prefix: string, hashes?: Record<string, string
|
|
1943
|
+
### 🔧 `generate_hash_subs(length: number, prefix: string, hashes?: Record<string, string>, format?: string): Promise<Record<string, string>>`
|
|
1807
1944
|
|
|
1808
1945
|
Generate a replacement table for mapping file paths to hashes in templates. This is useful for cache-busting static assets.
|
|
1809
1946
|
|
|
@@ -1847,6 +1984,25 @@ server.route('/test', (req, url) => {
|
|
|
1847
1984
|
});
|
|
1848
1985
|
```
|
|
1849
1986
|
|
|
1987
|
+
#### Custom Format Parameter
|
|
1988
|
+
|
|
1989
|
+
The optional `format` parameter allows you to customize how the substitution values are formatted. Use `$file` and `$hash` placeholders within the format string:
|
|
1990
|
+
|
|
1991
|
+
```ts
|
|
1992
|
+
// Asset-style substitutions - reduces verbosity
|
|
1993
|
+
const asset_subs = await generate_hash_subs(7, 'asset=', undefined, '$file?v=$hash');
|
|
1994
|
+
|
|
1995
|
+
// Usage in templates:
|
|
1996
|
+
// <link rel="stylesheet" href="{{asset=static/css/shared.css}}">
|
|
1997
|
+
// Resolves to: static/css/shared.css?v=a1b2c3d
|
|
1998
|
+
|
|
1999
|
+
// Custom format example:
|
|
2000
|
+
await generate_hash_subs(7, 'url=', undefined, 'https://assets.example.com/$file?hash=$hash');
|
|
2001
|
+
// Result: { 'url=app.js': 'https://assets.example.com/app.js?hash=a1b2c3d' }
|
|
2002
|
+
```
|
|
2003
|
+
|
|
2004
|
+
When `format` is omitted, the default behavior returns just the hash value (backward compatible).
|
|
2005
|
+
|
|
1850
2006
|
### 🔧 ``get_git_hashes(length: number): Promise<Record<string, string>>``
|
|
1851
2007
|
|
|
1852
2008
|
Internally, `generate_hash_subs()` uses `get_git_hashes()` to retrieve the hash table from git. This function is exposed for convenience.
|
package/package.json
CHANGED
package/src/api.ts
CHANGED
|
@@ -549,14 +549,22 @@ export async function get_git_hashes(length = 7): Promise<Record<string, string>
|
|
|
549
549
|
return hash_map;
|
|
550
550
|
}
|
|
551
551
|
|
|
552
|
-
export async function generate_hash_subs(length = 7, prefix = 'hash=', hashes?: Record<string, string
|
|
552
|
+
export async function generate_hash_subs(length = 7, prefix = 'hash=', hashes?: Record<string, string>, format?: string): Promise<Record<string, string>> {
|
|
553
553
|
const hash_map: Record<string, string> = {};
|
|
554
554
|
|
|
555
555
|
if (!hashes)
|
|
556
556
|
hashes = await get_git_hashes(length);
|
|
557
557
|
|
|
558
|
-
for (const [file, hash] of Object.entries(hashes))
|
|
559
|
-
|
|
558
|
+
for (const [file, hash] of Object.entries(hashes)) {
|
|
559
|
+
if (format !== undefined) {
|
|
560
|
+
const formatted_value = format
|
|
561
|
+
.replace(/\$file/g, file)
|
|
562
|
+
.replace(/\$hash/g, hash);
|
|
563
|
+
hash_map[prefix + file] = formatted_value;
|
|
564
|
+
} else {
|
|
565
|
+
hash_map[prefix + file] = hash;
|
|
566
|
+
}
|
|
567
|
+
}
|
|
560
568
|
|
|
561
569
|
return hash_map;
|
|
562
570
|
}
|
|
@@ -987,7 +995,12 @@ type BootstrapOptions = {
|
|
|
987
995
|
base?: string | BunFile;
|
|
988
996
|
routes: Record<string, BootstrapRoute>;
|
|
989
997
|
cache?: ReturnType<typeof cache_http> | CacheOptions;
|
|
990
|
-
|
|
998
|
+
hash_subs?: boolean | {
|
|
999
|
+
length?: number;
|
|
1000
|
+
prefix?: string;
|
|
1001
|
+
format?: string;
|
|
1002
|
+
hashes?: Record<string, string>;
|
|
1003
|
+
};
|
|
991
1004
|
error?: {
|
|
992
1005
|
use_canary_reporting?: boolean;
|
|
993
1006
|
error_page: string | BunFile;
|
|
@@ -1407,7 +1420,17 @@ export function http_serve(port: number, hostname?: string) {
|
|
|
1407
1420
|
|
|
1408
1421
|
/* Bootstrap a static web server */
|
|
1409
1422
|
bootstrap: async function(options: BootstrapOptions) {
|
|
1410
|
-
|
|
1423
|
+
let hash_sub_table = {};
|
|
1424
|
+
|
|
1425
|
+
if (options.hash_subs) {
|
|
1426
|
+
if (options.hash_subs === true) {
|
|
1427
|
+
hash_sub_table = await generate_hash_subs();
|
|
1428
|
+
} else {
|
|
1429
|
+
const { length, prefix, format, hashes } = options.hash_subs;
|
|
1430
|
+
hash_sub_table = await generate_hash_subs(length, prefix, hashes, format);
|
|
1431
|
+
}
|
|
1432
|
+
}
|
|
1433
|
+
|
|
1411
1434
|
const global_sub_table = sub_table_merge(hash_sub_table, options.global_subs);
|
|
1412
1435
|
|
|
1413
1436
|
let cache = options.cache;
|