@zoneout/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/LICENSE +21 -0
- package/README.md +124 -0
- package/dist/cjs/client.d.ts +53 -0
- package/dist/cjs/client.d.ts.map +1 -0
- package/dist/cjs/client.js +141 -0
- package/dist/cjs/client.js.map +1 -0
- package/dist/cjs/errors.d.ts +7 -0
- package/dist/cjs/errors.d.ts.map +1 -0
- package/dist/cjs/errors.js +13 -0
- package/dist/cjs/errors.js.map +1 -0
- package/dist/cjs/index.d.ts +7 -0
- package/dist/cjs/index.d.ts.map +1 -0
- package/dist/cjs/index.js +19 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/pkce.d.ts +4 -0
- package/dist/cjs/pkce.d.ts.map +1 -0
- package/dist/cjs/pkce.js +30 -0
- package/dist/cjs/pkce.js.map +1 -0
- package/dist/cjs/polling.d.ts +15 -0
- package/dist/cjs/polling.d.ts.map +1 -0
- package/dist/cjs/polling.js +53 -0
- package/dist/cjs/polling.js.map +1 -0
- package/dist/cjs/react/index.d.ts +3 -0
- package/dist/cjs/react/index.d.ts.map +1 -0
- package/dist/cjs/react/index.js +9 -0
- package/dist/cjs/react/index.js.map +1 -0
- package/dist/cjs/react/provider.d.ts +11 -0
- package/dist/cjs/react/provider.d.ts.map +1 -0
- package/dist/cjs/react/provider.js +24 -0
- package/dist/cjs/react/provider.js.map +1 -0
- package/dist/cjs/react/use-zoneout.d.ts +25 -0
- package/dist/cjs/react/use-zoneout.d.ts.map +1 -0
- package/dist/cjs/react/use-zoneout.js +60 -0
- package/dist/cjs/react/use-zoneout.js.map +1 -0
- package/dist/cjs/server.d.ts +12 -0
- package/dist/cjs/server.d.ts.map +1 -0
- package/dist/cjs/server.js +58 -0
- package/dist/cjs/server.js.map +1 -0
- package/dist/cjs/types.d.ts +85 -0
- package/dist/cjs/types.d.ts.map +1 -0
- package/dist/cjs/types.js +4 -0
- package/dist/cjs/types.js.map +1 -0
- package/dist/esm/client.d.ts +53 -0
- package/dist/esm/client.d.ts.map +1 -0
- package/dist/esm/client.js +137 -0
- package/dist/esm/client.js.map +1 -0
- package/dist/esm/errors.d.ts +7 -0
- package/dist/esm/errors.d.ts.map +1 -0
- package/dist/esm/errors.js +9 -0
- package/dist/esm/errors.js.map +1 -0
- package/dist/esm/index.d.ts +7 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +9 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/pkce.d.ts +4 -0
- package/dist/esm/pkce.d.ts.map +1 -0
- package/dist/esm/pkce.js +25 -0
- package/dist/esm/pkce.js.map +1 -0
- package/dist/esm/polling.d.ts +15 -0
- package/dist/esm/polling.d.ts.map +1 -0
- package/dist/esm/polling.js +50 -0
- package/dist/esm/polling.js.map +1 -0
- package/dist/esm/react/index.d.ts +3 -0
- package/dist/esm/react/index.d.ts.map +1 -0
- package/dist/esm/react/index.js +3 -0
- package/dist/esm/react/index.js.map +1 -0
- package/dist/esm/react/provider.d.ts +11 -0
- package/dist/esm/react/provider.d.ts.map +1 -0
- package/dist/esm/react/provider.js +20 -0
- package/dist/esm/react/provider.js.map +1 -0
- package/dist/esm/react/use-zoneout.d.ts +25 -0
- package/dist/esm/react/use-zoneout.d.ts.map +1 -0
- package/dist/esm/react/use-zoneout.js +57 -0
- package/dist/esm/react/use-zoneout.js.map +1 -0
- package/dist/esm/server.d.ts +12 -0
- package/dist/esm/server.d.ts.map +1 -0
- package/dist/esm/server.js +54 -0
- package/dist/esm/server.js.map +1 -0
- package/dist/esm/types.d.ts +85 -0
- package/dist/esm/types.d.ts.map +1 -0
- package/dist/esm/types.js +3 -0
- package/dist/esm/types.js.map +1 -0
- package/dist/types/client.d.ts +53 -0
- package/dist/types/client.d.ts.map +1 -0
- package/dist/types/errors.d.ts +7 -0
- package/dist/types/errors.d.ts.map +1 -0
- package/dist/types/index.d.ts +7 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/pkce.d.ts +4 -0
- package/dist/types/pkce.d.ts.map +1 -0
- package/dist/types/polling.d.ts +15 -0
- package/dist/types/polling.d.ts.map +1 -0
- package/dist/types/react/index.d.ts +3 -0
- package/dist/types/react/index.d.ts.map +1 -0
- package/dist/types/react/provider.d.ts +11 -0
- package/dist/types/react/provider.d.ts.map +1 -0
- package/dist/types/react/use-zoneout.d.ts +25 -0
- package/dist/types/react/use-zoneout.d.ts.map +1 -0
- package/dist/types/server.d.ts +12 -0
- package/dist/types/server.d.ts.map +1 -0
- package/dist/types/types.d.ts +85 -0
- package/dist/types/types.d.ts.map +1 -0
- package/package.json +68 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 ZoneOut
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
# @zoneout/sdk
|
|
2
|
+
|
|
3
|
+
SDK for integrating "Login with ZoneOut ID" into web applications.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @zoneout/sdk
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
### Frontend (React)
|
|
14
|
+
|
|
15
|
+
```tsx
|
|
16
|
+
import { ZoneOutProvider, useZoneOut } from '@zoneout/sdk/react';
|
|
17
|
+
|
|
18
|
+
function App() {
|
|
19
|
+
return (
|
|
20
|
+
<ZoneOutProvider config={{
|
|
21
|
+
clientId: process.env.NEXT_PUBLIC_ZONEOUT_CLIENT_ID!,
|
|
22
|
+
authServerUrl: process.env.NEXT_PUBLIC_ZONEOUT_AUTH_URL!,
|
|
23
|
+
redirectUri: `${window.location.origin}/auth/callback`,
|
|
24
|
+
scope: ['identity', 'trust:game', 'trust:social'],
|
|
25
|
+
}}>
|
|
26
|
+
<LoginButton />
|
|
27
|
+
</ZoneOutProvider>
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function LoginButton() {
|
|
32
|
+
const { login, isLoading, error } = useZoneOut();
|
|
33
|
+
|
|
34
|
+
return (
|
|
35
|
+
<button onClick={login} disabled={isLoading}>
|
|
36
|
+
{isLoading ? 'Waiting for approval...' : 'Login with ZoneOut ID'}
|
|
37
|
+
</button>
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Backend (Next.js Route Handler)
|
|
43
|
+
|
|
44
|
+
```typescript
|
|
45
|
+
// app/auth/callback/route.ts
|
|
46
|
+
import { exchangeCodeForTokens } from '@zoneout/sdk/server';
|
|
47
|
+
|
|
48
|
+
export async function GET(request: Request) {
|
|
49
|
+
const url = new URL(request.url);
|
|
50
|
+
const code = url.searchParams.get('code')!;
|
|
51
|
+
const codeVerifier = /* retrieve from session/cookie */;
|
|
52
|
+
|
|
53
|
+
const { access_token, refresh_token, user } = await exchangeCodeForTokens({
|
|
54
|
+
code,
|
|
55
|
+
clientId: process.env.ZONEOUT_CLIENT_ID!,
|
|
56
|
+
clientSecret: process.env.ZONEOUT_CLIENT_SECRET!,
|
|
57
|
+
codeVerifier,
|
|
58
|
+
redirectUri: `${process.env.NEXT_PUBLIC_BASE_URL}/auth/callback`,
|
|
59
|
+
authServerUrl: process.env.ZONEOUT_AUTH_URL!,
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
// Create session, set cookies, redirect
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Architecture
|
|
67
|
+
|
|
68
|
+
The SDK has two parts:
|
|
69
|
+
|
|
70
|
+
1. **Client-side** (`@zoneout/sdk`): Handles login initiation, QR code generation, and polling
|
|
71
|
+
2. **Server-side** (`@zoneout/sdk/server`): Handles token exchange using `client_secret` (never exposed to frontend)
|
|
72
|
+
|
|
73
|
+
The `client_secret` is NEVER used in the browser. Token exchange always happens server-to-server.
|
|
74
|
+
|
|
75
|
+
## API
|
|
76
|
+
|
|
77
|
+
### `ZoneOutClient`
|
|
78
|
+
|
|
79
|
+
Main client class for frontend use.
|
|
80
|
+
|
|
81
|
+
```typescript
|
|
82
|
+
import { ZoneOutClient } from '@zoneout/sdk';
|
|
83
|
+
|
|
84
|
+
const client = new ZoneOutClient({
|
|
85
|
+
clientId: 'your-client-id',
|
|
86
|
+
authServerUrl: 'https://xxx.supabase.co/functions/v1',
|
|
87
|
+
redirectUri: 'https://yourapp.com/auth/callback',
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
// Full login flow (initiate + poll + redirect)
|
|
91
|
+
await client.login();
|
|
92
|
+
|
|
93
|
+
// Or step-by-step for custom UI
|
|
94
|
+
const { qrCodeUrl, waitForApproval, abort } = await client.initiateLogin();
|
|
95
|
+
// Show QR code with qrCodeUrl...
|
|
96
|
+
const result = await waitForApproval();
|
|
97
|
+
// Handle result...
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Server Helpers
|
|
101
|
+
|
|
102
|
+
```typescript
|
|
103
|
+
import { exchangeCodeForTokens, refreshAccessToken } from '@zoneout/sdk/server';
|
|
104
|
+
|
|
105
|
+
// Exchange authorization code for tokens
|
|
106
|
+
const tokens = await exchangeCodeForTokens({ code, clientId, clientSecret, codeVerifier, redirectUri, authServerUrl });
|
|
107
|
+
|
|
108
|
+
// Refresh access token
|
|
109
|
+
const newTokens = await refreshAccessToken({ refreshToken, clientId, clientSecret, authServerUrl });
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### React
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
import { ZoneOutProvider, useZoneOut } from '@zoneout/sdk/react';
|
|
116
|
+
|
|
117
|
+
// Wrap your app
|
|
118
|
+
<ZoneOutProvider config={...}>
|
|
119
|
+
<App />
|
|
120
|
+
</ZoneOutProvider>
|
|
121
|
+
|
|
122
|
+
// Use the hook
|
|
123
|
+
const { login, initiateLogin, isLoading, qrCodeUrl, error } = useZoneOut();
|
|
124
|
+
```
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { ZoneOutConfig, ZoneOutEvent, ZoneOutEventCallback } from './types';
|
|
2
|
+
import { type PollingResult } from './polling';
|
|
3
|
+
export interface LoginInitResult {
|
|
4
|
+
/** URL del QR code da mostrare all'utente: zoneout://approve?session={id} */
|
|
5
|
+
qrCodeUrl: string;
|
|
6
|
+
/** ID della sessione di login */
|
|
7
|
+
sessionId: string;
|
|
8
|
+
/** Scade a (ISO string) */
|
|
9
|
+
expiresAt: string;
|
|
10
|
+
/** AbortController per annullare il login */
|
|
11
|
+
abort: AbortController;
|
|
12
|
+
/**
|
|
13
|
+
* Promise che si risolve quando l'utente approva.
|
|
14
|
+
* Restituisce il risultato con authorization_code.
|
|
15
|
+
* Il consumer è responsabile del redirect.
|
|
16
|
+
*/
|
|
17
|
+
waitForApproval: () => Promise<PollingResult>;
|
|
18
|
+
}
|
|
19
|
+
export declare class ZoneOutClient {
|
|
20
|
+
private config;
|
|
21
|
+
private listeners;
|
|
22
|
+
private _codeVerifier;
|
|
23
|
+
private _state;
|
|
24
|
+
constructor(config: ZoneOutConfig);
|
|
25
|
+
/**
|
|
26
|
+
* Avvia il flusso di login.
|
|
27
|
+
* Restituisce l'URL del QR code e una promise per attendere l'approvazione.
|
|
28
|
+
*/
|
|
29
|
+
initiateLogin(): Promise<LoginInitResult>;
|
|
30
|
+
/**
|
|
31
|
+
* Restituisce il code_verifier generato nell'ultimo initiateLogin.
|
|
32
|
+
* Serve al backend per il token exchange.
|
|
33
|
+
* ATTENZIONE: NON inviare mai il code_verifier a terzi. Va solo al TUO backend.
|
|
34
|
+
*/
|
|
35
|
+
getCodeVerifier(): string | null;
|
|
36
|
+
/**
|
|
37
|
+
* Restituisce lo state generato nell'ultimo initiateLogin.
|
|
38
|
+
*/
|
|
39
|
+
getState(): string | null;
|
|
40
|
+
/**
|
|
41
|
+
* Genera l'URL di redirect al backend del consumer con i parametri necessari.
|
|
42
|
+
*/
|
|
43
|
+
buildCallbackUrl(authorizationCode: string): string;
|
|
44
|
+
/**
|
|
45
|
+
* Flusso completo: initiate -> poll -> redirect.
|
|
46
|
+
*/
|
|
47
|
+
login(): Promise<void>;
|
|
48
|
+
on(event: ZoneOutEvent, callback: ZoneOutEventCallback): void;
|
|
49
|
+
off(event: ZoneOutEvent, callback: ZoneOutEventCallback): void;
|
|
50
|
+
private emit;
|
|
51
|
+
private mapServerError;
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,aAAa,EAEb,YAAY,EACZ,oBAAoB,EAErB,MAAM,SAAS,CAAC;AAGjB,OAAO,EAAmB,KAAK,aAAa,EAAE,MAAM,WAAW,CAAC;AAEhE,MAAM,WAAW,eAAe;IAC9B,6EAA6E;IAC7E,SAAS,EAAE,MAAM,CAAC;IAClB,iCAAiC;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,2BAA2B;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,6CAA6C;IAC7C,KAAK,EAAE,eAAe,CAAC;IACvB;;;;OAIG;IACH,eAAe,EAAE,MAAM,OAAO,CAAC,aAAa,CAAC,CAAC;CAC/C;AAED,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAA0B;IACxC,OAAO,CAAC,SAAS,CAA2D;IAC5E,OAAO,CAAC,aAAa,CAAuB;IAC5C,OAAO,CAAC,MAAM,CAAuB;gBAEzB,MAAM,EAAE,aAAa;IAUjC;;;OAGG;IACG,aAAa,IAAI,OAAO,CAAC,eAAe,CAAC;IAgE/C;;;;OAIG;IACH,eAAe,IAAI,MAAM,GAAG,IAAI;IAIhC;;OAEG;IACH,QAAQ,IAAI,MAAM,GAAG,IAAI;IAIzB;;OAEG;IACH,gBAAgB,CAAC,iBAAiB,EAAE,MAAM,GAAG,MAAM;IAOnD;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAW5B,EAAE,CAAC,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,oBAAoB,GAAG,IAAI;IAO7D,GAAG,CAAC,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,oBAAoB,GAAG,IAAI;IAI9D,OAAO,CAAC,IAAI;IAIZ,OAAO,CAAC,cAAc;CAQvB"}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ZoneOutClient = void 0;
|
|
4
|
+
const errors_1 = require("./errors");
|
|
5
|
+
const pkce_1 = require("./pkce");
|
|
6
|
+
const polling_1 = require("./polling");
|
|
7
|
+
class ZoneOutClient {
|
|
8
|
+
constructor(config) {
|
|
9
|
+
this.listeners = new Map();
|
|
10
|
+
this._codeVerifier = null;
|
|
11
|
+
this._state = null;
|
|
12
|
+
this.config = {
|
|
13
|
+
...config,
|
|
14
|
+
apiKey: config.apiKey ?? '',
|
|
15
|
+
scope: config.scope ?? ['identity'],
|
|
16
|
+
pollingTimeout: config.pollingTimeout ?? 300000,
|
|
17
|
+
pollingInterval: config.pollingInterval ?? 2000,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Avvia il flusso di login.
|
|
22
|
+
* Restituisce l'URL del QR code e una promise per attendere l'approvazione.
|
|
23
|
+
*/
|
|
24
|
+
async initiateLogin() {
|
|
25
|
+
const codeVerifier = (0, pkce_1.generateCodeVerifier)();
|
|
26
|
+
const codeChallenge = await (0, pkce_1.generateCodeChallenge)(codeVerifier);
|
|
27
|
+
const state = (0, pkce_1.generateState)();
|
|
28
|
+
this._codeVerifier = codeVerifier;
|
|
29
|
+
this._state = state;
|
|
30
|
+
this.emit('login_start');
|
|
31
|
+
const res = await fetch(`${this.config.authServerUrl}/auth-login-initiate`, {
|
|
32
|
+
method: 'POST',
|
|
33
|
+
headers: {
|
|
34
|
+
'Content-Type': 'application/json',
|
|
35
|
+
...(this.config.apiKey ? { apikey: this.config.apiKey, Authorization: `Bearer ${this.config.apiKey}` } : {}),
|
|
36
|
+
},
|
|
37
|
+
body: JSON.stringify({
|
|
38
|
+
client_id: this.config.clientId,
|
|
39
|
+
code_challenge: codeChallenge,
|
|
40
|
+
code_challenge_method: 'S256',
|
|
41
|
+
redirect_uri: this.config.redirectUri,
|
|
42
|
+
state,
|
|
43
|
+
scope: this.config.scope.join(' '),
|
|
44
|
+
}),
|
|
45
|
+
});
|
|
46
|
+
if (!res.ok) {
|
|
47
|
+
const body = await res.json().catch(() => ({}));
|
|
48
|
+
const code = this.mapServerError(body);
|
|
49
|
+
throw new errors_1.ZoneOutError(code, body.error || `Initiate failed: HTTP ${res.status}`, body);
|
|
50
|
+
}
|
|
51
|
+
const session = await res.json();
|
|
52
|
+
const abortController = new AbortController();
|
|
53
|
+
const qrCodeUrl = `zoneout://approve/${session.login_session_id}`;
|
|
54
|
+
const waitForApproval = async () => {
|
|
55
|
+
const result = await (0, polling_1.pollForApproval)({
|
|
56
|
+
sessionId: session.login_session_id,
|
|
57
|
+
authServerUrl: this.config.authServerUrl,
|
|
58
|
+
apiKey: this.config.apiKey,
|
|
59
|
+
interval: this.config.pollingInterval,
|
|
60
|
+
timeout: this.config.pollingTimeout,
|
|
61
|
+
signal: abortController.signal,
|
|
62
|
+
onStatusChange: (status) => {
|
|
63
|
+
if (status === 'approved')
|
|
64
|
+
this.emit('login_approved');
|
|
65
|
+
if (status === 'rejected')
|
|
66
|
+
this.emit('login_rejected');
|
|
67
|
+
if (status === 'expired')
|
|
68
|
+
this.emit('login_expired');
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
return result;
|
|
72
|
+
};
|
|
73
|
+
return {
|
|
74
|
+
qrCodeUrl,
|
|
75
|
+
sessionId: session.login_session_id,
|
|
76
|
+
expiresAt: session.expires_at,
|
|
77
|
+
abort: abortController,
|
|
78
|
+
waitForApproval,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Restituisce il code_verifier generato nell'ultimo initiateLogin.
|
|
83
|
+
* Serve al backend per il token exchange.
|
|
84
|
+
* ATTENZIONE: NON inviare mai il code_verifier a terzi. Va solo al TUO backend.
|
|
85
|
+
*/
|
|
86
|
+
getCodeVerifier() {
|
|
87
|
+
return this._codeVerifier;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Restituisce lo state generato nell'ultimo initiateLogin.
|
|
91
|
+
*/
|
|
92
|
+
getState() {
|
|
93
|
+
return this._state;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Genera l'URL di redirect al backend del consumer con i parametri necessari.
|
|
97
|
+
*/
|
|
98
|
+
buildCallbackUrl(authorizationCode) {
|
|
99
|
+
const url = new URL(this.config.redirectUri);
|
|
100
|
+
url.searchParams.set('code', authorizationCode);
|
|
101
|
+
url.searchParams.set('state', this._state ?? '');
|
|
102
|
+
return url.toString();
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Flusso completo: initiate -> poll -> redirect.
|
|
106
|
+
*/
|
|
107
|
+
async login() {
|
|
108
|
+
const { waitForApproval } = await this.initiateLogin();
|
|
109
|
+
const result = await waitForApproval();
|
|
110
|
+
if (result.authorization_code) {
|
|
111
|
+
window.location.href = this.buildCallbackUrl(result.authorization_code);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
// --- Event system ---
|
|
115
|
+
on(event, callback) {
|
|
116
|
+
if (!this.listeners.has(event)) {
|
|
117
|
+
this.listeners.set(event, new Set());
|
|
118
|
+
}
|
|
119
|
+
this.listeners.get(event).add(callback);
|
|
120
|
+
}
|
|
121
|
+
off(event, callback) {
|
|
122
|
+
this.listeners.get(event)?.delete(callback);
|
|
123
|
+
}
|
|
124
|
+
emit(event, data) {
|
|
125
|
+
this.listeners.get(event)?.forEach(cb => cb(event, data));
|
|
126
|
+
}
|
|
127
|
+
mapServerError(body) {
|
|
128
|
+
const error = String(body.error || '');
|
|
129
|
+
if (error.includes('client') || error.includes('client_id'))
|
|
130
|
+
return 'INVALID_CLIENT';
|
|
131
|
+
if (error.includes('redirect'))
|
|
132
|
+
return 'INVALID_REDIRECT';
|
|
133
|
+
if (error.includes('rate') || error.includes('limit'))
|
|
134
|
+
return 'RATE_LIMITED';
|
|
135
|
+
if (error.includes('provider'))
|
|
136
|
+
return 'PROVIDER_MISSING';
|
|
137
|
+
return 'UNKNOWN_ERROR';
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
exports.ZoneOutClient = ZoneOutClient;
|
|
141
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ZoneOutErrorCode } from './types';
|
|
2
|
+
export declare class ZoneOutError extends Error {
|
|
3
|
+
readonly code: ZoneOutErrorCode;
|
|
4
|
+
readonly detail?: Record<string, unknown>;
|
|
5
|
+
constructor(code: ZoneOutErrorCode, message: string, detail?: Record<string, unknown>);
|
|
6
|
+
}
|
|
7
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAEhD,qBAAa,YAAa,SAAQ,KAAK;IACrC,SAAgB,IAAI,EAAE,gBAAgB,CAAC;IACvC,SAAgB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;gBAErC,IAAI,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CAMtF"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ZoneOutError = void 0;
|
|
4
|
+
class ZoneOutError extends Error {
|
|
5
|
+
constructor(code, message, detail) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.name = 'ZoneOutError';
|
|
8
|
+
this.code = code;
|
|
9
|
+
this.detail = detail;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
exports.ZoneOutError = ZoneOutError;
|
|
13
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/errors.ts"],"names":[],"mappings":";;;AAEA,MAAa,YAAa,SAAQ,KAAK;IAIrC,YAAY,IAAsB,EAAE,OAAe,EAAE,MAAgC;QACnF,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,cAAc,CAAC;QAC3B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;CACF;AAVD,oCAUC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { ZoneOutClient } from './client';
|
|
2
|
+
export type { LoginInitResult } from './client';
|
|
3
|
+
export { exchangeCodeForTokens, refreshAccessToken } from './server';
|
|
4
|
+
export type { ZoneOutConfig, ZoneOutUser, ZoneOutTokens, ZoneOutLoginResult, LoginSession, LoginSessionStatus, LoginSessionDetail, LoginSessionResponse, TokenExchangeParams, TokenRefreshParams, TokenResponse, ZoneOutEvent, ZoneOutEventCallback, ZoneOutErrorCode, } from './types';
|
|
5
|
+
export { ZoneOutError } from './errors';
|
|
6
|
+
export { generateCodeVerifier, generateCodeChallenge, generateState } from './pkce';
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,YAAY,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAGhD,OAAO,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAGrE,YAAY,EACV,aAAa,EACb,WAAW,EACX,aAAa,EACb,kBAAkB,EAClB,YAAY,EACZ,kBAAkB,EAClB,kBAAkB,EAClB,oBAAoB,EACpB,mBAAmB,EACnB,kBAAkB,EAClB,aAAa,EACb,YAAY,EACZ,oBAAoB,EACpB,gBAAgB,GACjB,MAAM,SAAS,CAAC;AAGjB,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAGxC,OAAO,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateState = exports.generateCodeChallenge = exports.generateCodeVerifier = exports.ZoneOutError = exports.refreshAccessToken = exports.exchangeCodeForTokens = exports.ZoneOutClient = void 0;
|
|
4
|
+
// Client (frontend)
|
|
5
|
+
var client_1 = require("./client");
|
|
6
|
+
Object.defineProperty(exports, "ZoneOutClient", { enumerable: true, get: function () { return client_1.ZoneOutClient; } });
|
|
7
|
+
// Server helpers
|
|
8
|
+
var server_1 = require("./server");
|
|
9
|
+
Object.defineProperty(exports, "exchangeCodeForTokens", { enumerable: true, get: function () { return server_1.exchangeCodeForTokens; } });
|
|
10
|
+
Object.defineProperty(exports, "refreshAccessToken", { enumerable: true, get: function () { return server_1.refreshAccessToken; } });
|
|
11
|
+
// Errors
|
|
12
|
+
var errors_1 = require("./errors");
|
|
13
|
+
Object.defineProperty(exports, "ZoneOutError", { enumerable: true, get: function () { return errors_1.ZoneOutError; } });
|
|
14
|
+
// PKCE utils (exported for advanced use cases)
|
|
15
|
+
var pkce_1 = require("./pkce");
|
|
16
|
+
Object.defineProperty(exports, "generateCodeVerifier", { enumerable: true, get: function () { return pkce_1.generateCodeVerifier; } });
|
|
17
|
+
Object.defineProperty(exports, "generateCodeChallenge", { enumerable: true, get: function () { return pkce_1.generateCodeChallenge; } });
|
|
18
|
+
Object.defineProperty(exports, "generateState", { enumerable: true, get: function () { return pkce_1.generateState; } });
|
|
19
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;AAAA,oBAAoB;AACpB,mCAAyC;AAAhC,uGAAA,aAAa,OAAA;AAGtB,iBAAiB;AACjB,mCAAqE;AAA5D,+GAAA,qBAAqB,OAAA;AAAE,4GAAA,kBAAkB,OAAA;AAoBlD,SAAS;AACT,mCAAwC;AAA/B,sGAAA,YAAY,OAAA;AAErB,+CAA+C;AAC/C,+BAAoF;AAA3E,4GAAA,oBAAoB,OAAA;AAAE,6GAAA,qBAAqB,OAAA;AAAE,qGAAA,aAAa,OAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pkce.d.ts","sourceRoot":"","sources":["../../src/pkce.ts"],"names":[],"mappings":"AASA,wBAAgB,oBAAoB,IAAI,MAAM,CAI7C;AAED,wBAAsB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAK7E;AAED,wBAAgB,aAAa,IAAI,MAAM,CAItC"}
|
package/dist/cjs/pkce.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateCodeVerifier = generateCodeVerifier;
|
|
4
|
+
exports.generateCodeChallenge = generateCodeChallenge;
|
|
5
|
+
exports.generateState = generateState;
|
|
6
|
+
function base64UrlEncode(buffer) {
|
|
7
|
+
const bytes = new Uint8Array(buffer);
|
|
8
|
+
let binary = '';
|
|
9
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
10
|
+
binary += String.fromCharCode(bytes[i]);
|
|
11
|
+
}
|
|
12
|
+
return btoa(binary).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
|
|
13
|
+
}
|
|
14
|
+
function generateCodeVerifier() {
|
|
15
|
+
const array = new Uint8Array(48);
|
|
16
|
+
crypto.getRandomValues(array);
|
|
17
|
+
return base64UrlEncode(array.buffer);
|
|
18
|
+
}
|
|
19
|
+
async function generateCodeChallenge(verifier) {
|
|
20
|
+
const encoder = new TextEncoder();
|
|
21
|
+
const data = encoder.encode(verifier);
|
|
22
|
+
const hash = await crypto.subtle.digest('SHA-256', data);
|
|
23
|
+
return base64UrlEncode(hash);
|
|
24
|
+
}
|
|
25
|
+
function generateState() {
|
|
26
|
+
const array = new Uint8Array(32);
|
|
27
|
+
crypto.getRandomValues(array);
|
|
28
|
+
return base64UrlEncode(array.buffer);
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=pkce.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pkce.js","sourceRoot":"","sources":["../../src/pkce.ts"],"names":[],"mappings":";;AASA,oDAIC;AAED,sDAKC;AAED,sCAIC;AA1BD,SAAS,eAAe,CAAC,MAAmB;IAC1C,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC;IACrC,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,MAAM,IAAI,MAAM,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1C,CAAC;IACD,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;AACjF,CAAC;AAED,SAAgB,oBAAoB;IAClC,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,EAAE,CAAC,CAAC;IACjC,MAAM,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;IAC9B,OAAO,eAAe,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;AACvC,CAAC;AAEM,KAAK,UAAU,qBAAqB,CAAC,QAAgB;IAC1D,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;IAClC,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IACtC,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;IACzD,OAAO,eAAe,CAAC,IAAI,CAAC,CAAC;AAC/B,CAAC;AAED,SAAgB,aAAa;IAC3B,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,EAAE,CAAC,CAAC;IACjC,MAAM,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;IAC9B,OAAO,eAAe,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;AACvC,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface PollingOptions {
|
|
2
|
+
sessionId: string;
|
|
3
|
+
authServerUrl: string;
|
|
4
|
+
apiKey?: string;
|
|
5
|
+
interval: number;
|
|
6
|
+
timeout: number;
|
|
7
|
+
onStatusChange?: (status: string) => void;
|
|
8
|
+
signal?: AbortSignal;
|
|
9
|
+
}
|
|
10
|
+
export interface PollingResult {
|
|
11
|
+
status: string;
|
|
12
|
+
authorization_code?: string;
|
|
13
|
+
}
|
|
14
|
+
export declare function pollForApproval(options: PollingOptions): Promise<PollingResult>;
|
|
15
|
+
//# sourceMappingURL=polling.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"polling.d.ts","sourceRoot":"","sources":["../../src/polling.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1C,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,wBAAsB,eAAe,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC,CAwDrF"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.pollForApproval = pollForApproval;
|
|
4
|
+
const errors_1 = require("./errors");
|
|
5
|
+
async function pollForApproval(options) {
|
|
6
|
+
const { sessionId, authServerUrl, apiKey, interval, timeout, onStatusChange, signal } = options;
|
|
7
|
+
const startTime = Date.now();
|
|
8
|
+
while (true) {
|
|
9
|
+
if (signal?.aborted) {
|
|
10
|
+
throw new errors_1.ZoneOutError('USER_REJECTED', 'Login cancelled by user');
|
|
11
|
+
}
|
|
12
|
+
if (Date.now() - startTime > timeout) {
|
|
13
|
+
throw new errors_1.ZoneOutError('POLLING_TIMEOUT', 'Login session timed out');
|
|
14
|
+
}
|
|
15
|
+
try {
|
|
16
|
+
const url = `${authServerUrl}/auth-login-session?session_id=${encodeURIComponent(sessionId)}`;
|
|
17
|
+
const res = await fetch(url, {
|
|
18
|
+
headers: {
|
|
19
|
+
...(apiKey ? { apikey: apiKey, Authorization: `Bearer ${apiKey}` } : {}),
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
if (res.status === 429) {
|
|
23
|
+
throw new errors_1.ZoneOutError('RATE_LIMITED', 'Too many requests, slow down');
|
|
24
|
+
}
|
|
25
|
+
if (!res.ok) {
|
|
26
|
+
const body = await res.json().catch(() => ({}));
|
|
27
|
+
throw new errors_1.ZoneOutError('UNKNOWN_ERROR', body.error || `HTTP ${res.status}`);
|
|
28
|
+
}
|
|
29
|
+
const data = await res.json();
|
|
30
|
+
const status = data.session.status;
|
|
31
|
+
if (status === 'approved' && data.authorization_code) {
|
|
32
|
+
onStatusChange?.('approved');
|
|
33
|
+
return { status: 'approved', authorization_code: data.authorization_code };
|
|
34
|
+
}
|
|
35
|
+
if (status === 'rejected') {
|
|
36
|
+
onStatusChange?.('rejected');
|
|
37
|
+
throw new errors_1.ZoneOutError('USER_REJECTED', 'User rejected the login request');
|
|
38
|
+
}
|
|
39
|
+
if (status === 'expired') {
|
|
40
|
+
onStatusChange?.('expired');
|
|
41
|
+
throw new errors_1.ZoneOutError('SESSION_EXPIRED', 'Login session has expired');
|
|
42
|
+
}
|
|
43
|
+
onStatusChange?.('pending_approval');
|
|
44
|
+
}
|
|
45
|
+
catch (err) {
|
|
46
|
+
if (err instanceof errors_1.ZoneOutError)
|
|
47
|
+
throw err;
|
|
48
|
+
console.warn('[ZoneOut SDK] Polling error, retrying:', err);
|
|
49
|
+
}
|
|
50
|
+
await new Promise(resolve => setTimeout(resolve, interval));
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=polling.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"polling.js","sourceRoot":"","sources":["../../src/polling.ts"],"names":[],"mappings":";;AAkBA,0CAwDC;AAzED,qCAAwC;AAiBjC,KAAK,UAAU,eAAe,CAAC,OAAuB;IAC3D,MAAM,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;IAChG,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAE7B,OAAO,IAAI,EAAE,CAAC;QACZ,IAAI,MAAM,EAAE,OAAO,EAAE,CAAC;YACpB,MAAM,IAAI,qBAAY,CAAC,eAAe,EAAE,yBAAyB,CAAC,CAAC;QACrE,CAAC;QAED,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,GAAG,OAAO,EAAE,CAAC;YACrC,MAAM,IAAI,qBAAY,CAAC,iBAAiB,EAAE,yBAAyB,CAAC,CAAC;QACvE,CAAC;QAED,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,GAAG,aAAa,kCAAkC,kBAAkB,CAAC,SAAS,CAAC,EAAE,CAAC;YAC9F,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;gBAC3B,OAAO,EAAE;oBACP,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,UAAU,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;iBACzE;aACF,CAAC,CAAC;YAEH,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;gBACvB,MAAM,IAAI,qBAAY,CAAC,cAAc,EAAE,8BAA8B,CAAC,CAAC;YACzE,CAAC;YAED,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;gBACZ,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;gBAChD,MAAM,IAAI,qBAAY,CAAC,eAAe,EAAE,IAAI,CAAC,KAAK,IAAI,QAAQ,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;YAC9E,CAAC;YAED,MAAM,IAAI,GAAyB,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;YACpD,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC;YAEnC,IAAI,MAAM,KAAK,UAAU,IAAI,IAAI,CAAC,kBAAkB,EAAE,CAAC;gBACrD,cAAc,EAAE,CAAC,UAAU,CAAC,CAAC;gBAC7B,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,kBAAkB,EAAE,IAAI,CAAC,kBAAkB,EAAE,CAAC;YAC7E,CAAC;YAED,IAAI,MAAM,KAAK,UAAU,EAAE,CAAC;gBAC1B,cAAc,EAAE,CAAC,UAAU,CAAC,CAAC;gBAC7B,MAAM,IAAI,qBAAY,CAAC,eAAe,EAAE,iCAAiC,CAAC,CAAC;YAC7E,CAAC;YAED,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;gBACzB,cAAc,EAAE,CAAC,SAAS,CAAC,CAAC;gBAC5B,MAAM,IAAI,qBAAY,CAAC,iBAAiB,EAAE,2BAA2B,CAAC,CAAC;YACzE,CAAC;YAED,cAAc,EAAE,CAAC,kBAAkB,CAAC,CAAC;QACvC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,GAAG,YAAY,qBAAY;gBAAE,MAAM,GAAG,CAAC;YAC3C,OAAO,CAAC,IAAI,CAAC,wCAAwC,EAAE,GAAG,CAAC,CAAC;QAC9D,CAAC;QAED,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC;IAC9D,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/react/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAC/D,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useZoneOut = exports.useZoneOutClient = exports.ZoneOutProvider = void 0;
|
|
4
|
+
var provider_1 = require("./provider");
|
|
5
|
+
Object.defineProperty(exports, "ZoneOutProvider", { enumerable: true, get: function () { return provider_1.ZoneOutProvider; } });
|
|
6
|
+
Object.defineProperty(exports, "useZoneOutClient", { enumerable: true, get: function () { return provider_1.useZoneOutClient; } });
|
|
7
|
+
var use_zoneout_1 = require("./use-zoneout");
|
|
8
|
+
Object.defineProperty(exports, "useZoneOut", { enumerable: true, get: function () { return use_zoneout_1.useZoneOut; } });
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/react/index.ts"],"names":[],"mappings":";;;AAAA,uCAA+D;AAAtD,2GAAA,eAAe,OAAA;AAAE,4GAAA,gBAAgB,OAAA;AAC1C,6CAA2C;AAAlC,yGAAA,UAAU,OAAA"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { ZoneOutClient } from '../client';
|
|
3
|
+
import type { ZoneOutConfig } from '../types';
|
|
4
|
+
export declare function useZoneOutClient(): ZoneOutClient;
|
|
5
|
+
interface ZoneOutProviderProps {
|
|
6
|
+
config: ZoneOutConfig;
|
|
7
|
+
children: React.ReactNode;
|
|
8
|
+
}
|
|
9
|
+
export declare function ZoneOutProvider({ config, children }: ZoneOutProviderProps): import("react/jsx-runtime").JSX.Element;
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../../src/react/provider.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA6C,MAAM,OAAO,CAAC;AAClE,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAQ9C,wBAAgB,gBAAgB,IAAI,aAAa,CAMhD;AAED,UAAU,oBAAoB;IAC5B,MAAM,EAAE,aAAa,CAAC;IACtB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B;AAED,wBAAgB,eAAe,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,oBAAoB,2CAYzE"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useZoneOutClient = useZoneOutClient;
|
|
4
|
+
exports.ZoneOutProvider = ZoneOutProvider;
|
|
5
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
6
|
+
const react_1 = require("react");
|
|
7
|
+
const client_1 = require("../client");
|
|
8
|
+
const ZoneOutContext = (0, react_1.createContext)(null);
|
|
9
|
+
function useZoneOutClient() {
|
|
10
|
+
const ctx = (0, react_1.useContext)(ZoneOutContext);
|
|
11
|
+
if (!ctx) {
|
|
12
|
+
throw new Error('useZoneOutClient must be used within <ZoneOutProvider>');
|
|
13
|
+
}
|
|
14
|
+
return ctx.client;
|
|
15
|
+
}
|
|
16
|
+
function ZoneOutProvider({ config, children }) {
|
|
17
|
+
const client = (0, react_1.useMemo)(() => new client_1.ZoneOutClient(config), [
|
|
18
|
+
config.clientId,
|
|
19
|
+
config.authServerUrl,
|
|
20
|
+
config.redirectUri,
|
|
21
|
+
]);
|
|
22
|
+
return ((0, jsx_runtime_1.jsx)(ZoneOutContext.Provider, { value: { client }, children: children }));
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.js","sourceRoot":"","sources":["../../../src/react/provider.tsx"],"names":[],"mappings":";;AAUA,4CAMC;AAOD,0CAYC;;AAnCD,iCAAkE;AAClE,sCAA0C;AAO1C,MAAM,cAAc,GAAG,IAAA,qBAAa,EAA6B,IAAI,CAAC,CAAC;AAEvE,SAAgB,gBAAgB;IAC9B,MAAM,GAAG,GAAG,IAAA,kBAAU,EAAC,cAAc,CAAC,CAAC;IACvC,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,MAAM,IAAI,KAAK,CAAC,wDAAwD,CAAC,CAAC;IAC5E,CAAC;IACD,OAAO,GAAG,CAAC,MAAM,CAAC;AACpB,CAAC;AAOD,SAAgB,eAAe,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAwB;IACxE,MAAM,MAAM,GAAG,IAAA,eAAO,EAAC,GAAG,EAAE,CAAC,IAAI,sBAAa,CAAC,MAAM,CAAC,EAAE;QACtD,MAAM,CAAC,QAAQ;QACf,MAAM,CAAC,aAAa;QACpB,MAAM,CAAC,WAAW;KACnB,CAAC,CAAC;IAEH,OAAO,CACL,uBAAC,cAAc,CAAC,QAAQ,IAAC,KAAK,EAAE,EAAE,MAAM,EAAE,YACvC,QAAQ,GACe,CAC3B,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { ZoneOutErrorCode } from '../types';
|
|
2
|
+
interface UseZoneOutReturn {
|
|
3
|
+
/** Avvia il login. Restituisce l'URL del QR code. */
|
|
4
|
+
initiateLogin: () => Promise<{
|
|
5
|
+
qrCodeUrl: string;
|
|
6
|
+
sessionId: string;
|
|
7
|
+
expiresAt: string;
|
|
8
|
+
waitForApproval: () => Promise<void>;
|
|
9
|
+
abort: AbortController;
|
|
10
|
+
}>;
|
|
11
|
+
/** Flusso completo login -> redirect */
|
|
12
|
+
login: () => Promise<void>;
|
|
13
|
+
/** Loading state */
|
|
14
|
+
isLoading: boolean;
|
|
15
|
+
/** URL del QR code (disponibile dopo initiateLogin) */
|
|
16
|
+
qrCodeUrl: string | null;
|
|
17
|
+
/** Errore ultimo tentativo */
|
|
18
|
+
error: {
|
|
19
|
+
code: ZoneOutErrorCode;
|
|
20
|
+
message: string;
|
|
21
|
+
} | null;
|
|
22
|
+
}
|
|
23
|
+
export declare function useZoneOut(): UseZoneOutReturn;
|
|
24
|
+
export {};
|
|
25
|
+
//# sourceMappingURL=use-zoneout.d.ts.map
|