@authyon/auth 0.2.0-beta.0 → 0.2.0-beta.1

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/index.js CHANGED
@@ -1,26 +1,127 @@
1
- // src/errors.ts
1
+ import {
2
+ AuthyonAbility,
3
+ AuthyonAbilityBuilder,
4
+ AuthyonSessionController,
5
+ createAuthyonAbility,
6
+ createAuthyonRules
7
+ } from "./chunk-OKPSF4LZ.js";
8
+
9
+ // ../../internal/core/errors/authyonError.ts
10
+ var ErrorCodes = {
11
+ Unknown: "unknown",
12
+ NetworkError: "request.network_error",
13
+ Timeout: "request.timeout",
14
+ SessionMalformed: "session.malformed",
15
+ NotAuthenticated: "auth.not_authenticated",
16
+ InvalidToken: "auth.invalid_token",
17
+ MissingToken: "auth.missing_token",
18
+ EmailTaken: "user.email_taken",
19
+ PasswordWeak: "user.password_weak",
20
+ PasswordPwned: "user.password_pwned",
21
+ RateLimited: "rate_limited"
22
+ };
2
23
  var AuthyonError = class extends Error {
3
- constructor(status, body) {
24
+ constructor(status, body, options = {}) {
4
25
  super(body.detail ?? body.title ?? `Authyon request failed with status ${status}`);
5
26
  this.name = "AuthyonError";
6
27
  this.status = status;
7
28
  this.code = body.code ?? "unknown";
8
29
  this.title = body.title ?? "Error";
9
30
  this.detail = body.detail;
31
+ this.requestId = options.requestId;
32
+ this.retryAfter = options.retryAfter;
33
+ this.cause = options.cause;
10
34
  }
11
35
  is(code) {
12
36
  return this.code === code;
13
37
  }
38
+ isAny(...codes) {
39
+ return codes.includes(this.code);
40
+ }
41
+ hasPrefix(prefix) {
42
+ return this.code.startsWith(prefix);
43
+ }
44
+ isStatus(...statuses) {
45
+ return statuses.includes(this.status);
46
+ }
47
+ /** Stable interpretation for UI decisions, retries, telemetry and support flows. */
48
+ interpret() {
49
+ const category = classifyError(this.status, this.code);
50
+ return {
51
+ category,
52
+ action: actionFor(category),
53
+ retryable: isRetryable(category),
54
+ ...this.retryAfter !== void 0 ? { retryAfter: this.retryAfter } : {},
55
+ ...this.requestId !== void 0 ? { requestId: this.requestId } : {}
56
+ };
57
+ }
58
+ get category() {
59
+ return this.interpret().category;
60
+ }
61
+ get retryable() {
62
+ return this.interpret().retryable;
63
+ }
64
+ toJSON() {
65
+ return {
66
+ name: this.name,
67
+ message: this.message,
68
+ status: this.status,
69
+ code: this.code,
70
+ title: this.title,
71
+ detail: this.detail,
72
+ requestId: this.requestId,
73
+ retryAfter: this.retryAfter,
74
+ ...this.interpret()
75
+ };
76
+ }
14
77
  };
15
- var ErrorCodes = {
16
- EmailTaken: "user.email_taken",
17
- PasswordWeak: "user.password_weak",
18
- PasswordPwned: "user.password_pwned"
19
- };
78
+ function classifyError(status, code) {
79
+ if (code === ErrorCodes.NetworkError) return "network";
80
+ if (code === ErrorCodes.Timeout || status === 408) return "timeout";
81
+ if (code === ErrorCodes.RateLimited || status === 429) return "rate_limit";
82
+ if (code === ErrorCodes.EmailTaken || status === 409) return "conflict";
83
+ if (code === ErrorCodes.PasswordWeak || code === ErrorCodes.PasswordPwned) return "validation";
84
+ if (code === ErrorCodes.SessionMalformed) return "server";
85
+ if (code.startsWith("auth.") || status === 401) return "authentication";
86
+ if (status === 403) return "authorization";
87
+ if (status === 404) return "not_found";
88
+ if (status === 400 || status === 422) return "validation";
89
+ if (status >= 500) return "server";
90
+ return "unknown";
91
+ }
92
+ function actionFor(category) {
93
+ switch (category) {
94
+ case "network":
95
+ case "timeout":
96
+ case "rate_limit":
97
+ case "server":
98
+ return "retry";
99
+ case "authentication":
100
+ return "reauthenticate";
101
+ case "authorization":
102
+ return "request_access";
103
+ case "validation":
104
+ return "fix_input";
105
+ case "not_found":
106
+ return "not_found";
107
+ case "conflict":
108
+ return "resolve_conflict";
109
+ case "unknown":
110
+ return "contact_support";
111
+ }
112
+ }
113
+ function isRetryable(category) {
114
+ return category === "network" || category === "timeout" || category === "rate_limit" || category === "server";
115
+ }
20
116
 
21
- // src/storage.ts
117
+ // src/session/storage.ts
22
118
  var STORAGE_KEY = "authyon.session";
23
- function memoryStorage() {
119
+ function isSession(value) {
120
+ if (!value || typeof value !== "object") return false;
121
+ const candidate = value;
122
+ return typeof candidate.accessToken === "string" && candidate.accessToken.length > 0 && typeof candidate.refreshToken === "string" && candidate.refreshToken.length > 0 && typeof candidate.expiresIn === "number" && Number.isFinite(candidate.expiresIn) && candidate.expiresIn > 0 && typeof candidate.expiresAt === "number" && Number.isFinite(candidate.expiresAt);
123
+ }
124
+ function createMemoryStorage() {
24
125
  let session = null;
25
126
  return {
26
127
  get: () => session,
@@ -32,12 +133,16 @@ function memoryStorage() {
32
133
  }
33
134
  };
34
135
  }
35
- function localStorageAdapter(key = STORAGE_KEY) {
136
+ function createLocalStorage(key = STORAGE_KEY) {
36
137
  return {
37
138
  get() {
38
139
  try {
39
140
  const raw = window.localStorage.getItem(key);
40
- return raw ? JSON.parse(raw) : null;
141
+ if (!raw) return null;
142
+ const parsed = JSON.parse(raw);
143
+ if (isSession(parsed)) return parsed;
144
+ window.localStorage.removeItem(key);
145
+ return null;
41
146
  } catch {
42
147
  return null;
43
148
  }
@@ -56,22 +161,217 @@ function localStorageAdapter(key = STORAGE_KEY) {
56
161
  }
57
162
  };
58
163
  }
59
- function defaultStorage() {
60
- if (typeof window !== "undefined" && typeof window.localStorage !== "undefined") {
61
- return localStorageAdapter();
62
- }
63
- return memoryStorage();
164
+ function createDefaultStorage() {
165
+ return createMemoryStorage();
64
166
  }
65
167
 
66
- // src/client.ts
168
+ // ../../internal/core/config/defaults.ts
67
169
  var DEFAULT_BASE_URL = "https://api.authyon.com";
68
- var EXPIRY_SKEW_MS = 3e4;
170
+ var DEFAULT_EXPIRY_SKEW_MS = 3e4;
171
+
172
+ // ../../internal/core/http/query.ts
173
+ function appendQuery(path, params) {
174
+ if (!params) return path;
175
+ const query = new URLSearchParams();
176
+ for (const [key, value2] of Object.entries(params)) {
177
+ if (value2 !== void 0) query.set(key, String(value2));
178
+ }
179
+ const value = query.toString();
180
+ return value ? `${path}${path.includes("?") ? "&" : "?"}${value}` : path;
181
+ }
182
+
183
+ // ../../internal/core/http/httpAdapter.ts
184
+ var FetchHttpAdapter = class {
185
+ constructor(fetchImpl = fetch.bind(globalThis)) {
186
+ this.fetchImpl = fetchImpl;
187
+ }
188
+ request(request) {
189
+ return this.fetchImpl(request.url, {
190
+ method: request.method,
191
+ headers: request.headers,
192
+ body: request.body,
193
+ signal: request.signal
194
+ });
195
+ }
196
+ };
197
+ var LoggingHttpAdapter = class {
198
+ constructor(adapter, options) {
199
+ this.adapter = adapter;
200
+ this.options = options;
201
+ }
202
+ async request(request) {
203
+ const startedAt = Date.now();
204
+ const eventBase = {
205
+ method: request.method,
206
+ url: sanitizeUrl(request.url)
207
+ };
208
+ this.log({ type: "request", ...eventBase, timestamp: startedAt });
209
+ try {
210
+ const response = await this.adapter.request(request);
211
+ this.log({
212
+ type: "response",
213
+ ...eventBase,
214
+ status: response.status,
215
+ durationMs: Date.now() - startedAt,
216
+ requestId: response.headers.get("x-request-id") ?? response.headers.get("trace-id") ?? void 0,
217
+ timestamp: Date.now()
218
+ });
219
+ return response;
220
+ } catch (error) {
221
+ this.log({
222
+ type: "error",
223
+ ...eventBase,
224
+ errorName: error instanceof Error ? error.name : "UnknownError",
225
+ durationMs: Date.now() - startedAt,
226
+ timestamp: Date.now()
227
+ });
228
+ throw error;
229
+ }
230
+ }
231
+ log(event) {
232
+ if (!this.options.enabled) return;
233
+ const logger = this.options.logger ?? defaultHttpLogger;
234
+ try {
235
+ logger(event);
236
+ } catch {
237
+ }
238
+ }
239
+ };
240
+ function defaultHttpLogger(event) {
241
+ console.debug("[Authyon HTTP]", event);
242
+ }
243
+ function sanitizeUrl(value) {
244
+ const url = new URL(value);
245
+ const queryKeys = /* @__PURE__ */ new Set();
246
+ url.searchParams.forEach((_value, key) => queryKeys.add(key));
247
+ url.search = queryKeys.size > 0 ? [...queryKeys].map((key) => `${encodeURIComponent(key)}=REDACTED`).join("&") : "";
248
+ return url.toString();
249
+ }
250
+
251
+ // ../../internal/core/http/transport.ts
252
+ var DEFAULT_TIMEOUT_MS = 15e3;
253
+ var SharedTransportError = class extends Error {
254
+ constructor(code, cause) {
255
+ super(code === "request.timeout" ? "Request timed out" : "Network request failed");
256
+ this.name = "SharedTransportError";
257
+ this.code = code;
258
+ this.cause = cause;
259
+ }
260
+ };
261
+ function createSharedTransport(options) {
262
+ const baseUrl = normalizeBaseUrl(options.baseUrl, options.allowInsecureHttp ?? false);
263
+ const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
264
+ if (!Number.isFinite(timeoutMs) || timeoutMs < 0) {
265
+ throw new Error("Authyon: `timeoutMs` must be a non-negative finite number");
266
+ }
267
+ if (options.httpAdapter && options.fetch) {
268
+ throw new Error("Authyon: use either `httpAdapter` or `fetch`, not both");
269
+ }
270
+ const baseAdapter = options.httpAdapter ?? new FetchHttpAdapter(options.fetch);
271
+ const httpAdapter = options.httpLogger ? new LoggingHttpAdapter(baseAdapter, options.httpLogger) : baseAdapter;
272
+ return {
273
+ baseUrl,
274
+ async request(path, init) {
275
+ const controller = new AbortController();
276
+ const timeout = timeoutMs > 0 ? setTimeout(() => controller.abort(), timeoutMs) : void 0;
277
+ try {
278
+ return await httpAdapter.request({
279
+ url: `${baseUrl}${path}`,
280
+ method: init.method ?? "GET",
281
+ headers: normalizeHeaders(init.headers),
282
+ body: init.body,
283
+ signal: controller.signal
284
+ });
285
+ } catch (cause) {
286
+ throw new SharedTransportError(
287
+ controller.signal.aborted ? ErrorCodes.Timeout : ErrorCodes.NetworkError,
288
+ cause
289
+ );
290
+ } finally {
291
+ if (timeout !== void 0) clearTimeout(timeout);
292
+ }
293
+ }
294
+ };
295
+ }
296
+ function normalizeHeaders(headers) {
297
+ const normalized = {};
298
+ new Headers(headers).forEach((value, key) => {
299
+ normalized[key] = value;
300
+ });
301
+ return normalized;
302
+ }
303
+ function responseMetadata(response) {
304
+ const retryAfterHeader = response.headers.get("retry-after");
305
+ const retryAfter = retryAfterHeader ? Number(retryAfterHeader) : void 0;
306
+ return {
307
+ requestId: response.headers.get("x-request-id") ?? response.headers.get("trace-id") ?? void 0,
308
+ retryAfter: Number.isFinite(retryAfter) ? retryAfter : void 0
309
+ };
310
+ }
311
+ function normalizeBaseUrl(value, allowInsecureHttp) {
312
+ let url;
313
+ try {
314
+ url = new URL(value);
315
+ } catch {
316
+ throw new Error("Authyon: `baseUrl` must be an absolute URL");
317
+ }
318
+ const loopback = url.hostname === "localhost" || url.hostname === "127.0.0.1" || url.hostname === "[::1]";
319
+ if (url.protocol !== "https:" && !(url.protocol === "http:" && (loopback || allowInsecureHttp))) {
320
+ throw new Error(
321
+ "Authyon: `baseUrl` must use HTTPS (HTTP is allowed only for loopback or with `allowInsecureHttp`)"
322
+ );
323
+ }
324
+ if (url.username || url.password || url.search || url.hash) {
325
+ throw new Error(
326
+ "Authyon: `baseUrl` cannot contain credentials, query parameters, or fragments"
327
+ );
328
+ }
329
+ return url.toString().replace(/\/+$/, "");
330
+ }
331
+
332
+ // ../../internal/core/http/jsonHttpClient.ts
333
+ var JsonHttpClient = class {
334
+ constructor(transport) {
335
+ this.transport = transport;
336
+ }
337
+ async send(path, options = {}) {
338
+ const headers = { ...options.headers };
339
+ if (options.body !== void 0) headers["Content-Type"] = "application/json";
340
+ try {
341
+ return await this.transport.request(appendQuery(path, options.query), {
342
+ method: options.method ?? "GET",
343
+ headers,
344
+ body: options.body !== void 0 ? JSON.stringify(options.body) : void 0
345
+ });
346
+ } catch (cause) {
347
+ if (!(cause instanceof SharedTransportError)) throw cause;
348
+ throw new AuthyonError(0, { code: cause.code, title: cause.message }, { cause: cause.cause });
349
+ }
350
+ }
351
+ async parse(response) {
352
+ if (!response.ok) {
353
+ let body = {};
354
+ try {
355
+ body = await response.json();
356
+ } catch {
357
+ }
358
+ throw new AuthyonError(response.status, body, responseMetadata(response));
359
+ }
360
+ if (response.status === 204) return void 0;
361
+ return await response.json();
362
+ }
363
+ async request(path, options = {}) {
364
+ return this.parse(await this.send(path, options));
365
+ }
366
+ };
367
+
368
+ // src/client/authyonClient.ts
69
369
  var FALLBACK_EXPIRES_IN = 1800;
70
370
  function readTokens(raw) {
71
371
  const tokens = raw.tokens ?? raw;
72
372
  if (!tokens.accessToken || !tokens.refreshToken) {
73
373
  throw new AuthyonError(502, {
74
- code: "session.malformed",
374
+ code: ErrorCodes.SessionMalformed,
75
375
  title: "Malformed session response",
76
376
  detail: "The session response carried no access/refresh token pair."
77
377
  });
@@ -127,7 +427,7 @@ var AuthyonClient = class {
127
427
  /** GET /auth/sessions — active refresh-token sessions with device/IP data. */
128
428
  sessions: () => this.request("/auth/sessions", { bearer: true }),
129
429
  /** GET /auth/me/activities — paginated recent account activity for the current user. */
130
- activities: (params = {}) => this.request(`/auth/me/activities?${toQuery(params)}`, { bearer: true }),
430
+ activities: (params = {}) => this.request(appendQuery("/auth/me/activities", params), { bearer: true }),
131
431
  /**
132
432
  * Revokes a single session by id (e.g. one entry from `sessions()`),
133
433
  * signing that device out without affecting the current one.
@@ -183,11 +483,11 @@ var AuthyonClient = class {
183
483
  /**
184
484
  * GET /auth/tenants/{organizationId}/members — paginated list of an
185
485
  * organization's members. Consistent with the confirmed-live
186
- * `Page<T>` envelope every other `skip`/`take` endpoint returns
486
+ * `Paged<T>` envelope every other `skip`/`take` endpoint returns
187
487
  * (`user.activities()`, `@authyon/server`'s `environment.users.list()`).
188
488
  */
189
489
  list: (organizationId, params = {}) => this.request(
190
- `/auth/tenants/${encodeURIComponent(organizationId)}/members?${toQuery(params)}`,
490
+ appendQuery(`/auth/tenants/${encodeURIComponent(organizationId)}/members`, params),
191
491
  { bearer: true }
192
492
  ),
193
493
  /** POST /auth/tenants/{organizationId}/members — invite a member by e-mail. */
@@ -280,10 +580,18 @@ var AuthyonClient = class {
280
580
  if (!options.envKey)
281
581
  throw new Error("Authyon: `envKey` is required (pk_live_... / pk_test_...)");
282
582
  this.envKey = options.envKey;
283
- this.baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
284
- this.storage = options.storage ?? defaultStorage();
583
+ this.transport = createSharedTransport({
584
+ baseUrl: options.baseUrl ?? DEFAULT_BASE_URL,
585
+ allowInsecureHttp: options.allowInsecureHttp,
586
+ timeoutMs: options.timeoutMs,
587
+ httpAdapter: options.httpAdapter,
588
+ httpLogger: options.httpLogger,
589
+ fetch: options.fetch
590
+ });
591
+ this.baseUrl = this.transport.baseUrl;
592
+ this.http = new JsonHttpClient(this.transport);
593
+ this.storage = options.storage ?? createDefaultStorage();
285
594
  this.autoRefresh = options.autoRefresh ?? true;
286
- this.fetchImpl = options.fetch ?? fetch.bind(globalThis);
287
595
  }
288
596
  // ── Session state ────────────────────────────────────────────────────────
289
597
  /** Current persisted session, or null when signed out. */
@@ -291,7 +599,13 @@ var AuthyonClient = class {
291
599
  return this.storage.get();
292
600
  }
293
601
  isAuthenticated() {
294
- return this.getSession() !== null;
602
+ return this.getAuthState() === "authenticated";
603
+ }
604
+ /** Synchronous snapshot of the locally available authentication state. */
605
+ getAuthState() {
606
+ const session = this.getSession();
607
+ if (!session) return "signed_out";
608
+ return Date.now() < session.expiresAt ? "authenticated" : "expired";
295
609
  }
296
610
  /**
297
611
  * Returns a valid access token, refreshing it transparently when it is
@@ -300,15 +614,41 @@ var AuthyonClient = class {
300
614
  async getAccessToken() {
301
615
  const session = this.getSession();
302
616
  if (!session) return null;
303
- if (this.autoRefresh && Date.now() >= session.expiresAt - EXPIRY_SKEW_MS) {
617
+ if (this.autoRefresh && Date.now() >= session.expiresAt - DEFAULT_EXPIRY_SKEW_MS) {
304
618
  try {
305
619
  return (await this.refresh()).accessToken;
306
- } catch {
307
- return null;
620
+ } catch (error) {
621
+ if (error instanceof AuthyonError && (error.status === 401 || error.status === 403)) {
622
+ return null;
623
+ }
624
+ throw error;
308
625
  }
309
626
  }
310
627
  return session.accessToken;
311
628
  }
629
+ /**
630
+ * Refreshes when needed, validates the server-side session through `GET /auth/me`,
631
+ * and stores the fresh user profile. Returns null when the session is no longer valid.
632
+ */
633
+ async validateSession() {
634
+ const accessToken = await this.getAccessToken();
635
+ if (!accessToken) return null;
636
+ try {
637
+ const user = await this.user.me();
638
+ const current = this.getSession();
639
+ if (!current) return null;
640
+ const session = { ...current, user };
641
+ this.storage.set(session);
642
+ this.emit({ type: "session_validated", session });
643
+ return session;
644
+ } catch (error) {
645
+ if (error instanceof AuthyonError && (error.status === 401 || error.status === 403)) {
646
+ this.clearSession();
647
+ return null;
648
+ }
649
+ throw error;
650
+ }
651
+ }
312
652
  /** Subscribe to sign-in / refresh / sign-out events. Returns an unsubscribe fn. */
313
653
  onAuthStateChange(listener) {
314
654
  this.listeners.add(listener);
@@ -354,38 +694,26 @@ var AuthyonClient = class {
354
694
  "X-Authyon-Environment": this.envKey,
355
695
  ...options.headers
356
696
  };
357
- if (options.body !== void 0) headers["Content-Type"] = "application/json";
358
697
  if (options.bearer) {
359
698
  const token = await this.getAccessToken();
360
699
  if (!token)
361
- throw new AuthyonError(401, { code: "auth.not_authenticated", title: "Not authenticated" });
700
+ throw new AuthyonError(401, {
701
+ code: ErrorCodes.NotAuthenticated,
702
+ title: "Not authenticated"
703
+ });
362
704
  headers.Authorization = `Bearer ${token}`;
363
705
  }
364
- const response = await this.fetchImpl(`${this.baseUrl}${path}`, {
365
- method: options.method ?? "GET",
366
- headers,
367
- body: options.body !== void 0 ? JSON.stringify(options.body) : void 0
368
- });
706
+ const response = await this.http.send(path, { ...options, headers });
369
707
  if (response.status === 401 && options.bearer && this.autoRefresh && !isRetry && this.getSession()) {
370
708
  try {
371
709
  await this.refresh();
372
710
  } catch {
373
711
  this.clearSession();
374
- throw await this.toError(response);
712
+ return this.http.parse(response);
375
713
  }
376
714
  return this.request(path, options, true);
377
715
  }
378
- if (!response.ok) throw await this.toError(response);
379
- if (response.status === 204) return void 0;
380
- return await response.json();
381
- }
382
- async toError(response) {
383
- let body = {};
384
- try {
385
- body = await response.json();
386
- } catch {
387
- }
388
- return new AuthyonError(response.status, body);
716
+ return this.http.parse(response);
389
717
  }
390
718
  // ── Auth flows ───────────────────────────────────────────────────────────
391
719
  /** POST /auth/register — creates a new user (rate-limited to 20/hour per IP). */
@@ -421,7 +749,10 @@ var AuthyonClient = class {
421
749
  if (this.refreshInFlight) return this.refreshInFlight;
422
750
  const current = this.getSession();
423
751
  if (!current)
424
- throw new AuthyonError(401, { code: "auth.not_authenticated", title: "Not authenticated" });
752
+ throw new AuthyonError(401, {
753
+ code: ErrorCodes.NotAuthenticated,
754
+ title: "Not authenticated"
755
+ });
425
756
  this.refreshInFlight = this.request("/auth/refresh", {
426
757
  method: "POST",
427
758
  body: { refreshToken: current.refreshToken }
@@ -471,6 +802,8 @@ var AuthyonClient = class {
471
802
  * A browser app has no client secret to present, so this will fail from
472
803
  * `@authyon/auth` in practice; call it from your backend via
473
804
  * `@authyon/server` instead.
805
+ *
806
+ * @deprecated Use `@authyon/server.introspect()` from a trusted backend.
474
807
  */
475
808
  async introspect(token) {
476
809
  const accessToken = token ?? await this.getAccessToken();
@@ -480,6 +813,8 @@ var AuthyonClient = class {
480
813
  * POST /auth/validate — recommended: cross-checks DB state, catches
481
814
  * revocation immediately. Same caller-authentication requirement (and
482
815
  * the same practical limitation from the browser) as `introspect()`.
816
+ *
817
+ * @deprecated Use `@authyon/server.validate()` from a trusted backend.
483
818
  */
484
819
  async validate(token) {
485
820
  const accessToken = token ?? await this.getAccessToken();
@@ -502,19 +837,55 @@ function normalizeUser(raw) {
502
837
  function createClient(options) {
503
838
  return new AuthyonClient(options);
504
839
  }
505
- function toQuery(params) {
506
- const query = new URLSearchParams();
507
- for (const [key, value] of Object.entries(params)) {
508
- if (value !== void 0) query.set(key, String(value));
840
+
841
+ // src/client/authyonClientBuilder.ts
842
+ var AuthyonClientBuilder = class {
843
+ constructor(envKey) {
844
+ this.options = { envKey };
509
845
  }
510
- return query.toString();
511
- }
846
+ withBaseUrl(baseUrl, allowInsecureHttp = false) {
847
+ this.options.baseUrl = baseUrl;
848
+ this.options.allowInsecureHttp = allowInsecureHttp;
849
+ return this;
850
+ }
851
+ withStorage(storage) {
852
+ this.options.storage = storage;
853
+ return this;
854
+ }
855
+ withAutomaticRefresh(enabled = true) {
856
+ this.options.autoRefresh = enabled;
857
+ return this;
858
+ }
859
+ withTimeout(timeoutMs) {
860
+ this.options.timeoutMs = timeoutMs;
861
+ return this;
862
+ }
863
+ withHttpAdapter(httpAdapter) {
864
+ this.options.httpAdapter = httpAdapter;
865
+ return this;
866
+ }
867
+ withHttpLogger(httpLogger) {
868
+ this.options.httpLogger = httpLogger;
869
+ return this;
870
+ }
871
+ build() {
872
+ return new AuthyonClient({ ...this.options });
873
+ }
874
+ };
512
875
  export {
876
+ AuthyonAbility,
877
+ AuthyonAbilityBuilder,
513
878
  AuthyonClient,
879
+ AuthyonClientBuilder,
514
880
  AuthyonError,
881
+ AuthyonSessionController,
515
882
  ErrorCodes,
883
+ FetchHttpAdapter,
884
+ LoggingHttpAdapter,
885
+ createAuthyonAbility,
886
+ createAuthyonRules,
516
887
  createClient,
517
- defaultStorage,
518
- localStorageAdapter,
519
- memoryStorage
888
+ createDefaultStorage,
889
+ createLocalStorage,
890
+ createMemoryStorage
520
891
  };