@playcademy/sandbox 0.9.0 → 0.9.1-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.
Files changed (3) hide show
  1. package/dist/cli.js +55 -140
  2. package/dist/server.js +55 -140
  3. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -1128,7 +1128,7 @@ var package_default;
1128
1128
  var init_package = __esm(() => {
1129
1129
  package_default = {
1130
1130
  name: "@playcademy/sandbox",
1131
- version: "0.9.0",
1131
+ version: "0.9.1-beta.1",
1132
1132
  description: "Local development server for Playcademy game development",
1133
1133
  type: "module",
1134
1134
  exports: {
@@ -110749,10 +110749,10 @@ function createSandboxAuthProvider() {
110749
110749
  },
110750
110750
  async mintGameToken(gameId, userId) {
110751
110751
  const header = btoa(JSON.stringify({ alg: "none", typ: "sandbox" }));
110752
- const exp = Date.now() + 15 * 60 * 1000;
110752
+ const exp = Math.floor(Date.now() / 1000) + 15 * 60;
110753
110753
  const payload = btoa(JSON.stringify({ sub: gameId, uid: userId, exp }));
110754
110754
  const token = `${header}.${payload}.sandbox`;
110755
- return { token, exp };
110755
+ return { token, exp: exp * 1000 };
110756
110756
  },
110757
110757
  async validateGameToken(token) {
110758
110758
  try {
@@ -110760,18 +110760,9 @@ function createSandboxAuthProvider() {
110760
110760
  if (parts2.length !== 3) {
110761
110761
  return null;
110762
110762
  }
110763
- if (parts2[2] === "sandbox") {
110764
- const payload2 = JSON.parse(atob(parts2[1]));
110765
- if (payload2.sub && payload2.uid) {
110766
- if (payload2.exp && payload2.exp < Date.now()) {
110767
- log.debug("[SandboxAuthProvider] Token expired");
110768
- return null;
110769
- }
110770
- return payload2;
110771
- }
110772
- }
110773
110763
  const payload = JSON.parse(atob(parts2[1]));
110774
- if (payload.sub && payload.uid) {
110764
+ const nowSeconds = Date.now() / 1000;
110765
+ if (typeof payload?.sub === "string" && payload.sub.length > 0 && typeof payload.uid === "string" && payload.uid.length > 0 && typeof payload.exp === "number" && Number.isFinite(payload.exp) && payload.exp > nowSeconds && payload.exp < nowSeconds + MAX_TOKEN_LIFETIME_SECONDS) {
110775
110766
  return payload;
110776
110767
  }
110777
110768
  return null;
@@ -110869,7 +110860,7 @@ function createSandboxAuthProvider() {
110869
110860
  }
110870
110861
  };
110871
110862
  }
110872
- var sandboxApiKeys, sandboxAssessmentPreparationReceipts, ASSESSMENT_PREPARATION_RECEIPT_LIFETIME_MS, sandboxAssessmentTokens;
110863
+ var sandboxApiKeys, sandboxAssessmentPreparationReceipts, ASSESSMENT_PREPARATION_RECEIPT_LIFETIME_MS, MAX_TOKEN_LIFETIME_SECONDS, sandboxAssessmentTokens;
110873
110864
  var init_auth_provider = __esm(async () => {
110874
110865
  init_src6();
110875
110866
  init_constants();
@@ -110877,6 +110868,7 @@ var init_auth_provider = __esm(async () => {
110877
110868
  sandboxApiKeys = new Map;
110878
110869
  sandboxAssessmentPreparationReceipts = new Map;
110879
110870
  ASSESSMENT_PREPARATION_RECEIPT_LIFETIME_MS = 5 * 60 * 1000;
110871
+ MAX_TOKEN_LIFETIME_SECONDS = 30 * 24 * 60 * 60;
110880
110872
  sandboxAssessmentTokens = new TimebackCache({
110881
110873
  defaultTTL: 2 * 60 * 60 * 1000,
110882
110874
  maxSize: 1000
@@ -112904,56 +112896,13 @@ function extractBearerToken(authHeader) {
112904
112896
  }
112905
112897
  return authHeader.substring(7);
112906
112898
  }
112907
- function parseSandboxToken(token) {
112908
- try {
112909
- const parts2 = token.split(".");
112910
- if (parts2.length !== 3 || parts2[2] !== "sandbox") {
112911
- return null;
112912
- }
112913
- const header = JSON.parse(atob(parts2[0]));
112914
- if (header.typ !== "sandbox") {
112915
- return null;
112916
- }
112917
- const payload = JSON.parse(atob(parts2[1]));
112918
- if (!payload.uid || !payload.sub) {
112919
- return null;
112920
- }
112921
- return {
112922
- userId: payload.uid,
112923
- gameSlug: payload.sub
112924
- };
112925
- } catch {
112926
- return null;
112927
- }
112928
- }
112929
- function parseJwtClaims(token) {
112930
- try {
112931
- const parts2 = token.split(".");
112932
- if (parts2.length === 3 && parts2[1]) {
112933
- const payload = JSON.parse(atob(parts2[1]));
112934
- if (payload.uid) {
112935
- return {
112936
- userId: payload.uid,
112937
- gameId: payload.sub
112938
- };
112939
- }
112940
- }
112941
- } catch {}
112942
- return null;
112943
- }
112944
- function resolveAuth(token) {
112899
+ async function resolveAuth(token) {
112945
112900
  const demoUser = DEMO_TOKENS[token];
112946
112901
  if (demoUser) {
112947
112902
  return { userId: demoUser.id };
112948
112903
  }
112949
- if (token.includes(".")) {
112950
- const sandboxClaims = parseSandboxToken(token);
112951
- if (sandboxClaims) {
112952
- return sandboxClaims;
112953
- }
112954
- return parseJwtClaims(token);
112955
- }
112956
- return null;
112904
+ const payload = await sandboxAuth.validateGameToken(token);
112905
+ return payload ? { userId: payload.uid, gameId: payload.sub } : null;
112957
112906
  }
112958
112907
  async function fetchUserFromDatabase(db2, userId) {
112959
112908
  try {
@@ -112966,18 +112915,6 @@ async function fetchUserFromDatabase(db2, userId) {
112966
112915
  throw error88;
112967
112916
  }
112968
112917
  }
112969
- async function resolveGameIdFromSlug(db2, slug2) {
112970
- try {
112971
- const game2 = await db2.query.games.findFirst({
112972
- where: eq(games.slug, slug2),
112973
- columns: { id: true }
112974
- });
112975
- return game2?.id || null;
112976
- } catch (error88) {
112977
- console.error("[Auth] Error looking up game by slug:", error88);
112978
- return null;
112979
- }
112980
- }
112981
112918
  function isPublicRoute(path, exceptions) {
112982
112919
  return exceptions.some((exception) => {
112983
112920
  if (path === exception) {
@@ -112995,35 +112932,23 @@ async function authenticateRequest(c) {
112995
112932
  const apiKey = c.req.header("x-api-key");
112996
112933
  const token = bearerToken || apiKey;
112997
112934
  if (!token) {
112998
- return {
112999
- success: false,
113000
- error: "No authorization token provided",
113001
- shouldReturn404: true
113002
- };
112935
+ return { success: false, error: "No authorization token provided" };
113003
112936
  }
113004
- const resolved = resolveAuth(token);
112937
+ const resolved = await resolveAuth(token);
113005
112938
  if (!resolved) {
113006
- return {
113007
- success: false,
113008
- error: "Invalid or expired token",
113009
- shouldReturn404: true
113010
- };
112939
+ return { success: false, error: "Invalid or expired token" };
113011
112940
  }
113012
112941
  const claims = resolved;
113013
112942
  const db2 = c.get("db");
113014
112943
  if (!db2) {
113015
112944
  console.error("[Auth] Database not available in context");
113016
- return { success: false, error: "Internal server error", shouldReturn404: false };
112945
+ return { success: false, error: "Internal server error" };
113017
112946
  }
113018
112947
  const user = await fetchUserFromDatabase(db2, claims.userId);
113019
112948
  if (!user) {
113020
- return { success: false, error: "User not found or token invalid", shouldReturn404: true };
112949
+ return { success: false, error: "User not found or token invalid" };
113021
112950
  }
113022
- let gameId = claims.gameId;
113023
- if (!gameId && claims.gameSlug) {
113024
- gameId = await resolveGameIdFromSlug(db2, claims.gameSlug) ?? undefined;
113025
- }
113026
- return { success: true, user, gameId };
112951
+ return { success: true, user, gameId: claims.gameId };
113027
112952
  }
113028
112953
  function setupAuth(options = {}) {
113029
112954
  const { exceptions = [] } = options;
@@ -113043,20 +112968,19 @@ function setupAuth(options = {}) {
113043
112968
  }
113044
112969
  c.set("authError", result.error);
113045
112970
  await next();
113046
- if (result.shouldReturn404 && c.res.status === 404) {
113047
- return;
113048
- }
113049
- return c.json({ error: "Unauthorized", message: result.error }, 401);
113050
112971
  } catch (error88) {
113051
112972
  console.error("[Auth] Unexpected error in authentication middleware:", error88);
113052
112973
  return c.json({ error: "Internal Server Error", message: "Authentication failed" }, 500);
113053
112974
  }
113054
112975
  };
113055
112976
  }
113056
- var init_auth2 = __esm(() => {
112977
+ var sandboxAuth;
112978
+ var init_auth2 = __esm(async () => {
113057
112979
  init_drizzle_orm();
113058
112980
  init_tables_index();
113059
112981
  init_constants();
112982
+ await init_providers();
112983
+ sandboxAuth = createSandboxAuthProvider();
113060
112984
  });
113061
112985
 
113062
112986
  // src/server/app.ts
@@ -113075,11 +112999,11 @@ function createApp(db2, options) {
113075
112999
  }));
113076
113000
  return app;
113077
113001
  }
113078
- var init_app = __esm(() => {
113002
+ var init_app = __esm(async () => {
113079
113003
  init_dist7();
113080
113004
  init_cors();
113081
113005
  init_logger2();
113082
- init_auth2();
113006
+ await init_auth2();
113083
113007
  });
113084
113008
 
113085
113009
  // ../../node_modules/.bun/@electric-sql+pglite@0.3.16/node_modules/@electric-sql/pglite/dist/chunk-QY3QWFKW.js
@@ -169208,18 +169132,33 @@ var init_sessions = __esm(async () => {
169208
169132
  });
169209
169133
 
169210
169134
  // src/routes/platform/games/verify.ts
169211
- var gameVerifyRouter;
169135
+ function toUserInfo(userData) {
169136
+ return {
169137
+ sub: userData.id,
169138
+ email: userData.email || "",
169139
+ name: userData.name || userData.username || "",
169140
+ email_verified: true,
169141
+ given_name: undefined,
169142
+ family_name: undefined,
169143
+ timeback_id: userData.timebackId || undefined
169144
+ };
169145
+ }
169146
+ var gameVerifyRouter, sandboxAuth2;
169212
169147
  var init_verify = __esm(async () => {
169213
169148
  init_dist7();
169214
169149
  init_errors2();
169215
169150
  init_constants();
169216
169151
  init_error_handler();
169217
- await init_api3();
169152
+ await __promiseAll([
169153
+ init_api3(),
169154
+ init_providers()
169155
+ ]);
169218
169156
  gameVerifyRouter = new Hono2;
169157
+ sandboxAuth2 = createSandboxAuthProvider();
169219
169158
  gameVerifyRouter.post("/verify", async (c2) => {
169220
169159
  const body2 = await c2.req.json().catch(() => ({}));
169221
169160
  const token = body2?.token;
169222
- if (!token) {
169161
+ if (typeof token !== "string" || !token) {
169223
169162
  return c2.json({ error: "Missing token" }, 400);
169224
169163
  }
169225
169164
  const demoUser = DEMO_TOKENS[token];
@@ -169232,49 +169171,25 @@ var init_verify = __esm(async () => {
169232
169171
  return c2.json({ error: "User not found in sandbox" }, 500);
169233
169172
  }
169234
169173
  return c2.json({
169235
- claims: { sandbox: true },
169174
+ claims: { sandbox: true, exp: Math.floor(Date.now() / 1000) + 15 * 60 },
169236
169175
  gameId: MOCK_GAME_ID,
169237
- user: {
169238
- sub: userData.id,
169239
- email: userData.email || "",
169240
- name: userData.name || userData.username || "",
169241
- email_verified: true,
169242
- given_name: undefined,
169243
- family_name: undefined,
169244
- timeback_id: userData.timebackId || undefined
169245
- }
169176
+ user: toUserInfo(userData)
169246
169177
  });
169247
169178
  }
169248
169179
  if (token.endsWith(".sandbox")) {
169180
+ const payload = await sandboxAuth2.validateGameToken(token);
169181
+ if (!payload) {
169182
+ return c2.json({ error: "Invalid or expired sandbox token" }, 400);
169183
+ }
169249
169184
  try {
169250
- const parts2 = token.split(".");
169251
- if (parts2.length === 3) {
169252
- const payload = JSON.parse(atob(parts2[1]));
169253
- const userId = payload.uid;
169254
- const gameIdOrSlug = payload.sub;
169255
- const db2 = c2.get("db");
169256
- const userData = await db2.query.users.findFirst({
169257
- where: (users3, { eq: eq3 }) => eq3(users3.id, userId)
169258
- });
169259
- if (!userData) {
169260
- return c2.json({ error: "User not found in sandbox" }, 500);
169261
- }
169262
- return c2.json({
169263
- claims: payload,
169264
- gameId: gameIdOrSlug,
169265
- user: {
169266
- sub: userData.id,
169267
- email: userData.email || "",
169268
- name: userData.name || userData.username || "",
169269
- email_verified: true,
169270
- given_name: undefined,
169271
- family_name: undefined,
169272
- timeback_id: userData.timebackId || undefined
169273
- }
169274
- });
169275
- } else {
169276
- throw new Error("Malformed sandbox token: expected 3 parts");
169185
+ const db2 = c2.get("db");
169186
+ const userData = await db2.query.users.findFirst({
169187
+ where: (users3, { eq: eq3 }) => eq3(users3.id, payload.uid)
169188
+ });
169189
+ if (!userData) {
169190
+ return c2.json({ error: "User not found in sandbox" }, 500);
169277
169191
  }
169192
+ return c2.json({ claims: payload, gameId: payload.sub, user: toUserInfo(userData) });
169278
169193
  } catch {
169279
169194
  return c2.json({ error: "Invalid sandbox token" }, 400);
169280
169195
  }
@@ -169782,13 +169697,13 @@ var init_server = __esm(async () => {
169782
169697
  init_port();
169783
169698
  init_package();
169784
169699
  init_config();
169785
- init_app();
169786
169700
  init_database2();
169787
169701
  init_options();
169788
169702
  await __promiseAll([
169789
169703
  init_api3(),
169790
169704
  init_context(),
169791
- init_providers()
169705
+ init_providers(),
169706
+ init_app()
169792
169707
  ]);
169793
169708
  version5 = package_default.version;
169794
169709
  });
package/dist/server.js CHANGED
@@ -1127,7 +1127,7 @@ var package_default;
1127
1127
  var init_package = __esm(() => {
1128
1128
  package_default = {
1129
1129
  name: "@playcademy/sandbox",
1130
- version: "0.9.0",
1130
+ version: "0.9.1-beta.1",
1131
1131
  description: "Local development server for Playcademy game development",
1132
1132
  type: "module",
1133
1133
  exports: {
@@ -110748,10 +110748,10 @@ function createSandboxAuthProvider() {
110748
110748
  },
110749
110749
  async mintGameToken(gameId, userId) {
110750
110750
  const header = btoa(JSON.stringify({ alg: "none", typ: "sandbox" }));
110751
- const exp = Date.now() + 15 * 60 * 1000;
110751
+ const exp = Math.floor(Date.now() / 1000) + 15 * 60;
110752
110752
  const payload = btoa(JSON.stringify({ sub: gameId, uid: userId, exp }));
110753
110753
  const token = `${header}.${payload}.sandbox`;
110754
- return { token, exp };
110754
+ return { token, exp: exp * 1000 };
110755
110755
  },
110756
110756
  async validateGameToken(token) {
110757
110757
  try {
@@ -110759,18 +110759,9 @@ function createSandboxAuthProvider() {
110759
110759
  if (parts2.length !== 3) {
110760
110760
  return null;
110761
110761
  }
110762
- if (parts2[2] === "sandbox") {
110763
- const payload2 = JSON.parse(atob(parts2[1]));
110764
- if (payload2.sub && payload2.uid) {
110765
- if (payload2.exp && payload2.exp < Date.now()) {
110766
- log.debug("[SandboxAuthProvider] Token expired");
110767
- return null;
110768
- }
110769
- return payload2;
110770
- }
110771
- }
110772
110762
  const payload = JSON.parse(atob(parts2[1]));
110773
- if (payload.sub && payload.uid) {
110763
+ const nowSeconds = Date.now() / 1000;
110764
+ if (typeof payload?.sub === "string" && payload.sub.length > 0 && typeof payload.uid === "string" && payload.uid.length > 0 && typeof payload.exp === "number" && Number.isFinite(payload.exp) && payload.exp > nowSeconds && payload.exp < nowSeconds + MAX_TOKEN_LIFETIME_SECONDS) {
110774
110765
  return payload;
110775
110766
  }
110776
110767
  return null;
@@ -110868,7 +110859,7 @@ function createSandboxAuthProvider() {
110868
110859
  }
110869
110860
  };
110870
110861
  }
110871
- var sandboxApiKeys, sandboxAssessmentPreparationReceipts, ASSESSMENT_PREPARATION_RECEIPT_LIFETIME_MS, sandboxAssessmentTokens;
110862
+ var sandboxApiKeys, sandboxAssessmentPreparationReceipts, ASSESSMENT_PREPARATION_RECEIPT_LIFETIME_MS, MAX_TOKEN_LIFETIME_SECONDS, sandboxAssessmentTokens;
110872
110863
  var init_auth_provider = __esm(async () => {
110873
110864
  init_src6();
110874
110865
  init_constants();
@@ -110876,6 +110867,7 @@ var init_auth_provider = __esm(async () => {
110876
110867
  sandboxApiKeys = new Map;
110877
110868
  sandboxAssessmentPreparationReceipts = new Map;
110878
110869
  ASSESSMENT_PREPARATION_RECEIPT_LIFETIME_MS = 5 * 60 * 1000;
110870
+ MAX_TOKEN_LIFETIME_SECONDS = 30 * 24 * 60 * 60;
110879
110871
  sandboxAssessmentTokens = new TimebackCache({
110880
110872
  defaultTTL: 2 * 60 * 60 * 1000,
110881
110873
  maxSize: 1000
@@ -112903,56 +112895,13 @@ function extractBearerToken(authHeader) {
112903
112895
  }
112904
112896
  return authHeader.substring(7);
112905
112897
  }
112906
- function parseSandboxToken(token) {
112907
- try {
112908
- const parts2 = token.split(".");
112909
- if (parts2.length !== 3 || parts2[2] !== "sandbox") {
112910
- return null;
112911
- }
112912
- const header = JSON.parse(atob(parts2[0]));
112913
- if (header.typ !== "sandbox") {
112914
- return null;
112915
- }
112916
- const payload = JSON.parse(atob(parts2[1]));
112917
- if (!payload.uid || !payload.sub) {
112918
- return null;
112919
- }
112920
- return {
112921
- userId: payload.uid,
112922
- gameSlug: payload.sub
112923
- };
112924
- } catch {
112925
- return null;
112926
- }
112927
- }
112928
- function parseJwtClaims(token) {
112929
- try {
112930
- const parts2 = token.split(".");
112931
- if (parts2.length === 3 && parts2[1]) {
112932
- const payload = JSON.parse(atob(parts2[1]));
112933
- if (payload.uid) {
112934
- return {
112935
- userId: payload.uid,
112936
- gameId: payload.sub
112937
- };
112938
- }
112939
- }
112940
- } catch {}
112941
- return null;
112942
- }
112943
- function resolveAuth(token) {
112898
+ async function resolveAuth(token) {
112944
112899
  const demoUser = DEMO_TOKENS[token];
112945
112900
  if (demoUser) {
112946
112901
  return { userId: demoUser.id };
112947
112902
  }
112948
- if (token.includes(".")) {
112949
- const sandboxClaims = parseSandboxToken(token);
112950
- if (sandboxClaims) {
112951
- return sandboxClaims;
112952
- }
112953
- return parseJwtClaims(token);
112954
- }
112955
- return null;
112903
+ const payload = await sandboxAuth.validateGameToken(token);
112904
+ return payload ? { userId: payload.uid, gameId: payload.sub } : null;
112956
112905
  }
112957
112906
  async function fetchUserFromDatabase(db2, userId) {
112958
112907
  try {
@@ -112965,18 +112914,6 @@ async function fetchUserFromDatabase(db2, userId) {
112965
112914
  throw error88;
112966
112915
  }
112967
112916
  }
112968
- async function resolveGameIdFromSlug(db2, slug2) {
112969
- try {
112970
- const game2 = await db2.query.games.findFirst({
112971
- where: eq(games.slug, slug2),
112972
- columns: { id: true }
112973
- });
112974
- return game2?.id || null;
112975
- } catch (error88) {
112976
- console.error("[Auth] Error looking up game by slug:", error88);
112977
- return null;
112978
- }
112979
- }
112980
112917
  function isPublicRoute(path, exceptions) {
112981
112918
  return exceptions.some((exception) => {
112982
112919
  if (path === exception) {
@@ -112994,35 +112931,23 @@ async function authenticateRequest(c) {
112994
112931
  const apiKey = c.req.header("x-api-key");
112995
112932
  const token = bearerToken || apiKey;
112996
112933
  if (!token) {
112997
- return {
112998
- success: false,
112999
- error: "No authorization token provided",
113000
- shouldReturn404: true
113001
- };
112934
+ return { success: false, error: "No authorization token provided" };
113002
112935
  }
113003
- const resolved = resolveAuth(token);
112936
+ const resolved = await resolveAuth(token);
113004
112937
  if (!resolved) {
113005
- return {
113006
- success: false,
113007
- error: "Invalid or expired token",
113008
- shouldReturn404: true
113009
- };
112938
+ return { success: false, error: "Invalid or expired token" };
113010
112939
  }
113011
112940
  const claims = resolved;
113012
112941
  const db2 = c.get("db");
113013
112942
  if (!db2) {
113014
112943
  console.error("[Auth] Database not available in context");
113015
- return { success: false, error: "Internal server error", shouldReturn404: false };
112944
+ return { success: false, error: "Internal server error" };
113016
112945
  }
113017
112946
  const user = await fetchUserFromDatabase(db2, claims.userId);
113018
112947
  if (!user) {
113019
- return { success: false, error: "User not found or token invalid", shouldReturn404: true };
112948
+ return { success: false, error: "User not found or token invalid" };
113020
112949
  }
113021
- let gameId = claims.gameId;
113022
- if (!gameId && claims.gameSlug) {
113023
- gameId = await resolveGameIdFromSlug(db2, claims.gameSlug) ?? undefined;
113024
- }
113025
- return { success: true, user, gameId };
112950
+ return { success: true, user, gameId: claims.gameId };
113026
112951
  }
113027
112952
  function setupAuth(options = {}) {
113028
112953
  const { exceptions = [] } = options;
@@ -113042,20 +112967,19 @@ function setupAuth(options = {}) {
113042
112967
  }
113043
112968
  c.set("authError", result.error);
113044
112969
  await next();
113045
- if (result.shouldReturn404 && c.res.status === 404) {
113046
- return;
113047
- }
113048
- return c.json({ error: "Unauthorized", message: result.error }, 401);
113049
112970
  } catch (error88) {
113050
112971
  console.error("[Auth] Unexpected error in authentication middleware:", error88);
113051
112972
  return c.json({ error: "Internal Server Error", message: "Authentication failed" }, 500);
113052
112973
  }
113053
112974
  };
113054
112975
  }
113055
- var init_auth2 = __esm(() => {
112976
+ var sandboxAuth;
112977
+ var init_auth2 = __esm(async () => {
113056
112978
  init_drizzle_orm();
113057
112979
  init_tables_index();
113058
112980
  init_constants();
112981
+ await init_providers();
112982
+ sandboxAuth = createSandboxAuthProvider();
113059
112983
  });
113060
112984
 
113061
112985
  // src/server/app.ts
@@ -113074,11 +112998,11 @@ function createApp(db2, options) {
113074
112998
  }));
113075
112999
  return app;
113076
113000
  }
113077
- var init_app = __esm(() => {
113001
+ var init_app = __esm(async () => {
113078
113002
  init_dist7();
113079
113003
  init_cors();
113080
113004
  init_logger2();
113081
- init_auth2();
113005
+ await init_auth2();
113082
113006
  });
113083
113007
 
113084
113008
  // ../../node_modules/.bun/@electric-sql+pglite@0.3.16/node_modules/@electric-sql/pglite/dist/chunk-QY3QWFKW.js
@@ -169207,18 +169131,33 @@ var init_sessions = __esm(async () => {
169207
169131
  });
169208
169132
 
169209
169133
  // src/routes/platform/games/verify.ts
169210
- var gameVerifyRouter;
169134
+ function toUserInfo(userData) {
169135
+ return {
169136
+ sub: userData.id,
169137
+ email: userData.email || "",
169138
+ name: userData.name || userData.username || "",
169139
+ email_verified: true,
169140
+ given_name: undefined,
169141
+ family_name: undefined,
169142
+ timeback_id: userData.timebackId || undefined
169143
+ };
169144
+ }
169145
+ var gameVerifyRouter, sandboxAuth2;
169211
169146
  var init_verify = __esm(async () => {
169212
169147
  init_dist7();
169213
169148
  init_errors2();
169214
169149
  init_constants();
169215
169150
  init_error_handler();
169216
- await init_api3();
169151
+ await __promiseAll([
169152
+ init_api3(),
169153
+ init_providers()
169154
+ ]);
169217
169155
  gameVerifyRouter = new Hono2;
169156
+ sandboxAuth2 = createSandboxAuthProvider();
169218
169157
  gameVerifyRouter.post("/verify", async (c2) => {
169219
169158
  const body2 = await c2.req.json().catch(() => ({}));
169220
169159
  const token = body2?.token;
169221
- if (!token) {
169160
+ if (typeof token !== "string" || !token) {
169222
169161
  return c2.json({ error: "Missing token" }, 400);
169223
169162
  }
169224
169163
  const demoUser = DEMO_TOKENS[token];
@@ -169231,49 +169170,25 @@ var init_verify = __esm(async () => {
169231
169170
  return c2.json({ error: "User not found in sandbox" }, 500);
169232
169171
  }
169233
169172
  return c2.json({
169234
- claims: { sandbox: true },
169173
+ claims: { sandbox: true, exp: Math.floor(Date.now() / 1000) + 15 * 60 },
169235
169174
  gameId: MOCK_GAME_ID,
169236
- user: {
169237
- sub: userData.id,
169238
- email: userData.email || "",
169239
- name: userData.name || userData.username || "",
169240
- email_verified: true,
169241
- given_name: undefined,
169242
- family_name: undefined,
169243
- timeback_id: userData.timebackId || undefined
169244
- }
169175
+ user: toUserInfo(userData)
169245
169176
  });
169246
169177
  }
169247
169178
  if (token.endsWith(".sandbox")) {
169179
+ const payload = await sandboxAuth2.validateGameToken(token);
169180
+ if (!payload) {
169181
+ return c2.json({ error: "Invalid or expired sandbox token" }, 400);
169182
+ }
169248
169183
  try {
169249
- const parts2 = token.split(".");
169250
- if (parts2.length === 3) {
169251
- const payload = JSON.parse(atob(parts2[1]));
169252
- const userId = payload.uid;
169253
- const gameIdOrSlug = payload.sub;
169254
- const db2 = c2.get("db");
169255
- const userData = await db2.query.users.findFirst({
169256
- where: (users3, { eq: eq3 }) => eq3(users3.id, userId)
169257
- });
169258
- if (!userData) {
169259
- return c2.json({ error: "User not found in sandbox" }, 500);
169260
- }
169261
- return c2.json({
169262
- claims: payload,
169263
- gameId: gameIdOrSlug,
169264
- user: {
169265
- sub: userData.id,
169266
- email: userData.email || "",
169267
- name: userData.name || userData.username || "",
169268
- email_verified: true,
169269
- given_name: undefined,
169270
- family_name: undefined,
169271
- timeback_id: userData.timebackId || undefined
169272
- }
169273
- });
169274
- } else {
169275
- throw new Error("Malformed sandbox token: expected 3 parts");
169184
+ const db2 = c2.get("db");
169185
+ const userData = await db2.query.users.findFirst({
169186
+ where: (users3, { eq: eq3 }) => eq3(users3.id, payload.uid)
169187
+ });
169188
+ if (!userData) {
169189
+ return c2.json({ error: "User not found in sandbox" }, 500);
169276
169190
  }
169191
+ return c2.json({ claims: payload, gameId: payload.sub, user: toUserInfo(userData) });
169277
169192
  } catch {
169278
169193
  return c2.json({ error: "Invalid sandbox token" }, 400);
169279
169194
  }
@@ -169781,13 +169696,13 @@ var init_server = __esm(async () => {
169781
169696
  init_port();
169782
169697
  init_package();
169783
169698
  init_config();
169784
- init_app();
169785
169699
  init_database2();
169786
169700
  init_options();
169787
169701
  await __promiseAll([
169788
169702
  init_api3(),
169789
169703
  init_context(),
169790
- init_providers()
169704
+ init_providers(),
169705
+ init_app()
169791
169706
  ]);
169792
169707
  version5 = package_default.version;
169793
169708
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@playcademy/sandbox",
3
- "version": "0.9.0",
3
+ "version": "0.9.1-beta.1",
4
4
  "description": "Local development server for Playcademy game development",
5
5
  "type": "module",
6
6
  "exports": {