@authyon/server 0.2.0-beta.2 → 0.2.0-beta.21
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 +300 -2
- package/dist/authorization-D8tznR96.d.ts +129 -0
- package/dist/authorization-Soblu-A5.d.cts +129 -0
- package/dist/authyonServerClient-COrfN4o_.d.cts +1296 -0
- package/dist/authyonServerClient-COrfN4o_.d.ts +1296 -0
- package/dist/bff.cjs +1181 -0
- package/dist/bff.d.cts +149 -0
- package/dist/bff.d.ts +149 -0
- package/dist/bff.js +808 -0
- package/dist/chunk-77J4NURK.js +13 -0
- package/dist/chunk-NKWQMYB3.js +485 -0
- package/dist/chunk-SUL2HLRR.js +361 -0
- package/dist/index.cjs +708 -67
- package/dist/index.d.cts +47 -756
- package/dist/index.d.ts +47 -756
- package/dist/index.js +626 -784
- package/dist/next.cjs +328 -0
- package/dist/next.d.cts +27 -0
- package/dist/next.d.ts +27 -0
- package/dist/next.js +48 -0
- package/package.json +28 -5
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
// ../../internal/core/errors/authyonError.ts
|
|
2
|
+
var ErrorCodes = {
|
|
3
|
+
Unknown: "unknown",
|
|
4
|
+
NetworkError: "request.network_error",
|
|
5
|
+
Timeout: "request.timeout",
|
|
6
|
+
SessionMalformed: "session.malformed",
|
|
7
|
+
NotAuthenticated: "auth.not_authenticated",
|
|
8
|
+
InvalidToken: "auth.invalid_token",
|
|
9
|
+
MissingToken: "auth.missing_token",
|
|
10
|
+
EmailTaken: "user.email_taken",
|
|
11
|
+
PasswordWeak: "user.password_weak",
|
|
12
|
+
PasswordPwned: "user.password_pwned",
|
|
13
|
+
RateLimited: "rate_limited",
|
|
14
|
+
StepUpRequired: "step_up_required",
|
|
15
|
+
InvalidSecondFactorCode: "invalid_code",
|
|
16
|
+
VerificationAttemptsExhausted: "verification_attempts_exhausted",
|
|
17
|
+
MethodNotEnrolled: "method_not_enrolled",
|
|
18
|
+
InvalidApprovalState: "invalid_authorization_state",
|
|
19
|
+
PayloadMismatch: "payload_mismatch",
|
|
20
|
+
ApprovalNotConsumable: "authorization_not_consumable",
|
|
21
|
+
IdempotencyConflict: "idempotency_conflict",
|
|
22
|
+
UserDisabled: "user_disabled",
|
|
23
|
+
UserNotFound: "user_not_found",
|
|
24
|
+
TemporarilyUnavailable: "temporarily_unavailable",
|
|
25
|
+
InsufficientScope: "insufficient_scope",
|
|
26
|
+
CredentialThrottled: "credential_throttled",
|
|
27
|
+
ApprovalNotFound: "authorization_not_found",
|
|
28
|
+
SessionRevoked: "session_revoked",
|
|
29
|
+
TwoFactorTooManyFailures: "user.2fa.too_many_failures"
|
|
30
|
+
};
|
|
31
|
+
var STANDARD_ERROR_FIELDS = /* @__PURE__ */ new Set([
|
|
32
|
+
"type",
|
|
33
|
+
"status",
|
|
34
|
+
"title",
|
|
35
|
+
"detail",
|
|
36
|
+
"code",
|
|
37
|
+
"error",
|
|
38
|
+
"error_description"
|
|
39
|
+
]);
|
|
40
|
+
var AuthyonError = class extends Error {
|
|
41
|
+
constructor(status, body, options = {}) {
|
|
42
|
+
const detail = body.detail ?? body.error_description;
|
|
43
|
+
super(detail ?? body.title ?? `Authyon request failed with status ${status}`);
|
|
44
|
+
this.name = "AuthyonError";
|
|
45
|
+
this.status = status;
|
|
46
|
+
this.code = body.code ?? body.error ?? "unknown";
|
|
47
|
+
this.title = body.title ?? "Error";
|
|
48
|
+
this.detail = detail;
|
|
49
|
+
this.extensions = Object.fromEntries(
|
|
50
|
+
Object.entries(body).filter(([key]) => !STANDARD_ERROR_FIELDS.has(key))
|
|
51
|
+
);
|
|
52
|
+
this.requestId = options.requestId;
|
|
53
|
+
this.retryAfter = options.retryAfter;
|
|
54
|
+
this.cause = options.cause;
|
|
55
|
+
}
|
|
56
|
+
is(code) {
|
|
57
|
+
return this.code === code;
|
|
58
|
+
}
|
|
59
|
+
isAny(...codes) {
|
|
60
|
+
return codes.includes(this.code);
|
|
61
|
+
}
|
|
62
|
+
hasPrefix(prefix) {
|
|
63
|
+
return this.code.startsWith(prefix);
|
|
64
|
+
}
|
|
65
|
+
isStatus(...statuses) {
|
|
66
|
+
return statuses.includes(this.status);
|
|
67
|
+
}
|
|
68
|
+
/** Stable interpretation for UI decisions, retries, telemetry and support flows. */
|
|
69
|
+
interpret() {
|
|
70
|
+
const category = classifyError(this.status, this.code);
|
|
71
|
+
return {
|
|
72
|
+
category,
|
|
73
|
+
action: actionFor(category),
|
|
74
|
+
retryable: isRetryable(category),
|
|
75
|
+
...this.retryAfter !== void 0 ? { retryAfter: this.retryAfter } : {},
|
|
76
|
+
...this.requestId !== void 0 ? { requestId: this.requestId } : {}
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
get category() {
|
|
80
|
+
return this.interpret().category;
|
|
81
|
+
}
|
|
82
|
+
get retryable() {
|
|
83
|
+
return this.interpret().retryable;
|
|
84
|
+
}
|
|
85
|
+
toJSON() {
|
|
86
|
+
return {
|
|
87
|
+
name: this.name,
|
|
88
|
+
message: this.message,
|
|
89
|
+
status: this.status,
|
|
90
|
+
code: this.code,
|
|
91
|
+
title: this.title,
|
|
92
|
+
detail: this.detail,
|
|
93
|
+
requestId: this.requestId,
|
|
94
|
+
retryAfter: this.retryAfter,
|
|
95
|
+
...this.interpret()
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
function classifyError(status, code) {
|
|
100
|
+
if (code === ErrorCodes.NetworkError) return "network";
|
|
101
|
+
if (code === ErrorCodes.StepUpRequired) return "authentication";
|
|
102
|
+
if (code === ErrorCodes.Timeout || status === 408) return "timeout";
|
|
103
|
+
if (code === ErrorCodes.RateLimited || status === 429) return "rate_limit";
|
|
104
|
+
if (code === ErrorCodes.EmailTaken || status === 409) return "conflict";
|
|
105
|
+
if (code === ErrorCodes.PasswordWeak || code === ErrorCodes.PasswordPwned) return "validation";
|
|
106
|
+
if (code === ErrorCodes.SessionMalformed) return "server";
|
|
107
|
+
if (code.startsWith("auth.") || status === 401) return "authentication";
|
|
108
|
+
if (status === 403) return "authorization";
|
|
109
|
+
if (status === 404) return "not_found";
|
|
110
|
+
if (status === 400 || status === 422) return "validation";
|
|
111
|
+
if (status >= 500) return "server";
|
|
112
|
+
return "unknown";
|
|
113
|
+
}
|
|
114
|
+
function actionFor(category) {
|
|
115
|
+
switch (category) {
|
|
116
|
+
case "network":
|
|
117
|
+
case "timeout":
|
|
118
|
+
case "rate_limit":
|
|
119
|
+
case "server":
|
|
120
|
+
return "retry";
|
|
121
|
+
case "authentication":
|
|
122
|
+
return "reauthenticate";
|
|
123
|
+
case "authorization":
|
|
124
|
+
return "request_access";
|
|
125
|
+
case "validation":
|
|
126
|
+
return "fix_input";
|
|
127
|
+
case "not_found":
|
|
128
|
+
return "not_found";
|
|
129
|
+
case "conflict":
|
|
130
|
+
return "resolve_conflict";
|
|
131
|
+
case "unknown":
|
|
132
|
+
return "contact_support";
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
function isRetryable(category) {
|
|
136
|
+
return category === "network" || category === "timeout" || category === "rate_limit" || category === "server";
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// ../../internal/core/http/httpAdapter.ts
|
|
140
|
+
var FetchHttpAdapter = class {
|
|
141
|
+
constructor(fetchImpl = fetch.bind(globalThis)) {
|
|
142
|
+
this.fetchImpl = fetchImpl;
|
|
143
|
+
}
|
|
144
|
+
request(request) {
|
|
145
|
+
return this.fetchImpl(request.url, {
|
|
146
|
+
method: request.method,
|
|
147
|
+
headers: request.headers,
|
|
148
|
+
body: request.body,
|
|
149
|
+
signal: request.signal,
|
|
150
|
+
redirect: "error"
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
var LoggingHttpAdapter = class {
|
|
155
|
+
constructor(adapter, options) {
|
|
156
|
+
this.adapter = adapter;
|
|
157
|
+
this.options = options;
|
|
158
|
+
}
|
|
159
|
+
async request(request) {
|
|
160
|
+
const startedAt = Date.now();
|
|
161
|
+
const eventBase = {
|
|
162
|
+
method: request.method,
|
|
163
|
+
url: sanitizeUrl(request.url)
|
|
164
|
+
};
|
|
165
|
+
this.log({ type: "request", ...eventBase, timestamp: startedAt });
|
|
166
|
+
try {
|
|
167
|
+
const response = await this.adapter.request(request);
|
|
168
|
+
this.log({
|
|
169
|
+
type: "response",
|
|
170
|
+
...eventBase,
|
|
171
|
+
status: response.status,
|
|
172
|
+
durationMs: Date.now() - startedAt,
|
|
173
|
+
requestId: response.headers.get("x-request-id") ?? response.headers.get("trace-id") ?? void 0,
|
|
174
|
+
timestamp: Date.now()
|
|
175
|
+
});
|
|
176
|
+
return response;
|
|
177
|
+
} catch (error) {
|
|
178
|
+
this.log({
|
|
179
|
+
type: "error",
|
|
180
|
+
...eventBase,
|
|
181
|
+
errorName: error instanceof Error ? error.name : "UnknownError",
|
|
182
|
+
durationMs: Date.now() - startedAt,
|
|
183
|
+
timestamp: Date.now()
|
|
184
|
+
});
|
|
185
|
+
throw error;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
log(event) {
|
|
189
|
+
if (!this.options.enabled) return;
|
|
190
|
+
const logger = this.options.logger ?? defaultHttpLogger;
|
|
191
|
+
try {
|
|
192
|
+
logger(event);
|
|
193
|
+
} catch {
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
function defaultHttpLogger(event) {
|
|
198
|
+
console.debug("[Authyon HTTP]", event);
|
|
199
|
+
}
|
|
200
|
+
function sanitizeUrl(value) {
|
|
201
|
+
const url = new URL(value);
|
|
202
|
+
url.username = "";
|
|
203
|
+
url.password = "";
|
|
204
|
+
url.hash = "";
|
|
205
|
+
const queryKeys = /* @__PURE__ */ new Set();
|
|
206
|
+
url.searchParams.forEach((_value, key) => queryKeys.add(key));
|
|
207
|
+
url.search = queryKeys.size > 0 ? [...queryKeys].map((key) => `${encodeURIComponent(key)}=REDACTED`).join("&") : "";
|
|
208
|
+
return url.toString();
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// ../../internal/core/config/defaults.ts
|
|
212
|
+
var DEFAULT_BASE_URL = "https://api.authyon.com";
|
|
213
|
+
var DEFAULT_EXPIRY_SKEW_MS = 3e4;
|
|
214
|
+
|
|
215
|
+
// ../../internal/core/http/transport.ts
|
|
216
|
+
var DEFAULT_TIMEOUT_MS = 15e3;
|
|
217
|
+
var SharedTransportError = class extends Error {
|
|
218
|
+
constructor(code, cause) {
|
|
219
|
+
super(code === "request.timeout" ? "Request timed out" : "Network request failed");
|
|
220
|
+
this.name = "SharedTransportError";
|
|
221
|
+
this.code = code;
|
|
222
|
+
this.cause = cause;
|
|
223
|
+
}
|
|
224
|
+
};
|
|
225
|
+
function createSharedTransport(options) {
|
|
226
|
+
const baseUrl = normalizeBaseUrl(options.baseUrl, options.allowInsecureHttp ?? false);
|
|
227
|
+
const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
228
|
+
if (!Number.isFinite(timeoutMs) || timeoutMs < 0) {
|
|
229
|
+
throw new Error("Authyon: `timeoutMs` must be a non-negative finite number");
|
|
230
|
+
}
|
|
231
|
+
if (options.httpAdapter && options.fetch) {
|
|
232
|
+
throw new Error("Authyon: use either `httpAdapter` or `fetch`, not both");
|
|
233
|
+
}
|
|
234
|
+
const baseAdapter = options.httpAdapter ?? new FetchHttpAdapter(options.fetch);
|
|
235
|
+
const httpAdapter = options.httpLogger ? new LoggingHttpAdapter(baseAdapter, options.httpLogger) : baseAdapter;
|
|
236
|
+
return {
|
|
237
|
+
baseUrl,
|
|
238
|
+
async request(path, init) {
|
|
239
|
+
const controller = new AbortController();
|
|
240
|
+
const timeout = timeoutMs > 0 ? setTimeout(() => controller.abort(), timeoutMs) : void 0;
|
|
241
|
+
try {
|
|
242
|
+
return await httpAdapter.request({
|
|
243
|
+
url: `${baseUrl}${path}`,
|
|
244
|
+
method: init.method ?? "GET",
|
|
245
|
+
headers: normalizeHeaders(init.headers),
|
|
246
|
+
body: init.body,
|
|
247
|
+
signal: controller.signal
|
|
248
|
+
});
|
|
249
|
+
} catch (cause) {
|
|
250
|
+
throw new SharedTransportError(
|
|
251
|
+
controller.signal.aborted ? ErrorCodes.Timeout : ErrorCodes.NetworkError,
|
|
252
|
+
cause
|
|
253
|
+
);
|
|
254
|
+
} finally {
|
|
255
|
+
if (timeout !== void 0) clearTimeout(timeout);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
function normalizeHeaders(headers) {
|
|
261
|
+
const normalized = {};
|
|
262
|
+
new Headers(headers).forEach((value, key) => {
|
|
263
|
+
normalized[key] = value;
|
|
264
|
+
});
|
|
265
|
+
return normalized;
|
|
266
|
+
}
|
|
267
|
+
function responseMetadata(response) {
|
|
268
|
+
const retryAfterHeader = response.headers.get("retry-after");
|
|
269
|
+
const retryAfter = retryAfterHeader ? Number(retryAfterHeader) : void 0;
|
|
270
|
+
return {
|
|
271
|
+
requestId: response.headers.get("x-request-id") ?? response.headers.get("trace-id") ?? void 0,
|
|
272
|
+
retryAfter: Number.isFinite(retryAfter) ? retryAfter : void 0
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
function normalizeBaseUrl(value, allowInsecureHttp) {
|
|
276
|
+
let url;
|
|
277
|
+
try {
|
|
278
|
+
url = new URL(value);
|
|
279
|
+
} catch {
|
|
280
|
+
throw new Error("Authyon: `baseUrl` must be an absolute URL");
|
|
281
|
+
}
|
|
282
|
+
const loopback = url.hostname === "localhost" || url.hostname === "127.0.0.1" || url.hostname === "[::1]";
|
|
283
|
+
if (url.protocol !== "https:" && !(url.protocol === "http:" && (loopback || allowInsecureHttp))) {
|
|
284
|
+
throw new Error(
|
|
285
|
+
"Authyon: `baseUrl` must use HTTPS (HTTP is allowed only for loopback or with `allowInsecureHttp`)"
|
|
286
|
+
);
|
|
287
|
+
}
|
|
288
|
+
if (url.username || url.password || url.search || url.hash) {
|
|
289
|
+
throw new Error(
|
|
290
|
+
"Authyon: `baseUrl` cannot contain credentials, query parameters, or fragments"
|
|
291
|
+
);
|
|
292
|
+
}
|
|
293
|
+
return url.toString().replace(/\/+$/, "");
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// ../../internal/core/http/query.ts
|
|
297
|
+
function appendQuery(path, params) {
|
|
298
|
+
if (!params) return path;
|
|
299
|
+
const query = new URLSearchParams();
|
|
300
|
+
for (const [key, value2] of Object.entries(params)) {
|
|
301
|
+
if (value2 === void 0) continue;
|
|
302
|
+
if (Array.isArray(value2)) {
|
|
303
|
+
for (const item of value2) {
|
|
304
|
+
if (item !== void 0) query.append(key, String(item));
|
|
305
|
+
}
|
|
306
|
+
continue;
|
|
307
|
+
}
|
|
308
|
+
query.set(key, String(value2));
|
|
309
|
+
}
|
|
310
|
+
const value = query.toString();
|
|
311
|
+
return value ? `${path}${path.includes("?") ? "&" : "?"}${value}` : path;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// ../../internal/core/http/jsonHttpClient.ts
|
|
315
|
+
var JsonHttpClient = class {
|
|
316
|
+
constructor(transport) {
|
|
317
|
+
this.transport = transport;
|
|
318
|
+
}
|
|
319
|
+
async send(path, options = {}) {
|
|
320
|
+
const headers = { ...options.headers };
|
|
321
|
+
if (options.body !== void 0) headers["Content-Type"] = "application/json";
|
|
322
|
+
try {
|
|
323
|
+
return await this.transport.request(appendQuery(path, options.query), {
|
|
324
|
+
method: options.method ?? "GET",
|
|
325
|
+
headers,
|
|
326
|
+
body: options.body !== void 0 ? JSON.stringify(options.body) : void 0
|
|
327
|
+
});
|
|
328
|
+
} catch (cause) {
|
|
329
|
+
if (!(cause instanceof SharedTransportError)) throw cause;
|
|
330
|
+
throw new AuthyonError(0, { code: cause.code, title: cause.message }, { cause: cause.cause });
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
async parse(response) {
|
|
334
|
+
if (!response.ok) {
|
|
335
|
+
let body = {};
|
|
336
|
+
try {
|
|
337
|
+
const parsed = await response.json();
|
|
338
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed))
|
|
339
|
+
body = parsed;
|
|
340
|
+
} catch {
|
|
341
|
+
}
|
|
342
|
+
throw new AuthyonError(response.status, body, responseMetadata(response));
|
|
343
|
+
}
|
|
344
|
+
if (response.status === 204) return void 0;
|
|
345
|
+
return await response.json();
|
|
346
|
+
}
|
|
347
|
+
async request(path, options = {}) {
|
|
348
|
+
return this.parse(await this.send(path, options));
|
|
349
|
+
}
|
|
350
|
+
};
|
|
351
|
+
|
|
352
|
+
export {
|
|
353
|
+
ErrorCodes,
|
|
354
|
+
AuthyonError,
|
|
355
|
+
DEFAULT_BASE_URL,
|
|
356
|
+
DEFAULT_EXPIRY_SKEW_MS,
|
|
357
|
+
FetchHttpAdapter,
|
|
358
|
+
LoggingHttpAdapter,
|
|
359
|
+
createSharedTransport,
|
|
360
|
+
JsonHttpClient
|
|
361
|
+
};
|