@playcademy/better-auth 0.0.1 → 0.0.3-beta.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/dist/client.d.ts +49 -2
- package/dist/client.js +52 -26
- package/dist/server.d.ts +21 -12
- package/dist/server.js +6033 -10852
- package/package.json +7 -5
package/dist/client.d.ts
CHANGED
|
@@ -18,7 +18,6 @@
|
|
|
18
18
|
* })
|
|
19
19
|
* ```
|
|
20
20
|
*/
|
|
21
|
-
import { playcademy as playcademyServerPlugin } from './server';
|
|
22
21
|
/**
|
|
23
22
|
* Configuration options for the Playcademy Better Auth client plugin
|
|
24
23
|
*
|
|
@@ -138,6 +137,54 @@ export interface PlaycademyClientOptions {
|
|
|
138
137
|
*/
|
|
139
138
|
export declare function playcademy(options?: PlaycademyClientOptions): {
|
|
140
139
|
id: "playcademy-client";
|
|
141
|
-
$InferServerPlugin:
|
|
140
|
+
$InferServerPlugin: {
|
|
141
|
+
id: string;
|
|
142
|
+
schema: {
|
|
143
|
+
user: {
|
|
144
|
+
fields: {
|
|
145
|
+
playcademyUserId: {
|
|
146
|
+
type: "string";
|
|
147
|
+
unique: boolean;
|
|
148
|
+
required: boolean;
|
|
149
|
+
};
|
|
150
|
+
};
|
|
151
|
+
};
|
|
152
|
+
};
|
|
153
|
+
endpoints: {
|
|
154
|
+
playcademyAuth: {
|
|
155
|
+
<AsResponse extends boolean = false, ReturnHeaders extends boolean = false>(inputCtx_0?: ({
|
|
156
|
+
body?: undefined;
|
|
157
|
+
} & {
|
|
158
|
+
method?: "POST" | undefined;
|
|
159
|
+
} & {
|
|
160
|
+
query?: Record<string, any> | undefined;
|
|
161
|
+
} & {
|
|
162
|
+
params?: Record<string, any> | undefined;
|
|
163
|
+
} & {
|
|
164
|
+
request?: Request | undefined;
|
|
165
|
+
} & {
|
|
166
|
+
headers?: HeadersInit | undefined;
|
|
167
|
+
} & {
|
|
168
|
+
asResponse?: boolean | undefined;
|
|
169
|
+
returnHeaders?: boolean | undefined;
|
|
170
|
+
use?: any[] | undefined;
|
|
171
|
+
path?: string | undefined;
|
|
172
|
+
} & {
|
|
173
|
+
asResponse?: AsResponse | undefined;
|
|
174
|
+
returnHeaders?: ReturnHeaders | undefined;
|
|
175
|
+
}) | undefined): Promise<[AsResponse] extends [true] ? Response : [ReturnHeaders] extends [true] ? {
|
|
176
|
+
headers: Headers;
|
|
177
|
+
response: Response;
|
|
178
|
+
} : Response>;
|
|
179
|
+
options: {
|
|
180
|
+
method: "POST";
|
|
181
|
+
requireHeaders: false;
|
|
182
|
+
} & {
|
|
183
|
+
use: any[];
|
|
184
|
+
};
|
|
185
|
+
path: "/playcademy";
|
|
186
|
+
};
|
|
187
|
+
};
|
|
188
|
+
};
|
|
142
189
|
fetchPlugins: import("@better-fetch/fetch").BetterFetchPlugin[];
|
|
143
190
|
};
|
package/dist/client.js
CHANGED
|
@@ -11,23 +11,27 @@ var __export = (target, all) => {
|
|
|
11
11
|
|
|
12
12
|
// src/utils.ts
|
|
13
13
|
function isPlatformMode() {
|
|
14
|
-
if (typeof window === "undefined")
|
|
14
|
+
if (typeof globalThis.window === "undefined") {
|
|
15
15
|
return false;
|
|
16
|
-
|
|
16
|
+
}
|
|
17
|
+
if (globalThis.self === window.top) {
|
|
17
18
|
return false;
|
|
19
|
+
}
|
|
18
20
|
return true;
|
|
19
21
|
}
|
|
20
22
|
function isSafari() {
|
|
21
|
-
if (typeof window === "undefined")
|
|
23
|
+
if (typeof globalThis.window === "undefined") {
|
|
22
24
|
return false;
|
|
25
|
+
}
|
|
23
26
|
const ua = navigator.userAgent;
|
|
24
27
|
return ua.includes("Safari") && !ua.includes("Chrome") && !ua.includes("Chromium");
|
|
25
28
|
}
|
|
26
29
|
function getPlatformToken() {
|
|
27
|
-
if (typeof window === "undefined")
|
|
30
|
+
if (typeof globalThis.window === "undefined") {
|
|
28
31
|
return null;
|
|
32
|
+
}
|
|
29
33
|
try {
|
|
30
|
-
return
|
|
34
|
+
return globalThis.PLAYCADEMY?.token || null;
|
|
31
35
|
} catch {
|
|
32
36
|
return null;
|
|
33
37
|
}
|
|
@@ -36,12 +40,15 @@ function hasStorageAccessAPI() {
|
|
|
36
40
|
return typeof document !== "undefined" && "hasStorageAccess" in document;
|
|
37
41
|
}
|
|
38
42
|
async function needsStorageAccess() {
|
|
39
|
-
if (!isPlatformMode())
|
|
43
|
+
if (!isPlatformMode()) {
|
|
40
44
|
return false;
|
|
41
|
-
|
|
45
|
+
}
|
|
46
|
+
if (!isSafari()) {
|
|
42
47
|
return false;
|
|
43
|
-
|
|
48
|
+
}
|
|
49
|
+
if (!hasStorageAccessAPI()) {
|
|
44
50
|
return false;
|
|
51
|
+
}
|
|
45
52
|
try {
|
|
46
53
|
const hasAccess = await document.hasStorageAccess();
|
|
47
54
|
return !hasAccess;
|
|
@@ -50,8 +57,9 @@ async function needsStorageAccess() {
|
|
|
50
57
|
}
|
|
51
58
|
}
|
|
52
59
|
async function requestStorageAccess() {
|
|
53
|
-
if (!hasStorageAccessAPI())
|
|
60
|
+
if (!hasStorageAccessAPI()) {
|
|
54
61
|
return false;
|
|
62
|
+
}
|
|
55
63
|
try {
|
|
56
64
|
await document.requestStorageAccess();
|
|
57
65
|
return true;
|
|
@@ -62,8 +70,9 @@ async function requestStorageAccess() {
|
|
|
62
70
|
|
|
63
71
|
// src/fetch.ts
|
|
64
72
|
async function ensureStorageAccess() {
|
|
65
|
-
if (!isSafari())
|
|
73
|
+
if (!isSafari()) {
|
|
66
74
|
return true;
|
|
75
|
+
}
|
|
67
76
|
const needs = await needsStorageAccess();
|
|
68
77
|
if (needs) {
|
|
69
78
|
return false;
|
|
@@ -72,8 +81,8 @@ async function ensureStorageAccess() {
|
|
|
72
81
|
await document.requestStorageAccess();
|
|
73
82
|
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
74
83
|
return true;
|
|
75
|
-
} catch (
|
|
76
|
-
console.error("[Playcademy Auth] Safari Storage Access activation failed:",
|
|
84
|
+
} catch (error) {
|
|
85
|
+
console.error("[Playcademy Auth] Safari Storage Access activation failed:", error);
|
|
77
86
|
return false;
|
|
78
87
|
}
|
|
79
88
|
}
|
|
@@ -104,26 +113,40 @@ function playcademyExchangePlugin(_opts) {
|
|
|
104
113
|
id: "playcademy-exchange",
|
|
105
114
|
name: "Playcademy Exchange",
|
|
106
115
|
async init(url, options) {
|
|
107
|
-
if (exchangeComplete)
|
|
116
|
+
if (exchangeComplete) {
|
|
108
117
|
return { url, options };
|
|
118
|
+
}
|
|
109
119
|
if (exchangePromise) {
|
|
110
120
|
await exchangePromise;
|
|
111
121
|
return { url, options };
|
|
112
122
|
}
|
|
113
123
|
exchangePromise = (async () => {
|
|
114
124
|
const token = await waitForToken();
|
|
115
|
-
if (!token)
|
|
125
|
+
if (!token) {
|
|
116
126
|
return;
|
|
127
|
+
}
|
|
117
128
|
const canProceed = await ensureStorageAccess();
|
|
118
129
|
if (!canProceed) {
|
|
119
130
|
return;
|
|
120
131
|
}
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
132
|
+
try {
|
|
133
|
+
const headers = { Authorization: `Bearer ${token}` };
|
|
134
|
+
if (isPlatformMode()) {
|
|
135
|
+
headers["X-Playcademy-Mode"] = "platform";
|
|
136
|
+
}
|
|
137
|
+
const response = await fetch("/api/auth/playcademy", {
|
|
138
|
+
method: "POST",
|
|
139
|
+
headers,
|
|
140
|
+
credentials: "include"
|
|
141
|
+
});
|
|
142
|
+
if (response.status === 204) {
|
|
143
|
+
exchangeComplete = true;
|
|
144
|
+
} else if (response.status !== 200 && response.status !== 500) {
|
|
145
|
+
console.warn(`[Playcademy Auth] Unexpected response status: ${response.status}`);
|
|
146
|
+
}
|
|
147
|
+
} catch (error) {
|
|
148
|
+
console.warn("[Playcademy Auth] Network error during token exchange:", error);
|
|
149
|
+
}
|
|
127
150
|
})();
|
|
128
151
|
await exchangePromise;
|
|
129
152
|
return { url, options };
|
|
@@ -140,8 +163,9 @@ function removeOverlay() {
|
|
|
140
163
|
}
|
|
141
164
|
}
|
|
142
165
|
function injectStorageAccessOverlay() {
|
|
143
|
-
if (document.getElementById(OVERLAY_ID))
|
|
166
|
+
if (document.getElementById(OVERLAY_ID)) {
|
|
144
167
|
return;
|
|
168
|
+
}
|
|
145
169
|
if (!document.body) {
|
|
146
170
|
document.addEventListener("DOMContentLoaded", injectStorageAccessOverlay);
|
|
147
171
|
return;
|
|
@@ -225,7 +249,7 @@ function injectStorageAccessOverlay() {
|
|
|
225
249
|
const hasAccess = await document.hasStorageAccess();
|
|
226
250
|
if (hasAccess) {
|
|
227
251
|
removeOverlay();
|
|
228
|
-
|
|
252
|
+
globalThis.location.reload();
|
|
229
253
|
return;
|
|
230
254
|
}
|
|
231
255
|
} catch {}
|
|
@@ -233,7 +257,7 @@ function injectStorageAccessOverlay() {
|
|
|
233
257
|
const granted = await requestStorageAccess();
|
|
234
258
|
if (granted) {
|
|
235
259
|
removeOverlay();
|
|
236
|
-
|
|
260
|
+
globalThis.location.reload();
|
|
237
261
|
} else {
|
|
238
262
|
const message = overlay.querySelector(`#${OVERLAY_ID}-message`);
|
|
239
263
|
if (message) {
|
|
@@ -245,10 +269,12 @@ function injectStorageAccessOverlay() {
|
|
|
245
269
|
document.body.appendChild(overlay);
|
|
246
270
|
}
|
|
247
271
|
async function handleStorageAccess(options) {
|
|
248
|
-
if (!options.autoPrompt)
|
|
272
|
+
if (!options.autoPrompt) {
|
|
249
273
|
return;
|
|
250
|
-
|
|
274
|
+
}
|
|
275
|
+
if (!isPlatformMode() || !isSafari()) {
|
|
251
276
|
return;
|
|
277
|
+
}
|
|
252
278
|
const needs = await needsStorageAccess();
|
|
253
279
|
if (needs) {
|
|
254
280
|
injectStorageAccessOverlay();
|
|
@@ -260,7 +286,7 @@ function playcademy(options) {
|
|
|
260
286
|
autoPrompt: options?.safari?.autoPrompt ?? true
|
|
261
287
|
}
|
|
262
288
|
};
|
|
263
|
-
if (typeof window !== "undefined" && opts.safari.autoPrompt) {
|
|
289
|
+
if (typeof globalThis.window !== "undefined" && opts.safari.autoPrompt) {
|
|
264
290
|
if (isPlatformMode() && isSafari()) {
|
|
265
291
|
setTimeout(() => {
|
|
266
292
|
handleStorageAccess(opts.safari);
|
package/dist/server.d.ts
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
* 1. **Platform Mode (iframe)**:
|
|
18
18
|
* - Game receives JWT token from Playcademy platform
|
|
19
19
|
* - Client exchanges token via `/api/auth/playcademy` endpoint
|
|
20
|
-
* - Server verifies token with platform API
|
|
20
|
+
* - Server verifies token with platform API (uses PLAYCADEMY_BASE_URL env var)
|
|
21
21
|
* - Creates or links Better Auth user by `playcademyUserId`
|
|
22
22
|
* - Returns session cookie with CHIPS support
|
|
23
23
|
*
|
|
@@ -30,6 +30,15 @@
|
|
|
30
30
|
* - If a user exists with that `playcademyUserId`, sessions merge
|
|
31
31
|
* - Enables seamless switching between platform and standalone
|
|
32
32
|
*
|
|
33
|
+
* **Development/Testing**:
|
|
34
|
+
*
|
|
35
|
+
* To test deployed games against a local platform API, set the `PLAYCADEMY_AUTH_API_URL`
|
|
36
|
+
* environment variable to override the platform URL (e.g., using a tunnel service):
|
|
37
|
+
*
|
|
38
|
+
* ```bash
|
|
39
|
+
* PLAYCADEMY_AUTH_API_URL=https://your-tunnel.dev
|
|
40
|
+
* ```
|
|
41
|
+
*
|
|
33
42
|
* **Cookie Configuration**:
|
|
34
43
|
*
|
|
35
44
|
* For cross-origin iframe authentication to work, you MUST configure cookies:
|
|
@@ -131,15 +140,15 @@
|
|
|
131
140
|
* }
|
|
132
141
|
* ```
|
|
133
142
|
*/
|
|
134
|
-
export declare
|
|
135
|
-
id:
|
|
143
|
+
export declare function playcademy(): {
|
|
144
|
+
id: string;
|
|
136
145
|
schema: {
|
|
137
146
|
user: {
|
|
138
147
|
fields: {
|
|
139
148
|
playcademyUserId: {
|
|
140
149
|
type: "string";
|
|
141
|
-
unique:
|
|
142
|
-
required:
|
|
150
|
+
unique: boolean;
|
|
151
|
+
required: boolean;
|
|
143
152
|
};
|
|
144
153
|
};
|
|
145
154
|
};
|
|
@@ -168,16 +177,16 @@ export declare const playcademy: () => {
|
|
|
168
177
|
} & {
|
|
169
178
|
query?: Record<string, any> | undefined;
|
|
170
179
|
} & {
|
|
171
|
-
params?: Record<string, any
|
|
180
|
+
params?: Record<string, any> | undefined;
|
|
172
181
|
} & {
|
|
173
|
-
request?: Request;
|
|
182
|
+
request?: Request | undefined;
|
|
174
183
|
} & {
|
|
175
|
-
headers?: HeadersInit;
|
|
184
|
+
headers?: HeadersInit | undefined;
|
|
176
185
|
} & {
|
|
177
|
-
asResponse?: boolean;
|
|
178
|
-
returnHeaders?: boolean;
|
|
179
|
-
use?:
|
|
180
|
-
path?: string;
|
|
186
|
+
asResponse?: boolean | undefined;
|
|
187
|
+
returnHeaders?: boolean | undefined;
|
|
188
|
+
use?: any[] | undefined;
|
|
189
|
+
path?: string | undefined;
|
|
181
190
|
} & {
|
|
182
191
|
asResponse?: AsResponse | undefined;
|
|
183
192
|
returnHeaders?: ReturnHeaders | undefined;
|