@atpassport/client 0.1.7 → 0.1.9
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 +8 -9
- package/dist/chunk-HQWY5EUQ.mjs +1 -0
- package/dist/chunk-LGB4WCG6.mjs +1 -0
- package/dist/core.d.mts +46 -0
- package/dist/core.d.ts +46 -0
- package/dist/core.js +1 -0
- package/dist/core.mjs +1 -0
- package/dist/index.d.mts +4 -73
- package/dist/index.d.ts +4 -73
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/dist/ui.d.mts +31 -0
- package/dist/ui.d.ts +31 -0
- package/dist/ui.js +1 -0
- package/dist/ui.mjs +1 -0
- package/package.json +29 -9
- package/dist/__tests__/client.test.d.ts +0 -1
- package/dist/__tests__/client.test.js +0 -61
package/README.md
CHANGED
|
@@ -68,9 +68,14 @@ console.log(AtPassportUI.en.description); // "@passport is a universal handle ma
|
|
|
68
68
|
// Japanese translations
|
|
69
69
|
console.log(AtPassportUI.ja.title); // "@passportでログイン"
|
|
70
70
|
|
|
71
|
-
// Standard Icon (SVG String
|
|
72
|
-
// Can be injected into HTML directly or using React's dangerouslySetInnerHTML
|
|
71
|
+
// Standard Icon (SVG String)
|
|
73
72
|
const svgString = AtPassportUI.iconSvg;
|
|
73
|
+
|
|
74
|
+
// React Component
|
|
75
|
+
import { AtPassportIcon } from '@atpassport/client';
|
|
76
|
+
|
|
77
|
+
// Use it in your React component
|
|
78
|
+
// <AtPassportIcon size={24} />
|
|
74
79
|
```
|
|
75
80
|
|
|
76
81
|
---
|
|
@@ -85,10 +90,4 @@ When @passport redirects back to your `callbackUrl`, the following information w
|
|
|
85
90
|
- **`pdsurl`**: The endpoint URL of the user's Personal Data Server (PDS).
|
|
86
91
|
- **`atpstate`**: The state string automatically generated for CSRF protection via `generateAuthUrl()`.
|
|
87
92
|
|
|
88
|
-
|
|
89
|
-
Depending on the specific API endpoint used for integration or the exact implementation of the integrating client, there is a feature where placing `{handle}` or `{did}` string placeholders inside the `callbackUrl` string will instruct @passport to **dynamically string-replace** them with the actual handle/DID upon completion.
|
|
90
|
-
|
|
91
|
-
**Example:**
|
|
92
|
-
If the `callbackUrl` was `https://myapp.com/login?handle={handle}`, @passport would redirect back to `https://myapp.com/login?handle=alice.bsky.social`.
|
|
93
|
-
|
|
94
|
-
*Note: With the standard flow using `@atpassport/client` (`generateAuthUrl` → `parseCallback`), @passport does not rely on string replacement. Instead, it securely appends parameters like `&handle=...` as standardized URL queries. This allows you to simply and securely receive all information using `parseCallback()` without manually formatting placeholders.*
|
|
93
|
+
*Note: With the standard flow using `@atpassport/client` (`generateAuthUrl` → `parseCallback`), @passport securely appends parameters like `&handle=...` as standardized URL queries. This allows you to simply and securely receive all information using `parseCallback()` without manually formatting placeholders.*
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var d=class{baseUrl;callbackUrl;lang;constructor(t){this.baseUrl=(t.baseUrl||"https://atpassport.net").replace(/\/$/,""),this.callbackUrl=t.callbackUrl,this.lang=t.lang}generateAuthUrl(t){let a=crypto.randomUUID(),e=this.lang?`${this.lang}/authentication`:"authentication",s=new URL(`${this.baseUrl}/${e}`),r=new URL(this.callbackUrl);if(t)for(let[i,n]of Object.entries(t))r.searchParams.set(i,n);return s.searchParams.set("callback",r.toString()),s.searchParams.set("atpstate",a),{url:s.toString(),atpstate:a}}parseCallback(t,a){let e=new URL(t),s=e.searchParams.get("handle"),r=e.searchParams.get("did"),i=e.searchParams.get("pdsurl"),n=e.searchParams.get("atpstate");if(a&&n!==a)throw new Error("Invalid atpstate: CSRF validation failed.");let l={};return e.searchParams.forEach((c,o)=>{["handle","did","pdsurl","atpstate"].includes(o)||(l[o]=c)}),{handle:s,did:r,pdsUrl:i,atpstate:n,customParams:l}}async pick(){return new Promise(t=>{let s=window.screenX+(window.outerWidth-400)/2,r=window.screenY+(window.outerHeight-500)/2,i=this.lang?`${this.lang}/picker`:"picker",n=`${this.baseUrl}/${i}`,l=window.open(n,"atpassport:picker",`width=400,height=500,left=${s},top=${r}`),c=h=>{h.origin===new URL(this.baseUrl).origin&&h.data?.type==="atpassport:pick"&&(window.removeEventListener("message",c),t(h.data.handle))};window.addEventListener("message",c);let o=setInterval(()=>{l?.closed&&clearInterval(o)},1e3)})}decorate(t){t.addEventListener("focus",async()=>{if(t.value)return;let a=await this.pick();a&&(t.value=a,t.dispatchEvent(new Event("input",{bubbles:!0})),t.dispatchEvent(new Event("change",{bubbles:!0})))})}};export{d as a};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{jsx as r,jsxs as a}from"react/jsx-runtime";var o="M0 0 C1 0.5 2 1 3 1.5 C9.5 4.7 15.9 8.1 22.1 11.8 C25.2 13.2 27.3 13.3 30.7 12.9 C33.3 11.9 33.3 11.9 35.8 10.5 C44.4 5.8 54.9 5.7 64.5 7.5 C67.3 8.4 69.5 9.8 71.8 11.7 C73.2 15.3 72.9 17.3 71.7 20.9 C64.5 26.2 56.2 29.7 48.1 33.6 C46.6 34.3 45.2 35 43.7 35.7 C40 37.5 36.3 39.2 32.7 41 C29.9 42.3 27 43.7 24.2 45 C20.5 46.8 16.8 48.6 13.2 50.3 C9.2 52.2 5.3 54.1 1.3 56 C0.3 56.5 -0.8 57 -1.8 57.6 C-3.9 58.5 -5.9 59.5 -7.9 60.5 C-8.8 60.9 -9.7 61.4 -10.6 61.8 C-11.4 62.2 -12.2 62.6 -13 63 C-18.7 65.3 -24.9 66.1 -30.8 64.1 C-36.8 61.3 -41 57.8 -45.3 52.9 C-46 52.2 -46.6 51.6 -47.3 50.9 C-52.6 45 -52.6 45 -53.3 40.9 C-52 40.1 -50.7 39.3 -49.4 38.5 C-48.7 38 -48 37.6 -47.3 37.1 C-43.7 34.9 -41.5 34.6 -37.3 34.9 C-34.4 36.3 -31.8 38 -29.1 39.7 C-25.5 41.3 -24.1 41.1 -20.3 39.9 C-16.9 38.4 -13.7 36.7 -10.4 34.9 C-9.1 34.2 -9.1 34.2 -7.8 33.4 C-5.6 32.3 -3.5 31.1 -1.3 29.9 C-3.6 26.9 -5.9 24.2 -8.8 21.8 C-13 18.3 -17 14.6 -21 10.8 C-24 8.1 -27.1 5.5 -30.3 2.9 C-30.3 0.6 -30.3 0.6 -29.3 -2.1 C-18.8 -7.6 -10.1 -5.2 0 0 Z",s="M0 0 C1 -0 2.1 -0 3.2 -0 C4.3 -0 5.5 -0 6.7 -0 C7.9 -0 9.1 -0 10.3 -0 C13.6 -0 17 -0 20.3 -0 C23.8 -0 27.2 -0 30.7 -0 C36.5 -0 42.4 -0 48.2 -0 C54.9 0 61.7 0 68.4 -0 C74.2 -0 80 -0 85.8 -0 C89.2 -0 92.7 -0 96.1 -0 C100 -0 103.8 -0 107.7 -0 C109.4 -0 109.4 -0 111.2 -0 C112.8 -0 112.8 -0 114.4 0 C115.3 0 116.2 0 117.1 0 C119.2 0.1 119.2 0.1 120.2 1.1 C120.3 3.1 120.3 5.1 120.3 7.1 C120.3 8.8 120.3 8.8 120.3 10.4 C120.2 13.1 120.2 13.1 119.2 14.1 C117.6 14.2 116 14.3 114.4 14.3 C113.3 14.3 112.3 14.3 111.2 14.3 C110 14.3 108.9 14.3 107.7 14.3 C106.5 14.3 105.3 14.3 104 14.3 C100.7 14.3 97.4 14.3 94.1 14.3 C90.6 14.3 87.1 14.3 83.7 14.3 C77.8 14.3 72 14.3 66.2 14.3 C59.4 14.3 52.7 14.3 45.9 14.3 C40.2 14.3 34.4 14.3 28.6 14.3 C25.1 14.3 21.7 14.3 18.2 14.3 C14.4 14.3 10.5 14.3 6.7 14.3 C4.9 14.3 4.9 14.3 3.2 14.3 C1.6 14.3 1.6 14.3 0 14.3 C-0.9 14.3 -1.8 14.3 -2.8 14.3 C-4.8 14.1 -4.8 14.1 -5.8 13.1 C-5.9 11.1 -6 9.1 -5.9 7.1 C-5.9 6 -6 4.9 -6 3.8 C-5.7 -0.7 -4.1 0 0 0 Z",t=(C=128)=>`<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="${C}" height="${C}" viewBox="0 0 128 128"><path d="${o}" fill="currentColor" transform="translate(54.3,21.1)"/><path d="${s}" fill="currentColor" transform="translate(6.8,97.9)"/></svg>`,e=({size:C=24,...n})=>a("svg",{version:"1.1",xmlns:"http://www.w3.org/2000/svg",width:C,height:C,viewBox:"0 0 128 128",fill:"currentColor",...n,children:[r("path",{d:o,transform:"translate(54.3,21.1)"}),r("path",{d:s,transform:"translate(6.8,97.9)"})]}),p={ja:{title:"@passport\u3067\u30ED\u30B0\u30A4\u30F3",description:"@passport\u306F\u3001\u5404atproto\u30A2\u30D7\u30EA\u3067\u30CF\u30F3\u30C9\u30EB\u3092\u90FD\u5EA6\u5165\u529B\u3059\u308B\u624B\u9593\u304C\u7701\u3051\u308B\u5171\u901A\u30CF\u30F3\u30C9\u30EB\u30DE\u30CD\u30FC\u30B8\u30E3\u30FC\u3067\u3059\u3002"},en:{title:"Login with @passport",description:"@passport is a universal handle manager that saves you from typing your handle repeatedly across atproto apps."},iconSvg:t(128),getIconSvg:t};export{e as a,p as b};
|
package/dist/core.d.mts
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
interface AtPassportOptions {
|
|
2
|
+
callbackUrl: string;
|
|
3
|
+
baseUrl?: string;
|
|
4
|
+
lang?: 'en' | 'ja';
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* AtPassport Client
|
|
8
|
+
*/
|
|
9
|
+
declare class AtPassport {
|
|
10
|
+
private readonly baseUrl;
|
|
11
|
+
private readonly callbackUrl;
|
|
12
|
+
private readonly lang?;
|
|
13
|
+
constructor(options: AtPassportOptions);
|
|
14
|
+
/**
|
|
15
|
+
* Generates the authentication URL and state.
|
|
16
|
+
* By saving the state on the app side and verifying it in parseCallback,
|
|
17
|
+
* you can prevent CSRF attacks. Custom parameters will be attached to the callback.
|
|
18
|
+
*/
|
|
19
|
+
generateAuthUrl(customParams?: Record<string, string>): {
|
|
20
|
+
url: string;
|
|
21
|
+
atpstate: string;
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Parses the callback URL returned from AtPassport and extracts parameters.
|
|
25
|
+
* If `expectedState` is provided, it throws an error if the returned state does not match.
|
|
26
|
+
*/
|
|
27
|
+
parseCallback(currentUrl: string, expectedState?: string | null): {
|
|
28
|
+
handle: string | null;
|
|
29
|
+
did: string | null;
|
|
30
|
+
pdsUrl: string | null;
|
|
31
|
+
atpstate: string | null;
|
|
32
|
+
customParams: Record<string, string>;
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Opens a popup to let user pick a handle.
|
|
36
|
+
* Returns a promise that resolves with the selected handle.
|
|
37
|
+
*/
|
|
38
|
+
pick(): Promise<string>;
|
|
39
|
+
/**
|
|
40
|
+
* Attaches the picker to an input element.
|
|
41
|
+
* Automatically fills the input when a handle is picked on focus.
|
|
42
|
+
*/
|
|
43
|
+
decorate(input: HTMLInputElement): void;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export { AtPassport, type AtPassportOptions };
|
package/dist/core.d.ts
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
interface AtPassportOptions {
|
|
2
|
+
callbackUrl: string;
|
|
3
|
+
baseUrl?: string;
|
|
4
|
+
lang?: 'en' | 'ja';
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* AtPassport Client
|
|
8
|
+
*/
|
|
9
|
+
declare class AtPassport {
|
|
10
|
+
private readonly baseUrl;
|
|
11
|
+
private readonly callbackUrl;
|
|
12
|
+
private readonly lang?;
|
|
13
|
+
constructor(options: AtPassportOptions);
|
|
14
|
+
/**
|
|
15
|
+
* Generates the authentication URL and state.
|
|
16
|
+
* By saving the state on the app side and verifying it in parseCallback,
|
|
17
|
+
* you can prevent CSRF attacks. Custom parameters will be attached to the callback.
|
|
18
|
+
*/
|
|
19
|
+
generateAuthUrl(customParams?: Record<string, string>): {
|
|
20
|
+
url: string;
|
|
21
|
+
atpstate: string;
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Parses the callback URL returned from AtPassport and extracts parameters.
|
|
25
|
+
* If `expectedState` is provided, it throws an error if the returned state does not match.
|
|
26
|
+
*/
|
|
27
|
+
parseCallback(currentUrl: string, expectedState?: string | null): {
|
|
28
|
+
handle: string | null;
|
|
29
|
+
did: string | null;
|
|
30
|
+
pdsUrl: string | null;
|
|
31
|
+
atpstate: string | null;
|
|
32
|
+
customParams: Record<string, string>;
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Opens a popup to let user pick a handle.
|
|
36
|
+
* Returns a promise that resolves with the selected handle.
|
|
37
|
+
*/
|
|
38
|
+
pick(): Promise<string>;
|
|
39
|
+
/**
|
|
40
|
+
* Attaches the picker to an input element.
|
|
41
|
+
* Automatically fills the input when a handle is picked on focus.
|
|
42
|
+
*/
|
|
43
|
+
decorate(input: HTMLInputElement): void;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export { AtPassport, type AtPassportOptions };
|
package/dist/core.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";var g=Object.defineProperty;var u=Object.getOwnPropertyDescriptor;var w=Object.getOwnPropertyNames;var b=Object.prototype.hasOwnProperty;var U=(r,t)=>{for(var a in t)g(r,a,{get:t[a],enumerable:!0})},k=(r,t,a,s)=>{if(t&&typeof t=="object"||typeof t=="function")for(let e of w(t))!b.call(r,e)&&e!==a&&g(r,e,{get:()=>t[e],enumerable:!(s=u(t,e))||s.enumerable});return r};var m=r=>k(g({},"__esModule",{value:!0}),r);var v={};U(v,{AtPassport:()=>p});module.exports=m(v);var p=class{baseUrl;callbackUrl;lang;constructor(t){this.baseUrl=(t.baseUrl||"https://atpassport.net").replace(/\/$/,""),this.callbackUrl=t.callbackUrl,this.lang=t.lang}generateAuthUrl(t){let a=crypto.randomUUID(),s=this.lang?`${this.lang}/authentication`:"authentication",e=new URL(`${this.baseUrl}/${s}`),n=new URL(this.callbackUrl);if(t)for(let[l,i]of Object.entries(t))n.searchParams.set(l,i);return e.searchParams.set("callback",n.toString()),e.searchParams.set("atpstate",a),{url:e.toString(),atpstate:a}}parseCallback(t,a){let s=new URL(t),e=s.searchParams.get("handle"),n=s.searchParams.get("did"),l=s.searchParams.get("pdsurl"),i=s.searchParams.get("atpstate");if(a&&i!==a)throw new Error("Invalid atpstate: CSRF validation failed.");let c={};return s.searchParams.forEach((o,h)=>{["handle","did","pdsurl","atpstate"].includes(h)||(c[h]=o)}),{handle:e,did:n,pdsUrl:l,atpstate:i,customParams:c}}async pick(){return new Promise(t=>{let e=window.screenX+(window.outerWidth-400)/2,n=window.screenY+(window.outerHeight-500)/2,l=this.lang?`${this.lang}/picker`:"picker",i=`${this.baseUrl}/${l}`,c=window.open(i,"atpassport:picker",`width=400,height=500,left=${e},top=${n}`),o=d=>{d.origin===new URL(this.baseUrl).origin&&d.data?.type==="atpassport:pick"&&(window.removeEventListener("message",o),t(d.data.handle))};window.addEventListener("message",o);let h=setInterval(()=>{c?.closed&&clearInterval(h)},1e3)})}decorate(t){t.addEventListener("focus",async()=>{if(t.value)return;let a=await this.pick();a&&(t.value=a,t.dispatchEvent(new Event("input",{bubbles:!0})),t.dispatchEvent(new Event("change",{bubbles:!0})))})}};0&&(module.exports={AtPassport});
|
package/dist/core.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{a}from"./chunk-HQWY5EUQ.mjs";export{a as AtPassport};
|
package/dist/index.d.mts
CHANGED
|
@@ -1,73 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
}
|
|
6
|
-
/**
|
|
7
|
-
* Standard UI texts and icons for AtPassport integration components.
|
|
8
|
-
* Useful for building "Login with @passport" buttons and explanation dialogues.
|
|
9
|
-
*/
|
|
10
|
-
declare const AtPassportUI: {
|
|
11
|
-
ja: {
|
|
12
|
-
title: string;
|
|
13
|
-
description: string;
|
|
14
|
-
};
|
|
15
|
-
en: {
|
|
16
|
-
title: string;
|
|
17
|
-
description: string;
|
|
18
|
-
};
|
|
19
|
-
iconSvg: string;
|
|
20
|
-
/**
|
|
21
|
-
* Returns the @passport icon SVG string with a custom size.
|
|
22
|
-
*/
|
|
23
|
-
getIconSvg: (size?: number | string) => string;
|
|
24
|
-
};
|
|
25
|
-
/**
|
|
26
|
-
* AtPassport Client
|
|
27
|
-
*/
|
|
28
|
-
declare class AtPassport {
|
|
29
|
-
private readonly baseUrl;
|
|
30
|
-
private readonly callbackUrl;
|
|
31
|
-
private readonly lang?;
|
|
32
|
-
constructor(options: AtPassportOptions);
|
|
33
|
-
/**
|
|
34
|
-
* Generates the URL for handle registration.
|
|
35
|
-
*/
|
|
36
|
-
registerUrl(handle: string, callback: string): string;
|
|
37
|
-
/**
|
|
38
|
-
* Generates the URL for identity resolution.
|
|
39
|
-
*/
|
|
40
|
-
resolveUrl(callback: string): string;
|
|
41
|
-
/**
|
|
42
|
-
* Generates the authentication URL and state.
|
|
43
|
-
* By saving the state on the app side and verifying it in parseCallback,
|
|
44
|
-
* you can prevent CSRF attacks. Custom parameters will be attached to the callback.
|
|
45
|
-
*/
|
|
46
|
-
generateAuthUrl(customParams?: Record<string, string>): {
|
|
47
|
-
url: string;
|
|
48
|
-
atpstate: string;
|
|
49
|
-
};
|
|
50
|
-
/**
|
|
51
|
-
* Parses the callback URL returned from AtPassport and extracts parameters.
|
|
52
|
-
* If `expectedState` is provided, it throws an error if the returned state does not match.
|
|
53
|
-
*/
|
|
54
|
-
parseCallback(currentUrl: string, expectedState?: string | null): {
|
|
55
|
-
handle: string | null;
|
|
56
|
-
did: string | null;
|
|
57
|
-
pdsUrl: string | null;
|
|
58
|
-
atpstate: string | null;
|
|
59
|
-
customParams: Record<string, string>;
|
|
60
|
-
};
|
|
61
|
-
/**
|
|
62
|
-
* Opens a popup to let user pick a handle.
|
|
63
|
-
* Returns a promise that resolves with the selected handle.
|
|
64
|
-
*/
|
|
65
|
-
pick(): Promise<string>;
|
|
66
|
-
/**
|
|
67
|
-
* Attaches the picker to an input element.
|
|
68
|
-
* Automatically fills the input when a handle is picked on focus.
|
|
69
|
-
*/
|
|
70
|
-
decorate(input: HTMLInputElement): void;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
export { AtPassport, type AtPassportOptions, AtPassportUI };
|
|
1
|
+
export { AtPassport, AtPassportOptions } from './core.mjs';
|
|
2
|
+
export { AtPassportIcon, AtPassportIconProps, AtPassportUI } from './ui.mjs';
|
|
3
|
+
import 'react/jsx-runtime';
|
|
4
|
+
import 'react';
|
package/dist/index.d.ts
CHANGED
|
@@ -1,73 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
}
|
|
6
|
-
/**
|
|
7
|
-
* Standard UI texts and icons for AtPassport integration components.
|
|
8
|
-
* Useful for building "Login with @passport" buttons and explanation dialogues.
|
|
9
|
-
*/
|
|
10
|
-
declare const AtPassportUI: {
|
|
11
|
-
ja: {
|
|
12
|
-
title: string;
|
|
13
|
-
description: string;
|
|
14
|
-
};
|
|
15
|
-
en: {
|
|
16
|
-
title: string;
|
|
17
|
-
description: string;
|
|
18
|
-
};
|
|
19
|
-
iconSvg: string;
|
|
20
|
-
/**
|
|
21
|
-
* Returns the @passport icon SVG string with a custom size.
|
|
22
|
-
*/
|
|
23
|
-
getIconSvg: (size?: number | string) => string;
|
|
24
|
-
};
|
|
25
|
-
/**
|
|
26
|
-
* AtPassport Client
|
|
27
|
-
*/
|
|
28
|
-
declare class AtPassport {
|
|
29
|
-
private readonly baseUrl;
|
|
30
|
-
private readonly callbackUrl;
|
|
31
|
-
private readonly lang?;
|
|
32
|
-
constructor(options: AtPassportOptions);
|
|
33
|
-
/**
|
|
34
|
-
* Generates the URL for handle registration.
|
|
35
|
-
*/
|
|
36
|
-
registerUrl(handle: string, callback: string): string;
|
|
37
|
-
/**
|
|
38
|
-
* Generates the URL for identity resolution.
|
|
39
|
-
*/
|
|
40
|
-
resolveUrl(callback: string): string;
|
|
41
|
-
/**
|
|
42
|
-
* Generates the authentication URL and state.
|
|
43
|
-
* By saving the state on the app side and verifying it in parseCallback,
|
|
44
|
-
* you can prevent CSRF attacks. Custom parameters will be attached to the callback.
|
|
45
|
-
*/
|
|
46
|
-
generateAuthUrl(customParams?: Record<string, string>): {
|
|
47
|
-
url: string;
|
|
48
|
-
atpstate: string;
|
|
49
|
-
};
|
|
50
|
-
/**
|
|
51
|
-
* Parses the callback URL returned from AtPassport and extracts parameters.
|
|
52
|
-
* If `expectedState` is provided, it throws an error if the returned state does not match.
|
|
53
|
-
*/
|
|
54
|
-
parseCallback(currentUrl: string, expectedState?: string | null): {
|
|
55
|
-
handle: string | null;
|
|
56
|
-
did: string | null;
|
|
57
|
-
pdsUrl: string | null;
|
|
58
|
-
atpstate: string | null;
|
|
59
|
-
customParams: Record<string, string>;
|
|
60
|
-
};
|
|
61
|
-
/**
|
|
62
|
-
* Opens a popup to let user pick a handle.
|
|
63
|
-
* Returns a promise that resolves with the selected handle.
|
|
64
|
-
*/
|
|
65
|
-
pick(): Promise<string>;
|
|
66
|
-
/**
|
|
67
|
-
* Attaches the picker to an input element.
|
|
68
|
-
* Automatically fills the input when a handle is picked on focus.
|
|
69
|
-
*/
|
|
70
|
-
decorate(input: HTMLInputElement): void;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
export { AtPassport, type AtPassportOptions, AtPassportUI };
|
|
1
|
+
export { AtPassport, AtPassportOptions } from './core.js';
|
|
2
|
+
export { AtPassportIcon, AtPassportIconProps, AtPassportUI } from './ui.js';
|
|
3
|
+
import 'react/jsx-runtime';
|
|
4
|
+
import 'react';
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var g=Object.defineProperty;var
|
|
1
|
+
"use strict";var g=Object.defineProperty;var m=Object.getOwnPropertyDescriptor;var f=Object.getOwnPropertyNames;var b=Object.prototype.hasOwnProperty;var P=(r,t)=>{for(var s in t)g(r,s,{get:t[s],enumerable:!0})},U=(r,t,s,a)=>{if(t&&typeof t=="object"||typeof t=="function")for(let e of f(t))!b.call(r,e)&&e!==s&&g(r,e,{get:()=>t[e],enumerable:!(a=m(t,e))||a.enumerable});return r};var k=r=>U(g({},"__esModule",{value:!0}),r);var E={};P(E,{AtPassport:()=>d,AtPassportIcon:()=>$,AtPassportUI:()=>I});module.exports=k(E);var d=class{baseUrl;callbackUrl;lang;constructor(t){this.baseUrl=(t.baseUrl||"https://atpassport.net").replace(/\/$/,""),this.callbackUrl=t.callbackUrl,this.lang=t.lang}generateAuthUrl(t){let s=crypto.randomUUID(),a=this.lang?`${this.lang}/authentication`:"authentication",e=new URL(`${this.baseUrl}/${a}`),n=new URL(this.callbackUrl);if(t)for(let[i,o]of Object.entries(t))n.searchParams.set(i,o);return e.searchParams.set("callback",n.toString()),e.searchParams.set("atpstate",s),{url:e.toString(),atpstate:s}}parseCallback(t,s){let a=new URL(t),e=a.searchParams.get("handle"),n=a.searchParams.get("did"),i=a.searchParams.get("pdsurl"),o=a.searchParams.get("atpstate");if(s&&o!==s)throw new Error("Invalid atpstate: CSRF validation failed.");let c={};return a.searchParams.forEach((p,C)=>{["handle","did","pdsurl","atpstate"].includes(C)||(c[C]=p)}),{handle:e,did:n,pdsUrl:i,atpstate:o,customParams:c}}async pick(){return new Promise(t=>{let e=window.screenX+(window.outerWidth-400)/2,n=window.screenY+(window.outerHeight-500)/2,i=this.lang?`${this.lang}/picker`:"picker",o=`${this.baseUrl}/${i}`,c=window.open(o,"atpassport:picker",`width=400,height=500,left=${e},top=${n}`),p=h=>{h.origin===new URL(this.baseUrl).origin&&h.data?.type==="atpassport:pick"&&(window.removeEventListener("message",p),t(h.data.handle))};window.addEventListener("message",p);let C=setInterval(()=>{c?.closed&&clearInterval(C)},1e3)})}decorate(t){t.addEventListener("focus",async()=>{if(t.value)return;let s=await this.pick();s&&(t.value=s,t.dispatchEvent(new Event("input",{bubbles:!0})),t.dispatchEvent(new Event("change",{bubbles:!0})))})}};var l=require("react/jsx-runtime"),w="M0 0 C1 0.5 2 1 3 1.5 C9.5 4.7 15.9 8.1 22.1 11.8 C25.2 13.2 27.3 13.3 30.7 12.9 C33.3 11.9 33.3 11.9 35.8 10.5 C44.4 5.8 54.9 5.7 64.5 7.5 C67.3 8.4 69.5 9.8 71.8 11.7 C73.2 15.3 72.9 17.3 71.7 20.9 C64.5 26.2 56.2 29.7 48.1 33.6 C46.6 34.3 45.2 35 43.7 35.7 C40 37.5 36.3 39.2 32.7 41 C29.9 42.3 27 43.7 24.2 45 C20.5 46.8 16.8 48.6 13.2 50.3 C9.2 52.2 5.3 54.1 1.3 56 C0.3 56.5 -0.8 57 -1.8 57.6 C-3.9 58.5 -5.9 59.5 -7.9 60.5 C-8.8 60.9 -9.7 61.4 -10.6 61.8 C-11.4 62.2 -12.2 62.6 -13 63 C-18.7 65.3 -24.9 66.1 -30.8 64.1 C-36.8 61.3 -41 57.8 -45.3 52.9 C-46 52.2 -46.6 51.6 -47.3 50.9 C-52.6 45 -52.6 45 -53.3 40.9 C-52 40.1 -50.7 39.3 -49.4 38.5 C-48.7 38 -48 37.6 -47.3 37.1 C-43.7 34.9 -41.5 34.6 -37.3 34.9 C-34.4 36.3 -31.8 38 -29.1 39.7 C-25.5 41.3 -24.1 41.1 -20.3 39.9 C-16.9 38.4 -13.7 36.7 -10.4 34.9 C-9.1 34.2 -9.1 34.2 -7.8 33.4 C-5.6 32.3 -3.5 31.1 -1.3 29.9 C-3.6 26.9 -5.9 24.2 -8.8 21.8 C-13 18.3 -17 14.6 -21 10.8 C-24 8.1 -27.1 5.5 -30.3 2.9 C-30.3 0.6 -30.3 0.6 -29.3 -2.1 C-18.8 -7.6 -10.1 -5.2 0 0 Z",v="M0 0 C1 -0 2.1 -0 3.2 -0 C4.3 -0 5.5 -0 6.7 -0 C7.9 -0 9.1 -0 10.3 -0 C13.6 -0 17 -0 20.3 -0 C23.8 -0 27.2 -0 30.7 -0 C36.5 -0 42.4 -0 48.2 -0 C54.9 0 61.7 0 68.4 -0 C74.2 -0 80 -0 85.8 -0 C89.2 -0 92.7 -0 96.1 -0 C100 -0 103.8 -0 107.7 -0 C109.4 -0 109.4 -0 111.2 -0 C112.8 -0 112.8 -0 114.4 0 C115.3 0 116.2 0 117.1 0 C119.2 0.1 119.2 0.1 120.2 1.1 C120.3 3.1 120.3 5.1 120.3 7.1 C120.3 8.8 120.3 8.8 120.3 10.4 C120.2 13.1 120.2 13.1 119.2 14.1 C117.6 14.2 116 14.3 114.4 14.3 C113.3 14.3 112.3 14.3 111.2 14.3 C110 14.3 108.9 14.3 107.7 14.3 C106.5 14.3 105.3 14.3 104 14.3 C100.7 14.3 97.4 14.3 94.1 14.3 C90.6 14.3 87.1 14.3 83.7 14.3 C77.8 14.3 72 14.3 66.2 14.3 C59.4 14.3 52.7 14.3 45.9 14.3 C40.2 14.3 34.4 14.3 28.6 14.3 C25.1 14.3 21.7 14.3 18.2 14.3 C14.4 14.3 10.5 14.3 6.7 14.3 C4.9 14.3 4.9 14.3 3.2 14.3 C1.6 14.3 1.6 14.3 0 14.3 C-0.9 14.3 -1.8 14.3 -2.8 14.3 C-4.8 14.1 -4.8 14.1 -5.8 13.1 C-5.9 11.1 -6 9.1 -5.9 7.1 C-5.9 6 -6 4.9 -6 3.8 C-5.7 -0.7 -4.1 0 0 0 Z",u=(r=128)=>`<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="${r}" height="${r}" viewBox="0 0 128 128"><path d="${w}" fill="currentColor" transform="translate(54.3,21.1)"/><path d="${v}" fill="currentColor" transform="translate(6.8,97.9)"/></svg>`,$=({size:r=24,...t})=>(0,l.jsxs)("svg",{version:"1.1",xmlns:"http://www.w3.org/2000/svg",width:r,height:r,viewBox:"0 0 128 128",fill:"currentColor",...t,children:[(0,l.jsx)("path",{d:w,transform:"translate(54.3,21.1)"}),(0,l.jsx)("path",{d:v,transform:"translate(6.8,97.9)"})]}),I={ja:{title:"@passport\u3067\u30ED\u30B0\u30A4\u30F3",description:"@passport\u306F\u3001\u5404atproto\u30A2\u30D7\u30EA\u3067\u30CF\u30F3\u30C9\u30EB\u3092\u90FD\u5EA6\u5165\u529B\u3059\u308B\u624B\u9593\u304C\u7701\u3051\u308B\u5171\u901A\u30CF\u30F3\u30C9\u30EB\u30DE\u30CD\u30FC\u30B8\u30E3\u30FC\u3067\u3059\u3002"},en:{title:"Login with @passport",description:"@passport is a universal handle manager that saves you from typing your handle repeatedly across atproto apps."},iconSvg:u(128),getIconSvg:u};0&&(module.exports={AtPassport,AtPassportIcon,AtPassportUI});
|
package/dist/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
import{a as o}from"./chunk-HQWY5EUQ.mjs";import{a as r,b as e}from"./chunk-LGB4WCG6.mjs";export{o as AtPassport,r as AtPassportIcon,e as AtPassportUI};
|
package/dist/ui.d.mts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { SVGProps } from 'react';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* AtPassport Icon Component for React.
|
|
6
|
+
*/
|
|
7
|
+
interface AtPassportIconProps extends SVGProps<SVGSVGElement> {
|
|
8
|
+
size?: number | string;
|
|
9
|
+
}
|
|
10
|
+
declare const AtPassportIcon: ({ size, ...props }: AtPassportIconProps) => react_jsx_runtime.JSX.Element;
|
|
11
|
+
/**
|
|
12
|
+
* Standard UI texts and icons for AtPassport integration components.
|
|
13
|
+
* Useful for building "Login with @passport" buttons and explanation dialogues.
|
|
14
|
+
*/
|
|
15
|
+
declare const AtPassportUI: {
|
|
16
|
+
ja: {
|
|
17
|
+
title: string;
|
|
18
|
+
description: string;
|
|
19
|
+
};
|
|
20
|
+
en: {
|
|
21
|
+
title: string;
|
|
22
|
+
description: string;
|
|
23
|
+
};
|
|
24
|
+
iconSvg: string;
|
|
25
|
+
/**
|
|
26
|
+
* Returns the @passport icon SVG string with a custom size.
|
|
27
|
+
*/
|
|
28
|
+
getIconSvg: (size?: number | string) => string;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export { AtPassportIcon, type AtPassportIconProps, AtPassportUI };
|
package/dist/ui.d.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { SVGProps } from 'react';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* AtPassport Icon Component for React.
|
|
6
|
+
*/
|
|
7
|
+
interface AtPassportIconProps extends SVGProps<SVGSVGElement> {
|
|
8
|
+
size?: number | string;
|
|
9
|
+
}
|
|
10
|
+
declare const AtPassportIcon: ({ size, ...props }: AtPassportIconProps) => react_jsx_runtime.JSX.Element;
|
|
11
|
+
/**
|
|
12
|
+
* Standard UI texts and icons for AtPassport integration components.
|
|
13
|
+
* Useful for building "Login with @passport" buttons and explanation dialogues.
|
|
14
|
+
*/
|
|
15
|
+
declare const AtPassportUI: {
|
|
16
|
+
ja: {
|
|
17
|
+
title: string;
|
|
18
|
+
description: string;
|
|
19
|
+
};
|
|
20
|
+
en: {
|
|
21
|
+
title: string;
|
|
22
|
+
description: string;
|
|
23
|
+
};
|
|
24
|
+
iconSvg: string;
|
|
25
|
+
/**
|
|
26
|
+
* Returns the @passport icon SVG string with a custom size.
|
|
27
|
+
*/
|
|
28
|
+
getIconSvg: (size?: number | string) => string;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export { AtPassportIcon, type AtPassportIconProps, AtPassportUI };
|
package/dist/ui.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";var n=Object.defineProperty;var l=Object.getOwnPropertyDescriptor;var g=Object.getOwnPropertyNames;var c=Object.prototype.hasOwnProperty;var h=(C,t)=>{for(var s in t)n(C,s,{get:t[s],enumerable:!0})},v=(C,t,s,a)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of g(t))!c.call(C,r)&&r!==s&&n(C,r,{get:()=>t[r],enumerable:!(a=l(t,r))||a.enumerable});return C};var w=C=>v(n({},"__esModule",{value:!0}),C);var f={};h(f,{AtPassportIcon:()=>d,AtPassportUI:()=>m});module.exports=w(f);var o=require("react/jsx-runtime"),p="M0 0 C1 0.5 2 1 3 1.5 C9.5 4.7 15.9 8.1 22.1 11.8 C25.2 13.2 27.3 13.3 30.7 12.9 C33.3 11.9 33.3 11.9 35.8 10.5 C44.4 5.8 54.9 5.7 64.5 7.5 C67.3 8.4 69.5 9.8 71.8 11.7 C73.2 15.3 72.9 17.3 71.7 20.9 C64.5 26.2 56.2 29.7 48.1 33.6 C46.6 34.3 45.2 35 43.7 35.7 C40 37.5 36.3 39.2 32.7 41 C29.9 42.3 27 43.7 24.2 45 C20.5 46.8 16.8 48.6 13.2 50.3 C9.2 52.2 5.3 54.1 1.3 56 C0.3 56.5 -0.8 57 -1.8 57.6 C-3.9 58.5 -5.9 59.5 -7.9 60.5 C-8.8 60.9 -9.7 61.4 -10.6 61.8 C-11.4 62.2 -12.2 62.6 -13 63 C-18.7 65.3 -24.9 66.1 -30.8 64.1 C-36.8 61.3 -41 57.8 -45.3 52.9 C-46 52.2 -46.6 51.6 -47.3 50.9 C-52.6 45 -52.6 45 -53.3 40.9 C-52 40.1 -50.7 39.3 -49.4 38.5 C-48.7 38 -48 37.6 -47.3 37.1 C-43.7 34.9 -41.5 34.6 -37.3 34.9 C-34.4 36.3 -31.8 38 -29.1 39.7 C-25.5 41.3 -24.1 41.1 -20.3 39.9 C-16.9 38.4 -13.7 36.7 -10.4 34.9 C-9.1 34.2 -9.1 34.2 -7.8 33.4 C-5.6 32.3 -3.5 31.1 -1.3 29.9 C-3.6 26.9 -5.9 24.2 -8.8 21.8 C-13 18.3 -17 14.6 -21 10.8 C-24 8.1 -27.1 5.5 -30.3 2.9 C-30.3 0.6 -30.3 0.6 -29.3 -2.1 C-18.8 -7.6 -10.1 -5.2 0 0 Z",i="M0 0 C1 -0 2.1 -0 3.2 -0 C4.3 -0 5.5 -0 6.7 -0 C7.9 -0 9.1 -0 10.3 -0 C13.6 -0 17 -0 20.3 -0 C23.8 -0 27.2 -0 30.7 -0 C36.5 -0 42.4 -0 48.2 -0 C54.9 0 61.7 0 68.4 -0 C74.2 -0 80 -0 85.8 -0 C89.2 -0 92.7 -0 96.1 -0 C100 -0 103.8 -0 107.7 -0 C109.4 -0 109.4 -0 111.2 -0 C112.8 -0 112.8 -0 114.4 0 C115.3 0 116.2 0 117.1 0 C119.2 0.1 119.2 0.1 120.2 1.1 C120.3 3.1 120.3 5.1 120.3 7.1 C120.3 8.8 120.3 8.8 120.3 10.4 C120.2 13.1 120.2 13.1 119.2 14.1 C117.6 14.2 116 14.3 114.4 14.3 C113.3 14.3 112.3 14.3 111.2 14.3 C110 14.3 108.9 14.3 107.7 14.3 C106.5 14.3 105.3 14.3 104 14.3 C100.7 14.3 97.4 14.3 94.1 14.3 C90.6 14.3 87.1 14.3 83.7 14.3 C77.8 14.3 72 14.3 66.2 14.3 C59.4 14.3 52.7 14.3 45.9 14.3 C40.2 14.3 34.4 14.3 28.6 14.3 C25.1 14.3 21.7 14.3 18.2 14.3 C14.4 14.3 10.5 14.3 6.7 14.3 C4.9 14.3 4.9 14.3 3.2 14.3 C1.6 14.3 1.6 14.3 0 14.3 C-0.9 14.3 -1.8 14.3 -2.8 14.3 C-4.8 14.1 -4.8 14.1 -5.8 13.1 C-5.9 11.1 -6 9.1 -5.9 7.1 C-5.9 6 -6 4.9 -6 3.8 C-5.7 -0.7 -4.1 0 0 0 Z",e=(C=128)=>`<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="${C}" height="${C}" viewBox="0 0 128 128"><path d="${p}" fill="currentColor" transform="translate(54.3,21.1)"/><path d="${i}" fill="currentColor" transform="translate(6.8,97.9)"/></svg>`,d=({size:C=24,...t})=>(0,o.jsxs)("svg",{version:"1.1",xmlns:"http://www.w3.org/2000/svg",width:C,height:C,viewBox:"0 0 128 128",fill:"currentColor",...t,children:[(0,o.jsx)("path",{d:p,transform:"translate(54.3,21.1)"}),(0,o.jsx)("path",{d:i,transform:"translate(6.8,97.9)"})]}),m={ja:{title:"@passport\u3067\u30ED\u30B0\u30A4\u30F3",description:"@passport\u306F\u3001\u5404atproto\u30A2\u30D7\u30EA\u3067\u30CF\u30F3\u30C9\u30EB\u3092\u90FD\u5EA6\u5165\u529B\u3059\u308B\u624B\u9593\u304C\u7701\u3051\u308B\u5171\u901A\u30CF\u30F3\u30C9\u30EB\u30DE\u30CD\u30FC\u30B8\u30E3\u30FC\u3067\u3059\u3002"},en:{title:"Login with @passport",description:"@passport is a universal handle manager that saves you from typing your handle repeatedly across atproto apps."},iconSvg:e(128),getIconSvg:e};0&&(module.exports={AtPassportIcon,AtPassportUI});
|
package/dist/ui.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{a,b}from"./chunk-LGB4WCG6.mjs";export{a as AtPassportIcon,b as AtPassportUI};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atpassport/client",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.9",
|
|
4
4
|
"description": "AtPassport client library for integrating secure handle input assist into applications.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"atproto",
|
|
@@ -12,13 +12,6 @@
|
|
|
12
12
|
"main": "./dist/index.js",
|
|
13
13
|
"module": "./dist/index.mjs",
|
|
14
14
|
"types": "./dist/index.d.ts",
|
|
15
|
-
"exports": {
|
|
16
|
-
".": {
|
|
17
|
-
"types": "./dist/index.d.ts",
|
|
18
|
-
"import": "./dist/index.mjs",
|
|
19
|
-
"require": "./dist/index.js"
|
|
20
|
-
}
|
|
21
|
-
},
|
|
22
15
|
"files": [
|
|
23
16
|
"dist",
|
|
24
17
|
"README.md"
|
|
@@ -27,12 +20,39 @@
|
|
|
27
20
|
"access": "public"
|
|
28
21
|
},
|
|
29
22
|
"scripts": {
|
|
30
|
-
"build": "tsup src/index.ts --format cjs,esm --dts --minify",
|
|
23
|
+
"build": "tsup src/index.ts src/core.ts src/ui.tsx --format cjs,esm --dts --minify --clean",
|
|
31
24
|
"deploy": "pnpm build && npm publish --access public",
|
|
32
25
|
"test": "vitest run"
|
|
33
26
|
},
|
|
27
|
+
"peerDependencies": {
|
|
28
|
+
"react": ">=18.0.0"
|
|
29
|
+
},
|
|
30
|
+
"peerDependenciesMeta": {
|
|
31
|
+
"react": {
|
|
32
|
+
"optional": true
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
"exports": {
|
|
36
|
+
".": {
|
|
37
|
+
"types": "./dist/index.d.ts",
|
|
38
|
+
"import": "./dist/index.mjs",
|
|
39
|
+
"require": "./dist/index.js"
|
|
40
|
+
},
|
|
41
|
+
"./core": {
|
|
42
|
+
"types": "./dist/core.d.ts",
|
|
43
|
+
"import": "./dist/core.mjs",
|
|
44
|
+
"require": "./dist/core.js"
|
|
45
|
+
},
|
|
46
|
+
"./ui": {
|
|
47
|
+
"types": "./dist/ui.d.ts",
|
|
48
|
+
"import": "./dist/ui.mjs",
|
|
49
|
+
"require": "./dist/ui.js"
|
|
50
|
+
}
|
|
51
|
+
},
|
|
34
52
|
"devDependencies": {
|
|
35
53
|
"@types/node": "^25.5.0",
|
|
54
|
+
"@types/react": "^19.2.14",
|
|
55
|
+
"react": "^19.2.4",
|
|
36
56
|
"tsup": "^8.5.1",
|
|
37
57
|
"typescript": "^5.0.0",
|
|
38
58
|
"vitest": "^2.0.0"
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const vitest_1 = require("vitest");
|
|
4
|
-
const index_1 = require("../index");
|
|
5
|
-
(0, vitest_1.describe)('AtPassport', () => {
|
|
6
|
-
const baseUrl = 'https://passport.atproto.com';
|
|
7
|
-
const callbackUrl = 'https://app.com/callback';
|
|
8
|
-
(0, vitest_1.beforeEach)(async () => {
|
|
9
|
-
// Polyfill crypto.randomUUID for vitest environment if needed
|
|
10
|
-
if (typeof crypto === 'undefined' || typeof crypto.randomUUID !== 'function') {
|
|
11
|
-
const g = global;
|
|
12
|
-
if (!g.crypto)
|
|
13
|
-
g.crypto = {};
|
|
14
|
-
g.crypto.randomUUID = () => 'test-uuid-1234';
|
|
15
|
-
}
|
|
16
|
-
});
|
|
17
|
-
(0, vitest_1.it)('generates correct register URL', () => {
|
|
18
|
-
const passport = new index_1.AtPassport({ baseUrl, callbackUrl });
|
|
19
|
-
const url = passport.registerUrl('alice.bsky.social', 'https://app.com/register-callback');
|
|
20
|
-
const parsed = new URL(url);
|
|
21
|
-
(0, vitest_1.expect)(parsed.origin).toBe(baseUrl);
|
|
22
|
-
(0, vitest_1.expect)(parsed.pathname).toBe('/api/register');
|
|
23
|
-
(0, vitest_1.expect)(parsed.searchParams.get('handle')).toBe('alice.bsky.social');
|
|
24
|
-
(0, vitest_1.expect)(parsed.searchParams.get('callbackUrl')).toBe('https://app.com/register-callback');
|
|
25
|
-
});
|
|
26
|
-
(0, vitest_1.it)('generates correct resolve URL', () => {
|
|
27
|
-
const passport = new index_1.AtPassport({ baseUrl, callbackUrl });
|
|
28
|
-
const url = passport.resolveUrl('https://app.com/resolve-callback');
|
|
29
|
-
const parsed = new URL(url);
|
|
30
|
-
(0, vitest_1.expect)(parsed.origin).toBe(baseUrl);
|
|
31
|
-
(0, vitest_1.expect)(parsed.pathname).toBe('/api/resolve');
|
|
32
|
-
(0, vitest_1.expect)(parsed.searchParams.get('callbackUrl')).toBe('https://app.com/resolve-callback');
|
|
33
|
-
});
|
|
34
|
-
(0, vitest_1.it)('generates correct auth URL and state', () => {
|
|
35
|
-
const passport = new index_1.AtPassport({ baseUrl, callbackUrl });
|
|
36
|
-
const { url, atpstate } = passport.generateAuthUrl({ theme: 'dark' });
|
|
37
|
-
const parsed = new URL(url);
|
|
38
|
-
(0, vitest_1.expect)(parsed.origin).toBe(baseUrl);
|
|
39
|
-
(0, vitest_1.expect)(parsed.pathname).toBe('/authentication');
|
|
40
|
-
(0, vitest_1.expect)(parsed.searchParams.get('atpstate')).toBe(atpstate);
|
|
41
|
-
const innerCallback = new URL(parsed.searchParams.get('callback'));
|
|
42
|
-
(0, vitest_1.expect)(innerCallback.origin).toBe('https://app.com');
|
|
43
|
-
(0, vitest_1.expect)(innerCallback.searchParams.get('theme')).toBe('dark');
|
|
44
|
-
});
|
|
45
|
-
(0, vitest_1.it)('parses callback URL correctly', () => {
|
|
46
|
-
const passport = new index_1.AtPassport({ callbackUrl });
|
|
47
|
-
const testUrl = 'https://app.com/callback?handle=alice.bsky.social&did=did:plc:123&pdsurl=https://pds.example.com&atpstate=test-state&extra=param';
|
|
48
|
-
const result = passport.parseCallback(testUrl, 'test-state');
|
|
49
|
-
(0, vitest_1.expect)(result.handle).toBe('alice.bsky.social');
|
|
50
|
-
(0, vitest_1.expect)(result.did).toBe('did:plc:123');
|
|
51
|
-
(0, vitest_1.expect)(result.pdsUrl).toBe('https://pds.example.com');
|
|
52
|
-
(0, vitest_1.expect)(result.atpstate).toBe('test-state');
|
|
53
|
-
(0, vitest_1.expect)(result.customParams.extra).toBe('param');
|
|
54
|
-
(0, vitest_1.expect)(result.customParams.handle).toBeUndefined();
|
|
55
|
-
});
|
|
56
|
-
(0, vitest_1.it)('throws on CSRF state mismatch', () => {
|
|
57
|
-
const passport = new index_1.AtPassport({ callbackUrl });
|
|
58
|
-
const testUrl = 'https://app.com/callback?handle=alice.bsky.social&atpstate=test-state';
|
|
59
|
-
(0, vitest_1.expect)(() => passport.parseCallback(testUrl, 'wrong-state')).toThrow('Invalid atpstate: CSRF validation failed.');
|
|
60
|
-
});
|
|
61
|
-
});
|