@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 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: ReturnType<typeof playcademyServerPlugin>;
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
- if (window.self === window.top)
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 window.PLAYCADEMY?.token || null;
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
- if (!isSafari())
45
+ }
46
+ if (!isSafari()) {
42
47
  return false;
43
- if (!hasStorageAccessAPI())
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 (err) {
76
- console.error("[Playcademy Auth] Safari Storage Access activation failed:", err);
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
- await fetch("/api/auth/playcademy", {
122
- method: "POST",
123
- headers: { Authorization: `Bearer ${token}` },
124
- credentials: "include"
125
- });
126
- exchangeComplete = true;
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
- window.location.reload();
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
- window.location.reload();
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
- if (!isPlatformMode() || !isSafari())
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 const playcademy: () => {
135
- id: "playcademy";
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: true;
142
- required: false;
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?: import("better-call").Middleware[];
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;