playcademy 0.14.3 → 0.14.4-alpha.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/constants.d.ts +61 -1
- package/dist/constants.js +148 -0
- package/dist/db.js +118 -0
- package/dist/edge-play/src/entry/middleware.ts +102 -5
- package/dist/edge-play/src/entry/session.ts +44 -0
- package/dist/edge-play/src/entry.ts +33 -1
- package/dist/edge-play/src/index.ts +3 -1
- package/dist/edge-play/src/register-routes.ts +0 -4
- package/dist/edge-play/src/types.ts +7 -5
- package/dist/index.d.ts +122 -90
- package/dist/index.js +2663 -1751
- package/dist/templates/api/sample-protected.ts.template +34 -0
- package/dist/templates/auth/auth-catch-all.ts.template +18 -0
- package/dist/templates/auth/auth-schema.ts.template +62 -0
- package/dist/templates/auth/auth.ts.template +55 -0
- package/dist/templates/config/integrations-config.js.template +1 -1
- package/dist/templates/playcademy-env.d.ts.template +12 -3
- package/dist/utils.d.ts +12 -0
- package/dist/utils.js +764 -1028
- package/dist/version.d.ts +3 -0
- package/dist/version.js +82 -0
- package/package.json +10 -6
package/dist/utils.js
CHANGED
|
@@ -294,262 +294,461 @@ var init_file_loader = __esm({
|
|
|
294
294
|
}
|
|
295
295
|
});
|
|
296
296
|
|
|
297
|
+
// src/lib/config/loader.ts
|
|
298
|
+
init_file_loader();
|
|
299
|
+
import { dirname as dirname2, resolve as resolve2 } from "path";
|
|
300
|
+
|
|
297
301
|
// src/constants/api.ts
|
|
298
|
-
var DEFAULT_API_ROUTES_DIRECTORY;
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
302
|
+
var DEFAULT_API_ROUTES_DIRECTORY = "server/api";
|
|
303
|
+
|
|
304
|
+
// ../../package.json
|
|
305
|
+
var package_default = {
|
|
306
|
+
name: "playcademy",
|
|
307
|
+
devDependencies: {
|
|
308
|
+
"@aws-sdk/client-s3": "^3.787.0",
|
|
309
|
+
"@eslint/js": "^9.24.0",
|
|
310
|
+
"@ianvs/prettier-plugin-sort-imports": "^4.4.2",
|
|
311
|
+
"@pulumi/pulumi": "^3.195.0",
|
|
312
|
+
"@types/bun": "latest",
|
|
313
|
+
commander: "^14.0.0",
|
|
314
|
+
eslint: "^9.24.0",
|
|
315
|
+
globals: "^16.0.0",
|
|
316
|
+
husky: "^9.1.7",
|
|
317
|
+
jscodeshift: "^17.3.0",
|
|
318
|
+
"lint-staged": "^15.5.1",
|
|
319
|
+
prettier: "3.5.3",
|
|
320
|
+
"prettier-plugin-svelte": "^3.3.3",
|
|
321
|
+
rimraf: "^6.0.1",
|
|
322
|
+
sharp: "^0.34.2",
|
|
323
|
+
typedoc: "^0.28.5",
|
|
324
|
+
"typedoc-plugin-markdown": "^4.7.0",
|
|
325
|
+
"typedoc-vitepress-theme": "^1.1.2",
|
|
326
|
+
"typescript-eslint": "^8.30.1",
|
|
327
|
+
"yocto-spinner": "^0.2.2"
|
|
328
|
+
},
|
|
329
|
+
peerDependencies: {
|
|
330
|
+
typescript: "^5"
|
|
331
|
+
},
|
|
332
|
+
private: true,
|
|
333
|
+
scripts: {
|
|
334
|
+
build: "bun run scripts/build.ts",
|
|
335
|
+
"build:types": "bun tsc -b packages/data",
|
|
336
|
+
clean: "bun scripts/clean.ts && bun i",
|
|
337
|
+
"docs:commit": "bun scripts/docs-commit.ts",
|
|
338
|
+
dev: "bunx sst dev",
|
|
339
|
+
"dev:reset": "sst shell -- bun run scripts/dev-reset.ts",
|
|
340
|
+
"db:reseed": "sst shell -- bun run scripts/dev-reseed-db.ts",
|
|
341
|
+
"db:sync": "sst shell -- bun run scripts/dev-sync-db.ts",
|
|
342
|
+
"db:studio": "sst shell -- bun run --filter @playcademy/data studio",
|
|
343
|
+
"upload-games": "sst shell -- bun run scripts/upload-games.ts",
|
|
344
|
+
"upload-items": "sst shell -- bun run scripts/upload-items.ts",
|
|
345
|
+
"upload-sprites": "sst shell -- bun run scripts/upload-sprites.ts",
|
|
346
|
+
"upload-static-assets": "sst shell -- bun run scripts/upload-static-assets.ts",
|
|
347
|
+
"upload:all": "sst shell -- bun run scripts/upload-all.ts",
|
|
348
|
+
"sync-engine-assets": "bun scripts/sync-engine-assets.ts",
|
|
349
|
+
"sync-vite-templates": "bun scripts/sync-vite-templates.ts",
|
|
350
|
+
"sync-godot-template": "bun scripts/sync-godot-template.ts",
|
|
351
|
+
"sync:all": "bun scripts/sync-all.ts",
|
|
352
|
+
"setup-cloudflare": "bun scripts/setup-cloudflare-dispatch.ts",
|
|
353
|
+
"list-s3-bucket": "sst shell -- bun scripts/list-s3-bucket.ts",
|
|
354
|
+
doctor: "bunx sst shell -- bun scripts/doctor.ts",
|
|
355
|
+
format: "bun run --filter '*' format",
|
|
356
|
+
lint: "bun run --filter '*' lint",
|
|
357
|
+
prepare: "husky",
|
|
358
|
+
sort: "bunx sort-package-json **/package.json",
|
|
359
|
+
test: "bun test",
|
|
360
|
+
"test:unit": "bun scripts/test-unit.ts",
|
|
361
|
+
"test:integration": "bun scripts/test-integration.ts",
|
|
362
|
+
"test:watch": "bun test --watch",
|
|
363
|
+
"docker:relay": "bun run scripts/docker-relay.ts",
|
|
364
|
+
"debug:leaderboard-notifications": "bunx sst shell -- bun scripts/debug/leaderboard-notifications.ts",
|
|
365
|
+
"timeback:caliper": "sst shell -- bun scripts/caliper-cli.ts",
|
|
366
|
+
notify: "NODE_ENV=productionbunx sst shell -- bun scripts/notifications-cli.ts"
|
|
367
|
+
},
|
|
368
|
+
type: "module",
|
|
369
|
+
workspaces: {
|
|
370
|
+
packages: [
|
|
371
|
+
"apps/*",
|
|
372
|
+
"packages/*",
|
|
373
|
+
"games/*",
|
|
374
|
+
"templates/*"
|
|
375
|
+
],
|
|
376
|
+
catalog: {
|
|
377
|
+
sst: "^3.14.11",
|
|
378
|
+
dedent: "^1.6.0",
|
|
379
|
+
typescript: "^5.7.2",
|
|
380
|
+
vite: "^6.3.5",
|
|
381
|
+
eslint: "^9.24.0",
|
|
382
|
+
prettier: "3.5.3",
|
|
383
|
+
"@types/bun": "latest",
|
|
384
|
+
jose: "^5.2.3",
|
|
385
|
+
zod: "^3.25.53",
|
|
386
|
+
"better-auth": "1.3.33"
|
|
387
|
+
},
|
|
388
|
+
catalogs: {
|
|
389
|
+
svelte: {
|
|
390
|
+
svelte: "^5.23.1",
|
|
391
|
+
"@sveltejs/adapter-auto": "^6.0.0",
|
|
392
|
+
"@sveltejs/kit": "^2.16.0",
|
|
393
|
+
"@sveltejs/vite-plugin-svelte": "^5.0.3",
|
|
394
|
+
"svelte-check": "^4.2.1",
|
|
395
|
+
"prettier-plugin-svelte": "^3.3.3",
|
|
396
|
+
"eslint-plugin-svelte": "^3.0.0"
|
|
397
|
+
},
|
|
398
|
+
database: {
|
|
399
|
+
"drizzle-orm": "^0.42.0",
|
|
400
|
+
"drizzle-kit": "^0.31.0",
|
|
401
|
+
"drizzle-zod": "^0.7.1"
|
|
402
|
+
},
|
|
403
|
+
aws: {
|
|
404
|
+
"@aws-sdk/client-s3": "^3.787.0",
|
|
405
|
+
"@aws-sdk/s3-request-presigner": "^3.787.0"
|
|
406
|
+
},
|
|
407
|
+
linting: {
|
|
408
|
+
"typescript-eslint": "^8.30.1",
|
|
409
|
+
"@eslint/js": "^9.24.0",
|
|
410
|
+
"eslint-config-prettier": "^10.0.1"
|
|
411
|
+
}
|
|
412
|
+
}
|
|
303
413
|
}
|
|
304
|
-
}
|
|
414
|
+
};
|
|
415
|
+
|
|
416
|
+
// src/constants/auth.ts
|
|
417
|
+
var BETTER_AUTH_VERSION = package_default.workspaces.catalog["better-auth"];
|
|
305
418
|
|
|
306
419
|
// src/constants/config.ts
|
|
307
|
-
var ENV_FILES
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
// Modern tooling (try first)
|
|
322
|
-
"tsconfig.json"
|
|
323
|
-
// Standard (fallback)
|
|
324
|
-
];
|
|
325
|
-
}
|
|
326
|
-
});
|
|
420
|
+
var ENV_FILES = [
|
|
421
|
+
".env",
|
|
422
|
+
// Loaded first
|
|
423
|
+
".env.development",
|
|
424
|
+
// Overrides .env
|
|
425
|
+
".env.local"
|
|
426
|
+
// Overrides all (highest priority)
|
|
427
|
+
];
|
|
428
|
+
var TSCONFIG_FILES = [
|
|
429
|
+
"tsconfig.app.json",
|
|
430
|
+
// Modern tooling (try first)
|
|
431
|
+
"tsconfig.json"
|
|
432
|
+
// Standard (fallback)
|
|
433
|
+
];
|
|
327
434
|
|
|
328
435
|
// src/constants/bucket.ts
|
|
329
|
-
var BUCKET_ALWAYS_SKIP;
|
|
330
|
-
var init_bucket = __esm({
|
|
331
|
-
"src/constants/bucket.ts"() {
|
|
332
|
-
"use strict";
|
|
333
|
-
init_config();
|
|
334
|
-
BUCKET_ALWAYS_SKIP = [".git", ".DS_Store", ".gitignore", ...ENV_FILES];
|
|
335
|
-
}
|
|
336
|
-
});
|
|
436
|
+
var BUCKET_ALWAYS_SKIP = [".git", ".DS_Store", ".gitignore", ...ENV_FILES];
|
|
337
437
|
|
|
338
438
|
// src/constants/cloudflare.ts
|
|
339
|
-
var CLOUDFLARE_COMPATIBILITY_DATE
|
|
340
|
-
var
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
KV: "KV",
|
|
349
|
-
/** D1 database binding name */
|
|
350
|
-
DB: "DB"
|
|
351
|
-
};
|
|
352
|
-
}
|
|
353
|
-
});
|
|
354
|
-
|
|
355
|
-
// src/constants/database.ts
|
|
356
|
-
var init_database = __esm({
|
|
357
|
-
"src/constants/database.ts"() {
|
|
358
|
-
"use strict";
|
|
359
|
-
}
|
|
360
|
-
});
|
|
361
|
-
|
|
362
|
-
// src/constants/http-server.ts
|
|
363
|
-
var init_http_server = __esm({
|
|
364
|
-
"src/constants/http-server.ts"() {
|
|
365
|
-
"use strict";
|
|
366
|
-
}
|
|
367
|
-
});
|
|
439
|
+
var CLOUDFLARE_COMPATIBILITY_DATE = "2024-01-01";
|
|
440
|
+
var CLOUDFLARE_BINDINGS = {
|
|
441
|
+
/** R2 bucket binding name */
|
|
442
|
+
BUCKET: "BUCKET",
|
|
443
|
+
/** KV namespace binding name */
|
|
444
|
+
KV: "KV",
|
|
445
|
+
/** D1 database binding name */
|
|
446
|
+
DB: "DB"
|
|
447
|
+
};
|
|
368
448
|
|
|
369
449
|
// src/constants/paths.ts
|
|
370
450
|
import { join } from "path";
|
|
371
|
-
var WORKSPACE_NAME
|
|
372
|
-
var
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
KV: join(WORKSPACE_NAME, "kv"),
|
|
383
|
-
/** Bucket storage directory within workspace */
|
|
384
|
-
BUCKET: join(WORKSPACE_NAME, "bucket")
|
|
385
|
-
};
|
|
386
|
-
}
|
|
387
|
-
});
|
|
451
|
+
var WORKSPACE_NAME = ".playcademy";
|
|
452
|
+
var CLI_DIRECTORIES = {
|
|
453
|
+
/** Root directory for CLI artifacts in workspace */
|
|
454
|
+
WORKSPACE: WORKSPACE_NAME,
|
|
455
|
+
/** Database directory within workspace */
|
|
456
|
+
DATABASE: join(WORKSPACE_NAME, "db"),
|
|
457
|
+
/** KV storage directory within workspace */
|
|
458
|
+
KV: join(WORKSPACE_NAME, "kv"),
|
|
459
|
+
/** Bucket storage directory within workspace */
|
|
460
|
+
BUCKET: join(WORKSPACE_NAME, "bucket")
|
|
461
|
+
};
|
|
388
462
|
|
|
389
463
|
// src/constants/ports.ts
|
|
390
|
-
var DEFAULT_PORTS
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
SANDBOX: 4321,
|
|
397
|
-
/** Backend dev server (game backend with HMR) */
|
|
398
|
-
BACKEND: 8788
|
|
399
|
-
};
|
|
400
|
-
}
|
|
401
|
-
});
|
|
464
|
+
var DEFAULT_PORTS = {
|
|
465
|
+
/** Sandbox server (mock platform API) */
|
|
466
|
+
SANDBOX: 4321,
|
|
467
|
+
/** Backend dev server (game backend with HMR) */
|
|
468
|
+
BACKEND: 8788
|
|
469
|
+
};
|
|
402
470
|
|
|
403
471
|
// src/constants/timeback.ts
|
|
404
|
-
var CONFIG_FILE_NAMES
|
|
405
|
-
|
|
406
|
-
"
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
"playcademy.config.js",
|
|
410
|
-
"playcademy.config.json",
|
|
411
|
-
"playcademy.config.mjs"
|
|
412
|
-
];
|
|
413
|
-
}
|
|
414
|
-
});
|
|
415
|
-
|
|
416
|
-
// ../constants/src/auth.ts
|
|
417
|
-
var init_auth = __esm({
|
|
418
|
-
"../constants/src/auth.ts"() {
|
|
419
|
-
"use strict";
|
|
420
|
-
}
|
|
421
|
-
});
|
|
422
|
-
|
|
423
|
-
// ../constants/src/domains.ts
|
|
424
|
-
var init_domains = __esm({
|
|
425
|
-
"../constants/src/domains.ts"() {
|
|
426
|
-
"use strict";
|
|
427
|
-
}
|
|
428
|
-
});
|
|
429
|
-
|
|
430
|
-
// ../constants/src/env-vars.ts
|
|
431
|
-
var init_env_vars = __esm({
|
|
432
|
-
"../constants/src/env-vars.ts"() {
|
|
433
|
-
"use strict";
|
|
434
|
-
}
|
|
435
|
-
});
|
|
472
|
+
var CONFIG_FILE_NAMES = [
|
|
473
|
+
"playcademy.config.js",
|
|
474
|
+
"playcademy.config.json",
|
|
475
|
+
"playcademy.config.mjs"
|
|
476
|
+
];
|
|
436
477
|
|
|
437
478
|
// ../constants/src/overworld.ts
|
|
438
|
-
var ITEM_SLUGS
|
|
439
|
-
|
|
440
|
-
"
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
CORE_GAME_UUIDS = {
|
|
472
|
-
/** Internal playground game for development and testing */
|
|
473
|
-
PLAYGROUND: "00000000-0000-0000-0000-000000000001"
|
|
474
|
-
};
|
|
475
|
-
}
|
|
476
|
-
});
|
|
477
|
-
|
|
478
|
-
// ../constants/src/system.ts
|
|
479
|
-
var init_system = __esm({
|
|
480
|
-
"../constants/src/system.ts"() {
|
|
481
|
-
"use strict";
|
|
482
|
-
}
|
|
483
|
-
});
|
|
484
|
-
|
|
485
|
-
// ../constants/src/timeback.ts
|
|
486
|
-
var init_timeback2 = __esm({
|
|
487
|
-
"../constants/src/timeback.ts"() {
|
|
488
|
-
"use strict";
|
|
489
|
-
}
|
|
490
|
-
});
|
|
491
|
-
|
|
492
|
-
// ../constants/src/workers.ts
|
|
493
|
-
var init_workers = __esm({
|
|
494
|
-
"../constants/src/workers.ts"() {
|
|
495
|
-
"use strict";
|
|
496
|
-
}
|
|
497
|
-
});
|
|
498
|
-
|
|
499
|
-
// ../constants/src/index.ts
|
|
500
|
-
var init_src = __esm({
|
|
501
|
-
"../constants/src/index.ts"() {
|
|
502
|
-
"use strict";
|
|
503
|
-
init_auth();
|
|
504
|
-
init_domains();
|
|
505
|
-
init_env_vars();
|
|
506
|
-
init_overworld();
|
|
507
|
-
init_system();
|
|
508
|
-
init_timeback2();
|
|
509
|
-
init_workers();
|
|
510
|
-
}
|
|
511
|
-
});
|
|
512
|
-
|
|
513
|
-
// src/constants/urls.ts
|
|
514
|
-
var init_urls = __esm({
|
|
515
|
-
"src/constants/urls.ts"() {
|
|
516
|
-
"use strict";
|
|
517
|
-
init_src();
|
|
518
|
-
}
|
|
519
|
-
});
|
|
479
|
+
var ITEM_SLUGS = {
|
|
480
|
+
/** Primary platform currency */
|
|
481
|
+
PLAYCADEMY_CREDITS: "PLAYCADEMY_CREDITS",
|
|
482
|
+
/** Experience points currency */
|
|
483
|
+
PLAYCADEMY_XP: "PLAYCADEMY_XP",
|
|
484
|
+
/** Core platform badges */
|
|
485
|
+
FOUNDING_MEMBER_BADGE: "FOUNDING_MEMBER_BADGE",
|
|
486
|
+
EARLY_ADOPTER_BADGE: "EARLY_ADOPTER_BADGE",
|
|
487
|
+
FIRST_GAME_BADGE: "FIRST_GAME_BADGE",
|
|
488
|
+
/** Example items */
|
|
489
|
+
COMMON_SWORD: "COMMON_SWORD",
|
|
490
|
+
SMALL_HEALTH_POTION: "SMALL_HEALTH_POTION",
|
|
491
|
+
SMALL_BACKPACK: "SMALL_BACKPACK",
|
|
492
|
+
/** Placeable items */
|
|
493
|
+
LAVA_LAMP: "LAVA_LAMP",
|
|
494
|
+
BOOMBOX: "BOOMBOX",
|
|
495
|
+
CABIN_BED: "CABIN_BED"
|
|
496
|
+
};
|
|
497
|
+
var CURRENCIES = {
|
|
498
|
+
/** Primary platform currency slug */
|
|
499
|
+
PRIMARY: ITEM_SLUGS.PLAYCADEMY_CREDITS,
|
|
500
|
+
/** Experience points slug */
|
|
501
|
+
XP: ITEM_SLUGS.PLAYCADEMY_XP
|
|
502
|
+
};
|
|
503
|
+
var BADGES = {
|
|
504
|
+
FOUNDING_MEMBER: ITEM_SLUGS.FOUNDING_MEMBER_BADGE,
|
|
505
|
+
EARLY_ADOPTER: ITEM_SLUGS.EARLY_ADOPTER_BADGE,
|
|
506
|
+
FIRST_GAME: ITEM_SLUGS.FIRST_GAME_BADGE
|
|
507
|
+
};
|
|
508
|
+
var CORE_GAME_UUIDS = {
|
|
509
|
+
/** Internal playground game for development and testing */
|
|
510
|
+
PLAYGROUND: "00000000-0000-0000-0000-000000000001"
|
|
511
|
+
};
|
|
520
512
|
|
|
521
|
-
// src/
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
513
|
+
// src/lib/core/logger.ts
|
|
514
|
+
import {
|
|
515
|
+
blue,
|
|
516
|
+
blueBright,
|
|
517
|
+
bold,
|
|
518
|
+
cyan,
|
|
519
|
+
dim,
|
|
520
|
+
gray,
|
|
521
|
+
green,
|
|
522
|
+
greenBright,
|
|
523
|
+
red,
|
|
524
|
+
yellow,
|
|
525
|
+
yellowBright
|
|
526
|
+
} from "colorette";
|
|
527
|
+
import { colorize } from "json-colorizer";
|
|
528
|
+
function customTransform(text) {
|
|
529
|
+
let result = text;
|
|
530
|
+
result = result.replace(/`([^`]+)`/g, (_, code) => greenBright(code));
|
|
531
|
+
result = result.replace(/<([^>]+)>/g, (_, path2) => blueBright(path2));
|
|
532
|
+
return result;
|
|
533
|
+
}
|
|
534
|
+
function formatTable(data, title) {
|
|
535
|
+
if (data.length === 0) return;
|
|
536
|
+
const keys = Object.keys(data[0]);
|
|
537
|
+
const rows = data.map((item) => keys.map((key) => String(item[key] ?? "")));
|
|
538
|
+
const widths = keys.map((key, i) => {
|
|
539
|
+
const headerWidth = key.length;
|
|
540
|
+
const dataWidth = Math.max(...rows.map((row) => row[i].length));
|
|
541
|
+
return Math.max(headerWidth, dataWidth);
|
|
542
|
+
});
|
|
543
|
+
const totalWidth = widths.reduce((sum, w) => sum + w + 3, -1);
|
|
544
|
+
const separator = "\u251C" + widths.map((w) => "\u2500".repeat(w + 2)).join("\u253C") + "\u2524";
|
|
545
|
+
const topBorder = "\u250C" + "\u2500".repeat(totalWidth) + "\u2510";
|
|
546
|
+
const titleSeparator = "\u251C" + widths.map((w) => "\u2500".repeat(w + 2)).join("\u252C") + "\u2524";
|
|
547
|
+
const bottomBorder = "\u2514" + widths.map((w) => "\u2500".repeat(w + 2)).join("\u2534") + "\u2518";
|
|
548
|
+
console.log(topBorder);
|
|
549
|
+
if (title) {
|
|
550
|
+
const titleText = bold(title);
|
|
551
|
+
const titlePadding = totalWidth - title.length - 1;
|
|
552
|
+
const titleRow = "\u2502 " + titleText + " ".repeat(titlePadding) + "\u2502";
|
|
553
|
+
console.log(titleRow);
|
|
554
|
+
console.log(titleSeparator);
|
|
535
555
|
}
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
556
|
+
const header = "\u2502 " + keys.map((key, i) => key.padEnd(widths[i])).join(" \u2502 ") + " \u2502";
|
|
557
|
+
console.log(header);
|
|
558
|
+
console.log(separator);
|
|
559
|
+
rows.forEach((row) => {
|
|
560
|
+
const dataRow = "\u2502 " + row.map((cell, i) => cell.padEnd(widths[i])).join(" \u2502 ") + " \u2502";
|
|
561
|
+
console.log(dataRow);
|
|
562
|
+
});
|
|
563
|
+
console.log(bottomBorder);
|
|
564
|
+
}
|
|
565
|
+
var logger = {
|
|
566
|
+
table: (data, title) => {
|
|
567
|
+
formatTable(data, title);
|
|
568
|
+
},
|
|
569
|
+
/**
|
|
570
|
+
* Info message - general information
|
|
571
|
+
*/
|
|
572
|
+
info: (message, indent = 0) => {
|
|
573
|
+
const spaces = " ".repeat(indent);
|
|
574
|
+
console.log(`${spaces}${blue("\u2139")} ${bold(customTransform(message))}`);
|
|
575
|
+
},
|
|
576
|
+
/**
|
|
577
|
+
* Admonition - highlighted note/tip/warning box (Docusaurus-style)
|
|
578
|
+
*/
|
|
579
|
+
admonition: (type, title, lines, indent = 0) => {
|
|
580
|
+
const spaces = " ".repeat(indent);
|
|
581
|
+
const configs = {
|
|
582
|
+
note: { color: green },
|
|
583
|
+
tip: { color: cyan },
|
|
584
|
+
info: { color: blue },
|
|
585
|
+
warning: { color: yellow }
|
|
586
|
+
};
|
|
587
|
+
const { color } = configs[type];
|
|
588
|
+
console.log(`${spaces}${color("\u250C\u2500")} ${bold(color(title.toUpperCase()))}`);
|
|
589
|
+
if (lines && lines.length > 0) {
|
|
590
|
+
lines.forEach((line) => {
|
|
591
|
+
console.log(`${spaces}${color("\u2502")} ${customTransform(line)}`);
|
|
592
|
+
});
|
|
593
|
+
}
|
|
594
|
+
console.log(`${spaces}${color("\u2514\u2500")}`);
|
|
595
|
+
},
|
|
596
|
+
/**
|
|
597
|
+
* Dim message - less important information
|
|
598
|
+
*/
|
|
599
|
+
dim: (message, indent = 0) => {
|
|
600
|
+
const spaces = " ".repeat(indent);
|
|
601
|
+
console.log(`${spaces}${dim(customTransform(message))}`);
|
|
602
|
+
},
|
|
603
|
+
/**
|
|
604
|
+
* Success message - operation completed successfully
|
|
605
|
+
*/
|
|
606
|
+
success: (message, indent = 0) => {
|
|
607
|
+
const spaces = " ".repeat(indent);
|
|
608
|
+
console.log(`${spaces}${green("\u2714")} ${bold(customTransform(message))}`);
|
|
609
|
+
},
|
|
610
|
+
remark: (message, indent = 0) => {
|
|
611
|
+
const spaces = " ".repeat(indent);
|
|
612
|
+
console.log(`${spaces}${bold(yellowBright("\u2726"))} ${bold(customTransform(message))}`);
|
|
613
|
+
},
|
|
614
|
+
/**
|
|
615
|
+
* Error message - operation failed
|
|
616
|
+
*/
|
|
617
|
+
error: (message, indent = 0) => {
|
|
618
|
+
const spaces = " ".repeat(indent);
|
|
619
|
+
console.error(`${spaces}${red("\u2716")} ${customTransform(message)}`);
|
|
620
|
+
},
|
|
621
|
+
bold: (message, indent = 0) => {
|
|
622
|
+
const spaces = " ".repeat(indent);
|
|
623
|
+
console.log(`${spaces}${bold(customTransform(message))}`);
|
|
624
|
+
},
|
|
625
|
+
/**
|
|
626
|
+
* Warning message - something to be aware of
|
|
627
|
+
*/
|
|
628
|
+
warn: (message, indent = 0) => {
|
|
629
|
+
const spaces = " ".repeat(indent);
|
|
630
|
+
console.warn(`${spaces}${yellow("\u26A0")} ${bold(customTransform(message))}`);
|
|
631
|
+
},
|
|
632
|
+
/**
|
|
633
|
+
* Debug message - only shown when DEBUG env var is set
|
|
634
|
+
*/
|
|
635
|
+
debug: (message, indent = 0) => {
|
|
636
|
+
const spaces = " ".repeat(indent);
|
|
637
|
+
if (process.env.DEBUG) {
|
|
638
|
+
console.log(gray("[DEBUG]"), `${spaces}${message}`);
|
|
639
|
+
}
|
|
640
|
+
},
|
|
641
|
+
/**
|
|
642
|
+
* Step message - shows progress through a process
|
|
643
|
+
*/
|
|
644
|
+
step: (step, total, message, indent = 0) => {
|
|
645
|
+
const spaces = " ".repeat(indent);
|
|
646
|
+
console.log(spaces + cyan(`[${step}/${total}]`), customTransform(message));
|
|
647
|
+
},
|
|
648
|
+
/**
|
|
649
|
+
* Highlighted message - draws attention
|
|
650
|
+
*/
|
|
651
|
+
highlight: (message, indent = 0) => {
|
|
652
|
+
const spaces = " ".repeat(indent);
|
|
653
|
+
console.log(bold(`${spaces}${cyan(customTransform(message))}`));
|
|
654
|
+
},
|
|
655
|
+
/**
|
|
656
|
+
* Aside message - for side information
|
|
657
|
+
*/
|
|
658
|
+
aside: (message, indent = 0) => {
|
|
659
|
+
const spaces = " ".repeat(indent);
|
|
660
|
+
console.log(`${spaces}${bold(customTransform(message))}`);
|
|
661
|
+
},
|
|
662
|
+
/**
|
|
663
|
+
* Data display - for structured data output
|
|
664
|
+
*/
|
|
665
|
+
data: (label, value, indent = 0) => {
|
|
666
|
+
const spaces = " ".repeat(indent);
|
|
667
|
+
if (value !== void 0) {
|
|
668
|
+
console.log(`${spaces}${dim(label + ":")} ${bold(value)}`);
|
|
669
|
+
} else {
|
|
670
|
+
console.log(`${spaces}${dim(label)}`);
|
|
671
|
+
}
|
|
672
|
+
},
|
|
673
|
+
/**
|
|
674
|
+
* JSON output - pretty-printed JSON
|
|
675
|
+
*/
|
|
676
|
+
json: (data, indent = 0) => {
|
|
677
|
+
const spaces = " ".repeat(indent);
|
|
678
|
+
const jsonString = colorize(JSON.stringify(data, null, 2));
|
|
679
|
+
jsonString.split("\n").forEach((line) => {
|
|
680
|
+
console.log(`${spaces}${line}`);
|
|
681
|
+
});
|
|
682
|
+
},
|
|
683
|
+
/**
|
|
684
|
+
* New line
|
|
685
|
+
*/
|
|
686
|
+
newLine: () => {
|
|
687
|
+
console.log();
|
|
688
|
+
},
|
|
689
|
+
/**
|
|
690
|
+
* Raw output - no formatting, useful for ASCII art or pre-formatted text
|
|
691
|
+
*/
|
|
692
|
+
raw: (text, indent = 0) => {
|
|
693
|
+
const spaces = " ".repeat(indent);
|
|
694
|
+
console.log(`${spaces}${text}`);
|
|
695
|
+
},
|
|
696
|
+
customRaw: (text, indent = 0) => {
|
|
697
|
+
const spaces = " ".repeat(indent);
|
|
698
|
+
console.log(`${spaces}${customTransform(text)}`);
|
|
699
|
+
},
|
|
700
|
+
/**
|
|
701
|
+
* Display a configuration error with helpful suggestions
|
|
702
|
+
*/
|
|
703
|
+
configError: (error, indent = 0) => {
|
|
704
|
+
const spaces = " ".repeat(indent);
|
|
705
|
+
const isConfigError = error && typeof error === "object" && "name" in error && error.name === "ConfigError";
|
|
706
|
+
if (isConfigError && "message" in error && "field" in error && "suggestion" in error) {
|
|
707
|
+
const configErr = error;
|
|
708
|
+
console.error(`${spaces}${red("\u2716")} ${bold(configErr.message)}`);
|
|
709
|
+
if (configErr.field) {
|
|
710
|
+
console.error(`${spaces} ${dim("Field:")} ${configErr.field}`);
|
|
711
|
+
}
|
|
712
|
+
if (configErr.suggestion) {
|
|
713
|
+
console.error(`${spaces} ${dim("Fix:")} ${configErr.suggestion}`);
|
|
714
|
+
}
|
|
715
|
+
} else if (error instanceof Error) {
|
|
716
|
+
console.error(`${spaces}${red("\u2716")} ${bold(error.message)}`);
|
|
717
|
+
} else {
|
|
718
|
+
console.error(`${spaces}${red("\u2716")} ${bold(String(error))}`);
|
|
719
|
+
}
|
|
543
720
|
}
|
|
544
|
-
}
|
|
721
|
+
};
|
|
545
722
|
|
|
546
723
|
// src/lib/config/loader.ts
|
|
547
|
-
|
|
724
|
+
var ConfigError = class extends Error {
|
|
725
|
+
constructor(message, field, suggestion) {
|
|
726
|
+
super(message);
|
|
727
|
+
this.field = field;
|
|
728
|
+
this.suggestion = suggestion;
|
|
729
|
+
this.name = "ConfigError";
|
|
730
|
+
}
|
|
731
|
+
/**
|
|
732
|
+
* Format a user-friendly error message with the field and suggestion
|
|
733
|
+
*/
|
|
734
|
+
toString() {
|
|
735
|
+
let msg = `Configuration Error: ${this.message}`;
|
|
736
|
+
if (this.field) {
|
|
737
|
+
msg += `
|
|
738
|
+
Field: ${this.field}`;
|
|
739
|
+
}
|
|
740
|
+
if (this.suggestion) {
|
|
741
|
+
msg += `
|
|
742
|
+
Suggestion: ${this.suggestion}`;
|
|
743
|
+
}
|
|
744
|
+
return msg;
|
|
745
|
+
}
|
|
746
|
+
};
|
|
548
747
|
async function findConfigPath(configPath) {
|
|
549
748
|
const { findFile: findFile2 } = await Promise.resolve().then(() => (init_file_loader(), file_loader_exports));
|
|
550
749
|
if (configPath) {
|
|
551
750
|
const fullPath = resolve2(configPath);
|
|
552
|
-
const result2 = await findFile2(fullPath, { cwd: dirname2(fullPath) });
|
|
751
|
+
const result2 = await findFile2(fullPath, { cwd: dirname2(fullPath), searchUp: false });
|
|
553
752
|
if (!result2) {
|
|
554
753
|
throw new ConfigError(
|
|
555
754
|
`Config file not found: ${fullPath}`,
|
|
@@ -572,10 +771,7 @@ async function findConfigPath(configPath) {
|
|
|
572
771
|
}
|
|
573
772
|
return result2.path;
|
|
574
773
|
}
|
|
575
|
-
const result = await findFile2(CONFIG_FILE_NAMES
|
|
576
|
-
searchUp: true,
|
|
577
|
-
maxLevels: 10
|
|
578
|
-
});
|
|
774
|
+
const result = await findFile2(CONFIG_FILE_NAMES);
|
|
579
775
|
if (!result) {
|
|
580
776
|
throw new ConfigError(
|
|
581
777
|
"No Playcademy config file found in this directory or any parent directory",
|
|
@@ -720,642 +916,15 @@ function processConfigVariables(config) {
|
|
|
720
916
|
const result = {};
|
|
721
917
|
for (const [key, val] of Object.entries(obj)) {
|
|
722
918
|
result[key] = processValue(val);
|
|
723
|
-
}
|
|
724
|
-
return result;
|
|
725
|
-
}
|
|
726
|
-
return value;
|
|
727
|
-
};
|
|
728
|
-
return processValue(processed);
|
|
729
|
-
}
|
|
730
|
-
var ConfigError;
|
|
731
|
-
var init_loader = __esm({
|
|
732
|
-
"src/lib/config/loader.ts"() {
|
|
733
|
-
"use strict";
|
|
734
|
-
init_file_loader();
|
|
735
|
-
init_constants2();
|
|
736
|
-
ConfigError = class extends Error {
|
|
737
|
-
constructor(message, field, suggestion) {
|
|
738
|
-
super(message);
|
|
739
|
-
this.field = field;
|
|
740
|
-
this.suggestion = suggestion;
|
|
741
|
-
this.name = "ConfigError";
|
|
742
|
-
}
|
|
743
|
-
/**
|
|
744
|
-
* Format a user-friendly error message with the field and suggestion
|
|
745
|
-
*/
|
|
746
|
-
toString() {
|
|
747
|
-
let msg = `Configuration Error: ${this.message}`;
|
|
748
|
-
if (this.field) {
|
|
749
|
-
msg += `
|
|
750
|
-
Field: ${this.field}`;
|
|
751
|
-
}
|
|
752
|
-
if (this.suggestion) {
|
|
753
|
-
msg += `
|
|
754
|
-
Suggestion: ${this.suggestion}`;
|
|
755
|
-
}
|
|
756
|
-
return msg;
|
|
757
|
-
}
|
|
758
|
-
};
|
|
759
|
-
}
|
|
760
|
-
});
|
|
761
|
-
|
|
762
|
-
// ../utils/src/package-manager.ts
|
|
763
|
-
import { execSync } from "child_process";
|
|
764
|
-
import { existsSync as existsSync3 } from "fs";
|
|
765
|
-
import { join as join3 } from "path";
|
|
766
|
-
function isCommandAvailable(command) {
|
|
767
|
-
try {
|
|
768
|
-
execSync(`command -v ${command}`, { stdio: "ignore" });
|
|
769
|
-
return true;
|
|
770
|
-
} catch {
|
|
771
|
-
return false;
|
|
772
|
-
}
|
|
773
|
-
}
|
|
774
|
-
function detectPackageManager(cwd = process.cwd()) {
|
|
775
|
-
if (existsSync3(join3(cwd, "bun.lock")) || existsSync3(join3(cwd, "bun.lockb"))) {
|
|
776
|
-
return "bun";
|
|
777
|
-
}
|
|
778
|
-
if (existsSync3(join3(cwd, "pnpm-lock.yaml"))) {
|
|
779
|
-
return "pnpm";
|
|
780
|
-
}
|
|
781
|
-
if (existsSync3(join3(cwd, "yarn.lock"))) {
|
|
782
|
-
return "yarn";
|
|
783
|
-
}
|
|
784
|
-
if (existsSync3(join3(cwd, "package-lock.json"))) {
|
|
785
|
-
return "npm";
|
|
786
|
-
}
|
|
787
|
-
return detectByCommandAvailability();
|
|
788
|
-
}
|
|
789
|
-
function detectByCommandAvailability() {
|
|
790
|
-
if (isCommandAvailable("bun")) {
|
|
791
|
-
return "bun";
|
|
792
|
-
}
|
|
793
|
-
if (isCommandAvailable("pnpm")) {
|
|
794
|
-
return "pnpm";
|
|
795
|
-
}
|
|
796
|
-
if (isCommandAvailable("yarn")) {
|
|
797
|
-
return "yarn";
|
|
798
|
-
}
|
|
799
|
-
return "npm";
|
|
800
|
-
}
|
|
801
|
-
function getInstallCommand(pm) {
|
|
802
|
-
switch (pm) {
|
|
803
|
-
case "bun":
|
|
804
|
-
return "bun install";
|
|
805
|
-
case "pnpm":
|
|
806
|
-
return "pnpm install";
|
|
807
|
-
case "yarn":
|
|
808
|
-
return "yarn install";
|
|
809
|
-
case "npm":
|
|
810
|
-
default:
|
|
811
|
-
return "npm install";
|
|
812
|
-
}
|
|
813
|
-
}
|
|
814
|
-
var init_package_manager = __esm({
|
|
815
|
-
"../utils/src/package-manager.ts"() {
|
|
816
|
-
"use strict";
|
|
817
|
-
}
|
|
818
|
-
});
|
|
819
|
-
|
|
820
|
-
// src/lib/core/context.ts
|
|
821
|
-
function getWorkspace() {
|
|
822
|
-
return context.workspace || process.cwd();
|
|
823
|
-
}
|
|
824
|
-
var context;
|
|
825
|
-
var init_context = __esm({
|
|
826
|
-
"src/lib/core/context.ts"() {
|
|
827
|
-
"use strict";
|
|
828
|
-
init_package_manager();
|
|
829
|
-
context = {};
|
|
830
|
-
}
|
|
831
|
-
});
|
|
832
|
-
|
|
833
|
-
// src/lib/core/logger.ts
|
|
834
|
-
import {
|
|
835
|
-
blue,
|
|
836
|
-
blueBright,
|
|
837
|
-
bold,
|
|
838
|
-
cyan,
|
|
839
|
-
dim,
|
|
840
|
-
gray,
|
|
841
|
-
green,
|
|
842
|
-
greenBright,
|
|
843
|
-
red,
|
|
844
|
-
yellow,
|
|
845
|
-
yellowBright
|
|
846
|
-
} from "colorette";
|
|
847
|
-
import { colorize } from "json-colorizer";
|
|
848
|
-
function customTransform(text) {
|
|
849
|
-
let result = text;
|
|
850
|
-
result = result.replace(/`([^`]+)`/g, (_, code) => greenBright(code));
|
|
851
|
-
result = result.replace(/<([^>]+)>/g, (_, path2) => blueBright(path2));
|
|
852
|
-
return result;
|
|
853
|
-
}
|
|
854
|
-
function formatTable(data, title) {
|
|
855
|
-
if (data.length === 0) return;
|
|
856
|
-
const keys = Object.keys(data[0]);
|
|
857
|
-
const rows = data.map((item) => keys.map((key) => String(item[key] ?? "")));
|
|
858
|
-
const widths = keys.map((key, i) => {
|
|
859
|
-
const headerWidth = key.length;
|
|
860
|
-
const dataWidth = Math.max(...rows.map((row) => row[i].length));
|
|
861
|
-
return Math.max(headerWidth, dataWidth);
|
|
862
|
-
});
|
|
863
|
-
const totalWidth = widths.reduce((sum, w) => sum + w + 3, -1);
|
|
864
|
-
const separator = "\u251C" + widths.map((w) => "\u2500".repeat(w + 2)).join("\u253C") + "\u2524";
|
|
865
|
-
const topBorder = "\u250C" + "\u2500".repeat(totalWidth) + "\u2510";
|
|
866
|
-
const titleSeparator = "\u251C" + widths.map((w) => "\u2500".repeat(w + 2)).join("\u252C") + "\u2524";
|
|
867
|
-
const bottomBorder = "\u2514" + widths.map((w) => "\u2500".repeat(w + 2)).join("\u2534") + "\u2518";
|
|
868
|
-
console.log(topBorder);
|
|
869
|
-
if (title) {
|
|
870
|
-
const titleText = bold(title);
|
|
871
|
-
const titlePadding = totalWidth - title.length - 1;
|
|
872
|
-
const titleRow = "\u2502 " + titleText + " ".repeat(titlePadding) + "\u2502";
|
|
873
|
-
console.log(titleRow);
|
|
874
|
-
console.log(titleSeparator);
|
|
875
|
-
}
|
|
876
|
-
const header = "\u2502 " + keys.map((key, i) => key.padEnd(widths[i])).join(" \u2502 ") + " \u2502";
|
|
877
|
-
console.log(header);
|
|
878
|
-
console.log(separator);
|
|
879
|
-
rows.forEach((row) => {
|
|
880
|
-
const dataRow = "\u2502 " + row.map((cell, i) => cell.padEnd(widths[i])).join(" \u2502 ") + " \u2502";
|
|
881
|
-
console.log(dataRow);
|
|
882
|
-
});
|
|
883
|
-
console.log(bottomBorder);
|
|
884
|
-
}
|
|
885
|
-
var logger;
|
|
886
|
-
var init_logger = __esm({
|
|
887
|
-
"src/lib/core/logger.ts"() {
|
|
888
|
-
"use strict";
|
|
889
|
-
logger = {
|
|
890
|
-
table: (data, title) => {
|
|
891
|
-
formatTable(data, title);
|
|
892
|
-
},
|
|
893
|
-
/**
|
|
894
|
-
* Info message - general information
|
|
895
|
-
*/
|
|
896
|
-
info: (message, indent = 0) => {
|
|
897
|
-
const spaces = " ".repeat(indent);
|
|
898
|
-
console.log(`${spaces}${blue("\u2139")} ${bold(customTransform(message))}`);
|
|
899
|
-
},
|
|
900
|
-
/**
|
|
901
|
-
* Admonition - highlighted note/tip/warning box (Docusaurus-style)
|
|
902
|
-
*/
|
|
903
|
-
admonition: (type, title, lines, indent = 0) => {
|
|
904
|
-
const spaces = " ".repeat(indent);
|
|
905
|
-
const configs = {
|
|
906
|
-
note: { color: green },
|
|
907
|
-
tip: { color: cyan },
|
|
908
|
-
info: { color: blue },
|
|
909
|
-
warning: { color: yellow }
|
|
910
|
-
};
|
|
911
|
-
const { color } = configs[type];
|
|
912
|
-
console.log(`${spaces}${color("\u250C\u2500")} ${bold(color(title.toUpperCase()))}`);
|
|
913
|
-
if (lines && lines.length > 0) {
|
|
914
|
-
lines.forEach((line) => {
|
|
915
|
-
console.log(`${spaces}${color("\u2502")} ${customTransform(line)}`);
|
|
916
|
-
});
|
|
917
|
-
}
|
|
918
|
-
console.log(`${spaces}${color("\u2514\u2500")}`);
|
|
919
|
-
},
|
|
920
|
-
/**
|
|
921
|
-
* Dim message - less important information
|
|
922
|
-
*/
|
|
923
|
-
dim: (message, indent = 0) => {
|
|
924
|
-
const spaces = " ".repeat(indent);
|
|
925
|
-
console.log(`${spaces}${dim(customTransform(message))}`);
|
|
926
|
-
},
|
|
927
|
-
/**
|
|
928
|
-
* Success message - operation completed successfully
|
|
929
|
-
*/
|
|
930
|
-
success: (message, indent = 0) => {
|
|
931
|
-
const spaces = " ".repeat(indent);
|
|
932
|
-
console.log(`${spaces}${green("\u2714")} ${bold(customTransform(message))}`);
|
|
933
|
-
},
|
|
934
|
-
remark: (message, indent = 0) => {
|
|
935
|
-
const spaces = " ".repeat(indent);
|
|
936
|
-
console.log(`${spaces}${bold(yellowBright("\u2726"))} ${bold(customTransform(message))}`);
|
|
937
|
-
},
|
|
938
|
-
/**
|
|
939
|
-
* Error message - operation failed
|
|
940
|
-
*/
|
|
941
|
-
error: (message, indent = 0) => {
|
|
942
|
-
const spaces = " ".repeat(indent);
|
|
943
|
-
console.error(`${spaces}${red("\u2716")} ${customTransform(message)}`);
|
|
944
|
-
},
|
|
945
|
-
bold: (message, indent = 0) => {
|
|
946
|
-
const spaces = " ".repeat(indent);
|
|
947
|
-
console.log(`${spaces}${bold(customTransform(message))}`);
|
|
948
|
-
},
|
|
949
|
-
/**
|
|
950
|
-
* Warning message - something to be aware of
|
|
951
|
-
*/
|
|
952
|
-
warn: (message, indent = 0) => {
|
|
953
|
-
const spaces = " ".repeat(indent);
|
|
954
|
-
console.warn(`${spaces}${yellow("\u26A0")} ${bold(customTransform(message))}`);
|
|
955
|
-
},
|
|
956
|
-
/**
|
|
957
|
-
* Debug message - only shown when DEBUG env var is set
|
|
958
|
-
*/
|
|
959
|
-
debug: (message, indent = 0) => {
|
|
960
|
-
const spaces = " ".repeat(indent);
|
|
961
|
-
if (process.env.DEBUG) {
|
|
962
|
-
console.log(gray("[DEBUG]"), `${spaces}${message}`);
|
|
963
|
-
}
|
|
964
|
-
},
|
|
965
|
-
/**
|
|
966
|
-
* Step message - shows progress through a process
|
|
967
|
-
*/
|
|
968
|
-
step: (step, total, message, indent = 0) => {
|
|
969
|
-
const spaces = " ".repeat(indent);
|
|
970
|
-
console.log(spaces + cyan(`[${step}/${total}]`), customTransform(message));
|
|
971
|
-
},
|
|
972
|
-
/**
|
|
973
|
-
* Highlighted message - draws attention
|
|
974
|
-
*/
|
|
975
|
-
highlight: (message, indent = 0) => {
|
|
976
|
-
const spaces = " ".repeat(indent);
|
|
977
|
-
console.log(bold(`${spaces}${cyan(customTransform(message))}`));
|
|
978
|
-
},
|
|
979
|
-
/**
|
|
980
|
-
* Aside message - for side information
|
|
981
|
-
*/
|
|
982
|
-
aside: (message, indent = 0) => {
|
|
983
|
-
const spaces = " ".repeat(indent);
|
|
984
|
-
console.log(`${spaces}${bold(customTransform(message))}`);
|
|
985
|
-
},
|
|
986
|
-
/**
|
|
987
|
-
* Data display - for structured data output
|
|
988
|
-
*/
|
|
989
|
-
data: (label, value, indent = 0) => {
|
|
990
|
-
const spaces = " ".repeat(indent);
|
|
991
|
-
if (value !== void 0) {
|
|
992
|
-
console.log(`${spaces}${dim(label + ":")} ${bold(value)}`);
|
|
993
|
-
} else {
|
|
994
|
-
console.log(`${spaces}${dim(label)}`);
|
|
995
|
-
}
|
|
996
|
-
},
|
|
997
|
-
/**
|
|
998
|
-
* JSON output - pretty-printed JSON
|
|
999
|
-
*/
|
|
1000
|
-
json: (data, indent = 0) => {
|
|
1001
|
-
const spaces = " ".repeat(indent);
|
|
1002
|
-
const jsonString = colorize(JSON.stringify(data, null, 2));
|
|
1003
|
-
jsonString.split("\n").forEach((line) => {
|
|
1004
|
-
console.log(`${spaces}${line}`);
|
|
1005
|
-
});
|
|
1006
|
-
},
|
|
1007
|
-
/**
|
|
1008
|
-
* New line
|
|
1009
|
-
*/
|
|
1010
|
-
newLine: () => {
|
|
1011
|
-
console.log();
|
|
1012
|
-
},
|
|
1013
|
-
/**
|
|
1014
|
-
* Raw output - no formatting, useful for ASCII art or pre-formatted text
|
|
1015
|
-
*/
|
|
1016
|
-
raw: (text, indent = 0) => {
|
|
1017
|
-
const spaces = " ".repeat(indent);
|
|
1018
|
-
console.log(`${spaces}${text}`);
|
|
1019
|
-
},
|
|
1020
|
-
customRaw: (text, indent = 0) => {
|
|
1021
|
-
const spaces = " ".repeat(indent);
|
|
1022
|
-
console.log(`${spaces}${customTransform(text)}`);
|
|
1023
|
-
},
|
|
1024
|
-
/**
|
|
1025
|
-
* Display a configuration error with helpful suggestions
|
|
1026
|
-
*/
|
|
1027
|
-
configError: (error, indent = 0) => {
|
|
1028
|
-
const spaces = " ".repeat(indent);
|
|
1029
|
-
const isConfigError = error && typeof error === "object" && "name" in error && error.name === "ConfigError";
|
|
1030
|
-
if (isConfigError && "message" in error && "field" in error && "suggestion" in error) {
|
|
1031
|
-
const configErr = error;
|
|
1032
|
-
console.error(`${spaces}${red("\u2716")} ${bold(configErr.message)}`);
|
|
1033
|
-
if (configErr.field) {
|
|
1034
|
-
console.error(`${spaces} ${dim("Field:")} ${configErr.field}`);
|
|
1035
|
-
}
|
|
1036
|
-
if (configErr.suggestion) {
|
|
1037
|
-
console.error(`${spaces} ${dim("Fix:")} ${configErr.suggestion}`);
|
|
1038
|
-
}
|
|
1039
|
-
} else if (error instanceof Error) {
|
|
1040
|
-
console.error(`${spaces}${red("\u2716")} ${bold(error.message)}`);
|
|
1041
|
-
} else {
|
|
1042
|
-
console.error(`${spaces}${red("\u2716")} ${bold(String(error))}`);
|
|
1043
|
-
}
|
|
1044
|
-
}
|
|
1045
|
-
};
|
|
1046
|
-
}
|
|
1047
|
-
});
|
|
1048
|
-
|
|
1049
|
-
// src/lib/core/config.ts
|
|
1050
|
-
var init_config2 = __esm({
|
|
1051
|
-
"src/lib/core/config.ts"() {
|
|
1052
|
-
"use strict";
|
|
1053
|
-
init_constants2();
|
|
1054
|
-
init_context();
|
|
1055
|
-
init_logger();
|
|
1056
|
-
}
|
|
1057
|
-
});
|
|
1058
|
-
|
|
1059
|
-
// src/lib/auth/storage.ts
|
|
1060
|
-
var init_storage = __esm({
|
|
1061
|
-
"src/lib/auth/storage.ts"() {
|
|
1062
|
-
"use strict";
|
|
1063
|
-
init_constants2();
|
|
1064
|
-
init_config2();
|
|
1065
|
-
}
|
|
1066
|
-
});
|
|
1067
|
-
|
|
1068
|
-
// src/lib/core/client.ts
|
|
1069
|
-
import { PlaycademyClient } from "@playcademy/sdk";
|
|
1070
|
-
var init_client = __esm({
|
|
1071
|
-
"src/lib/core/client.ts"() {
|
|
1072
|
-
"use strict";
|
|
1073
|
-
init_storage();
|
|
1074
|
-
init_logger();
|
|
1075
|
-
init_config2();
|
|
1076
|
-
}
|
|
1077
|
-
});
|
|
1078
|
-
|
|
1079
|
-
// src/lib/core/errors.ts
|
|
1080
|
-
function getErrorMessage(error) {
|
|
1081
|
-
if (error instanceof Error) return error.message;
|
|
1082
|
-
if (typeof error === "string") return error;
|
|
1083
|
-
if (error && typeof error === "object" && "message" in error) {
|
|
1084
|
-
return String(error.message);
|
|
1085
|
-
}
|
|
1086
|
-
return "Unknown error";
|
|
1087
|
-
}
|
|
1088
|
-
var init_errors = __esm({
|
|
1089
|
-
"src/lib/core/errors.ts"() {
|
|
1090
|
-
"use strict";
|
|
1091
|
-
}
|
|
1092
|
-
});
|
|
1093
|
-
|
|
1094
|
-
// ../utils/src/uuid.ts
|
|
1095
|
-
var init_uuid = __esm({
|
|
1096
|
-
"../utils/src/uuid.ts"() {
|
|
1097
|
-
"use strict";
|
|
1098
|
-
}
|
|
1099
|
-
});
|
|
1100
|
-
|
|
1101
|
-
// ../utils/src/mime.ts
|
|
1102
|
-
var init_mime = __esm({
|
|
1103
|
-
"../utils/src/mime.ts"() {
|
|
1104
|
-
"use strict";
|
|
1105
|
-
}
|
|
1106
|
-
});
|
|
1107
|
-
|
|
1108
|
-
// ../utils/src/ansi.ts
|
|
1109
|
-
var isInteractive;
|
|
1110
|
-
var init_ansi = __esm({
|
|
1111
|
-
"../utils/src/ansi.ts"() {
|
|
1112
|
-
"use strict";
|
|
1113
|
-
isInteractive = typeof process !== "undefined" && process.stdout?.isTTY && !process.env.CI && process.env.TERM !== "dumb";
|
|
1114
|
-
}
|
|
1115
|
-
});
|
|
1116
|
-
|
|
1117
|
-
// ../utils/src/spinner.ts
|
|
1118
|
-
var SPINNER_FRAMES, CHECK_MARK, CROSS_MARK;
|
|
1119
|
-
var init_spinner = __esm({
|
|
1120
|
-
"../utils/src/spinner.ts"() {
|
|
1121
|
-
"use strict";
|
|
1122
|
-
init_ansi();
|
|
1123
|
-
SPINNER_FRAMES = [
|
|
1124
|
-
10251,
|
|
1125
|
-
10265,
|
|
1126
|
-
10297,
|
|
1127
|
-
10296,
|
|
1128
|
-
10300,
|
|
1129
|
-
10292,
|
|
1130
|
-
10278,
|
|
1131
|
-
10279,
|
|
1132
|
-
10247,
|
|
1133
|
-
10255
|
|
1134
|
-
].map((code) => String.fromCodePoint(code));
|
|
1135
|
-
CHECK_MARK = String.fromCodePoint(10004);
|
|
1136
|
-
CROSS_MARK = String.fromCodePoint(10006);
|
|
1137
|
-
}
|
|
1138
|
-
});
|
|
1139
|
-
|
|
1140
|
-
// ../utils/src/log.ts
|
|
1141
|
-
var init_log = __esm({
|
|
1142
|
-
"../utils/src/log.ts"() {
|
|
1143
|
-
"use strict";
|
|
1144
|
-
init_ansi();
|
|
1145
|
-
init_spinner();
|
|
1146
|
-
}
|
|
1147
|
-
});
|
|
1148
|
-
|
|
1149
|
-
// ../utils/src/name.ts
|
|
1150
|
-
var init_name = __esm({
|
|
1151
|
-
"../utils/src/name.ts"() {
|
|
1152
|
-
"use strict";
|
|
1153
|
-
}
|
|
1154
|
-
});
|
|
1155
|
-
|
|
1156
|
-
// ../utils/src/string.ts
|
|
1157
|
-
function pluralize(count, singular, plural) {
|
|
1158
|
-
return count === 1 ? singular : plural || `${singular}s`;
|
|
1159
|
-
}
|
|
1160
|
-
var init_string = __esm({
|
|
1161
|
-
"../utils/src/string.ts"() {
|
|
1162
|
-
"use strict";
|
|
1163
|
-
}
|
|
1164
|
-
});
|
|
1165
|
-
|
|
1166
|
-
// ../utils/src/lifecycle.ts
|
|
1167
|
-
var init_lifecycle = __esm({
|
|
1168
|
-
"../utils/src/lifecycle.ts"() {
|
|
1169
|
-
"use strict";
|
|
1170
|
-
}
|
|
1171
|
-
});
|
|
1172
|
-
|
|
1173
|
-
// ../utils/src/timezone.ts
|
|
1174
|
-
var init_timezone = __esm({
|
|
1175
|
-
"../utils/src/timezone.ts"() {
|
|
1176
|
-
"use strict";
|
|
1177
|
-
}
|
|
1178
|
-
});
|
|
1179
|
-
|
|
1180
|
-
// ../utils/src/slug.ts
|
|
1181
|
-
var init_slug = __esm({
|
|
1182
|
-
"../utils/src/slug.ts"() {
|
|
1183
|
-
"use strict";
|
|
1184
|
-
}
|
|
1185
|
-
});
|
|
1186
|
-
|
|
1187
|
-
// ../utils/src/pure/index.ts
|
|
1188
|
-
var init_pure = __esm({
|
|
1189
|
-
"../utils/src/pure/index.ts"() {
|
|
1190
|
-
"use strict";
|
|
1191
|
-
init_uuid();
|
|
1192
|
-
init_mime();
|
|
1193
|
-
init_log();
|
|
1194
|
-
init_name();
|
|
1195
|
-
init_string();
|
|
1196
|
-
init_lifecycle();
|
|
1197
|
-
init_timezone();
|
|
1198
|
-
init_package_json();
|
|
1199
|
-
init_slug();
|
|
1200
|
-
}
|
|
1201
|
-
});
|
|
1202
|
-
|
|
1203
|
-
// ../utils/src/index.ts
|
|
1204
|
-
var init_src2 = __esm({
|
|
1205
|
-
"../utils/src/index.ts"() {
|
|
1206
|
-
"use strict";
|
|
1207
|
-
init_pure();
|
|
1208
|
-
}
|
|
1209
|
-
});
|
|
1210
|
-
|
|
1211
|
-
// src/lib/config/timeback-derive.ts
|
|
1212
|
-
var init_timeback_derive = __esm({
|
|
1213
|
-
"src/lib/config/timeback-derive.ts"() {
|
|
1214
|
-
"use strict";
|
|
1215
|
-
init_game();
|
|
1216
|
-
}
|
|
1217
|
-
});
|
|
1218
|
-
|
|
1219
|
-
// src/lib/templates/loader.ts
|
|
1220
|
-
import { existsSync as existsSync4, readFileSync as readFileSync2 } from "fs";
|
|
1221
|
-
import { dirname as dirname3, resolve as resolve3 } from "path";
|
|
1222
|
-
import { fileURLToPath } from "url";
|
|
1223
|
-
function loadTemplateString(filename) {
|
|
1224
|
-
const filenamesToTry = filename.endsWith(".template") ? [filename] : [filename, `${filename}.template`];
|
|
1225
|
-
const candidatePaths = filenamesToTry.flatMap((name) => [
|
|
1226
|
-
// Dev (TS sources): ../../templates from src/lib/templates
|
|
1227
|
-
resolve3(currentDir, "../../templates", name),
|
|
1228
|
-
// Bundled build (single-file output): templates relative to dist root
|
|
1229
|
-
resolve3(currentDir, "templates", name)
|
|
1230
|
-
]);
|
|
1231
|
-
for (const candidate of candidatePaths) {
|
|
1232
|
-
if (existsSync4(candidate)) {
|
|
1233
|
-
return readFileSync2(candidate, "utf-8");
|
|
1234
|
-
}
|
|
1235
|
-
}
|
|
1236
|
-
throw new Error(`Template not found: ${filename}. Searched: ${candidatePaths.join(", ")}`);
|
|
1237
|
-
}
|
|
1238
|
-
var currentDir;
|
|
1239
|
-
var init_loader2 = __esm({
|
|
1240
|
-
"src/lib/templates/loader.ts"() {
|
|
1241
|
-
"use strict";
|
|
1242
|
-
currentDir = dirname3(fileURLToPath(import.meta.url));
|
|
1243
|
-
}
|
|
1244
|
-
});
|
|
1245
|
-
|
|
1246
|
-
// src/lib/config/generator.ts
|
|
1247
|
-
var init_generator = __esm({
|
|
1248
|
-
"src/lib/config/generator.ts"() {
|
|
1249
|
-
"use strict";
|
|
1250
|
-
init_loader2();
|
|
1251
|
-
}
|
|
1252
|
-
});
|
|
1253
|
-
|
|
1254
|
-
// src/lib/config/writer.ts
|
|
1255
|
-
var init_writer = __esm({
|
|
1256
|
-
"src/lib/config/writer.ts"() {
|
|
1257
|
-
"use strict";
|
|
1258
|
-
}
|
|
1259
|
-
});
|
|
1260
|
-
|
|
1261
|
-
// src/lib/config/index.ts
|
|
1262
|
-
var init_config3 = __esm({
|
|
1263
|
-
"src/lib/config/index.ts"() {
|
|
1264
|
-
"use strict";
|
|
1265
|
-
init_loader();
|
|
1266
|
-
init_timeback_derive();
|
|
1267
|
-
init_generator();
|
|
1268
|
-
init_writer();
|
|
1269
|
-
}
|
|
1270
|
-
});
|
|
1271
|
-
|
|
1272
|
-
// src/lib/core/game.ts
|
|
1273
|
-
var init_game = __esm({
|
|
1274
|
-
"src/lib/core/game.ts"() {
|
|
1275
|
-
"use strict";
|
|
1276
|
-
init_src2();
|
|
1277
|
-
init_slug();
|
|
1278
|
-
init_config3();
|
|
1279
|
-
}
|
|
1280
|
-
});
|
|
1281
|
-
|
|
1282
|
-
// src/lib/core/gitignore.ts
|
|
1283
|
-
var init_gitignore = __esm({
|
|
1284
|
-
"src/lib/core/gitignore.ts"() {
|
|
1285
|
-
"use strict";
|
|
1286
|
-
}
|
|
1287
|
-
});
|
|
1288
|
-
|
|
1289
|
-
// src/lib/core/import.ts
|
|
1290
|
-
import { mkdtempSync, rmSync } from "fs";
|
|
1291
|
-
import { tmpdir } from "os";
|
|
1292
|
-
import { join as join4 } from "path";
|
|
1293
|
-
import { pathToFileURL } from "url";
|
|
1294
|
-
import * as esbuild from "esbuild";
|
|
1295
|
-
async function importTypescriptFile(filePath, bundleOptions) {
|
|
1296
|
-
const tempDir = mkdtempSync(join4(tmpdir(), "playcademy-import-"));
|
|
1297
|
-
const outFile = join4(tempDir, "bundle.mjs");
|
|
1298
|
-
try {
|
|
1299
|
-
await esbuild.build({
|
|
1300
|
-
entryPoints: [filePath],
|
|
1301
|
-
outfile: outFile,
|
|
1302
|
-
bundle: true,
|
|
1303
|
-
platform: "node",
|
|
1304
|
-
format: "esm",
|
|
1305
|
-
target: "node20",
|
|
1306
|
-
sourcemap: false,
|
|
1307
|
-
minify: false,
|
|
1308
|
-
...bundleOptions
|
|
1309
|
-
});
|
|
1310
|
-
const module = await import(pathToFileURL(outFile).href);
|
|
1311
|
-
return module;
|
|
1312
|
-
} finally {
|
|
1313
|
-
rmSync(tempDir, { recursive: true, force: true });
|
|
1314
|
-
}
|
|
1315
|
-
}
|
|
1316
|
-
async function importTypescriptDefault(filePath, bundleOptions) {
|
|
1317
|
-
const module = await importTypescriptFile(filePath, bundleOptions);
|
|
1318
|
-
if (module && typeof module === "object" && "default" in module) {
|
|
1319
|
-
return module.default;
|
|
1320
|
-
}
|
|
1321
|
-
return module;
|
|
1322
|
-
}
|
|
1323
|
-
var init_import = __esm({
|
|
1324
|
-
"src/lib/core/import.ts"() {
|
|
1325
|
-
"use strict";
|
|
1326
|
-
}
|
|
1327
|
-
});
|
|
1328
|
-
|
|
1329
|
-
// src/lib/core/mime.ts
|
|
1330
|
-
var init_mime2 = __esm({
|
|
1331
|
-
"src/lib/core/mime.ts"() {
|
|
1332
|
-
"use strict";
|
|
1333
|
-
}
|
|
1334
|
-
});
|
|
1335
|
-
|
|
1336
|
-
// src/lib/core/index.ts
|
|
1337
|
-
var init_core = __esm({
|
|
1338
|
-
"src/lib/core/index.ts"() {
|
|
1339
|
-
"use strict";
|
|
1340
|
-
init_client();
|
|
1341
|
-
init_config2();
|
|
1342
|
-
init_context();
|
|
1343
|
-
init_errors();
|
|
1344
|
-
init_game();
|
|
1345
|
-
init_gitignore();
|
|
1346
|
-
init_import();
|
|
1347
|
-
init_logger();
|
|
1348
|
-
init_mime2();
|
|
1349
|
-
}
|
|
1350
|
-
});
|
|
1351
|
-
|
|
1352
|
-
// src/utils.ts
|
|
1353
|
-
init_loader();
|
|
1354
|
-
init_loader();
|
|
1355
|
-
init_loader();
|
|
919
|
+
}
|
|
920
|
+
return result;
|
|
921
|
+
}
|
|
922
|
+
return value;
|
|
923
|
+
};
|
|
924
|
+
return processValue(processed);
|
|
925
|
+
}
|
|
1356
926
|
|
|
1357
927
|
// src/lib/dev/server.ts
|
|
1358
|
-
init_src();
|
|
1359
928
|
import { mkdir as mkdir2 } from "fs/promises";
|
|
1360
929
|
import { join as join12 } from "path";
|
|
1361
930
|
import { Log, LogLevel, Miniflare } from "miniflare";
|
|
@@ -1447,17 +1016,212 @@ function readServerInfo(type, projectRoot) {
|
|
|
1447
1016
|
return servers[0] || null;
|
|
1448
1017
|
}
|
|
1449
1018
|
|
|
1450
|
-
// src/lib/
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1019
|
+
// src/lib/core/client.ts
|
|
1020
|
+
import { PlaycademyClient } from "@playcademy/sdk";
|
|
1021
|
+
|
|
1022
|
+
// ../utils/src/package-manager.ts
|
|
1023
|
+
import { execSync } from "child_process";
|
|
1024
|
+
import { existsSync as existsSync3 } from "fs";
|
|
1025
|
+
import { join as join3 } from "path";
|
|
1026
|
+
function isCommandAvailable(command) {
|
|
1027
|
+
try {
|
|
1028
|
+
execSync(`command -v ${command}`, { stdio: "ignore" });
|
|
1029
|
+
return true;
|
|
1030
|
+
} catch {
|
|
1031
|
+
return false;
|
|
1032
|
+
}
|
|
1033
|
+
}
|
|
1034
|
+
function detectPackageManager(cwd = process.cwd()) {
|
|
1035
|
+
if (existsSync3(join3(cwd, "bun.lock")) || existsSync3(join3(cwd, "bun.lockb"))) {
|
|
1036
|
+
return "bun";
|
|
1037
|
+
}
|
|
1038
|
+
if (existsSync3(join3(cwd, "pnpm-lock.yaml"))) {
|
|
1039
|
+
return "pnpm";
|
|
1040
|
+
}
|
|
1041
|
+
if (existsSync3(join3(cwd, "yarn.lock"))) {
|
|
1042
|
+
return "yarn";
|
|
1043
|
+
}
|
|
1044
|
+
if (existsSync3(join3(cwd, "package-lock.json"))) {
|
|
1045
|
+
return "npm";
|
|
1046
|
+
}
|
|
1047
|
+
return detectByCommandAvailability();
|
|
1048
|
+
}
|
|
1049
|
+
function detectByCommandAvailability() {
|
|
1050
|
+
if (isCommandAvailable("bun")) {
|
|
1051
|
+
return "bun";
|
|
1052
|
+
}
|
|
1053
|
+
if (isCommandAvailable("pnpm")) {
|
|
1054
|
+
return "pnpm";
|
|
1055
|
+
}
|
|
1056
|
+
if (isCommandAvailable("yarn")) {
|
|
1057
|
+
return "yarn";
|
|
1058
|
+
}
|
|
1059
|
+
return "npm";
|
|
1060
|
+
}
|
|
1061
|
+
function getInstallCommand(pm) {
|
|
1062
|
+
switch (pm) {
|
|
1063
|
+
case "bun":
|
|
1064
|
+
return "bun install";
|
|
1065
|
+
case "pnpm":
|
|
1066
|
+
return "pnpm install";
|
|
1067
|
+
case "yarn":
|
|
1068
|
+
return "yarn install";
|
|
1069
|
+
case "npm":
|
|
1070
|
+
default:
|
|
1071
|
+
return "npm install";
|
|
1072
|
+
}
|
|
1073
|
+
}
|
|
1074
|
+
|
|
1075
|
+
// src/lib/core/context.ts
|
|
1076
|
+
var context = {};
|
|
1077
|
+
function getWorkspace() {
|
|
1078
|
+
return context.workspace || process.cwd();
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
// src/lib/core/errors.ts
|
|
1082
|
+
function getErrorMessage(error) {
|
|
1083
|
+
if (error instanceof Error) return error.message;
|
|
1084
|
+
if (typeof error === "string") return error;
|
|
1085
|
+
if (error && typeof error === "object" && "message" in error) {
|
|
1086
|
+
return String(error.message);
|
|
1087
|
+
}
|
|
1088
|
+
return "Unknown error";
|
|
1089
|
+
}
|
|
1090
|
+
|
|
1091
|
+
// ../utils/src/ansi.ts
|
|
1092
|
+
var isInteractive = typeof process !== "undefined" && process.stdout?.isTTY && !process.env.CI && process.env.TERM !== "dumb";
|
|
1093
|
+
|
|
1094
|
+
// ../utils/src/spinner.ts
|
|
1095
|
+
var SPINNER_FRAMES = [
|
|
1096
|
+
10251,
|
|
1097
|
+
10265,
|
|
1098
|
+
10297,
|
|
1099
|
+
10296,
|
|
1100
|
+
10300,
|
|
1101
|
+
10292,
|
|
1102
|
+
10278,
|
|
1103
|
+
10279,
|
|
1104
|
+
10247,
|
|
1105
|
+
10255
|
|
1106
|
+
].map((code) => String.fromCodePoint(code));
|
|
1107
|
+
var CHECK_MARK = String.fromCodePoint(10004);
|
|
1108
|
+
var CROSS_MARK = String.fromCodePoint(10006);
|
|
1109
|
+
|
|
1110
|
+
// ../utils/src/string.ts
|
|
1111
|
+
function pluralize(count, singular, plural) {
|
|
1112
|
+
return count === 1 ? singular : plural || `${singular}s`;
|
|
1113
|
+
}
|
|
1114
|
+
|
|
1115
|
+
// ../utils/src/pure/index.ts
|
|
1116
|
+
init_package_json();
|
|
1117
|
+
|
|
1118
|
+
// src/lib/secrets/env.ts
|
|
1119
|
+
init_file_loader();
|
|
1120
|
+
import { existsSync as existsSync4, writeFileSync as writeFileSync2 } from "fs";
|
|
1121
|
+
import { join as join4 } from "path";
|
|
1122
|
+
function parseEnvFile(contents) {
|
|
1123
|
+
const secrets = {};
|
|
1124
|
+
for (const line of contents.split("\n")) {
|
|
1125
|
+
const trimmed = line.trim();
|
|
1126
|
+
if (!trimmed || trimmed.startsWith("#")) {
|
|
1127
|
+
continue;
|
|
1128
|
+
}
|
|
1129
|
+
const match = trimmed.match(/^([A-Z_][A-Z0-9_]*)=(.*)$/);
|
|
1130
|
+
if (match) {
|
|
1131
|
+
const [, key, value] = match;
|
|
1132
|
+
if (!key || !value) {
|
|
1133
|
+
continue;
|
|
1134
|
+
}
|
|
1135
|
+
const unquoted = value.replace(/^["']|["']$/g, "");
|
|
1136
|
+
secrets[key] = unquoted;
|
|
1137
|
+
}
|
|
1138
|
+
}
|
|
1139
|
+
return secrets;
|
|
1140
|
+
}
|
|
1141
|
+
async function readEnvFile(workspace) {
|
|
1142
|
+
let secrets = {};
|
|
1143
|
+
for (const filename of ENV_FILES) {
|
|
1144
|
+
try {
|
|
1145
|
+
const contents = await loadFile(filename, { cwd: workspace, searchUp: false });
|
|
1146
|
+
if (contents) {
|
|
1147
|
+
const fileSecrets = parseEnvFile(contents);
|
|
1148
|
+
secrets = { ...secrets, ...fileSecrets };
|
|
1149
|
+
}
|
|
1150
|
+
} catch {
|
|
1151
|
+
continue;
|
|
1152
|
+
}
|
|
1153
|
+
}
|
|
1154
|
+
return secrets;
|
|
1155
|
+
}
|
|
1156
|
+
function getLoadedEnvFiles(workspace) {
|
|
1157
|
+
return ENV_FILES.filter((filename) => existsSync4(join4(workspace, filename)));
|
|
1158
|
+
}
|
|
1159
|
+
function hasEnvFile(workspace) {
|
|
1160
|
+
return ENV_FILES.some((filename) => existsSync4(join4(workspace, filename)));
|
|
1161
|
+
}
|
|
1162
|
+
|
|
1163
|
+
// src/lib/templates/loader.ts
|
|
1164
|
+
import { existsSync as existsSync5, readFileSync as readFileSync2 } from "fs";
|
|
1165
|
+
import { dirname as dirname3, resolve as resolve3 } from "path";
|
|
1166
|
+
import { fileURLToPath } from "url";
|
|
1167
|
+
var currentDir = dirname3(fileURLToPath(import.meta.url));
|
|
1168
|
+
function loadTemplateString(filename) {
|
|
1169
|
+
const filenamesToTry = filename.endsWith(".template") ? [filename] : [filename, `${filename}.template`];
|
|
1170
|
+
const candidatePaths = filenamesToTry.flatMap((name) => [
|
|
1171
|
+
// Dev (TS sources): ../../templates from src/lib/templates
|
|
1172
|
+
resolve3(currentDir, "../../templates", name),
|
|
1173
|
+
// Bundled build (single-file output): templates relative to dist root
|
|
1174
|
+
resolve3(currentDir, "templates", name)
|
|
1175
|
+
]);
|
|
1176
|
+
for (const candidate of candidatePaths) {
|
|
1177
|
+
if (existsSync5(candidate)) {
|
|
1178
|
+
return readFileSync2(candidate, "utf-8");
|
|
1179
|
+
}
|
|
1180
|
+
}
|
|
1181
|
+
throw new Error(`Template not found: ${filename}. Searched: ${candidatePaths.join(", ")}`);
|
|
1182
|
+
}
|
|
1183
|
+
|
|
1184
|
+
// src/lib/core/import.ts
|
|
1185
|
+
import { mkdtempSync, rmSync } from "fs";
|
|
1186
|
+
import { tmpdir } from "os";
|
|
1187
|
+
import { join as join5 } from "path";
|
|
1188
|
+
import { pathToFileURL } from "url";
|
|
1189
|
+
import * as esbuild from "esbuild";
|
|
1190
|
+
async function importTypescriptFile(filePath, bundleOptions) {
|
|
1191
|
+
const tempDir = mkdtempSync(join5(tmpdir(), "playcademy-import-"));
|
|
1192
|
+
const outFile = join5(tempDir, "bundle.mjs");
|
|
1193
|
+
try {
|
|
1194
|
+
await esbuild.build({
|
|
1195
|
+
entryPoints: [filePath],
|
|
1196
|
+
outfile: outFile,
|
|
1197
|
+
bundle: true,
|
|
1198
|
+
platform: "node",
|
|
1199
|
+
format: "esm",
|
|
1200
|
+
target: "node20",
|
|
1201
|
+
sourcemap: false,
|
|
1202
|
+
minify: false,
|
|
1203
|
+
...bundleOptions
|
|
1204
|
+
});
|
|
1205
|
+
const module = await import(pathToFileURL(outFile).href);
|
|
1206
|
+
return module;
|
|
1207
|
+
} finally {
|
|
1208
|
+
rmSync(tempDir, { recursive: true, force: true });
|
|
1209
|
+
}
|
|
1210
|
+
}
|
|
1211
|
+
async function importTypescriptDefault(filePath, bundleOptions) {
|
|
1212
|
+
const module = await importTypescriptFile(filePath, bundleOptions);
|
|
1213
|
+
if (module && typeof module === "object" && "default" in module) {
|
|
1214
|
+
return module.default;
|
|
1215
|
+
}
|
|
1216
|
+
return module;
|
|
1217
|
+
}
|
|
1454
1218
|
|
|
1455
1219
|
// src/lib/deploy/bundle.ts
|
|
1456
|
-
import { existsSync as
|
|
1457
|
-
import { join as
|
|
1220
|
+
import { existsSync as existsSync6 } from "fs";
|
|
1221
|
+
import { join as join7 } from "path";
|
|
1458
1222
|
|
|
1459
1223
|
// ../edge-play/src/entry.ts
|
|
1460
|
-
var entry_default = "/**\n * Game Backend Entry Point\n *\n * This file is the main entry point for deployed game backends.\n * It creates a Hono app and registers all enabled integration routes.\n *\n * Bundled with esbuild and deployed to Cloudflare Workers (or AWS Lambda).\n * Config is injected at build time via esbuild's `define` option.\n */\n\nimport { Hono } from 'hono'\n\nimport {
|
|
1224
|
+
var entry_default = "/**\n * Game Backend Entry Point\n *\n * This file is the main entry point for deployed game backends.\n * It creates a Hono app and registers all enabled integration routes.\n *\n * Bundled with esbuild and deployed to Cloudflare Workers (or AWS Lambda).\n * Config is injected at build time via esbuild's `define` option.\n *\n * DO NOT REMOVE any code wrapped by \u26A0\uFE0F BUILD_MARKER: <marker> \u26A0\uFE0F\n */\n\nimport { Hono } from 'hono'\n\nimport {\n registerApiNotFoundHandler,\n registerAssetFallback,\n registerCors,\n registerEnvSetup,\n registerPlaycademyUser,\n registerSdkInit,\n} from './entry/middleware'\nimport { setupProcessGlobal } from './entry/setup'\nimport { registerBuiltinRoutes } from './register-routes'\n\nimport type { RuntimeConfig } from './entry/types'\nimport type { HonoEnv } from './types'\n\n// DO NOT REMOVE THE BELOW COMMENT\n// \u26A0\uFE0F BUILD_MARKER: CUSTOM_ROUTE_IMPORTS \u26A0\uFE0F\n\n/**\n * Config injected at build time by esbuild\n *\n * The `declare const` tells TypeScript \"this exists at runtime, trust me.\"\n * During bundling, esbuild's `define` option does literal text replacement:\n *\n * Example bundling:\n * Source: if (PLAYCADEMY_CONFIG.integrations.timeback) { ... }\n * Define: { 'PLAYCADEMY_CONFIG': JSON.stringify({ integrations: { timeback: {...} } }) }\n * Output: if ({\"integrations\":{\"timeback\":{...}}}.integrations.timeback) { ... }\n *\n * This enables tree-shaking: if timeback is not configured, those code paths are removed.\n * The bundled Worker only includes the routes that are actually enabled.\n */\ndeclare const PLAYCADEMY_CONFIG: RuntimeConfig\n\n// Setup process global polyfill for SDK compatibility\nsetupProcessGlobal()\n\n// Create Hono app\nconst app = new Hono<HonoEnv>()\n\n// Register middleware\nregisterCors(app)\nregisterEnvSetup(app, PLAYCADEMY_CONFIG)\nregisterSdkInit(app, PLAYCADEMY_CONFIG)\nregisterPlaycademyUser(app)\n\n// DO NOT REMOVE THE BELOW COMMENT\n// \u26A0\uFE0F BUILD_MARKER: SESSION_MIDDLEWARE \u26A0\uFE0F\n\n// Register built-in integration routes based on enabled integrations\n// This function conditionally imports and registers routes like:\n// - GET /api (always included)\n// - GET /api/health (always included)\n// - POST /api/integrations/timeback/end-activity (if timeback enabled)\n//\n// Uses dynamic imports for tree-shaking: if an integration is not enabled,\n// its route code is completely removed from the bundle.\nawait registerBuiltinRoutes(app, PLAYCADEMY_CONFIG.integrations)\n\n// DO NOT REMOVE THE BELOW COMMENT\n// \u26A0\uFE0F BUILD_MARKER: CUSTOM_ROUTES \u26A0\uFE0F\n\n// Register API 404 handler\n// Returns JSON error for unmatched /api/* routes\n// Must be registered after all API routes\nregisterApiNotFoundHandler(app)\n\n// Register static asset fallback handler\n// Serves frontend assets from Workers Assets binding\n// MUST be registered last as it uses a wildcard GET route (app.get('*', ...))\n//\n// In production: Serves frontend assets from Workers Assets binding\n// In local dev: Returns 404 (Vite serves the frontend separately)\nregisterAssetFallback(app)\n\nexport default app\n";
|
|
1461
1225
|
|
|
1462
1226
|
// ../utils/src/path.ts
|
|
1463
1227
|
import fs from "node:fs";
|
|
@@ -1604,8 +1368,13 @@ var shouldLog = (level) => {
|
|
|
1604
1368
|
const minLevel = getMinimumLogLevel();
|
|
1605
1369
|
return levelPriority[level] >= levelPriority[minLevel];
|
|
1606
1370
|
};
|
|
1371
|
+
var customHandler;
|
|
1607
1372
|
var performLog = (level, message, context2) => {
|
|
1608
1373
|
if (!shouldLog(level)) return;
|
|
1374
|
+
if (customHandler) {
|
|
1375
|
+
customHandler(level, message, context2);
|
|
1376
|
+
return;
|
|
1377
|
+
}
|
|
1609
1378
|
const outputFormat = detectOutputFormat();
|
|
1610
1379
|
switch (outputFormat) {
|
|
1611
1380
|
case "browser":
|
|
@@ -1677,9 +1446,6 @@ function getMonorepoRoot() {
|
|
|
1677
1446
|
return memoizedRoot;
|
|
1678
1447
|
}
|
|
1679
1448
|
|
|
1680
|
-
// src/lib/deploy/bundle.ts
|
|
1681
|
-
init_constants2();
|
|
1682
|
-
|
|
1683
1449
|
// src/lib/build/plugins.ts
|
|
1684
1450
|
function textLoaderPlugin() {
|
|
1685
1451
|
return {
|
|
@@ -1713,15 +1479,11 @@ function textLoaderPlugin() {
|
|
|
1713
1479
|
};
|
|
1714
1480
|
}
|
|
1715
1481
|
|
|
1716
|
-
// src/lib/deploy/bundle.ts
|
|
1717
|
-
init_core();
|
|
1718
|
-
|
|
1719
1482
|
// src/lib/dev/routes.ts
|
|
1720
1483
|
init_file_loader();
|
|
1721
|
-
init_core();
|
|
1722
1484
|
import { mkdir, writeFile } from "fs/promises";
|
|
1723
1485
|
import { tmpdir as tmpdir2 } from "os";
|
|
1724
|
-
import { join as
|
|
1486
|
+
import { join as join6, relative } from "path";
|
|
1725
1487
|
|
|
1726
1488
|
// src/lib/deploy/hash.ts
|
|
1727
1489
|
import { createHash } from "crypto";
|
|
@@ -1740,7 +1502,7 @@ async function discoverRoutes(apiDir) {
|
|
|
1740
1502
|
const routes = await Promise.all(
|
|
1741
1503
|
files.map(async (file) => {
|
|
1742
1504
|
const routePath = filePathToRoutePath(file);
|
|
1743
|
-
const absolutePath =
|
|
1505
|
+
const absolutePath = join6(apiDir, file);
|
|
1744
1506
|
const relativePath = relative(getWorkspace(), absolutePath);
|
|
1745
1507
|
const methods = await detectExportedMethods(absolutePath);
|
|
1746
1508
|
return {
|
|
@@ -1801,10 +1563,10 @@ async function transpileRoute(filePath) {
|
|
|
1801
1563
|
if (!result.outputFiles?.[0]) {
|
|
1802
1564
|
throw new Error("Transpilation failed: no output");
|
|
1803
1565
|
}
|
|
1804
|
-
const tempDir =
|
|
1566
|
+
const tempDir = join6(tmpdir2(), "playcademy-dev");
|
|
1805
1567
|
await mkdir(tempDir, { recursive: true });
|
|
1806
1568
|
const hash = hashContent(filePath).slice(0, 12);
|
|
1807
|
-
const jsPath =
|
|
1569
|
+
const jsPath = join6(tempDir, `${hash}.mjs`);
|
|
1808
1570
|
await writeFile(jsPath, result.outputFiles[0].text);
|
|
1809
1571
|
return jsPath;
|
|
1810
1572
|
}
|
|
@@ -1815,7 +1577,7 @@ async function discoverCustomRoutes(config) {
|
|
|
1815
1577
|
const workspace = getWorkspace();
|
|
1816
1578
|
const customRoutesConfig = config.integrations?.customRoutes;
|
|
1817
1579
|
const customRoutesDir = typeof customRoutesConfig === "object" && customRoutesConfig.directory || DEFAULT_API_ROUTES_DIRECTORY;
|
|
1818
|
-
const customRoutes = await discoverRoutes(
|
|
1580
|
+
const customRoutes = await discoverRoutes(join7(workspace, customRoutesDir));
|
|
1819
1581
|
const customRouteData = customRoutes.map((r) => ({
|
|
1820
1582
|
path: r.path,
|
|
1821
1583
|
file: r.file,
|
|
@@ -1827,15 +1589,15 @@ async function discoverCustomRoutes(config) {
|
|
|
1827
1589
|
function resolveEmbeddedSourcePaths() {
|
|
1828
1590
|
const workspace = getWorkspace();
|
|
1829
1591
|
const distDir = new URL(".", import.meta.url).pathname;
|
|
1830
|
-
const embeddedEdgeSrc =
|
|
1831
|
-
const isBuiltPackage =
|
|
1592
|
+
const embeddedEdgeSrc = join7(distDir, "edge-play", "src");
|
|
1593
|
+
const isBuiltPackage = existsSync6(embeddedEdgeSrc);
|
|
1832
1594
|
const monorepoRoot = getMonorepoRoot();
|
|
1833
|
-
const monorepoEdgeSrc =
|
|
1595
|
+
const monorepoEdgeSrc = join7(monorepoRoot, "packages/edge-play/src");
|
|
1834
1596
|
const edgePlaySrc = isBuiltPackage ? embeddedEdgeSrc : monorepoEdgeSrc;
|
|
1835
|
-
const cliPackageRoot = isBuiltPackage ?
|
|
1836
|
-
const cliNodeModules = isBuiltPackage ?
|
|
1837
|
-
const workspaceNodeModules =
|
|
1838
|
-
const constantsEntry = isBuiltPackage ?
|
|
1597
|
+
const cliPackageRoot = isBuiltPackage ? join7(distDir, "../../..") : join7(monorepoRoot, "packages/cli");
|
|
1598
|
+
const cliNodeModules = isBuiltPackage ? join7(cliPackageRoot, "node_modules") : monorepoRoot;
|
|
1599
|
+
const workspaceNodeModules = join7(workspace, "node_modules");
|
|
1600
|
+
const constantsEntry = isBuiltPackage ? join7(embeddedEdgeSrc, "..", "..", "constants", "src", "index.ts") : join7(monorepoRoot, "packages", "constants", "src", "index.ts");
|
|
1839
1601
|
return {
|
|
1840
1602
|
isBuiltPackage,
|
|
1841
1603
|
edgePlaySrc,
|
|
@@ -1890,21 +1652,32 @@ function createEsbuildConfig(entryCode, paths, bundleConfig, customRoutesDir, op
|
|
|
1890
1652
|
// │ install. We embed it in dist/ and alias imports to point there. │
|
|
1891
1653
|
// └─────────────────────────────────────────────────────────────────┘
|
|
1892
1654
|
"@playcademy/constants": constantsEntry,
|
|
1655
|
+
// ┌─ Workspace-only edge-play package ──────────────────────────────┐
|
|
1656
|
+
// │ @playcademy/edge-play is used in generated entry code for auth │
|
|
1657
|
+
// │ middleware. It's embedded in dist/ like constants. │
|
|
1658
|
+
// └─────────────────────────────────────────────────────────────────┘
|
|
1659
|
+
"@playcademy/edge-play": edgePlaySrc,
|
|
1893
1660
|
// ┌─ User's custom routes ──────────────────────────────────────────┐
|
|
1894
1661
|
// │ @game-api is a virtual module that maps to the user's API dir. │
|
|
1895
1662
|
// │ Example: import * as route from '@game-api/hello.ts' │
|
|
1896
1663
|
// │ Resolves to: /user-project/server/api/hello.ts │
|
|
1897
1664
|
// └─────────────────────────────────────────────────────────────────┘
|
|
1898
|
-
"@game-api":
|
|
1665
|
+
"@game-api": join7(workspace, customRoutesDir),
|
|
1666
|
+
// ┌─ User's server lib directory ───────────────────────────────────┐
|
|
1667
|
+
// │ @game-server is a virtual module for server utilities/config │
|
|
1668
|
+
// │ Example: import { getAuth } from '@game-server/lib/auth' │
|
|
1669
|
+
// │ Resolves to: /user-project/server/lib/auth.ts │
|
|
1670
|
+
// └─────────────────────────────────────────────────────────────────┘
|
|
1671
|
+
"@game-server": join7(workspace, "server"),
|
|
1899
1672
|
// ┌─ Node.js polyfills for Cloudflare Workers ──────────────────────┐
|
|
1900
1673
|
// │ Workers don't have fs, path, os, etc. Redirect to polyfills │
|
|
1901
1674
|
// │ that throw helpful errors if user code tries to use them. │
|
|
1902
1675
|
// └─────────────────────────────────────────────────────────────────┘
|
|
1903
|
-
fs:
|
|
1904
|
-
"fs/promises":
|
|
1905
|
-
path:
|
|
1906
|
-
os:
|
|
1907
|
-
process:
|
|
1676
|
+
fs: join7(edgePlaySrc, "polyfills.js"),
|
|
1677
|
+
"fs/promises": join7(edgePlaySrc, "polyfills.js"),
|
|
1678
|
+
path: join7(edgePlaySrc, "polyfills.js"),
|
|
1679
|
+
os: join7(edgePlaySrc, "polyfills.js"),
|
|
1680
|
+
process: join7(edgePlaySrc, "polyfills.js")
|
|
1908
1681
|
},
|
|
1909
1682
|
// ──── Build Plugins ────
|
|
1910
1683
|
plugins: [textLoaderPlugin()],
|
|
@@ -1921,7 +1694,8 @@ async function bundleBackend(config, options = {}) {
|
|
|
1921
1694
|
...config,
|
|
1922
1695
|
__routeMetadata: customRouteData
|
|
1923
1696
|
};
|
|
1924
|
-
const
|
|
1697
|
+
const hasAuth = !!config.integrations?.auth;
|
|
1698
|
+
const entryCode = generateEntryCode(customRouteData, customRoutesDir, hasAuth);
|
|
1925
1699
|
const paths = resolveEmbeddedSourcePaths();
|
|
1926
1700
|
const buildConfig = createEsbuildConfig(
|
|
1927
1701
|
entryCode,
|
|
@@ -1941,7 +1715,7 @@ async function bundleBackend(config, options = {}) {
|
|
|
1941
1715
|
customRoutes: customRouteData
|
|
1942
1716
|
};
|
|
1943
1717
|
}
|
|
1944
|
-
function generateEntryCode(customRoutes, customRoutesDir) {
|
|
1718
|
+
function generateEntryCode(customRoutes, customRoutesDir, hasAuth) {
|
|
1945
1719
|
if (customRoutes.length === 0) {
|
|
1946
1720
|
return entryTemplate;
|
|
1947
1721
|
}
|
|
@@ -1950,9 +1724,10 @@ function generateEntryCode(customRoutes, customRoutesDir) {
|
|
|
1950
1724
|
const importPath = route.file.startsWith(customRoutesPrefix) ? route.file.slice(customRoutesPrefix.length) : route.file;
|
|
1951
1725
|
return `import * as customRoute${i} from '@game-api/${importPath}'`;
|
|
1952
1726
|
}).join("\n");
|
|
1953
|
-
const
|
|
1954
|
-
|
|
1955
|
-
|
|
1727
|
+
const withImports = entryTemplate.replace(
|
|
1728
|
+
"// \u26A0\uFE0F BUILD_MARKER: CUSTOM_ROUTE_IMPORTS \u26A0\uFE0F",
|
|
1729
|
+
importStatements
|
|
1730
|
+
);
|
|
1956
1731
|
const registrationStatements = customRoutes.flatMap((route, i) => {
|
|
1957
1732
|
const methods = ["GET", "POST", "PUT", "PATCH", "DELETE"];
|
|
1958
1733
|
return methods.map((method) => {
|
|
@@ -1961,29 +1736,33 @@ function generateEntryCode(customRoutes, customRoutesDir) {
|
|
|
1961
1736
|
});
|
|
1962
1737
|
});
|
|
1963
1738
|
const registrationCode = ["// Custom routes", ...registrationStatements, ""].join("\n");
|
|
1964
|
-
const
|
|
1965
|
-
const
|
|
1739
|
+
const withRoutes = withImports.replace("// \u26A0\uFE0F BUILD_MARKER: CUSTOM_ROUTES \u26A0\uFE0F", registrationCode);
|
|
1740
|
+
const sessionMiddlewareStatements = hasAuth ? [
|
|
1741
|
+
"import { createSessionMiddleware } from '@playcademy/edge-play'",
|
|
1742
|
+
"import { getAuth } from '@game-server/lib/auth'",
|
|
1743
|
+
"app.use('*', createSessionMiddleware(getAuth))"
|
|
1744
|
+
] : [];
|
|
1745
|
+
const sessionMiddlewareCode = sessionMiddlewareStatements.join("\n");
|
|
1746
|
+
const result = withRoutes.replace(
|
|
1747
|
+
"// \u26A0\uFE0F BUILD_MARKER: SESSION_MIDDLEWARE \u26A0\uFE0F",
|
|
1748
|
+
sessionMiddlewareCode
|
|
1749
|
+
);
|
|
1966
1750
|
return result;
|
|
1967
1751
|
}
|
|
1968
1752
|
|
|
1969
1753
|
// src/lib/init/prompts.ts
|
|
1970
1754
|
import { checkbox, confirm, input, select } from "@inquirer/prompts";
|
|
1971
1755
|
import { bold as bold3, cyan as cyan2 } from "colorette";
|
|
1972
|
-
init_constants2();
|
|
1973
1756
|
|
|
1974
|
-
// src/lib/init/
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1757
|
+
// src/lib/init/auth.ts
|
|
1758
|
+
var authTemplate = loadTemplateString("auth/auth.ts");
|
|
1759
|
+
var authCatchAllTemplate = loadTemplateString("auth/auth-catch-all.ts");
|
|
1760
|
+
var authSchemaTemplate = loadTemplateString("auth/auth-schema.ts");
|
|
1761
|
+
var protectedRouteTemplate = loadTemplateString("api/sample-protected.ts");
|
|
1978
1762
|
|
|
1979
1763
|
// src/lib/init/database.ts
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
init_core();
|
|
1983
|
-
init_logger();
|
|
1984
|
-
init_loader2();
|
|
1985
|
-
import { existsSync as existsSync6, mkdirSync as mkdirSync2, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
|
|
1986
|
-
import { join as join7 } from "path";
|
|
1764
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync2, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
|
|
1765
|
+
import { join as join8 } from "path";
|
|
1987
1766
|
var drizzleConfigTemplate = loadTemplateString("database/drizzle-config.ts");
|
|
1988
1767
|
var dbSchemaUsersTemplate = loadTemplateString("database/db-schema-users.ts");
|
|
1989
1768
|
var dbSchemaScoresTemplate = loadTemplateString("database/db-schema-scores.ts");
|
|
@@ -1994,9 +1773,9 @@ var dbSeedTemplate = loadTemplateString("database/db-seed.ts");
|
|
|
1994
1773
|
var packageTemplate = loadTemplateString("database/package.json");
|
|
1995
1774
|
function hasDatabaseSetup() {
|
|
1996
1775
|
const workspace = getWorkspace();
|
|
1997
|
-
const drizzleConfigPath =
|
|
1998
|
-
const drizzleConfigJsPath =
|
|
1999
|
-
return
|
|
1776
|
+
const drizzleConfigPath = join8(workspace, "drizzle.config.ts");
|
|
1777
|
+
const drizzleConfigJsPath = join8(workspace, "drizzle.config.js");
|
|
1778
|
+
return existsSync7(drizzleConfigPath) || existsSync7(drizzleConfigJsPath);
|
|
2000
1779
|
}
|
|
2001
1780
|
|
|
2002
1781
|
// src/lib/init/scaffold.ts
|
|
@@ -2006,11 +1785,6 @@ var sampleKvRouteTemplate = loadTemplateString("api/sample-kv.ts");
|
|
|
2006
1785
|
var sampleBucketRouteTemplate = loadTemplateString("api/sample-bucket.ts");
|
|
2007
1786
|
var playcademyGitignoreTemplate = loadTemplateString("playcademy-gitignore");
|
|
2008
1787
|
|
|
2009
|
-
// src/lib/init/display.ts
|
|
2010
|
-
init_package_manager();
|
|
2011
|
-
init_context();
|
|
2012
|
-
init_logger();
|
|
2013
|
-
|
|
2014
1788
|
// src/lib/init/kv.ts
|
|
2015
1789
|
function hasKVSetup(config) {
|
|
2016
1790
|
return !!config.integrations?.kv;
|
|
@@ -2023,106 +1797,27 @@ function hasBucketSetup(config) {
|
|
|
2023
1797
|
|
|
2024
1798
|
// src/lib/init/types.ts
|
|
2025
1799
|
init_file_loader();
|
|
2026
|
-
init_package_manager();
|
|
2027
|
-
init_string();
|
|
2028
|
-
init_constants2();
|
|
2029
|
-
init_loader();
|
|
2030
|
-
init_core();
|
|
2031
1800
|
import { execSync as execSync2 } from "child_process";
|
|
2032
|
-
import { writeFileSync as
|
|
1801
|
+
import { existsSync as existsSync10, writeFileSync as writeFileSync5 } from "fs";
|
|
2033
1802
|
import { dirname as dirname4, join as join11 } from "path";
|
|
2034
1803
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
2035
1804
|
|
|
2036
1805
|
// src/lib/deploy/backend.ts
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
init_core();
|
|
2040
|
-
import { existsSync as existsSync7 } from "node:fs";
|
|
2041
|
-
import { join as join8 } from "node:path";
|
|
2042
|
-
|
|
2043
|
-
// src/lib/integrations/timeback.ts
|
|
2044
|
-
init_src2();
|
|
2045
|
-
init_core();
|
|
2046
|
-
|
|
2047
|
-
// src/lib/integrations/utils.ts
|
|
2048
|
-
init_string();
|
|
2049
|
-
|
|
2050
|
-
// src/lib/deploy/schema.ts
|
|
2051
|
-
init_constants2();
|
|
2052
|
-
init_config3();
|
|
2053
|
-
init_core();
|
|
2054
|
-
|
|
2055
|
-
// src/lib/deploy/secrets.ts
|
|
2056
|
-
init_core();
|
|
2057
|
-
init_logger();
|
|
2058
|
-
|
|
2059
|
-
// src/lib/deploy/utils.ts
|
|
2060
|
-
init_src();
|
|
2061
|
-
|
|
2062
|
-
// src/lib/deploy/backend.ts
|
|
1806
|
+
import { existsSync as existsSync8 } from "node:fs";
|
|
1807
|
+
import { join as join9 } from "node:path";
|
|
2063
1808
|
function getCustomRoutesDirectory(projectPath, config) {
|
|
2064
1809
|
const customRoutes = config?.integrations?.customRoutes;
|
|
2065
1810
|
const customRoutesDir = typeof customRoutes === "object" && customRoutes.directory || DEFAULT_API_ROUTES_DIRECTORY;
|
|
2066
|
-
return
|
|
1811
|
+
return join9(projectPath, customRoutesDir);
|
|
2067
1812
|
}
|
|
2068
1813
|
function hasLocalCustomRoutes(projectPath, config) {
|
|
2069
1814
|
const customRoutesDir = getCustomRoutesDirectory(projectPath, config);
|
|
2070
|
-
return
|
|
2071
|
-
}
|
|
2072
|
-
|
|
2073
|
-
// src/lib/secrets/env.ts
|
|
2074
|
-
init_file_loader();
|
|
2075
|
-
init_constants2();
|
|
2076
|
-
import { existsSync as existsSync8 } from "fs";
|
|
2077
|
-
import { join as join9 } from "path";
|
|
2078
|
-
function parseEnvFile(contents) {
|
|
2079
|
-
const secrets = {};
|
|
2080
|
-
for (const line of contents.split("\n")) {
|
|
2081
|
-
const trimmed = line.trim();
|
|
2082
|
-
if (!trimmed || trimmed.startsWith("#")) {
|
|
2083
|
-
continue;
|
|
2084
|
-
}
|
|
2085
|
-
const match = trimmed.match(/^([A-Z_][A-Z0-9_]*)=(.*)$/);
|
|
2086
|
-
if (match) {
|
|
2087
|
-
const [, key, value] = match;
|
|
2088
|
-
if (!key || !value) {
|
|
2089
|
-
continue;
|
|
2090
|
-
}
|
|
2091
|
-
const unquoted = value.replace(/^["']|["']$/g, "");
|
|
2092
|
-
secrets[key] = unquoted;
|
|
2093
|
-
}
|
|
2094
|
-
}
|
|
2095
|
-
return secrets;
|
|
2096
|
-
}
|
|
2097
|
-
async function readEnvFile(workspace) {
|
|
2098
|
-
let secrets = {};
|
|
2099
|
-
for (const filename of ENV_FILES) {
|
|
2100
|
-
try {
|
|
2101
|
-
const contents = await loadFile(filename, { cwd: workspace, searchUp: false });
|
|
2102
|
-
if (contents) {
|
|
2103
|
-
const fileSecrets = parseEnvFile(contents);
|
|
2104
|
-
secrets = { ...secrets, ...fileSecrets };
|
|
2105
|
-
}
|
|
2106
|
-
} catch {
|
|
2107
|
-
continue;
|
|
2108
|
-
}
|
|
2109
|
-
}
|
|
2110
|
-
return secrets;
|
|
2111
|
-
}
|
|
2112
|
-
function getLoadedEnvFiles(workspace) {
|
|
2113
|
-
return ENV_FILES.filter((filename) => existsSync8(join9(workspace, filename)));
|
|
1815
|
+
return existsSync8(customRoutesDir);
|
|
2114
1816
|
}
|
|
2115
|
-
function hasEnvFile(workspace) {
|
|
2116
|
-
return ENV_FILES.some((filename) => existsSync8(join9(workspace, filename)));
|
|
2117
|
-
}
|
|
2118
|
-
|
|
2119
|
-
// src/lib/init/types.ts
|
|
2120
|
-
init_loader2();
|
|
2121
1817
|
|
|
2122
1818
|
// src/lib/init/tsconfig.ts
|
|
2123
1819
|
init_file_loader();
|
|
2124
|
-
|
|
2125
|
-
import { existsSync as existsSync9, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "fs";
|
|
1820
|
+
import { existsSync as existsSync9, readFileSync as readFileSync4, writeFileSync as writeFileSync4 } from "fs";
|
|
2126
1821
|
import { join as join10 } from "path";
|
|
2127
1822
|
function hasPlaycademyEnv(config) {
|
|
2128
1823
|
return config.include?.includes("playcademy-env.d.ts") ?? false;
|
|
@@ -2200,13 +1895,13 @@ async function ensureTsconfigIncludes(workspace) {
|
|
|
2200
1895
|
const rawContent = readFileSync4(configPath, "utf-8");
|
|
2201
1896
|
const updatedContent = addToIncludeArrayPreservingComments(rawContent);
|
|
2202
1897
|
if (updatedContent && updatedContent !== rawContent) {
|
|
2203
|
-
|
|
1898
|
+
writeFileSync4(configPath, updatedContent);
|
|
2204
1899
|
return filename;
|
|
2205
1900
|
}
|
|
2206
1901
|
} catch {
|
|
2207
1902
|
}
|
|
2208
1903
|
addPlaycademyEnv(config);
|
|
2209
|
-
|
|
1904
|
+
writeFileSync4(configPath, JSON.stringify(config, null, 4) + "\n");
|
|
2210
1905
|
return filename;
|
|
2211
1906
|
} catch {
|
|
2212
1907
|
continue;
|
|
@@ -2241,7 +1936,7 @@ async function setupPlaycademyDependencies(workspace) {
|
|
|
2241
1936
|
dependencies: { hono: honoVersion },
|
|
2242
1937
|
devDependencies: { "@cloudflare/workers-types": workersTypesVersion }
|
|
2243
1938
|
};
|
|
2244
|
-
|
|
1939
|
+
writeFileSync5(playcademyPkgPath, JSON.stringify(playcademyPkg, null, 4) + "\n");
|
|
2245
1940
|
const pm = detectPackageManager(workspace);
|
|
2246
1941
|
const installCmd = getInstallCommand(pm);
|
|
2247
1942
|
execSync2(installCmd, {
|
|
@@ -2256,6 +1951,22 @@ function generateBindingsTypeString(features) {
|
|
|
2256
1951
|
if (features.hasBucket) bindings.push(" BUCKET: R2Bucket");
|
|
2257
1952
|
return bindings.length > 0 ? "\n" + bindings.join("\n") : "";
|
|
2258
1953
|
}
|
|
1954
|
+
function generateAuthVariablesString(hasAuth, hasAuthFile) {
|
|
1955
|
+
const authImport = hasAuthFile ? "\nimport type { UserInfo } from './node_modules/@playcademy/sdk/dist/server.d.ts'\nimport type { User } from './server/lib/auth'" : "\nimport type { UserInfo } from './node_modules/@playcademy/sdk/dist/server.d.ts'";
|
|
1956
|
+
const variableFields = [" playcademyUser?: UserInfo"];
|
|
1957
|
+
if (hasAuth && hasAuthFile) {
|
|
1958
|
+
variableFields.push(" user?: User");
|
|
1959
|
+
}
|
|
1960
|
+
return {
|
|
1961
|
+
authImport,
|
|
1962
|
+
variables: `
|
|
1963
|
+
|
|
1964
|
+
interface PlaycademyVariables {
|
|
1965
|
+
${variableFields.join("\n")}
|
|
1966
|
+
}`,
|
|
1967
|
+
contextVars: "; Variables: PlaycademyVariables"
|
|
1968
|
+
};
|
|
1969
|
+
}
|
|
2259
1970
|
async function generateSecretsTypeString(workspace, verbose = false) {
|
|
2260
1971
|
try {
|
|
2261
1972
|
const envSecrets = await readEnvFile(workspace);
|
|
@@ -2299,10 +2010,16 @@ async function ensurePlaycademyTypes(options = {}) {
|
|
|
2299
2010
|
}
|
|
2300
2011
|
const bindingsStr = generateBindingsTypeString(features);
|
|
2301
2012
|
const secretsStr = await generateSecretsTypeString(workspace, verbose);
|
|
2013
|
+
const hasAuth = !!config.integrations?.auth;
|
|
2014
|
+
const hasAuthFile = existsSync10(join11(workspace, "server/lib/auth.ts"));
|
|
2015
|
+
const authVariablesString = generateAuthVariablesString(hasAuth, hasAuthFile);
|
|
2302
2016
|
let envContent = playcademyEnvTemplate.replace("{{BINDINGS}}", bindingsStr);
|
|
2303
2017
|
envContent = envContent.replace("{{SECRETS}}", secretsStr);
|
|
2018
|
+
envContent = envContent.replace("{{AUTH_IMPORT}}", authVariablesString.authImport);
|
|
2019
|
+
envContent = envContent.replace("{{VARIABLES}}", authVariablesString.variables);
|
|
2020
|
+
envContent = envContent.replace("{{CONTEXT_VARS}}", authVariablesString.contextVars);
|
|
2304
2021
|
const envPath = join11(workspace, "playcademy-env.d.ts");
|
|
2305
|
-
|
|
2022
|
+
writeFileSync5(envPath, envContent);
|
|
2306
2023
|
if (verbose) {
|
|
2307
2024
|
logger.success(`Generated <playcademy-env.d.ts>`);
|
|
2308
2025
|
}
|
|
@@ -2310,7 +2027,6 @@ async function ensurePlaycademyTypes(options = {}) {
|
|
|
2310
2027
|
if (verbose) {
|
|
2311
2028
|
logger.success(`Updated <${tsConfigFilename}>`);
|
|
2312
2029
|
}
|
|
2313
|
-
logger.newLine();
|
|
2314
2030
|
} catch (error) {
|
|
2315
2031
|
logger.warn(
|
|
2316
2032
|
`Failed to generate TypeScript types: ${error instanceof Error ? error.message : String(error)}`
|
|
@@ -2319,19 +2035,33 @@ async function ensurePlaycademyTypes(options = {}) {
|
|
|
2319
2035
|
}
|
|
2320
2036
|
|
|
2321
2037
|
// src/lib/init/gitignore.ts
|
|
2322
|
-
init_core();
|
|
2323
|
-
init_loader2();
|
|
2324
2038
|
var rootGitignoreTemplate = loadTemplateString("gitignore");
|
|
2325
2039
|
|
|
2326
2040
|
// src/lib/dev/server.ts
|
|
2327
2041
|
var FilteredLog = class extends Log {
|
|
2042
|
+
customLogger;
|
|
2043
|
+
constructor(logLevel, customLogger) {
|
|
2044
|
+
super(logLevel);
|
|
2045
|
+
this.customLogger = customLogger;
|
|
2046
|
+
}
|
|
2328
2047
|
logWithLevel(level, message) {
|
|
2329
2048
|
if (message.includes("Ready on")) return;
|
|
2330
|
-
|
|
2049
|
+
if (message.includes("Updated `Request.cf` object cache!")) return;
|
|
2050
|
+
if (this.customLogger) {
|
|
2051
|
+
this.customLogger.info(message);
|
|
2052
|
+
} else {
|
|
2053
|
+
console.log(message);
|
|
2054
|
+
}
|
|
2331
2055
|
}
|
|
2332
2056
|
};
|
|
2333
2057
|
async function startDevServer(options) {
|
|
2334
|
-
const {
|
|
2058
|
+
const {
|
|
2059
|
+
port: preferredPort,
|
|
2060
|
+
config: providedConfig,
|
|
2061
|
+
platformUrl,
|
|
2062
|
+
logger: logger2 = true,
|
|
2063
|
+
customLogger
|
|
2064
|
+
} = options;
|
|
2335
2065
|
const port = await findAvailablePort(preferredPort);
|
|
2336
2066
|
const config = providedConfig ?? await loadConfig();
|
|
2337
2067
|
await ensurePlaycademyTypes();
|
|
@@ -2349,7 +2079,7 @@ async function startDevServer(options) {
|
|
|
2349
2079
|
const bucketDir = hasBucket ? await ensureBucketDirectory() : void 0;
|
|
2350
2080
|
const workspace = getWorkspace();
|
|
2351
2081
|
const envSecrets = await readEnvFile(workspace);
|
|
2352
|
-
const log2 = logger2 ? new FilteredLog(LogLevel.INFO) : new Log(LogLevel.NONE);
|
|
2082
|
+
const log2 = logger2 ? new FilteredLog(LogLevel.INFO, customLogger) : new Log(LogLevel.NONE);
|
|
2353
2083
|
const sandboxInfo = readServerInfo("sandbox", workspace);
|
|
2354
2084
|
const baseUrl = platformUrl ?? sandboxInfo?.url ?? process.env.PLAYCADEMY_BASE_URL ?? `http://localhost:${DEFAULT_PORTS.SANDBOX}`;
|
|
2355
2085
|
const bindings = {
|
|
@@ -2377,7 +2107,18 @@ async function startDevServer(options) {
|
|
|
2377
2107
|
kvPersist: kvDir,
|
|
2378
2108
|
r2Buckets: hasBucket ? [CLOUDFLARE_BINDINGS.BUCKET] : [],
|
|
2379
2109
|
r2Persist: bucketDir,
|
|
2380
|
-
compatibilityDate: CLOUDFLARE_COMPATIBILITY_DATE
|
|
2110
|
+
compatibilityDate: CLOUDFLARE_COMPATIBILITY_DATE,
|
|
2111
|
+
/**
|
|
2112
|
+
* Enable Node.js compatibility for libraries that use Node.js APIs (like AsyncLocalStorage).
|
|
2113
|
+
* This was added when integrating Better Auth, which requires AsyncLocalStorage for session
|
|
2114
|
+
* management. No other integration has required this flag yet, but it provides additional
|
|
2115
|
+
* flexibility for users who may want to use other libraries that depend on Node.js APIs in
|
|
2116
|
+
* their custom routes. Future consideration: We may want to make this conditional based on
|
|
2117
|
+
* detected dependencies (e.g., only enable if better-auth is in package.json), but enabling
|
|
2118
|
+
* it by default seems reasonable given the tradeoff of better compatibility vs. minimal
|
|
2119
|
+
* performance impact.
|
|
2120
|
+
*/
|
|
2121
|
+
compatibilityFlags: ["nodejs_compat"]
|
|
2381
2122
|
});
|
|
2382
2123
|
if (hasDatabase) {
|
|
2383
2124
|
await initializeDatabase(mf);
|
|
@@ -2427,8 +2168,6 @@ async function writeBackendServerInfo(port) {
|
|
|
2427
2168
|
}
|
|
2428
2169
|
|
|
2429
2170
|
// src/lib/dev/reload.ts
|
|
2430
|
-
init_constants2();
|
|
2431
|
-
init_core();
|
|
2432
2171
|
import { join as join13, relative as relative2 } from "path";
|
|
2433
2172
|
import chokidar from "chokidar";
|
|
2434
2173
|
import { bold as bold4, cyan as cyan3, dim as dim3, green as green2 } from "colorette";
|
|
@@ -2486,9 +2225,6 @@ function startHotReload(onReload, options = {}) {
|
|
|
2486
2225
|
watcher.on("unlink", createReloadHandler("removed"));
|
|
2487
2226
|
return watcher;
|
|
2488
2227
|
}
|
|
2489
|
-
|
|
2490
|
-
// src/utils.ts
|
|
2491
|
-
init_import();
|
|
2492
2228
|
export {
|
|
2493
2229
|
findConfigPath as findPlaycademyConfigPath,
|
|
2494
2230
|
importTypescriptDefault,
|