@server/next 0.42.0 → 0.43.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 +4 -1
- package/index.js +52 -41
- package/package.json +1 -1
package/index.d.ts
CHANGED
|
@@ -103,10 +103,13 @@ type RouteOptions = {
|
|
|
103
103
|
params?: StandardSchemaV1<any, any>;
|
|
104
104
|
response?: StandardSchemaV1<any, any>;
|
|
105
105
|
cache?: CacheOption;
|
|
106
|
+
uploads?: string | Bucket | UploadOptions | false;
|
|
106
107
|
};
|
|
107
108
|
type Route = {
|
|
108
109
|
path: string;
|
|
109
|
-
options: RouteOptions
|
|
110
|
+
options: Omit<RouteOptions, "uploads"> & {
|
|
111
|
+
uploads?: Settings["uploads"];
|
|
112
|
+
};
|
|
110
113
|
fns: Middleware[];
|
|
111
114
|
};
|
|
112
115
|
type Cookie = {
|
package/index.js
CHANGED
|
@@ -50,6 +50,7 @@ ServerError_default.extend({
|
|
|
50
50
|
message: "Missing the OAuth 'code' in the request body"
|
|
51
51
|
},
|
|
52
52
|
SESSION_JWT: "The `jwt` strategy is stateless, so there is no `ctx.session` (tried '{key}'). Use the `token` strategy for server-side sessions, or `cookie` for browsers",
|
|
53
|
+
SESSION_GUEST: "No `ctx.session` for this request (tried '{key}'): the `token` strategy carries the session in the Authorization header, and this request has none. Sign in first, or use the `cookie` strategy for guest sessions",
|
|
53
54
|
AUTH_INVALID_HEADER: {
|
|
54
55
|
status: 401,
|
|
55
56
|
message: "Invalid authorization header {type}, must send 'Bearer {TOKEN}' (with space)"
|
|
@@ -104,6 +105,17 @@ var StatusError = class extends Error {
|
|
|
104
105
|
}
|
|
105
106
|
};
|
|
106
107
|
|
|
108
|
+
// src/helpers/bucket.ts
|
|
109
|
+
import FileSystem from "bucket/fs";
|
|
110
|
+
function bucket(root) {
|
|
111
|
+
if (!root) return null;
|
|
112
|
+
if (typeof root === "string") return FileSystem(root);
|
|
113
|
+
if (typeof root.file === "function") return root;
|
|
114
|
+
throw new Error(
|
|
115
|
+
"Invalid bucket: pass a directory path or a `bucket` instance (with .file())"
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
|
|
107
119
|
// src/helpers/createId.ts
|
|
108
120
|
var alphabet = "useandom26T198340PX75pxJACKVERYMINDBUSHWOLFGQZbfghjklqvwyzrict";
|
|
109
121
|
var random = (bytes) => crypto.getRandomValues(new Uint8Array(bytes));
|
|
@@ -146,6 +158,16 @@ function createId(source, size = 16) {
|
|
|
146
158
|
}
|
|
147
159
|
|
|
148
160
|
// src/helpers/upload.ts
|
|
161
|
+
function resolveUploads(up) {
|
|
162
|
+
if (!up) return null;
|
|
163
|
+
if (typeof up === "object" && "bucket" in up) {
|
|
164
|
+
const { bucket: bucket2, maxSize, minSize, fileType: fileType2 } = up;
|
|
165
|
+
if (maxSize != null) parseBytes(maxSize);
|
|
166
|
+
if (minSize != null) parseBytes(minSize);
|
|
167
|
+
return { bucket: bucket(bucket2), maxSize, minSize, fileType: fileType2 };
|
|
168
|
+
}
|
|
169
|
+
return { bucket: bucket(up) };
|
|
170
|
+
}
|
|
149
171
|
function parseBytes(value) {
|
|
150
172
|
if (typeof value === "number") return value;
|
|
151
173
|
const units = {
|
|
@@ -1010,8 +1032,8 @@ var validateToken = (authorization) => {
|
|
|
1010
1032
|
return id;
|
|
1011
1033
|
};
|
|
1012
1034
|
function findSessionId(ctx) {
|
|
1013
|
-
|
|
1014
|
-
|
|
1035
|
+
if (ctx.options.auth?.strategy.includes("token")) {
|
|
1036
|
+
if (!ctx.headers.authorization) return;
|
|
1015
1037
|
return validateToken(ctx.headers.authorization);
|
|
1016
1038
|
}
|
|
1017
1039
|
return ctx.cookies.session || void 0;
|
|
@@ -1019,28 +1041,33 @@ function findSessionId(ctx) {
|
|
|
1019
1041
|
|
|
1020
1042
|
// src/middle/session.ts
|
|
1021
1043
|
var loaded = /* @__PURE__ */ new WeakMap();
|
|
1022
|
-
function
|
|
1044
|
+
function noSession(error) {
|
|
1023
1045
|
const target = {};
|
|
1024
1046
|
return new Proxy(target, {
|
|
1025
1047
|
get(target2, key) {
|
|
1026
1048
|
if (typeof key === "symbol" || key === "then") return target2[key];
|
|
1027
|
-
throw
|
|
1049
|
+
throw error(String(key));
|
|
1028
1050
|
},
|
|
1029
1051
|
set(target2, key, value) {
|
|
1030
1052
|
if (typeof key === "symbol") {
|
|
1031
1053
|
target2[key] = value;
|
|
1032
1054
|
return true;
|
|
1033
1055
|
}
|
|
1034
|
-
throw
|
|
1056
|
+
throw error(String(key));
|
|
1035
1057
|
}
|
|
1036
1058
|
});
|
|
1037
1059
|
}
|
|
1038
1060
|
async function session(ctx) {
|
|
1039
|
-
|
|
1040
|
-
|
|
1061
|
+
const strategy = ctx.options.auth?.strategy;
|
|
1062
|
+
if (strategy?.includes("jwt")) {
|
|
1063
|
+
ctx.session = noSession((key) => ServerError_default.SESSION_JWT({ key }));
|
|
1041
1064
|
return;
|
|
1042
1065
|
}
|
|
1043
1066
|
const id = findSessionId(ctx);
|
|
1067
|
+
if (!id && strategy?.includes("token")) {
|
|
1068
|
+
ctx.session = noSession((key) => ServerError_default.SESSION_GUEST({ key }));
|
|
1069
|
+
return;
|
|
1070
|
+
}
|
|
1044
1071
|
ctx.session = id && await ctx.options.sessions.get(id) || {};
|
|
1045
1072
|
loaded.set(ctx, { id, data: JSON.stringify(ctx.session) });
|
|
1046
1073
|
}
|
|
@@ -1050,6 +1077,10 @@ async function finishLogin(ctx, input, opts = {}) {
|
|
|
1050
1077
|
const settings = ctx.options.auth;
|
|
1051
1078
|
const { strategy, onLogin, onUser, onToken } = settings;
|
|
1052
1079
|
const key = String(input.key);
|
|
1080
|
+
if (!strategy.includes("jwt") && !loaded.has(ctx)) {
|
|
1081
|
+
ctx.session = {};
|
|
1082
|
+
loaded.set(ctx, { id: void 0, data: "{}" });
|
|
1083
|
+
}
|
|
1053
1084
|
const auth2 = {
|
|
1054
1085
|
user: key,
|
|
1055
1086
|
provider: input.provider,
|
|
@@ -1613,17 +1644,6 @@ function parseAuthOptions(auth2) {
|
|
|
1613
1644
|
};
|
|
1614
1645
|
}
|
|
1615
1646
|
|
|
1616
|
-
// src/helpers/bucket.ts
|
|
1617
|
-
import FileSystem from "bucket/fs";
|
|
1618
|
-
function bucket(root) {
|
|
1619
|
-
if (!root) return null;
|
|
1620
|
-
if (typeof root === "string") return FileSystem(root);
|
|
1621
|
-
if (typeof root.file === "function") return root;
|
|
1622
|
-
throw new Error(
|
|
1623
|
-
"Invalid bucket: pass a directory path or a `bucket` instance (with .file())"
|
|
1624
|
-
);
|
|
1625
|
-
}
|
|
1626
|
-
|
|
1627
1647
|
// src/helpers/color.ts
|
|
1628
1648
|
var map = {
|
|
1629
1649
|
reset: 0,
|
|
@@ -1863,17 +1883,7 @@ function config(options = {}) {
|
|
|
1863
1883
|
}
|
|
1864
1884
|
const publicDir = options.public || env2.PUBLIC;
|
|
1865
1885
|
settings.public = publicDir ? bucket(publicDir) : null;
|
|
1866
|
-
|
|
1867
|
-
if (!up) {
|
|
1868
|
-
settings.uploads = null;
|
|
1869
|
-
} else if (typeof up === "object" && "bucket" in up) {
|
|
1870
|
-
const { bucket: bucket2, maxSize, minSize, fileType: fileType2 } = up;
|
|
1871
|
-
if (maxSize != null) parseBytes(maxSize);
|
|
1872
|
-
if (minSize != null) parseBytes(minSize);
|
|
1873
|
-
settings.uploads = { bucket: bucket(bucket2), maxSize, minSize, fileType: fileType2 };
|
|
1874
|
-
} else {
|
|
1875
|
-
settings.uploads = { bucket: bucket(up) };
|
|
1876
|
-
}
|
|
1886
|
+
settings.uploads = resolveUploads(options.uploads);
|
|
1877
1887
|
const favicon2 = options.favicon || env2.FAVICON;
|
|
1878
1888
|
if (favicon2) settings.favicon = favicon2;
|
|
1879
1889
|
const production = env2.NODE_ENV === "production";
|
|
@@ -1886,7 +1896,7 @@ function config(options = {}) {
|
|
|
1886
1896
|
if (!settings.auth.users) {
|
|
1887
1897
|
if (production) {
|
|
1888
1898
|
throw new Error(
|
|
1889
|
-
"Auth in production needs a persistent `users` store, like auth: { ..., users: kv(redis).prefix('
|
|
1899
|
+
"Auth in production needs a persistent `users` store, like auth: { ..., users: kv(redis).prefix('user:') }."
|
|
1890
1900
|
);
|
|
1891
1901
|
}
|
|
1892
1902
|
settings.auth.users = toStore(/* @__PURE__ */ new Map());
|
|
@@ -2106,13 +2116,11 @@ async function parseResponse(out, ctx) {
|
|
|
2106
2116
|
out.headers.set("Server-Timing", ctx.time.headers());
|
|
2107
2117
|
}
|
|
2108
2118
|
const prev = loaded.get(ctx);
|
|
2109
|
-
|
|
2110
|
-
const data = jwt ? "{}" : JSON.stringify(ctx.session ?? {});
|
|
2111
|
-
if (!jwt && data !== (prev?.data ?? "{}")) {
|
|
2119
|
+
if (prev && JSON.stringify(ctx.session ?? {}) !== prev.data) {
|
|
2112
2120
|
if (ctx.options.sessionsDefault && ctx.platform.production) {
|
|
2113
2121
|
warnDefault();
|
|
2114
2122
|
}
|
|
2115
|
-
let id = prev
|
|
2123
|
+
let id = prev.id;
|
|
2116
2124
|
if (!id) {
|
|
2117
2125
|
id = createId();
|
|
2118
2126
|
out.headers.append(
|
|
@@ -2465,14 +2473,14 @@ async function getJwtUser(ctx) {
|
|
|
2465
2473
|
return exposed;
|
|
2466
2474
|
}
|
|
2467
2475
|
async function getAuthSession(ctx) {
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
if (!id) return;
|
|
2472
|
-
session2 = await ctx.options.sessions.get(id) ?? void 0;
|
|
2476
|
+
if (loaded.has(ctx)) {
|
|
2477
|
+
const session3 = ctx.session;
|
|
2478
|
+
return session3?.user ? session3 : void 0;
|
|
2473
2479
|
}
|
|
2474
|
-
|
|
2475
|
-
return
|
|
2480
|
+
const id = findSessionId(ctx);
|
|
2481
|
+
if (!id) return;
|
|
2482
|
+
const session2 = await ctx.options.sessions.get(id);
|
|
2483
|
+
return session2?.user ? session2 : void 0;
|
|
2476
2484
|
}
|
|
2477
2485
|
async function getUser(ctx) {
|
|
2478
2486
|
if (!ctx.options.auth) return;
|
|
@@ -3231,6 +3239,9 @@ var Router = class _Router {
|
|
|
3231
3239
|
options = rest.shift();
|
|
3232
3240
|
}
|
|
3233
3241
|
checkParserConflict(options, this.settings?.parser);
|
|
3242
|
+
if (options.uploads !== void 0) {
|
|
3243
|
+
options.uploads = resolveUploads(options.uploads);
|
|
3244
|
+
}
|
|
3234
3245
|
const base = method === "socket" ? [] : this.middleware;
|
|
3235
3246
|
const fns = [...base, ...rest].filter((fn) => fn != null);
|
|
3236
3247
|
this.handlers[method].push({ path, options, fns });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@server/next",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.43.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",
|