spooder 6.2.0 → 6.2.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 +28 -0
- package/package.json +1 -1
- package/src/api.ts +21 -5
package/README.md
CHANGED
|
@@ -2520,6 +2520,34 @@ await parse_template(..., {
|
|
|
2520
2520
|
</t-for>
|
|
2521
2521
|
```
|
|
2522
2522
|
|
|
2523
|
+
#### Object Serialization
|
|
2524
|
+
|
|
2525
|
+
When a replacement value is an object or array, it is automatically serialized to JSON. This allows server-side data to be embedded directly into client-side scripts.
|
|
2526
|
+
|
|
2527
|
+
```ts
|
|
2528
|
+
const config = {
|
|
2529
|
+
debug: true,
|
|
2530
|
+
api_url: '/api/v1',
|
|
2531
|
+
features: ['auth', 'logging']
|
|
2532
|
+
};
|
|
2533
|
+
|
|
2534
|
+
await parse_template('<script>const CONFIG = {{config}};</script>', { config });
|
|
2535
|
+
// Result: "<script>const CONFIG = {"debug":true,"api_url":"/api/v1","features":["auth","logging"]};</script>"
|
|
2536
|
+
```
|
|
2537
|
+
|
|
2538
|
+
This also works with nested objects accessed via dot notation:
|
|
2539
|
+
|
|
2540
|
+
```ts
|
|
2541
|
+
const data = {
|
|
2542
|
+
app: {
|
|
2543
|
+
settings: { theme: 'dark', lang: 'en' }
|
|
2544
|
+
}
|
|
2545
|
+
};
|
|
2546
|
+
|
|
2547
|
+
await parse_template('<script>const SETTINGS = {{app.settings}};</script>', data);
|
|
2548
|
+
// Result: "<script>const SETTINGS = {"theme":"dark","lang":"en"};</script>"
|
|
2549
|
+
```
|
|
2550
|
+
|
|
2523
2551
|
<a id="api-cache-busting"></a>
|
|
2524
2552
|
## API > Cache Busting
|
|
2525
2553
|
|
package/package.json
CHANGED
package/src/api.ts
CHANGED
|
@@ -1040,8 +1040,12 @@ export async function parse_template(template: string, replacements: Replacement
|
|
|
1040
1040
|
replacement = await replacement();
|
|
1041
1041
|
}
|
|
1042
1042
|
|
|
1043
|
-
if (replacement !== undefined)
|
|
1043
|
+
if (replacement !== undefined) {
|
|
1044
|
+
if (typeof replacement === 'object' && replacement !== null)
|
|
1045
|
+
return JSON.stringify(replacement);
|
|
1046
|
+
|
|
1044
1047
|
return replacement;
|
|
1048
|
+
}
|
|
1045
1049
|
|
|
1046
1050
|
if (!drop_missing)
|
|
1047
1051
|
return match;
|
|
@@ -1332,6 +1336,8 @@ export const HTTP_STATUS_CODE = {
|
|
|
1332
1336
|
type HTTP_METHOD = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'HEAD' | 'OPTIONS' | 'CONNECT' | 'TRACE';
|
|
1333
1337
|
type HTTP_METHODS = HTTP_METHOD|HTTP_METHOD[];
|
|
1334
1338
|
|
|
1339
|
+
type BodylessMethod = 'GET' | 'HEAD';
|
|
1340
|
+
|
|
1335
1341
|
export function http_apply_range(file: BunFile, request: Request): BunFile {
|
|
1336
1342
|
const range_header = request.headers.get('range');
|
|
1337
1343
|
if (range_header !== null) {
|
|
@@ -1384,7 +1390,7 @@ type ErrorHandler = (err: Error, req: Request, url: URL) => Resolvable<Response>
|
|
|
1384
1390
|
type DefaultHandler = (req: Request, status_code: number) => HandlerReturnType;
|
|
1385
1391
|
type StatusCodeHandler = (req: Request) => HandlerReturnType;
|
|
1386
1392
|
|
|
1387
|
-
type JSONRequestHandler = (req: Request, url: URL, json:
|
|
1393
|
+
type JSONRequestHandler<T extends JsonObject | null = JsonObject> = (req: Request, url: URL, json: T) => HandlerReturnType;
|
|
1388
1394
|
|
|
1389
1395
|
export type ServerSentEventClient = {
|
|
1390
1396
|
message: (message: string) => void;
|
|
@@ -1823,10 +1829,20 @@ export function http_serve(port: number, hostname?: string) {
|
|
|
1823
1829
|
log_spooder(`server started on port {${server.port}} (host: {${hostname ?? 'unspecified'}})`);
|
|
1824
1830
|
|
|
1825
1831
|
type ThrottleHandler = {
|
|
1826
|
-
(delta: number, handler: JSONRequestHandler): JSONRequestHandler
|
|
1832
|
+
(delta: number, handler: JSONRequestHandler<JsonObject>): JSONRequestHandler<JsonObject>;
|
|
1833
|
+
(delta: number, handler: JSONRequestHandler<null>): JSONRequestHandler<null>;
|
|
1827
1834
|
(delta: number, handler: RequestHandler): RequestHandler;
|
|
1828
1835
|
};
|
|
1829
1836
|
|
|
1837
|
+
type JsonEndpointHandler = {
|
|
1838
|
+
<M extends BodylessMethod>(path: string, handler: JSONRequestHandler<null>, method: M): void;
|
|
1839
|
+
<M extends BodylessMethod[]>(path: string, handler: JSONRequestHandler<null>, method: M): void;
|
|
1840
|
+
<M extends Exclude<HTTP_METHOD, BodylessMethod>>(path: string, handler: JSONRequestHandler<JsonObject>, method: M): void;
|
|
1841
|
+
<M extends Exclude<HTTP_METHOD, BodylessMethod>[]>(path: string, handler: JSONRequestHandler<JsonObject>, method: M): void;
|
|
1842
|
+
<M extends HTTP_METHOD[]>(path: string, handler: JSONRequestHandler<JsonObject | null>, method: M): void;
|
|
1843
|
+
(path: string, handler: JSONRequestHandler<JsonObject>): void;
|
|
1844
|
+
};
|
|
1845
|
+
|
|
1830
1846
|
return {
|
|
1831
1847
|
/** Register a handler for a specific route. */
|
|
1832
1848
|
route: (path: string, handler: RequestHandler, method: HTTP_METHODS = 'GET'): void => {
|
|
@@ -1853,7 +1869,7 @@ export function http_serve(port: number, hostname?: string) {
|
|
|
1853
1869
|
}) as ThrottleHandler,
|
|
1854
1870
|
|
|
1855
1871
|
/** Register a JSON endpoint with automatic content validation. */
|
|
1856
|
-
json: (path: string, handler: JSONRequestHandler
|
|
1872
|
+
json: ((path: string, handler: JSONRequestHandler<JsonObject | null>, method: HTTP_METHODS = 'POST'): void => {
|
|
1857
1873
|
const json_wrapper: RequestHandler = async (req: Request, url: URL) => {
|
|
1858
1874
|
// handle CORS preflight
|
|
1859
1875
|
if (req.method === 'OPTIONS') {
|
|
@@ -1890,7 +1906,7 @@ export function http_serve(port: number, hostname?: string) {
|
|
|
1890
1906
|
|
|
1891
1907
|
const methods: HTTP_METHODS = Array.isArray(method) ? [...method, 'OPTIONS'] : [method, 'OPTIONS'];
|
|
1892
1908
|
routes.push([path.split('/'), json_wrapper, methods]);
|
|
1893
|
-
},
|
|
1909
|
+
}) as JsonEndpointHandler,
|
|
1894
1910
|
|
|
1895
1911
|
/** Unregister a specific route */
|
|
1896
1912
|
unroute: (path: string): void => {
|