@server/next 0.35.1 → 0.36.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/index.d.ts +7 -1
- package/index.js +103 -67
- package/package.json +1 -1
package/index.d.ts
CHANGED
|
@@ -34,11 +34,13 @@ type BodyOption = BodyMode | {
|
|
|
34
34
|
mode?: BodyMode;
|
|
35
35
|
max?: number | string | false;
|
|
36
36
|
};
|
|
37
|
+
type CacheOption = string | number | false;
|
|
37
38
|
type RouteOptions = {
|
|
38
39
|
tags?: string | string[];
|
|
39
40
|
title?: string;
|
|
40
41
|
description?: string;
|
|
41
42
|
body?: BodyOption;
|
|
43
|
+
cache?: CacheOption;
|
|
42
44
|
};
|
|
43
45
|
type Route = {
|
|
44
46
|
path: string;
|
|
@@ -188,6 +190,7 @@ type Options = {
|
|
|
188
190
|
favicon?: string | BucketFile;
|
|
189
191
|
security?: boolean | SecurityOptions;
|
|
190
192
|
body?: BodyOption;
|
|
193
|
+
cache?: CacheOption;
|
|
191
194
|
};
|
|
192
195
|
type Settings = {
|
|
193
196
|
port: number;
|
|
@@ -207,6 +210,7 @@ type Settings = {
|
|
|
207
210
|
favicon?: string | BucketFile;
|
|
208
211
|
security: SecuritySettings;
|
|
209
212
|
body: BodyOption;
|
|
213
|
+
cache?: CacheOption;
|
|
210
214
|
};
|
|
211
215
|
type Time = {
|
|
212
216
|
(name: string): void;
|
|
@@ -345,6 +349,7 @@ declare class Reply {
|
|
|
345
349
|
type(type?: string): this;
|
|
346
350
|
download(name?: string): this;
|
|
347
351
|
headers(key: string | Record<string, string>, value?: string): this;
|
|
352
|
+
cache(value: CacheOption): this;
|
|
348
353
|
cookies(key: string | Record<string, CookieOptions>, value?: CookieOptions): this;
|
|
349
354
|
json(body: unknown): Response;
|
|
350
355
|
redirect(path: string): Response;
|
|
@@ -355,6 +360,7 @@ type Params<K extends keyof Reply> = Reply[K] extends (...args: infer A) => any
|
|
|
355
360
|
declare const status: (...args: Params<"status">) => Reply;
|
|
356
361
|
declare const headers: (...args: Params<"headers">) => Reply;
|
|
357
362
|
declare const type: (...args: Params<"type">) => Reply;
|
|
363
|
+
declare const cache: (...args: Params<"cache">) => Reply;
|
|
358
364
|
declare const download: (...args: Params<"download">) => Reply;
|
|
359
365
|
declare const cookies: (...args: Params<"cookies">) => Reply;
|
|
360
366
|
declare const send: (...args: Params<"send">) => Response;
|
|
@@ -494,4 +500,4 @@ declare class Server<O extends ServerConfig = {}> extends Router<O> {
|
|
|
494
500
|
}
|
|
495
501
|
declare function server<Session extends Record<string, any> = {}, User extends Record<string, any> = {}>(options?: Options): Server<ServerConfig<Session, User>>;
|
|
496
502
|
|
|
497
|
-
export { type AuthOption, type AuthSession, type AuthSettings, type AuthUser, type BasicValue, type Body, type BodyMode, type BodyOption, type Bucket, type BucketFile, type BunEnv, type Context, type Cookie, type CorsSettings, type ExtractPathParams, type FileInfo, type InferParamType, type InlineReply, type KVStore, type LimitOptions, type LogLevel, type Logger, type Method, type Middleware, type Options, type ParamTypeMap, type ParamsToObject, type PathToParams, type Platform, type Provider, type Route, type RouteOptions, type RouterMethod, type SecurityOptions, type SecuritySettings, type SerializableValue, Server, type ServerConfig, TypedServerError as ServerError, type Settings, type Strategy, type Time, UploadPipeline, type UploadedFile, cookies, server as default, download, file, headers, json, redirect, router, send, status, type, upload };
|
|
503
|
+
export { type AuthOption, type AuthSession, type AuthSettings, type AuthUser, type BasicValue, type Body, type BodyMode, type BodyOption, type Bucket, type BucketFile, type BunEnv, type CacheOption, type Context, type Cookie, type CorsSettings, type ExtractPathParams, type FileInfo, type InferParamType, type InlineReply, type KVStore, type LimitOptions, type LogLevel, type Logger, type Method, type Middleware, type Options, type ParamTypeMap, type ParamsToObject, type PathToParams, type Platform, type Provider, type Route, type RouteOptions, type RouterMethod, type SecurityOptions, type SecuritySettings, type SerializableValue, Server, type ServerConfig, TypedServerError as ServerError, type Settings, type Strategy, type Time, UploadPipeline, type UploadedFile, cache, cookies, server as default, download, file, headers, json, redirect, router, send, status, type, upload };
|
package/index.js
CHANGED
|
@@ -683,6 +683,97 @@ async function resolveBody(ctx, body) {
|
|
|
683
683
|
return parsed;
|
|
684
684
|
}
|
|
685
685
|
|
|
686
|
+
// src/helpers/createCookies.ts
|
|
687
|
+
var EXPIRED = (/* @__PURE__ */ new Date(0)).toUTCString();
|
|
688
|
+
var times = /(-?(?:\d+\.?\d*|\d*\.?\d+)(?:e[-+]?\d+)?)\s*([\p{L}]*)/iu;
|
|
689
|
+
parse.millisecond = parse.ms = 1e-3;
|
|
690
|
+
parse.second = parse.sec = parse.s = parse[""] = 1;
|
|
691
|
+
parse.minute = parse.min = parse.m = parse.s * 60;
|
|
692
|
+
parse.hour = parse.hr = parse.h = parse.m * 60;
|
|
693
|
+
parse.day = parse.d = parse.h * 24;
|
|
694
|
+
parse.week = parse.wk = parse.w = parse.d * 7;
|
|
695
|
+
parse.year = parse.yr = parse.y = parse.d * 365.25;
|
|
696
|
+
parse.month = parse.b = parse.y / 12;
|
|
697
|
+
function parse(str) {
|
|
698
|
+
if (str === null || str === void 0) return null;
|
|
699
|
+
if (typeof str === "number") return str;
|
|
700
|
+
if (typeof str !== "string") {
|
|
701
|
+
throw new Error(`Not a string: ${str} (${typeof str})`);
|
|
702
|
+
}
|
|
703
|
+
str = str.toLowerCase().replace(/[,_]/g, "");
|
|
704
|
+
const [_, value, units] = times.exec(str) || [];
|
|
705
|
+
if (!units) return null;
|
|
706
|
+
const unitValue = parse[units] || parse[units.replace(/s$/, "")];
|
|
707
|
+
if (!unitValue) return null;
|
|
708
|
+
const result = unitValue * parseFloat(value);
|
|
709
|
+
return Math.abs(Math.round(result * 1e3));
|
|
710
|
+
}
|
|
711
|
+
function normalizeExpires(expires) {
|
|
712
|
+
if (expires === null || expires === void 0) return void 0;
|
|
713
|
+
if (expires === 0) return EXPIRED;
|
|
714
|
+
if (typeof expires === "string") {
|
|
715
|
+
if (/^[\d._]+\w+$/.test(expires)) {
|
|
716
|
+
return new Date(Date.now() + parse(expires)).toUTCString();
|
|
717
|
+
} else {
|
|
718
|
+
return expires;
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
if (typeof expires === "number") {
|
|
722
|
+
return new Date(Date.now() + expires).toUTCString();
|
|
723
|
+
}
|
|
724
|
+
if (expires instanceof Date) {
|
|
725
|
+
return expires.toUTCString();
|
|
726
|
+
}
|
|
727
|
+
return void 0;
|
|
728
|
+
}
|
|
729
|
+
function createCookies(key, val) {
|
|
730
|
+
if (val.value === null) val.expires = EXPIRED;
|
|
731
|
+
const { value, path: path2, expires, maxAge, httpOnly, secure, sameSite } = val;
|
|
732
|
+
let str = `${key}=${value || ""};Path=${path2 || "/"}`;
|
|
733
|
+
if (typeof expires !== "undefined") str += `;Expires=${normalizeExpires(expires)}`;
|
|
734
|
+
if (typeof maxAge === "number") str += `;Max-Age=${maxAge}`;
|
|
735
|
+
if (httpOnly) str += ";HttpOnly";
|
|
736
|
+
if (secure) str += ";Secure";
|
|
737
|
+
if (sameSite) str += `;SameSite=${sameSite}`;
|
|
738
|
+
return str;
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
// src/helpers/etag.ts
|
|
742
|
+
function etag(bytes) {
|
|
743
|
+
let h = 2166136261;
|
|
744
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
745
|
+
h ^= bytes[i];
|
|
746
|
+
h = Math.imul(h, 16777619);
|
|
747
|
+
}
|
|
748
|
+
return `"${bytes.length.toString(16)}-${(h >>> 0).toString(16)}"`;
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
// src/helpers/cache.ts
|
|
752
|
+
function resolveCache(value) {
|
|
753
|
+
if (value === false || value === 0) return "no-store";
|
|
754
|
+
if (typeof value === "number") return `public, max-age=${Math.round(value)}`;
|
|
755
|
+
if (typeof value !== "string") return null;
|
|
756
|
+
const ms = parse(value);
|
|
757
|
+
return ms === null ? null : `public, max-age=${Math.round(ms / 1e3)}`;
|
|
758
|
+
}
|
|
759
|
+
async function applyCache(out, ctx) {
|
|
760
|
+
if (ctx.method !== "get" || out.status !== 200) return out;
|
|
761
|
+
if (!out.headers.has("cache-control")) {
|
|
762
|
+
const value = resolveCache(ctx.options.cache);
|
|
763
|
+
if (value) out.headers.set("cache-control", value);
|
|
764
|
+
}
|
|
765
|
+
if (out.headers.has("etag") || !out.headers.has("content-length")) return out;
|
|
766
|
+
const bytes = new Uint8Array(await out.arrayBuffer());
|
|
767
|
+
const tag = etag(bytes);
|
|
768
|
+
const headers2 = new Headers(out.headers);
|
|
769
|
+
headers2.set("etag", tag);
|
|
770
|
+
if (ctx.headers["if-none-match"] === tag) {
|
|
771
|
+
headers2.delete("content-length");
|
|
772
|
+
return new Response(null, { status: 304, headers: headers2 });
|
|
773
|
+
}
|
|
774
|
+
return new Response(bytes, { status: 200, headers: headers2 });
|
|
775
|
+
}
|
|
776
|
+
|
|
686
777
|
// src/helpers/clientIp.ts
|
|
687
778
|
var first = (v) => (Array.isArray(v) ? v[0] : v) || "";
|
|
688
779
|
var normalize = (ip) => ip.replace(/^::ffff:/, "");
|
|
@@ -707,7 +798,7 @@ function isReadableStream(obj) {
|
|
|
707
798
|
}
|
|
708
799
|
|
|
709
800
|
// src/reply.ts
|
|
710
|
-
var
|
|
801
|
+
var EXPIRED2 = (/* @__PURE__ */ new Date(0)).toUTCString();
|
|
711
802
|
var Reply = class {
|
|
712
803
|
res;
|
|
713
804
|
constructor() {
|
|
@@ -743,6 +834,11 @@ var Reply = class {
|
|
|
743
834
|
this.res.headers.append(key, value);
|
|
744
835
|
return this;
|
|
745
836
|
}
|
|
837
|
+
cache(value) {
|
|
838
|
+
const resolved = resolveCache(value);
|
|
839
|
+
if (resolved) this.res.headers.set("cache-control", resolved);
|
|
840
|
+
return this;
|
|
841
|
+
}
|
|
746
842
|
cookies(key, value) {
|
|
747
843
|
if (typeof key === "object") {
|
|
748
844
|
Object.entries(key).map(([key2, value2]) => this.cookies(key2, value2));
|
|
@@ -752,7 +848,7 @@ var Reply = class {
|
|
|
752
848
|
Object.values(value).map((val) => this.cookies(key, val));
|
|
753
849
|
return this;
|
|
754
850
|
}
|
|
755
|
-
if (value === null) return this.cookies(key, { expires:
|
|
851
|
+
if (value === null) return this.cookies(key, { expires: EXPIRED2 });
|
|
756
852
|
if (typeof value !== "object") return this.cookies(key, { value });
|
|
757
853
|
return this.headers("set-cookie", createCookies(key, value));
|
|
758
854
|
}
|
|
@@ -822,6 +918,7 @@ var r = () => new Reply();
|
|
|
822
918
|
var status = (...args) => r().status(...args);
|
|
823
919
|
var headers = (...args) => r().headers(...args);
|
|
824
920
|
var type = (...args) => r().type(...args);
|
|
921
|
+
var cache = (...args) => r().cache(...args);
|
|
825
922
|
var download = (...args) => r().download(...args);
|
|
826
923
|
var cookies = (...args) => r().cookies(...args);
|
|
827
924
|
var send = (...args) => r().send(...args);
|
|
@@ -939,61 +1036,6 @@ async function finishLogin(ctx, input) {
|
|
|
939
1036
|
throw new Error("Unknown auth type");
|
|
940
1037
|
}
|
|
941
1038
|
|
|
942
|
-
// src/helpers/createCookies.ts
|
|
943
|
-
var EXPIRED2 = (/* @__PURE__ */ new Date(0)).toUTCString();
|
|
944
|
-
var times = /(-?(?:\d+\.?\d*|\d*\.?\d+)(?:e[-+]?\d+)?)\s*([\p{L}]*)/iu;
|
|
945
|
-
parse.millisecond = parse.ms = 1e-3;
|
|
946
|
-
parse.second = parse.sec = parse.s = parse[""] = 1;
|
|
947
|
-
parse.minute = parse.min = parse.m = parse.s * 60;
|
|
948
|
-
parse.hour = parse.hr = parse.h = parse.m * 60;
|
|
949
|
-
parse.day = parse.d = parse.h * 24;
|
|
950
|
-
parse.week = parse.wk = parse.w = parse.d * 7;
|
|
951
|
-
parse.year = parse.yr = parse.y = parse.d * 365.25;
|
|
952
|
-
parse.month = parse.b = parse.y / 12;
|
|
953
|
-
function parse(str) {
|
|
954
|
-
if (str === null || str === void 0) return null;
|
|
955
|
-
if (typeof str === "number") return str;
|
|
956
|
-
if (typeof str !== "string") {
|
|
957
|
-
throw new Error(`Not a string: ${str} (${typeof str})`);
|
|
958
|
-
}
|
|
959
|
-
str = str.toLowerCase().replace(/[,_]/g, "");
|
|
960
|
-
const [_, value, units] = times.exec(str) || [];
|
|
961
|
-
if (!units) return null;
|
|
962
|
-
const unitValue = parse[units] || parse[units.replace(/s$/, "")];
|
|
963
|
-
if (!unitValue) return null;
|
|
964
|
-
const result = unitValue * parseFloat(value);
|
|
965
|
-
return Math.abs(Math.round(result * 1e3));
|
|
966
|
-
}
|
|
967
|
-
function normalizeExpires(expires) {
|
|
968
|
-
if (expires === null || expires === void 0) return void 0;
|
|
969
|
-
if (expires === 0) return EXPIRED2;
|
|
970
|
-
if (typeof expires === "string") {
|
|
971
|
-
if (/^[\d._]+\w+$/.test(expires)) {
|
|
972
|
-
return new Date(Date.now() + parse(expires)).toUTCString();
|
|
973
|
-
} else {
|
|
974
|
-
return expires;
|
|
975
|
-
}
|
|
976
|
-
}
|
|
977
|
-
if (typeof expires === "number") {
|
|
978
|
-
return new Date(Date.now() + expires).toUTCString();
|
|
979
|
-
}
|
|
980
|
-
if (expires instanceof Date) {
|
|
981
|
-
return expires.toUTCString();
|
|
982
|
-
}
|
|
983
|
-
return void 0;
|
|
984
|
-
}
|
|
985
|
-
function createCookies(key, val) {
|
|
986
|
-
if (val.value === null) val.expires = EXPIRED2;
|
|
987
|
-
const { value, path: path2, expires, maxAge, httpOnly, secure, sameSite } = val;
|
|
988
|
-
let str = `${key}=${value || ""};Path=${path2 || "/"}`;
|
|
989
|
-
if (typeof expires !== "undefined") str += `;Expires=${normalizeExpires(expires)}`;
|
|
990
|
-
if (typeof maxAge === "number") str += `;Max-Age=${maxAge}`;
|
|
991
|
-
if (httpOnly) str += ";HttpOnly";
|
|
992
|
-
if (secure) str += ";Secure";
|
|
993
|
-
if (sameSite) str += `;SameSite=${sameSite}`;
|
|
994
|
-
return str;
|
|
995
|
-
}
|
|
996
|
-
|
|
997
1039
|
// src/auth/state.ts
|
|
998
1040
|
var NAME = "oauth_state";
|
|
999
1041
|
function startState(ctx, crossSite = false) {
|
|
@@ -1606,6 +1648,7 @@ function config(options = {}) {
|
|
|
1606
1648
|
// the added headers off; see resolveSecurity for the defaults.
|
|
1607
1649
|
security: resolveSecurity(options.security)
|
|
1608
1650
|
};
|
|
1651
|
+
if (options.cache !== void 0) settings.cache = options.cache;
|
|
1609
1652
|
options.cors = options.cors || env2.CORS || null;
|
|
1610
1653
|
if (options.cors) {
|
|
1611
1654
|
const cors2 = {
|
|
@@ -1683,6 +1726,7 @@ function config(options = {}) {
|
|
|
1683
1726
|
log.message("cors", origin);
|
|
1684
1727
|
}
|
|
1685
1728
|
if (settings.favicon) log.message("favicon", loc(settings.favicon));
|
|
1729
|
+
if (settings.cache !== void 0) log.message("cache", loc(options.cache));
|
|
1686
1730
|
if (settings.openapi) log.message("openapi", settings.openapi.path || "/docs");
|
|
1687
1731
|
return settings;
|
|
1688
1732
|
}
|
|
@@ -1722,16 +1766,6 @@ function applyCors(res, ctx) {
|
|
|
1722
1766
|
}
|
|
1723
1767
|
}
|
|
1724
1768
|
|
|
1725
|
-
// src/helpers/etag.ts
|
|
1726
|
-
function etag(bytes) {
|
|
1727
|
-
let h = 2166136261;
|
|
1728
|
-
for (let i = 0; i < bytes.length; i++) {
|
|
1729
|
-
h ^= bytes[i];
|
|
1730
|
-
h = Math.imul(h, 16777619);
|
|
1731
|
-
}
|
|
1732
|
-
return `"${bytes.length.toString(16)}-${(h >>> 0).toString(16)}"`;
|
|
1733
|
-
}
|
|
1734
|
-
|
|
1735
1769
|
// src/helpers/createWebsocket.ts
|
|
1736
1770
|
function createWebsocket(sockets, handlers) {
|
|
1737
1771
|
const run = (event, socket, body) => {
|
|
@@ -1846,6 +1880,7 @@ async function parseResponse(out, ctx) {
|
|
|
1846
1880
|
}
|
|
1847
1881
|
applyCors(out, ctx);
|
|
1848
1882
|
applySecurity(out, ctx);
|
|
1883
|
+
out = await applyCache(out, ctx);
|
|
1849
1884
|
if (ctx.time?.times?.length > 1) {
|
|
1850
1885
|
out.headers.set("Server-Timing", ctx.time.headers());
|
|
1851
1886
|
}
|
|
@@ -3173,6 +3208,7 @@ function server(options) {
|
|
|
3173
3208
|
export {
|
|
3174
3209
|
Server,
|
|
3175
3210
|
ServerError_default as ServerError,
|
|
3211
|
+
cache,
|
|
3176
3212
|
cookies,
|
|
3177
3213
|
server as default,
|
|
3178
3214
|
download,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@server/next",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.36.0",
|
|
4
4
|
"description": "A fully-fledged web server with routing, file uploads, sessions, static files, schema validation, websockets, testing, etc.",
|
|
5
5
|
"homepage": "https://server-js.com/",
|
|
6
6
|
"repository": "github:franciscop/server-next",
|