playcademy 0.14.13 → 0.14.14-alpha.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/constants/src/academics.ts +28 -0
- package/dist/constants/src/domains.ts +22 -5
- package/dist/constants/src/index.ts +1 -0
- package/dist/constants.d.ts +54 -20
- package/dist/constants.js +59 -19
- package/dist/db.js +68 -18
- package/dist/edge-play/src/entry/middleware.ts +60 -0
- package/dist/edge-play/src/entry/session.ts +34 -0
- package/dist/edge-play/src/entry.ts +6 -0
- package/dist/index.d.ts +220 -128
- package/dist/index.js +1198 -461
- package/dist/templates/api/sample-database.ts.template +18 -39
- package/dist/templates/api/sample-kv.ts.template +53 -46
- package/dist/templates/auth/auth.ts.template +1 -1
- package/dist/templates/config/timeback-config.js.template +2 -2
- package/dist/templates/database/db-schema-example.ts.template +29 -0
- package/dist/templates/database/db-schema-index.ts.template +1 -2
- package/dist/templates/database/db-seed.ts.template +12 -20
- package/dist/templates/database/db-types.ts.template +2 -10
- package/dist/templates/database/drizzle-config.ts.template +2 -2
- package/dist/utils.d.ts +9 -2
- package/dist/utils.js +211 -71
- package/dist/version.js +1 -1
- package/package.json +1 -1
- package/dist/templates/database/db-schema-scores.ts.template +0 -43
- package/dist/templates/database/db-schema-users.ts.template +0 -23
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Academic Content Constants
|
|
3
|
+
*
|
|
4
|
+
* Constants for academic problem sets and educational content served via TimeBack.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Problem Sets Storage
|
|
9
|
+
*/
|
|
10
|
+
export const PROBLEM_SETS = {
|
|
11
|
+
/** Base S3 prefix for problem sets */
|
|
12
|
+
S3_PREFIX: 'academics/problems/v1',
|
|
13
|
+
|
|
14
|
+
/** CDN manifest path */
|
|
15
|
+
MANIFEST_PATH: 'academics/problems/v1/index.json',
|
|
16
|
+
|
|
17
|
+
/** Expected directory structure: {subject}/{grade}/{domain}/{standard}.qti.json */
|
|
18
|
+
DIRECTORY_PATTERN: '{subject}/{grade}/{domain}',
|
|
19
|
+
|
|
20
|
+
/** Current manifest schema version */
|
|
21
|
+
MANIFEST_VERSION: 1,
|
|
22
|
+
|
|
23
|
+
/** Local directory in monorepo */
|
|
24
|
+
SOURCE_DIR: 'static/academics/problems',
|
|
25
|
+
|
|
26
|
+
/** Default XP per problem item */
|
|
27
|
+
DEFAULT_XP_PER_ITEM: 10,
|
|
28
|
+
} as const
|
|
@@ -6,15 +6,32 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
|
-
* Playcademy
|
|
9
|
+
* Core Playcademy domains
|
|
10
|
+
*/
|
|
11
|
+
export const APEX_DOMAIN = 'playcademy.net'
|
|
12
|
+
export const DEV_DOMAIN = 'playcademy.dev'
|
|
13
|
+
export const GAMES_DOMAIN = 'playcademy.gg'
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Playcademy domain names grouped
|
|
10
17
|
*/
|
|
11
18
|
export const PLAYCADEMY_DOMAINS = {
|
|
12
19
|
/** Primary domain (hub, landing pages) */
|
|
13
|
-
apex:
|
|
14
|
-
/**
|
|
15
|
-
|
|
20
|
+
apex: APEX_DOMAIN,
|
|
21
|
+
/** Development/utility domain */
|
|
22
|
+
dev: DEV_DOMAIN,
|
|
16
23
|
/** Game backend worker domain */
|
|
17
|
-
games:
|
|
24
|
+
games: GAMES_DOMAIN,
|
|
25
|
+
} as const
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* CDN domains by environment
|
|
29
|
+
*/
|
|
30
|
+
export const CDN_DOMAINS = {
|
|
31
|
+
/** Production CDN: https://cdn.playcademy.net */
|
|
32
|
+
production: `https://cdn.${APEX_DOMAIN}`,
|
|
33
|
+
/** Development CDN: https://cdn.dev.playcademy.net */
|
|
34
|
+
staging: `https://cdn.dev.${APEX_DOMAIN}`,
|
|
18
35
|
} as const
|
|
19
36
|
|
|
20
37
|
/**
|
package/dist/constants.d.ts
CHANGED
|
@@ -7,15 +7,7 @@ export { GAME_WORKER_DOMAINS, PLAYCADEMY_BASE_URLS, PLAYCADEMY_DOMAINS } from '@
|
|
|
7
7
|
* Default directory for custom API routes
|
|
8
8
|
* Used when integrations.customRoutes.directory is not specified in config
|
|
9
9
|
*/
|
|
10
|
-
declare const DEFAULT_API_ROUTES_DIRECTORY
|
|
11
|
-
/**
|
|
12
|
-
* Server root directory (fixed location)
|
|
13
|
-
*/
|
|
14
|
-
declare const SERVER_ROOT_DIRECTORY = "server";
|
|
15
|
-
/**
|
|
16
|
-
* Server library/utilities directory (fixed location)
|
|
17
|
-
*/
|
|
18
|
-
declare const SERVER_LIB_DIRECTORY = "server/lib";
|
|
10
|
+
declare const DEFAULT_API_ROUTES_DIRECTORY: string;
|
|
19
11
|
/**
|
|
20
12
|
* Auth routes subdirectory name within API directory (fixed structure)
|
|
21
13
|
*/
|
|
@@ -92,6 +84,8 @@ declare const CLOUDFLARE_COMPATIBILITY_DATE = "2024-01-01";
|
|
|
92
84
|
declare const CLOUDFLARE_BINDINGS: {
|
|
93
85
|
/** R2 bucket binding name */
|
|
94
86
|
readonly BUCKET: "BUCKET";
|
|
87
|
+
/** Problem sets bucket binding name */
|
|
88
|
+
readonly BUCKET_PROBLEM_SETS: "PROBLEM_SETS";
|
|
95
89
|
/** KV namespace binding name */
|
|
96
90
|
readonly KV: "KV";
|
|
97
91
|
/** D1 database binding name */
|
|
@@ -141,19 +135,30 @@ declare const TSCONFIG_FILES: readonly ["tsconfig.app.json", "tsconfig.json"];
|
|
|
141
135
|
/**
|
|
142
136
|
* Default directory for database files (configurable via playcademy.config)
|
|
143
137
|
*/
|
|
144
|
-
declare const DEFAULT_DATABASE_DIRECTORY
|
|
138
|
+
declare const DEFAULT_DATABASE_DIRECTORY: string;
|
|
145
139
|
/**
|
|
146
140
|
* Schema subdirectory name within database directory (fixed structure)
|
|
147
141
|
*/
|
|
148
142
|
declare const SCHEMA_SUBDIRECTORY = "schema";
|
|
149
143
|
/**
|
|
150
|
-
*
|
|
151
|
-
*/
|
|
152
|
-
declare const
|
|
144
|
+
* Database file names (fixed structure)
|
|
145
|
+
*/
|
|
146
|
+
declare const DB_FILES: {
|
|
147
|
+
/** Index file name */
|
|
148
|
+
readonly INDEX: "index.ts";
|
|
149
|
+
/** Seed file name */
|
|
150
|
+
readonly SEED: "seed.ts";
|
|
151
|
+
/** Types file name */
|
|
152
|
+
readonly TYPES: "types.ts";
|
|
153
|
+
/** Schema index file name */
|
|
154
|
+
readonly SCHEMA_INDEX: "index.ts";
|
|
155
|
+
/** Example schema file name */
|
|
156
|
+
readonly EXAMPLE_SCHEMA: "example.ts";
|
|
157
|
+
};
|
|
153
158
|
/**
|
|
154
|
-
*
|
|
159
|
+
* Drizzle config file names
|
|
155
160
|
*/
|
|
156
|
-
declare const
|
|
161
|
+
declare const DRIZZLE_CONFIG_FILES: readonly ["drizzle.config.ts", "drizzle.config.js"];
|
|
157
162
|
|
|
158
163
|
/**
|
|
159
164
|
* Godot engine integration constants
|
|
@@ -179,16 +184,16 @@ declare const GODOT_BUILD_DIRECTORIES: {
|
|
|
179
184
|
/** Root build directory (cleared before each export) */
|
|
180
185
|
readonly ROOT: "build";
|
|
181
186
|
/** Web export subdirectory */
|
|
182
|
-
readonly WEB:
|
|
187
|
+
readonly WEB: string;
|
|
183
188
|
};
|
|
184
189
|
/**
|
|
185
190
|
* Build output file paths
|
|
186
191
|
*/
|
|
187
192
|
declare const GODOT_BUILD_OUTPUTS: {
|
|
188
193
|
/** Exported web build entry point */
|
|
189
|
-
readonly INDEX_HTML:
|
|
194
|
+
readonly INDEX_HTML: string;
|
|
190
195
|
/** Packaged zip file (created by Godot export) */
|
|
191
|
-
readonly ZIP:
|
|
196
|
+
readonly ZIP: string;
|
|
192
197
|
};
|
|
193
198
|
/**
|
|
194
199
|
* Platform-specific Godot executable discovery patterns
|
|
@@ -247,7 +252,7 @@ declare const CLI_USER_DIRECTORIES: {
|
|
|
247
252
|
*/
|
|
248
253
|
declare const CLI_DEFAULT_OUTPUTS: {
|
|
249
254
|
/** Default worker bundle output for debug command */
|
|
250
|
-
readonly WORKER_BUNDLE:
|
|
255
|
+
readonly WORKER_BUNDLE: string;
|
|
251
256
|
};
|
|
252
257
|
/**
|
|
253
258
|
* CLI file names
|
|
@@ -271,9 +276,38 @@ declare const DEFAULT_PORTS: {
|
|
|
271
276
|
readonly BACKEND: 8788;
|
|
272
277
|
};
|
|
273
278
|
|
|
279
|
+
/**
|
|
280
|
+
* Server directory structure constants
|
|
281
|
+
*/
|
|
282
|
+
/**
|
|
283
|
+
* Server root directory (fixed location)
|
|
284
|
+
*/
|
|
285
|
+
declare const SERVER_ROOT_DIRECTORY = "server";
|
|
286
|
+
/**
|
|
287
|
+
* Server library/utilities directory (fixed location)
|
|
288
|
+
*/
|
|
289
|
+
declare const SERVER_LIB_DIRECTORY: string;
|
|
290
|
+
/**
|
|
291
|
+
* Public assets directory (fixed location)
|
|
292
|
+
*/
|
|
293
|
+
declare const PUBLIC_DIRECTORY = "public";
|
|
294
|
+
/**
|
|
295
|
+
* Academic content subdirectory within public/
|
|
296
|
+
*/
|
|
297
|
+
declare const ACADEMICS_PUBLIC_DIRECTORY: string;
|
|
298
|
+
/**
|
|
299
|
+
* Problem sets directory (frontend static assets)
|
|
300
|
+
* Used by TimeBack integration for educational content
|
|
301
|
+
*/
|
|
302
|
+
declare const PROBLEM_SETS_DIRECTORY: string;
|
|
303
|
+
/**
|
|
304
|
+
* Problem sets URL path (for serving via worker/middleware)
|
|
305
|
+
*/
|
|
306
|
+
declare const PROBLEM_SETS_URL_PATH = "academics/problem-sets";
|
|
307
|
+
|
|
274
308
|
/**
|
|
275
309
|
* Config file names to search for
|
|
276
310
|
*/
|
|
277
311
|
declare const CONFIG_FILE_NAMES: string[];
|
|
278
312
|
|
|
279
|
-
export { AUTH_API_SUBDIRECTORY, AUTH_CONFIG_FILE, AUTH_PROVIDER_NAMES, BETTER_AUTH_VERSION, BUCKET_ALWAYS_SKIP, CALLBACK_PATH, CALLBACK_PORT, CLI_DEFAULT_OUTPUTS, CLI_DIRECTORIES, CLI_FILES, CLI_USER_DIRECTORIES, CLOUDFLARE_BINDINGS, CLOUDFLARE_COMPATIBILITY_DATE, CONFIG_FILE_NAMES, DEFAULT_API_ROUTES_DIRECTORY, DEFAULT_DATABASE_DIRECTORY, DEFAULT_PORTS,
|
|
313
|
+
export { ACADEMICS_PUBLIC_DIRECTORY, AUTH_API_SUBDIRECTORY, AUTH_CONFIG_FILE, AUTH_PROVIDER_NAMES, BETTER_AUTH_VERSION, BUCKET_ALWAYS_SKIP, CALLBACK_PATH, CALLBACK_PORT, CLI_DEFAULT_OUTPUTS, CLI_DIRECTORIES, CLI_FILES, CLI_USER_DIRECTORIES, CLOUDFLARE_BINDINGS, CLOUDFLARE_COMPATIBILITY_DATE, CONFIG_FILE_NAMES, DB_FILES, DEFAULT_API_ROUTES_DIRECTORY, DEFAULT_DATABASE_DIRECTORY, DEFAULT_PORTS, DRIZZLE_CONFIG_FILES, ENV_EXAMPLE_FILE, ENV_FILES, GODOT_BUILD_DIRECTORIES, GODOT_BUILD_OUTPUTS, GODOT_EXECUTABLE_PATTERNS, GODOT_EXPORT_PRESETS_FILE, GODOT_PROJECT_FILE, GODOT_WEB_PLATFORM, MINIFLARE_D1_DIRECTORY, OAUTH_CALLBACK_URL_PATTERN, PLACEHOLDER_GAME_URL, PLAYCADEMY_AUTH_VERSION, PROBLEM_SETS_DIRECTORY, PROBLEM_SETS_URL_PATH, PUBLIC_DIRECTORY, SAMPLE_API_SUBDIRECTORY, SAMPLE_BUCKET_FILENAME, SAMPLE_CUSTOM_FILENAME, SAMPLE_DATABASE_FILENAME, SAMPLE_KV_FILENAME, SCHEMA_SUBDIRECTORY, SERVER_LIB_DIRECTORY, SERVER_ROOT_DIRECTORY, SSO_AUTH_TIMEOUT_MS, TSCONFIG_FILES, WORKSPACE_NAME };
|
package/dist/constants.js
CHANGED
|
@@ -1,7 +1,17 @@
|
|
|
1
1
|
// src/constants/api.ts
|
|
2
|
-
|
|
2
|
+
import { join as join2 } from "node:path";
|
|
3
|
+
|
|
4
|
+
// src/constants/server.ts
|
|
5
|
+
import { join } from "node:path";
|
|
3
6
|
var SERVER_ROOT_DIRECTORY = "server";
|
|
4
|
-
var SERVER_LIB_DIRECTORY = "
|
|
7
|
+
var SERVER_LIB_DIRECTORY = join(SERVER_ROOT_DIRECTORY, "lib");
|
|
8
|
+
var PUBLIC_DIRECTORY = "public";
|
|
9
|
+
var ACADEMICS_PUBLIC_DIRECTORY = join(PUBLIC_DIRECTORY, "academics");
|
|
10
|
+
var PROBLEM_SETS_DIRECTORY = join(ACADEMICS_PUBLIC_DIRECTORY, "problem-sets");
|
|
11
|
+
var PROBLEM_SETS_URL_PATH = "academics/problem-sets";
|
|
12
|
+
|
|
13
|
+
// src/constants/api.ts
|
|
14
|
+
var DEFAULT_API_ROUTES_DIRECTORY = join2(SERVER_ROOT_DIRECTORY, "api");
|
|
5
15
|
var AUTH_API_SUBDIRECTORY = "auth";
|
|
6
16
|
var SAMPLE_API_SUBDIRECTORY = "sample";
|
|
7
17
|
var SAMPLE_CUSTOM_FILENAME = "custom.ts";
|
|
@@ -56,9 +66,11 @@ var package_default = {
|
|
|
56
66
|
"sync-engine-assets": "bun scripts/sync-engine-assets.ts",
|
|
57
67
|
"sync-vite-templates": "bun scripts/sync-vite-templates.ts",
|
|
58
68
|
"sync-godot-template": "bun scripts/sync-godot-template.ts",
|
|
69
|
+
"sync-problem-sets": "sst shell -- bun scripts/sync-problem-sets.ts",
|
|
59
70
|
"sync:all": "bun scripts/sync-all.ts",
|
|
60
71
|
cf: "sst shell -- bun scripts/setup-cloudflare-dispatch.ts",
|
|
61
72
|
"list-s3-bucket": "sst shell -- bun scripts/list-s3-bucket.ts",
|
|
73
|
+
"invalidate-cdn": "sst shell -- bun scripts/invalidate-cdn.ts",
|
|
62
74
|
doctor: "bunx sst shell -- bun scripts/doctor.ts",
|
|
63
75
|
format: "bun run --filter '*' format",
|
|
64
76
|
lint: "bun run --filter '*' lint",
|
|
@@ -158,6 +170,8 @@ var CLOUDFLARE_COMPATIBILITY_DATE = "2024-01-01";
|
|
|
158
170
|
var CLOUDFLARE_BINDINGS = {
|
|
159
171
|
/** R2 bucket binding name */
|
|
160
172
|
BUCKET: "BUCKET",
|
|
173
|
+
/** Problem sets bucket binding name */
|
|
174
|
+
BUCKET_PROBLEM_SETS: "PROBLEM_SETS",
|
|
161
175
|
/** KV namespace binding name */
|
|
162
176
|
KV: "KV",
|
|
163
177
|
/** D1 database binding name */
|
|
@@ -166,12 +180,25 @@ var CLOUDFLARE_BINDINGS = {
|
|
|
166
180
|
var MINIFLARE_D1_DIRECTORY = "miniflare-D1DatabaseObject";
|
|
167
181
|
|
|
168
182
|
// src/constants/database.ts
|
|
169
|
-
|
|
183
|
+
import { join as join3 } from "path";
|
|
184
|
+
var DEFAULT_DATABASE_DIRECTORY = join3("server", "db");
|
|
170
185
|
var SCHEMA_SUBDIRECTORY = "schema";
|
|
171
|
-
var
|
|
172
|
-
|
|
186
|
+
var DB_FILES = {
|
|
187
|
+
/** Index file name */
|
|
188
|
+
INDEX: "index.ts",
|
|
189
|
+
/** Seed file name */
|
|
190
|
+
SEED: "seed.ts",
|
|
191
|
+
/** Types file name */
|
|
192
|
+
TYPES: "types.ts",
|
|
193
|
+
/** Schema index file name */
|
|
194
|
+
SCHEMA_INDEX: "index.ts",
|
|
195
|
+
/** Example schema file name */
|
|
196
|
+
EXAMPLE_SCHEMA: "example.ts"
|
|
197
|
+
};
|
|
198
|
+
var DRIZZLE_CONFIG_FILES = ["drizzle.config.ts", "drizzle.config.js"];
|
|
173
199
|
|
|
174
200
|
// src/constants/godot.ts
|
|
201
|
+
import { join as join4 } from "node:path";
|
|
175
202
|
var GODOT_PROJECT_FILE = "project.godot";
|
|
176
203
|
var GODOT_EXPORT_PRESETS_FILE = "export_presets.cfg";
|
|
177
204
|
var GODOT_WEB_PLATFORM = 'platform="Web"';
|
|
@@ -179,13 +206,13 @@ var GODOT_BUILD_DIRECTORIES = {
|
|
|
179
206
|
/** Root build directory (cleared before each export) */
|
|
180
207
|
ROOT: "build",
|
|
181
208
|
/** Web export subdirectory */
|
|
182
|
-
WEB: "build
|
|
209
|
+
WEB: join4("build", "web")
|
|
183
210
|
};
|
|
184
211
|
var GODOT_BUILD_OUTPUTS = {
|
|
185
212
|
/** Exported web build entry point */
|
|
186
|
-
INDEX_HTML: "build
|
|
213
|
+
INDEX_HTML: join4("build", "web", "index.html"),
|
|
187
214
|
/** Packaged zip file (created by Godot export) */
|
|
188
|
-
ZIP: "build
|
|
215
|
+
ZIP: join4("build", "web_playcademy.zip")
|
|
189
216
|
};
|
|
190
217
|
var GODOT_EXECUTABLE_PATTERNS = {
|
|
191
218
|
/** macOS app bundle suffix */
|
|
@@ -208,17 +235,17 @@ var CALLBACK_PATH = "/callback";
|
|
|
208
235
|
var SSO_AUTH_TIMEOUT_MS = 3e4;
|
|
209
236
|
|
|
210
237
|
// src/constants/paths.ts
|
|
211
|
-
import { join } from "path";
|
|
238
|
+
import { join as join5 } from "path";
|
|
212
239
|
var WORKSPACE_NAME = ".playcademy";
|
|
213
240
|
var CLI_DIRECTORIES = {
|
|
214
241
|
/** Root directory for CLI artifacts in workspace */
|
|
215
242
|
WORKSPACE: WORKSPACE_NAME,
|
|
216
243
|
/** Database directory within workspace */
|
|
217
|
-
DATABASE:
|
|
244
|
+
DATABASE: join5(WORKSPACE_NAME, "db"),
|
|
218
245
|
/** KV storage directory within workspace */
|
|
219
|
-
KV:
|
|
246
|
+
KV: join5(WORKSPACE_NAME, "kv"),
|
|
220
247
|
/** Bucket storage directory within workspace */
|
|
221
|
-
BUCKET:
|
|
248
|
+
BUCKET: join5(WORKSPACE_NAME, "bucket")
|
|
222
249
|
};
|
|
223
250
|
var CLI_USER_DIRECTORIES = {
|
|
224
251
|
/** User config directory for auth, games store, etc. */
|
|
@@ -226,7 +253,7 @@ var CLI_USER_DIRECTORIES = {
|
|
|
226
253
|
};
|
|
227
254
|
var CLI_DEFAULT_OUTPUTS = {
|
|
228
255
|
/** Default worker bundle output for debug command */
|
|
229
|
-
WORKER_BUNDLE: "
|
|
256
|
+
WORKER_BUNDLE: join5(WORKSPACE_NAME, "worker-bundle.js")
|
|
230
257
|
};
|
|
231
258
|
var CLI_FILES = {
|
|
232
259
|
/** Auth store file in user config directory */
|
|
@@ -253,13 +280,22 @@ var CONFIG_FILE_NAMES = [
|
|
|
253
280
|
];
|
|
254
281
|
|
|
255
282
|
// ../constants/src/domains.ts
|
|
283
|
+
var APEX_DOMAIN = "playcademy.net";
|
|
284
|
+
var DEV_DOMAIN = "playcademy.dev";
|
|
285
|
+
var GAMES_DOMAIN = "playcademy.gg";
|
|
256
286
|
var PLAYCADEMY_DOMAINS = {
|
|
257
287
|
/** Primary domain (hub, landing pages) */
|
|
258
|
-
apex:
|
|
259
|
-
/**
|
|
260
|
-
|
|
288
|
+
apex: APEX_DOMAIN,
|
|
289
|
+
/** Development/utility domain */
|
|
290
|
+
dev: DEV_DOMAIN,
|
|
261
291
|
/** Game backend worker domain */
|
|
262
|
-
games:
|
|
292
|
+
games: GAMES_DOMAIN
|
|
293
|
+
};
|
|
294
|
+
var CDN_DOMAINS = {
|
|
295
|
+
/** Production CDN: https://cdn.playcademy.net */
|
|
296
|
+
production: `https://cdn.${APEX_DOMAIN}`,
|
|
297
|
+
/** Development CDN: https://cdn.dev.playcademy.net */
|
|
298
|
+
staging: `https://cdn.dev.${APEX_DOMAIN}`
|
|
263
299
|
};
|
|
264
300
|
var PLAYCADEMY_BASE_URLS = {
|
|
265
301
|
production: "https://hub.playcademy.net",
|
|
@@ -301,6 +337,7 @@ var BADGES = {
|
|
|
301
337
|
FIRST_GAME: ITEM_SLUGS.FIRST_GAME_BADGE
|
|
302
338
|
};
|
|
303
339
|
export {
|
|
340
|
+
ACADEMICS_PUBLIC_DIRECTORY,
|
|
304
341
|
AUTH_API_SUBDIRECTORY,
|
|
305
342
|
AUTH_CONFIG_FILE,
|
|
306
343
|
AUTH_PROVIDER_NAMES,
|
|
@@ -315,10 +352,11 @@ export {
|
|
|
315
352
|
CLOUDFLARE_BINDINGS,
|
|
316
353
|
CLOUDFLARE_COMPATIBILITY_DATE,
|
|
317
354
|
CONFIG_FILE_NAMES,
|
|
355
|
+
DB_FILES,
|
|
318
356
|
DEFAULT_API_ROUTES_DIRECTORY,
|
|
319
357
|
DEFAULT_DATABASE_DIRECTORY,
|
|
320
358
|
DEFAULT_PORTS,
|
|
321
|
-
|
|
359
|
+
DRIZZLE_CONFIG_FILES,
|
|
322
360
|
ENV_EXAMPLE_FILE,
|
|
323
361
|
ENV_FILES,
|
|
324
362
|
GAME_WORKER_DOMAINS,
|
|
@@ -334,12 +372,14 @@ export {
|
|
|
334
372
|
PLAYCADEMY_AUTH_VERSION,
|
|
335
373
|
PLAYCADEMY_BASE_URLS,
|
|
336
374
|
PLAYCADEMY_DOMAINS,
|
|
375
|
+
PROBLEM_SETS_DIRECTORY,
|
|
376
|
+
PROBLEM_SETS_URL_PATH,
|
|
377
|
+
PUBLIC_DIRECTORY,
|
|
337
378
|
SAMPLE_API_SUBDIRECTORY,
|
|
338
379
|
SAMPLE_BUCKET_FILENAME,
|
|
339
380
|
SAMPLE_CUSTOM_FILENAME,
|
|
340
381
|
SAMPLE_DATABASE_FILENAME,
|
|
341
382
|
SAMPLE_KV_FILENAME,
|
|
342
|
-
SCHEMA_INDEX_FILE,
|
|
343
383
|
SCHEMA_SUBDIRECTORY,
|
|
344
384
|
SERVER_LIB_DIRECTORY,
|
|
345
385
|
SERVER_ROOT_DIRECTORY,
|
package/dist/db.js
CHANGED
|
@@ -1430,7 +1430,21 @@ var init_file_loader = __esm({
|
|
|
1430
1430
|
|
|
1431
1431
|
// src/lib/db/path.ts
|
|
1432
1432
|
import { copyFileSync, existsSync, mkdirSync, readdirSync, unlinkSync } from "fs";
|
|
1433
|
-
import { join as
|
|
1433
|
+
import { join as join6 } from "path";
|
|
1434
|
+
|
|
1435
|
+
// src/constants/api.ts
|
|
1436
|
+
import { join as join2 } from "node:path";
|
|
1437
|
+
|
|
1438
|
+
// src/constants/server.ts
|
|
1439
|
+
import { join } from "node:path";
|
|
1440
|
+
var SERVER_ROOT_DIRECTORY = "server";
|
|
1441
|
+
var SERVER_LIB_DIRECTORY = join(SERVER_ROOT_DIRECTORY, "lib");
|
|
1442
|
+
var PUBLIC_DIRECTORY = "public";
|
|
1443
|
+
var ACADEMICS_PUBLIC_DIRECTORY = join(PUBLIC_DIRECTORY, "academics");
|
|
1444
|
+
var PROBLEM_SETS_DIRECTORY = join(ACADEMICS_PUBLIC_DIRECTORY, "problem-sets");
|
|
1445
|
+
|
|
1446
|
+
// src/constants/api.ts
|
|
1447
|
+
var DEFAULT_API_ROUTES_DIRECTORY = join2(SERVER_ROOT_DIRECTORY, "api");
|
|
1434
1448
|
|
|
1435
1449
|
// ../../package.json
|
|
1436
1450
|
var package_default = {
|
|
@@ -1479,9 +1493,11 @@ var package_default = {
|
|
|
1479
1493
|
"sync-engine-assets": "bun scripts/sync-engine-assets.ts",
|
|
1480
1494
|
"sync-vite-templates": "bun scripts/sync-vite-templates.ts",
|
|
1481
1495
|
"sync-godot-template": "bun scripts/sync-godot-template.ts",
|
|
1496
|
+
"sync-problem-sets": "sst shell -- bun scripts/sync-problem-sets.ts",
|
|
1482
1497
|
"sync:all": "bun scripts/sync-all.ts",
|
|
1483
1498
|
cf: "sst shell -- bun scripts/setup-cloudflare-dispatch.ts",
|
|
1484
1499
|
"list-s3-bucket": "sst shell -- bun scripts/list-s3-bucket.ts",
|
|
1500
|
+
"invalidate-cdn": "sst shell -- bun scripts/invalidate-cdn.ts",
|
|
1485
1501
|
doctor: "bunx sst shell -- bun scripts/doctor.ts",
|
|
1486
1502
|
format: "bun run --filter '*' format",
|
|
1487
1503
|
lint: "bun run --filter '*' lint",
|
|
@@ -1564,6 +1580,8 @@ var BUCKET_ALWAYS_SKIP = [".git", ".DS_Store", ".gitignore", ...ENV_FILES];
|
|
|
1564
1580
|
var CLOUDFLARE_BINDINGS = {
|
|
1565
1581
|
/** R2 bucket binding name */
|
|
1566
1582
|
BUCKET: "BUCKET",
|
|
1583
|
+
/** Problem sets bucket binding name */
|
|
1584
|
+
BUCKET_PROBLEM_SETS: "PROBLEM_SETS",
|
|
1567
1585
|
/** KV namespace binding name */
|
|
1568
1586
|
KV: "KV",
|
|
1569
1587
|
/** D1 database binding name */
|
|
@@ -1571,18 +1589,41 @@ var CLOUDFLARE_BINDINGS = {
|
|
|
1571
1589
|
};
|
|
1572
1590
|
var MINIFLARE_D1_DIRECTORY = "miniflare-D1DatabaseObject";
|
|
1573
1591
|
|
|
1592
|
+
// src/constants/database.ts
|
|
1593
|
+
import { join as join3 } from "path";
|
|
1594
|
+
var DEFAULT_DATABASE_DIRECTORY = join3("server", "db");
|
|
1595
|
+
|
|
1596
|
+
// src/constants/godot.ts
|
|
1597
|
+
import { join as join4 } from "node:path";
|
|
1598
|
+
var GODOT_BUILD_DIRECTORIES = {
|
|
1599
|
+
/** Root build directory (cleared before each export) */
|
|
1600
|
+
ROOT: "build",
|
|
1601
|
+
/** Web export subdirectory */
|
|
1602
|
+
WEB: join4("build", "web")
|
|
1603
|
+
};
|
|
1604
|
+
var GODOT_BUILD_OUTPUTS = {
|
|
1605
|
+
/** Exported web build entry point */
|
|
1606
|
+
INDEX_HTML: join4("build", "web", "index.html"),
|
|
1607
|
+
/** Packaged zip file (created by Godot export) */
|
|
1608
|
+
ZIP: join4("build", "web_playcademy.zip")
|
|
1609
|
+
};
|
|
1610
|
+
|
|
1574
1611
|
// src/constants/paths.ts
|
|
1575
|
-
import { join } from "path";
|
|
1612
|
+
import { join as join5 } from "path";
|
|
1576
1613
|
var WORKSPACE_NAME = ".playcademy";
|
|
1577
1614
|
var CLI_DIRECTORIES = {
|
|
1578
1615
|
/** Root directory for CLI artifacts in workspace */
|
|
1579
1616
|
WORKSPACE: WORKSPACE_NAME,
|
|
1580
1617
|
/** Database directory within workspace */
|
|
1581
|
-
DATABASE:
|
|
1618
|
+
DATABASE: join5(WORKSPACE_NAME, "db"),
|
|
1582
1619
|
/** KV storage directory within workspace */
|
|
1583
|
-
KV:
|
|
1620
|
+
KV: join5(WORKSPACE_NAME, "kv"),
|
|
1584
1621
|
/** Bucket storage directory within workspace */
|
|
1585
|
-
BUCKET:
|
|
1622
|
+
BUCKET: join5(WORKSPACE_NAME, "bucket")
|
|
1623
|
+
};
|
|
1624
|
+
var CLI_DEFAULT_OUTPUTS = {
|
|
1625
|
+
/** Default worker bundle output for debug command */
|
|
1626
|
+
WORKER_BUNDLE: join5(WORKSPACE_NAME, "worker-bundle.js")
|
|
1586
1627
|
};
|
|
1587
1628
|
var CLI_FILES = {
|
|
1588
1629
|
/** Auth store file in user config directory */
|
|
@@ -1593,6 +1634,15 @@ var CLI_FILES = {
|
|
|
1593
1634
|
INITIAL_DATABASE: "initial.sqlite"
|
|
1594
1635
|
};
|
|
1595
1636
|
|
|
1637
|
+
// ../constants/src/domains.ts
|
|
1638
|
+
var APEX_DOMAIN = "playcademy.net";
|
|
1639
|
+
var CDN_DOMAINS = {
|
|
1640
|
+
/** Production CDN: https://cdn.playcademy.net */
|
|
1641
|
+
production: `https://cdn.${APEX_DOMAIN}`,
|
|
1642
|
+
/** Development CDN: https://cdn.dev.playcademy.net */
|
|
1643
|
+
staging: `https://cdn.dev.${APEX_DOMAIN}`
|
|
1644
|
+
};
|
|
1645
|
+
|
|
1596
1646
|
// ../constants/src/overworld.ts
|
|
1597
1647
|
var ITEM_SLUGS = {
|
|
1598
1648
|
/** Primary platform currency */
|
|
@@ -1633,11 +1683,11 @@ var ensureDirectoryExists = (dir) => {
|
|
|
1633
1683
|
}
|
|
1634
1684
|
};
|
|
1635
1685
|
var findMiniflareDatabase = (dbDir) => {
|
|
1636
|
-
const miniflareDir =
|
|
1686
|
+
const miniflareDir = join6(dbDir, MINIFLARE_D1_DIRECTORY);
|
|
1637
1687
|
if (!existsSync(miniflareDir)) return null;
|
|
1638
1688
|
const sqliteFiles = readdirSync(miniflareDir).filter((file) => file.endsWith(".sqlite"));
|
|
1639
1689
|
if (sqliteFiles.length === 0) return null;
|
|
1640
|
-
return
|
|
1690
|
+
return join6(miniflareDir, sqliteFiles[0]);
|
|
1641
1691
|
};
|
|
1642
1692
|
var migrateInitialDbToTarget = (initialPath, targetPath) => {
|
|
1643
1693
|
if (!existsSync(initialPath)) return;
|
|
@@ -1645,7 +1695,7 @@ var migrateInitialDbToTarget = (initialPath, targetPath) => {
|
|
|
1645
1695
|
unlinkSync(initialPath);
|
|
1646
1696
|
};
|
|
1647
1697
|
function getDevDbPath() {
|
|
1648
|
-
const initialDbPath =
|
|
1698
|
+
const initialDbPath = join6(DB_DIRECTORY, INITIAL_DB_NAME);
|
|
1649
1699
|
ensureDirectoryExists(DB_DIRECTORY);
|
|
1650
1700
|
const miniflareDbPath = findMiniflareDatabase(DB_DIRECTORY);
|
|
1651
1701
|
if (miniflareDbPath) {
|
|
@@ -1709,7 +1759,7 @@ async function bundleSeedWorker(seedFilePath, projectPath) {
|
|
|
1709
1759
|
// src/lib/db/reset.ts
|
|
1710
1760
|
import { execSync as execSync2 } from "child_process";
|
|
1711
1761
|
import { rmSync as rmSync2 } from "fs";
|
|
1712
|
-
import { join as
|
|
1762
|
+
import { join as join9 } from "path";
|
|
1713
1763
|
|
|
1714
1764
|
// ../utils/src/ansi.ts
|
|
1715
1765
|
var colors = {
|
|
@@ -1938,7 +1988,7 @@ init_package_json();
|
|
|
1938
1988
|
// ../utils/src/package-manager.ts
|
|
1939
1989
|
import { execSync } from "child_process";
|
|
1940
1990
|
import { existsSync as existsSync2 } from "fs";
|
|
1941
|
-
import { join as
|
|
1991
|
+
import { join as join7 } from "path";
|
|
1942
1992
|
function isCommandAvailable(command) {
|
|
1943
1993
|
try {
|
|
1944
1994
|
execSync(`command -v ${command}`, { stdio: "ignore" });
|
|
@@ -1948,16 +1998,16 @@ function isCommandAvailable(command) {
|
|
|
1948
1998
|
}
|
|
1949
1999
|
}
|
|
1950
2000
|
function detectPackageManager(cwd = process.cwd()) {
|
|
1951
|
-
if (existsSync2(
|
|
2001
|
+
if (existsSync2(join7(cwd, "bun.lock")) || existsSync2(join7(cwd, "bun.lockb"))) {
|
|
1952
2002
|
return "bun";
|
|
1953
2003
|
}
|
|
1954
|
-
if (existsSync2(
|
|
2004
|
+
if (existsSync2(join7(cwd, "pnpm-lock.yaml"))) {
|
|
1955
2005
|
return "pnpm";
|
|
1956
2006
|
}
|
|
1957
|
-
if (existsSync2(
|
|
2007
|
+
if (existsSync2(join7(cwd, "yarn.lock"))) {
|
|
1958
2008
|
return "yarn";
|
|
1959
2009
|
}
|
|
1960
|
-
if (existsSync2(
|
|
2010
|
+
if (existsSync2(join7(cwd, "package-lock.json"))) {
|
|
1961
2011
|
return "npm";
|
|
1962
2012
|
}
|
|
1963
2013
|
return detectByCommandAvailability();
|
|
@@ -2882,12 +2932,12 @@ var currentDir = dirname(fileURLToPath(import.meta.url));
|
|
|
2882
2932
|
// src/lib/core/import.ts
|
|
2883
2933
|
import { mkdtempSync, rmSync } from "fs";
|
|
2884
2934
|
import { tmpdir } from "os";
|
|
2885
|
-
import { join as
|
|
2935
|
+
import { join as join8 } from "path";
|
|
2886
2936
|
import { pathToFileURL } from "url";
|
|
2887
2937
|
import * as esbuild from "esbuild";
|
|
2888
2938
|
async function importTypescriptFile(filePath, bundleOptions) {
|
|
2889
|
-
const tempDir = mkdtempSync(
|
|
2890
|
-
const outFile =
|
|
2939
|
+
const tempDir = mkdtempSync(join8(tmpdir(), "playcademy-import-"));
|
|
2940
|
+
const outFile = join8(tempDir, "bundle.mjs");
|
|
2891
2941
|
try {
|
|
2892
2942
|
await esbuild.build({
|
|
2893
2943
|
entryPoints: [filePath],
|
|
@@ -2910,7 +2960,7 @@ async function importTypescriptFile(filePath, bundleOptions) {
|
|
|
2910
2960
|
// src/lib/db/reset.ts
|
|
2911
2961
|
async function resetDatabase(workspace, mf, options = { debug: false }) {
|
|
2912
2962
|
const { debug } = options;
|
|
2913
|
-
const dbDir =
|
|
2963
|
+
const dbDir = join9(workspace, CLI_DIRECTORIES.DATABASE);
|
|
2914
2964
|
await runStep(
|
|
2915
2965
|
"Resetting database...",
|
|
2916
2966
|
async () => {
|
|
@@ -205,6 +205,66 @@ async function serveFromR2(c: Context<HonoEnv>, bucket: R2Bucket): Promise<Respo
|
|
|
205
205
|
return c.json({ error: 'Not Found', message: 'Asset not found', path }, 404)
|
|
206
206
|
}
|
|
207
207
|
|
|
208
|
+
/**
|
|
209
|
+
* Register problem sets middleware (dev and prod)
|
|
210
|
+
*
|
|
211
|
+
* Serves TimeBack problem sets from public/timeback/problems/ directory.
|
|
212
|
+
*
|
|
213
|
+
* In local development:
|
|
214
|
+
* - Problem sets are loaded from public/timeback/problems/ at dev server startup
|
|
215
|
+
* - Stored in PROBLEM_SETS R2 bucket binding
|
|
216
|
+
* - Served at /timeback/problems/*.qti.json
|
|
217
|
+
*
|
|
218
|
+
* In production:
|
|
219
|
+
* - Problem sets uploaded with public/ assets during deploy
|
|
220
|
+
* - Served from Workers Assets or R2 (depending on asset strategy)
|
|
221
|
+
* - Falls through to asset fallback handler if PROBLEM_SETS binding not present
|
|
222
|
+
*
|
|
223
|
+
* Problem sets are customized by developers in their repo after running:
|
|
224
|
+
* - `playcademy init` (downloads initial problem sets)
|
|
225
|
+
* - `playcademy timeback problem-sets download` (downloads additional sets)
|
|
226
|
+
*/
|
|
227
|
+
export function registerLocalProblemSets(app: Hono<HonoEnv>): void {
|
|
228
|
+
app.use('/academics/problem-sets/*', async (c, next) => {
|
|
229
|
+
// Only handle if PROBLEM_SETS binding exists (standalone dev mode)
|
|
230
|
+
// In production or Vite mode, pass through to asset fallback
|
|
231
|
+
const problemSets = c.env.PROBLEM_SETS as R2Bucket | undefined
|
|
232
|
+
|
|
233
|
+
if (!problemSets) {
|
|
234
|
+
return next()
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
const path = new URL(c.req.url).pathname
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Security: Prevent directory traversal attacks
|
|
241
|
+
*
|
|
242
|
+
* Only allow paths under /academics/problem-sets/ with flat filenames
|
|
243
|
+
* Reject paths with ".." (parent directory traversal)
|
|
244
|
+
*/
|
|
245
|
+
if (path.includes('..')) {
|
|
246
|
+
return c.json({ error: 'Invalid path' }, 400)
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
try {
|
|
250
|
+
// Remove leading slash from path for R2 key
|
|
251
|
+
const key = path.slice(1)
|
|
252
|
+
const object = await problemSets.get(key)
|
|
253
|
+
|
|
254
|
+
if (object) {
|
|
255
|
+
return c.json(JSON.parse(await object.text()), 200, {
|
|
256
|
+
'Cache-Control': 'no-cache',
|
|
257
|
+
'Content-Type': 'application/json',
|
|
258
|
+
})
|
|
259
|
+
}
|
|
260
|
+
} catch {
|
|
261
|
+
// Error accessing R2 - fall through
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
return next()
|
|
265
|
+
})
|
|
266
|
+
}
|
|
267
|
+
|
|
208
268
|
/**
|
|
209
269
|
* Register asset fallback handler
|
|
210
270
|
*
|