@genation/sdk 0.1.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/README.md +149 -0
- package/dist/genation.cjs.js +2 -0
- package/dist/genation.cjs.js.map +1 -0
- package/dist/genation.es.js +626 -0
- package/dist/genation.es.js.map +1 -0
- package/dist/genation.umd.js +2 -0
- package/dist/genation.umd.js.map +1 -0
- package/dist/index.d.ts +823 -0
- package/package.json +52 -0
|
@@ -0,0 +1,626 @@
|
|
|
1
|
+
class w extends Error {
|
|
2
|
+
code;
|
|
3
|
+
cause;
|
|
4
|
+
constructor(e, t, r) {
|
|
5
|
+
super(e), this.name = "GenationError", this.code = t, this.cause = r;
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
class h extends w {
|
|
9
|
+
constructor(e, t, r) {
|
|
10
|
+
super(e, t, r), this.name = "AuthError";
|
|
11
|
+
}
|
|
12
|
+
static invalidGrant(e = "Invalid authorization code or refresh token") {
|
|
13
|
+
return new h(e, "invalid_grant");
|
|
14
|
+
}
|
|
15
|
+
static accessDenied(e = "User denied access") {
|
|
16
|
+
return new h(e, "access_denied");
|
|
17
|
+
}
|
|
18
|
+
static expiredToken(e = "Token has expired") {
|
|
19
|
+
return new h(e, "expired_token");
|
|
20
|
+
}
|
|
21
|
+
static invalidState(e = "State mismatch, possible CSRF attack") {
|
|
22
|
+
return new h(e, "invalid_state");
|
|
23
|
+
}
|
|
24
|
+
static pkceVerificationFailed(e = "PKCE verification failed") {
|
|
25
|
+
return new h(e, "pkce_verification_failed");
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
class c extends w {
|
|
29
|
+
status;
|
|
30
|
+
constructor(e, t, r) {
|
|
31
|
+
super(e, "network_error", r), this.name = "NetworkError", this.status = t;
|
|
32
|
+
}
|
|
33
|
+
static fromResponse(e) {
|
|
34
|
+
return new c(
|
|
35
|
+
`HTTP ${e.status}: ${e.statusText}`,
|
|
36
|
+
e.status
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
class u extends w {
|
|
41
|
+
constructor(e) {
|
|
42
|
+
super(e, "config_error"), this.name = "ConfigError";
|
|
43
|
+
}
|
|
44
|
+
static missingField(e) {
|
|
45
|
+
return new u(`Missing required config field: ${e}`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
class p {
|
|
49
|
+
baseUrl;
|
|
50
|
+
timeout;
|
|
51
|
+
constructor(e) {
|
|
52
|
+
this.baseUrl = e.baseUrl.replace(/\/$/, ""), this.timeout = e.timeout ?? 3e4;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Make an HTTP request
|
|
56
|
+
*/
|
|
57
|
+
async request(e, t = {}) {
|
|
58
|
+
const { method: r = "GET", headers: n = {}, body: a, params: l } = t;
|
|
59
|
+
let o = `${this.baseUrl}${e}`;
|
|
60
|
+
if (l) {
|
|
61
|
+
const i = new URLSearchParams(l);
|
|
62
|
+
o += `?${i.toString()}`;
|
|
63
|
+
}
|
|
64
|
+
const m = new AbortController(), y = setTimeout(() => m.abort(), this.timeout);
|
|
65
|
+
try {
|
|
66
|
+
const i = await fetch(o, {
|
|
67
|
+
method: r,
|
|
68
|
+
headers: {
|
|
69
|
+
"Content-Type": "application/json",
|
|
70
|
+
...n
|
|
71
|
+
},
|
|
72
|
+
body: a ? JSON.stringify(a) : void 0,
|
|
73
|
+
signal: m.signal
|
|
74
|
+
});
|
|
75
|
+
if (clearTimeout(y), !i.ok)
|
|
76
|
+
throw c.fromResponse(i);
|
|
77
|
+
return await i.json();
|
|
78
|
+
} catch (i) {
|
|
79
|
+
throw clearTimeout(y), i instanceof c ? i : i instanceof Error && i.name === "AbortError" ? new c("Request timeout", void 0, i) : new c("Network request failed", void 0, i);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* POST request with form data (for OAuth token exchange)
|
|
84
|
+
*/
|
|
85
|
+
async postForm(e, t, r = {}) {
|
|
86
|
+
const n = `${this.baseUrl}${e}`, a = new AbortController(), l = setTimeout(() => a.abort(), this.timeout);
|
|
87
|
+
try {
|
|
88
|
+
const o = await fetch(n, {
|
|
89
|
+
method: "POST",
|
|
90
|
+
headers: {
|
|
91
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
92
|
+
...r
|
|
93
|
+
},
|
|
94
|
+
body: new URLSearchParams(t).toString(),
|
|
95
|
+
signal: a.signal
|
|
96
|
+
});
|
|
97
|
+
if (clearTimeout(l), !o.ok)
|
|
98
|
+
throw c.fromResponse(o);
|
|
99
|
+
return await o.json();
|
|
100
|
+
} catch (o) {
|
|
101
|
+
throw clearTimeout(l), o instanceof c ? o : new c("Network request failed", void 0, o);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
function k(s) {
|
|
106
|
+
return btoa(String.fromCharCode(...s)).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
|
|
107
|
+
}
|
|
108
|
+
function T() {
|
|
109
|
+
const s = new Uint8Array(32);
|
|
110
|
+
return crypto.getRandomValues(s), k(s);
|
|
111
|
+
}
|
|
112
|
+
async function b(s) {
|
|
113
|
+
const t = new TextEncoder().encode(s), r = await crypto.subtle.digest("SHA-256", t);
|
|
114
|
+
return k(new Uint8Array(r));
|
|
115
|
+
}
|
|
116
|
+
async function v() {
|
|
117
|
+
const s = T(), e = await b(s);
|
|
118
|
+
return {
|
|
119
|
+
codeVerifier: s,
|
|
120
|
+
codeChallenge: e,
|
|
121
|
+
codeChallengeMethod: "S256"
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
function _() {
|
|
125
|
+
const s = new Uint8Array(16);
|
|
126
|
+
return crypto.getRandomValues(s), k(s);
|
|
127
|
+
}
|
|
128
|
+
const d = "tokens", g = "pkce", f = "state";
|
|
129
|
+
class C {
|
|
130
|
+
storage;
|
|
131
|
+
constructor(e) {
|
|
132
|
+
this.storage = e;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Store token set
|
|
136
|
+
*/
|
|
137
|
+
async setTokens(e) {
|
|
138
|
+
await this.storage.set(d, JSON.stringify(e));
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Get stored tokens
|
|
142
|
+
*/
|
|
143
|
+
async getTokens() {
|
|
144
|
+
const e = await this.storage.get(d);
|
|
145
|
+
if (!e) return null;
|
|
146
|
+
try {
|
|
147
|
+
return JSON.parse(e);
|
|
148
|
+
} catch {
|
|
149
|
+
return null;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Clear stored tokens
|
|
154
|
+
*/
|
|
155
|
+
async clearTokens() {
|
|
156
|
+
await this.storage.remove(d);
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Check if access token is expired
|
|
160
|
+
*/
|
|
161
|
+
async isTokenExpired() {
|
|
162
|
+
const e = await this.getTokens();
|
|
163
|
+
if (!e) return !0;
|
|
164
|
+
const t = e.issuedAt + e.expiresIn * 1e3;
|
|
165
|
+
return Date.now() > t - 6e4;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Store PKCE verifier for later validation
|
|
169
|
+
*/
|
|
170
|
+
async setPKCE(e) {
|
|
171
|
+
await this.storage.set(g, e);
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Get and clear stored PKCE verifier
|
|
175
|
+
*/
|
|
176
|
+
async consumePKCE() {
|
|
177
|
+
const e = await this.storage.get(g);
|
|
178
|
+
return e && await this.storage.remove(g), e;
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Store state for CSRF validation
|
|
182
|
+
*/
|
|
183
|
+
async setState(e) {
|
|
184
|
+
await this.storage.set(f, e);
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Get and clear stored state
|
|
188
|
+
*/
|
|
189
|
+
async consumeState() {
|
|
190
|
+
const e = await this.storage.get(f);
|
|
191
|
+
return e && await this.storage.remove(f), e;
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Clear all auth-related data
|
|
195
|
+
*/
|
|
196
|
+
async clearAll() {
|
|
197
|
+
await this.storage.clear();
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
const I = "https://mnnoheowoowbtpuoguul.supabase.co/auth/v1";
|
|
201
|
+
class U {
|
|
202
|
+
config;
|
|
203
|
+
http;
|
|
204
|
+
tokenManager;
|
|
205
|
+
constructor(e, t) {
|
|
206
|
+
this.config = {
|
|
207
|
+
clientId: e.clientId,
|
|
208
|
+
clientSecret: e.clientSecret,
|
|
209
|
+
redirectUri: e.redirectUri,
|
|
210
|
+
scopes: e.scopes,
|
|
211
|
+
authUrl: e.authUrl ?? I
|
|
212
|
+
}, this.http = new p({ baseUrl: this.config.authUrl }), this.tokenManager = t;
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Generate authorization URL for OAuth flow
|
|
216
|
+
* Stores PKCE verifier and state for later validation
|
|
217
|
+
*/
|
|
218
|
+
async getAuthorizationUrl() {
|
|
219
|
+
const e = await v(), t = _();
|
|
220
|
+
await this.tokenManager.setPKCE(e.codeVerifier), await this.tokenManager.setState(t);
|
|
221
|
+
const r = new URLSearchParams({
|
|
222
|
+
response_type: "code",
|
|
223
|
+
client_id: this.config.clientId,
|
|
224
|
+
redirect_uri: this.config.redirectUri,
|
|
225
|
+
state: t,
|
|
226
|
+
code_challenge: e.codeChallenge,
|
|
227
|
+
code_challenge_method: e.codeChallengeMethod
|
|
228
|
+
});
|
|
229
|
+
return this.config.scopes && this.config.scopes.length > 0 && r.append("scope", this.config.scopes.join(" ")), `${this.config.authUrl}/oauth/authorize?${r.toString()}`;
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Exchange authorization code for tokens
|
|
233
|
+
*/
|
|
234
|
+
async exchangeCode(e, t) {
|
|
235
|
+
const r = await this.tokenManager.consumeState();
|
|
236
|
+
if (!r || r !== t)
|
|
237
|
+
throw h.invalidState();
|
|
238
|
+
const n = await this.tokenManager.consumePKCE();
|
|
239
|
+
if (!n)
|
|
240
|
+
throw h.pkceVerificationFailed("Missing code verifier");
|
|
241
|
+
const a = await this.http.postForm(
|
|
242
|
+
"/oauth/token",
|
|
243
|
+
{
|
|
244
|
+
grant_type: "authorization_code",
|
|
245
|
+
code: e,
|
|
246
|
+
redirect_uri: this.config.redirectUri,
|
|
247
|
+
client_id: this.config.clientId,
|
|
248
|
+
client_secret: this.config.clientSecret,
|
|
249
|
+
code_verifier: n
|
|
250
|
+
}
|
|
251
|
+
), l = this.mapTokenResponse(a);
|
|
252
|
+
return await this.tokenManager.setTokens(l), l;
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* Refresh access token using refresh token
|
|
256
|
+
*/
|
|
257
|
+
async refreshToken() {
|
|
258
|
+
const e = await this.tokenManager.getTokens();
|
|
259
|
+
if (!e?.refreshToken)
|
|
260
|
+
throw h.invalidGrant("No refresh token available");
|
|
261
|
+
const t = await this.http.postForm(
|
|
262
|
+
"/oauth/token",
|
|
263
|
+
{
|
|
264
|
+
grant_type: "refresh_token",
|
|
265
|
+
refresh_token: e.refreshToken,
|
|
266
|
+
client_id: this.config.clientId,
|
|
267
|
+
client_secret: this.config.clientSecret
|
|
268
|
+
}
|
|
269
|
+
), r = this.mapTokenResponse(t);
|
|
270
|
+
return await this.tokenManager.setTokens(r), r;
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Revoke current tokens
|
|
274
|
+
*/
|
|
275
|
+
async revokeToken() {
|
|
276
|
+
const e = await this.tokenManager.getTokens();
|
|
277
|
+
if (e)
|
|
278
|
+
try {
|
|
279
|
+
await this.http.postForm("/oauth/revoke", {
|
|
280
|
+
token: e.accessToken,
|
|
281
|
+
client_id: this.config.clientId,
|
|
282
|
+
client_secret: this.config.clientSecret
|
|
283
|
+
});
|
|
284
|
+
} finally {
|
|
285
|
+
await this.tokenManager.clearTokens();
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* Map OAuth token response to TokenSet
|
|
290
|
+
*/
|
|
291
|
+
mapTokenResponse(e) {
|
|
292
|
+
return {
|
|
293
|
+
accessToken: e.access_token,
|
|
294
|
+
refreshToken: e.refresh_token,
|
|
295
|
+
tokenType: e.token_type,
|
|
296
|
+
expiresIn: e.expires_in,
|
|
297
|
+
issuedAt: Date.now(),
|
|
298
|
+
scope: e.scope
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
class x {
|
|
303
|
+
store = /* @__PURE__ */ new Map();
|
|
304
|
+
async get(e) {
|
|
305
|
+
return this.store.get(e) ?? null;
|
|
306
|
+
}
|
|
307
|
+
async set(e, t) {
|
|
308
|
+
this.store.set(e, t);
|
|
309
|
+
}
|
|
310
|
+
async remove(e) {
|
|
311
|
+
this.store.delete(e);
|
|
312
|
+
}
|
|
313
|
+
async clear() {
|
|
314
|
+
this.store.clear();
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
class S {
|
|
318
|
+
prefix;
|
|
319
|
+
constructor(e = "genation") {
|
|
320
|
+
this.prefix = e;
|
|
321
|
+
}
|
|
322
|
+
getKey(e) {
|
|
323
|
+
return `${this.prefix}:${e}`;
|
|
324
|
+
}
|
|
325
|
+
async get(e) {
|
|
326
|
+
return typeof window > "u" ? null : localStorage.getItem(this.getKey(e));
|
|
327
|
+
}
|
|
328
|
+
async set(e, t) {
|
|
329
|
+
typeof window > "u" || localStorage.setItem(this.getKey(e), t);
|
|
330
|
+
}
|
|
331
|
+
async remove(e) {
|
|
332
|
+
typeof window > "u" || localStorage.removeItem(this.getKey(e));
|
|
333
|
+
}
|
|
334
|
+
async clear() {
|
|
335
|
+
if (typeof window > "u") return;
|
|
336
|
+
Object.keys(localStorage).filter(
|
|
337
|
+
(t) => t.startsWith(`${this.prefix}:`)
|
|
338
|
+
).forEach((t) => localStorage.removeItem(t));
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
class E {
|
|
342
|
+
prefix;
|
|
343
|
+
constructor(e = "genation") {
|
|
344
|
+
this.prefix = e;
|
|
345
|
+
}
|
|
346
|
+
getKey(e) {
|
|
347
|
+
return `${this.prefix}:${e}`;
|
|
348
|
+
}
|
|
349
|
+
async get(e) {
|
|
350
|
+
return typeof window > "u" ? null : sessionStorage.getItem(this.getKey(e));
|
|
351
|
+
}
|
|
352
|
+
async set(e, t) {
|
|
353
|
+
typeof window > "u" || sessionStorage.setItem(this.getKey(e), t);
|
|
354
|
+
}
|
|
355
|
+
async remove(e) {
|
|
356
|
+
typeof window > "u" || sessionStorage.removeItem(this.getKey(e));
|
|
357
|
+
}
|
|
358
|
+
async clear() {
|
|
359
|
+
if (typeof window > "u") return;
|
|
360
|
+
Object.keys(sessionStorage).filter(
|
|
361
|
+
(t) => t.startsWith(`${this.prefix}:`)
|
|
362
|
+
).forEach((t) => sessionStorage.removeItem(t));
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
function A(s = "localStorage") {
|
|
366
|
+
switch (s) {
|
|
367
|
+
case "memory":
|
|
368
|
+
return new x();
|
|
369
|
+
case "localStorage":
|
|
370
|
+
return new S();
|
|
371
|
+
case "sessionStorage":
|
|
372
|
+
return new E();
|
|
373
|
+
default:
|
|
374
|
+
return new S();
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
class M {
|
|
378
|
+
oauth;
|
|
379
|
+
tokenManager;
|
|
380
|
+
http;
|
|
381
|
+
httpServer;
|
|
382
|
+
listeners = /* @__PURE__ */ new Set();
|
|
383
|
+
initialized = !1;
|
|
384
|
+
constructor(e) {
|
|
385
|
+
this.validateConfig(e);
|
|
386
|
+
const t = typeof e.storage == "object" ? e.storage : A(e.storage);
|
|
387
|
+
this.tokenManager = new C(t), this.oauth = new U(e, this.tokenManager), this.http = new p({
|
|
388
|
+
baseUrl: e.authUrl ?? "https://mnnoheowoowbtpuoguul.supabase.co/auth/v1"
|
|
389
|
+
}), this.httpServer = new p({
|
|
390
|
+
baseUrl: "https://ff-api.genation.ai/api/v2/client"
|
|
391
|
+
});
|
|
392
|
+
}
|
|
393
|
+
validateConfig(e) {
|
|
394
|
+
if (!e.clientId) throw u.missingField("clientId");
|
|
395
|
+
if (!e.clientSecret)
|
|
396
|
+
throw u.missingField("clientSecret");
|
|
397
|
+
if (!e.redirectUri) throw u.missingField("redirectUri");
|
|
398
|
+
}
|
|
399
|
+
/**
|
|
400
|
+
* Emit auth state change event to all listeners
|
|
401
|
+
*/
|
|
402
|
+
async emitAuthStateChange(e) {
|
|
403
|
+
const t = await this.getSession();
|
|
404
|
+
this.listeners.forEach((r) => {
|
|
405
|
+
try {
|
|
406
|
+
r(e, t);
|
|
407
|
+
} catch (n) {
|
|
408
|
+
console.error("Error in auth state change callback:", n);
|
|
409
|
+
}
|
|
410
|
+
});
|
|
411
|
+
}
|
|
412
|
+
/**
|
|
413
|
+
* Listen to authentication state changes
|
|
414
|
+
*
|
|
415
|
+
* Register a callback that fires when:
|
|
416
|
+
* - `INITIAL_SESSION`: On first subscription, with current session state
|
|
417
|
+
* - `SIGNED_IN`: User successfully authenticated
|
|
418
|
+
* - `SIGNED_OUT`: User logged out or session expired
|
|
419
|
+
* - `TOKEN_REFRESHED`: Access token was automatically refreshed
|
|
420
|
+
*
|
|
421
|
+
* @param callback - Function called on each auth state change
|
|
422
|
+
* @returns Object containing subscription with `unsubscribe()` method
|
|
423
|
+
*
|
|
424
|
+
* @example
|
|
425
|
+
* ```typescript
|
|
426
|
+
* const { subscription } = client.onAuthStateChange((event, session) => {
|
|
427
|
+
* console.log('Auth event:', event);
|
|
428
|
+
*
|
|
429
|
+
* if (event === 'INITIAL_SESSION') {
|
|
430
|
+
* // Check if user was previously logged in
|
|
431
|
+
* if (session) {
|
|
432
|
+
* console.log('Welcome back!', session.user);
|
|
433
|
+
* }
|
|
434
|
+
* } else if (event === 'SIGNED_IN') {
|
|
435
|
+
* // User just signed in
|
|
436
|
+
* console.log('Signed in:', session?.user);
|
|
437
|
+
* } else if (event === 'SIGNED_OUT') {
|
|
438
|
+
* // Clear app state, redirect to login
|
|
439
|
+
* console.log('Signed out');
|
|
440
|
+
* }
|
|
441
|
+
* });
|
|
442
|
+
*
|
|
443
|
+
* // Cleanup when component unmounts
|
|
444
|
+
* subscription.unsubscribe();
|
|
445
|
+
* ```
|
|
446
|
+
*/
|
|
447
|
+
onAuthStateChange(e) {
|
|
448
|
+
return this.listeners.add(e), this.initialized ? setTimeout(() => {
|
|
449
|
+
this.emitAuthStateChange("INITIAL_SESSION");
|
|
450
|
+
}, 0) : (this.initialized = !0, setTimeout(() => {
|
|
451
|
+
this.emitAuthStateChange("INITIAL_SESSION");
|
|
452
|
+
}, 0)), {
|
|
453
|
+
subscription: {
|
|
454
|
+
unsubscribe: () => {
|
|
455
|
+
this.listeners.delete(e);
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
};
|
|
459
|
+
}
|
|
460
|
+
/**
|
|
461
|
+
* Start OAuth sign-in flow
|
|
462
|
+
*
|
|
463
|
+
* Generates authorization URL with PKCE challenge.
|
|
464
|
+
* Redirect user to this URL to start authentication.
|
|
465
|
+
*
|
|
466
|
+
* @returns Authorization URL to redirect user to
|
|
467
|
+
*
|
|
468
|
+
* @example
|
|
469
|
+
* ```typescript
|
|
470
|
+
* async function handleLogin() {
|
|
471
|
+
* const url = await client.signIn();
|
|
472
|
+
* window.location.href = url;
|
|
473
|
+
* }
|
|
474
|
+
* ```
|
|
475
|
+
*/
|
|
476
|
+
async signIn() {
|
|
477
|
+
return this.oauth.getAuthorizationUrl();
|
|
478
|
+
}
|
|
479
|
+
/**
|
|
480
|
+
* Handle OAuth callback after user authentication
|
|
481
|
+
*
|
|
482
|
+
* Call this on your redirect URI page to exchange
|
|
483
|
+
* the authorization code for access tokens.
|
|
484
|
+
* Triggers `SIGNED_IN` event on success.
|
|
485
|
+
*
|
|
486
|
+
* @param code - Authorization code from URL query params
|
|
487
|
+
* @param state - State parameter for CSRF validation
|
|
488
|
+
* @returns Token set with access and refresh tokens
|
|
489
|
+
* @throws {AuthError} If state mismatch or code exchange fails
|
|
490
|
+
*
|
|
491
|
+
* @example
|
|
492
|
+
* ```typescript
|
|
493
|
+
* // On your /callback page
|
|
494
|
+
* async function handleCallback() {
|
|
495
|
+
* const params = new URLSearchParams(window.location.search);
|
|
496
|
+
* const code = params.get('code');
|
|
497
|
+
* const state = params.get('state');
|
|
498
|
+
*
|
|
499
|
+
* if (code && state) {
|
|
500
|
+
* await client.handleCallback(code, state);
|
|
501
|
+
* // onAuthStateChange will fire with SIGNED_IN event
|
|
502
|
+
* }
|
|
503
|
+
* }
|
|
504
|
+
* ```
|
|
505
|
+
*/
|
|
506
|
+
async handleCallback(e, t) {
|
|
507
|
+
const r = await this.oauth.exchangeCode(e, t);
|
|
508
|
+
try {
|
|
509
|
+
const n = await this.fetchUser(r.accessToken);
|
|
510
|
+
console.log("Debug: handleCallback fetched user:", n);
|
|
511
|
+
} catch (n) {
|
|
512
|
+
console.error("Debug: handleCallback fetchUser failed:", n);
|
|
513
|
+
}
|
|
514
|
+
return await this.emitAuthStateChange("SIGNED_IN"), r;
|
|
515
|
+
}
|
|
516
|
+
/**
|
|
517
|
+
* Sign out and revoke tokens
|
|
518
|
+
*
|
|
519
|
+
* Clears local session and revokes tokens on server.
|
|
520
|
+
* Triggers `SIGNED_OUT` event for all listeners.
|
|
521
|
+
*
|
|
522
|
+
* @example
|
|
523
|
+
* ```typescript
|
|
524
|
+
* async function handleLogout() {
|
|
525
|
+
* await client.signOut();
|
|
526
|
+
* // onAuthStateChange will fire with SIGNED_OUT event
|
|
527
|
+
* }
|
|
528
|
+
* ```
|
|
529
|
+
*/
|
|
530
|
+
async signOut() {
|
|
531
|
+
await this.oauth.revokeToken(), await this.emitAuthStateChange("SIGNED_OUT");
|
|
532
|
+
}
|
|
533
|
+
/**
|
|
534
|
+
* Get current session
|
|
535
|
+
*
|
|
536
|
+
* Returns session with access token and user info.
|
|
537
|
+
* Automatically refreshes token if expired.
|
|
538
|
+
*
|
|
539
|
+
* @returns Current session or null if not authenticated
|
|
540
|
+
*
|
|
541
|
+
* @example
|
|
542
|
+
* ```typescript
|
|
543
|
+
* const session = await client.getSession();
|
|
544
|
+
* if (session) {
|
|
545
|
+
* console.log('Logged in as:', session.user?.email);
|
|
546
|
+
*
|
|
547
|
+
* // Use access token for API calls
|
|
548
|
+
* fetch('/api/data', {
|
|
549
|
+
* headers: { Authorization: `Bearer ${session.accessToken}` }
|
|
550
|
+
* });
|
|
551
|
+
* }
|
|
552
|
+
* ```
|
|
553
|
+
*/
|
|
554
|
+
async getSession() {
|
|
555
|
+
if (await this.tokenManager.isTokenExpired())
|
|
556
|
+
try {
|
|
557
|
+
await this.oauth.refreshToken();
|
|
558
|
+
} catch {
|
|
559
|
+
return null;
|
|
560
|
+
}
|
|
561
|
+
const t = await this.tokenManager.getTokens();
|
|
562
|
+
if (!t) return null;
|
|
563
|
+
const r = await this.fetchUser(t.accessToken);
|
|
564
|
+
return {
|
|
565
|
+
accessToken: t.accessToken,
|
|
566
|
+
refreshToken: t.refreshToken,
|
|
567
|
+
expiresIn: t.expiresIn,
|
|
568
|
+
expiresAt: t.issuedAt + t.expiresIn * 1e3,
|
|
569
|
+
user: r
|
|
570
|
+
};
|
|
571
|
+
}
|
|
572
|
+
/**
|
|
573
|
+
* Get licenses
|
|
574
|
+
* @param accessToken - The access token to use for the request
|
|
575
|
+
* @param options - The options for the request
|
|
576
|
+
* @param options.expiresAfter - Query licenses that are expired after the given date, default set to today to get all valid licenses (unexpired licenses)
|
|
577
|
+
* @returns The licenses
|
|
578
|
+
*/
|
|
579
|
+
async getLicenses(e = {}) {
|
|
580
|
+
const t = await this.getSession();
|
|
581
|
+
if (!t)
|
|
582
|
+
return null;
|
|
583
|
+
const r = t.accessToken, { expiresAfter: n = /* @__PURE__ */ new Date() } = e, a = await this.httpServer.request("/licenses", {
|
|
584
|
+
headers: { Authorization: `Bearer ${r}` },
|
|
585
|
+
params: { expiresAfter: n.toISOString() }
|
|
586
|
+
});
|
|
587
|
+
return a.ok ? a.data : (console.error("GenationClient: Error fetching licenses:", a.error), null);
|
|
588
|
+
}
|
|
589
|
+
/**
|
|
590
|
+
* Fetch user info from auth server
|
|
591
|
+
*/
|
|
592
|
+
async fetchUser(e) {
|
|
593
|
+
try {
|
|
594
|
+
const t = await this.http.request("/oauth/userinfo", {
|
|
595
|
+
headers: { Authorization: `Bearer ${e}` }
|
|
596
|
+
});
|
|
597
|
+
return {
|
|
598
|
+
sub: t.sub,
|
|
599
|
+
name: t.name,
|
|
600
|
+
picture: t.picture,
|
|
601
|
+
email: t.email,
|
|
602
|
+
email_verified: t.email_verified,
|
|
603
|
+
phone_number: t.phone_number,
|
|
604
|
+
phone_number_verified: t.phone_number_verified
|
|
605
|
+
};
|
|
606
|
+
} catch (t) {
|
|
607
|
+
return console.error("GenationClient: Error fetching user:", t), null;
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
function K(s) {
|
|
612
|
+
return new M(s);
|
|
613
|
+
}
|
|
614
|
+
export {
|
|
615
|
+
h as AuthError,
|
|
616
|
+
u as ConfigError,
|
|
617
|
+
M as GenationClient,
|
|
618
|
+
w as GenationError,
|
|
619
|
+
S as LocalStorage,
|
|
620
|
+
x as MemoryStorage,
|
|
621
|
+
c as NetworkError,
|
|
622
|
+
E as SessionStorage,
|
|
623
|
+
K as createClient,
|
|
624
|
+
A as createStorage
|
|
625
|
+
};
|
|
626
|
+
//# sourceMappingURL=genation.es.js.map
|