auth101 0.1.1
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 +174 -0
- package/dist/index.cjs +176 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +121 -0
- package/dist/index.d.ts +121 -0
- package/dist/index.js +173 -0
- package/dist/index.js.map +1 -0
- package/package.json +43 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Elsai Deribu
|
|
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,174 @@
|
|
|
1
|
+
# auth101
|
|
2
|
+
|
|
3
|
+
TypeScript client for [auth101](https://github.com/your-org/auth101) — simple email/password authentication for Python backends (FastAPI, Flask, Django).
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install auth101
|
|
9
|
+
# or
|
|
10
|
+
pnpm add auth101
|
|
11
|
+
# or
|
|
12
|
+
yarn add auth101
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Quick Start
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
import { createAuth101Client } from "auth101"
|
|
19
|
+
|
|
20
|
+
const auth = createAuth101Client({
|
|
21
|
+
baseURL: "http://localhost:8000/auth", // where auth101 is mounted on your backend
|
|
22
|
+
})
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Usage
|
|
26
|
+
|
|
27
|
+
All methods return `{ data, error }`. Exactly one of them will be non-null.
|
|
28
|
+
|
|
29
|
+
### Sign Up
|
|
30
|
+
|
|
31
|
+
```ts
|
|
32
|
+
const { data, error } = await auth.signUp({
|
|
33
|
+
email: "user@example.com",
|
|
34
|
+
password: "hunter2",
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
if (error) {
|
|
38
|
+
console.error(error.message, error.code)
|
|
39
|
+
} else {
|
|
40
|
+
console.log(data.user) // { id, email, is_active }
|
|
41
|
+
console.log(data.token) // JWT — stored automatically
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Sign In
|
|
46
|
+
|
|
47
|
+
```ts
|
|
48
|
+
const { data, error } = await auth.signIn({
|
|
49
|
+
email: "user@example.com",
|
|
50
|
+
password: "hunter2",
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
if (data) {
|
|
54
|
+
console.log("Welcome back,", data.user.email)
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Get Session
|
|
59
|
+
|
|
60
|
+
Reads the stored token and asks the backend to return the current user.
|
|
61
|
+
|
|
62
|
+
```ts
|
|
63
|
+
const { data, error } = await auth.getSession()
|
|
64
|
+
|
|
65
|
+
if (data) {
|
|
66
|
+
console.log("Logged in as", data.user.email)
|
|
67
|
+
} else {
|
|
68
|
+
console.log("Not authenticated:", error?.code)
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Sign Out
|
|
73
|
+
|
|
74
|
+
Notifies the backend (best-effort) and clears the local token.
|
|
75
|
+
|
|
76
|
+
```ts
|
|
77
|
+
const { data, error } = await auth.signOut()
|
|
78
|
+
// data.success === true
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Token Helpers
|
|
82
|
+
|
|
83
|
+
```ts
|
|
84
|
+
auth.getToken() // → string | null
|
|
85
|
+
auth.setToken(jwt) // store a token manually
|
|
86
|
+
auth.clearToken() // remove the stored token
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Configuration
|
|
90
|
+
|
|
91
|
+
```ts
|
|
92
|
+
const auth = createAuth101Client({
|
|
93
|
+
// Required: base URL where auth101 is mounted
|
|
94
|
+
baseURL: "https://api.myapp.com/auth",
|
|
95
|
+
|
|
96
|
+
// Optional: custom storage (defaults to localStorage in browsers)
|
|
97
|
+
storage: sessionStorage,
|
|
98
|
+
|
|
99
|
+
// Pass null to keep the token in memory only (useful for SSR)
|
|
100
|
+
// storage: null,
|
|
101
|
+
|
|
102
|
+
// Optional: key used in storage (default: "auth101_token")
|
|
103
|
+
storageKey: "myapp_token",
|
|
104
|
+
|
|
105
|
+
// Optional: default fetch options merged into every request
|
|
106
|
+
fetchOptions: {
|
|
107
|
+
credentials: "include",
|
|
108
|
+
},
|
|
109
|
+
})
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Custom Storage
|
|
113
|
+
|
|
114
|
+
Any object with `getItem`, `setItem`, and `removeItem` works:
|
|
115
|
+
|
|
116
|
+
```ts
|
|
117
|
+
const auth = createAuth101Client({
|
|
118
|
+
baseURL: "...",
|
|
119
|
+
storage: {
|
|
120
|
+
getItem: (key) => cookies.get(key) ?? null,
|
|
121
|
+
setItem: (key, value) => cookies.set(key, value),
|
|
122
|
+
removeItem: (key) => cookies.delete(key),
|
|
123
|
+
},
|
|
124
|
+
})
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## TypeScript
|
|
128
|
+
|
|
129
|
+
All types are exported:
|
|
130
|
+
|
|
131
|
+
```ts
|
|
132
|
+
import type {
|
|
133
|
+
User,
|
|
134
|
+
AuthResult,
|
|
135
|
+
BackendError,
|
|
136
|
+
SignUpInput,
|
|
137
|
+
SignInInput,
|
|
138
|
+
SignUpResponse,
|
|
139
|
+
SignInResponse,
|
|
140
|
+
SignOutResponse,
|
|
141
|
+
SessionResponse,
|
|
142
|
+
Auth101ClientOptions,
|
|
143
|
+
StorageLike,
|
|
144
|
+
} from "auth101"
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## Backend Endpoints
|
|
148
|
+
|
|
149
|
+
The client maps to these endpoints exposed by the Python `auth101` package:
|
|
150
|
+
|
|
151
|
+
| Method | Path | Description |
|
|
152
|
+
|--------|------|-------------|
|
|
153
|
+
| `POST` | `/sign-up/email` | Register a new user |
|
|
154
|
+
| `POST` | `/sign-in/email` | Sign in an existing user |
|
|
155
|
+
| `POST` | `/sign-out` | Acknowledge sign-out |
|
|
156
|
+
| `GET` | `/session` | Get current user from token |
|
|
157
|
+
|
|
158
|
+
## Error Codes
|
|
159
|
+
|
|
160
|
+
| Code | Meaning |
|
|
161
|
+
|------|---------|
|
|
162
|
+
| `VALIDATION_ERROR` | Missing or invalid input |
|
|
163
|
+
| `USER_EXISTS` | Email is already registered |
|
|
164
|
+
| `INVALID_CREDENTIALS` | Wrong email or password |
|
|
165
|
+
| `INVALID_TOKEN` | JWT is malformed or expired |
|
|
166
|
+
| `UNAUTHORIZED` | No valid token provided |
|
|
167
|
+
| `USER_NOT_FOUND` | Token valid but user deleted |
|
|
168
|
+
| `NETWORK_ERROR` | Could not reach the server |
|
|
169
|
+
| `PARSE_ERROR` | Server returned non-JSON |
|
|
170
|
+
| `HTTP_ERROR` | Non-2xx response with no error body |
|
|
171
|
+
|
|
172
|
+
## License
|
|
173
|
+
|
|
174
|
+
MIT
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// src/storage.ts
|
|
4
|
+
var MemoryStorage = class {
|
|
5
|
+
constructor() {
|
|
6
|
+
this._map = /* @__PURE__ */ new Map();
|
|
7
|
+
}
|
|
8
|
+
getItem(key) {
|
|
9
|
+
return this._map.get(key) ?? null;
|
|
10
|
+
}
|
|
11
|
+
setItem(key, value) {
|
|
12
|
+
this._map.set(key, value);
|
|
13
|
+
}
|
|
14
|
+
removeItem(key) {
|
|
15
|
+
this._map.delete(key);
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
function resolveStorage(storage) {
|
|
19
|
+
if (storage === null) {
|
|
20
|
+
return new MemoryStorage();
|
|
21
|
+
}
|
|
22
|
+
if (storage !== void 0) {
|
|
23
|
+
return storage;
|
|
24
|
+
}
|
|
25
|
+
if (typeof window !== "undefined" && window.localStorage) {
|
|
26
|
+
return window.localStorage;
|
|
27
|
+
}
|
|
28
|
+
return new MemoryStorage();
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// src/client.ts
|
|
32
|
+
var DEFAULT_STORAGE_KEY = "auth101_token";
|
|
33
|
+
var Auth101Client = class {
|
|
34
|
+
constructor(options) {
|
|
35
|
+
if (!options.baseURL) {
|
|
36
|
+
throw new Error("[auth101] baseURL is required");
|
|
37
|
+
}
|
|
38
|
+
this._baseURL = options.baseURL.replace(/\/$/, "");
|
|
39
|
+
this._storage = resolveStorage(options.storage);
|
|
40
|
+
this._storageKey = options.storageKey ?? DEFAULT_STORAGE_KEY;
|
|
41
|
+
this._fetchOptions = options.fetchOptions ?? {};
|
|
42
|
+
}
|
|
43
|
+
// ── Token management ────────────────────────────────────────────────────────
|
|
44
|
+
/** Returns the stored JWT, or `null` if the user is not signed in. */
|
|
45
|
+
getToken() {
|
|
46
|
+
return this._storage.getItem(this._storageKey);
|
|
47
|
+
}
|
|
48
|
+
/** Manually store a token (e.g. after server-side sign-in). */
|
|
49
|
+
setToken(token) {
|
|
50
|
+
this._storage.setItem(this._storageKey, token);
|
|
51
|
+
}
|
|
52
|
+
/** Remove the stored token. */
|
|
53
|
+
clearToken() {
|
|
54
|
+
this._storage.removeItem(this._storageKey);
|
|
55
|
+
}
|
|
56
|
+
// ── Auth methods ────────────────────────────────────────────────────────────
|
|
57
|
+
/**
|
|
58
|
+
* Register a new user with email and password.
|
|
59
|
+
*
|
|
60
|
+
* On success the token is persisted automatically.
|
|
61
|
+
* Returns `{ data: { user, token }, error: null }` or `{ data: null, error }`.
|
|
62
|
+
*/
|
|
63
|
+
async signUp(input) {
|
|
64
|
+
const result = await this._post("/sign-up/email", input);
|
|
65
|
+
if (result.data?.token) {
|
|
66
|
+
this.setToken(result.data.token);
|
|
67
|
+
}
|
|
68
|
+
return result;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Sign in with email and password.
|
|
72
|
+
*
|
|
73
|
+
* On success the token is persisted automatically.
|
|
74
|
+
* Returns `{ data: { user, token }, error: null }` or `{ data: null, error }`.
|
|
75
|
+
*/
|
|
76
|
+
async signIn(input) {
|
|
77
|
+
const result = await this._post("/sign-in/email", input);
|
|
78
|
+
if (result.data?.token) {
|
|
79
|
+
this.setToken(result.data.token);
|
|
80
|
+
}
|
|
81
|
+
return result;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Sign out the current user.
|
|
85
|
+
*
|
|
86
|
+
* The token is always cleared from storage regardless of the backend response.
|
|
87
|
+
* Returns `{ data: { success: true }, error: null }` or `{ data: null, error }`.
|
|
88
|
+
*/
|
|
89
|
+
async signOut() {
|
|
90
|
+
const token = this.getToken();
|
|
91
|
+
if (!token) {
|
|
92
|
+
this.clearToken();
|
|
93
|
+
return { data: { success: true }, error: null };
|
|
94
|
+
}
|
|
95
|
+
const result = await this._post("/sign-out", void 0, token);
|
|
96
|
+
this.clearToken();
|
|
97
|
+
return result;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Fetch the currently authenticated user from the backend.
|
|
101
|
+
*
|
|
102
|
+
* Returns `{ data: { user }, error: null }` or `{ data: null, error }`.
|
|
103
|
+
*/
|
|
104
|
+
async getSession() {
|
|
105
|
+
const token = this.getToken();
|
|
106
|
+
if (!token) {
|
|
107
|
+
return {
|
|
108
|
+
data: null,
|
|
109
|
+
error: { message: "Not signed in", code: "UNAUTHORIZED" }
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
return this._get("/session", token);
|
|
113
|
+
}
|
|
114
|
+
// ── Internal HTTP helpers ───────────────────────────────────────────────────
|
|
115
|
+
async _post(path, body, token) {
|
|
116
|
+
return this._request("POST", path, body, token);
|
|
117
|
+
}
|
|
118
|
+
async _get(path, token) {
|
|
119
|
+
return this._request("GET", path, void 0, token);
|
|
120
|
+
}
|
|
121
|
+
async _request(method, path, body, token) {
|
|
122
|
+
const headers = {
|
|
123
|
+
"Content-Type": "application/json",
|
|
124
|
+
...this._fetchOptions.headers
|
|
125
|
+
};
|
|
126
|
+
if (token) {
|
|
127
|
+
headers["Authorization"] = `Bearer ${token}`;
|
|
128
|
+
}
|
|
129
|
+
const init = {
|
|
130
|
+
...this._fetchOptions,
|
|
131
|
+
method,
|
|
132
|
+
headers,
|
|
133
|
+
...body !== void 0 ? { body: JSON.stringify(body) } : {}
|
|
134
|
+
};
|
|
135
|
+
let response;
|
|
136
|
+
try {
|
|
137
|
+
response = await fetch(`${this._baseURL}${path}`, init);
|
|
138
|
+
} catch (cause) {
|
|
139
|
+
return {
|
|
140
|
+
data: null,
|
|
141
|
+
error: {
|
|
142
|
+
message: "Network error \u2014 could not reach the server",
|
|
143
|
+
code: "NETWORK_ERROR"
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
let json;
|
|
148
|
+
try {
|
|
149
|
+
json = await response.json();
|
|
150
|
+
} catch {
|
|
151
|
+
return {
|
|
152
|
+
data: null,
|
|
153
|
+
error: {
|
|
154
|
+
message: `Unexpected response from server (status ${response.status})`,
|
|
155
|
+
code: "PARSE_ERROR"
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
if (!response.ok || isBackendError(json)) {
|
|
160
|
+
const err = isBackendError(json) ? json.error : { message: `Request failed with status ${response.status}`, code: "HTTP_ERROR" };
|
|
161
|
+
return { data: null, error: err };
|
|
162
|
+
}
|
|
163
|
+
return { data: json, error: null };
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
function isBackendError(json) {
|
|
167
|
+
return typeof json === "object" && json !== null && "error" in json && typeof json.error === "object";
|
|
168
|
+
}
|
|
169
|
+
function createAuth101Client(options) {
|
|
170
|
+
return new Auth101Client(options);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
exports.Auth101Client = Auth101Client;
|
|
174
|
+
exports.createAuth101Client = createAuth101Client;
|
|
175
|
+
//# sourceMappingURL=index.cjs.map
|
|
176
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/storage.ts","../src/client.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["import type { StorageLike } from \"./types\"\r\n\r\n/**\r\n * In-memory fallback used when localStorage is unavailable (SSR, Node, tests).\r\n * Token is lost when the instance is garbage-collected.\r\n */\r\nclass MemoryStorage implements StorageLike {\r\n private readonly _map = new Map<string, string>()\r\n\r\n getItem(key: string): string | null {\r\n return this._map.get(key) ?? null\r\n }\r\n\r\n setItem(key: string, value: string): void {\r\n this._map.set(key, value)\r\n }\r\n\r\n removeItem(key: string): void {\r\n this._map.delete(key)\r\n }\r\n}\r\n\r\n/**\r\n * Resolve a storage backend in priority order:\r\n *\r\n * 1. Explicit `null` → no persistence, always return `MemoryStorage`\r\n * 2. Explicit object → use as-is (duck-typed StorageLike)\r\n * 3. `undefined` → try `localStorage`, fall back to `MemoryStorage`\r\n */\r\nexport function resolveStorage(storage: StorageLike | null | undefined): StorageLike {\r\n if (storage === null) {\r\n return new MemoryStorage()\r\n }\r\n\r\n if (storage !== undefined) {\r\n return storage\r\n }\r\n\r\n if (typeof window !== \"undefined\" && window.localStorage) {\r\n return window.localStorage\r\n }\r\n\r\n return new MemoryStorage()\r\n}\r\n","import { resolveStorage } from \"./storage\"\r\nimport type {\r\n Auth101ClientOptions,\r\n AuthResult,\r\n BackendError,\r\n SessionResponse,\r\n SignInInput,\r\n SignInResponse,\r\n SignOutResponse,\r\n SignUpInput,\r\n SignUpResponse,\r\n StorageLike,\r\n} from \"./types\"\r\n\r\nconst DEFAULT_STORAGE_KEY = \"auth101_token\"\r\n\r\nexport class Auth101Client {\r\n private readonly _baseURL: string\r\n private readonly _storage: StorageLike\r\n private readonly _storageKey: string\r\n private readonly _fetchOptions: RequestInit\r\n\r\n constructor(options: Auth101ClientOptions) {\r\n if (!options.baseURL) {\r\n throw new Error(\"[auth101] baseURL is required\")\r\n }\r\n\r\n this._baseURL = options.baseURL.replace(/\\/$/, \"\")\r\n this._storage = resolveStorage(options.storage)\r\n this._storageKey = options.storageKey ?? DEFAULT_STORAGE_KEY\r\n this._fetchOptions = options.fetchOptions ?? {}\r\n }\r\n\r\n // ── Token management ────────────────────────────────────────────────────────\r\n\r\n /** Returns the stored JWT, or `null` if the user is not signed in. */\r\n getToken(): string | null {\r\n return this._storage.getItem(this._storageKey)\r\n }\r\n\r\n /** Manually store a token (e.g. after server-side sign-in). */\r\n setToken(token: string): void {\r\n this._storage.setItem(this._storageKey, token)\r\n }\r\n\r\n /** Remove the stored token. */\r\n clearToken(): void {\r\n this._storage.removeItem(this._storageKey)\r\n }\r\n\r\n // ── Auth methods ────────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Register a new user with email and password.\r\n *\r\n * On success the token is persisted automatically.\r\n * Returns `{ data: { user, token }, error: null }` or `{ data: null, error }`.\r\n */\r\n async signUp(input: SignUpInput): Promise<AuthResult<SignUpResponse>> {\r\n const result = await this._post<SignUpResponse>(\"/sign-up/email\", input)\r\n\r\n if (result.data?.token) {\r\n this.setToken(result.data.token)\r\n }\r\n\r\n return result\r\n }\r\n\r\n /**\r\n * Sign in with email and password.\r\n *\r\n * On success the token is persisted automatically.\r\n * Returns `{ data: { user, token }, error: null }` or `{ data: null, error }`.\r\n */\r\n async signIn(input: SignInInput): Promise<AuthResult<SignInResponse>> {\r\n const result = await this._post<SignInResponse>(\"/sign-in/email\", input)\r\n\r\n if (result.data?.token) {\r\n this.setToken(result.data.token)\r\n }\r\n\r\n return result\r\n }\r\n\r\n /**\r\n * Sign out the current user.\r\n *\r\n * The token is always cleared from storage regardless of the backend response.\r\n * Returns `{ data: { success: true }, error: null }` or `{ data: null, error }`.\r\n */\r\n async signOut(): Promise<AuthResult<SignOutResponse>> {\r\n const token = this.getToken()\r\n\r\n if (!token) {\r\n this.clearToken()\r\n return { data: { success: true }, error: null }\r\n }\r\n\r\n const result = await this._post<SignOutResponse>(\"/sign-out\", undefined, token)\r\n this.clearToken()\r\n return result\r\n }\r\n\r\n /**\r\n * Fetch the currently authenticated user from the backend.\r\n *\r\n * Returns `{ data: { user }, error: null }` or `{ data: null, error }`.\r\n */\r\n async getSession(): Promise<AuthResult<SessionResponse>> {\r\n const token = this.getToken()\r\n\r\n if (!token) {\r\n return {\r\n data: null,\r\n error: { message: \"Not signed in\", code: \"UNAUTHORIZED\" },\r\n }\r\n }\r\n\r\n return this._get<SessionResponse>(\"/session\", token)\r\n }\r\n\r\n // ── Internal HTTP helpers ───────────────────────────────────────────────────\r\n\r\n private async _post<T>(\r\n path: string,\r\n body: object | undefined,\r\n token?: string,\r\n ): Promise<AuthResult<T>> {\r\n return this._request<T>(\"POST\", path, body, token)\r\n }\r\n\r\n private async _get<T>(path: string, token?: string): Promise<AuthResult<T>> {\r\n return this._request<T>(\"GET\", path, undefined, token)\r\n }\r\n\r\n private async _request<T>(\r\n method: string,\r\n path: string,\r\n body: object | undefined,\r\n token?: string,\r\n ): Promise<AuthResult<T>> {\r\n const headers: Record<string, string> = {\r\n \"Content-Type\": \"application/json\",\r\n ...(this._fetchOptions.headers as Record<string, string> | undefined),\r\n }\r\n\r\n if (token) {\r\n headers[\"Authorization\"] = `Bearer ${token}`\r\n }\r\n\r\n const init: RequestInit = {\r\n ...this._fetchOptions,\r\n method,\r\n headers,\r\n ...(body !== undefined ? { body: JSON.stringify(body) } : {}),\r\n }\r\n\r\n let response: Response\r\n\r\n try {\r\n response = await fetch(`${this._baseURL}${path}`, init)\r\n } catch (cause) {\r\n return {\r\n data: null,\r\n error: {\r\n message: \"Network error — could not reach the server\",\r\n code: \"NETWORK_ERROR\",\r\n },\r\n }\r\n }\r\n\r\n let json: unknown\r\n\r\n try {\r\n json = await response.json()\r\n } catch {\r\n return {\r\n data: null,\r\n error: {\r\n message: `Unexpected response from server (status ${response.status})`,\r\n code: \"PARSE_ERROR\",\r\n },\r\n }\r\n }\r\n\r\n if (!response.ok || isBackendError(json)) {\r\n const err = isBackendError(json)\r\n ? (json as { error: BackendError }).error\r\n : { message: `Request failed with status ${response.status}`, code: \"HTTP_ERROR\" }\r\n\r\n return { data: null, error: err }\r\n }\r\n\r\n return { data: json as T, error: null }\r\n }\r\n}\r\n\r\nfunction isBackendError(json: unknown): boolean {\r\n return (\r\n typeof json === \"object\" &&\r\n json !== null &&\r\n \"error\" in json &&\r\n typeof (json as { error: unknown }).error === \"object\"\r\n )\r\n}\r\n\r\n// ── Factory ───────────────────────────────────────────────────────────────────\r\n\r\n/**\r\n * Create an `Auth101Client` instance.\r\n *\r\n * @example\r\n * ```ts\r\n * const auth = createAuth101Client({ baseURL: \"http://localhost:8000/auth\" })\r\n *\r\n * const { data, error } = await auth.signIn({ email, password })\r\n * if (data) console.log(data.user)\r\n * ```\r\n */\r\nexport function createAuth101Client(options: Auth101ClientOptions): Auth101Client {\r\n return new Auth101Client(options)\r\n}\r\n"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
interface User {
|
|
2
|
+
id: string;
|
|
3
|
+
email: string;
|
|
4
|
+
is_active: boolean;
|
|
5
|
+
}
|
|
6
|
+
interface SignUpInput {
|
|
7
|
+
email: string;
|
|
8
|
+
password: string;
|
|
9
|
+
}
|
|
10
|
+
interface SignInInput {
|
|
11
|
+
email: string;
|
|
12
|
+
password: string;
|
|
13
|
+
}
|
|
14
|
+
interface SignUpResponse {
|
|
15
|
+
user: User;
|
|
16
|
+
token: string;
|
|
17
|
+
}
|
|
18
|
+
interface SignInResponse {
|
|
19
|
+
user: User;
|
|
20
|
+
token: string;
|
|
21
|
+
}
|
|
22
|
+
interface SignOutResponse {
|
|
23
|
+
success: boolean;
|
|
24
|
+
}
|
|
25
|
+
interface SessionResponse {
|
|
26
|
+
user: User;
|
|
27
|
+
}
|
|
28
|
+
interface BackendError {
|
|
29
|
+
message: string;
|
|
30
|
+
code: string;
|
|
31
|
+
}
|
|
32
|
+
interface AuthResult<T> {
|
|
33
|
+
data: T | null;
|
|
34
|
+
error: BackendError | null;
|
|
35
|
+
}
|
|
36
|
+
interface StorageLike {
|
|
37
|
+
getItem(key: string): string | null;
|
|
38
|
+
setItem(key: string, value: string): void;
|
|
39
|
+
removeItem(key: string): void;
|
|
40
|
+
}
|
|
41
|
+
interface Auth101ClientOptions {
|
|
42
|
+
/**
|
|
43
|
+
* Base URL where auth101 is mounted on your backend, e.g.
|
|
44
|
+
* `"http://localhost:8000/auth"` — no trailing slash.
|
|
45
|
+
*/
|
|
46
|
+
baseURL: string;
|
|
47
|
+
/**
|
|
48
|
+
* Custom storage implementation for persisting the token.
|
|
49
|
+
* Defaults to `localStorage` in browser environments.
|
|
50
|
+
* Pass `null` to keep the token in memory only (useful for SSR or testing).
|
|
51
|
+
*/
|
|
52
|
+
storage?: StorageLike | null;
|
|
53
|
+
/**
|
|
54
|
+
* Key used to store the token in the provided storage.
|
|
55
|
+
* Defaults to `"auth101_token"`.
|
|
56
|
+
*/
|
|
57
|
+
storageKey?: string;
|
|
58
|
+
/**
|
|
59
|
+
* Default `RequestInit` options merged into every `fetch` call.
|
|
60
|
+
* Useful for setting custom headers, credentials mode, etc.
|
|
61
|
+
*/
|
|
62
|
+
fetchOptions?: RequestInit;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
declare class Auth101Client {
|
|
66
|
+
private readonly _baseURL;
|
|
67
|
+
private readonly _storage;
|
|
68
|
+
private readonly _storageKey;
|
|
69
|
+
private readonly _fetchOptions;
|
|
70
|
+
constructor(options: Auth101ClientOptions);
|
|
71
|
+
/** Returns the stored JWT, or `null` if the user is not signed in. */
|
|
72
|
+
getToken(): string | null;
|
|
73
|
+
/** Manually store a token (e.g. after server-side sign-in). */
|
|
74
|
+
setToken(token: string): void;
|
|
75
|
+
/** Remove the stored token. */
|
|
76
|
+
clearToken(): void;
|
|
77
|
+
/**
|
|
78
|
+
* Register a new user with email and password.
|
|
79
|
+
*
|
|
80
|
+
* On success the token is persisted automatically.
|
|
81
|
+
* Returns `{ data: { user, token }, error: null }` or `{ data: null, error }`.
|
|
82
|
+
*/
|
|
83
|
+
signUp(input: SignUpInput): Promise<AuthResult<SignUpResponse>>;
|
|
84
|
+
/**
|
|
85
|
+
* Sign in with email and password.
|
|
86
|
+
*
|
|
87
|
+
* On success the token is persisted automatically.
|
|
88
|
+
* Returns `{ data: { user, token }, error: null }` or `{ data: null, error }`.
|
|
89
|
+
*/
|
|
90
|
+
signIn(input: SignInInput): Promise<AuthResult<SignInResponse>>;
|
|
91
|
+
/**
|
|
92
|
+
* Sign out the current user.
|
|
93
|
+
*
|
|
94
|
+
* The token is always cleared from storage regardless of the backend response.
|
|
95
|
+
* Returns `{ data: { success: true }, error: null }` or `{ data: null, error }`.
|
|
96
|
+
*/
|
|
97
|
+
signOut(): Promise<AuthResult<SignOutResponse>>;
|
|
98
|
+
/**
|
|
99
|
+
* Fetch the currently authenticated user from the backend.
|
|
100
|
+
*
|
|
101
|
+
* Returns `{ data: { user }, error: null }` or `{ data: null, error }`.
|
|
102
|
+
*/
|
|
103
|
+
getSession(): Promise<AuthResult<SessionResponse>>;
|
|
104
|
+
private _post;
|
|
105
|
+
private _get;
|
|
106
|
+
private _request;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Create an `Auth101Client` instance.
|
|
110
|
+
*
|
|
111
|
+
* @example
|
|
112
|
+
* ```ts
|
|
113
|
+
* const auth = createAuth101Client({ baseURL: "http://localhost:8000/auth" })
|
|
114
|
+
*
|
|
115
|
+
* const { data, error } = await auth.signIn({ email, password })
|
|
116
|
+
* if (data) console.log(data.user)
|
|
117
|
+
* ```
|
|
118
|
+
*/
|
|
119
|
+
declare function createAuth101Client(options: Auth101ClientOptions): Auth101Client;
|
|
120
|
+
|
|
121
|
+
export { Auth101Client, type Auth101ClientOptions, type AuthResult, type BackendError, type SessionResponse, type SignInInput, type SignInResponse, type SignOutResponse, type SignUpInput, type SignUpResponse, type StorageLike, type User, createAuth101Client };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
interface User {
|
|
2
|
+
id: string;
|
|
3
|
+
email: string;
|
|
4
|
+
is_active: boolean;
|
|
5
|
+
}
|
|
6
|
+
interface SignUpInput {
|
|
7
|
+
email: string;
|
|
8
|
+
password: string;
|
|
9
|
+
}
|
|
10
|
+
interface SignInInput {
|
|
11
|
+
email: string;
|
|
12
|
+
password: string;
|
|
13
|
+
}
|
|
14
|
+
interface SignUpResponse {
|
|
15
|
+
user: User;
|
|
16
|
+
token: string;
|
|
17
|
+
}
|
|
18
|
+
interface SignInResponse {
|
|
19
|
+
user: User;
|
|
20
|
+
token: string;
|
|
21
|
+
}
|
|
22
|
+
interface SignOutResponse {
|
|
23
|
+
success: boolean;
|
|
24
|
+
}
|
|
25
|
+
interface SessionResponse {
|
|
26
|
+
user: User;
|
|
27
|
+
}
|
|
28
|
+
interface BackendError {
|
|
29
|
+
message: string;
|
|
30
|
+
code: string;
|
|
31
|
+
}
|
|
32
|
+
interface AuthResult<T> {
|
|
33
|
+
data: T | null;
|
|
34
|
+
error: BackendError | null;
|
|
35
|
+
}
|
|
36
|
+
interface StorageLike {
|
|
37
|
+
getItem(key: string): string | null;
|
|
38
|
+
setItem(key: string, value: string): void;
|
|
39
|
+
removeItem(key: string): void;
|
|
40
|
+
}
|
|
41
|
+
interface Auth101ClientOptions {
|
|
42
|
+
/**
|
|
43
|
+
* Base URL where auth101 is mounted on your backend, e.g.
|
|
44
|
+
* `"http://localhost:8000/auth"` — no trailing slash.
|
|
45
|
+
*/
|
|
46
|
+
baseURL: string;
|
|
47
|
+
/**
|
|
48
|
+
* Custom storage implementation for persisting the token.
|
|
49
|
+
* Defaults to `localStorage` in browser environments.
|
|
50
|
+
* Pass `null` to keep the token in memory only (useful for SSR or testing).
|
|
51
|
+
*/
|
|
52
|
+
storage?: StorageLike | null;
|
|
53
|
+
/**
|
|
54
|
+
* Key used to store the token in the provided storage.
|
|
55
|
+
* Defaults to `"auth101_token"`.
|
|
56
|
+
*/
|
|
57
|
+
storageKey?: string;
|
|
58
|
+
/**
|
|
59
|
+
* Default `RequestInit` options merged into every `fetch` call.
|
|
60
|
+
* Useful for setting custom headers, credentials mode, etc.
|
|
61
|
+
*/
|
|
62
|
+
fetchOptions?: RequestInit;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
declare class Auth101Client {
|
|
66
|
+
private readonly _baseURL;
|
|
67
|
+
private readonly _storage;
|
|
68
|
+
private readonly _storageKey;
|
|
69
|
+
private readonly _fetchOptions;
|
|
70
|
+
constructor(options: Auth101ClientOptions);
|
|
71
|
+
/** Returns the stored JWT, or `null` if the user is not signed in. */
|
|
72
|
+
getToken(): string | null;
|
|
73
|
+
/** Manually store a token (e.g. after server-side sign-in). */
|
|
74
|
+
setToken(token: string): void;
|
|
75
|
+
/** Remove the stored token. */
|
|
76
|
+
clearToken(): void;
|
|
77
|
+
/**
|
|
78
|
+
* Register a new user with email and password.
|
|
79
|
+
*
|
|
80
|
+
* On success the token is persisted automatically.
|
|
81
|
+
* Returns `{ data: { user, token }, error: null }` or `{ data: null, error }`.
|
|
82
|
+
*/
|
|
83
|
+
signUp(input: SignUpInput): Promise<AuthResult<SignUpResponse>>;
|
|
84
|
+
/**
|
|
85
|
+
* Sign in with email and password.
|
|
86
|
+
*
|
|
87
|
+
* On success the token is persisted automatically.
|
|
88
|
+
* Returns `{ data: { user, token }, error: null }` or `{ data: null, error }`.
|
|
89
|
+
*/
|
|
90
|
+
signIn(input: SignInInput): Promise<AuthResult<SignInResponse>>;
|
|
91
|
+
/**
|
|
92
|
+
* Sign out the current user.
|
|
93
|
+
*
|
|
94
|
+
* The token is always cleared from storage regardless of the backend response.
|
|
95
|
+
* Returns `{ data: { success: true }, error: null }` or `{ data: null, error }`.
|
|
96
|
+
*/
|
|
97
|
+
signOut(): Promise<AuthResult<SignOutResponse>>;
|
|
98
|
+
/**
|
|
99
|
+
* Fetch the currently authenticated user from the backend.
|
|
100
|
+
*
|
|
101
|
+
* Returns `{ data: { user }, error: null }` or `{ data: null, error }`.
|
|
102
|
+
*/
|
|
103
|
+
getSession(): Promise<AuthResult<SessionResponse>>;
|
|
104
|
+
private _post;
|
|
105
|
+
private _get;
|
|
106
|
+
private _request;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Create an `Auth101Client` instance.
|
|
110
|
+
*
|
|
111
|
+
* @example
|
|
112
|
+
* ```ts
|
|
113
|
+
* const auth = createAuth101Client({ baseURL: "http://localhost:8000/auth" })
|
|
114
|
+
*
|
|
115
|
+
* const { data, error } = await auth.signIn({ email, password })
|
|
116
|
+
* if (data) console.log(data.user)
|
|
117
|
+
* ```
|
|
118
|
+
*/
|
|
119
|
+
declare function createAuth101Client(options: Auth101ClientOptions): Auth101Client;
|
|
120
|
+
|
|
121
|
+
export { Auth101Client, type Auth101ClientOptions, type AuthResult, type BackendError, type SessionResponse, type SignInInput, type SignInResponse, type SignOutResponse, type SignUpInput, type SignUpResponse, type StorageLike, type User, createAuth101Client };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
// src/storage.ts
|
|
2
|
+
var MemoryStorage = class {
|
|
3
|
+
constructor() {
|
|
4
|
+
this._map = /* @__PURE__ */ new Map();
|
|
5
|
+
}
|
|
6
|
+
getItem(key) {
|
|
7
|
+
return this._map.get(key) ?? null;
|
|
8
|
+
}
|
|
9
|
+
setItem(key, value) {
|
|
10
|
+
this._map.set(key, value);
|
|
11
|
+
}
|
|
12
|
+
removeItem(key) {
|
|
13
|
+
this._map.delete(key);
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
function resolveStorage(storage) {
|
|
17
|
+
if (storage === null) {
|
|
18
|
+
return new MemoryStorage();
|
|
19
|
+
}
|
|
20
|
+
if (storage !== void 0) {
|
|
21
|
+
return storage;
|
|
22
|
+
}
|
|
23
|
+
if (typeof window !== "undefined" && window.localStorage) {
|
|
24
|
+
return window.localStorage;
|
|
25
|
+
}
|
|
26
|
+
return new MemoryStorage();
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// src/client.ts
|
|
30
|
+
var DEFAULT_STORAGE_KEY = "auth101_token";
|
|
31
|
+
var Auth101Client = class {
|
|
32
|
+
constructor(options) {
|
|
33
|
+
if (!options.baseURL) {
|
|
34
|
+
throw new Error("[auth101] baseURL is required");
|
|
35
|
+
}
|
|
36
|
+
this._baseURL = options.baseURL.replace(/\/$/, "");
|
|
37
|
+
this._storage = resolveStorage(options.storage);
|
|
38
|
+
this._storageKey = options.storageKey ?? DEFAULT_STORAGE_KEY;
|
|
39
|
+
this._fetchOptions = options.fetchOptions ?? {};
|
|
40
|
+
}
|
|
41
|
+
// ── Token management ────────────────────────────────────────────────────────
|
|
42
|
+
/** Returns the stored JWT, or `null` if the user is not signed in. */
|
|
43
|
+
getToken() {
|
|
44
|
+
return this._storage.getItem(this._storageKey);
|
|
45
|
+
}
|
|
46
|
+
/** Manually store a token (e.g. after server-side sign-in). */
|
|
47
|
+
setToken(token) {
|
|
48
|
+
this._storage.setItem(this._storageKey, token);
|
|
49
|
+
}
|
|
50
|
+
/** Remove the stored token. */
|
|
51
|
+
clearToken() {
|
|
52
|
+
this._storage.removeItem(this._storageKey);
|
|
53
|
+
}
|
|
54
|
+
// ── Auth methods ────────────────────────────────────────────────────────────
|
|
55
|
+
/**
|
|
56
|
+
* Register a new user with email and password.
|
|
57
|
+
*
|
|
58
|
+
* On success the token is persisted automatically.
|
|
59
|
+
* Returns `{ data: { user, token }, error: null }` or `{ data: null, error }`.
|
|
60
|
+
*/
|
|
61
|
+
async signUp(input) {
|
|
62
|
+
const result = await this._post("/sign-up/email", input);
|
|
63
|
+
if (result.data?.token) {
|
|
64
|
+
this.setToken(result.data.token);
|
|
65
|
+
}
|
|
66
|
+
return result;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Sign in with email and password.
|
|
70
|
+
*
|
|
71
|
+
* On success the token is persisted automatically.
|
|
72
|
+
* Returns `{ data: { user, token }, error: null }` or `{ data: null, error }`.
|
|
73
|
+
*/
|
|
74
|
+
async signIn(input) {
|
|
75
|
+
const result = await this._post("/sign-in/email", input);
|
|
76
|
+
if (result.data?.token) {
|
|
77
|
+
this.setToken(result.data.token);
|
|
78
|
+
}
|
|
79
|
+
return result;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Sign out the current user.
|
|
83
|
+
*
|
|
84
|
+
* The token is always cleared from storage regardless of the backend response.
|
|
85
|
+
* Returns `{ data: { success: true }, error: null }` or `{ data: null, error }`.
|
|
86
|
+
*/
|
|
87
|
+
async signOut() {
|
|
88
|
+
const token = this.getToken();
|
|
89
|
+
if (!token) {
|
|
90
|
+
this.clearToken();
|
|
91
|
+
return { data: { success: true }, error: null };
|
|
92
|
+
}
|
|
93
|
+
const result = await this._post("/sign-out", void 0, token);
|
|
94
|
+
this.clearToken();
|
|
95
|
+
return result;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Fetch the currently authenticated user from the backend.
|
|
99
|
+
*
|
|
100
|
+
* Returns `{ data: { user }, error: null }` or `{ data: null, error }`.
|
|
101
|
+
*/
|
|
102
|
+
async getSession() {
|
|
103
|
+
const token = this.getToken();
|
|
104
|
+
if (!token) {
|
|
105
|
+
return {
|
|
106
|
+
data: null,
|
|
107
|
+
error: { message: "Not signed in", code: "UNAUTHORIZED" }
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
return this._get("/session", token);
|
|
111
|
+
}
|
|
112
|
+
// ── Internal HTTP helpers ───────────────────────────────────────────────────
|
|
113
|
+
async _post(path, body, token) {
|
|
114
|
+
return this._request("POST", path, body, token);
|
|
115
|
+
}
|
|
116
|
+
async _get(path, token) {
|
|
117
|
+
return this._request("GET", path, void 0, token);
|
|
118
|
+
}
|
|
119
|
+
async _request(method, path, body, token) {
|
|
120
|
+
const headers = {
|
|
121
|
+
"Content-Type": "application/json",
|
|
122
|
+
...this._fetchOptions.headers
|
|
123
|
+
};
|
|
124
|
+
if (token) {
|
|
125
|
+
headers["Authorization"] = `Bearer ${token}`;
|
|
126
|
+
}
|
|
127
|
+
const init = {
|
|
128
|
+
...this._fetchOptions,
|
|
129
|
+
method,
|
|
130
|
+
headers,
|
|
131
|
+
...body !== void 0 ? { body: JSON.stringify(body) } : {}
|
|
132
|
+
};
|
|
133
|
+
let response;
|
|
134
|
+
try {
|
|
135
|
+
response = await fetch(`${this._baseURL}${path}`, init);
|
|
136
|
+
} catch (cause) {
|
|
137
|
+
return {
|
|
138
|
+
data: null,
|
|
139
|
+
error: {
|
|
140
|
+
message: "Network error \u2014 could not reach the server",
|
|
141
|
+
code: "NETWORK_ERROR"
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
let json;
|
|
146
|
+
try {
|
|
147
|
+
json = await response.json();
|
|
148
|
+
} catch {
|
|
149
|
+
return {
|
|
150
|
+
data: null,
|
|
151
|
+
error: {
|
|
152
|
+
message: `Unexpected response from server (status ${response.status})`,
|
|
153
|
+
code: "PARSE_ERROR"
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
if (!response.ok || isBackendError(json)) {
|
|
158
|
+
const err = isBackendError(json) ? json.error : { message: `Request failed with status ${response.status}`, code: "HTTP_ERROR" };
|
|
159
|
+
return { data: null, error: err };
|
|
160
|
+
}
|
|
161
|
+
return { data: json, error: null };
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
function isBackendError(json) {
|
|
165
|
+
return typeof json === "object" && json !== null && "error" in json && typeof json.error === "object";
|
|
166
|
+
}
|
|
167
|
+
function createAuth101Client(options) {
|
|
168
|
+
return new Auth101Client(options);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
export { Auth101Client, createAuth101Client };
|
|
172
|
+
//# sourceMappingURL=index.js.map
|
|
173
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/storage.ts","../src/client.ts"],"names":[],"mappings":";AAMA,IAAM,gBAAN,MAA2C;AAAA,EAA3C,WAAA,GAAA;AACE,IAAA,IAAA,CAAiB,IAAA,uBAAW,GAAA,EAAoB;AAAA,EAAA;AAAA,EAEhD,QAAQ,GAAA,EAA4B;AAClC,IAAA,OAAO,IAAA,CAAK,IAAA,CAAK,GAAA,CAAI,GAAG,CAAA,IAAK,IAAA;AAAA,EAC/B;AAAA,EAEA,OAAA,CAAQ,KAAa,KAAA,EAAqB;AACxC,IAAA,IAAA,CAAK,IAAA,CAAK,GAAA,CAAI,GAAA,EAAK,KAAK,CAAA;AAAA,EAC1B;AAAA,EAEA,WAAW,GAAA,EAAmB;AAC5B,IAAA,IAAA,CAAK,IAAA,CAAK,OAAO,GAAG,CAAA;AAAA,EACtB;AACF,CAAA;AASO,SAAS,eAAe,OAAA,EAAsD;AACnF,EAAA,IAAI,YAAY,IAAA,EAAM;AACpB,IAAA,OAAO,IAAI,aAAA,EAAc;AAAA,EAC3B;AAEA,EAAA,IAAI,YAAY,MAAA,EAAW;AACzB,IAAA,OAAO,OAAA;AAAA,EACT;AAEA,EAAA,IAAI,OAAO,MAAA,KAAW,WAAA,IAAe,MAAA,CAAO,YAAA,EAAc;AACxD,IAAA,OAAO,MAAA,CAAO,YAAA;AAAA,EAChB;AAEA,EAAA,OAAO,IAAI,aAAA,EAAc;AAC3B;;;AC7BA,IAAM,mBAAA,GAAsB,eAAA;AAErB,IAAM,gBAAN,MAAoB;AAAA,EAMzB,YAAY,OAAA,EAA+B;AACzC,IAAA,IAAI,CAAC,QAAQ,OAAA,EAAS;AACpB,MAAA,MAAM,IAAI,MAAM,+BAA+B,CAAA;AAAA,IACjD;AAEA,IAAA,IAAA,CAAK,QAAA,GAAW,OAAA,CAAQ,OAAA,CAAQ,OAAA,CAAQ,OAAO,EAAE,CAAA;AACjD,IAAA,IAAA,CAAK,QAAA,GAAW,cAAA,CAAe,OAAA,CAAQ,OAAO,CAAA;AAC9C,IAAA,IAAA,CAAK,WAAA,GAAc,QAAQ,UAAA,IAAc,mBAAA;AACzC,IAAA,IAAA,CAAK,aAAA,GAAgB,OAAA,CAAQ,YAAA,IAAgB,EAAC;AAAA,EAChD;AAAA;AAAA;AAAA,EAKA,QAAA,GAA0B;AACxB,IAAA,OAAO,IAAA,CAAK,QAAA,CAAS,OAAA,CAAQ,IAAA,CAAK,WAAW,CAAA;AAAA,EAC/C;AAAA;AAAA,EAGA,SAAS,KAAA,EAAqB;AAC5B,IAAA,IAAA,CAAK,QAAA,CAAS,OAAA,CAAQ,IAAA,CAAK,WAAA,EAAa,KAAK,CAAA;AAAA,EAC/C;AAAA;AAAA,EAGA,UAAA,GAAmB;AACjB,IAAA,IAAA,CAAK,QAAA,CAAS,UAAA,CAAW,IAAA,CAAK,WAAW,CAAA;AAAA,EAC3C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAM,OAAO,KAAA,EAAyD;AACpE,IAAA,MAAM,MAAA,GAAS,MAAM,IAAA,CAAK,KAAA,CAAsB,kBAAkB,KAAK,CAAA;AAEvE,IAAA,IAAI,MAAA,CAAO,MAAM,KAAA,EAAO;AACtB,MAAA,IAAA,CAAK,QAAA,CAAS,MAAA,CAAO,IAAA,CAAK,KAAK,CAAA;AAAA,IACjC;AAEA,IAAA,OAAO,MAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,OAAO,KAAA,EAAyD;AACpE,IAAA,MAAM,MAAA,GAAS,MAAM,IAAA,CAAK,KAAA,CAAsB,kBAAkB,KAAK,CAAA;AAEvE,IAAA,IAAI,MAAA,CAAO,MAAM,KAAA,EAAO;AACtB,MAAA,IAAA,CAAK,QAAA,CAAS,MAAA,CAAO,IAAA,CAAK,KAAK,CAAA;AAAA,IACjC;AAEA,IAAA,OAAO,MAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,OAAA,GAAgD;AACpD,IAAA,MAAM,KAAA,GAAQ,KAAK,QAAA,EAAS;AAE5B,IAAA,IAAI,CAAC,KAAA,EAAO;AACV,MAAA,IAAA,CAAK,UAAA,EAAW;AAChB,MAAA,OAAO,EAAE,IAAA,EAAM,EAAE,SAAS,IAAA,EAAK,EAAG,OAAO,IAAA,EAAK;AAAA,IAChD;AAEA,IAAA,MAAM,SAAS,MAAM,IAAA,CAAK,KAAA,CAAuB,WAAA,EAAa,QAAW,KAAK,CAAA;AAC9E,IAAA,IAAA,CAAK,UAAA,EAAW;AAChB,IAAA,OAAO,MAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,UAAA,GAAmD;AACvD,IAAA,MAAM,KAAA,GAAQ,KAAK,QAAA,EAAS;AAE5B,IAAA,IAAI,CAAC,KAAA,EAAO;AACV,MAAA,OAAO;AAAA,QACL,IAAA,EAAM,IAAA;AAAA,QACN,KAAA,EAAO,EAAE,OAAA,EAAS,eAAA,EAAiB,MAAM,cAAA;AAAe,OAC1D;AAAA,IACF;AAEA,IAAA,OAAO,IAAA,CAAK,IAAA,CAAsB,UAAA,EAAY,KAAK,CAAA;AAAA,EACrD;AAAA;AAAA,EAIA,MAAc,KAAA,CACZ,IAAA,EACA,IAAA,EACA,KAAA,EACwB;AACxB,IAAA,OAAO,IAAA,CAAK,QAAA,CAAY,MAAA,EAAQ,IAAA,EAAM,MAAM,KAAK,CAAA;AAAA,EACnD;AAAA,EAEA,MAAc,IAAA,CAAQ,IAAA,EAAc,KAAA,EAAwC;AAC1E,IAAA,OAAO,IAAA,CAAK,QAAA,CAAY,KAAA,EAAO,IAAA,EAAM,QAAW,KAAK,CAAA;AAAA,EACvD;AAAA,EAEA,MAAc,QAAA,CACZ,MAAA,EACA,IAAA,EACA,MACA,KAAA,EACwB;AACxB,IAAA,MAAM,OAAA,GAAkC;AAAA,MACtC,cAAA,EAAgB,kBAAA;AAAA,MAChB,GAAI,KAAK,aAAA,CAAc;AAAA,KACzB;AAEA,IAAA,IAAI,KAAA,EAAO;AACT,MAAA,OAAA,CAAQ,eAAe,CAAA,GAAI,CAAA,OAAA,EAAU,KAAK,CAAA,CAAA;AAAA,IAC5C;AAEA,IAAA,MAAM,IAAA,GAAoB;AAAA,MACxB,GAAG,IAAA,CAAK,aAAA;AAAA,MACR,MAAA;AAAA,MACA,OAAA;AAAA,MACA,GAAI,IAAA,KAAS,MAAA,GAAY,EAAE,IAAA,EAAM,KAAK,SAAA,CAAU,IAAI,CAAA,EAAE,GAAI;AAAC,KAC7D;AAEA,IAAA,IAAI,QAAA;AAEJ,IAAA,IAAI;AACF,MAAA,QAAA,GAAW,MAAM,MAAM,CAAA,EAAG,IAAA,CAAK,QAAQ,CAAA,EAAG,IAAI,IAAI,IAAI,CAAA;AAAA,IACxD,SAAS,KAAA,EAAO;AACd,MAAA,OAAO;AAAA,QACL,IAAA,EAAM,IAAA;AAAA,QACN,KAAA,EAAO;AAAA,UACL,OAAA,EAAS,iDAAA;AAAA,UACT,IAAA,EAAM;AAAA;AACR,OACF;AAAA,IACF;AAEA,IAAA,IAAI,IAAA;AAEJ,IAAA,IAAI;AACF,MAAA,IAAA,GAAO,MAAM,SAAS,IAAA,EAAK;AAAA,IAC7B,CAAA,CAAA,MAAQ;AACN,MAAA,OAAO;AAAA,QACL,IAAA,EAAM,IAAA;AAAA,QACN,KAAA,EAAO;AAAA,UACL,OAAA,EAAS,CAAA,wCAAA,EAA2C,QAAA,CAAS,MAAM,CAAA,CAAA,CAAA;AAAA,UACnE,IAAA,EAAM;AAAA;AACR,OACF;AAAA,IACF;AAEA,IAAA,IAAI,CAAC,QAAA,CAAS,EAAA,IAAM,cAAA,CAAe,IAAI,CAAA,EAAG;AACxC,MAAA,MAAM,GAAA,GAAM,cAAA,CAAe,IAAI,CAAA,GAC1B,IAAA,CAAiC,KAAA,GAClC,EAAE,OAAA,EAAS,CAAA,2BAAA,EAA8B,QAAA,CAAS,MAAM,CAAA,CAAA,EAAI,MAAM,YAAA,EAAa;AAEnF,MAAA,OAAO,EAAE,IAAA,EAAM,IAAA,EAAM,KAAA,EAAO,GAAA,EAAI;AAAA,IAClC;AAEA,IAAA,OAAO,EAAE,IAAA,EAAM,IAAA,EAAW,KAAA,EAAO,IAAA,EAAK;AAAA,EACxC;AACF;AAEA,SAAS,eAAe,IAAA,EAAwB;AAC9C,EAAA,OACE,OAAO,SAAS,QAAA,IAChB,IAAA,KAAS,QACT,OAAA,IAAW,IAAA,IACX,OAAQ,IAAA,CAA4B,KAAA,KAAU,QAAA;AAElD;AAeO,SAAS,oBAAoB,OAAA,EAA8C;AAChF,EAAA,OAAO,IAAI,cAAc,OAAO,CAAA;AAClC","file":"index.js","sourcesContent":["import type { StorageLike } from \"./types\"\r\n\r\n/**\r\n * In-memory fallback used when localStorage is unavailable (SSR, Node, tests).\r\n * Token is lost when the instance is garbage-collected.\r\n */\r\nclass MemoryStorage implements StorageLike {\r\n private readonly _map = new Map<string, string>()\r\n\r\n getItem(key: string): string | null {\r\n return this._map.get(key) ?? null\r\n }\r\n\r\n setItem(key: string, value: string): void {\r\n this._map.set(key, value)\r\n }\r\n\r\n removeItem(key: string): void {\r\n this._map.delete(key)\r\n }\r\n}\r\n\r\n/**\r\n * Resolve a storage backend in priority order:\r\n *\r\n * 1. Explicit `null` → no persistence, always return `MemoryStorage`\r\n * 2. Explicit object → use as-is (duck-typed StorageLike)\r\n * 3. `undefined` → try `localStorage`, fall back to `MemoryStorage`\r\n */\r\nexport function resolveStorage(storage: StorageLike | null | undefined): StorageLike {\r\n if (storage === null) {\r\n return new MemoryStorage()\r\n }\r\n\r\n if (storage !== undefined) {\r\n return storage\r\n }\r\n\r\n if (typeof window !== \"undefined\" && window.localStorage) {\r\n return window.localStorage\r\n }\r\n\r\n return new MemoryStorage()\r\n}\r\n","import { resolveStorage } from \"./storage\"\r\nimport type {\r\n Auth101ClientOptions,\r\n AuthResult,\r\n BackendError,\r\n SessionResponse,\r\n SignInInput,\r\n SignInResponse,\r\n SignOutResponse,\r\n SignUpInput,\r\n SignUpResponse,\r\n StorageLike,\r\n} from \"./types\"\r\n\r\nconst DEFAULT_STORAGE_KEY = \"auth101_token\"\r\n\r\nexport class Auth101Client {\r\n private readonly _baseURL: string\r\n private readonly _storage: StorageLike\r\n private readonly _storageKey: string\r\n private readonly _fetchOptions: RequestInit\r\n\r\n constructor(options: Auth101ClientOptions) {\r\n if (!options.baseURL) {\r\n throw new Error(\"[auth101] baseURL is required\")\r\n }\r\n\r\n this._baseURL = options.baseURL.replace(/\\/$/, \"\")\r\n this._storage = resolveStorage(options.storage)\r\n this._storageKey = options.storageKey ?? DEFAULT_STORAGE_KEY\r\n this._fetchOptions = options.fetchOptions ?? {}\r\n }\r\n\r\n // ── Token management ────────────────────────────────────────────────────────\r\n\r\n /** Returns the stored JWT, or `null` if the user is not signed in. */\r\n getToken(): string | null {\r\n return this._storage.getItem(this._storageKey)\r\n }\r\n\r\n /** Manually store a token (e.g. after server-side sign-in). */\r\n setToken(token: string): void {\r\n this._storage.setItem(this._storageKey, token)\r\n }\r\n\r\n /** Remove the stored token. */\r\n clearToken(): void {\r\n this._storage.removeItem(this._storageKey)\r\n }\r\n\r\n // ── Auth methods ────────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Register a new user with email and password.\r\n *\r\n * On success the token is persisted automatically.\r\n * Returns `{ data: { user, token }, error: null }` or `{ data: null, error }`.\r\n */\r\n async signUp(input: SignUpInput): Promise<AuthResult<SignUpResponse>> {\r\n const result = await this._post<SignUpResponse>(\"/sign-up/email\", input)\r\n\r\n if (result.data?.token) {\r\n this.setToken(result.data.token)\r\n }\r\n\r\n return result\r\n }\r\n\r\n /**\r\n * Sign in with email and password.\r\n *\r\n * On success the token is persisted automatically.\r\n * Returns `{ data: { user, token }, error: null }` or `{ data: null, error }`.\r\n */\r\n async signIn(input: SignInInput): Promise<AuthResult<SignInResponse>> {\r\n const result = await this._post<SignInResponse>(\"/sign-in/email\", input)\r\n\r\n if (result.data?.token) {\r\n this.setToken(result.data.token)\r\n }\r\n\r\n return result\r\n }\r\n\r\n /**\r\n * Sign out the current user.\r\n *\r\n * The token is always cleared from storage regardless of the backend response.\r\n * Returns `{ data: { success: true }, error: null }` or `{ data: null, error }`.\r\n */\r\n async signOut(): Promise<AuthResult<SignOutResponse>> {\r\n const token = this.getToken()\r\n\r\n if (!token) {\r\n this.clearToken()\r\n return { data: { success: true }, error: null }\r\n }\r\n\r\n const result = await this._post<SignOutResponse>(\"/sign-out\", undefined, token)\r\n this.clearToken()\r\n return result\r\n }\r\n\r\n /**\r\n * Fetch the currently authenticated user from the backend.\r\n *\r\n * Returns `{ data: { user }, error: null }` or `{ data: null, error }`.\r\n */\r\n async getSession(): Promise<AuthResult<SessionResponse>> {\r\n const token = this.getToken()\r\n\r\n if (!token) {\r\n return {\r\n data: null,\r\n error: { message: \"Not signed in\", code: \"UNAUTHORIZED\" },\r\n }\r\n }\r\n\r\n return this._get<SessionResponse>(\"/session\", token)\r\n }\r\n\r\n // ── Internal HTTP helpers ───────────────────────────────────────────────────\r\n\r\n private async _post<T>(\r\n path: string,\r\n body: object | undefined,\r\n token?: string,\r\n ): Promise<AuthResult<T>> {\r\n return this._request<T>(\"POST\", path, body, token)\r\n }\r\n\r\n private async _get<T>(path: string, token?: string): Promise<AuthResult<T>> {\r\n return this._request<T>(\"GET\", path, undefined, token)\r\n }\r\n\r\n private async _request<T>(\r\n method: string,\r\n path: string,\r\n body: object | undefined,\r\n token?: string,\r\n ): Promise<AuthResult<T>> {\r\n const headers: Record<string, string> = {\r\n \"Content-Type\": \"application/json\",\r\n ...(this._fetchOptions.headers as Record<string, string> | undefined),\r\n }\r\n\r\n if (token) {\r\n headers[\"Authorization\"] = `Bearer ${token}`\r\n }\r\n\r\n const init: RequestInit = {\r\n ...this._fetchOptions,\r\n method,\r\n headers,\r\n ...(body !== undefined ? { body: JSON.stringify(body) } : {}),\r\n }\r\n\r\n let response: Response\r\n\r\n try {\r\n response = await fetch(`${this._baseURL}${path}`, init)\r\n } catch (cause) {\r\n return {\r\n data: null,\r\n error: {\r\n message: \"Network error — could not reach the server\",\r\n code: \"NETWORK_ERROR\",\r\n },\r\n }\r\n }\r\n\r\n let json: unknown\r\n\r\n try {\r\n json = await response.json()\r\n } catch {\r\n return {\r\n data: null,\r\n error: {\r\n message: `Unexpected response from server (status ${response.status})`,\r\n code: \"PARSE_ERROR\",\r\n },\r\n }\r\n }\r\n\r\n if (!response.ok || isBackendError(json)) {\r\n const err = isBackendError(json)\r\n ? (json as { error: BackendError }).error\r\n : { message: `Request failed with status ${response.status}`, code: \"HTTP_ERROR\" }\r\n\r\n return { data: null, error: err }\r\n }\r\n\r\n return { data: json as T, error: null }\r\n }\r\n}\r\n\r\nfunction isBackendError(json: unknown): boolean {\r\n return (\r\n typeof json === \"object\" &&\r\n json !== null &&\r\n \"error\" in json &&\r\n typeof (json as { error: unknown }).error === \"object\"\r\n )\r\n}\r\n\r\n// ── Factory ───────────────────────────────────────────────────────────────────\r\n\r\n/**\r\n * Create an `Auth101Client` instance.\r\n *\r\n * @example\r\n * ```ts\r\n * const auth = createAuth101Client({ baseURL: \"http://localhost:8000/auth\" })\r\n *\r\n * const { data, error } = await auth.signIn({ email, password })\r\n * if (data) console.log(data.user)\r\n * ```\r\n */\r\nexport function createAuth101Client(options: Auth101ClientOptions): Auth101Client {\r\n return new Auth101Client(options)\r\n}\r\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "auth101",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "TypeScript client for auth101 — simple email/password auth for Python backends",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"auth",
|
|
7
|
+
"authentication",
|
|
8
|
+
"typescript",
|
|
9
|
+
"python",
|
|
10
|
+
"fastapi",
|
|
11
|
+
"flask",
|
|
12
|
+
"django"
|
|
13
|
+
],
|
|
14
|
+
"license": "MIT",
|
|
15
|
+
"type": "module",
|
|
16
|
+
"main": "./dist/index.cjs",
|
|
17
|
+
"module": "./dist/index.js",
|
|
18
|
+
"types": "./dist/index.d.ts",
|
|
19
|
+
"exports": {
|
|
20
|
+
".": {
|
|
21
|
+
"import": {
|
|
22
|
+
"types": "./dist/index.d.ts",
|
|
23
|
+
"default": "./dist/index.js"
|
|
24
|
+
},
|
|
25
|
+
"require": {
|
|
26
|
+
"types": "./dist/index.d.cts",
|
|
27
|
+
"default": "./dist/index.cjs"
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"files": [
|
|
32
|
+
"dist"
|
|
33
|
+
],
|
|
34
|
+
"scripts": {
|
|
35
|
+
"build": "tsup",
|
|
36
|
+
"dev": "tsup --watch",
|
|
37
|
+
"typecheck": "tsc --noEmit"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"tsup": "^8.4.0",
|
|
41
|
+
"typescript": "^5.8.2"
|
|
42
|
+
}
|
|
43
|
+
}
|