@draftlab/auth 0.15.0 → 0.16.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/dist/esm/allow.js +26 -0
- package/dist/esm/client.js +254 -0
- package/dist/esm/core.js +597 -0
- package/dist/esm/css.d.js +0 -0
- package/dist/esm/error.js +88 -0
- package/dist/esm/index.js +5 -0
- package/dist/esm/keys.js +126 -0
- package/dist/esm/mutex.js +53 -0
- package/dist/esm/pkce.js +87 -0
- package/dist/esm/provider/apple.js +15 -0
- package/dist/esm/provider/code.js +62 -0
- package/dist/esm/provider/discord.js +15 -0
- package/dist/esm/provider/facebook.js +15 -0
- package/dist/esm/provider/github.js +15 -0
- package/dist/esm/provider/gitlab.js +15 -0
- package/dist/esm/provider/google.js +16 -0
- package/dist/esm/provider/linkedin.js +15 -0
- package/dist/esm/provider/magiclink.js +83 -0
- package/dist/esm/provider/microsoft.js +15 -0
- package/dist/esm/provider/oauth2.js +130 -0
- package/dist/esm/provider/password.js +331 -0
- package/dist/esm/provider/provider.js +18 -0
- package/dist/esm/provider/reddit.js +15 -0
- package/dist/esm/provider/slack.js +15 -0
- package/dist/esm/provider/spotify.js +15 -0
- package/dist/esm/provider/twitch.js +15 -0
- package/dist/esm/provider/vercel.js +17 -0
- package/dist/esm/random.js +40 -0
- package/dist/esm/revocation.js +27 -0
- package/dist/esm/storage/memory.js +110 -0
- package/dist/esm/storage/storage.js +56 -0
- package/dist/esm/storage/turso.js +93 -0
- package/dist/esm/storage/unstorage.js +78 -0
- package/dist/esm/subject.js +7 -0
- package/dist/esm/themes/theme.js +115 -0
- package/dist/esm/toolkit/client.js +119 -0
- package/dist/esm/toolkit/index.js +25 -0
- package/dist/esm/toolkit/providers/facebook.js +11 -0
- package/dist/esm/toolkit/providers/github.js +11 -0
- package/dist/esm/toolkit/providers/google.js +11 -0
- package/dist/esm/toolkit/providers/strategy.js +0 -0
- package/dist/esm/toolkit/storage.js +81 -0
- package/dist/esm/toolkit/utils.js +18 -0
- package/dist/esm/types.js +0 -0
- package/dist/esm/ui/base.js +478 -0
- package/dist/esm/ui/code.js +186 -0
- package/dist/esm/ui/form.js +46 -0
- package/dist/esm/ui/icon.js +242 -0
- package/dist/esm/ui/magiclink.js +158 -0
- package/dist/esm/ui/password.js +435 -0
- package/dist/esm/ui/select.js +102 -0
- package/dist/esm/util.js +59 -0
- package/dist/{allow.d.mts → types/allow.d.ts} +9 -11
- package/dist/types/allow.d.ts.map +1 -0
- package/dist/types/client.d.ts +462 -0
- package/dist/types/client.d.ts.map +1 -0
- package/dist/types/core.d.ts +113 -0
- package/dist/types/core.d.ts.map +1 -0
- package/dist/{error.d.mts → types/error.d.ts} +95 -97
- package/dist/types/error.d.ts.map +1 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/{keys.d.mts → types/keys.d.ts} +20 -24
- package/dist/types/keys.d.ts.map +1 -0
- package/dist/types/mutex.d.ts +42 -0
- package/dist/types/mutex.d.ts.map +1 -0
- package/dist/{pkce.d.mts → types/pkce.d.ts} +10 -11
- package/dist/types/pkce.d.ts.map +1 -0
- package/dist/types/provider/apple.d.ts +197 -0
- package/dist/types/provider/apple.d.ts.map +1 -0
- package/dist/types/provider/code.d.ts +288 -0
- package/dist/types/provider/code.d.ts.map +1 -0
- package/dist/types/provider/discord.d.ts +206 -0
- package/dist/types/provider/discord.d.ts.map +1 -0
- package/dist/types/provider/facebook.d.ts +200 -0
- package/dist/types/provider/facebook.d.ts.map +1 -0
- package/dist/types/provider/github.d.ts +220 -0
- package/dist/types/provider/github.d.ts.map +1 -0
- package/dist/types/provider/gitlab.d.ts +180 -0
- package/dist/types/provider/gitlab.d.ts.map +1 -0
- package/dist/types/provider/google.d.ts +158 -0
- package/dist/types/provider/google.d.ts.map +1 -0
- package/dist/types/provider/linkedin.d.ts +190 -0
- package/dist/types/provider/linkedin.d.ts.map +1 -0
- package/dist/types/provider/magiclink.d.ts +141 -0
- package/dist/types/provider/magiclink.d.ts.map +1 -0
- package/dist/types/provider/microsoft.d.ts +247 -0
- package/dist/types/provider/microsoft.d.ts.map +1 -0
- package/dist/types/provider/oauth2.d.ts +229 -0
- package/dist/types/provider/oauth2.d.ts.map +1 -0
- package/dist/types/provider/password.d.ts +408 -0
- package/dist/types/provider/password.d.ts.map +1 -0
- package/dist/types/provider/provider.d.ts +226 -0
- package/dist/types/provider/provider.d.ts.map +1 -0
- package/dist/types/provider/reddit.d.ts +159 -0
- package/dist/types/provider/reddit.d.ts.map +1 -0
- package/dist/types/provider/slack.d.ts +171 -0
- package/dist/types/provider/slack.d.ts.map +1 -0
- package/dist/types/provider/spotify.d.ts +168 -0
- package/dist/types/provider/spotify.d.ts.map +1 -0
- package/dist/types/provider/twitch.d.ts +163 -0
- package/dist/types/provider/twitch.d.ts.map +1 -0
- package/dist/types/provider/vercel.d.ts +294 -0
- package/dist/types/provider/vercel.d.ts.map +1 -0
- package/dist/{random.d.mts → types/random.d.ts} +4 -6
- package/dist/types/random.d.ts.map +1 -0
- package/dist/types/revocation.d.ts +76 -0
- package/dist/types/revocation.d.ts.map +1 -0
- package/dist/{storage/memory.d.mts → types/storage/memory.d.ts} +17 -21
- package/dist/types/storage/memory.d.ts.map +1 -0
- package/dist/types/storage/storage.d.ts +177 -0
- package/dist/types/storage/storage.d.ts.map +1 -0
- package/dist/{storage/turso.d.mts → types/storage/turso.d.ts} +4 -8
- package/dist/types/storage/turso.d.ts.map +1 -0
- package/dist/{storage/unstorage.d.mts → types/storage/unstorage.d.ts} +12 -11
- package/dist/types/storage/unstorage.d.ts.map +1 -0
- package/dist/types/subject.d.ts +115 -0
- package/dist/types/subject.d.ts.map +1 -0
- package/dist/types/themes/theme.d.ts +207 -0
- package/dist/types/themes/theme.d.ts.map +1 -0
- package/dist/types/toolkit/client.d.ts +235 -0
- package/dist/types/toolkit/client.d.ts.map +1 -0
- package/dist/types/toolkit/index.d.ts +45 -0
- package/dist/types/toolkit/index.d.ts.map +1 -0
- package/dist/types/toolkit/providers/facebook.d.ts +8 -0
- package/dist/types/toolkit/providers/facebook.d.ts.map +1 -0
- package/dist/types/toolkit/providers/github.d.ts +8 -0
- package/dist/types/toolkit/providers/github.d.ts.map +1 -0
- package/dist/types/toolkit/providers/google.d.ts +8 -0
- package/dist/types/toolkit/providers/google.d.ts.map +1 -0
- package/dist/types/toolkit/providers/strategy.d.ts +38 -0
- package/dist/types/toolkit/providers/strategy.d.ts.map +1 -0
- package/dist/{toolkit/storage.d.mts → types/toolkit/storage.d.ts} +37 -39
- package/dist/types/toolkit/storage.d.ts.map +1 -0
- package/dist/{toolkit/utils.d.mts → types/toolkit/utils.d.ts} +2 -4
- package/dist/types/toolkit/utils.d.ts.map +1 -0
- package/dist/types/types.d.ts +92 -0
- package/dist/types/types.d.ts.map +1 -0
- package/dist/types/ui/base.d.ts +18 -0
- package/dist/types/ui/base.d.ts.map +1 -0
- package/dist/types/ui/code.d.ts +43 -0
- package/dist/types/ui/code.d.ts.map +1 -0
- package/dist/types/ui/form.d.ts +24 -0
- package/dist/types/ui/form.d.ts.map +1 -0
- package/dist/types/ui/icon.d.ts +60 -0
- package/dist/types/ui/icon.d.ts.map +1 -0
- package/dist/types/ui/magiclink.d.ts +41 -0
- package/dist/types/ui/magiclink.d.ts.map +1 -0
- package/dist/types/ui/password.d.ts +43 -0
- package/dist/types/ui/password.d.ts.map +1 -0
- package/dist/types/ui/select.d.ts +33 -0
- package/dist/types/ui/select.d.ts.map +1 -0
- package/dist/{util.d.mts → types/util.d.ts} +11 -13
- package/dist/types/util.d.ts.map +1 -0
- package/package.json +10 -16
- package/dist/adapters/node.d.mts +0 -18
- package/dist/adapters/node.mjs +0 -69
- package/dist/allow.mjs +0 -63
- package/dist/client.d.mts +0 -456
- package/dist/client.mjs +0 -283
- package/dist/core.d.mts +0 -110
- package/dist/core.mjs +0 -595
- package/dist/error.mjs +0 -237
- package/dist/index.d.mts +0 -2
- package/dist/index.mjs +0 -3
- package/dist/keys.mjs +0 -146
- package/dist/mutex.d.mts +0 -44
- package/dist/mutex.mjs +0 -110
- package/dist/pkce.mjs +0 -157
- package/dist/provider/apple.d.mts +0 -111
- package/dist/provider/apple.mjs +0 -164
- package/dist/provider/code.d.mts +0 -228
- package/dist/provider/code.mjs +0 -246
- package/dist/provider/discord.d.mts +0 -146
- package/dist/provider/discord.mjs +0 -156
- package/dist/provider/facebook.d.mts +0 -142
- package/dist/provider/facebook.mjs +0 -150
- package/dist/provider/github.d.mts +0 -140
- package/dist/provider/github.mjs +0 -169
- package/dist/provider/gitlab.d.mts +0 -106
- package/dist/provider/gitlab.mjs +0 -147
- package/dist/provider/google.d.mts +0 -112
- package/dist/provider/google.mjs +0 -109
- package/dist/provider/linkedin.d.mts +0 -132
- package/dist/provider/linkedin.mjs +0 -142
- package/dist/provider/magiclink.d.mts +0 -89
- package/dist/provider/magiclink.mjs +0 -143
- package/dist/provider/microsoft.d.mts +0 -178
- package/dist/provider/microsoft.mjs +0 -177
- package/dist/provider/oauth2.d.mts +0 -176
- package/dist/provider/oauth2.mjs +0 -222
- package/dist/provider/passkey.d.mts +0 -104
- package/dist/provider/passkey.mjs +0 -320
- package/dist/provider/password.d.mts +0 -412
- package/dist/provider/password.mjs +0 -363
- package/dist/provider/provider.d.mts +0 -227
- package/dist/provider/provider.mjs +0 -44
- package/dist/provider/reddit.d.mts +0 -107
- package/dist/provider/reddit.mjs +0 -127
- package/dist/provider/slack.d.mts +0 -114
- package/dist/provider/slack.mjs +0 -138
- package/dist/provider/spotify.d.mts +0 -113
- package/dist/provider/spotify.mjs +0 -135
- package/dist/provider/totp.d.mts +0 -112
- package/dist/provider/totp.mjs +0 -191
- package/dist/provider/twitch.d.mts +0 -108
- package/dist/provider/twitch.mjs +0 -131
- package/dist/provider/vercel.d.mts +0 -177
- package/dist/provider/vercel.mjs +0 -230
- package/dist/random.mjs +0 -86
- package/dist/revocation.d.mts +0 -55
- package/dist/revocation.mjs +0 -63
- package/dist/router/context.d.mts +0 -21
- package/dist/router/context.mjs +0 -193
- package/dist/router/cookies.d.mts +0 -8
- package/dist/router/cookies.mjs +0 -13
- package/dist/router/index.d.mts +0 -21
- package/dist/router/index.mjs +0 -107
- package/dist/router/matcher.d.mts +0 -15
- package/dist/router/matcher.mjs +0 -76
- package/dist/router/middleware/cors.d.mts +0 -15
- package/dist/router/middleware/cors.mjs +0 -114
- package/dist/router/safe-request.d.mts +0 -52
- package/dist/router/safe-request.mjs +0 -160
- package/dist/router/types.d.mts +0 -67
- package/dist/router/types.mjs +0 -1
- package/dist/router/variables.d.mts +0 -12
- package/dist/router/variables.mjs +0 -20
- package/dist/storage/memory.mjs +0 -125
- package/dist/storage/storage.d.mts +0 -179
- package/dist/storage/storage.mjs +0 -104
- package/dist/storage/turso.mjs +0 -117
- package/dist/storage/unstorage.mjs +0 -103
- package/dist/subject.d.mts +0 -62
- package/dist/subject.mjs +0 -36
- package/dist/themes/theme.d.mts +0 -209
- package/dist/themes/theme.mjs +0 -120
- package/dist/toolkit/client.d.mts +0 -169
- package/dist/toolkit/client.mjs +0 -209
- package/dist/toolkit/index.d.mts +0 -9
- package/dist/toolkit/index.mjs +0 -9
- package/dist/toolkit/providers/facebook.d.mts +0 -12
- package/dist/toolkit/providers/facebook.mjs +0 -16
- package/dist/toolkit/providers/github.d.mts +0 -12
- package/dist/toolkit/providers/github.mjs +0 -16
- package/dist/toolkit/providers/google.d.mts +0 -12
- package/dist/toolkit/providers/google.mjs +0 -20
- package/dist/toolkit/providers/strategy.d.mts +0 -40
- package/dist/toolkit/providers/strategy.mjs +0 -1
- package/dist/toolkit/storage.mjs +0 -157
- package/dist/toolkit/utils.mjs +0 -30
- package/dist/types.d.mts +0 -94
- package/dist/types.mjs +0 -1
- package/dist/ui/base.d.mts +0 -30
- package/dist/ui/base.mjs +0 -407
- package/dist/ui/code.d.mts +0 -43
- package/dist/ui/code.mjs +0 -173
- package/dist/ui/form.d.mts +0 -32
- package/dist/ui/form.mjs +0 -49
- package/dist/ui/icon.d.mts +0 -58
- package/dist/ui/icon.mjs +0 -247
- package/dist/ui/magiclink.d.mts +0 -41
- package/dist/ui/magiclink.mjs +0 -152
- package/dist/ui/passkey.d.mts +0 -27
- package/dist/ui/passkey.mjs +0 -323
- package/dist/ui/password.d.mts +0 -42
- package/dist/ui/password.mjs +0 -402
- package/dist/ui/select.d.mts +0 -34
- package/dist/ui/select.mjs +0 -98
- package/dist/ui/totp.d.mts +0 -34
- package/dist/ui/totp.mjs +0 -270
- package/dist/util.mjs +0 -128
|
@@ -1,160 +0,0 @@
|
|
|
1
|
-
//#region src/router/safe-request.ts
|
|
2
|
-
var SafeRequest = class SafeRequest {
|
|
3
|
-
cachedBody = null;
|
|
4
|
-
bodyBuffer = null;
|
|
5
|
-
textDecoder = new TextDecoder();
|
|
6
|
-
cache;
|
|
7
|
-
credentials;
|
|
8
|
-
destination;
|
|
9
|
-
headers;
|
|
10
|
-
integrity;
|
|
11
|
-
keepalive;
|
|
12
|
-
method;
|
|
13
|
-
mode;
|
|
14
|
-
redirect;
|
|
15
|
-
referrer;
|
|
16
|
-
referrerPolicy;
|
|
17
|
-
signal;
|
|
18
|
-
url;
|
|
19
|
-
constructor(url, method, headers, body, options) {
|
|
20
|
-
this.url = url;
|
|
21
|
-
this.method = method;
|
|
22
|
-
this.headers = headers;
|
|
23
|
-
this.bodyBuffer = body;
|
|
24
|
-
this.cache = options?.cache ?? "default";
|
|
25
|
-
this.credentials = options?.credentials ?? "same-origin";
|
|
26
|
-
this.destination = options?.destination ?? "";
|
|
27
|
-
this.integrity = options?.integrity ?? "";
|
|
28
|
-
this.keepalive = options?.keepalive ?? false;
|
|
29
|
-
this.mode = options?.mode ?? "cors";
|
|
30
|
-
this.redirect = options?.redirect ?? "follow";
|
|
31
|
-
this.referrer = options?.referrer ?? "";
|
|
32
|
-
this.referrerPolicy = options?.referrerPolicy ?? "";
|
|
33
|
-
this.signal = options?.signal ?? new AbortController().signal;
|
|
34
|
-
}
|
|
35
|
-
async arrayBuffer() {
|
|
36
|
-
return this.bodyBuffer ?? /* @__PURE__ */ new ArrayBuffer(0);
|
|
37
|
-
}
|
|
38
|
-
async blob() {
|
|
39
|
-
const buffer = await this.arrayBuffer();
|
|
40
|
-
return new Blob([buffer]);
|
|
41
|
-
}
|
|
42
|
-
async formData() {
|
|
43
|
-
const buffer = await this.arrayBuffer();
|
|
44
|
-
const blob = new Blob([buffer], { type: this.headers.get("content-type") || "application/x-www-form-urlencoded" });
|
|
45
|
-
return new Request(this.url, {
|
|
46
|
-
method: this.method,
|
|
47
|
-
headers: this.headers,
|
|
48
|
-
body: blob
|
|
49
|
-
}).formData();
|
|
50
|
-
}
|
|
51
|
-
async json() {
|
|
52
|
-
const text = await this.text();
|
|
53
|
-
return JSON.parse(text);
|
|
54
|
-
}
|
|
55
|
-
async text() {
|
|
56
|
-
const buffer = await this.arrayBuffer();
|
|
57
|
-
return this.textDecoder.decode(buffer);
|
|
58
|
-
}
|
|
59
|
-
async bytes() {
|
|
60
|
-
return this.arrayBuffer().then((buffer) => new Uint8Array(buffer));
|
|
61
|
-
}
|
|
62
|
-
get body() {
|
|
63
|
-
if (this.cachedBody) return this.cachedBody;
|
|
64
|
-
if (this.bodyBuffer) {
|
|
65
|
-
const buffer = this.bodyBuffer;
|
|
66
|
-
this.cachedBody = new ReadableStream({ start(controller) {
|
|
67
|
-
controller.enqueue(new Uint8Array(buffer));
|
|
68
|
-
controller.close();
|
|
69
|
-
} });
|
|
70
|
-
return this.cachedBody;
|
|
71
|
-
}
|
|
72
|
-
return null;
|
|
73
|
-
}
|
|
74
|
-
get bodyUsed() {
|
|
75
|
-
return false;
|
|
76
|
-
}
|
|
77
|
-
clone() {
|
|
78
|
-
return new SafeRequest(this.url, this.method, this.headers, this.bodyBuffer, {
|
|
79
|
-
cache: this.cache,
|
|
80
|
-
credentials: this.credentials,
|
|
81
|
-
destination: this.destination,
|
|
82
|
-
integrity: this.integrity,
|
|
83
|
-
keepalive: this.keepalive,
|
|
84
|
-
mode: this.mode,
|
|
85
|
-
redirect: this.redirect,
|
|
86
|
-
referrer: this.referrer,
|
|
87
|
-
referrerPolicy: this.referrerPolicy,
|
|
88
|
-
signal: this.signal
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
};
|
|
92
|
-
/**
|
|
93
|
-
* Extracts data from a Request and creates a SafeRequest.
|
|
94
|
-
* Uses ReadableStream to safely read the body and avoid issues with certain Request implementations.
|
|
95
|
-
*/
|
|
96
|
-
async function makeSafeRequest(request) {
|
|
97
|
-
if (request instanceof SafeRequest) return request;
|
|
98
|
-
const url = request.url;
|
|
99
|
-
const method = request.method;
|
|
100
|
-
const headers = new Headers(request.headers);
|
|
101
|
-
let bodyBuffer = null;
|
|
102
|
-
const requestMethod = method.toUpperCase();
|
|
103
|
-
if (requestMethod === "POST" || requestMethod === "PUT" || requestMethod === "PATCH") try {
|
|
104
|
-
const body = request.body;
|
|
105
|
-
if (body) {
|
|
106
|
-
const reader = body.getReader();
|
|
107
|
-
const chunks = [];
|
|
108
|
-
while (true) {
|
|
109
|
-
const { done, value } = await reader.read();
|
|
110
|
-
if (done) break;
|
|
111
|
-
if (value) chunks.push(value);
|
|
112
|
-
}
|
|
113
|
-
const totalLength = chunks.reduce((acc, chunk) => acc + chunk.length, 0);
|
|
114
|
-
const combined = new Uint8Array(totalLength);
|
|
115
|
-
let offset = 0;
|
|
116
|
-
for (const chunk of chunks) {
|
|
117
|
-
combined.set(chunk, offset);
|
|
118
|
-
offset += chunk.length;
|
|
119
|
-
}
|
|
120
|
-
bodyBuffer = combined.buffer;
|
|
121
|
-
}
|
|
122
|
-
} catch (error) {
|
|
123
|
-
console.warn("Failed to read request body via stream:", error);
|
|
124
|
-
}
|
|
125
|
-
const options = {};
|
|
126
|
-
try {
|
|
127
|
-
options.cache = request.cache;
|
|
128
|
-
} catch {}
|
|
129
|
-
try {
|
|
130
|
-
options.credentials = request.credentials;
|
|
131
|
-
} catch {}
|
|
132
|
-
try {
|
|
133
|
-
options.destination = request.destination;
|
|
134
|
-
} catch {}
|
|
135
|
-
try {
|
|
136
|
-
options.integrity = request.integrity;
|
|
137
|
-
} catch {}
|
|
138
|
-
try {
|
|
139
|
-
options.keepalive = request.keepalive;
|
|
140
|
-
} catch {}
|
|
141
|
-
try {
|
|
142
|
-
options.mode = request.mode;
|
|
143
|
-
} catch {}
|
|
144
|
-
try {
|
|
145
|
-
options.redirect = request.redirect;
|
|
146
|
-
} catch {}
|
|
147
|
-
try {
|
|
148
|
-
options.referrer = request.referrer;
|
|
149
|
-
} catch {}
|
|
150
|
-
try {
|
|
151
|
-
options.referrerPolicy = request.referrerPolicy;
|
|
152
|
-
} catch {}
|
|
153
|
-
try {
|
|
154
|
-
options.signal = request.signal;
|
|
155
|
-
} catch {}
|
|
156
|
-
return new SafeRequest(url, method, headers, bodyBuffer, options);
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
//#endregion
|
|
160
|
-
export { SafeRequest, makeSafeRequest };
|
package/dist/router/types.d.mts
DELETED
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
//#region src/router/types.d.ts
|
|
2
|
-
type ExtractParams<T extends string> = string extends T ? Record<string, string> : T extends `${string}:${infer Param}/${infer Rest}` ? { readonly [K in Param]: string } & ExtractParams<`/${Rest}`> : T extends `${string}:${infer Param}` ? { readonly [K in Param]: string } : Record<string, never>;
|
|
3
|
-
type VariableMap = Record<string, unknown>;
|
|
4
|
-
interface RouterEnvironment<TVariables extends VariableMap = VariableMap> {
|
|
5
|
-
Variables: TVariables;
|
|
6
|
-
}
|
|
7
|
-
interface CookieOptions {
|
|
8
|
-
domain?: string;
|
|
9
|
-
path?: string;
|
|
10
|
-
expires?: Date;
|
|
11
|
-
maxAge?: number;
|
|
12
|
-
httpOnly?: boolean;
|
|
13
|
-
secure?: boolean;
|
|
14
|
-
sameSite?: "Strict" | "Lax" | "None";
|
|
15
|
-
}
|
|
16
|
-
interface RouterContext<TParams extends Record<string, string> = Record<string, string>, TVariables extends VariableMap = VariableMap> {
|
|
17
|
-
readonly request: Request;
|
|
18
|
-
readonly params: Readonly<TParams>;
|
|
19
|
-
readonly searchParams: Readonly<URLSearchParams>;
|
|
20
|
-
query<K extends string>(key: K): string | undefined;
|
|
21
|
-
header<K extends string>(key: K): string | undefined;
|
|
22
|
-
cookie<K extends string>(key: K): string | undefined;
|
|
23
|
-
formData(): Promise<FormData>;
|
|
24
|
-
parseJson<T = unknown>(): Promise<T>;
|
|
25
|
-
json<T>(data: T, init?: ResponseInit): Response;
|
|
26
|
-
redirect(url: string | URL, status?: 300 | 301 | 302 | 303 | 307 | 308): Response;
|
|
27
|
-
text(data: string, init?: ResponseInit): Response;
|
|
28
|
-
setCookie(name: string, value: string, options?: CookieOptions): void;
|
|
29
|
-
deleteCookie(name: string, options?: Pick<CookieOptions, "domain" | "path">): void;
|
|
30
|
-
newResponse(body?: BodyInit, init?: ResponseInit): Response;
|
|
31
|
-
set<K extends keyof TVariables>(key: K, value: TVariables[K]): void;
|
|
32
|
-
get<K extends keyof TVariables>(key: K): TVariables[K];
|
|
33
|
-
has<K extends keyof TVariables>(key: K): key is K;
|
|
34
|
-
}
|
|
35
|
-
type RouteHandler<TParams extends Record<string, string> = Record<string, string>, TVariables extends VariableMap = VariableMap> = (ctx: RouterContext<TParams, TVariables>) => Promise<Response> | Response;
|
|
36
|
-
type MiddlewareHandler<TParams extends Record<string, string> = Record<string, string>, TVariables extends VariableMap = VariableMap> = (ctx: RouterContext<TParams, TVariables>, next: () => Promise<Response> | Response) => Promise<Response> | Response;
|
|
37
|
-
type EnhancedRouteHandler<TParams extends Record<string, string> = Record<string, string>, TVariables extends VariableMap = VariableMap> = {
|
|
38
|
-
handler: RouteHandler<TParams, TVariables>;
|
|
39
|
-
middleware?: MiddlewareHandler<TParams, TVariables>[];
|
|
40
|
-
};
|
|
41
|
-
type AnyHandler<TParams extends Record<string, string>, TVariables extends VariableMap = VariableMap> = RouteHandler<TParams, TVariables> | EnhancedRouteHandler<TParams, TVariables>;
|
|
42
|
-
type HttpMethod = "GET" | "POST";
|
|
43
|
-
interface CompiledRoute {
|
|
44
|
-
regex: RegExp;
|
|
45
|
-
paramNames: string[];
|
|
46
|
-
pattern: string;
|
|
47
|
-
}
|
|
48
|
-
interface MatchResult {
|
|
49
|
-
params: Record<string, string>;
|
|
50
|
-
pattern: string;
|
|
51
|
-
}
|
|
52
|
-
interface RouteDefinition<TVariables extends VariableMap = VariableMap> {
|
|
53
|
-
method: HttpMethod;
|
|
54
|
-
pattern: string;
|
|
55
|
-
handler: RouteHandler<Record<string, string>, TVariables>;
|
|
56
|
-
middleware: MiddlewareHandler<Record<string, string>, TVariables>[];
|
|
57
|
-
compiled: CompiledRoute;
|
|
58
|
-
}
|
|
59
|
-
interface RouterOptions {
|
|
60
|
-
caseSensitive?: boolean;
|
|
61
|
-
strict?: boolean;
|
|
62
|
-
basePath?: string;
|
|
63
|
-
}
|
|
64
|
-
type ErrorHandler<TVariables extends VariableMap = VariableMap> = (error: Error, ctx: RouterContext<Record<string, string>, TVariables>) => Promise<Response> | Response;
|
|
65
|
-
type GlobalMiddleware<TVariables extends VariableMap = VariableMap> = (ctx: RouterContext<Record<string, string>, TVariables>, next: () => Promise<Response> | Response) => Promise<Response> | Response;
|
|
66
|
-
//#endregion
|
|
67
|
-
export { AnyHandler, CompiledRoute, CookieOptions, EnhancedRouteHandler, ErrorHandler, ExtractParams, GlobalMiddleware, HttpMethod, MatchResult, MiddlewareHandler, RouteDefinition, RouteHandler, RouterContext, RouterEnvironment, RouterOptions, VariableMap };
|
package/dist/router/types.mjs
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { };
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { VariableMap } from "./types.mjs";
|
|
2
|
-
|
|
3
|
-
//#region src/router/variables.d.ts
|
|
4
|
-
declare class ContextVariableManager<TVariables extends VariableMap = VariableMap> {
|
|
5
|
-
private readonly state;
|
|
6
|
-
constructor(initialVariables?: Partial<TVariables>);
|
|
7
|
-
set<K extends keyof TVariables>(key: K, value: TVariables[K]): void;
|
|
8
|
-
get<K extends keyof TVariables>(key: K): TVariables[K];
|
|
9
|
-
has<K extends keyof TVariables>(key: K): key is K;
|
|
10
|
-
}
|
|
11
|
-
//#endregion
|
|
12
|
-
export { ContextVariableManager };
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
//#region src/router/variables.ts
|
|
2
|
-
var ContextVariableManager = class {
|
|
3
|
-
state = /* @__PURE__ */ new Map();
|
|
4
|
-
constructor(initialVariables) {
|
|
5
|
-
if (initialVariables) for (const [key, value] of Object.entries(initialVariables)) this.state.set(key, value);
|
|
6
|
-
}
|
|
7
|
-
set(key, value) {
|
|
8
|
-
if (typeof key !== "string" || key.length === 0) throw new Error("Variable key must be a non-empty string");
|
|
9
|
-
this.state.set(key, value);
|
|
10
|
-
}
|
|
11
|
-
get(key) {
|
|
12
|
-
return this.state.get(key);
|
|
13
|
-
}
|
|
14
|
-
has(key) {
|
|
15
|
-
return this.state.has(key);
|
|
16
|
-
}
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
//#endregion
|
|
20
|
-
export { ContextVariableManager };
|
package/dist/storage/memory.mjs
DELETED
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
import { joinKey, splitKey } from "./storage.mjs";
|
|
2
|
-
import { existsSync, readFileSync } from "node:fs";
|
|
3
|
-
import { writeFile } from "node:fs/promises";
|
|
4
|
-
|
|
5
|
-
//#region src/storage/memory.ts
|
|
6
|
-
/**
|
|
7
|
-
* Creates an in-memory storage adapter with optional file persistence.
|
|
8
|
-
* Uses binary search for efficient key lookups and maintains sorted order.
|
|
9
|
-
*
|
|
10
|
-
* @param options - Configuration options for the memory storage
|
|
11
|
-
* @returns Storage adapter implementing the StorageAdapter interface
|
|
12
|
-
*
|
|
13
|
-
* @example
|
|
14
|
-
* ```ts
|
|
15
|
-
* // Development storage (data lost on restart)
|
|
16
|
-
* const devStorage = MemoryStorage()
|
|
17
|
-
*
|
|
18
|
-
* // Persistent storage (survives restarts)
|
|
19
|
-
* const persistentStorage = MemoryStorage({
|
|
20
|
-
* persist: "./auth-data.json"
|
|
21
|
-
* })
|
|
22
|
-
*
|
|
23
|
-
* // Use with issuer
|
|
24
|
-
* export default issuer({
|
|
25
|
-
* storage: persistentStorage,
|
|
26
|
-
* providers: { ... }
|
|
27
|
-
* })
|
|
28
|
-
* ```
|
|
29
|
-
*/
|
|
30
|
-
const MemoryStorage = (options) => {
|
|
31
|
-
const store = [];
|
|
32
|
-
/**
|
|
33
|
-
* Type guard to validate loaded store data structure.
|
|
34
|
-
*/
|
|
35
|
-
const isValidStoreData = (data) => {
|
|
36
|
-
return Array.isArray(data) && data.every((item) => Array.isArray(item) && item.length === 2 && typeof item[0] === "string" && typeof item[1] === "object" && item[1] !== null && "value" in item[1]);
|
|
37
|
-
};
|
|
38
|
-
if (options?.persist && existsSync(options.persist)) try {
|
|
39
|
-
const fileContent = readFileSync(options.persist, "utf8");
|
|
40
|
-
const parsed = JSON.parse(fileContent);
|
|
41
|
-
if (isValidStoreData(parsed)) store.push(...parsed);
|
|
42
|
-
} catch {}
|
|
43
|
-
/**
|
|
44
|
-
* Saves the current store state to the persistence file if configured.
|
|
45
|
-
*/
|
|
46
|
-
const save = async () => {
|
|
47
|
-
if (!options?.persist) return;
|
|
48
|
-
try {
|
|
49
|
-
const serialized = JSON.stringify(store, null, 2);
|
|
50
|
-
await writeFile(options.persist, serialized, "utf8");
|
|
51
|
-
} catch {}
|
|
52
|
-
};
|
|
53
|
-
/**
|
|
54
|
-
* Performs binary search to find a key in the sorted store.
|
|
55
|
-
* Returns both whether the key was found and the insertion index.
|
|
56
|
-
*/
|
|
57
|
-
const search = (key) => {
|
|
58
|
-
let left = 0;
|
|
59
|
-
let right = store.length - 1;
|
|
60
|
-
while (left <= right) {
|
|
61
|
-
const mid = Math.floor((left + right) / 2);
|
|
62
|
-
const midEntry = store[mid];
|
|
63
|
-
if (!midEntry) return {
|
|
64
|
-
found: false,
|
|
65
|
-
index: left
|
|
66
|
-
};
|
|
67
|
-
const comparison = key.localeCompare(midEntry[0]);
|
|
68
|
-
if (comparison === 0) return {
|
|
69
|
-
found: true,
|
|
70
|
-
index: mid
|
|
71
|
-
};
|
|
72
|
-
if (comparison < 0) right = mid - 1;
|
|
73
|
-
else left = mid + 1;
|
|
74
|
-
}
|
|
75
|
-
return {
|
|
76
|
-
found: false,
|
|
77
|
-
index: left
|
|
78
|
-
};
|
|
79
|
-
};
|
|
80
|
-
return {
|
|
81
|
-
async get(key) {
|
|
82
|
-
const match = search(joinKey(key));
|
|
83
|
-
if (!match.found) return;
|
|
84
|
-
const storeEntry = store[match.index];
|
|
85
|
-
if (!storeEntry) return;
|
|
86
|
-
const entry = storeEntry[1];
|
|
87
|
-
if (entry.expiry && Date.now() >= entry.expiry) {
|
|
88
|
-
store.splice(match.index, 1);
|
|
89
|
-
await save();
|
|
90
|
-
return;
|
|
91
|
-
}
|
|
92
|
-
return entry.value;
|
|
93
|
-
},
|
|
94
|
-
async set(key, value, expiry) {
|
|
95
|
-
const searchKey = joinKey(key);
|
|
96
|
-
const match = search(searchKey);
|
|
97
|
-
const entry = [searchKey, {
|
|
98
|
-
value,
|
|
99
|
-
expiry: expiry?.getTime()
|
|
100
|
-
}];
|
|
101
|
-
if (match.found) store[match.index] = entry;
|
|
102
|
-
else store.splice(match.index, 0, entry);
|
|
103
|
-
await save();
|
|
104
|
-
},
|
|
105
|
-
async remove(key) {
|
|
106
|
-
const match = search(joinKey(key));
|
|
107
|
-
if (match.found) {
|
|
108
|
-
store.splice(match.index, 1);
|
|
109
|
-
await save();
|
|
110
|
-
}
|
|
111
|
-
},
|
|
112
|
-
async *scan(prefix) {
|
|
113
|
-
const now = Date.now();
|
|
114
|
-
const prefixStr = joinKey(prefix);
|
|
115
|
-
for (const [key, entry] of store) {
|
|
116
|
-
if (!key.startsWith(prefixStr)) continue;
|
|
117
|
-
if (entry.expiry && now >= entry.expiry) continue;
|
|
118
|
-
yield [splitKey(key), entry.value];
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
};
|
|
122
|
-
};
|
|
123
|
-
|
|
124
|
-
//#endregion
|
|
125
|
-
export { MemoryStorage };
|
|
@@ -1,179 +0,0 @@
|
|
|
1
|
-
//#region src/storage/storage.d.ts
|
|
2
|
-
/**
|
|
3
|
-
* Storage abstraction layer for Draft Auth persistence operations.
|
|
4
|
-
* Provides a unified interface for different storage backends with key encoding,
|
|
5
|
-
* TTL support, and type-safe operations.
|
|
6
|
-
*/
|
|
7
|
-
/**
|
|
8
|
-
* Abstract storage adapter interface that must be implemented by all storage backends.
|
|
9
|
-
* Defines the core operations needed for OAuth data persistence.
|
|
10
|
-
*/
|
|
11
|
-
interface StorageAdapter {
|
|
12
|
-
/**
|
|
13
|
-
* Retrieves a value by its key path.
|
|
14
|
-
*
|
|
15
|
-
* @param key - Array of key segments forming the storage path
|
|
16
|
-
* @returns Promise resolving to the stored value or undefined if not found
|
|
17
|
-
*/
|
|
18
|
-
get(key: string[]): Promise<Record<string, unknown> | undefined>;
|
|
19
|
-
/**
|
|
20
|
-
* Removes a value by its key path.
|
|
21
|
-
*
|
|
22
|
-
* @param key - Array of key segments forming the storage path
|
|
23
|
-
* @returns Promise that resolves when removal is complete
|
|
24
|
-
*/
|
|
25
|
-
remove(key: string[]): Promise<void>;
|
|
26
|
-
/**
|
|
27
|
-
* Stores a value with an optional expiration date.
|
|
28
|
-
*
|
|
29
|
-
* @param key - Array of key segments forming the storage path
|
|
30
|
-
* @param value - The value to store
|
|
31
|
-
* @param expiry - Optional expiration date for automatic cleanup
|
|
32
|
-
* @returns Promise that resolves when storage is complete
|
|
33
|
-
*/
|
|
34
|
-
set(key: string[], value: unknown, expiry?: Date): Promise<void>;
|
|
35
|
-
/**
|
|
36
|
-
* Scans for keys matching a prefix pattern.
|
|
37
|
-
*
|
|
38
|
-
* @param prefix - Array of key segments to use as prefix filter
|
|
39
|
-
* @returns Async iterable of key-value pairs matching the prefix
|
|
40
|
-
*/
|
|
41
|
-
scan(prefix: string[]): AsyncIterable<readonly [string[], unknown]>;
|
|
42
|
-
}
|
|
43
|
-
/**
|
|
44
|
-
* Joins an array of key segments into a single string using the separator.
|
|
45
|
-
* Segments are properly escaped to handle any input, including separators and escape characters.
|
|
46
|
-
*
|
|
47
|
-
* @param key - Array of key segments to join
|
|
48
|
-
* @returns Single string representing the full key path
|
|
49
|
-
*
|
|
50
|
-
* @example
|
|
51
|
-
* ```ts
|
|
52
|
-
* joinKey(['user', 'data\x1fwith\x1fseparators'])
|
|
53
|
-
* // Returns: "user\x1fdata\\x1fwith\\x1fseparators"
|
|
54
|
-
* ```
|
|
55
|
-
*/
|
|
56
|
-
declare const joinKey: (key: string[]) => string;
|
|
57
|
-
/**
|
|
58
|
-
* Splits a joined key string back into its component segments.
|
|
59
|
-
* Handles escaped characters properly.
|
|
60
|
-
*
|
|
61
|
-
* @param key - Joined key string to split
|
|
62
|
-
* @returns Array of individual key segments
|
|
63
|
-
*
|
|
64
|
-
* @example
|
|
65
|
-
* ```ts
|
|
66
|
-
* splitKey("user\x1fdata\\x1fwith\\x1fseparators")
|
|
67
|
-
* // Returns: ['user', 'data\x1fwith\x1fseparators']
|
|
68
|
-
* ```
|
|
69
|
-
*/
|
|
70
|
-
declare const splitKey: (key: string) => string[];
|
|
71
|
-
/**
|
|
72
|
-
* High-level storage operations with key encoding and type safety.
|
|
73
|
-
* Provides a convenient interface over storage adapters with additional features
|
|
74
|
-
* like TTL validation and secure key encoding to prevent collisions.
|
|
75
|
-
*/
|
|
76
|
-
declare const Storage: {
|
|
77
|
-
/**
|
|
78
|
-
* Encodes key segments by escaping special characters.
|
|
79
|
-
* Ensures storage keys don't contain unescaped separator characters that could cause collisions.
|
|
80
|
-
*
|
|
81
|
-
* @param key - Array of key segments to encode
|
|
82
|
-
* @returns Array of properly escaped key segments
|
|
83
|
-
*
|
|
84
|
-
* @throws {Error} If any segment is empty or whitespace-only
|
|
85
|
-
*
|
|
86
|
-
* @example
|
|
87
|
-
* ```ts
|
|
88
|
-
* Storage.encode(['user', 'data\x1fwith\x1fseparators'])
|
|
89
|
-
* // Returns: ['user', 'data\\x1fwith\\x1fseparators']
|
|
90
|
-
* ```
|
|
91
|
-
*/
|
|
92
|
-
readonly encode: (key: string[]) => string[];
|
|
93
|
-
/**
|
|
94
|
-
* Decodes key segments by unescaping special characters.
|
|
95
|
-
* Reverse operation of encode().
|
|
96
|
-
*
|
|
97
|
-
* @param key - Array of encoded key segments
|
|
98
|
-
* @returns Array of decoded key segments
|
|
99
|
-
*
|
|
100
|
-
* @internal
|
|
101
|
-
*/
|
|
102
|
-
readonly decode: (key: string[]) => string[];
|
|
103
|
-
/**
|
|
104
|
-
* Retrieves a typed value from storage.
|
|
105
|
-
*
|
|
106
|
-
* @template T - Expected type of the stored value
|
|
107
|
-
* @param adapter - Storage adapter to use
|
|
108
|
-
* @param key - Array of key segments identifying the value
|
|
109
|
-
* @returns Promise resolving to the typed value or null if not found
|
|
110
|
-
*
|
|
111
|
-
* @example
|
|
112
|
-
* ```ts
|
|
113
|
-
* interface UserSession {
|
|
114
|
-
* userId: string
|
|
115
|
-
* expiresAt: number
|
|
116
|
-
* }
|
|
117
|
-
*
|
|
118
|
-
* const session = await Storage.get<UserSession>(adapter, ['sessions', sessionId])
|
|
119
|
-
* if (session) {
|
|
120
|
-
* // Fully typed: session.userId
|
|
121
|
-
* }
|
|
122
|
-
* ```
|
|
123
|
-
*/
|
|
124
|
-
readonly get: <T = Record<string, unknown>>(adapter: StorageAdapter, key: string[]) => Promise<T | null>;
|
|
125
|
-
/**
|
|
126
|
-
* Stores a value with optional time-to-live in seconds.
|
|
127
|
-
* Validates that TTL is a positive integer to prevent edge cases like negative or overflow values.
|
|
128
|
-
*
|
|
129
|
-
* @param adapter - Storage adapter to use
|
|
130
|
-
* @param key - Array of key segments identifying where to store
|
|
131
|
-
* @param value - The value to store
|
|
132
|
-
* @param ttlSeconds - Optional TTL in seconds for automatic expiration
|
|
133
|
-
* @returns Promise that resolves when storage is complete
|
|
134
|
-
*
|
|
135
|
-
* @throws {RangeError} If TTL is invalid (negative, non-integer, or exceeds maximum)
|
|
136
|
-
*
|
|
137
|
-
* @example
|
|
138
|
-
* ```ts
|
|
139
|
-
* // Store with 1 hour TTL
|
|
140
|
-
* await Storage.set(adapter, ['sessions', sessionId], sessionData, 3600)
|
|
141
|
-
*
|
|
142
|
-
* // Store permanently (no expiration)
|
|
143
|
-
* await Storage.set(adapter, ['users', userId], userData)
|
|
144
|
-
* ```
|
|
145
|
-
*/
|
|
146
|
-
readonly set: (adapter: StorageAdapter, key: string[], value: unknown, ttlSeconds?: number) => Promise<void>;
|
|
147
|
-
/**
|
|
148
|
-
* Removes a value from storage.
|
|
149
|
-
*
|
|
150
|
-
* @param adapter - Storage adapter to use
|
|
151
|
-
* @param key - Array of key segments identifying the value to remove
|
|
152
|
-
* @returns Promise that resolves when removal is complete
|
|
153
|
-
*
|
|
154
|
-
* @example
|
|
155
|
-
* ```ts
|
|
156
|
-
* await Storage.remove(adapter, ['sessions', expiredSessionId])
|
|
157
|
-
* ```
|
|
158
|
-
*/
|
|
159
|
-
readonly remove: (adapter: StorageAdapter, key: string[]) => Promise<void>;
|
|
160
|
-
/**
|
|
161
|
-
* Scans for entries matching a key prefix with type safety.
|
|
162
|
-
*
|
|
163
|
-
* @template T - Expected type of the stored values
|
|
164
|
-
* @param adapter - Storage adapter to use
|
|
165
|
-
* @param prefix - Array of key segments to use as prefix filter
|
|
166
|
-
* @returns Async iterable of typed key-value pairs
|
|
167
|
-
*
|
|
168
|
-
* @example
|
|
169
|
-
* ```ts
|
|
170
|
-
* // Find all user sessions
|
|
171
|
-
* for await (const [key, session] of Storage.scan<UserSession>(adapter, ['sessions'])) {
|
|
172
|
-
* // Session: `${key.join('/')} expires at ${session.expiresAt}`
|
|
173
|
-
* }
|
|
174
|
-
* ```
|
|
175
|
-
*/
|
|
176
|
-
readonly scan: <T = Record<string, unknown>>(adapter: StorageAdapter, prefix: string[]) => AsyncIterable<readonly [string[], T]>;
|
|
177
|
-
};
|
|
178
|
-
//#endregion
|
|
179
|
-
export { Storage, StorageAdapter, joinKey, splitKey };
|
package/dist/storage/storage.mjs
DELETED
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
//#region src/storage/storage.ts
|
|
2
|
-
/**
|
|
3
|
-
* ASCII unit separator character used to join key segments.
|
|
4
|
-
* Using a control character ensures it won't conflict with user data.
|
|
5
|
-
*/
|
|
6
|
-
const SEPARATOR = String.fromCharCode(31);
|
|
7
|
-
/**
|
|
8
|
-
* Escape character used to escape SEPARATOR characters in key segments.
|
|
9
|
-
* Uses backslash as the escape character, which is then itself escaped when appearing.
|
|
10
|
-
*/
|
|
11
|
-
const ESCAPE = "\\";
|
|
12
|
-
/**
|
|
13
|
-
* Joins an array of key segments into a single string using the separator.
|
|
14
|
-
* Segments are properly escaped to handle any input, including separators and escape characters.
|
|
15
|
-
*
|
|
16
|
-
* @param key - Array of key segments to join
|
|
17
|
-
* @returns Single string representing the full key path
|
|
18
|
-
*
|
|
19
|
-
* @example
|
|
20
|
-
* ```ts
|
|
21
|
-
* joinKey(['user', 'data\x1fwith\x1fseparators'])
|
|
22
|
-
* // Returns: "user\x1fdata\\x1fwith\\x1fseparators"
|
|
23
|
-
* ```
|
|
24
|
-
*/
|
|
25
|
-
const joinKey = (key) => {
|
|
26
|
-
return key.join(SEPARATOR);
|
|
27
|
-
};
|
|
28
|
-
/**
|
|
29
|
-
* Splits a joined key string back into its component segments.
|
|
30
|
-
* Handles escaped characters properly.
|
|
31
|
-
*
|
|
32
|
-
* @param key - Joined key string to split
|
|
33
|
-
* @returns Array of individual key segments
|
|
34
|
-
*
|
|
35
|
-
* @example
|
|
36
|
-
* ```ts
|
|
37
|
-
* splitKey("user\x1fdata\\x1fwith\\x1fseparators")
|
|
38
|
-
* // Returns: ['user', 'data\x1fwith\x1fseparators']
|
|
39
|
-
* ```
|
|
40
|
-
*/
|
|
41
|
-
const splitKey = (key) => {
|
|
42
|
-
return key.split(SEPARATOR);
|
|
43
|
-
};
|
|
44
|
-
/**
|
|
45
|
-
* Encodes a single key segment by escaping special characters.
|
|
46
|
-
* Prevents collisions by properly escaping separator and escape characters.
|
|
47
|
-
*
|
|
48
|
-
* @param segment - The key segment to encode
|
|
49
|
-
* @returns Encoded segment with special characters escaped
|
|
50
|
-
* @throws {Error} If segment is empty or whitespace-only
|
|
51
|
-
*
|
|
52
|
-
* @internal
|
|
53
|
-
*/
|
|
54
|
-
const encodeSegment = (segment) => {
|
|
55
|
-
if (!segment || !segment.trim()) throw new Error(`Storage key segment cannot be empty or whitespace-only: "${segment}"`);
|
|
56
|
-
return segment.replaceAll(ESCAPE, ESCAPE + ESCAPE).replaceAll(SEPARATOR, ESCAPE + SEPARATOR);
|
|
57
|
-
};
|
|
58
|
-
/**
|
|
59
|
-
* Decodes a key segment by unescaping special characters.
|
|
60
|
-
* Reverse of encodeSegment operation.
|
|
61
|
-
*
|
|
62
|
-
* @param segment - The encoded segment to decode
|
|
63
|
-
* @returns Decoded segment with special characters restored
|
|
64
|
-
*
|
|
65
|
-
* @internal
|
|
66
|
-
*/
|
|
67
|
-
const decodeSegment = (segment) => {
|
|
68
|
-
return segment.replaceAll(ESCAPE + SEPARATOR, SEPARATOR).replaceAll(ESCAPE + ESCAPE, ESCAPE);
|
|
69
|
-
};
|
|
70
|
-
/**
|
|
71
|
-
* High-level storage operations with key encoding and type safety.
|
|
72
|
-
* Provides a convenient interface over storage adapters with additional features
|
|
73
|
-
* like TTL validation and secure key encoding to prevent collisions.
|
|
74
|
-
*/
|
|
75
|
-
const Storage = {
|
|
76
|
-
encode: (key) => {
|
|
77
|
-
return key.map(encodeSegment);
|
|
78
|
-
},
|
|
79
|
-
decode: (key) => {
|
|
80
|
-
return key.map(decodeSegment);
|
|
81
|
-
},
|
|
82
|
-
get: (adapter, key) => {
|
|
83
|
-
return adapter.get(Storage.encode(key));
|
|
84
|
-
},
|
|
85
|
-
set: (adapter, key, value, ttlSeconds) => {
|
|
86
|
-
if (ttlSeconds !== void 0 && ttlSeconds !== null) {
|
|
87
|
-
if (!Number.isInteger(ttlSeconds)) throw new RangeError(`Storage TTL must be an integer in seconds, received ${typeof ttlSeconds}`);
|
|
88
|
-
if (ttlSeconds <= 0) throw new RangeError(`Storage TTL must be positive, received ${ttlSeconds}`);
|
|
89
|
-
const maxTtlSeconds = 3600 * 24 * 365 * 10;
|
|
90
|
-
if (ttlSeconds > maxTtlSeconds) throw new RangeError(`Storage TTL exceeds maximum (${maxTtlSeconds}s = 10 years), received ${ttlSeconds}s`);
|
|
91
|
-
}
|
|
92
|
-
const expiry = ttlSeconds ? new Date(Date.now() + ttlSeconds * 1e3) : void 0;
|
|
93
|
-
return adapter.set(Storage.encode(key), value, expiry);
|
|
94
|
-
},
|
|
95
|
-
remove: (adapter, key) => {
|
|
96
|
-
return adapter.remove(Storage.encode(key));
|
|
97
|
-
},
|
|
98
|
-
scan: (adapter, prefix) => {
|
|
99
|
-
return adapter.scan(Storage.encode(prefix));
|
|
100
|
-
}
|
|
101
|
-
};
|
|
102
|
-
|
|
103
|
-
//#endregion
|
|
104
|
-
export { Storage, joinKey, splitKey };
|