@playcademy/better-auth 0.0.1 → 0.0.2

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.js CHANGED
@@ -118,12 +118,24 @@ function playcademyExchangePlugin(_opts) {
118
118
  if (!canProceed) {
119
119
  return;
120
120
  }
121
- await fetch("/api/auth/playcademy", {
122
- method: "POST",
123
- headers: { Authorization: `Bearer ${token}` },
124
- credentials: "include"
125
- });
126
- exchangeComplete = true;
121
+ try {
122
+ const headers = { Authorization: `Bearer ${token}` };
123
+ if (isPlatformMode()) {
124
+ headers["X-Playcademy-Mode"] = "platform";
125
+ }
126
+ const response = await fetch("/api/auth/playcademy", {
127
+ method: "POST",
128
+ headers,
129
+ credentials: "include"
130
+ });
131
+ if (response.status === 204) {
132
+ exchangeComplete = true;
133
+ } else if (response.status !== 200 && response.status !== 500) {
134
+ console.warn(`[Playcademy Auth] Unexpected response status: ${response.status}`);
135
+ }
136
+ } catch (error) {
137
+ console.warn("[Playcademy Auth] Network error during token exchange:", error);
138
+ }
127
139
  })();
128
140
  await exchangePromise;
129
141
  return { url, options };
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:
package/dist/server.js CHANGED
@@ -20473,7 +20473,6 @@ Please set the PLAYCADEMY_BASE_URL environment variable`);
20473
20473
  // src/server.ts
20474
20474
  var DEFAULT_SESSION_MAX_AGE = 60 * 60 * 24 * 7;
20475
20475
  var DEFAULT_COOKIE_PATH = "/";
20476
- var DEV_TUNNEL_URL = "https://hbauer.playcademy.dev";
20477
20476
  function extractGameToken(authHeader) {
20478
20477
  if (!authHeader?.startsWith("Bearer ")) {
20479
20478
  throw new Error("Missing or invalid Authorization header");
@@ -20602,50 +20601,66 @@ var playcademy = () => {
20602
20601
  }, async (ctx) => {
20603
20602
  const authHeader = ctx.request?.headers.get("authorization");
20604
20603
  const gameToken = extractGameToken(authHeader ?? "");
20605
- const isLocalDev = ctx.request?.url.includes("localhost");
20606
- const platformApiUrl = isLocalDev ? undefined : DEV_TUNNEL_URL;
20604
+ const authApiUrl = process.env.PLAYCADEMY_AUTH_API_URL || undefined;
20607
20605
  let verified = null;
20608
20606
  try {
20609
- verified = await verifyGameToken(gameToken, {
20610
- baseUrl: platformApiUrl
20607
+ verified = await verifyGameToken(gameToken, { baseUrl: authApiUrl });
20608
+ } catch (error4) {
20609
+ const errorMessage = error4 instanceof Error ? error4.message : String(error4);
20610
+ const platformMode = ctx.request?.headers.get("x-playcademy-mode");
20611
+ if (platformMode === "platform") {
20612
+ console.error("[Playcademy Auth] Token verification failed:", {
20613
+ error: errorMessage,
20614
+ hasAuthApiOverride: !!authApiUrl
20615
+ });
20616
+ }
20617
+ return new Response(JSON.stringify({ ok: false, code: "invalid_token" }), {
20618
+ status: 200,
20619
+ headers: { "Content-Type": "application/json" }
20611
20620
  });
20612
- } catch {
20613
- return new Response(null, { status: 204 });
20614
- }
20615
- const user = await findOrCreateUser(ctx.context.adapter, verified.user);
20616
- if (!user) {
20617
- throw new Error("Failed to find or create user");
20618
20621
  }
20619
- const cookieName = ctx.context.authCookies.sessionToken.name;
20620
- const cookieHeader = ctx.request?.headers.get("cookie") ?? null;
20621
- const ctxSecret = ctx.context.secret;
20622
- const existingSession = await readSignedSessionCookie(cookieHeader, cookieName, ctxSecret);
20623
- if (existingSession) {
20624
- const isValid = await hasValidSession(ctx.context.adapter, existingSession.token, user.id);
20625
- if (isValid) {
20626
- return new Response(null, { status: 204 });
20622
+ try {
20623
+ const user = await findOrCreateUser(ctx.context.adapter, verified.user);
20624
+ if (!user) {
20625
+ throw new Error("Failed to find or create user");
20627
20626
  }
20628
- }
20629
- const session = await ctx.context.internalAdapter.createSession(user.id, ctx);
20630
- if (!session) {
20631
- throw new Error("Failed to create session");
20632
- }
20633
- const cookieOpts = ctx.context.authCookies.sessionToken.options;
20634
- const setCookieValue = await buildCrossSiteCookie({
20635
- cookieName,
20636
- sessionToken: session.token,
20637
- secret: ctxSecret,
20638
- maxAge: cookieOpts.maxAge ?? DEFAULT_SESSION_MAX_AGE,
20639
- path: cookieOpts.path ?? DEFAULT_COOKIE_PATH,
20640
- userAgent: ctx.request?.headers.get("user-agent") ?? null
20641
- });
20642
- return new Response(null, {
20643
- status: 200,
20644
- headers: {
20645
- "Set-Cookie": setCookieValue,
20646
- "Content-Type": "application/json"
20627
+ const cookieName = ctx.context.authCookies.sessionToken.name;
20628
+ const cookieHeader = ctx.request?.headers.get("cookie") ?? null;
20629
+ const ctxSecret = ctx.context.secret;
20630
+ const existingSession = await readSignedSessionCookie(cookieHeader, cookieName, ctxSecret);
20631
+ if (existingSession) {
20632
+ const isValid = await hasValidSession(ctx.context.adapter, existingSession.token, user.id);
20633
+ if (isValid) {
20634
+ return new Response(null, { status: 204 });
20635
+ }
20647
20636
  }
20648
- });
20637
+ const session = await ctx.context.internalAdapter.createSession(user.id, ctx);
20638
+ if (!session) {
20639
+ throw new Error("Failed to create session");
20640
+ }
20641
+ const cookieOpts = ctx.context.authCookies.sessionToken.options;
20642
+ const setCookieValue = await buildCrossSiteCookie({
20643
+ cookieName,
20644
+ sessionToken: session.token,
20645
+ secret: ctxSecret,
20646
+ maxAge: cookieOpts.maxAge ?? DEFAULT_SESSION_MAX_AGE,
20647
+ path: cookieOpts.path ?? DEFAULT_COOKIE_PATH,
20648
+ userAgent: ctx.request?.headers.get("user-agent") ?? null
20649
+ });
20650
+ return new Response(null, {
20651
+ status: 204,
20652
+ headers: {
20653
+ "Set-Cookie": setCookieValue
20654
+ }
20655
+ });
20656
+ } catch (error4) {
20657
+ const errorMessage = error4 instanceof Error ? error4.message : String(error4);
20658
+ console.error("[Playcademy Auth] Internal error during token exchange/session setup:", { error: errorMessage });
20659
+ return new Response(JSON.stringify({ ok: false, code: "internal_error" }), {
20660
+ status: 500,
20661
+ headers: { "Content-Type": "application/json" }
20662
+ });
20663
+ }
20649
20664
  })
20650
20665
  }
20651
20666
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@playcademy/better-auth",
3
- "version": "0.0.1",
3
+ "version": "0.0.2",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  "./server": {
@@ -28,7 +28,7 @@
28
28
  },
29
29
  "devDependencies": {
30
30
  "@inquirer/prompts": "^7.9.0",
31
- "@playcademy/sdk": "0.1.14",
31
+ "@playcademy/sdk": "0.1.18",
32
32
  "@playcademy/utils": "0.0.1",
33
33
  "@types/bun": "latest",
34
34
  "typescript": "^5.7.2"