pauth-js 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 +125 -0
- package/dist/index.d.mts +75 -0
- package/dist/index.d.ts +75 -0
- package/dist/index.js +240 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +206 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +42 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 pauth.me
|
|
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,125 @@
|
|
|
1
|
+
# pauth-js
|
|
2
|
+
|
|
3
|
+
> Official JavaScript/TypeScript SDK for [pauth.me](https://pauth.me)
|
|
4
|
+
|
|
5
|
+
[](LICENSE)
|
|
6
|
+
[]()
|
|
7
|
+
[]()
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install github:pauth-me/pauth-js
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Quick Start
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
import { PauthClient } from 'pauth-js';
|
|
19
|
+
|
|
20
|
+
const client = new PauthClient({ apiKey: 'test_your-api-key' });
|
|
21
|
+
const result = await client.verify('+819012345678');
|
|
22
|
+
console.log(result.pin); // "1234"(サンドボックスでは約2秒後に返る)
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Sandbox Mode
|
|
26
|
+
|
|
27
|
+
- APIキーが `test_` で始まる場合、サンドボックスモードで動作
|
|
28
|
+
- 実際に着信はせず、約2秒後に自動でPIN=1234が返る
|
|
29
|
+
- [pauth.me](https://pauth.me) でサインアップすれば無料枠(100回/月)で利用可能
|
|
30
|
+
|
|
31
|
+
## API Reference
|
|
32
|
+
|
|
33
|
+
### `new PauthClient(options)`
|
|
34
|
+
|
|
35
|
+
| Option | Type | Required | Description |
|
|
36
|
+
|--------|------|----------|-------------|
|
|
37
|
+
| `apiKey` | `string` | Yes | Your API key (`test_` prefix for sandbox) |
|
|
38
|
+
| `baseUrl` | `string` | No | Base URL (default: `https://pauth.me`) |
|
|
39
|
+
|
|
40
|
+
### `client.authenticate(): Promise<string>`
|
|
41
|
+
|
|
42
|
+
APIキーでBearer トークンを取得します。トークンはクライアント内部でキャッシュされるため、通常は直接呼び出す必要はありません。
|
|
43
|
+
|
|
44
|
+
### `client.entry(callerNumber, signal?): Promise<EntryEvent>`
|
|
45
|
+
|
|
46
|
+
SSEストリームで着信PINを待ち受けます。
|
|
47
|
+
|
|
48
|
+
| Parameter | Type | Description |
|
|
49
|
+
|-----------|------|-------------|
|
|
50
|
+
| `callerNumber` | `string` | 電話番号(国際形式: `+819012345678`) |
|
|
51
|
+
| `signal` | `AbortSignal` | (optional) キャンセル用シグナル |
|
|
52
|
+
|
|
53
|
+
Returns: `EntryEvent` — `{ expires_in: number, callerd_number: string, pin: string | null }`
|
|
54
|
+
|
|
55
|
+
### `client.apply(callerNumber, pin): Promise<boolean>`
|
|
56
|
+
|
|
57
|
+
PINを照合します。
|
|
58
|
+
|
|
59
|
+
| Parameter | Type | Description |
|
|
60
|
+
|-----------|------|-------------|
|
|
61
|
+
| `callerNumber` | `string` | 電話番号(国際形式) |
|
|
62
|
+
| `pin` | `string` | PIN コード |
|
|
63
|
+
|
|
64
|
+
Returns: `true` (認証成功) / `false` (PIN不一致)
|
|
65
|
+
|
|
66
|
+
### `client.verify(callerNumber, options?): Promise<VerifyResult>`
|
|
67
|
+
|
|
68
|
+
電話番号認証を一括実行します(authenticate → entry → apply)。
|
|
69
|
+
|
|
70
|
+
| Parameter | Type | Description |
|
|
71
|
+
|-----------|------|-------------|
|
|
72
|
+
| `callerNumber` | `string` | 電話番号(国際形式) |
|
|
73
|
+
| `options.onStep` | `function` | ステップ進捗コールバック |
|
|
74
|
+
| `options.signal` | `AbortSignal` | キャンセル用シグナル |
|
|
75
|
+
|
|
76
|
+
```typescript
|
|
77
|
+
const result = await client.verify('+819012345678', {
|
|
78
|
+
onStep: (step) => console.log('Step:', step),
|
|
79
|
+
// step: 'authenticating' | 'waiting_for_call' | 'verifying_pin'
|
|
80
|
+
});
|
|
81
|
+
// result: { callerNumber: string, pin: string }
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Error Handling
|
|
85
|
+
|
|
86
|
+
```typescript
|
|
87
|
+
import {
|
|
88
|
+
PauthError, AuthenticationError, ConflictError,
|
|
89
|
+
RateLimitError, StreamError, TimeoutError, PauthAPIError
|
|
90
|
+
} from 'pauth-js';
|
|
91
|
+
|
|
92
|
+
try {
|
|
93
|
+
const result = await client.verify('+819012345678');
|
|
94
|
+
} catch (err) {
|
|
95
|
+
if (err instanceof RateLimitError) {
|
|
96
|
+
console.log('Rate limited. Retry after:', err.retryAfter);
|
|
97
|
+
} else if (err instanceof ConflictError) {
|
|
98
|
+
console.log('Duplicate request detected');
|
|
99
|
+
} else if (err instanceof TimeoutError) {
|
|
100
|
+
console.log('Timed out waiting for call');
|
|
101
|
+
} else if (err instanceof AuthenticationError) {
|
|
102
|
+
console.log('Invalid or expired API key');
|
|
103
|
+
} else if (err instanceof PauthAPIError) {
|
|
104
|
+
console.log('API error:', err.status, err.message);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
| Error Class | Trigger |
|
|
110
|
+
|-------------|---------|
|
|
111
|
+
| `AuthenticationError` | 無効または期限切れのAPIキー/トークン (401) |
|
|
112
|
+
| `ConflictError` | 同一番号で認証が既に進行中 (409) |
|
|
113
|
+
| `RateLimitError` | レート制限超過 (429)。`err.retryAfter` (秒) を参照 |
|
|
114
|
+
| `StreamError` | SSEストリームエラー |
|
|
115
|
+
| `TimeoutError` | PIN待機タイムアウト |
|
|
116
|
+
| `PauthAPIError` | その他のAPIエラー。`err.status` でHTTPステータスを取得 |
|
|
117
|
+
|
|
118
|
+
## Examples
|
|
119
|
+
|
|
120
|
+
- [examples/node-basic](./examples/node-basic/) — Node.js での基本的な使い方
|
|
121
|
+
- [examples/nextjs-form](./examples/nextjs-form/) — Next.js (App Router) フォームサンプル
|
|
122
|
+
|
|
123
|
+
## License
|
|
124
|
+
|
|
125
|
+
MIT
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
interface PauthClientOptions {
|
|
2
|
+
apiKey: string;
|
|
3
|
+
baseUrl?: string;
|
|
4
|
+
}
|
|
5
|
+
interface AuthResponse {
|
|
6
|
+
token: string;
|
|
7
|
+
}
|
|
8
|
+
interface EntryEvent {
|
|
9
|
+
expires_in: number;
|
|
10
|
+
callerd_number: string;
|
|
11
|
+
pin: string | null;
|
|
12
|
+
}
|
|
13
|
+
interface VerifyResult {
|
|
14
|
+
callerNumber: string;
|
|
15
|
+
pin: string;
|
|
16
|
+
}
|
|
17
|
+
interface VerifyOptions {
|
|
18
|
+
onStep?: (step: 'authenticating' | 'waiting_for_call' | 'verifying_pin') => void;
|
|
19
|
+
signal?: AbortSignal;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
declare class PauthClient {
|
|
23
|
+
private apiKey;
|
|
24
|
+
private baseUrl;
|
|
25
|
+
private token;
|
|
26
|
+
private tokenExpiresAt;
|
|
27
|
+
constructor(options: PauthClientOptions);
|
|
28
|
+
/**
|
|
29
|
+
* APIキーでトークンを取得(内部キャッシュあり)
|
|
30
|
+
*/
|
|
31
|
+
authenticate(): Promise<string>;
|
|
32
|
+
/**
|
|
33
|
+
* SSEストリームで PIN を待ち受ける
|
|
34
|
+
* @param callerNumber 電話番号(国際形式: +819012345678)
|
|
35
|
+
* @param signal AbortSignal for cancellation
|
|
36
|
+
*/
|
|
37
|
+
entry(callerNumber: string, signal?: AbortSignal): Promise<EntryEvent>;
|
|
38
|
+
/**
|
|
39
|
+
* PIN照合
|
|
40
|
+
* @returns true: 認証成功, false: PIN不一致
|
|
41
|
+
*/
|
|
42
|
+
apply(callerNumber: string, pin: string): Promise<boolean>;
|
|
43
|
+
/**
|
|
44
|
+
* 電話番号認証の一括実行(authenticate + entry + apply)
|
|
45
|
+
* サンドボックス(test_ キー)では約2秒後に PIN=1234 が返る
|
|
46
|
+
*/
|
|
47
|
+
verify(callerNumber: string, options?: VerifyOptions): Promise<VerifyResult>;
|
|
48
|
+
private handleErrors;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
declare class PauthError extends Error {
|
|
52
|
+
constructor(message: string);
|
|
53
|
+
}
|
|
54
|
+
declare class AuthenticationError extends PauthError {
|
|
55
|
+
constructor();
|
|
56
|
+
}
|
|
57
|
+
declare class ConflictError extends PauthError {
|
|
58
|
+
constructor(callerNumber: string);
|
|
59
|
+
}
|
|
60
|
+
declare class RateLimitError extends PauthError {
|
|
61
|
+
retryAfter: number;
|
|
62
|
+
constructor(retryAfter: number);
|
|
63
|
+
}
|
|
64
|
+
declare class StreamError extends PauthError {
|
|
65
|
+
constructor(message: string);
|
|
66
|
+
}
|
|
67
|
+
declare class TimeoutError extends PauthError {
|
|
68
|
+
constructor();
|
|
69
|
+
}
|
|
70
|
+
declare class PauthAPIError extends PauthError {
|
|
71
|
+
status: number;
|
|
72
|
+
constructor(status: number, message: string);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export { type AuthResponse, AuthenticationError, ConflictError, type EntryEvent, PauthAPIError, PauthClient, type PauthClientOptions, PauthError, RateLimitError, StreamError, TimeoutError, type VerifyOptions, type VerifyResult };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
interface PauthClientOptions {
|
|
2
|
+
apiKey: string;
|
|
3
|
+
baseUrl?: string;
|
|
4
|
+
}
|
|
5
|
+
interface AuthResponse {
|
|
6
|
+
token: string;
|
|
7
|
+
}
|
|
8
|
+
interface EntryEvent {
|
|
9
|
+
expires_in: number;
|
|
10
|
+
callerd_number: string;
|
|
11
|
+
pin: string | null;
|
|
12
|
+
}
|
|
13
|
+
interface VerifyResult {
|
|
14
|
+
callerNumber: string;
|
|
15
|
+
pin: string;
|
|
16
|
+
}
|
|
17
|
+
interface VerifyOptions {
|
|
18
|
+
onStep?: (step: 'authenticating' | 'waiting_for_call' | 'verifying_pin') => void;
|
|
19
|
+
signal?: AbortSignal;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
declare class PauthClient {
|
|
23
|
+
private apiKey;
|
|
24
|
+
private baseUrl;
|
|
25
|
+
private token;
|
|
26
|
+
private tokenExpiresAt;
|
|
27
|
+
constructor(options: PauthClientOptions);
|
|
28
|
+
/**
|
|
29
|
+
* APIキーでトークンを取得(内部キャッシュあり)
|
|
30
|
+
*/
|
|
31
|
+
authenticate(): Promise<string>;
|
|
32
|
+
/**
|
|
33
|
+
* SSEストリームで PIN を待ち受ける
|
|
34
|
+
* @param callerNumber 電話番号(国際形式: +819012345678)
|
|
35
|
+
* @param signal AbortSignal for cancellation
|
|
36
|
+
*/
|
|
37
|
+
entry(callerNumber: string, signal?: AbortSignal): Promise<EntryEvent>;
|
|
38
|
+
/**
|
|
39
|
+
* PIN照合
|
|
40
|
+
* @returns true: 認証成功, false: PIN不一致
|
|
41
|
+
*/
|
|
42
|
+
apply(callerNumber: string, pin: string): Promise<boolean>;
|
|
43
|
+
/**
|
|
44
|
+
* 電話番号認証の一括実行(authenticate + entry + apply)
|
|
45
|
+
* サンドボックス(test_ キー)では約2秒後に PIN=1234 が返る
|
|
46
|
+
*/
|
|
47
|
+
verify(callerNumber: string, options?: VerifyOptions): Promise<VerifyResult>;
|
|
48
|
+
private handleErrors;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
declare class PauthError extends Error {
|
|
52
|
+
constructor(message: string);
|
|
53
|
+
}
|
|
54
|
+
declare class AuthenticationError extends PauthError {
|
|
55
|
+
constructor();
|
|
56
|
+
}
|
|
57
|
+
declare class ConflictError extends PauthError {
|
|
58
|
+
constructor(callerNumber: string);
|
|
59
|
+
}
|
|
60
|
+
declare class RateLimitError extends PauthError {
|
|
61
|
+
retryAfter: number;
|
|
62
|
+
constructor(retryAfter: number);
|
|
63
|
+
}
|
|
64
|
+
declare class StreamError extends PauthError {
|
|
65
|
+
constructor(message: string);
|
|
66
|
+
}
|
|
67
|
+
declare class TimeoutError extends PauthError {
|
|
68
|
+
constructor();
|
|
69
|
+
}
|
|
70
|
+
declare class PauthAPIError extends PauthError {
|
|
71
|
+
status: number;
|
|
72
|
+
constructor(status: number, message: string);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export { type AuthResponse, AuthenticationError, ConflictError, type EntryEvent, PauthAPIError, PauthClient, type PauthClientOptions, PauthError, RateLimitError, StreamError, TimeoutError, type VerifyOptions, type VerifyResult };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
AuthenticationError: () => AuthenticationError,
|
|
24
|
+
ConflictError: () => ConflictError,
|
|
25
|
+
PauthAPIError: () => PauthAPIError,
|
|
26
|
+
PauthClient: () => PauthClient,
|
|
27
|
+
PauthError: () => PauthError,
|
|
28
|
+
RateLimitError: () => RateLimitError,
|
|
29
|
+
StreamError: () => StreamError,
|
|
30
|
+
TimeoutError: () => TimeoutError
|
|
31
|
+
});
|
|
32
|
+
module.exports = __toCommonJS(index_exports);
|
|
33
|
+
|
|
34
|
+
// src/errors.ts
|
|
35
|
+
var PauthError = class extends Error {
|
|
36
|
+
constructor(message) {
|
|
37
|
+
super(message);
|
|
38
|
+
this.name = "PauthError";
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
var AuthenticationError = class extends PauthError {
|
|
42
|
+
constructor() {
|
|
43
|
+
super("Authentication failed: invalid or expired API key / token");
|
|
44
|
+
this.name = "AuthenticationError";
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
var ConflictError = class extends PauthError {
|
|
48
|
+
constructor(callerNumber) {
|
|
49
|
+
super(`Authentication already in progress for ${callerNumber}`);
|
|
50
|
+
this.name = "ConflictError";
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
var RateLimitError = class extends PauthError {
|
|
54
|
+
constructor(retryAfter) {
|
|
55
|
+
super(`Rate limit exceeded. Retry after ${retryAfter} seconds`);
|
|
56
|
+
this.name = "RateLimitError";
|
|
57
|
+
this.retryAfter = retryAfter;
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
var StreamError = class extends PauthError {
|
|
61
|
+
constructor(message) {
|
|
62
|
+
super(`SSE stream error: ${message}`);
|
|
63
|
+
this.name = "StreamError";
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
var TimeoutError = class extends PauthError {
|
|
67
|
+
constructor() {
|
|
68
|
+
super("SSE stream timed out waiting for PIN");
|
|
69
|
+
this.name = "TimeoutError";
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
var PauthAPIError = class extends PauthError {
|
|
73
|
+
constructor(status, message) {
|
|
74
|
+
super(`API error ${status}: ${message}`);
|
|
75
|
+
this.name = "PauthAPIError";
|
|
76
|
+
this.status = status;
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
// src/sse.ts
|
|
81
|
+
async function readSSEStream(url, token, signal) {
|
|
82
|
+
const response = await fetch(url, {
|
|
83
|
+
headers: {
|
|
84
|
+
Authorization: `Bearer ${token}`,
|
|
85
|
+
Accept: "text/event-stream"
|
|
86
|
+
},
|
|
87
|
+
signal
|
|
88
|
+
});
|
|
89
|
+
if (!response.ok) {
|
|
90
|
+
throw new StreamError(`HTTP ${response.status}`);
|
|
91
|
+
}
|
|
92
|
+
if (!response.body) {
|
|
93
|
+
throw new StreamError("Response body is null");
|
|
94
|
+
}
|
|
95
|
+
const reader = response.body.getReader();
|
|
96
|
+
const decoder = new TextDecoder();
|
|
97
|
+
let buffer = "";
|
|
98
|
+
try {
|
|
99
|
+
while (true) {
|
|
100
|
+
const { done, value } = await reader.read();
|
|
101
|
+
if (done) break;
|
|
102
|
+
buffer += decoder.decode(value, { stream: true });
|
|
103
|
+
const events = buffer.split("\n\n");
|
|
104
|
+
buffer = events.pop() ?? "";
|
|
105
|
+
for (const event of events) {
|
|
106
|
+
const line = event.trim();
|
|
107
|
+
if (!line.startsWith("data:")) continue;
|
|
108
|
+
const dataStr = line.slice("data:".length).trim();
|
|
109
|
+
if (!dataStr || dataStr === "{}") continue;
|
|
110
|
+
try {
|
|
111
|
+
const data = JSON.parse(dataStr);
|
|
112
|
+
if (data.pin !== null && data.pin !== void 0) {
|
|
113
|
+
reader.cancel();
|
|
114
|
+
return data;
|
|
115
|
+
}
|
|
116
|
+
} catch {
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
} catch (err) {
|
|
121
|
+
if (err instanceof Error && err.name === "AbortError") {
|
|
122
|
+
throw err;
|
|
123
|
+
}
|
|
124
|
+
throw new StreamError(err instanceof Error ? err.message : "Unknown error");
|
|
125
|
+
} finally {
|
|
126
|
+
reader.releaseLock();
|
|
127
|
+
}
|
|
128
|
+
throw new TimeoutError();
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// src/client.ts
|
|
132
|
+
var PauthClient = class {
|
|
133
|
+
constructor(options) {
|
|
134
|
+
this.token = null;
|
|
135
|
+
this.tokenExpiresAt = 0;
|
|
136
|
+
this.apiKey = options.apiKey;
|
|
137
|
+
this.baseUrl = options.baseUrl ?? "https://pauth.me";
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* APIキーでトークンを取得(内部キャッシュあり)
|
|
141
|
+
*/
|
|
142
|
+
async authenticate() {
|
|
143
|
+
if (this.token && Date.now() < this.tokenExpiresAt - 3e4) {
|
|
144
|
+
return this.token;
|
|
145
|
+
}
|
|
146
|
+
const response = await fetch(`${this.baseUrl}/api/v1/auth`, {
|
|
147
|
+
headers: { "api-key": this.apiKey }
|
|
148
|
+
});
|
|
149
|
+
await this.handleErrors(response);
|
|
150
|
+
const data = await response.json();
|
|
151
|
+
this.token = data.token;
|
|
152
|
+
this.tokenExpiresAt = Date.now() + 6e5;
|
|
153
|
+
return this.token;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* SSEストリームで PIN を待ち受ける
|
|
157
|
+
* @param callerNumber 電話番号(国際形式: +819012345678)
|
|
158
|
+
* @param signal AbortSignal for cancellation
|
|
159
|
+
*/
|
|
160
|
+
async entry(callerNumber, signal) {
|
|
161
|
+
const token = await this.authenticate();
|
|
162
|
+
const encodedNumber = encodeURIComponent(callerNumber);
|
|
163
|
+
const url = `${this.baseUrl}/api/v1/entry/${encodedNumber}`;
|
|
164
|
+
return readSSEStream(url, token, signal);
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* PIN照合
|
|
168
|
+
* @returns true: 認証成功, false: PIN不一致
|
|
169
|
+
*/
|
|
170
|
+
async apply(callerNumber, pin) {
|
|
171
|
+
const token = await this.authenticate();
|
|
172
|
+
const params = new URLSearchParams({
|
|
173
|
+
callerd_number: callerNumber,
|
|
174
|
+
pin
|
|
175
|
+
});
|
|
176
|
+
const response = await fetch(
|
|
177
|
+
`${this.baseUrl}/api/v1/apply?${params}`,
|
|
178
|
+
{ headers: { Authorization: `Bearer ${token}` } }
|
|
179
|
+
);
|
|
180
|
+
if (response.status === 200) return true;
|
|
181
|
+
if (response.status === 204) return false;
|
|
182
|
+
await this.handleErrors(response);
|
|
183
|
+
return false;
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* 電話番号認証の一括実行(authenticate + entry + apply)
|
|
187
|
+
* サンドボックス(test_ キー)では約2秒後に PIN=1234 が返る
|
|
188
|
+
*/
|
|
189
|
+
async verify(callerNumber, options) {
|
|
190
|
+
options?.onStep?.("authenticating");
|
|
191
|
+
await this.authenticate();
|
|
192
|
+
options?.onStep?.("waiting_for_call");
|
|
193
|
+
const entryResult = await this.entry(callerNumber, options?.signal);
|
|
194
|
+
if (!entryResult.pin) {
|
|
195
|
+
throw new Error("PIN not received from SSE stream");
|
|
196
|
+
}
|
|
197
|
+
options?.onStep?.("verifying_pin");
|
|
198
|
+
await this.apply(callerNumber, entryResult.pin);
|
|
199
|
+
return {
|
|
200
|
+
callerNumber,
|
|
201
|
+
pin: entryResult.pin
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
async handleErrors(response) {
|
|
205
|
+
if (response.ok) return;
|
|
206
|
+
switch (response.status) {
|
|
207
|
+
case 401:
|
|
208
|
+
this.token = null;
|
|
209
|
+
this.tokenExpiresAt = 0;
|
|
210
|
+
throw new AuthenticationError();
|
|
211
|
+
case 409:
|
|
212
|
+
throw new ConflictError("unknown");
|
|
213
|
+
case 429: {
|
|
214
|
+
const retryAfter = parseInt(response.headers.get("Retry-After") ?? "60", 10);
|
|
215
|
+
throw new RateLimitError(retryAfter);
|
|
216
|
+
}
|
|
217
|
+
default: {
|
|
218
|
+
let message = response.statusText;
|
|
219
|
+
try {
|
|
220
|
+
const body = await response.json();
|
|
221
|
+
if (body.message) message = body.message;
|
|
222
|
+
} catch {
|
|
223
|
+
}
|
|
224
|
+
throw new PauthAPIError(response.status, message);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
};
|
|
229
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
230
|
+
0 && (module.exports = {
|
|
231
|
+
AuthenticationError,
|
|
232
|
+
ConflictError,
|
|
233
|
+
PauthAPIError,
|
|
234
|
+
PauthClient,
|
|
235
|
+
PauthError,
|
|
236
|
+
RateLimitError,
|
|
237
|
+
StreamError,
|
|
238
|
+
TimeoutError
|
|
239
|
+
});
|
|
240
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/sse.ts","../src/client.ts"],"sourcesContent":["export { PauthClient } from './client';\r\nexport type {\r\n PauthClientOptions,\r\n AuthResponse,\r\n EntryEvent,\r\n VerifyResult,\r\n VerifyOptions,\r\n} from './types';\r\nexport {\r\n PauthError,\r\n AuthenticationError,\r\n ConflictError,\r\n RateLimitError,\r\n StreamError,\r\n TimeoutError,\r\n PauthAPIError,\r\n} from './errors';\r\n","export class PauthError extends Error {\r\n constructor(message: string) {\r\n super(message);\r\n this.name = 'PauthError';\r\n }\r\n}\r\n\r\nexport class AuthenticationError extends PauthError {\r\n constructor() {\r\n super('Authentication failed: invalid or expired API key / token');\r\n this.name = 'AuthenticationError';\r\n }\r\n}\r\n\r\nexport class ConflictError extends PauthError {\r\n constructor(callerNumber: string) {\r\n super(`Authentication already in progress for ${callerNumber}`);\r\n this.name = 'ConflictError';\r\n }\r\n}\r\n\r\nexport class RateLimitError extends PauthError {\r\n retryAfter: number;\r\n constructor(retryAfter: number) {\r\n super(`Rate limit exceeded. Retry after ${retryAfter} seconds`);\r\n this.name = 'RateLimitError';\r\n this.retryAfter = retryAfter;\r\n }\r\n}\r\n\r\nexport class StreamError extends PauthError {\r\n constructor(message: string) {\r\n super(`SSE stream error: ${message}`);\r\n this.name = 'StreamError';\r\n }\r\n}\r\n\r\nexport class TimeoutError extends PauthError {\r\n constructor() {\r\n super('SSE stream timed out waiting for PIN');\r\n this.name = 'TimeoutError';\r\n }\r\n}\r\n\r\nexport class PauthAPIError extends PauthError {\r\n status: number;\r\n constructor(status: number, message: string) {\r\n super(`API error ${status}: ${message}`);\r\n this.name = 'PauthAPIError';\r\n this.status = status;\r\n }\r\n}\r\n","import { StreamError, TimeoutError } from './errors';\r\nimport type { EntryEvent } from './types';\r\n\r\n/**\r\n * SSEストリームを読み取り、PIN受信で resolve する Promise を返す\r\n * @param url SSEエンドポイントURL\r\n * @param token Bearer token\r\n * @param signal AbortSignal for cancellation\r\n */\r\nexport async function readSSEStream(\r\n url: string,\r\n token: string,\r\n signal?: AbortSignal\r\n): Promise<EntryEvent> {\r\n const response = await fetch(url, {\r\n headers: {\r\n Authorization: `Bearer ${token}`,\r\n Accept: 'text/event-stream',\r\n },\r\n signal,\r\n });\r\n\r\n if (!response.ok) {\r\n throw new StreamError(`HTTP ${response.status}`);\r\n }\r\n\r\n if (!response.body) {\r\n throw new StreamError('Response body is null');\r\n }\r\n\r\n const reader = response.body.getReader();\r\n const decoder = new TextDecoder();\r\n let buffer = '';\r\n\r\n try {\r\n while (true) {\r\n const { done, value } = await reader.read();\r\n if (done) break;\r\n\r\n buffer += decoder.decode(value, { stream: true });\r\n\r\n // \\n\\n をイベント区切りとしてパース\r\n const events = buffer.split('\\n\\n');\r\n buffer = events.pop() ?? ''; // 最後の不完全なチャンクをバッファに戻す\r\n\r\n for (const event of events) {\r\n const line = event.trim();\r\n if (!line.startsWith('data:')) continue;\r\n\r\n const dataStr = line.slice('data:'.length).trim();\r\n if (!dataStr || dataStr === '{}') continue;\r\n\r\n try {\r\n const data = JSON.parse(dataStr) as EntryEvent;\r\n if (data.pin !== null && data.pin !== undefined) {\r\n // PIN受信 → ストリーム終了\r\n reader.cancel();\r\n return data;\r\n }\r\n } catch {\r\n // パースエラーは無視(不完全なチャンクの残留の可能性)\r\n }\r\n }\r\n }\r\n } catch (err) {\r\n if (err instanceof Error && err.name === 'AbortError') {\r\n throw err; // キャンセルはそのままスロー\r\n }\r\n throw new StreamError(err instanceof Error ? err.message : 'Unknown error');\r\n } finally {\r\n reader.releaseLock();\r\n }\r\n\r\n throw new TimeoutError();\r\n}\r\n","import { readSSEStream } from './sse';\r\nimport {\r\n AuthenticationError, ConflictError, RateLimitError, PauthAPIError\r\n} from './errors';\r\nimport type {\r\n PauthClientOptions, AuthResponse, VerifyResult, VerifyOptions\r\n} from './types';\r\n\r\nexport class PauthClient {\r\n private apiKey: string;\r\n private baseUrl: string;\r\n private token: string | null = null;\r\n private tokenExpiresAt: number = 0;\r\n\r\n constructor(options: PauthClientOptions) {\r\n this.apiKey = options.apiKey;\r\n this.baseUrl = options.baseUrl ?? 'https://pauth.me';\r\n }\r\n\r\n /**\r\n * APIキーでトークンを取得(内部キャッシュあり)\r\n */\r\n async authenticate(): Promise<string> {\r\n // キャッシュが有効なら再利用(30秒マージン)\r\n if (this.token && Date.now() < this.tokenExpiresAt - 30_000) {\r\n return this.token;\r\n }\r\n\r\n const response = await fetch(`${this.baseUrl}/api/v1/auth`, {\r\n headers: { 'api-key': this.apiKey },\r\n });\r\n\r\n await this.handleErrors(response);\r\n\r\n const data = (await response.json()) as AuthResponse;\r\n this.token = data.token;\r\n this.tokenExpiresAt = Date.now() + 600_000; // 600秒\r\n return this.token;\r\n }\r\n\r\n /**\r\n * SSEストリームで PIN を待ち受ける\r\n * @param callerNumber 電話番号(国際形式: +819012345678)\r\n * @param signal AbortSignal for cancellation\r\n */\r\n async entry(callerNumber: string, signal?: AbortSignal) {\r\n const token = await this.authenticate();\r\n // 公開メソッドは callerNumber(正しいスペル)、API送信時は callerd_number(APIのtypo)\r\n const encodedNumber = encodeURIComponent(callerNumber);\r\n const url = `${this.baseUrl}/api/v1/entry/${encodedNumber}`;\r\n return readSSEStream(url, token, signal);\r\n }\r\n\r\n /**\r\n * PIN照合\r\n * @returns true: 認証成功, false: PIN不一致\r\n */\r\n async apply(callerNumber: string, pin: string): Promise<boolean> {\r\n const token = await this.authenticate();\r\n const params = new URLSearchParams({\r\n callerd_number: callerNumber,\r\n pin,\r\n });\r\n const response = await fetch(\r\n `${this.baseUrl}/api/v1/apply?${params}`,\r\n { headers: { Authorization: `Bearer ${token}` } }\r\n );\r\n\r\n if (response.status === 200) return true;\r\n if (response.status === 204) return false;\r\n\r\n await this.handleErrors(response);\r\n return false;\r\n }\r\n\r\n /**\r\n * 電話番号認証の一括実行(authenticate + entry + apply)\r\n * サンドボックス(test_ キー)では約2秒後に PIN=1234 が返る\r\n */\r\n async verify(callerNumber: string, options?: VerifyOptions): Promise<VerifyResult> {\r\n options?.onStep?.('authenticating');\r\n await this.authenticate();\r\n\r\n options?.onStep?.('waiting_for_call');\r\n const entryResult = await this.entry(callerNumber, options?.signal);\r\n\r\n if (!entryResult.pin) {\r\n throw new Error('PIN not received from SSE stream');\r\n }\r\n\r\n options?.onStep?.('verifying_pin');\r\n await this.apply(callerNumber, entryResult.pin);\r\n\r\n return {\r\n callerNumber,\r\n pin: entryResult.pin,\r\n };\r\n }\r\n\r\n private async handleErrors(response: Response): Promise<void> {\r\n if (response.ok) return;\r\n\r\n switch (response.status) {\r\n case 401:\r\n // トークンをクリアして次回再取得\r\n this.token = null;\r\n this.tokenExpiresAt = 0;\r\n throw new AuthenticationError();\r\n case 409:\r\n throw new ConflictError('unknown');\r\n case 429: {\r\n const retryAfter = parseInt(response.headers.get('Retry-After') ?? '60', 10);\r\n throw new RateLimitError(retryAfter);\r\n }\r\n default: {\r\n let message = response.statusText;\r\n try {\r\n const body = await response.json() as { message?: string };\r\n if (body.message) message = body.message;\r\n } catch { /* ignore */ }\r\n throw new PauthAPIError(response.status, message);\r\n }\r\n }\r\n }\r\n}\r\n"],"mappings":"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","names":[]}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
// src/errors.ts
|
|
2
|
+
var PauthError = class extends Error {
|
|
3
|
+
constructor(message) {
|
|
4
|
+
super(message);
|
|
5
|
+
this.name = "PauthError";
|
|
6
|
+
}
|
|
7
|
+
};
|
|
8
|
+
var AuthenticationError = class extends PauthError {
|
|
9
|
+
constructor() {
|
|
10
|
+
super("Authentication failed: invalid or expired API key / token");
|
|
11
|
+
this.name = "AuthenticationError";
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
var ConflictError = class extends PauthError {
|
|
15
|
+
constructor(callerNumber) {
|
|
16
|
+
super(`Authentication already in progress for ${callerNumber}`);
|
|
17
|
+
this.name = "ConflictError";
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
var RateLimitError = class extends PauthError {
|
|
21
|
+
constructor(retryAfter) {
|
|
22
|
+
super(`Rate limit exceeded. Retry after ${retryAfter} seconds`);
|
|
23
|
+
this.name = "RateLimitError";
|
|
24
|
+
this.retryAfter = retryAfter;
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
var StreamError = class extends PauthError {
|
|
28
|
+
constructor(message) {
|
|
29
|
+
super(`SSE stream error: ${message}`);
|
|
30
|
+
this.name = "StreamError";
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
var TimeoutError = class extends PauthError {
|
|
34
|
+
constructor() {
|
|
35
|
+
super("SSE stream timed out waiting for PIN");
|
|
36
|
+
this.name = "TimeoutError";
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
var PauthAPIError = class extends PauthError {
|
|
40
|
+
constructor(status, message) {
|
|
41
|
+
super(`API error ${status}: ${message}`);
|
|
42
|
+
this.name = "PauthAPIError";
|
|
43
|
+
this.status = status;
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
// src/sse.ts
|
|
48
|
+
async function readSSEStream(url, token, signal) {
|
|
49
|
+
const response = await fetch(url, {
|
|
50
|
+
headers: {
|
|
51
|
+
Authorization: `Bearer ${token}`,
|
|
52
|
+
Accept: "text/event-stream"
|
|
53
|
+
},
|
|
54
|
+
signal
|
|
55
|
+
});
|
|
56
|
+
if (!response.ok) {
|
|
57
|
+
throw new StreamError(`HTTP ${response.status}`);
|
|
58
|
+
}
|
|
59
|
+
if (!response.body) {
|
|
60
|
+
throw new StreamError("Response body is null");
|
|
61
|
+
}
|
|
62
|
+
const reader = response.body.getReader();
|
|
63
|
+
const decoder = new TextDecoder();
|
|
64
|
+
let buffer = "";
|
|
65
|
+
try {
|
|
66
|
+
while (true) {
|
|
67
|
+
const { done, value } = await reader.read();
|
|
68
|
+
if (done) break;
|
|
69
|
+
buffer += decoder.decode(value, { stream: true });
|
|
70
|
+
const events = buffer.split("\n\n");
|
|
71
|
+
buffer = events.pop() ?? "";
|
|
72
|
+
for (const event of events) {
|
|
73
|
+
const line = event.trim();
|
|
74
|
+
if (!line.startsWith("data:")) continue;
|
|
75
|
+
const dataStr = line.slice("data:".length).trim();
|
|
76
|
+
if (!dataStr || dataStr === "{}") continue;
|
|
77
|
+
try {
|
|
78
|
+
const data = JSON.parse(dataStr);
|
|
79
|
+
if (data.pin !== null && data.pin !== void 0) {
|
|
80
|
+
reader.cancel();
|
|
81
|
+
return data;
|
|
82
|
+
}
|
|
83
|
+
} catch {
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
} catch (err) {
|
|
88
|
+
if (err instanceof Error && err.name === "AbortError") {
|
|
89
|
+
throw err;
|
|
90
|
+
}
|
|
91
|
+
throw new StreamError(err instanceof Error ? err.message : "Unknown error");
|
|
92
|
+
} finally {
|
|
93
|
+
reader.releaseLock();
|
|
94
|
+
}
|
|
95
|
+
throw new TimeoutError();
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// src/client.ts
|
|
99
|
+
var PauthClient = class {
|
|
100
|
+
constructor(options) {
|
|
101
|
+
this.token = null;
|
|
102
|
+
this.tokenExpiresAt = 0;
|
|
103
|
+
this.apiKey = options.apiKey;
|
|
104
|
+
this.baseUrl = options.baseUrl ?? "https://pauth.me";
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* APIキーでトークンを取得(内部キャッシュあり)
|
|
108
|
+
*/
|
|
109
|
+
async authenticate() {
|
|
110
|
+
if (this.token && Date.now() < this.tokenExpiresAt - 3e4) {
|
|
111
|
+
return this.token;
|
|
112
|
+
}
|
|
113
|
+
const response = await fetch(`${this.baseUrl}/api/v1/auth`, {
|
|
114
|
+
headers: { "api-key": this.apiKey }
|
|
115
|
+
});
|
|
116
|
+
await this.handleErrors(response);
|
|
117
|
+
const data = await response.json();
|
|
118
|
+
this.token = data.token;
|
|
119
|
+
this.tokenExpiresAt = Date.now() + 6e5;
|
|
120
|
+
return this.token;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* SSEストリームで PIN を待ち受ける
|
|
124
|
+
* @param callerNumber 電話番号(国際形式: +819012345678)
|
|
125
|
+
* @param signal AbortSignal for cancellation
|
|
126
|
+
*/
|
|
127
|
+
async entry(callerNumber, signal) {
|
|
128
|
+
const token = await this.authenticate();
|
|
129
|
+
const encodedNumber = encodeURIComponent(callerNumber);
|
|
130
|
+
const url = `${this.baseUrl}/api/v1/entry/${encodedNumber}`;
|
|
131
|
+
return readSSEStream(url, token, signal);
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* PIN照合
|
|
135
|
+
* @returns true: 認証成功, false: PIN不一致
|
|
136
|
+
*/
|
|
137
|
+
async apply(callerNumber, pin) {
|
|
138
|
+
const token = await this.authenticate();
|
|
139
|
+
const params = new URLSearchParams({
|
|
140
|
+
callerd_number: callerNumber,
|
|
141
|
+
pin
|
|
142
|
+
});
|
|
143
|
+
const response = await fetch(
|
|
144
|
+
`${this.baseUrl}/api/v1/apply?${params}`,
|
|
145
|
+
{ headers: { Authorization: `Bearer ${token}` } }
|
|
146
|
+
);
|
|
147
|
+
if (response.status === 200) return true;
|
|
148
|
+
if (response.status === 204) return false;
|
|
149
|
+
await this.handleErrors(response);
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* 電話番号認証の一括実行(authenticate + entry + apply)
|
|
154
|
+
* サンドボックス(test_ キー)では約2秒後に PIN=1234 が返る
|
|
155
|
+
*/
|
|
156
|
+
async verify(callerNumber, options) {
|
|
157
|
+
options?.onStep?.("authenticating");
|
|
158
|
+
await this.authenticate();
|
|
159
|
+
options?.onStep?.("waiting_for_call");
|
|
160
|
+
const entryResult = await this.entry(callerNumber, options?.signal);
|
|
161
|
+
if (!entryResult.pin) {
|
|
162
|
+
throw new Error("PIN not received from SSE stream");
|
|
163
|
+
}
|
|
164
|
+
options?.onStep?.("verifying_pin");
|
|
165
|
+
await this.apply(callerNumber, entryResult.pin);
|
|
166
|
+
return {
|
|
167
|
+
callerNumber,
|
|
168
|
+
pin: entryResult.pin
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
async handleErrors(response) {
|
|
172
|
+
if (response.ok) return;
|
|
173
|
+
switch (response.status) {
|
|
174
|
+
case 401:
|
|
175
|
+
this.token = null;
|
|
176
|
+
this.tokenExpiresAt = 0;
|
|
177
|
+
throw new AuthenticationError();
|
|
178
|
+
case 409:
|
|
179
|
+
throw new ConflictError("unknown");
|
|
180
|
+
case 429: {
|
|
181
|
+
const retryAfter = parseInt(response.headers.get("Retry-After") ?? "60", 10);
|
|
182
|
+
throw new RateLimitError(retryAfter);
|
|
183
|
+
}
|
|
184
|
+
default: {
|
|
185
|
+
let message = response.statusText;
|
|
186
|
+
try {
|
|
187
|
+
const body = await response.json();
|
|
188
|
+
if (body.message) message = body.message;
|
|
189
|
+
} catch {
|
|
190
|
+
}
|
|
191
|
+
throw new PauthAPIError(response.status, message);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
export {
|
|
197
|
+
AuthenticationError,
|
|
198
|
+
ConflictError,
|
|
199
|
+
PauthAPIError,
|
|
200
|
+
PauthClient,
|
|
201
|
+
PauthError,
|
|
202
|
+
RateLimitError,
|
|
203
|
+
StreamError,
|
|
204
|
+
TimeoutError
|
|
205
|
+
};
|
|
206
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts","../src/sse.ts","../src/client.ts"],"sourcesContent":["export class PauthError extends Error {\r\n constructor(message: string) {\r\n super(message);\r\n this.name = 'PauthError';\r\n }\r\n}\r\n\r\nexport class AuthenticationError extends PauthError {\r\n constructor() {\r\n super('Authentication failed: invalid or expired API key / token');\r\n this.name = 'AuthenticationError';\r\n }\r\n}\r\n\r\nexport class ConflictError extends PauthError {\r\n constructor(callerNumber: string) {\r\n super(`Authentication already in progress for ${callerNumber}`);\r\n this.name = 'ConflictError';\r\n }\r\n}\r\n\r\nexport class RateLimitError extends PauthError {\r\n retryAfter: number;\r\n constructor(retryAfter: number) {\r\n super(`Rate limit exceeded. Retry after ${retryAfter} seconds`);\r\n this.name = 'RateLimitError';\r\n this.retryAfter = retryAfter;\r\n }\r\n}\r\n\r\nexport class StreamError extends PauthError {\r\n constructor(message: string) {\r\n super(`SSE stream error: ${message}`);\r\n this.name = 'StreamError';\r\n }\r\n}\r\n\r\nexport class TimeoutError extends PauthError {\r\n constructor() {\r\n super('SSE stream timed out waiting for PIN');\r\n this.name = 'TimeoutError';\r\n }\r\n}\r\n\r\nexport class PauthAPIError extends PauthError {\r\n status: number;\r\n constructor(status: number, message: string) {\r\n super(`API error ${status}: ${message}`);\r\n this.name = 'PauthAPIError';\r\n this.status = status;\r\n }\r\n}\r\n","import { StreamError, TimeoutError } from './errors';\r\nimport type { EntryEvent } from './types';\r\n\r\n/**\r\n * SSEストリームを読み取り、PIN受信で resolve する Promise を返す\r\n * @param url SSEエンドポイントURL\r\n * @param token Bearer token\r\n * @param signal AbortSignal for cancellation\r\n */\r\nexport async function readSSEStream(\r\n url: string,\r\n token: string,\r\n signal?: AbortSignal\r\n): Promise<EntryEvent> {\r\n const response = await fetch(url, {\r\n headers: {\r\n Authorization: `Bearer ${token}`,\r\n Accept: 'text/event-stream',\r\n },\r\n signal,\r\n });\r\n\r\n if (!response.ok) {\r\n throw new StreamError(`HTTP ${response.status}`);\r\n }\r\n\r\n if (!response.body) {\r\n throw new StreamError('Response body is null');\r\n }\r\n\r\n const reader = response.body.getReader();\r\n const decoder = new TextDecoder();\r\n let buffer = '';\r\n\r\n try {\r\n while (true) {\r\n const { done, value } = await reader.read();\r\n if (done) break;\r\n\r\n buffer += decoder.decode(value, { stream: true });\r\n\r\n // \\n\\n をイベント区切りとしてパース\r\n const events = buffer.split('\\n\\n');\r\n buffer = events.pop() ?? ''; // 最後の不完全なチャンクをバッファに戻す\r\n\r\n for (const event of events) {\r\n const line = event.trim();\r\n if (!line.startsWith('data:')) continue;\r\n\r\n const dataStr = line.slice('data:'.length).trim();\r\n if (!dataStr || dataStr === '{}') continue;\r\n\r\n try {\r\n const data = JSON.parse(dataStr) as EntryEvent;\r\n if (data.pin !== null && data.pin !== undefined) {\r\n // PIN受信 → ストリーム終了\r\n reader.cancel();\r\n return data;\r\n }\r\n } catch {\r\n // パースエラーは無視(不完全なチャンクの残留の可能性)\r\n }\r\n }\r\n }\r\n } catch (err) {\r\n if (err instanceof Error && err.name === 'AbortError') {\r\n throw err; // キャンセルはそのままスロー\r\n }\r\n throw new StreamError(err instanceof Error ? err.message : 'Unknown error');\r\n } finally {\r\n reader.releaseLock();\r\n }\r\n\r\n throw new TimeoutError();\r\n}\r\n","import { readSSEStream } from './sse';\r\nimport {\r\n AuthenticationError, ConflictError, RateLimitError, PauthAPIError\r\n} from './errors';\r\nimport type {\r\n PauthClientOptions, AuthResponse, VerifyResult, VerifyOptions\r\n} from './types';\r\n\r\nexport class PauthClient {\r\n private apiKey: string;\r\n private baseUrl: string;\r\n private token: string | null = null;\r\n private tokenExpiresAt: number = 0;\r\n\r\n constructor(options: PauthClientOptions) {\r\n this.apiKey = options.apiKey;\r\n this.baseUrl = options.baseUrl ?? 'https://pauth.me';\r\n }\r\n\r\n /**\r\n * APIキーでトークンを取得(内部キャッシュあり)\r\n */\r\n async authenticate(): Promise<string> {\r\n // キャッシュが有効なら再利用(30秒マージン)\r\n if (this.token && Date.now() < this.tokenExpiresAt - 30_000) {\r\n return this.token;\r\n }\r\n\r\n const response = await fetch(`${this.baseUrl}/api/v1/auth`, {\r\n headers: { 'api-key': this.apiKey },\r\n });\r\n\r\n await this.handleErrors(response);\r\n\r\n const data = (await response.json()) as AuthResponse;\r\n this.token = data.token;\r\n this.tokenExpiresAt = Date.now() + 600_000; // 600秒\r\n return this.token;\r\n }\r\n\r\n /**\r\n * SSEストリームで PIN を待ち受ける\r\n * @param callerNumber 電話番号(国際形式: +819012345678)\r\n * @param signal AbortSignal for cancellation\r\n */\r\n async entry(callerNumber: string, signal?: AbortSignal) {\r\n const token = await this.authenticate();\r\n // 公開メソッドは callerNumber(正しいスペル)、API送信時は callerd_number(APIのtypo)\r\n const encodedNumber = encodeURIComponent(callerNumber);\r\n const url = `${this.baseUrl}/api/v1/entry/${encodedNumber}`;\r\n return readSSEStream(url, token, signal);\r\n }\r\n\r\n /**\r\n * PIN照合\r\n * @returns true: 認証成功, false: PIN不一致\r\n */\r\n async apply(callerNumber: string, pin: string): Promise<boolean> {\r\n const token = await this.authenticate();\r\n const params = new URLSearchParams({\r\n callerd_number: callerNumber,\r\n pin,\r\n });\r\n const response = await fetch(\r\n `${this.baseUrl}/api/v1/apply?${params}`,\r\n { headers: { Authorization: `Bearer ${token}` } }\r\n );\r\n\r\n if (response.status === 200) return true;\r\n if (response.status === 204) return false;\r\n\r\n await this.handleErrors(response);\r\n return false;\r\n }\r\n\r\n /**\r\n * 電話番号認証の一括実行(authenticate + entry + apply)\r\n * サンドボックス(test_ キー)では約2秒後に PIN=1234 が返る\r\n */\r\n async verify(callerNumber: string, options?: VerifyOptions): Promise<VerifyResult> {\r\n options?.onStep?.('authenticating');\r\n await this.authenticate();\r\n\r\n options?.onStep?.('waiting_for_call');\r\n const entryResult = await this.entry(callerNumber, options?.signal);\r\n\r\n if (!entryResult.pin) {\r\n throw new Error('PIN not received from SSE stream');\r\n }\r\n\r\n options?.onStep?.('verifying_pin');\r\n await this.apply(callerNumber, entryResult.pin);\r\n\r\n return {\r\n callerNumber,\r\n pin: entryResult.pin,\r\n };\r\n }\r\n\r\n private async handleErrors(response: Response): Promise<void> {\r\n if (response.ok) return;\r\n\r\n switch (response.status) {\r\n case 401:\r\n // トークンをクリアして次回再取得\r\n this.token = null;\r\n this.tokenExpiresAt = 0;\r\n throw new AuthenticationError();\r\n case 409:\r\n throw new ConflictError('unknown');\r\n case 429: {\r\n const retryAfter = parseInt(response.headers.get('Retry-After') ?? '60', 10);\r\n throw new RateLimitError(retryAfter);\r\n }\r\n default: {\r\n let message = response.statusText;\r\n try {\r\n const body = await response.json() as { message?: string };\r\n if (body.message) message = body.message;\r\n } catch { /* ignore */ }\r\n throw new PauthAPIError(response.status, message);\r\n }\r\n }\r\n }\r\n}\r\n"],"mappings":"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","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "pauth-js",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Official JavaScript/TypeScript SDK for pauth.me - Phone-based authentication API",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"module": "./dist/index.mjs",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.mjs",
|
|
12
|
+
"require": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": ["dist", "README.md", "LICENSE"],
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build": "tsup",
|
|
18
|
+
"dev": "tsup --watch",
|
|
19
|
+
"type-check": "tsc --noEmit",
|
|
20
|
+
"prepublishOnly": "npm run build"
|
|
21
|
+
},
|
|
22
|
+
"keywords": ["pauth", "authentication", "phone", "api", "sdk", "typescript"],
|
|
23
|
+
"author": "pauth.me",
|
|
24
|
+
"license": "MIT",
|
|
25
|
+
"repository": {
|
|
26
|
+
"type": "git",
|
|
27
|
+
"url": "git+https://github.com/mskz-ptplus-jp/pauth-js.git"
|
|
28
|
+
},
|
|
29
|
+
"bugs": {
|
|
30
|
+
"url": "https://github.com/mskz-ptplus-jp/pauth-js/issues"
|
|
31
|
+
},
|
|
32
|
+
"homepage": "https://github.com/mskz-ptplus-jp/pauth-js#readme",
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"tsup": "^8.0.0",
|
|
35
|
+
"typescript": "^5.0.0",
|
|
36
|
+
"@types/node": "^20.0.0",
|
|
37
|
+
"vitest": "^1.0.0"
|
|
38
|
+
},
|
|
39
|
+
"engines": {
|
|
40
|
+
"node": ">=18.0.0"
|
|
41
|
+
}
|
|
42
|
+
}
|