playcademy 0.28.1-beta.9 → 0.29.0
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/README.md +56 -6
- package/dist/bin.js +1 -0
- package/dist/bucket.d.ts +15 -0
- package/dist/bucket.js +27 -37
- package/dist/cli.js +90 -87
- package/dist/constants.d.ts +21 -7
- package/dist/constants.js +43 -39
- package/dist/db.js +72 -77
- package/dist/index.d.ts +63 -8
- package/dist/index.js +2226 -630
- package/dist/runtime/dashboard-runtime/index.js +69 -20
- package/dist/runtime/dashboard-runtime/manifest.json +4 -4
- package/dist/runtime/game-runtime/index.js +2149 -337
- package/dist/runtime/game-runtime/manifest.json +4 -4
- package/dist/utils.d.ts +15 -0
- package/dist/utils.js +1202 -236
- package/dist/version.js +3 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
# playcademy
|
|
2
2
|
|
|
3
|
-
The official command-line interface for
|
|
3
|
+
**The official command-line interface for deploying and managing Playcademy games.**
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
The `playcademy` CLI authenticates developers, configures games, deploys frontend and backend
|
|
8
|
+
resources, and manages integrations such as TimeBack.
|
|
4
9
|
|
|
5
10
|
## Installation
|
|
6
11
|
|
|
@@ -186,7 +191,7 @@ my-game/
|
|
|
186
191
|
|
|
187
192
|
Backend routes are automatically deployed with hosted games.
|
|
188
193
|
|
|
189
|
-
|
|
194
|
+
### Credential Storage
|
|
190
195
|
|
|
191
196
|
Credentials are stored in `~/.playcademy/auth.json`:
|
|
192
197
|
|
|
@@ -277,7 +282,22 @@ playcademy timeback assessments import --env production
|
|
|
277
282
|
Fixtures are written to `.playcademy/timeback/assessment-fixtures.json`. The local dev host serves
|
|
278
283
|
them through the normal game SDK assessment methods and resets local attempts when it restarts.
|
|
279
284
|
|
|
280
|
-
|
|
285
|
+
#### `timeback assessments assets upload`
|
|
286
|
+
|
|
287
|
+
Upload one public assessment image to immutable, content-addressed CDN storage. Production is the
|
|
288
|
+
default for this command; pass `--env staging` explicitly when testing the upload flow.
|
|
289
|
+
|
|
290
|
+
```bash
|
|
291
|
+
playcademy timeback assessments assets upload ./diagram.png
|
|
292
|
+
playcademy timeback assessments assets upload ./diagram.png --env staging
|
|
293
|
+
playcademy timeback assessments assets upload ./diagram.png --json
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
Uploads accept PNG, JPEG, single-frame GIF, single-frame WebP, and uncompressed BMP files up to
|
|
297
|
+
4 MiB and 25 megapixels. Re-uploading identical bytes returns the existing URL without creating
|
|
298
|
+
another object.
|
|
299
|
+
|
|
300
|
+
### Environment Variables
|
|
281
301
|
|
|
282
302
|
- `CI` - Set to `1` or `true` to disable interactive prompts
|
|
283
303
|
- `PLAYCADEMY_API_TOKEN` - API token for non-interactive authentication
|
|
@@ -300,7 +320,7 @@ PLAYCADEMY_PROFILE=work playcademy deploy
|
|
|
300
320
|
PLAYCADEMY_BASE_URL=http://localhost:5174 playcademy deploy
|
|
301
321
|
```
|
|
302
322
|
|
|
303
|
-
|
|
323
|
+
### CI/CD
|
|
304
324
|
|
|
305
325
|
Use `CI=1`, `PLAYCADEMY_API_TOKEN`, and an explicit environment for pipeline deploys:
|
|
306
326
|
|
|
@@ -361,7 +381,7 @@ jobs:
|
|
|
361
381
|
PLAYCADEMY_API_TOKEN: ${{ secrets.PLAYCADEMY_API_TOKEN }}
|
|
362
382
|
```
|
|
363
383
|
|
|
364
|
-
|
|
384
|
+
### Configuration Files
|
|
365
385
|
|
|
366
386
|
The CLI supports multiple configuration formats:
|
|
367
387
|
|
|
@@ -371,7 +391,18 @@ The CLI supports multiple configuration formats:
|
|
|
371
391
|
|
|
372
392
|
Priority: CLI flags > config file > interactive prompts
|
|
373
393
|
|
|
374
|
-
##
|
|
394
|
+
## Development
|
|
395
|
+
|
|
396
|
+
From the repository root, install dependencies and run the CLI directly from source:
|
|
397
|
+
|
|
398
|
+
```bash
|
|
399
|
+
bun install
|
|
400
|
+
bun packages/cli/src/main.ts --help
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
Run `bun run check` and the relevant targeted tests before submitting changes.
|
|
404
|
+
|
|
405
|
+
## Dependencies
|
|
375
406
|
|
|
376
407
|
Built with:
|
|
377
408
|
|
|
@@ -380,6 +411,25 @@ Built with:
|
|
|
380
411
|
- **Colorette** - Terminal styling
|
|
381
412
|
- **esbuild** - Bundling (for encoding compatibility)
|
|
382
413
|
|
|
414
|
+
## Examples
|
|
415
|
+
|
|
416
|
+
```bash
|
|
417
|
+
# Inspect the authenticated account
|
|
418
|
+
playcademy me
|
|
419
|
+
|
|
420
|
+
# Validate a staging deployment without publishing it
|
|
421
|
+
playcademy deploy --env staging --dry-run
|
|
422
|
+
|
|
423
|
+
# Upload an immutable assessment image to staging
|
|
424
|
+
playcademy timeback assessments assets upload ./diagram.png --env staging
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
## Related Packages
|
|
428
|
+
|
|
429
|
+
- [`@playcademy/sdk`](../sdk) - Runtime and server APIs used by Playcademy games
|
|
430
|
+
- [`@playcademy/vite-plugin`](../vite-plugin) - Vite integration for Playcademy projects
|
|
431
|
+
- [`@playcademy/timeback`](../timeback) - Shared TimeBack integration utilities
|
|
432
|
+
|
|
383
433
|
## Contributing
|
|
384
434
|
|
|
385
435
|
See the main [CONTRIBUTING.md](../../CONTRIBUTING.md) for guidelines.
|
package/dist/bin.js
CHANGED
package/dist/bucket.d.ts
CHANGED
|
@@ -138,6 +138,19 @@ interface DashboardThemeConfig {
|
|
|
138
138
|
/** Secondary/accent color as a hex string, e.g. '#ffd166' */
|
|
139
139
|
secondary?: string;
|
|
140
140
|
}
|
|
141
|
+
/**
|
|
142
|
+
* Child-catalog contract generation (see @playcademy/sdk/contracts).
|
|
143
|
+
* The extractor is a repo-local script (run with the CLI's runtime) that
|
|
144
|
+
* prints `{ generatedFrom, deliveries }` as JSON on stdout; the CLI
|
|
145
|
+
* validates, stamps the contract fields, and writes
|
|
146
|
+
* `.playcademy/catalog.json` deterministically. The document carries no
|
|
147
|
+
* app identity — consuming repos assign the namespace key from sync
|
|
148
|
+
* provenance.
|
|
149
|
+
*/
|
|
150
|
+
interface CatalogConfig {
|
|
151
|
+
/** Path to the extractor script, relative to the config file. */
|
|
152
|
+
extractor: string;
|
|
153
|
+
}
|
|
141
154
|
/**
|
|
142
155
|
* Unified Playcademy configuration
|
|
143
156
|
* Used for playcademy.config.{js,json}
|
|
@@ -170,6 +183,8 @@ interface PlaycademyConfig {
|
|
|
170
183
|
dashboard?: DashboardConfig | boolean;
|
|
171
184
|
/** Integrations (database, custom routes, external services) */
|
|
172
185
|
integrations?: IntegrationsConfig;
|
|
186
|
+
/** Child-catalog contract generation (`playcademy catalog`) */
|
|
187
|
+
catalog?: CatalogConfig;
|
|
173
188
|
}
|
|
174
189
|
|
|
175
190
|
/**
|
package/dist/bucket.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { createRequire as __pcCreateRequire } from 'node:module'; const require = __pcCreateRequire(import.meta.url);
|
|
1
2
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
2
3
|
var __esm = (fn, res) => function __init() {
|
|
3
4
|
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
@@ -20,7 +21,7 @@ var init_file_loader = __esm({
|
|
|
20
21
|
|
|
21
22
|
// src/lib/bucket/dev.ts
|
|
22
23
|
import { existsSync } from "fs";
|
|
23
|
-
import { join as
|
|
24
|
+
import { join as join7 } from "path";
|
|
24
25
|
|
|
25
26
|
// ../edge-play/src/lib/constants.ts
|
|
26
27
|
var ASSET_PREFIX = "_assets/";
|
|
@@ -28,10 +29,7 @@ var MANIFEST_KEY = "_manifest.json";
|
|
|
28
29
|
var ASSET_ROUTE_PREFIX = "/api/assets/";
|
|
29
30
|
|
|
30
31
|
// src/lib/bundle/game-backend.ts
|
|
31
|
-
import { join as
|
|
32
|
-
|
|
33
|
-
// src/constants/api.ts
|
|
34
|
-
import { join as join2 } from "node:path";
|
|
32
|
+
import { join as join5 } from "node:path";
|
|
35
33
|
|
|
36
34
|
// src/constants/server.ts
|
|
37
35
|
import { join } from "node:path";
|
|
@@ -39,12 +37,12 @@ var GAME_SERVER_ROOT_DIRECTORY = "server";
|
|
|
39
37
|
var GAME_SERVER_LIB_DIRECTORY = join(GAME_SERVER_ROOT_DIRECTORY, "lib");
|
|
40
38
|
|
|
41
39
|
// src/constants/api.ts
|
|
42
|
-
var GAME_API_ROUTES_DIRECTORY =
|
|
40
|
+
var GAME_API_ROUTES_DIRECTORY = `${GAME_SERVER_ROOT_DIRECTORY}/api`;
|
|
43
41
|
|
|
44
42
|
// ../better-auth/package.json
|
|
45
43
|
var package_default = {
|
|
46
44
|
name: "@playcademy/better-auth",
|
|
47
|
-
version: "0.0.21
|
|
45
|
+
version: "0.0.21",
|
|
48
46
|
type: "module",
|
|
49
47
|
exports: {
|
|
50
48
|
"./server": {
|
|
@@ -87,18 +85,7 @@ var package_default = {
|
|
|
87
85
|
// src/constants/auth.ts
|
|
88
86
|
var BETTER_AUTH_VERSION = package_default.dependencies["better-auth"];
|
|
89
87
|
|
|
90
|
-
// src/constants/config.ts
|
|
91
|
-
var ENV_FILES = [
|
|
92
|
-
".env",
|
|
93
|
-
// Loaded first
|
|
94
|
-
".env.development",
|
|
95
|
-
// Overrides .env
|
|
96
|
-
".env.local"
|
|
97
|
-
// Overrides all (highest priority)
|
|
98
|
-
];
|
|
99
|
-
|
|
100
88
|
// src/constants/bucket.ts
|
|
101
|
-
var BUCKET_ALWAYS_SKIP = [".git", ".DS_Store", ".gitignore", ...ENV_FILES];
|
|
102
89
|
var PRESIGNED_UPLOAD_THRESHOLD = 4 * 1024 * 1024;
|
|
103
90
|
|
|
104
91
|
// src/constants/cloudflare.ts
|
|
@@ -112,45 +99,48 @@ var CLOUDFLARE_BINDINGS = {
|
|
|
112
99
|
};
|
|
113
100
|
|
|
114
101
|
// src/constants/database.ts
|
|
115
|
-
import { join as
|
|
116
|
-
var DEFAULT_DATABASE_DIRECTORY =
|
|
102
|
+
import { join as join2 } from "path";
|
|
103
|
+
var DEFAULT_DATABASE_DIRECTORY = join2("server", "db");
|
|
117
104
|
|
|
118
105
|
// src/constants/godot.ts
|
|
119
|
-
import { join as
|
|
106
|
+
import { join as join3 } from "node:path";
|
|
120
107
|
var GODOT_BUILD_DIRECTORIES = {
|
|
121
108
|
/** Root build directory (cleared before each export) */
|
|
122
109
|
ROOT: "build",
|
|
123
110
|
/** Web export subdirectory */
|
|
124
|
-
WEB:
|
|
111
|
+
WEB: join3("build", "web")
|
|
125
112
|
};
|
|
126
113
|
var GODOT_BUILD_OUTPUTS = {
|
|
127
114
|
/** Exported web build entry point */
|
|
128
|
-
INDEX_HTML:
|
|
115
|
+
INDEX_HTML: join3("build", "web", "index.html"),
|
|
129
116
|
/** Packaged zip file (created by Godot export) */
|
|
130
|
-
ZIP:
|
|
117
|
+
ZIP: join3("build", "web_playcademy.zip")
|
|
131
118
|
};
|
|
132
119
|
|
|
133
120
|
// src/constants/paths.ts
|
|
134
121
|
import { homedir } from "node:os";
|
|
135
|
-
import { join as
|
|
122
|
+
import { join as join4 } from "node:path";
|
|
136
123
|
var WORKSPACE_NAME = ".playcademy";
|
|
137
124
|
var CLI_DIRECTORIES = {
|
|
138
125
|
WORKSPACE: WORKSPACE_NAME,
|
|
139
|
-
DATABASE:
|
|
140
|
-
KV:
|
|
141
|
-
BUCKET:
|
|
142
|
-
TIMEBACK:
|
|
126
|
+
DATABASE: join4(WORKSPACE_NAME, "db"),
|
|
127
|
+
KV: join4(WORKSPACE_NAME, "kv"),
|
|
128
|
+
BUCKET: join4(WORKSPACE_NAME, "bucket"),
|
|
129
|
+
TIMEBACK: join4(WORKSPACE_NAME, "timeback")
|
|
143
130
|
};
|
|
144
|
-
var PLAYCADEMY_HOME =
|
|
131
|
+
var PLAYCADEMY_HOME = join4(homedir(), ".playcademy");
|
|
145
132
|
var CLI_USER_DIRECTORIES = {
|
|
146
133
|
CONFIG: PLAYCADEMY_HOME,
|
|
147
|
-
BIN:
|
|
148
|
-
CACHE:
|
|
134
|
+
BIN: join4(PLAYCADEMY_HOME, "bin"),
|
|
135
|
+
CACHE: join4(PLAYCADEMY_HOME, "cache")
|
|
149
136
|
};
|
|
150
137
|
var CLI_DEFAULT_OUTPUTS = {
|
|
151
|
-
WORKER_BUNDLE:
|
|
138
|
+
WORKER_BUNDLE: join4(WORKSPACE_NAME, "worker-bundle.js")
|
|
152
139
|
};
|
|
153
140
|
|
|
141
|
+
// ../constants/src/platform.ts
|
|
142
|
+
var ASSESSMENT_ASSET_MAX_BYTES = 4 * 1024 * 1024;
|
|
143
|
+
|
|
154
144
|
// ../constants/src/timeback.ts
|
|
155
145
|
var TIMEBACK_GAME_METRIC_DECIMAL_PLACES = {
|
|
156
146
|
xp: 1,
|
|
@@ -344,14 +334,14 @@ function resolveGameRoutesDir(config) {
|
|
|
344
334
|
return typeof customRoutes === "object" && customRoutes.directory || GAME_API_ROUTES_DIRECTORY;
|
|
345
335
|
}
|
|
346
336
|
function getGameRoutesDirectory(projectPath, config) {
|
|
347
|
-
return
|
|
337
|
+
return join5(projectPath, resolveGameRoutesDir(config));
|
|
348
338
|
}
|
|
349
339
|
|
|
350
340
|
// src/lib/bucket/local.ts
|
|
351
|
-
import { join as
|
|
341
|
+
import { join as join6 } from "path";
|
|
352
342
|
import { Miniflare } from "miniflare";
|
|
353
343
|
async function openLocalBucket() {
|
|
354
|
-
const bucketDir =
|
|
344
|
+
const bucketDir = join6(getWorkspace(), CLI_DIRECTORIES.BUCKET);
|
|
355
345
|
const mf = new Miniflare({
|
|
356
346
|
modules: [{ type: "ESModule", path: "index.mjs", contents: "" }],
|
|
357
347
|
r2Buckets: [CLOUDFLARE_BINDINGS.BUCKET],
|
|
@@ -368,7 +358,7 @@ async function openLocalBucket() {
|
|
|
368
358
|
var ASSET_DEV_ROUTE_PREFIX = ASSET_ROUTE_PREFIX;
|
|
369
359
|
function hasCustomAssetsRoute(projectRoot, config) {
|
|
370
360
|
const routesDir = getGameRoutesDirectory(projectRoot, config);
|
|
371
|
-
return existsSync(
|
|
361
|
+
return existsSync(join7(routesDir, "assets")) || existsSync(join7(routesDir, "assets.ts"));
|
|
372
362
|
}
|
|
373
363
|
function openLocalAssetBucket() {
|
|
374
364
|
return openLocalBucket();
|