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

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