playcademy 0.13.22 → 0.14.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/dist/constants.d.ts +49 -12
- package/dist/constants.js +24 -7
- package/dist/db.d.ts +62 -18
- package/dist/db.js +152 -43
- package/dist/index.d.ts +69 -1
- package/dist/index.js +1693 -812
- package/dist/templates/database/db-seed.ts.template +7 -19
- package/dist/utils.js +56 -6
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -2130,10 +2130,43 @@ var init_config = __esm({
|
|
|
2130
2130
|
}
|
|
2131
2131
|
});
|
|
2132
2132
|
|
|
2133
|
+
// src/constants/bucket.ts
|
|
2134
|
+
var BUCKET_ALWAYS_SKIP;
|
|
2135
|
+
var init_bucket = __esm({
|
|
2136
|
+
"src/constants/bucket.ts"() {
|
|
2137
|
+
"use strict";
|
|
2138
|
+
init_config();
|
|
2139
|
+
BUCKET_ALWAYS_SKIP = [".git", ".DS_Store", ".gitignore", ...ENV_FILES];
|
|
2140
|
+
}
|
|
2141
|
+
});
|
|
2142
|
+
|
|
2143
|
+
// src/constants/cloudflare.ts
|
|
2144
|
+
var CLOUDFLARE_COMPATIBILITY_DATE, CLOUDFLARE_BINDINGS, MINIFLARE_D1_DIRECTORY;
|
|
2145
|
+
var init_cloudflare = __esm({
|
|
2146
|
+
"src/constants/cloudflare.ts"() {
|
|
2147
|
+
"use strict";
|
|
2148
|
+
CLOUDFLARE_COMPATIBILITY_DATE = "2024-01-01";
|
|
2149
|
+
CLOUDFLARE_BINDINGS = {
|
|
2150
|
+
/** R2 bucket binding name */
|
|
2151
|
+
BUCKET: "BUCKET",
|
|
2152
|
+
/** KV namespace binding name */
|
|
2153
|
+
KV: "KV",
|
|
2154
|
+
/** D1 database binding name */
|
|
2155
|
+
DB: "DB"
|
|
2156
|
+
};
|
|
2157
|
+
MINIFLARE_D1_DIRECTORY = "miniflare-D1DatabaseObject";
|
|
2158
|
+
}
|
|
2159
|
+
});
|
|
2160
|
+
|
|
2133
2161
|
// src/constants/database.ts
|
|
2162
|
+
var DEFAULT_DATABASE_DIRECTORY, SCHEMA_SUBDIRECTORY, SCHEMA_INDEX_FILE, DEFAULT_SEED_FILE_NAME;
|
|
2134
2163
|
var init_database = __esm({
|
|
2135
2164
|
"src/constants/database.ts"() {
|
|
2136
2165
|
"use strict";
|
|
2166
|
+
DEFAULT_DATABASE_DIRECTORY = "db";
|
|
2167
|
+
SCHEMA_SUBDIRECTORY = "schema";
|
|
2168
|
+
SCHEMA_INDEX_FILE = "index.ts";
|
|
2169
|
+
DEFAULT_SEED_FILE_NAME = "seed.ts";
|
|
2137
2170
|
}
|
|
2138
2171
|
});
|
|
2139
2172
|
|
|
@@ -2337,11 +2370,12 @@ var init_urls = __esm({
|
|
|
2337
2370
|
});
|
|
2338
2371
|
|
|
2339
2372
|
// src/constants/index.ts
|
|
2340
|
-
var CLOUDFLARE_COMPATIBILITY_DATE;
|
|
2341
2373
|
var init_constants = __esm({
|
|
2342
2374
|
"src/constants/index.ts"() {
|
|
2343
2375
|
"use strict";
|
|
2344
2376
|
init_api();
|
|
2377
|
+
init_bucket();
|
|
2378
|
+
init_cloudflare();
|
|
2345
2379
|
init_config();
|
|
2346
2380
|
init_database();
|
|
2347
2381
|
init_http_server();
|
|
@@ -2349,7 +2383,6 @@ var init_constants = __esm({
|
|
|
2349
2383
|
init_ports();
|
|
2350
2384
|
init_timeback();
|
|
2351
2385
|
init_urls();
|
|
2352
|
-
CLOUDFLARE_COMPATIBILITY_DATE = "2024-01-01";
|
|
2353
2386
|
}
|
|
2354
2387
|
});
|
|
2355
2388
|
|
|
@@ -2800,6 +2833,68 @@ var init_storage = __esm({
|
|
|
2800
2833
|
}
|
|
2801
2834
|
});
|
|
2802
2835
|
|
|
2836
|
+
// src/lib/core/client.ts
|
|
2837
|
+
import { PlaycademyClient } from "@playcademy/sdk";
|
|
2838
|
+
async function createClient() {
|
|
2839
|
+
const profile = await getCurrentProfile();
|
|
2840
|
+
const baseUrl = getBaseUrl();
|
|
2841
|
+
const client = new PlaycademyClient({
|
|
2842
|
+
baseUrl,
|
|
2843
|
+
token: profile?.token
|
|
2844
|
+
});
|
|
2845
|
+
if (profile?.token && profile?.tokenType) {
|
|
2846
|
+
client.setToken(profile.token, profile.tokenType);
|
|
2847
|
+
}
|
|
2848
|
+
return client;
|
|
2849
|
+
}
|
|
2850
|
+
async function requireAuthenticatedClient() {
|
|
2851
|
+
const profile = await getCurrentProfile();
|
|
2852
|
+
const environment = getEnvironment();
|
|
2853
|
+
if (!profile) {
|
|
2854
|
+
logger.newLine();
|
|
2855
|
+
logger.admonition("warning", "Login Required", [
|
|
2856
|
+
`You are not logged into ${environment}.`,
|
|
2857
|
+
environment === "production" ? `Run \`playcademy login --env ${environment}\` to authenticate.` : "Run `playcademy login` to authenticate."
|
|
2858
|
+
]);
|
|
2859
|
+
logger.newLine();
|
|
2860
|
+
process.exit(1);
|
|
2861
|
+
}
|
|
2862
|
+
const client = await createClient();
|
|
2863
|
+
return client;
|
|
2864
|
+
}
|
|
2865
|
+
var init_client = __esm({
|
|
2866
|
+
"src/lib/core/client.ts"() {
|
|
2867
|
+
"use strict";
|
|
2868
|
+
init_storage();
|
|
2869
|
+
init_logger();
|
|
2870
|
+
init_config2();
|
|
2871
|
+
}
|
|
2872
|
+
});
|
|
2873
|
+
|
|
2874
|
+
// src/lib/core/errors.ts
|
|
2875
|
+
function getErrorMessage(error) {
|
|
2876
|
+
if (error instanceof Error) return error.message;
|
|
2877
|
+
if (typeof error === "string") return error;
|
|
2878
|
+
if (error && typeof error === "object" && "message" in error) {
|
|
2879
|
+
return String(error.message);
|
|
2880
|
+
}
|
|
2881
|
+
return "Unknown error";
|
|
2882
|
+
}
|
|
2883
|
+
function logAndExit(error, logger2, options = {}) {
|
|
2884
|
+
const { code = 1, prefix } = options;
|
|
2885
|
+
const message = getErrorMessage(error);
|
|
2886
|
+
const fullMessage = prefix ? `${prefix}: ${message}` : message;
|
|
2887
|
+
logger2.newLine();
|
|
2888
|
+
logger2.error(fullMessage);
|
|
2889
|
+
logger2.newLine();
|
|
2890
|
+
process.exit(code);
|
|
2891
|
+
}
|
|
2892
|
+
var init_errors = __esm({
|
|
2893
|
+
"src/lib/core/errors.ts"() {
|
|
2894
|
+
"use strict";
|
|
2895
|
+
}
|
|
2896
|
+
});
|
|
2897
|
+
|
|
2803
2898
|
// src/lib/config/loader.ts
|
|
2804
2899
|
import { dirname as dirname2, resolve as resolve3 } from "path";
|
|
2805
2900
|
async function findConfigPath(configPath) {
|
|
@@ -3135,68 +3230,6 @@ var init_constants3 = __esm({
|
|
|
3135
3230
|
}
|
|
3136
3231
|
});
|
|
3137
3232
|
|
|
3138
|
-
// src/lib/core/game.ts
|
|
3139
|
-
function getSlugFromConfig(config) {
|
|
3140
|
-
return generateSlug(config.name);
|
|
3141
|
-
}
|
|
3142
|
-
async function ensureGameExists(client, config) {
|
|
3143
|
-
const slug = getSlugFromConfig(config);
|
|
3144
|
-
let game = await runStep(
|
|
3145
|
-
`Checking for game "${slug}"`,
|
|
3146
|
-
async () => {
|
|
3147
|
-
try {
|
|
3148
|
-
return await client.games.fetch(slug);
|
|
3149
|
-
} catch {
|
|
3150
|
-
return null;
|
|
3151
|
-
}
|
|
3152
|
-
},
|
|
3153
|
-
(result) => result ? "Found existing game" : "Game not found"
|
|
3154
|
-
);
|
|
3155
|
-
if (!game) {
|
|
3156
|
-
game = await runStep(
|
|
3157
|
-
`Creating game metadata for "${slug}"`,
|
|
3158
|
-
() => client.dev.games.upsert(slug, {
|
|
3159
|
-
displayName: config.name,
|
|
3160
|
-
platform: config.platform ?? "web",
|
|
3161
|
-
gameType: config.gameType ?? "hosted",
|
|
3162
|
-
metadata: {
|
|
3163
|
-
...config.description && { description: config.description },
|
|
3164
|
-
...config.emoji && { emoji: config.emoji }
|
|
3165
|
-
},
|
|
3166
|
-
...config.gameType === "external" && config.externalUrl && {
|
|
3167
|
-
externalUrl: config.externalUrl
|
|
3168
|
-
}
|
|
3169
|
-
}),
|
|
3170
|
-
"Game metadata created"
|
|
3171
|
-
);
|
|
3172
|
-
}
|
|
3173
|
-
return game;
|
|
3174
|
-
}
|
|
3175
|
-
async function getGameFromConfig(client) {
|
|
3176
|
-
const config = await runStep("Loading configuration", loadConfig, "Configuration loaded");
|
|
3177
|
-
const slug = getSlugFromConfig(config);
|
|
3178
|
-
const game = await runStep(
|
|
3179
|
-
`Finding game "${slug}"`,
|
|
3180
|
-
async () => {
|
|
3181
|
-
try {
|
|
3182
|
-
return await client.games.fetch(slug);
|
|
3183
|
-
} catch {
|
|
3184
|
-
throw new Error(`Game "${slug}" not found`);
|
|
3185
|
-
}
|
|
3186
|
-
},
|
|
3187
|
-
"Game found"
|
|
3188
|
-
);
|
|
3189
|
-
return { game, config };
|
|
3190
|
-
}
|
|
3191
|
-
var init_game = __esm({
|
|
3192
|
-
"src/lib/core/game.ts"() {
|
|
3193
|
-
"use strict";
|
|
3194
|
-
init_src();
|
|
3195
|
-
init_slug();
|
|
3196
|
-
init_config3();
|
|
3197
|
-
}
|
|
3198
|
-
});
|
|
3199
|
-
|
|
3200
3233
|
// src/lib/config/timeback-derive.ts
|
|
3201
3234
|
function generateCourseCode(slug) {
|
|
3202
3235
|
return slug.split("-").slice(0, 2).map((word) => word.substring(0, 3).toUpperCase()).join("-");
|
|
@@ -3622,81 +3655,131 @@ var init_config3 = __esm({
|
|
|
3622
3655
|
}
|
|
3623
3656
|
});
|
|
3624
3657
|
|
|
3625
|
-
// src/lib/core/
|
|
3626
|
-
|
|
3627
|
-
|
|
3628
|
-
const profile = await getCurrentProfile();
|
|
3629
|
-
const baseUrl = getBaseUrl();
|
|
3630
|
-
const client = new PlaycademyClient({
|
|
3631
|
-
baseUrl,
|
|
3632
|
-
token: profile?.token
|
|
3633
|
-
});
|
|
3634
|
-
if (profile?.token && profile?.tokenType) {
|
|
3635
|
-
client.setToken(profile.token, profile.tokenType);
|
|
3636
|
-
}
|
|
3637
|
-
return client;
|
|
3658
|
+
// src/lib/core/game.ts
|
|
3659
|
+
function getSlugFromConfig(config) {
|
|
3660
|
+
return generateSlug(config.name);
|
|
3638
3661
|
}
|
|
3639
|
-
async function
|
|
3640
|
-
const
|
|
3641
|
-
|
|
3642
|
-
|
|
3643
|
-
|
|
3644
|
-
|
|
3645
|
-
|
|
3646
|
-
|
|
3647
|
-
|
|
3648
|
-
|
|
3649
|
-
|
|
3662
|
+
async function ensureGameExists(client, config) {
|
|
3663
|
+
const slug = getSlugFromConfig(config);
|
|
3664
|
+
let game = await runStep(
|
|
3665
|
+
`Checking for game "${slug}"`,
|
|
3666
|
+
async () => {
|
|
3667
|
+
try {
|
|
3668
|
+
return await client.games.fetch(slug);
|
|
3669
|
+
} catch {
|
|
3670
|
+
return null;
|
|
3671
|
+
}
|
|
3672
|
+
},
|
|
3673
|
+
(result) => result ? "Found existing game" : "Game not found"
|
|
3674
|
+
);
|
|
3675
|
+
if (!game) {
|
|
3676
|
+
game = await runStep(
|
|
3677
|
+
`Creating game metadata for "${slug}"`,
|
|
3678
|
+
() => client.dev.games.upsert(slug, {
|
|
3679
|
+
displayName: config.name,
|
|
3680
|
+
platform: config.platform ?? "web",
|
|
3681
|
+
gameType: config.gameType ?? "hosted",
|
|
3682
|
+
metadata: {
|
|
3683
|
+
...config.description && { description: config.description },
|
|
3684
|
+
...config.emoji && { emoji: config.emoji }
|
|
3685
|
+
},
|
|
3686
|
+
...config.gameType === "external" && config.externalUrl && {
|
|
3687
|
+
externalUrl: config.externalUrl
|
|
3688
|
+
}
|
|
3689
|
+
}),
|
|
3690
|
+
"Game metadata created"
|
|
3691
|
+
);
|
|
3650
3692
|
}
|
|
3651
|
-
|
|
3652
|
-
return client;
|
|
3693
|
+
return game;
|
|
3653
3694
|
}
|
|
3654
|
-
|
|
3655
|
-
"
|
|
3695
|
+
async function getGameFromConfig(client) {
|
|
3696
|
+
const config = await runStep("Loading configuration", loadConfig, "Configuration loaded");
|
|
3697
|
+
const slug = getSlugFromConfig(config);
|
|
3698
|
+
const game = await runStep(
|
|
3699
|
+
`Finding game "${slug}"`,
|
|
3700
|
+
async () => {
|
|
3701
|
+
try {
|
|
3702
|
+
return await client.games.fetch(slug);
|
|
3703
|
+
} catch {
|
|
3704
|
+
throw new Error(`Game "${slug}" not found`);
|
|
3705
|
+
}
|
|
3706
|
+
},
|
|
3707
|
+
"Game found"
|
|
3708
|
+
);
|
|
3709
|
+
return { game, config };
|
|
3710
|
+
}
|
|
3711
|
+
var init_game = __esm({
|
|
3712
|
+
"src/lib/core/game.ts"() {
|
|
3656
3713
|
"use strict";
|
|
3657
|
-
|
|
3658
|
-
|
|
3659
|
-
|
|
3714
|
+
init_src();
|
|
3715
|
+
init_slug();
|
|
3716
|
+
init_config3();
|
|
3660
3717
|
}
|
|
3661
3718
|
});
|
|
3662
3719
|
|
|
3663
|
-
// src/lib/core/
|
|
3664
|
-
|
|
3665
|
-
|
|
3666
|
-
|
|
3667
|
-
|
|
3668
|
-
return String(error.message);
|
|
3669
|
-
}
|
|
3670
|
-
return "Unknown error";
|
|
3671
|
-
}
|
|
3672
|
-
function logAndExit(error, logger2, options = {}) {
|
|
3673
|
-
const { code = 1, prefix } = options;
|
|
3674
|
-
const message = getErrorMessage(error);
|
|
3675
|
-
const fullMessage = prefix ? `${prefix}: ${message}` : message;
|
|
3676
|
-
logger2.newLine();
|
|
3677
|
-
logger2.error(fullMessage);
|
|
3678
|
-
logger2.newLine();
|
|
3679
|
-
process.exit(code);
|
|
3720
|
+
// src/lib/core/gitignore.ts
|
|
3721
|
+
import { existsSync as existsSync5, readFileSync as readFileSync3 } from "fs";
|
|
3722
|
+
import { join as join4, sep } from "path";
|
|
3723
|
+
function normalizeGitignoreEntry(entry) {
|
|
3724
|
+
return entry.replace(/^\/+/, "").replace(/\/+$/, "");
|
|
3680
3725
|
}
|
|
3681
|
-
|
|
3682
|
-
"
|
|
3683
|
-
|
|
3726
|
+
function loadGitignorePatterns(directory) {
|
|
3727
|
+
const gitignorePath = join4(directory, ".gitignore");
|
|
3728
|
+
if (!existsSync5(gitignorePath)) {
|
|
3729
|
+
return [];
|
|
3684
3730
|
}
|
|
3685
|
-
});
|
|
3686
|
-
|
|
3687
|
-
// src/lib/core/import.ts
|
|
3688
|
-
import { mkdtempSync, rmSync } from "fs";
|
|
3689
|
-
import { tmpdir } from "os";
|
|
3690
|
-
import { join as join4 } from "path";
|
|
3691
|
-
import { pathToFileURL } from "url";
|
|
3692
|
-
import * as esbuild from "esbuild";
|
|
3693
|
-
async function importTypescriptFile(filePath, bundleOptions) {
|
|
3694
|
-
const tempDir = mkdtempSync(join4(tmpdir(), "playcademy-import-"));
|
|
3695
|
-
const outFile = join4(tempDir, "bundle.mjs");
|
|
3696
3731
|
try {
|
|
3697
|
-
|
|
3698
|
-
|
|
3699
|
-
|
|
3732
|
+
const content = readFileSync3(gitignorePath, "utf-8");
|
|
3733
|
+
return content.split("\n").map((line) => line.trim()).filter((line) => line && !line.startsWith("#"));
|
|
3734
|
+
} catch {
|
|
3735
|
+
return [];
|
|
3736
|
+
}
|
|
3737
|
+
}
|
|
3738
|
+
function matchesGitignorePattern(filePath, pattern) {
|
|
3739
|
+
if (pattern.endsWith("/")) {
|
|
3740
|
+
const dirPattern = pattern.slice(0, -1);
|
|
3741
|
+
if (filePath.includes(dirPattern + sep) || filePath === dirPattern) {
|
|
3742
|
+
return true;
|
|
3743
|
+
}
|
|
3744
|
+
}
|
|
3745
|
+
if (pattern.includes("*")) {
|
|
3746
|
+
const regex = new RegExp("^" + pattern.replace(/\*/g, ".*") + "$");
|
|
3747
|
+
if (regex.test(filePath)) {
|
|
3748
|
+
return true;
|
|
3749
|
+
}
|
|
3750
|
+
}
|
|
3751
|
+
if (filePath === pattern || filePath.includes(sep + pattern) || filePath.endsWith(pattern)) {
|
|
3752
|
+
return true;
|
|
3753
|
+
}
|
|
3754
|
+
return false;
|
|
3755
|
+
}
|
|
3756
|
+
function isIgnoredByGitignore(filePath, patterns) {
|
|
3757
|
+
for (const pattern of patterns) {
|
|
3758
|
+
if (matchesGitignorePattern(filePath, pattern)) {
|
|
3759
|
+
return true;
|
|
3760
|
+
}
|
|
3761
|
+
}
|
|
3762
|
+
return false;
|
|
3763
|
+
}
|
|
3764
|
+
var init_gitignore = __esm({
|
|
3765
|
+
"src/lib/core/gitignore.ts"() {
|
|
3766
|
+
"use strict";
|
|
3767
|
+
}
|
|
3768
|
+
});
|
|
3769
|
+
|
|
3770
|
+
// src/lib/core/import.ts
|
|
3771
|
+
import { mkdtempSync, rmSync } from "fs";
|
|
3772
|
+
import { tmpdir } from "os";
|
|
3773
|
+
import { join as join5 } from "path";
|
|
3774
|
+
import { pathToFileURL } from "url";
|
|
3775
|
+
import * as esbuild from "esbuild";
|
|
3776
|
+
async function importTypescriptFile(filePath, bundleOptions) {
|
|
3777
|
+
const tempDir = mkdtempSync(join5(tmpdir(), "playcademy-import-"));
|
|
3778
|
+
const outFile = join5(tempDir, "bundle.mjs");
|
|
3779
|
+
try {
|
|
3780
|
+
await esbuild.build({
|
|
3781
|
+
entryPoints: [filePath],
|
|
3782
|
+
outfile: outFile,
|
|
3700
3783
|
bundle: true,
|
|
3701
3784
|
platform: "node",
|
|
3702
3785
|
format: "esm",
|
|
@@ -3724,6 +3807,57 @@ var init_import = __esm({
|
|
|
3724
3807
|
}
|
|
3725
3808
|
});
|
|
3726
3809
|
|
|
3810
|
+
// src/lib/core/mime.ts
|
|
3811
|
+
function getContentType(filePath) {
|
|
3812
|
+
const ext = filePath.split(".").pop()?.toLowerCase();
|
|
3813
|
+
const types = {
|
|
3814
|
+
// Images
|
|
3815
|
+
jpg: "image/jpeg",
|
|
3816
|
+
jpeg: "image/jpeg",
|
|
3817
|
+
png: "image/png",
|
|
3818
|
+
gif: "image/gif",
|
|
3819
|
+
webp: "image/webp",
|
|
3820
|
+
svg: "image/svg+xml",
|
|
3821
|
+
ico: "image/x-icon",
|
|
3822
|
+
// Audio
|
|
3823
|
+
mp3: "audio/mpeg",
|
|
3824
|
+
wav: "audio/wav",
|
|
3825
|
+
ogg: "audio/ogg",
|
|
3826
|
+
m4a: "audio/mp4",
|
|
3827
|
+
// Video
|
|
3828
|
+
mp4: "video/mp4",
|
|
3829
|
+
webm: "video/webm",
|
|
3830
|
+
mov: "video/quicktime",
|
|
3831
|
+
// Documents
|
|
3832
|
+
pdf: "application/pdf",
|
|
3833
|
+
txt: "text/plain",
|
|
3834
|
+
md: "text/markdown",
|
|
3835
|
+
// Web
|
|
3836
|
+
html: "text/html",
|
|
3837
|
+
htm: "text/html",
|
|
3838
|
+
css: "text/css",
|
|
3839
|
+
js: "application/javascript",
|
|
3840
|
+
mjs: "application/javascript",
|
|
3841
|
+
json: "application/json",
|
|
3842
|
+
xml: "application/xml",
|
|
3843
|
+
// Archives
|
|
3844
|
+
zip: "application/zip",
|
|
3845
|
+
gz: "application/gzip",
|
|
3846
|
+
tar: "application/x-tar",
|
|
3847
|
+
// Fonts
|
|
3848
|
+
woff: "font/woff",
|
|
3849
|
+
woff2: "font/woff2",
|
|
3850
|
+
ttf: "font/ttf",
|
|
3851
|
+
otf: "font/otf"
|
|
3852
|
+
};
|
|
3853
|
+
return types[ext || ""] || "application/octet-stream";
|
|
3854
|
+
}
|
|
3855
|
+
var init_mime2 = __esm({
|
|
3856
|
+
"src/lib/core/mime.ts"() {
|
|
3857
|
+
"use strict";
|
|
3858
|
+
}
|
|
3859
|
+
});
|
|
3860
|
+
|
|
3727
3861
|
// src/lib/core/index.ts
|
|
3728
3862
|
var core_exports = {};
|
|
3729
3863
|
__export(core_exports, {
|
|
@@ -3733,6 +3867,7 @@ __export(core_exports, {
|
|
|
3733
3867
|
getApiUrl: () => getApiUrl,
|
|
3734
3868
|
getBaseUrl: () => getBaseUrl,
|
|
3735
3869
|
getCliContext: () => getCliContext,
|
|
3870
|
+
getContentType: () => getContentType,
|
|
3736
3871
|
getEnvironment: () => getEnvironment,
|
|
3737
3872
|
getErrorMessage: () => getErrorMessage,
|
|
3738
3873
|
getGameFromConfig: () => getGameFromConfig,
|
|
@@ -3744,9 +3879,13 @@ __export(core_exports, {
|
|
|
3744
3879
|
hasPackageJson: () => hasPackageJson,
|
|
3745
3880
|
importTypescriptDefault: () => importTypescriptDefault,
|
|
3746
3881
|
importTypescriptFile: () => importTypescriptFile,
|
|
3882
|
+
isIgnoredByGitignore: () => isIgnoredByGitignore,
|
|
3883
|
+
loadGitignorePatterns: () => loadGitignorePatterns,
|
|
3747
3884
|
logAndExit: () => logAndExit,
|
|
3748
3885
|
logger: () => logger,
|
|
3886
|
+
matchesGitignorePattern: () => matchesGitignorePattern,
|
|
3749
3887
|
normalizeEnvironment: () => normalizeEnvironment,
|
|
3888
|
+
normalizeGitignoreEntry: () => normalizeGitignoreEntry,
|
|
3750
3889
|
requireAuthenticatedClient: () => requireAuthenticatedClient,
|
|
3751
3890
|
setCliContext: () => setCliContext
|
|
3752
3891
|
});
|
|
@@ -3758,8 +3897,10 @@ var init_core = __esm({
|
|
|
3758
3897
|
init_context();
|
|
3759
3898
|
init_errors();
|
|
3760
3899
|
init_game();
|
|
3900
|
+
init_gitignore();
|
|
3761
3901
|
init_import();
|
|
3762
3902
|
init_logger();
|
|
3903
|
+
init_mime2();
|
|
3763
3904
|
}
|
|
3764
3905
|
});
|
|
3765
3906
|
|
|
@@ -3790,7 +3931,7 @@ import { program } from "commander";
|
|
|
3790
3931
|
|
|
3791
3932
|
// src/commands/init/index.ts
|
|
3792
3933
|
import { execSync as execSync4 } from "child_process";
|
|
3793
|
-
import { readFileSync as
|
|
3934
|
+
import { readFileSync as readFileSync9, writeFileSync as writeFileSync9 } from "fs";
|
|
3794
3935
|
import { resolve as resolve10 } from "path";
|
|
3795
3936
|
|
|
3796
3937
|
// ../../node_modules/@inquirer/core/dist/esm/lib/errors.js
|
|
@@ -4586,19 +4727,166 @@ function getCallbackUrl() {
|
|
|
4586
4727
|
return `http://localhost:${CALLBACK_PORT}${CALLBACK_PATH}`;
|
|
4587
4728
|
}
|
|
4588
4729
|
|
|
4730
|
+
// src/lib/bucket/bulk.ts
|
|
4731
|
+
init_src();
|
|
4732
|
+
init_core();
|
|
4733
|
+
import { readFileSync as readFileSync4 } from "fs";
|
|
4734
|
+
import { dim as dim3 } from "colorette";
|
|
4735
|
+
|
|
4736
|
+
// src/lib/bucket/collect.ts
|
|
4737
|
+
init_constants2();
|
|
4738
|
+
init_core();
|
|
4739
|
+
init_core();
|
|
4740
|
+
import { readdirSync as readdirSync2, statSync as statSync2 } from "fs";
|
|
4741
|
+
import { join as join6, relative, sep as sep2 } from "path";
|
|
4742
|
+
function shouldSkipFile(filePath, baseDir, gitignorePatterns) {
|
|
4743
|
+
const relativePath = relative(baseDir, filePath);
|
|
4744
|
+
const pathParts = relativePath.split(sep2);
|
|
4745
|
+
const alwaysSkip = BUCKET_ALWAYS_SKIP;
|
|
4746
|
+
for (const part of pathParts) {
|
|
4747
|
+
if (alwaysSkip.includes(part)) return true;
|
|
4748
|
+
}
|
|
4749
|
+
return isIgnoredByGitignore(relativePath, gitignorePatterns);
|
|
4750
|
+
}
|
|
4751
|
+
function collectFiles(directory, baseDir, gitignorePatterns) {
|
|
4752
|
+
const files = [];
|
|
4753
|
+
try {
|
|
4754
|
+
const entries = readdirSync2(directory, { withFileTypes: true });
|
|
4755
|
+
for (const entry of entries) {
|
|
4756
|
+
const fullPath = join6(directory, entry.name);
|
|
4757
|
+
if (shouldSkipFile(fullPath, baseDir, gitignorePatterns)) {
|
|
4758
|
+
continue;
|
|
4759
|
+
}
|
|
4760
|
+
if (entry.isDirectory()) {
|
|
4761
|
+
files.push(...collectFiles(fullPath, baseDir, gitignorePatterns));
|
|
4762
|
+
} else if (entry.isFile()) {
|
|
4763
|
+
const stats = statSync2(fullPath);
|
|
4764
|
+
files.push({
|
|
4765
|
+
absolutePath: fullPath,
|
|
4766
|
+
relativePath: relative(baseDir, fullPath),
|
|
4767
|
+
size: stats.size
|
|
4768
|
+
});
|
|
4769
|
+
}
|
|
4770
|
+
}
|
|
4771
|
+
} catch {
|
|
4772
|
+
}
|
|
4773
|
+
return files;
|
|
4774
|
+
}
|
|
4775
|
+
function formatBytes(bytes) {
|
|
4776
|
+
if (bytes === 0) return "0 B";
|
|
4777
|
+
const k = 1024;
|
|
4778
|
+
const sizes = ["B", "KB", "MB", "GB"];
|
|
4779
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
4780
|
+
return `${(bytes / Math.pow(k, i)).toFixed(1)} ${sizes[i]}`;
|
|
4781
|
+
}
|
|
4782
|
+
function getBucketKey(relativePath, prefix) {
|
|
4783
|
+
const key = relativePath.replace(/\\/g, "/");
|
|
4784
|
+
return prefix ? `${prefix}/${key}` : key;
|
|
4785
|
+
}
|
|
4786
|
+
|
|
4787
|
+
// src/lib/bucket/bulk.ts
|
|
4788
|
+
function collectBulkFiles(directory) {
|
|
4789
|
+
const gitignorePatterns = loadGitignorePatterns(directory);
|
|
4790
|
+
const files = collectFiles(directory, directory, gitignorePatterns);
|
|
4791
|
+
const totalSize = files.reduce((sum, file) => sum + file.size, 0);
|
|
4792
|
+
return { files, totalSize };
|
|
4793
|
+
}
|
|
4794
|
+
function outputDryRunResults(files, totalSize, prefix, json, raw) {
|
|
4795
|
+
if (json) {
|
|
4796
|
+
logger.json({
|
|
4797
|
+
files: files.map((f) => ({
|
|
4798
|
+
path: f.relativePath,
|
|
4799
|
+
key: getBucketKey(f.relativePath, prefix),
|
|
4800
|
+
size: f.size
|
|
4801
|
+
})),
|
|
4802
|
+
totalFiles: files.length,
|
|
4803
|
+
totalSize
|
|
4804
|
+
});
|
|
4805
|
+
return;
|
|
4806
|
+
}
|
|
4807
|
+
if (raw) {
|
|
4808
|
+
for (const file of files) {
|
|
4809
|
+
logger.raw(getBucketKey(file.relativePath, prefix));
|
|
4810
|
+
}
|
|
4811
|
+
return;
|
|
4812
|
+
}
|
|
4813
|
+
logger.remark(`Files to upload ${dim3(`[${files.length}]`)}`);
|
|
4814
|
+
logger.newLine();
|
|
4815
|
+
for (const file of files) {
|
|
4816
|
+
logger.data(getBucketKey(file.relativePath, prefix), formatBytes(file.size), 1);
|
|
4817
|
+
}
|
|
4818
|
+
logger.newLine();
|
|
4819
|
+
logger.data("Total", `${files.length} files (${formatBytes(totalSize)})`, 0);
|
|
4820
|
+
logger.newLine();
|
|
4821
|
+
}
|
|
4822
|
+
function outputUploadResults(uploaded, totalSize, environment, prefix, json, raw) {
|
|
4823
|
+
if (json) {
|
|
4824
|
+
logger.json({
|
|
4825
|
+
success: true,
|
|
4826
|
+
uploaded,
|
|
4827
|
+
totalSize,
|
|
4828
|
+
environment,
|
|
4829
|
+
prefix
|
|
4830
|
+
});
|
|
4831
|
+
return;
|
|
4832
|
+
}
|
|
4833
|
+
if (raw) {
|
|
4834
|
+
logger.raw(`Uploaded files`);
|
|
4835
|
+
return;
|
|
4836
|
+
}
|
|
4837
|
+
if (environment || prefix) {
|
|
4838
|
+
logger.newLine();
|
|
4839
|
+
if (environment) logger.data("Environment", environment, 1);
|
|
4840
|
+
if (prefix) logger.data("Prefix", prefix, 1);
|
|
4841
|
+
}
|
|
4842
|
+
logger.newLine();
|
|
4843
|
+
}
|
|
4844
|
+
async function uploadFilesRemote(files, gameSlug, prefix, uploadFn) {
|
|
4845
|
+
const totalSize = files.reduce((sum, f) => sum + f.size, 0);
|
|
4846
|
+
await runStep(
|
|
4847
|
+
`Uploading ${files.length} files ${dim3(`[${formatBytes(totalSize)}]`)}`,
|
|
4848
|
+
async () => {
|
|
4849
|
+
for (const file of files) {
|
|
4850
|
+
const fileBuffer = readFileSync4(file.absolutePath);
|
|
4851
|
+
const contentType = getContentType(file.absolutePath);
|
|
4852
|
+
const key = getBucketKey(file.relativePath, prefix);
|
|
4853
|
+
await uploadFn(gameSlug, key, fileBuffer, contentType);
|
|
4854
|
+
}
|
|
4855
|
+
},
|
|
4856
|
+
`Uploaded ${files.length} files ${dim3(`[${formatBytes(totalSize)}]`)}`
|
|
4857
|
+
);
|
|
4858
|
+
return files.length;
|
|
4859
|
+
}
|
|
4860
|
+
async function uploadFilesLocal(files, prefix, uploadFn) {
|
|
4861
|
+
const totalSize = files.reduce((sum, f) => sum + f.size, 0);
|
|
4862
|
+
await runStep(
|
|
4863
|
+
`Uploading ${files.length} files ${dim3(`[${formatBytes(totalSize)}]`)}`,
|
|
4864
|
+
async () => {
|
|
4865
|
+
for (const file of files) {
|
|
4866
|
+
const fileBuffer = readFileSync4(file.absolutePath);
|
|
4867
|
+
const contentType = getContentType(file.absolutePath);
|
|
4868
|
+
const key = getBucketKey(file.relativePath, prefix);
|
|
4869
|
+
await uploadFn(key, new Uint8Array(fileBuffer).buffer, contentType);
|
|
4870
|
+
}
|
|
4871
|
+
},
|
|
4872
|
+
`Uploaded ${files.length} files ${dim3(`[${formatBytes(totalSize)}]`)}`
|
|
4873
|
+
);
|
|
4874
|
+
return files.length;
|
|
4875
|
+
}
|
|
4876
|
+
|
|
4589
4877
|
// src/lib/index.ts
|
|
4590
4878
|
init_config3();
|
|
4591
4879
|
init_core();
|
|
4592
4880
|
|
|
4593
4881
|
// src/lib/db/path.ts
|
|
4594
4882
|
init_constants2();
|
|
4595
|
-
import { copyFileSync, existsSync as
|
|
4596
|
-
import { join as
|
|
4883
|
+
import { copyFileSync, existsSync as existsSync6, mkdirSync, readdirSync as readdirSync3, unlinkSync } from "fs";
|
|
4884
|
+
import { join as join7 } from "path";
|
|
4597
4885
|
import Database from "better-sqlite3";
|
|
4598
4886
|
var DB_DIRECTORY = CLI_DIRECTORIES.DATABASE;
|
|
4599
4887
|
var INITIAL_DB_NAME = CLI_FILES.INITIAL_DATABASE;
|
|
4600
4888
|
var ensureDirectoryExists = (dir) => {
|
|
4601
|
-
if (!
|
|
4889
|
+
if (!existsSync6(dir)) {
|
|
4602
4890
|
mkdirSync(dir, { recursive: true });
|
|
4603
4891
|
}
|
|
4604
4892
|
};
|
|
@@ -4607,79 +4895,150 @@ var createEmptyDatabase = (path2) => {
|
|
|
4607
4895
|
db.close();
|
|
4608
4896
|
};
|
|
4609
4897
|
var findMiniflareDatabase = (dbDir) => {
|
|
4610
|
-
const miniflareDir =
|
|
4611
|
-
if (!
|
|
4612
|
-
const sqliteFiles =
|
|
4898
|
+
const miniflareDir = join7(dbDir, MINIFLARE_D1_DIRECTORY);
|
|
4899
|
+
if (!existsSync6(miniflareDir)) return null;
|
|
4900
|
+
const sqliteFiles = readdirSync3(miniflareDir).filter((file) => file.endsWith(".sqlite"));
|
|
4613
4901
|
if (sqliteFiles.length === 0) return null;
|
|
4614
|
-
return
|
|
4902
|
+
return join7(miniflareDir, sqliteFiles[0]);
|
|
4615
4903
|
};
|
|
4616
4904
|
var migrateInitialDbToTarget = (initialPath, targetPath) => {
|
|
4617
|
-
if (!
|
|
4905
|
+
if (!existsSync6(initialPath)) return;
|
|
4618
4906
|
copyFileSync(initialPath, targetPath);
|
|
4619
4907
|
unlinkSync(initialPath);
|
|
4620
4908
|
};
|
|
4621
4909
|
function getDevDbPath() {
|
|
4622
|
-
const initialDbPath =
|
|
4910
|
+
const initialDbPath = join7(DB_DIRECTORY, INITIAL_DB_NAME);
|
|
4623
4911
|
ensureDirectoryExists(DB_DIRECTORY);
|
|
4624
4912
|
const miniflareDbPath = findMiniflareDatabase(DB_DIRECTORY);
|
|
4625
4913
|
if (miniflareDbPath) {
|
|
4626
4914
|
migrateInitialDbToTarget(initialDbPath, miniflareDbPath);
|
|
4627
4915
|
return miniflareDbPath;
|
|
4628
4916
|
}
|
|
4629
|
-
if (!
|
|
4917
|
+
if (!existsSync6(initialDbPath)) {
|
|
4630
4918
|
createEmptyDatabase(initialDbPath);
|
|
4631
4919
|
}
|
|
4632
4920
|
return initialDbPath;
|
|
4633
4921
|
}
|
|
4634
4922
|
|
|
4923
|
+
// src/lib/db/bundle-seed.ts
|
|
4924
|
+
async function bundleSeedWorker(seedFilePath, projectPath) {
|
|
4925
|
+
const esbuild2 = await import("esbuild");
|
|
4926
|
+
const entryCode = `
|
|
4927
|
+
import { seed } from '${seedFilePath}'
|
|
4928
|
+
|
|
4929
|
+
export default {
|
|
4930
|
+
async fetch(req, env, ctx) {
|
|
4931
|
+
try {
|
|
4932
|
+
// Create Hono-like context
|
|
4933
|
+
const c = { env, ctx, req }
|
|
4934
|
+
await seed(c)
|
|
4935
|
+
return Response.json({ success: true })
|
|
4936
|
+
} catch (error) {
|
|
4937
|
+
return Response.json({
|
|
4938
|
+
success: false,
|
|
4939
|
+
error: error instanceof Error ? error.message : String(error),
|
|
4940
|
+
stack: error instanceof Error ? error.stack : undefined,
|
|
4941
|
+
}, 500)
|
|
4942
|
+
}
|
|
4943
|
+
}
|
|
4944
|
+
}
|
|
4945
|
+
`;
|
|
4946
|
+
const buildConfig = {
|
|
4947
|
+
stdin: {
|
|
4948
|
+
contents: entryCode,
|
|
4949
|
+
resolveDir: projectPath,
|
|
4950
|
+
loader: "ts"
|
|
4951
|
+
},
|
|
4952
|
+
bundle: true,
|
|
4953
|
+
format: "esm",
|
|
4954
|
+
platform: "browser",
|
|
4955
|
+
target: "esnext",
|
|
4956
|
+
external: [],
|
|
4957
|
+
// Bundle everything for self-contained worker
|
|
4958
|
+
write: false,
|
|
4959
|
+
minify: false,
|
|
4960
|
+
sourcemap: false,
|
|
4961
|
+
logLevel: "error"
|
|
4962
|
+
};
|
|
4963
|
+
const result = await esbuild2.build(buildConfig);
|
|
4964
|
+
if (!result.outputFiles?.[0]) {
|
|
4965
|
+
throw new Error("Seed worker bundling failed: no output");
|
|
4966
|
+
}
|
|
4967
|
+
const code = result.outputFiles[0].text;
|
|
4968
|
+
return {
|
|
4969
|
+
code,
|
|
4970
|
+
size: code.length
|
|
4971
|
+
};
|
|
4972
|
+
}
|
|
4973
|
+
|
|
4635
4974
|
// src/lib/db/reset.ts
|
|
4636
|
-
|
|
4975
|
+
init_src();
|
|
4637
4976
|
init_package_manager();
|
|
4977
|
+
init_constants2();
|
|
4638
4978
|
init_core();
|
|
4639
4979
|
import { execSync as execSync2 } from "child_process";
|
|
4640
|
-
import
|
|
4641
|
-
|
|
4642
|
-
|
|
4643
|
-
const
|
|
4644
|
-
const
|
|
4645
|
-
|
|
4646
|
-
|
|
4647
|
-
const DROP_TABLE_SQL = (tableName) => `DROP TABLE IF EXISTS ${tableName}`;
|
|
4648
|
-
runStep(
|
|
4649
|
-
"Dropping all tables",
|
|
4980
|
+
import { rmSync as rmSync2 } from "fs";
|
|
4981
|
+
import { join as join8 } from "path";
|
|
4982
|
+
async function resetDatabase(workspace, mf, options = { debug: false }) {
|
|
4983
|
+
const { debug } = options;
|
|
4984
|
+
const dbDir = join8(workspace, CLI_DIRECTORIES.DATABASE);
|
|
4985
|
+
await runStep(
|
|
4986
|
+
"Resetting database...",
|
|
4650
4987
|
async () => {
|
|
4651
|
-
|
|
4652
|
-
|
|
4653
|
-
|
|
4654
|
-
|
|
4988
|
+
rmSync2(dbDir, { recursive: true, force: true });
|
|
4989
|
+
try {
|
|
4990
|
+
const d1 = await mf.getD1Database(CLOUDFLARE_BINDINGS.DB);
|
|
4991
|
+
await d1.exec("SELECT 1");
|
|
4992
|
+
} catch {
|
|
4993
|
+
logger.error("Database recreation failed");
|
|
4994
|
+
logger.newLine();
|
|
4995
|
+
process.exit(1);
|
|
4655
4996
|
}
|
|
4656
|
-
|
|
4997
|
+
const pm = getPackageManager();
|
|
4998
|
+
const pushCommand = getRunCommand(pm, "db:push");
|
|
4999
|
+
execSync2(pushCommand, {
|
|
5000
|
+
cwd: workspace,
|
|
5001
|
+
stdio: debug ? ["inherit", "inherit", "inherit"] : ["inherit", "ignore", "ignore"]
|
|
5002
|
+
});
|
|
4657
5003
|
},
|
|
4658
|
-
"
|
|
5004
|
+
"Database reset"
|
|
4659
5005
|
);
|
|
4660
|
-
|
|
4661
|
-
|
|
4662
|
-
|
|
4663
|
-
|
|
4664
|
-
|
|
4665
|
-
|
|
4666
|
-
|
|
4667
|
-
|
|
4668
|
-
|
|
4669
|
-
|
|
4670
|
-
|
|
4671
|
-
|
|
4672
|
-
|
|
5006
|
+
}
|
|
5007
|
+
|
|
5008
|
+
// src/lib/db/seed.ts
|
|
5009
|
+
init_src();
|
|
5010
|
+
init_constants2();
|
|
5011
|
+
init_core();
|
|
5012
|
+
async function importSeedModule(seedPath) {
|
|
5013
|
+
return await importTypescriptFile(seedPath);
|
|
5014
|
+
}
|
|
5015
|
+
async function executeSeedFile(seedFilePath, mf) {
|
|
5016
|
+
const d1 = await mf.getD1Database(CLOUDFLARE_BINDINGS.DB);
|
|
5017
|
+
const seedModule = await importSeedModule(seedFilePath);
|
|
5018
|
+
if (typeof seedModule.seed !== "function") {
|
|
5019
|
+
logger.error("Seed file must export a seed function");
|
|
5020
|
+
logger.newLine();
|
|
5021
|
+
logger.admonition("warning", "Invalid Seed File", [
|
|
5022
|
+
`Expected: \`export async function seed(c: Context) { ... }\``,
|
|
5023
|
+
`Found in: <${seedFilePath}>`
|
|
5024
|
+
]);
|
|
5025
|
+
logger.newLine();
|
|
4673
5026
|
process.exit(1);
|
|
4674
5027
|
}
|
|
5028
|
+
await runStep(
|
|
5029
|
+
"Seeding database...",
|
|
5030
|
+
async () => seedModule.seed?.({ env: { DB: d1 } }),
|
|
5031
|
+
"Database seeded successfully!"
|
|
5032
|
+
);
|
|
5033
|
+
logger.newLine();
|
|
4675
5034
|
}
|
|
4676
5035
|
|
|
4677
5036
|
// src/lib/deploy/backend.ts
|
|
4678
5037
|
init_src();
|
|
4679
5038
|
init_constants2();
|
|
4680
5039
|
init_core();
|
|
4681
|
-
import { existsSync as
|
|
4682
|
-
import { join as
|
|
5040
|
+
import { existsSync as existsSync14 } from "node:fs";
|
|
5041
|
+
import { join as join18 } from "node:path";
|
|
4683
5042
|
|
|
4684
5043
|
// src/lib/init/bucket.ts
|
|
4685
5044
|
function hasBucketSetup(config) {
|
|
@@ -4692,14 +5051,15 @@ init_slug();
|
|
|
4692
5051
|
init_core();
|
|
4693
5052
|
init_logger();
|
|
4694
5053
|
init_loader2();
|
|
4695
|
-
import { existsSync as
|
|
4696
|
-
import { join as
|
|
5054
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync2, readFileSync as readFileSync5, writeFileSync as writeFileSync2 } from "fs";
|
|
5055
|
+
import { join as join9 } from "path";
|
|
4697
5056
|
var drizzleConfigTemplate = loadTemplateString("database/drizzle-config.ts");
|
|
4698
5057
|
var dbSchemaUsersTemplate = loadTemplateString("database/db-schema-users.ts");
|
|
4699
5058
|
var dbSchemaScoresTemplate = loadTemplateString("database/db-schema-scores.ts");
|
|
4700
5059
|
var dbSchemaIndexTemplate = loadTemplateString("database/db-schema-index.ts");
|
|
4701
5060
|
var dbIndexTemplate = loadTemplateString("database/db-index.ts");
|
|
4702
5061
|
var dbTypesTemplate = loadTemplateString("database/db-types.ts");
|
|
5062
|
+
var dbSeedTemplate = loadTemplateString("database/db-seed.ts");
|
|
4703
5063
|
var packageTemplate = loadTemplateString("database/package.json");
|
|
4704
5064
|
async function scaffoldDatabaseSetup(options) {
|
|
4705
5065
|
const workspace = getWorkspace();
|
|
@@ -4707,25 +5067,27 @@ async function scaffoldDatabaseSetup(options) {
|
|
|
4707
5067
|
await runStep(
|
|
4708
5068
|
"Configuring database...",
|
|
4709
5069
|
async () => {
|
|
4710
|
-
const dbDir =
|
|
4711
|
-
const schemaDir =
|
|
4712
|
-
if (!
|
|
5070
|
+
const dbDir = join9(workspace, "db");
|
|
5071
|
+
const schemaDir = join9(dbDir, "schema");
|
|
5072
|
+
if (!existsSync7(dbDir)) {
|
|
4713
5073
|
mkdirSync2(dbDir, { recursive: true });
|
|
4714
5074
|
}
|
|
4715
|
-
if (!
|
|
5075
|
+
if (!existsSync7(schemaDir)) {
|
|
4716
5076
|
mkdirSync2(schemaDir, { recursive: true });
|
|
4717
5077
|
}
|
|
4718
|
-
const usersSchemaPath =
|
|
5078
|
+
const usersSchemaPath = join9(schemaDir, "users.ts");
|
|
4719
5079
|
writeFileSync2(usersSchemaPath, dbSchemaUsersTemplate);
|
|
4720
|
-
const scoresSchemaPath =
|
|
5080
|
+
const scoresSchemaPath = join9(schemaDir, "scores.ts");
|
|
4721
5081
|
writeFileSync2(scoresSchemaPath, dbSchemaScoresTemplate);
|
|
4722
|
-
const schemaIndexPath =
|
|
5082
|
+
const schemaIndexPath = join9(schemaDir, "index.ts");
|
|
4723
5083
|
writeFileSync2(schemaIndexPath, dbSchemaIndexTemplate);
|
|
4724
|
-
const dbIndexPath =
|
|
5084
|
+
const dbIndexPath = join9(dbDir, "index.ts");
|
|
4725
5085
|
writeFileSync2(dbIndexPath, dbIndexTemplate);
|
|
4726
|
-
const dbTypesPath =
|
|
5086
|
+
const dbTypesPath = join9(dbDir, "types.ts");
|
|
4727
5087
|
writeFileSync2(dbTypesPath, dbTypesTemplate);
|
|
4728
|
-
const
|
|
5088
|
+
const dbSeedPath = join9(dbDir, "seed.ts");
|
|
5089
|
+
writeFileSync2(dbSeedPath, dbSeedTemplate);
|
|
5090
|
+
const drizzleConfigPath = join9(workspace, "drizzle.config.ts");
|
|
4729
5091
|
writeFileSync2(drizzleConfigPath, drizzleConfigTemplate);
|
|
4730
5092
|
packagesUpdated = await setupPackageJson(workspace, options.gameName);
|
|
4731
5093
|
},
|
|
@@ -4734,7 +5096,7 @@ async function scaffoldDatabaseSetup(options) {
|
|
|
4734
5096
|
return packagesUpdated;
|
|
4735
5097
|
}
|
|
4736
5098
|
async function setupPackageJson(workspace, gameName) {
|
|
4737
|
-
const pkgPath =
|
|
5099
|
+
const pkgPath = join9(workspace, "package.json");
|
|
4738
5100
|
const dbDeps = {
|
|
4739
5101
|
"drizzle-orm": "^0.42.0",
|
|
4740
5102
|
"better-sqlite3": "^12.0.0"
|
|
@@ -4748,13 +5110,13 @@ async function setupPackageJson(workspace, gameName) {
|
|
|
4748
5110
|
"db:generate": "drizzle-kit generate",
|
|
4749
5111
|
"db:push": "drizzle-kit push",
|
|
4750
5112
|
"db:studio": "drizzle-kit studio",
|
|
4751
|
-
"db:seed": "
|
|
5113
|
+
"db:seed": "playcademy db seed"
|
|
4752
5114
|
};
|
|
4753
|
-
if (
|
|
5115
|
+
if (existsSync7(pkgPath)) {
|
|
4754
5116
|
await runStep(
|
|
4755
5117
|
"Updating package.json deps",
|
|
4756
5118
|
async () => {
|
|
4757
|
-
const existing = JSON.parse(
|
|
5119
|
+
const existing = JSON.parse(readFileSync5(pkgPath, "utf-8"));
|
|
4758
5120
|
existing.dependencies = { ...existing.dependencies, ...dbDeps };
|
|
4759
5121
|
existing.devDependencies = { ...existing.devDependencies, ...dbDevDeps };
|
|
4760
5122
|
existing.scripts = { ...existing.scripts, ...dbScripts };
|
|
@@ -4773,9 +5135,9 @@ async function setupPackageJson(workspace, gameName) {
|
|
|
4773
5135
|
}
|
|
4774
5136
|
function hasDatabaseSetup() {
|
|
4775
5137
|
const workspace = getWorkspace();
|
|
4776
|
-
const drizzleConfigPath =
|
|
4777
|
-
const drizzleConfigJsPath =
|
|
4778
|
-
return
|
|
5138
|
+
const drizzleConfigPath = join9(workspace, "drizzle.config.ts");
|
|
5139
|
+
const drizzleConfigJsPath = join9(workspace, "drizzle.config.js");
|
|
5140
|
+
return existsSync7(drizzleConfigPath) || existsSync7(drizzleConfigJsPath);
|
|
4779
5141
|
}
|
|
4780
5142
|
|
|
4781
5143
|
// src/lib/init/kv.ts
|
|
@@ -4912,8 +5274,8 @@ var integrationChangeDetectors = {
|
|
|
4912
5274
|
};
|
|
4913
5275
|
|
|
4914
5276
|
// src/lib/deploy/bundle.ts
|
|
4915
|
-
import { existsSync as
|
|
4916
|
-
import { join as
|
|
5277
|
+
import { existsSync as existsSync8 } from "fs";
|
|
5278
|
+
import { join as join11 } from "path";
|
|
4917
5279
|
|
|
4918
5280
|
// ../edge-play/src/entry.ts
|
|
4919
5281
|
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 { registerCors, registerEnvSetup, registerSdkInit } 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/**\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)\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\nexport default app\n";
|
|
@@ -4936,6 +5298,9 @@ var isDevelopment = () => {
|
|
|
4936
5298
|
var isInteractiveTTY = () => {
|
|
4937
5299
|
return typeof process !== "undefined" && Boolean(process.stdout && process.stdout.isTTY);
|
|
4938
5300
|
};
|
|
5301
|
+
var isSilent = () => {
|
|
5302
|
+
return typeof process !== "undefined" && process.env.LOG_SILENT === "true";
|
|
5303
|
+
};
|
|
4939
5304
|
var detectOutputFormat = () => {
|
|
4940
5305
|
if (isBrowser()) {
|
|
4941
5306
|
return "browser";
|
|
@@ -5056,6 +5421,7 @@ var getMinimumLogLevel = () => {
|
|
|
5056
5421
|
return isProduction() ? "info" : "debug";
|
|
5057
5422
|
};
|
|
5058
5423
|
var shouldLog = (level) => {
|
|
5424
|
+
if (isSilent()) return false;
|
|
5059
5425
|
const minLevel = getMinimumLogLevel();
|
|
5060
5426
|
return levelPriority[level] >= levelPriority[minLevel];
|
|
5061
5427
|
};
|
|
@@ -5176,7 +5542,7 @@ init_file_loader();
|
|
|
5176
5542
|
init_core();
|
|
5177
5543
|
import { mkdir as mkdir2, writeFile as writeFile2 } from "fs/promises";
|
|
5178
5544
|
import { tmpdir as tmpdir2 } from "os";
|
|
5179
|
-
import { join as
|
|
5545
|
+
import { join as join10, relative as relative2 } from "path";
|
|
5180
5546
|
|
|
5181
5547
|
// src/lib/deploy/hash.ts
|
|
5182
5548
|
init_file_loader();
|
|
@@ -5224,8 +5590,8 @@ async function discoverRoutes(apiDir) {
|
|
|
5224
5590
|
const routes = await Promise.all(
|
|
5225
5591
|
files.map(async (file) => {
|
|
5226
5592
|
const routePath = filePathToRoutePath(file);
|
|
5227
|
-
const absolutePath =
|
|
5228
|
-
const relativePath =
|
|
5593
|
+
const absolutePath = join10(apiDir, file);
|
|
5594
|
+
const relativePath = relative2(getWorkspace(), absolutePath);
|
|
5229
5595
|
const methods = await detectExportedMethods(absolutePath);
|
|
5230
5596
|
return {
|
|
5231
5597
|
path: routePath,
|
|
@@ -5285,10 +5651,10 @@ async function transpileRoute(filePath) {
|
|
|
5285
5651
|
if (!result.outputFiles?.[0]) {
|
|
5286
5652
|
throw new Error("Transpilation failed: no output");
|
|
5287
5653
|
}
|
|
5288
|
-
const tempDir =
|
|
5654
|
+
const tempDir = join10(tmpdir2(), "playcademy-dev");
|
|
5289
5655
|
await mkdir2(tempDir, { recursive: true });
|
|
5290
5656
|
const hash = hashContent(filePath).slice(0, 12);
|
|
5291
|
-
const jsPath =
|
|
5657
|
+
const jsPath = join10(tempDir, `${hash}.mjs`);
|
|
5292
5658
|
await writeFile2(jsPath, result.outputFiles[0].text);
|
|
5293
5659
|
return jsPath;
|
|
5294
5660
|
}
|
|
@@ -5316,7 +5682,7 @@ async function discoverCustomRoutes(config) {
|
|
|
5316
5682
|
const workspace = getWorkspace();
|
|
5317
5683
|
const customRoutesConfig = config.integrations?.customRoutes;
|
|
5318
5684
|
const customRoutesDir = typeof customRoutesConfig === "object" && customRoutesConfig.directory || DEFAULT_API_ROUTES_DIRECTORY;
|
|
5319
|
-
const customRoutes = await discoverRoutes(
|
|
5685
|
+
const customRoutes = await discoverRoutes(join11(workspace, customRoutesDir));
|
|
5320
5686
|
const customRouteData = customRoutes.map((r) => ({
|
|
5321
5687
|
path: r.path,
|
|
5322
5688
|
file: r.file,
|
|
@@ -5328,15 +5694,15 @@ async function discoverCustomRoutes(config) {
|
|
|
5328
5694
|
function resolveEmbeddedSourcePaths() {
|
|
5329
5695
|
const workspace = getWorkspace();
|
|
5330
5696
|
const distDir = new URL(".", import.meta.url).pathname;
|
|
5331
|
-
const embeddedEdgeSrc =
|
|
5332
|
-
const isBuiltPackage =
|
|
5697
|
+
const embeddedEdgeSrc = join11(distDir, "edge-play", "src");
|
|
5698
|
+
const isBuiltPackage = existsSync8(embeddedEdgeSrc);
|
|
5333
5699
|
const monorepoRoot = getMonorepoRoot();
|
|
5334
|
-
const monorepoEdgeSrc =
|
|
5700
|
+
const monorepoEdgeSrc = join11(monorepoRoot, "packages/edge-play/src");
|
|
5335
5701
|
const edgePlaySrc = isBuiltPackage ? embeddedEdgeSrc : monorepoEdgeSrc;
|
|
5336
|
-
const cliPackageRoot = isBuiltPackage ?
|
|
5337
|
-
const cliNodeModules = isBuiltPackage ?
|
|
5338
|
-
const workspaceNodeModules =
|
|
5339
|
-
const constantsEntry = isBuiltPackage ?
|
|
5702
|
+
const cliPackageRoot = isBuiltPackage ? join11(distDir, "../../..") : join11(monorepoRoot, "packages/cli");
|
|
5703
|
+
const cliNodeModules = isBuiltPackage ? join11(cliPackageRoot, "node_modules") : monorepoRoot;
|
|
5704
|
+
const workspaceNodeModules = join11(workspace, "node_modules");
|
|
5705
|
+
const constantsEntry = isBuiltPackage ? join11(embeddedEdgeSrc, "..", "..", "constants", "src", "index.ts") : join11(monorepoRoot, "packages", "constants", "src", "index.ts");
|
|
5340
5706
|
return {
|
|
5341
5707
|
isBuiltPackage,
|
|
5342
5708
|
edgePlaySrc,
|
|
@@ -5396,16 +5762,16 @@ function createEsbuildConfig(entryCode, paths, bundleConfig, customRoutesDir, op
|
|
|
5396
5762
|
// │ Example: import * as route from '@game-api/hello.ts' │
|
|
5397
5763
|
// │ Resolves to: /user-project/server/api/hello.ts │
|
|
5398
5764
|
// └─────────────────────────────────────────────────────────────────┘
|
|
5399
|
-
"@game-api":
|
|
5765
|
+
"@game-api": join11(workspace, customRoutesDir),
|
|
5400
5766
|
// ┌─ Node.js polyfills for Cloudflare Workers ──────────────────────┐
|
|
5401
5767
|
// │ Workers don't have fs, path, os, etc. Redirect to polyfills │
|
|
5402
5768
|
// │ that throw helpful errors if user code tries to use them. │
|
|
5403
5769
|
// └─────────────────────────────────────────────────────────────────┘
|
|
5404
|
-
fs:
|
|
5405
|
-
"fs/promises":
|
|
5406
|
-
path:
|
|
5407
|
-
os:
|
|
5408
|
-
process:
|
|
5770
|
+
fs: join11(edgePlaySrc, "polyfills.js"),
|
|
5771
|
+
"fs/promises": join11(edgePlaySrc, "polyfills.js"),
|
|
5772
|
+
path: join11(edgePlaySrc, "polyfills.js"),
|
|
5773
|
+
os: join11(edgePlaySrc, "polyfills.js"),
|
|
5774
|
+
process: join11(edgePlaySrc, "polyfills.js")
|
|
5409
5775
|
},
|
|
5410
5776
|
// ──── Build Plugins ────
|
|
5411
5777
|
plugins: [textLoaderPlugin()],
|
|
@@ -5468,10 +5834,12 @@ function generateEntryCode(customRoutes, customRoutesDir) {
|
|
|
5468
5834
|
}
|
|
5469
5835
|
|
|
5470
5836
|
// src/lib/deploy/schema.ts
|
|
5837
|
+
init_constants2();
|
|
5838
|
+
init_config3();
|
|
5471
5839
|
init_core();
|
|
5472
|
-
import { existsSync as
|
|
5840
|
+
import { existsSync as existsSync13 } from "fs";
|
|
5473
5841
|
import { createRequire } from "module";
|
|
5474
|
-
import { join as
|
|
5842
|
+
import { join as join17 } from "path";
|
|
5475
5843
|
|
|
5476
5844
|
// src/lib/init/prompts.ts
|
|
5477
5845
|
init_constants3();
|
|
@@ -5483,8 +5851,8 @@ import { bold as bold3, cyan as cyan2 } from "colorette";
|
|
|
5483
5851
|
init_constants2();
|
|
5484
5852
|
init_core();
|
|
5485
5853
|
init_loader2();
|
|
5486
|
-
import { existsSync as
|
|
5487
|
-
import { join as
|
|
5854
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync3, writeFileSync as writeFileSync3 } from "fs";
|
|
5855
|
+
import { join as join12, resolve as resolve6 } from "path";
|
|
5488
5856
|
var sampleCustomRouteTemplate = loadTemplateString("api/sample-custom.ts");
|
|
5489
5857
|
var sampleDatabaseRouteTemplate = loadTemplateString("api/sample-database.ts");
|
|
5490
5858
|
var sampleKvRouteTemplate = loadTemplateString("api/sample-kv.ts");
|
|
@@ -5492,31 +5860,31 @@ var sampleBucketRouteTemplate = loadTemplateString("api/sample-bucket.ts");
|
|
|
5492
5860
|
var playcademyGitignoreTemplate = loadTemplateString("playcademy-gitignore");
|
|
5493
5861
|
async function scaffoldApiDirectory(apiDirectory, sampleRoutes) {
|
|
5494
5862
|
const apiPath = resolve6(getWorkspace(), apiDirectory);
|
|
5495
|
-
const samplePath =
|
|
5496
|
-
if (!
|
|
5863
|
+
const samplePath = join12(apiPath, "sample");
|
|
5864
|
+
if (!existsSync9(apiPath)) {
|
|
5497
5865
|
mkdirSync3(apiPath, { recursive: true });
|
|
5498
5866
|
}
|
|
5499
|
-
if (!
|
|
5867
|
+
if (!existsSync9(samplePath)) {
|
|
5500
5868
|
mkdirSync3(samplePath, { recursive: true });
|
|
5501
5869
|
}
|
|
5502
5870
|
for (const route of sampleRoutes) {
|
|
5503
|
-
writeFileSync3(
|
|
5871
|
+
writeFileSync3(join12(samplePath, route.filename), route.template, "utf-8");
|
|
5504
5872
|
}
|
|
5505
5873
|
}
|
|
5506
5874
|
function validateApiDirectoryDoesNotExist(value) {
|
|
5507
5875
|
const dirPath = resolve6(getWorkspace(), value.trim());
|
|
5508
|
-
if (
|
|
5876
|
+
if (existsSync9(dirPath)) {
|
|
5509
5877
|
return `Directory "${value.trim()}" already exists. Please choose a different name or remove the existing directory.`;
|
|
5510
5878
|
}
|
|
5511
5879
|
return true;
|
|
5512
5880
|
}
|
|
5513
5881
|
function ensurePlaycademyGitignore() {
|
|
5514
5882
|
const workspace = getWorkspace();
|
|
5515
|
-
const playcademyDir =
|
|
5516
|
-
if (!
|
|
5883
|
+
const playcademyDir = join12(workspace, CLI_DIRECTORIES.WORKSPACE);
|
|
5884
|
+
if (!existsSync9(playcademyDir)) {
|
|
5517
5885
|
mkdirSync3(playcademyDir, { recursive: true });
|
|
5518
5886
|
}
|
|
5519
|
-
const gitignorePath =
|
|
5887
|
+
const gitignorePath = join12(playcademyDir, ".gitignore");
|
|
5520
5888
|
writeFileSync3(gitignorePath, playcademyGitignoreTemplate);
|
|
5521
5889
|
}
|
|
5522
5890
|
async function scaffoldIntegrations(gameName, options) {
|
|
@@ -5772,14 +6140,14 @@ init_loader();
|
|
|
5772
6140
|
init_core();
|
|
5773
6141
|
import { execSync as execSync3 } from "child_process";
|
|
5774
6142
|
import { writeFileSync as writeFileSync5 } from "fs";
|
|
5775
|
-
import { dirname as dirname4, join as
|
|
6143
|
+
import { dirname as dirname4, join as join15 } from "path";
|
|
5776
6144
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
5777
6145
|
|
|
5778
6146
|
// src/lib/secrets/env.ts
|
|
5779
6147
|
init_file_loader();
|
|
5780
6148
|
init_constants2();
|
|
5781
|
-
import { existsSync as
|
|
5782
|
-
import { join as
|
|
6149
|
+
import { existsSync as existsSync10 } from "fs";
|
|
6150
|
+
import { join as join13 } from "path";
|
|
5783
6151
|
function parseEnvFile(contents) {
|
|
5784
6152
|
const secrets = {};
|
|
5785
6153
|
for (const line of contents.split("\n")) {
|
|
@@ -5815,10 +6183,10 @@ async function readEnvFile(workspace) {
|
|
|
5815
6183
|
return secrets;
|
|
5816
6184
|
}
|
|
5817
6185
|
function getLoadedEnvFiles(workspace) {
|
|
5818
|
-
return ENV_FILES.filter((filename) =>
|
|
6186
|
+
return ENV_FILES.filter((filename) => existsSync10(join13(workspace, filename)));
|
|
5819
6187
|
}
|
|
5820
6188
|
function hasEnvFile(workspace) {
|
|
5821
|
-
return ENV_FILES.some((filename) =>
|
|
6189
|
+
return ENV_FILES.some((filename) => existsSync10(join13(workspace, filename)));
|
|
5822
6190
|
}
|
|
5823
6191
|
|
|
5824
6192
|
// src/lib/init/types.ts
|
|
@@ -5827,8 +6195,8 @@ init_loader2();
|
|
|
5827
6195
|
// src/lib/init/tsconfig.ts
|
|
5828
6196
|
init_file_loader();
|
|
5829
6197
|
init_constants2();
|
|
5830
|
-
import { existsSync as
|
|
5831
|
-
import { join as
|
|
6198
|
+
import { existsSync as existsSync11, readFileSync as readFileSync6, writeFileSync as writeFileSync4 } from "fs";
|
|
6199
|
+
import { join as join14 } from "path";
|
|
5832
6200
|
function hasPlaycademyEnv(config) {
|
|
5833
6201
|
return config.include?.includes("playcademy-env.d.ts") ?? false;
|
|
5834
6202
|
}
|
|
@@ -5885,8 +6253,8 @@ function addToIncludeArrayPreservingComments(content) {
|
|
|
5885
6253
|
}
|
|
5886
6254
|
async function ensureTsconfigIncludes(workspace) {
|
|
5887
6255
|
for (const filename of TSCONFIG_FILES) {
|
|
5888
|
-
const configPath =
|
|
5889
|
-
if (!
|
|
6256
|
+
const configPath = join14(workspace, filename);
|
|
6257
|
+
if (!existsSync11(configPath)) {
|
|
5890
6258
|
continue;
|
|
5891
6259
|
}
|
|
5892
6260
|
try {
|
|
@@ -5902,7 +6270,7 @@ async function ensureTsconfigIncludes(workspace) {
|
|
|
5902
6270
|
return filename;
|
|
5903
6271
|
}
|
|
5904
6272
|
try {
|
|
5905
|
-
const rawContent =
|
|
6273
|
+
const rawContent = readFileSync6(configPath, "utf-8");
|
|
5906
6274
|
const updatedContent = addToIncludeArrayPreservingComments(rawContent);
|
|
5907
6275
|
if (updatedContent && updatedContent !== rawContent) {
|
|
5908
6276
|
writeFileSync4(configPath, updatedContent);
|
|
@@ -5935,8 +6303,8 @@ function hasAnyBackend(features) {
|
|
|
5935
6303
|
return Object.values(features).some(Boolean);
|
|
5936
6304
|
}
|
|
5937
6305
|
async function setupPlaycademyDependencies(workspace) {
|
|
5938
|
-
const playcademyDir =
|
|
5939
|
-
const playcademyPkgPath =
|
|
6306
|
+
const playcademyDir = join15(workspace, CLI_DIRECTORIES.WORKSPACE);
|
|
6307
|
+
const playcademyPkgPath = join15(playcademyDir, "package.json");
|
|
5940
6308
|
const __dirname2 = dirname4(fileURLToPath2(import.meta.url));
|
|
5941
6309
|
const cliPkg = await loadPackageJson({ cwd: __dirname2, searchUp: true, required: true });
|
|
5942
6310
|
const workersTypesVersion = cliPkg?.devDependencies?.["@cloudflare/workers-types"] || "latest";
|
|
@@ -6006,7 +6374,7 @@ async function ensurePlaycademyTypes(options = {}) {
|
|
|
6006
6374
|
const secretsStr = await generateSecretsTypeString(workspace, verbose);
|
|
6007
6375
|
let envContent = playcademyEnvTemplate.replace("{{BINDINGS}}", bindingsStr);
|
|
6008
6376
|
envContent = envContent.replace("{{SECRETS}}", secretsStr);
|
|
6009
|
-
const envPath =
|
|
6377
|
+
const envPath = join15(workspace, "playcademy-env.d.ts");
|
|
6010
6378
|
writeFileSync5(envPath, envContent);
|
|
6011
6379
|
if (verbose) {
|
|
6012
6380
|
logger.success(`Generated <playcademy-env.d.ts>`);
|
|
@@ -6026,19 +6394,16 @@ async function ensurePlaycademyTypes(options = {}) {
|
|
|
6026
6394
|
// src/lib/init/gitignore.ts
|
|
6027
6395
|
init_core();
|
|
6028
6396
|
init_loader2();
|
|
6029
|
-
import { existsSync as
|
|
6030
|
-
import { join as
|
|
6397
|
+
import { existsSync as existsSync12, readFileSync as readFileSync7, writeFileSync as writeFileSync6 } from "fs";
|
|
6398
|
+
import { join as join16 } from "path";
|
|
6031
6399
|
var rootGitignoreTemplate = loadTemplateString("gitignore");
|
|
6032
|
-
function normalizeGitignoreEntry(entry) {
|
|
6033
|
-
return entry.replace(/^\/+/, "").replace(/\/+$/, "");
|
|
6034
|
-
}
|
|
6035
6400
|
function ensureRootGitignore(workspace = getWorkspace()) {
|
|
6036
|
-
const gitignorePath =
|
|
6037
|
-
if (!
|
|
6401
|
+
const gitignorePath = join16(workspace, ".gitignore");
|
|
6402
|
+
if (!existsSync12(gitignorePath)) {
|
|
6038
6403
|
writeFileSync6(gitignorePath, rootGitignoreTemplate);
|
|
6039
6404
|
return;
|
|
6040
6405
|
}
|
|
6041
|
-
const existingContent =
|
|
6406
|
+
const existingContent = readFileSync7(gitignorePath, "utf-8");
|
|
6042
6407
|
const existingNormalized = new Set(
|
|
6043
6408
|
existingContent.split("\n").map((line) => line.trim()).filter((line) => line && !line.startsWith("#")).map(normalizeGitignoreEntry)
|
|
6044
6409
|
);
|
|
@@ -6059,6 +6424,18 @@ function ensureRootGitignore(workspace = getWorkspace()) {
|
|
|
6059
6424
|
}
|
|
6060
6425
|
|
|
6061
6426
|
// src/lib/deploy/schema.ts
|
|
6427
|
+
async function getDatabaseDirectory() {
|
|
6428
|
+
try {
|
|
6429
|
+
const config = await loadConfig();
|
|
6430
|
+
const dbIntegration = config.integrations?.database;
|
|
6431
|
+
if (!dbIntegration || dbIntegration === true) {
|
|
6432
|
+
return DEFAULT_DATABASE_DIRECTORY;
|
|
6433
|
+
}
|
|
6434
|
+
return dbIntegration.directory ?? DEFAULT_DATABASE_DIRECTORY;
|
|
6435
|
+
} catch {
|
|
6436
|
+
return DEFAULT_DATABASE_DIRECTORY;
|
|
6437
|
+
}
|
|
6438
|
+
}
|
|
6062
6439
|
function getDrizzleKitApiExports() {
|
|
6063
6440
|
const require2 = createRequire(import.meta.url);
|
|
6064
6441
|
const drizzleKitApi = require2("drizzle-kit/api");
|
|
@@ -6073,8 +6450,9 @@ async function getSchemaInfo(previousSchemaSnapshot) {
|
|
|
6073
6450
|
if (!hasDatabaseSetup()) {
|
|
6074
6451
|
return null;
|
|
6075
6452
|
}
|
|
6076
|
-
const
|
|
6077
|
-
|
|
6453
|
+
const dbDirectory = await getDatabaseDirectory();
|
|
6454
|
+
const schemaPath = join17(workspace, dbDirectory, SCHEMA_SUBDIRECTORY, SCHEMA_INDEX_FILE);
|
|
6455
|
+
if (!existsSync13(schemaPath)) {
|
|
6078
6456
|
return null;
|
|
6079
6457
|
}
|
|
6080
6458
|
try {
|
|
@@ -6157,11 +6535,11 @@ var CUSTOM_ROUTES_EXTENSIONS_WITH_DOT = [".ts", ".js", ".mjs", ".cjs"];
|
|
|
6157
6535
|
function getCustomRoutesDirectory(projectPath, config) {
|
|
6158
6536
|
const customRoutes = config?.integrations?.customRoutes;
|
|
6159
6537
|
const customRoutesDir = typeof customRoutes === "object" && customRoutes.directory || DEFAULT_API_ROUTES_DIRECTORY;
|
|
6160
|
-
return
|
|
6538
|
+
return join18(projectPath, customRoutesDir);
|
|
6161
6539
|
}
|
|
6162
6540
|
function hasLocalCustomRoutes(projectPath, config) {
|
|
6163
6541
|
const customRoutesDir = getCustomRoutesDirectory(projectPath, config);
|
|
6164
|
-
return
|
|
6542
|
+
return existsSync14(customRoutesDir);
|
|
6165
6543
|
}
|
|
6166
6544
|
async function getCustomRoutesHash(projectPath, config) {
|
|
6167
6545
|
const customRoutesDir = getCustomRoutesDirectory(projectPath, config);
|
|
@@ -6169,16 +6547,16 @@ async function getCustomRoutesHash(projectPath, config) {
|
|
|
6169
6547
|
}
|
|
6170
6548
|
async function getCustomRoutesSize(projectPath, config) {
|
|
6171
6549
|
const { stat: stat3, readdir } = await import("node:fs/promises");
|
|
6172
|
-
const { join:
|
|
6550
|
+
const { join: join41 } = await import("node:path");
|
|
6173
6551
|
const customRoutesDir = getCustomRoutesDirectory(projectPath, config);
|
|
6174
|
-
if (!
|
|
6552
|
+
if (!existsSync14(customRoutesDir)) {
|
|
6175
6553
|
return null;
|
|
6176
6554
|
}
|
|
6177
6555
|
let totalSize = 0;
|
|
6178
6556
|
async function calculateDirSize(dir) {
|
|
6179
6557
|
const entries = await readdir(dir, { withFileTypes: true });
|
|
6180
6558
|
for (const entry of entries) {
|
|
6181
|
-
const fullPath =
|
|
6559
|
+
const fullPath = join41(dir, entry.name);
|
|
6182
6560
|
if (entry.isDirectory()) {
|
|
6183
6561
|
await calculateDirSize(fullPath);
|
|
6184
6562
|
} else if (entry.isFile()) {
|
|
@@ -6372,7 +6750,7 @@ async function loadDeployConfig(configPath) {
|
|
|
6372
6750
|
// src/lib/deploy/diff.ts
|
|
6373
6751
|
init_string();
|
|
6374
6752
|
init_logger();
|
|
6375
|
-
import { dim as
|
|
6753
|
+
import { dim as dim4, green as green2, red as red2 } from "colorette";
|
|
6376
6754
|
function calculateConfigDiff(existingGame, newConfig) {
|
|
6377
6755
|
const diff = {};
|
|
6378
6756
|
if (existingGame.displayName !== newConfig.displayName) {
|
|
@@ -6489,7 +6867,7 @@ function displayDeploymentDiff(options) {
|
|
|
6489
6867
|
const oldSize = formatSize(previousSize);
|
|
6490
6868
|
const newSize = formatSize(currentSize);
|
|
6491
6869
|
const maxWidth = Math.max(oldSize.length, newSize.length);
|
|
6492
|
-
const delta =
|
|
6870
|
+
const delta = dim4(`(${formatDelta(currentSize - previousSize)})`);
|
|
6493
6871
|
buildInfo = `${red2(oldSize.padEnd(maxWidth))} \u2192 ${green2(newSize.padEnd(maxWidth))} ${delta}`;
|
|
6494
6872
|
} else if (currentSize !== void 0) {
|
|
6495
6873
|
buildInfo = green2(formatSize(currentSize));
|
|
@@ -6509,7 +6887,7 @@ function displayDeploymentDiff(options) {
|
|
|
6509
6887
|
const oldSize = formatSize(previousSize);
|
|
6510
6888
|
const newSize = formatSize(currentSize);
|
|
6511
6889
|
const maxWidth = Math.max(oldSize.length, newSize.length);
|
|
6512
|
-
const delta =
|
|
6890
|
+
const delta = dim4(`(${formatDelta(currentSize - previousSize)})`);
|
|
6513
6891
|
routesInfo = `${red2(oldSize.padEnd(maxWidth))} \u2192 ${green2(newSize.padEnd(maxWidth))} ${delta}`;
|
|
6514
6892
|
} else if (currentSize !== void 0) {
|
|
6515
6893
|
routesInfo = green2(formatSize(currentSize));
|
|
@@ -6523,12 +6901,12 @@ function displayDeploymentDiff(options) {
|
|
|
6523
6901
|
const currentSize = backend?.currentBundleSize;
|
|
6524
6902
|
let bundleInfo;
|
|
6525
6903
|
if (forceBackend && !backendChanged) {
|
|
6526
|
-
bundleInfo =
|
|
6904
|
+
bundleInfo = dim4("(forced)");
|
|
6527
6905
|
} else if (previousSize !== void 0 && currentSize !== void 0) {
|
|
6528
6906
|
const oldSize = formatSize(previousSize);
|
|
6529
6907
|
const newSize = formatSize(currentSize);
|
|
6530
6908
|
const maxWidth = Math.max(oldSize.length, newSize.length);
|
|
6531
|
-
const delta =
|
|
6909
|
+
const delta = dim4(`(${formatDelta(currentSize - previousSize)})`);
|
|
6532
6910
|
bundleInfo = `${red2(oldSize.padEnd(maxWidth))} \u2192 ${green2(newSize.padEnd(maxWidth))} ${delta}`;
|
|
6533
6911
|
} else if (currentSize !== void 0) {
|
|
6534
6912
|
bundleInfo = green2(formatSize(currentSize));
|
|
@@ -6590,19 +6968,19 @@ init_context();
|
|
|
6590
6968
|
init_logger();
|
|
6591
6969
|
import { stat } from "node:fs/promises";
|
|
6592
6970
|
import { confirm as confirm2, input as input2, select as select2 } from "@inquirer/prompts";
|
|
6593
|
-
import { dim as
|
|
6971
|
+
import { dim as dim5 } from "colorette";
|
|
6594
6972
|
|
|
6595
6973
|
// src/lib/deploy/build-discovery.ts
|
|
6596
6974
|
init_file_loader();
|
|
6597
6975
|
init_constants2();
|
|
6598
6976
|
init_core();
|
|
6599
|
-
import { join as
|
|
6977
|
+
import { join as join19, relative as relative3 } from "path";
|
|
6600
6978
|
function findSingleBuildZip() {
|
|
6601
6979
|
const workspace = getWorkspace();
|
|
6602
|
-
const playcademyDir =
|
|
6980
|
+
const playcademyDir = join19(workspace, CLI_DIRECTORIES.WORKSPACE);
|
|
6603
6981
|
const zipFiles = findFilesByExtension(playcademyDir, "zip");
|
|
6604
6982
|
if (zipFiles.length === 1) {
|
|
6605
|
-
return zipFiles[0] ?
|
|
6983
|
+
return zipFiles[0] ? relative3(workspace, zipFiles[0]) : null;
|
|
6606
6984
|
}
|
|
6607
6985
|
return null;
|
|
6608
6986
|
}
|
|
@@ -6635,14 +7013,14 @@ function hasOptionalFieldsMissing(missing) {
|
|
|
6635
7013
|
|
|
6636
7014
|
// src/lib/deploy/validate.ts
|
|
6637
7015
|
init_logger();
|
|
6638
|
-
import { existsSync as
|
|
7016
|
+
import { existsSync as existsSync15 } from "fs";
|
|
6639
7017
|
import { resolve as resolve7 } from "path";
|
|
6640
7018
|
function validateBuildPath(path2) {
|
|
6641
7019
|
if (!path2.trim()) {
|
|
6642
7020
|
return "Build path is required";
|
|
6643
7021
|
}
|
|
6644
7022
|
const resolvedPath = resolve7(path2.trim());
|
|
6645
|
-
if (!
|
|
7023
|
+
if (!existsSync15(resolvedPath)) {
|
|
6646
7024
|
return `Build path not found: ${path2.trim()}`;
|
|
6647
7025
|
}
|
|
6648
7026
|
return true;
|
|
@@ -6740,8 +7118,8 @@ async function promptForMissingConfig(context2) {
|
|
|
6740
7118
|
const gameType = await select2({
|
|
6741
7119
|
message: "Game type:",
|
|
6742
7120
|
choices: [
|
|
6743
|
-
{ value: "hosted", name: `Hosted ${
|
|
6744
|
-
{ value: "external", name: `External ${
|
|
7121
|
+
{ value: "hosted", name: `Hosted ${dim5("[Upload a game build]")}` },
|
|
7122
|
+
{ value: "external", name: `External ${dim5("[Link to an external URL]")}` }
|
|
6745
7123
|
]
|
|
6746
7124
|
});
|
|
6747
7125
|
config.gameType = gameType;
|
|
@@ -7449,22 +7827,22 @@ init_context();
|
|
|
7449
7827
|
|
|
7450
7828
|
// src/lib/games/storage.ts
|
|
7451
7829
|
init_constants2();
|
|
7452
|
-
import { existsSync as
|
|
7830
|
+
import { existsSync as existsSync16 } from "node:fs";
|
|
7453
7831
|
import { mkdir as mkdir3, readFile as readFile3, writeFile as writeFile3 } from "node:fs/promises";
|
|
7454
7832
|
import { homedir as homedir2 } from "node:os";
|
|
7455
|
-
import { join as
|
|
7833
|
+
import { join as join20 } from "node:path";
|
|
7456
7834
|
function getGamesStorePath() {
|
|
7457
|
-
return
|
|
7835
|
+
return join20(homedir2(), CLI_USER_DIRECTORIES.CONFIG, CLI_FILES.GAMES_STORE);
|
|
7458
7836
|
}
|
|
7459
7837
|
async function ensureConfigDir() {
|
|
7460
|
-
const configDir =
|
|
7838
|
+
const configDir = join20(homedir2(), CLI_USER_DIRECTORIES.CONFIG);
|
|
7461
7839
|
await mkdir3(configDir, { recursive: true });
|
|
7462
7840
|
}
|
|
7463
7841
|
async function loadGameStore() {
|
|
7464
7842
|
try {
|
|
7465
7843
|
await ensureConfigDir();
|
|
7466
7844
|
const storePath = getGamesStorePath();
|
|
7467
|
-
if (
|
|
7845
|
+
if (existsSync16(storePath)) {
|
|
7468
7846
|
const content = await readFile3(storePath, "utf-8");
|
|
7469
7847
|
return JSON.parse(content);
|
|
7470
7848
|
}
|
|
@@ -7733,7 +8111,7 @@ async function calculateDeploymentPlan(context2, changes) {
|
|
|
7733
8111
|
// src/lib/deploy/steps.ts
|
|
7734
8112
|
init_src();
|
|
7735
8113
|
init_logger();
|
|
7736
|
-
import { existsSync as
|
|
8114
|
+
import { existsSync as existsSync17 } from "fs";
|
|
7737
8115
|
import { readFile as readFile4 } from "fs/promises";
|
|
7738
8116
|
import { basename as basename2, resolve as resolve8 } from "path";
|
|
7739
8117
|
function prepareGameMetadata(config) {
|
|
@@ -7753,7 +8131,7 @@ function prepareGameMetadata(config) {
|
|
|
7753
8131
|
}
|
|
7754
8132
|
async function prepareBuildFile(buildPath) {
|
|
7755
8133
|
const resolvedPath = resolve8(buildPath);
|
|
7756
|
-
if (resolvedPath.endsWith(".zip") &&
|
|
8134
|
+
if (resolvedPath.endsWith(".zip") && existsSync17(resolvedPath)) {
|
|
7757
8135
|
const buffer = await readFile4(resolvedPath);
|
|
7758
8136
|
const uint8Array = new Uint8Array(buffer);
|
|
7759
8137
|
const blob = new Blob([uint8Array], { type: "application/zip" });
|
|
@@ -7971,20 +8349,20 @@ async function saveDeploymentState(game, backendDeployment, context2) {
|
|
|
7971
8349
|
// src/lib/dev/backend.ts
|
|
7972
8350
|
init_constants2();
|
|
7973
8351
|
init_core();
|
|
7974
|
-
import { existsSync as
|
|
7975
|
-
import { join as
|
|
8352
|
+
import { existsSync as existsSync18 } from "fs";
|
|
8353
|
+
import { join as join21 } from "path";
|
|
7976
8354
|
function hasCustomRoutes(config) {
|
|
7977
8355
|
const workspace = getWorkspace();
|
|
7978
8356
|
const customRoutesConfig = config?.integrations?.customRoutes;
|
|
7979
8357
|
const customRoutesDir = typeof customRoutesConfig === "object" && customRoutesConfig.directory || DEFAULT_API_ROUTES_DIRECTORY;
|
|
7980
|
-
return
|
|
8358
|
+
return existsSync18(join21(workspace, customRoutesDir));
|
|
7981
8359
|
}
|
|
7982
8360
|
function needsBackend(config) {
|
|
7983
8361
|
return !!config?.integrations || hasCustomRoutes(config);
|
|
7984
8362
|
}
|
|
7985
8363
|
|
|
7986
8364
|
// src/lib/dev/display.ts
|
|
7987
|
-
import { dim as
|
|
8365
|
+
import { dim as dim6 } from "colorette";
|
|
7988
8366
|
|
|
7989
8367
|
// ../edge-play/src/register-routes.ts
|
|
7990
8368
|
init_constants4();
|
|
@@ -8068,16 +8446,16 @@ function displayRegisteredRoutes(integrations, customRoutes = []) {
|
|
|
8068
8446
|
const maxPathLength = Math.max(...sortedRoutes.map((r) => r.path.length));
|
|
8069
8447
|
sortedRoutes.forEach((route) => {
|
|
8070
8448
|
const paddedPath = route.path.padEnd(maxPathLength + 2, " ");
|
|
8071
|
-
logger.customRaw(`<${paddedPath}> ${
|
|
8449
|
+
logger.customRaw(`<${paddedPath}> ${dim6(route.method)}`, 1);
|
|
8072
8450
|
});
|
|
8073
8451
|
}
|
|
8074
8452
|
|
|
8075
8453
|
// src/lib/dev/reload.ts
|
|
8076
8454
|
init_constants2();
|
|
8077
8455
|
init_core();
|
|
8078
|
-
import { join as
|
|
8456
|
+
import { join as join22, relative as relative4 } from "path";
|
|
8079
8457
|
import chokidar from "chokidar";
|
|
8080
|
-
import { bold as bold4, cyan as cyan3, dim as
|
|
8458
|
+
import { bold as bold4, cyan as cyan3, dim as dim7, green as green3 } from "colorette";
|
|
8081
8459
|
function formatTime() {
|
|
8082
8460
|
const now = /* @__PURE__ */ new Date();
|
|
8083
8461
|
let hours = now.getHours();
|
|
@@ -8092,9 +8470,9 @@ function startHotReload(onReload, options = {}) {
|
|
|
8092
8470
|
const customRoutesConfig = options.config?.integrations?.customRoutes;
|
|
8093
8471
|
const customRoutesDir = typeof customRoutesConfig === "object" && customRoutesConfig.directory || DEFAULT_API_ROUTES_DIRECTORY;
|
|
8094
8472
|
const watchPaths = [
|
|
8095
|
-
|
|
8096
|
-
|
|
8097
|
-
|
|
8473
|
+
join22(workspace, customRoutesDir),
|
|
8474
|
+
join22(workspace, "playcademy.config.js"),
|
|
8475
|
+
join22(workspace, "playcademy.config.json")
|
|
8098
8476
|
];
|
|
8099
8477
|
const watcher = chokidar.watch(watchPaths, {
|
|
8100
8478
|
persistent: true,
|
|
@@ -8106,11 +8484,11 @@ function startHotReload(onReload, options = {}) {
|
|
|
8106
8484
|
});
|
|
8107
8485
|
const logSuccess = options.onSuccess || ((changedPath, eventType) => {
|
|
8108
8486
|
if (changedPath) {
|
|
8109
|
-
const relativePath =
|
|
8110
|
-
const timestamp5 =
|
|
8487
|
+
const relativePath = relative4(workspace, changedPath);
|
|
8488
|
+
const timestamp5 = dim7(formatTime());
|
|
8111
8489
|
const brand = bold4(cyan3("[playcademy]"));
|
|
8112
8490
|
const event = eventType === "changed" ? green3("reload") : green3(eventType || "reload");
|
|
8113
|
-
console.log(`${timestamp5} ${brand} ${event} ${
|
|
8491
|
+
console.log(`${timestamp5} ${brand} ${event} ${dim7(relativePath)}`);
|
|
8114
8492
|
} else {
|
|
8115
8493
|
logger.success("Reloaded");
|
|
8116
8494
|
}
|
|
@@ -8136,14 +8514,14 @@ function startHotReload(onReload, options = {}) {
|
|
|
8136
8514
|
// src/lib/dev/server.ts
|
|
8137
8515
|
init_src2();
|
|
8138
8516
|
import { mkdir as mkdir4 } from "fs/promises";
|
|
8139
|
-
import { join as
|
|
8517
|
+
import { join as join24 } from "path";
|
|
8140
8518
|
import { Log, LogLevel, Miniflare } from "miniflare";
|
|
8141
8519
|
|
|
8142
8520
|
// ../utils/src/port.ts
|
|
8143
|
-
import { existsSync as
|
|
8521
|
+
import { existsSync as existsSync19, mkdirSync as mkdirSync4, readFileSync as readFileSync8, writeFileSync as writeFileSync7 } from "node:fs";
|
|
8144
8522
|
import { createServer as createServer2 } from "node:net";
|
|
8145
8523
|
import { homedir as homedir3 } from "node:os";
|
|
8146
|
-
import { join as
|
|
8524
|
+
import { join as join23 } from "node:path";
|
|
8147
8525
|
async function isPortAvailableOnHost(port, host) {
|
|
8148
8526
|
return new Promise((resolve11) => {
|
|
8149
8527
|
const server = createServer2();
|
|
@@ -8182,19 +8560,19 @@ async function findAvailablePort(startPort = 4321) {
|
|
|
8182
8560
|
}
|
|
8183
8561
|
function getRegistryPath() {
|
|
8184
8562
|
const home = homedir3();
|
|
8185
|
-
const dir =
|
|
8186
|
-
if (!
|
|
8563
|
+
const dir = join23(home, ".playcademy");
|
|
8564
|
+
if (!existsSync19(dir)) {
|
|
8187
8565
|
mkdirSync4(dir, { recursive: true });
|
|
8188
8566
|
}
|
|
8189
|
-
return
|
|
8567
|
+
return join23(dir, ".proc");
|
|
8190
8568
|
}
|
|
8191
8569
|
function readRegistry() {
|
|
8192
8570
|
const registryPath = getRegistryPath();
|
|
8193
|
-
if (!
|
|
8571
|
+
if (!existsSync19(registryPath)) {
|
|
8194
8572
|
return {};
|
|
8195
8573
|
}
|
|
8196
8574
|
try {
|
|
8197
|
-
const content =
|
|
8575
|
+
const content = readFileSync8(registryPath, "utf-8");
|
|
8198
8576
|
return JSON.parse(content);
|
|
8199
8577
|
} catch {
|
|
8200
8578
|
return {};
|
|
@@ -8326,11 +8704,11 @@ async function startDevServer(options) {
|
|
|
8326
8704
|
}
|
|
8327
8705
|
],
|
|
8328
8706
|
bindings,
|
|
8329
|
-
d1Databases: hasDatabase ? [
|
|
8707
|
+
d1Databases: hasDatabase ? [CLOUDFLARE_BINDINGS.DB] : [],
|
|
8330
8708
|
d1Persist: dbDir,
|
|
8331
|
-
kvNamespaces: hasKV ? [
|
|
8709
|
+
kvNamespaces: hasKV ? [CLOUDFLARE_BINDINGS.KV] : [],
|
|
8332
8710
|
kvPersist: kvDir,
|
|
8333
|
-
r2Buckets: hasBucket ? [
|
|
8711
|
+
r2Buckets: hasBucket ? [CLOUDFLARE_BINDINGS.BUCKET] : [],
|
|
8334
8712
|
r2Persist: bucketDir,
|
|
8335
8713
|
compatibilityDate: CLOUDFLARE_COMPATIBILITY_DATE
|
|
8336
8714
|
});
|
|
@@ -8341,7 +8719,7 @@ async function startDevServer(options) {
|
|
|
8341
8719
|
return { server: mf, port };
|
|
8342
8720
|
}
|
|
8343
8721
|
async function ensureDatabaseDirectory() {
|
|
8344
|
-
const dbDir =
|
|
8722
|
+
const dbDir = join24(getWorkspace(), CLI_DIRECTORIES.DATABASE);
|
|
8345
8723
|
try {
|
|
8346
8724
|
await mkdir4(dbDir, { recursive: true });
|
|
8347
8725
|
} catch (error) {
|
|
@@ -8350,7 +8728,7 @@ async function ensureDatabaseDirectory() {
|
|
|
8350
8728
|
return dbDir;
|
|
8351
8729
|
}
|
|
8352
8730
|
async function ensureKvDirectory() {
|
|
8353
|
-
const kvDir =
|
|
8731
|
+
const kvDir = join24(getWorkspace(), CLI_DIRECTORIES.KV);
|
|
8354
8732
|
try {
|
|
8355
8733
|
await mkdir4(kvDir, { recursive: true });
|
|
8356
8734
|
} catch (error) {
|
|
@@ -8359,7 +8737,7 @@ async function ensureKvDirectory() {
|
|
|
8359
8737
|
return kvDir;
|
|
8360
8738
|
}
|
|
8361
8739
|
async function ensureBucketDirectory() {
|
|
8362
|
-
const bucketDir =
|
|
8740
|
+
const bucketDir = join24(getWorkspace(), CLI_DIRECTORIES.BUCKET);
|
|
8363
8741
|
try {
|
|
8364
8742
|
await mkdir4(bucketDir, { recursive: true });
|
|
8365
8743
|
} catch (error) {
|
|
@@ -8368,7 +8746,7 @@ async function ensureBucketDirectory() {
|
|
|
8368
8746
|
return bucketDir;
|
|
8369
8747
|
}
|
|
8370
8748
|
async function initializeDatabase(mf) {
|
|
8371
|
-
const d1 = await mf.getD1Database(
|
|
8749
|
+
const d1 = await mf.getD1Database(CLOUDFLARE_BINDINGS.DB);
|
|
8372
8750
|
await d1.exec("SELECT 1");
|
|
8373
8751
|
}
|
|
8374
8752
|
async function writeBackendServerInfo(port) {
|
|
@@ -8595,7 +8973,6 @@ var initCommand = new Command2("init").description("Initialize a playcademy.conf
|
|
|
8595
8973
|
},
|
|
8596
8974
|
"Project configured"
|
|
8597
8975
|
);
|
|
8598
|
-
logger.newLine();
|
|
8599
8976
|
const configContent = configFormat === "js" ? generateJsConfig({
|
|
8600
8977
|
name: gameInfo.name,
|
|
8601
8978
|
description: gameInfo.description,
|
|
@@ -8633,7 +9010,7 @@ var initCommand = new Command2("init").description("Initialize a playcademy.conf
|
|
|
8633
9010
|
});
|
|
8634
9011
|
async function addPlaycademySdk() {
|
|
8635
9012
|
const pkgPath = resolve10(getWorkspace(), "package.json");
|
|
8636
|
-
const pkg = JSON.parse(
|
|
9013
|
+
const pkg = JSON.parse(readFileSync9(pkgPath, "utf-8"));
|
|
8637
9014
|
const hasSdk = pkg.dependencies?.["@playcademy/sdk"] || pkg.devDependencies?.["@playcademy/sdk"];
|
|
8638
9015
|
if (hasSdk) {
|
|
8639
9016
|
return false;
|
|
@@ -8650,7 +9027,7 @@ init_src();
|
|
|
8650
9027
|
init_file_loader();
|
|
8651
9028
|
init_constants2();
|
|
8652
9029
|
import { input as input3, password, select as select3 } from "@inquirer/prompts";
|
|
8653
|
-
import { bold as bold5, dim as
|
|
9030
|
+
import { bold as bold5, dim as dim8, whiteBright } from "colorette";
|
|
8654
9031
|
import { Command as Command3 } from "commander";
|
|
8655
9032
|
import open from "open";
|
|
8656
9033
|
var loginCommand = new Command3("login").description("Authenticate with Playcademy").option("-e, --email <email>", "Email address (for email/password auth)").option("-p, --password <password>", "Password (for email/password auth)").option("--sso", "Use Timeback SSO authentication").option("--env <environment>", "Environment to login to (staging or production)").action(async (options) => {
|
|
@@ -8666,10 +9043,10 @@ var loginCommand = new Command3("login").description("Authenticate with Playcade
|
|
|
8666
9043
|
logger.admonition("note", "Hello again", [
|
|
8667
9044
|
bold5("You're already logged in"),
|
|
8668
9045
|
"",
|
|
8669
|
-
|
|
8670
|
-
|
|
8671
|
-
|
|
8672
|
-
...otherProfile ? [
|
|
9046
|
+
dim8("Email: ") + bold5(email2),
|
|
9047
|
+
dim8("Environment: ") + bold5(environment),
|
|
9048
|
+
dim8("Profile: ") + bold5(profileName),
|
|
9049
|
+
...otherProfile ? [dim8("Other Profile: ") + bold5(otherEnv)] : []
|
|
8673
9050
|
]);
|
|
8674
9051
|
logger.newLine();
|
|
8675
9052
|
return;
|
|
@@ -9507,139 +9884,329 @@ async function runDbInit() {
|
|
|
9507
9884
|
|
|
9508
9885
|
// src/commands/db/reset.ts
|
|
9509
9886
|
init_src();
|
|
9510
|
-
import {
|
|
9511
|
-
import {
|
|
9512
|
-
import {
|
|
9513
|
-
import {
|
|
9887
|
+
import { existsSync as existsSync20 } from "fs";
|
|
9888
|
+
import { join as join25 } from "path";
|
|
9889
|
+
import { confirm as confirm6, input as input7 } from "@inquirer/prompts";
|
|
9890
|
+
import { bold as bold6, redBright, underline as underline3 } from "colorette";
|
|
9514
9891
|
import { Miniflare as Miniflare2 } from "miniflare";
|
|
9515
9892
|
init_constants2();
|
|
9516
|
-
async function
|
|
9517
|
-
|
|
9518
|
-
|
|
9519
|
-
|
|
9520
|
-
|
|
9521
|
-
|
|
9522
|
-
logger.newLine();
|
|
9523
|
-
logger.remark("Nothing to do");
|
|
9524
|
-
logger.newLine();
|
|
9525
|
-
return;
|
|
9526
|
-
}
|
|
9893
|
+
async function runDbResetRemote(options) {
|
|
9894
|
+
const environment = ensureEnvironment(options.env);
|
|
9895
|
+
const client = await requireAuthenticatedClient();
|
|
9896
|
+
const workspace = getWorkspace();
|
|
9897
|
+
const deployedGame = await getDeployedGame(workspace);
|
|
9898
|
+
if (!deployedGame) {
|
|
9527
9899
|
logger.newLine();
|
|
9528
|
-
|
|
9529
|
-
|
|
9530
|
-
|
|
9531
|
-
"Stop the server (Ctrl+C) and run this command again to ensure a clean reset."
|
|
9532
|
-
]);
|
|
9533
|
-
logger.newLine();
|
|
9534
|
-
process.exit(1);
|
|
9535
|
-
}
|
|
9536
|
-
const shouldReset = await confirm6({
|
|
9537
|
-
message: "This will delete all local database data. Continue?",
|
|
9538
|
-
default: false
|
|
9539
|
-
});
|
|
9540
|
-
if (!shouldReset) {
|
|
9541
|
-
logger.newLine();
|
|
9542
|
-
logger.remark("Nothing to do");
|
|
9543
|
-
logger.newLine();
|
|
9544
|
-
return;
|
|
9545
|
-
}
|
|
9546
|
-
runStep(
|
|
9547
|
-
"Deleting database...",
|
|
9548
|
-
async () => {
|
|
9549
|
-
rmSync2(dbDir, { recursive: true, force: true });
|
|
9550
|
-
},
|
|
9551
|
-
"Database deleted"
|
|
9552
|
-
);
|
|
9900
|
+
logger.admonition("warning", "Deploy First", [
|
|
9901
|
+
`Deploy your game before resetting remote database: \`playcademy deploy\``
|
|
9902
|
+
]);
|
|
9553
9903
|
logger.newLine();
|
|
9554
|
-
|
|
9555
|
-
|
|
9556
|
-
|
|
9557
|
-
|
|
9558
|
-
|
|
9559
|
-
|
|
9560
|
-
|
|
9561
|
-
|
|
9562
|
-
|
|
9563
|
-
|
|
9564
|
-
|
|
9565
|
-
|
|
9566
|
-
|
|
9567
|
-
|
|
9568
|
-
|
|
9569
|
-
await mf.dispose();
|
|
9570
|
-
} catch {
|
|
9571
|
-
logger.newLine();
|
|
9572
|
-
logger.error("Database recreation failed");
|
|
9573
|
-
logger.newLine();
|
|
9574
|
-
process.exit(1);
|
|
9575
|
-
}
|
|
9576
|
-
const exitCode = await runStep(
|
|
9577
|
-
"Database recreating...",
|
|
9578
|
-
async () => {
|
|
9579
|
-
const exitCode2 = await new Promise((resolve11) => {
|
|
9580
|
-
const child = spawn("npx", ["drizzle-kit", "push", "--force"], {
|
|
9581
|
-
cwd: workspace,
|
|
9582
|
-
stdio: ["ignore", "ignore", "inherit"],
|
|
9583
|
-
// stdin: ignore, stdout: ignore, stderr: inherit
|
|
9584
|
-
env: process.env
|
|
9585
|
-
});
|
|
9586
|
-
child.on("close", (code) => resolve11(code || 0));
|
|
9587
|
-
child.on("error", () => resolve11(1));
|
|
9588
|
-
});
|
|
9589
|
-
return exitCode2;
|
|
9590
|
-
},
|
|
9591
|
-
"Database recreated"
|
|
9592
|
-
);
|
|
9593
|
-
if (exitCode !== 0) {
|
|
9594
|
-
logger.newLine();
|
|
9595
|
-
logger.error("Schema push failed");
|
|
9596
|
-
process.exit(exitCode ?? 1);
|
|
9597
|
-
}
|
|
9904
|
+
process.exit(1);
|
|
9905
|
+
}
|
|
9906
|
+
const game = await client.games.fetch(deployedGame.gameId);
|
|
9907
|
+
logger.newLine();
|
|
9908
|
+
logger.admonition("warning", "DESTRUCTIVE OPERATION", [
|
|
9909
|
+
`Are you sure you want to ${redBright(underline3(bold6("DELETE ALL DATA")))} in your ${environment} database?`,
|
|
9910
|
+
`All tables will be dropped and recreated from schema.`,
|
|
9911
|
+
`This action is irreversible and ${underline3(bold6("cannot be undone"))}.`
|
|
9912
|
+
]);
|
|
9913
|
+
logger.newLine();
|
|
9914
|
+
const confirmed = await confirm6({
|
|
9915
|
+
message: "Are you sure you want to reset this database? This cannot be undone.",
|
|
9916
|
+
default: false
|
|
9917
|
+
});
|
|
9918
|
+
if (!confirmed) {
|
|
9598
9919
|
logger.newLine();
|
|
9599
|
-
logger.
|
|
9920
|
+
logger.remark("Cancelled");
|
|
9600
9921
|
logger.newLine();
|
|
9922
|
+
return;
|
|
9923
|
+
}
|
|
9924
|
+
const slugConfirmation = await input7({
|
|
9925
|
+
message: `Type the game slug "${game.slug}" to confirm:`,
|
|
9926
|
+
validate: (value) => {
|
|
9927
|
+
if (value !== game.slug) {
|
|
9928
|
+
return `Slug does not match. Please type exactly: ${game.slug}`;
|
|
9929
|
+
}
|
|
9930
|
+
return true;
|
|
9931
|
+
}
|
|
9932
|
+
});
|
|
9933
|
+
if (slugConfirmation !== game.slug) {
|
|
9934
|
+
logger.newLine();
|
|
9935
|
+
logger.remark("Cancelled");
|
|
9936
|
+
logger.newLine();
|
|
9937
|
+
return;
|
|
9938
|
+
}
|
|
9939
|
+
logger.newLine();
|
|
9940
|
+
const schema = await getSchemaInfo();
|
|
9941
|
+
if (!schema) {
|
|
9942
|
+
logger.error("Failed to generate schema. Make sure your database schema directory exists.");
|
|
9943
|
+
logger.newLine();
|
|
9944
|
+
process.exit(1);
|
|
9945
|
+
}
|
|
9946
|
+
const result = await runStep(
|
|
9947
|
+
`Resetting ${environment} database`,
|
|
9948
|
+
async () => {
|
|
9949
|
+
return client.dev.games.database.reset(game.slug, schema);
|
|
9950
|
+
},
|
|
9951
|
+
`${capitalize(environment)} database reset`
|
|
9952
|
+
);
|
|
9953
|
+
if (!result.schemaPushed) {
|
|
9954
|
+
logger.admonition("warning", "Failed to recreate schema", [
|
|
9955
|
+
"During reset, the schema was not successfully pushed to your database.",
|
|
9956
|
+
"Please retry the `db reset` command; if the problem persists, contact support."
|
|
9957
|
+
]);
|
|
9958
|
+
logger.newLine();
|
|
9959
|
+
process.exit(1);
|
|
9960
|
+
}
|
|
9961
|
+
logger.newLine();
|
|
9962
|
+
logger.success("Database reset complete!");
|
|
9963
|
+
logger.newLine();
|
|
9964
|
+
}
|
|
9965
|
+
async function runDbResetLocal(options) {
|
|
9966
|
+
const workspace = getWorkspace();
|
|
9967
|
+
const dbDir = join25(workspace, CLI_DIRECTORIES.DATABASE);
|
|
9968
|
+
if (!existsSync20(dbDir)) {
|
|
9969
|
+
logger.warn("No database found to reset");
|
|
9970
|
+
logger.newLine();
|
|
9971
|
+
logger.remark("Nothing to do");
|
|
9972
|
+
logger.newLine();
|
|
9973
|
+
return;
|
|
9974
|
+
}
|
|
9975
|
+
logger.newLine();
|
|
9976
|
+
if (isServerRunning("backend", workspace)) {
|
|
9977
|
+
logger.admonition("warning", "Stop Dev Server First", [
|
|
9978
|
+
"The development server must be stopped before resetting the database.",
|
|
9979
|
+
"Stop the server (Ctrl+C) and run this command again to ensure a clean reset."
|
|
9980
|
+
]);
|
|
9981
|
+
logger.newLine();
|
|
9982
|
+
process.exit(1);
|
|
9983
|
+
}
|
|
9984
|
+
const shouldReset = await confirm6({
|
|
9985
|
+
message: "This will delete all local database data. Continue?",
|
|
9986
|
+
default: false
|
|
9987
|
+
});
|
|
9988
|
+
if (!shouldReset) {
|
|
9989
|
+
logger.newLine();
|
|
9990
|
+
logger.remark("Nothing to do");
|
|
9991
|
+
logger.newLine();
|
|
9992
|
+
return;
|
|
9993
|
+
}
|
|
9994
|
+
if (!hasDatabaseSetup()) {
|
|
9995
|
+
logger.remark("No drizzle config found, skipping schema setup");
|
|
9996
|
+
logger.newLine();
|
|
9997
|
+
return;
|
|
9998
|
+
}
|
|
9999
|
+
const mf = new Miniflare2({
|
|
10000
|
+
modules: [{ type: "ESModule", path: "index.mjs", contents: "" }],
|
|
10001
|
+
d1Databases: [CLOUDFLARE_BINDINGS.DB],
|
|
10002
|
+
d1Persist: dbDir,
|
|
10003
|
+
compatibilityDate: CLOUDFLARE_COMPATIBILITY_DATE
|
|
10004
|
+
});
|
|
10005
|
+
try {
|
|
10006
|
+
logger.newLine();
|
|
10007
|
+
await resetDatabase(workspace, mf, { debug: options.debug });
|
|
10008
|
+
} finally {
|
|
10009
|
+
await mf.dispose();
|
|
10010
|
+
}
|
|
10011
|
+
logger.newLine();
|
|
10012
|
+
}
|
|
10013
|
+
async function runDbReset(options = {}) {
|
|
10014
|
+
try {
|
|
10015
|
+
if (options.remote) {
|
|
10016
|
+
await runDbResetRemote(options);
|
|
10017
|
+
} else {
|
|
10018
|
+
await runDbResetLocal(options);
|
|
10019
|
+
}
|
|
9601
10020
|
} catch (error) {
|
|
9602
10021
|
logAndExit(error, logger, { prefix: "Failed to reset database" });
|
|
9603
10022
|
}
|
|
9604
10023
|
}
|
|
9605
10024
|
|
|
9606
10025
|
// src/commands/db/seed.ts
|
|
9607
|
-
|
|
9608
|
-
|
|
9609
|
-
import { existsSync as
|
|
9610
|
-
import { join as
|
|
9611
|
-
|
|
10026
|
+
init_src();
|
|
10027
|
+
init_constants2();
|
|
10028
|
+
import { existsSync as existsSync21 } from "fs";
|
|
10029
|
+
import { join as join26 } from "path";
|
|
10030
|
+
import { confirm as confirm7, input as input8 } from "@inquirer/prompts";
|
|
10031
|
+
import { bold as bold7, redBright as redBright2, underline as underline4 } from "colorette";
|
|
10032
|
+
import { Miniflare as Miniflare3 } from "miniflare";
|
|
10033
|
+
async function runDbResetRemote2(gameSlug, environment) {
|
|
10034
|
+
const client = await requireAuthenticatedClient();
|
|
10035
|
+
const schema = await getSchemaInfo();
|
|
10036
|
+
if (!schema) {
|
|
10037
|
+
logger.error("Failed to generate schema. Make sure your database schema directory exists.");
|
|
10038
|
+
logger.newLine();
|
|
10039
|
+
process.exit(1);
|
|
10040
|
+
}
|
|
10041
|
+
const result = await runStep(
|
|
10042
|
+
`Resetting ${environment} database`,
|
|
10043
|
+
async () => {
|
|
10044
|
+
return client.dev.games.database.reset(gameSlug, schema);
|
|
10045
|
+
},
|
|
10046
|
+
`${capitalize(environment)} database reset`
|
|
10047
|
+
);
|
|
10048
|
+
if (!result.schemaPushed) {
|
|
10049
|
+
logger.admonition("warning", "Failed to recreate schema", [
|
|
10050
|
+
"Schema was not successfully pushed after reset.",
|
|
10051
|
+
"Please retry the command."
|
|
10052
|
+
]);
|
|
10053
|
+
logger.newLine();
|
|
10054
|
+
process.exit(1);
|
|
10055
|
+
}
|
|
10056
|
+
}
|
|
10057
|
+
async function runDbSeedRemote(seedFile, options) {
|
|
10058
|
+
const environment = ensureEnvironment(options.env);
|
|
10059
|
+
const client = await requireAuthenticatedClient();
|
|
9612
10060
|
const workspace = getWorkspace();
|
|
9613
|
-
|
|
9614
|
-
|
|
9615
|
-
|
|
10061
|
+
const deployedGame = await getDeployedGame(workspace);
|
|
10062
|
+
if (!deployedGame) {
|
|
10063
|
+
logger.newLine();
|
|
10064
|
+
logger.admonition("warning", "Deploy First", [
|
|
10065
|
+
`Deploy your game before seeding remote database: \`playcademy deploy\``
|
|
10066
|
+
]);
|
|
10067
|
+
logger.newLine();
|
|
10068
|
+
process.exit(1);
|
|
10069
|
+
}
|
|
10070
|
+
const game = await client.games.fetch(deployedGame.gameId);
|
|
10071
|
+
const willReset = options.reset !== false;
|
|
10072
|
+
logger.newLine();
|
|
10073
|
+
if (willReset) {
|
|
10074
|
+
logger.admonition("warning", "Remote Database Seeding", [
|
|
10075
|
+
`Are you sure you want to ${redBright2(underline4(bold7("DELETE ALL DATA")))} in your ${environment} database?`,
|
|
10076
|
+
`This action is irreversible and ${underline4(bold7("cannot be undone"))}.`,
|
|
10077
|
+
`Run this command with \`--no-reset\` if you want to seed without resetting.`
|
|
10078
|
+
]);
|
|
10079
|
+
} else {
|
|
10080
|
+
logger.admonition("warning", "Remote Database Seeding", [
|
|
10081
|
+
`Are you sure you want to seed your ${environment} database?`,
|
|
10082
|
+
`If existing data is present, this may produce unpredictable results.`,
|
|
10083
|
+
"Proceed with caution."
|
|
10084
|
+
]);
|
|
10085
|
+
}
|
|
10086
|
+
logger.newLine();
|
|
10087
|
+
if (willReset) {
|
|
10088
|
+
const confirmed = await confirm7({
|
|
10089
|
+
message: "Are you sure you want to reset and seed this database? This cannot be undone.",
|
|
10090
|
+
default: false
|
|
10091
|
+
});
|
|
10092
|
+
if (!confirmed) {
|
|
10093
|
+
logger.newLine();
|
|
10094
|
+
logger.remark("Cancelled");
|
|
9616
10095
|
logger.newLine();
|
|
10096
|
+
return;
|
|
9617
10097
|
}
|
|
9618
|
-
|
|
9619
|
-
|
|
9620
|
-
|
|
9621
|
-
|
|
9622
|
-
|
|
9623
|
-
|
|
10098
|
+
const slugConfirmation = await input8({
|
|
10099
|
+
message: `Type the game slug "${game.slug}" to confirm:`,
|
|
10100
|
+
validate: (value) => {
|
|
10101
|
+
if (value !== game.slug) {
|
|
10102
|
+
return `Slug does not match. Please type exactly: ${game.slug}`;
|
|
10103
|
+
}
|
|
10104
|
+
return true;
|
|
9624
10105
|
}
|
|
9625
|
-
|
|
9626
|
-
|
|
9627
|
-
|
|
10106
|
+
});
|
|
10107
|
+
if (slugConfirmation !== game.slug) {
|
|
10108
|
+
logger.newLine();
|
|
10109
|
+
logger.remark("Cancelled");
|
|
10110
|
+
logger.newLine();
|
|
10111
|
+
return;
|
|
10112
|
+
}
|
|
10113
|
+
} else {
|
|
10114
|
+
const shouldSeed = await confirm7({
|
|
10115
|
+
message: `Seed ${environment} database for ${game.slug}?`,
|
|
10116
|
+
default: false
|
|
10117
|
+
});
|
|
10118
|
+
if (!shouldSeed) {
|
|
10119
|
+
logger.newLine();
|
|
10120
|
+
logger.remark("Cancelled");
|
|
10121
|
+
logger.newLine();
|
|
9628
10122
|
return;
|
|
9629
10123
|
}
|
|
9630
|
-
|
|
9631
|
-
|
|
9632
|
-
|
|
10124
|
+
}
|
|
10125
|
+
logger.newLine();
|
|
10126
|
+
if (willReset) {
|
|
10127
|
+
await runDbResetRemote2(game.slug, environment);
|
|
10128
|
+
}
|
|
10129
|
+
let bundle;
|
|
10130
|
+
await runStep(
|
|
10131
|
+
"Bundling seed task",
|
|
10132
|
+
async () => {
|
|
10133
|
+
bundle = await bundleSeedWorker(seedFile, workspace);
|
|
10134
|
+
},
|
|
10135
|
+
"Seed task bundled"
|
|
10136
|
+
);
|
|
10137
|
+
await runStep(
|
|
10138
|
+
`Seeding ${environment} database`,
|
|
10139
|
+
async () => {
|
|
10140
|
+
await client.dev.games.deploy.seed(game.slug, bundle.code, environment);
|
|
10141
|
+
},
|
|
10142
|
+
`${environment.charAt(0).toUpperCase() + environment.slice(1)} database seeded`
|
|
10143
|
+
);
|
|
10144
|
+
logger.newLine();
|
|
10145
|
+
}
|
|
10146
|
+
async function runDbSeedLocal(seedFile, options) {
|
|
10147
|
+
const workspace = getWorkspace();
|
|
10148
|
+
const dbDir = join26(workspace, CLI_DIRECTORIES.DATABASE);
|
|
10149
|
+
const mf = new Miniflare3({
|
|
10150
|
+
modules: [{ type: "ESModule", path: "index.mjs", contents: "" }],
|
|
10151
|
+
d1Databases: [CLOUDFLARE_BINDINGS.DB],
|
|
10152
|
+
d1Persist: dbDir,
|
|
10153
|
+
compatibilityDate: CLOUDFLARE_COMPATIBILITY_DATE
|
|
10154
|
+
});
|
|
10155
|
+
logger.newLine();
|
|
10156
|
+
if (options.reset !== false) {
|
|
10157
|
+
await resetDatabase(workspace, mf, { debug: options.debug });
|
|
10158
|
+
}
|
|
10159
|
+
try {
|
|
10160
|
+
await executeSeedFile(seedFile, mf);
|
|
10161
|
+
} finally {
|
|
10162
|
+
await mf.dispose();
|
|
10163
|
+
}
|
|
10164
|
+
}
|
|
10165
|
+
async function runDbSeed(options = {}) {
|
|
10166
|
+
const workspace = getWorkspace();
|
|
10167
|
+
try {
|
|
10168
|
+
const seedFile = options.file ? join26(workspace, options.file) : join26(workspace, DEFAULT_DATABASE_DIRECTORY, DEFAULT_SEED_FILE_NAME);
|
|
10169
|
+
if (!existsSync21(seedFile)) {
|
|
10170
|
+
logger.newLine();
|
|
10171
|
+
logger.error(`Seed file not found: ${seedFile}`);
|
|
10172
|
+
logger.newLine();
|
|
10173
|
+
logger.admonition("tip", "Create Seed File", [
|
|
10174
|
+
"Run `playcademy db init` to scaffold database with seed file",
|
|
10175
|
+
`Or create ${seedFile} with: \`export async function seed(c: Context) { ... }\``
|
|
10176
|
+
]);
|
|
10177
|
+
logger.newLine();
|
|
10178
|
+
process.exit(1);
|
|
10179
|
+
}
|
|
10180
|
+
if (options.remote) {
|
|
10181
|
+
await runDbSeedRemote(seedFile, options);
|
|
10182
|
+
} else {
|
|
10183
|
+
await runDbSeedLocal(seedFile, options);
|
|
10184
|
+
}
|
|
9633
10185
|
} catch (error) {
|
|
9634
|
-
|
|
10186
|
+
logger.newLine();
|
|
10187
|
+
logger.error(
|
|
10188
|
+
`Failed to seed database: ${error instanceof Error ? error.message : String(error)}`
|
|
10189
|
+
);
|
|
10190
|
+
logger.newLine();
|
|
10191
|
+
process.exit(1);
|
|
9635
10192
|
}
|
|
9636
10193
|
}
|
|
9637
10194
|
|
|
9638
10195
|
// src/commands/db/index.ts
|
|
9639
10196
|
var dbCommand = new Command14("db").description("Database management commands");
|
|
9640
10197
|
dbCommand.command("init").description("Add database to your project").action(runDbInit);
|
|
9641
|
-
dbCommand.command("reset").description("Reset
|
|
9642
|
-
|
|
10198
|
+
dbCommand.command("reset").description("Reset database").option("--remote", "Reset remote deployed database").option("--env <environment>", "Environment: staging (default) or production").option("--debug", "Enable debug mode").action(
|
|
10199
|
+
(options) => runDbReset({ debug: options.debug, remote: options.remote, env: options.env })
|
|
10200
|
+
);
|
|
10201
|
+
dbCommand.command("seed [file]").description("Seed database with initial data").option("--no-reset", "Skip database reset before seeding").option("--remote", "Seed remote deployed database").option("--debug", "Enable debug mode").option("--env <environment>", "Environment: staging (default) or production").action(
|
|
10202
|
+
(file, options) => runDbSeed({
|
|
10203
|
+
file,
|
|
10204
|
+
reset: options.reset,
|
|
10205
|
+
remote: options.remote,
|
|
10206
|
+
env: options.env,
|
|
10207
|
+
debug: options.debug
|
|
10208
|
+
})
|
|
10209
|
+
);
|
|
9643
10210
|
dbCommand.command("diff").description("Show schema changes since last deployment").action(runDbDiff);
|
|
9644
10211
|
|
|
9645
10212
|
// src/commands/kv/index.ts
|
|
@@ -9648,9 +10215,9 @@ import { Command as Command15 } from "commander";
|
|
|
9648
10215
|
// src/commands/kv/clear.ts
|
|
9649
10216
|
init_string();
|
|
9650
10217
|
init_constants2();
|
|
9651
|
-
import { join as
|
|
9652
|
-
import { confirm as
|
|
9653
|
-
import { Miniflare as
|
|
10218
|
+
import { join as join27 } from "path";
|
|
10219
|
+
import { confirm as confirm8 } from "@inquirer/prompts";
|
|
10220
|
+
import { Miniflare as Miniflare4 } from "miniflare";
|
|
9654
10221
|
async function runKVClear(options = {}) {
|
|
9655
10222
|
try {
|
|
9656
10223
|
if (!options.raw && !options.json) {
|
|
@@ -9681,15 +10248,15 @@ async function runKVClear(options = {}) {
|
|
|
9681
10248
|
}
|
|
9682
10249
|
process.exit(1);
|
|
9683
10250
|
}
|
|
9684
|
-
const kvDir =
|
|
9685
|
-
const mf = new
|
|
10251
|
+
const kvDir = join27(getWorkspace(), CLI_DIRECTORIES.KV);
|
|
10252
|
+
const mf = new Miniflare4({
|
|
9686
10253
|
modules: [{ type: "ESModule", path: "index.mjs", contents: "" }],
|
|
9687
|
-
kvNamespaces: [
|
|
10254
|
+
kvNamespaces: [CLOUDFLARE_BINDINGS.KV],
|
|
9688
10255
|
kvPersist: kvDir,
|
|
9689
10256
|
compatibilityDate: CLOUDFLARE_COMPATIBILITY_DATE
|
|
9690
10257
|
});
|
|
9691
10258
|
try {
|
|
9692
|
-
const kv = await mf.getKVNamespace(
|
|
10259
|
+
const kv = await mf.getKVNamespace(CLOUDFLARE_BINDINGS.KV);
|
|
9693
10260
|
const listResult = await kv.list();
|
|
9694
10261
|
const keyCount = listResult.keys?.length || 0;
|
|
9695
10262
|
if (keyCount === 0) {
|
|
@@ -9711,7 +10278,7 @@ async function runKVClear(options = {}) {
|
|
|
9711
10278
|
if (!options.force && !options.raw && !options.json) {
|
|
9712
10279
|
logger.warn(`This will delete ${keyCount} ${pluralize(keyCount, "key")}`);
|
|
9713
10280
|
logger.newLine();
|
|
9714
|
-
const confirmed = await
|
|
10281
|
+
const confirmed = await confirm8({
|
|
9715
10282
|
message: "Are you sure you want to clear all keys?",
|
|
9716
10283
|
default: false
|
|
9717
10284
|
});
|
|
@@ -9753,8 +10320,8 @@ async function runKVClear(options = {}) {
|
|
|
9753
10320
|
|
|
9754
10321
|
// src/commands/kv/delete.ts
|
|
9755
10322
|
init_constants2();
|
|
9756
|
-
import { join as
|
|
9757
|
-
import { Miniflare as
|
|
10323
|
+
import { join as join28 } from "path";
|
|
10324
|
+
import { Miniflare as Miniflare5 } from "miniflare";
|
|
9758
10325
|
async function runKVDelete(key, options = {}) {
|
|
9759
10326
|
try {
|
|
9760
10327
|
if (!options.raw && !options.json) {
|
|
@@ -9794,15 +10361,15 @@ async function runKVDelete(key, options = {}) {
|
|
|
9794
10361
|
}
|
|
9795
10362
|
process.exit(1);
|
|
9796
10363
|
}
|
|
9797
|
-
const kvDir =
|
|
9798
|
-
const mf = new
|
|
10364
|
+
const kvDir = join28(getWorkspace(), CLI_DIRECTORIES.KV);
|
|
10365
|
+
const mf = new Miniflare5({
|
|
9799
10366
|
modules: [{ type: "ESModule", path: "index.mjs", contents: "" }],
|
|
9800
|
-
kvNamespaces: [
|
|
10367
|
+
kvNamespaces: [CLOUDFLARE_BINDINGS.KV],
|
|
9801
10368
|
kvPersist: kvDir,
|
|
9802
10369
|
compatibilityDate: CLOUDFLARE_COMPATIBILITY_DATE
|
|
9803
10370
|
});
|
|
9804
10371
|
try {
|
|
9805
|
-
const kv = await mf.getKVNamespace(
|
|
10372
|
+
const kv = await mf.getKVNamespace(CLOUDFLARE_BINDINGS.KV);
|
|
9806
10373
|
await kv.delete(key);
|
|
9807
10374
|
if (options.json) {
|
|
9808
10375
|
logger.json({
|
|
@@ -9831,8 +10398,8 @@ async function runKVDelete(key, options = {}) {
|
|
|
9831
10398
|
|
|
9832
10399
|
// src/commands/kv/get.ts
|
|
9833
10400
|
init_constants2();
|
|
9834
|
-
import { join as
|
|
9835
|
-
import { Miniflare as
|
|
10401
|
+
import { join as join29 } from "path";
|
|
10402
|
+
import { Miniflare as Miniflare6 } from "miniflare";
|
|
9836
10403
|
async function runKVGet(key, options = {}) {
|
|
9837
10404
|
try {
|
|
9838
10405
|
if (!options.raw && !options.json) {
|
|
@@ -9872,15 +10439,15 @@ async function runKVGet(key, options = {}) {
|
|
|
9872
10439
|
}
|
|
9873
10440
|
process.exit(1);
|
|
9874
10441
|
}
|
|
9875
|
-
const kvDir =
|
|
9876
|
-
const mf = new
|
|
10442
|
+
const kvDir = join29(getWorkspace(), CLI_DIRECTORIES.KV);
|
|
10443
|
+
const mf = new Miniflare6({
|
|
9877
10444
|
modules: [{ type: "ESModule", path: "index.mjs", contents: "" }],
|
|
9878
|
-
kvNamespaces: [
|
|
10445
|
+
kvNamespaces: [CLOUDFLARE_BINDINGS.KV],
|
|
9879
10446
|
kvPersist: kvDir,
|
|
9880
10447
|
compatibilityDate: CLOUDFLARE_COMPATIBILITY_DATE
|
|
9881
10448
|
});
|
|
9882
10449
|
try {
|
|
9883
|
-
const kv = await mf.getKVNamespace(
|
|
10450
|
+
const kv = await mf.getKVNamespace(CLOUDFLARE_BINDINGS.KV);
|
|
9884
10451
|
const value = await kv.get(key);
|
|
9885
10452
|
if (value === null) {
|
|
9886
10453
|
if (!options.raw && !options.json) {
|
|
@@ -9937,7 +10504,7 @@ async function runKVGet(key, options = {}) {
|
|
|
9937
10504
|
|
|
9938
10505
|
// src/commands/kv/init.ts
|
|
9939
10506
|
init_constants2();
|
|
9940
|
-
import { input as
|
|
10507
|
+
import { input as input9 } from "@inquirer/prompts";
|
|
9941
10508
|
init_writer();
|
|
9942
10509
|
init_loader2();
|
|
9943
10510
|
var sampleCustomRouteTemplate3 = loadTemplateString("api/sample-custom.ts");
|
|
@@ -9970,7 +10537,7 @@ async function runKVInit() {
|
|
|
9970
10537
|
logger.success("Added KV integration to config");
|
|
9971
10538
|
logger.newLine();
|
|
9972
10539
|
if (!hasLocalCustomRoutes(getWorkspace(), config)) {
|
|
9973
|
-
const apiDirectory = await
|
|
10540
|
+
const apiDirectory = await input9({
|
|
9974
10541
|
message: " \u2514\u2500 API routes directory:",
|
|
9975
10542
|
default: DEFAULT_API_ROUTES_DIRECTORY,
|
|
9976
10543
|
validate: (value) => {
|
|
@@ -10011,8 +10578,8 @@ async function runKVInit() {
|
|
|
10011
10578
|
|
|
10012
10579
|
// src/commands/kv/inspect.ts
|
|
10013
10580
|
init_constants2();
|
|
10014
|
-
import { join as
|
|
10015
|
-
import { Miniflare as
|
|
10581
|
+
import { join as join30 } from "path";
|
|
10582
|
+
import { Miniflare as Miniflare7 } from "miniflare";
|
|
10016
10583
|
async function runKVInspect(key, options = {}) {
|
|
10017
10584
|
try {
|
|
10018
10585
|
if (!options.raw && !options.json) {
|
|
@@ -10052,15 +10619,15 @@ async function runKVInspect(key, options = {}) {
|
|
|
10052
10619
|
}
|
|
10053
10620
|
process.exit(1);
|
|
10054
10621
|
}
|
|
10055
|
-
const kvDir =
|
|
10056
|
-
const mf = new
|
|
10622
|
+
const kvDir = join30(getWorkspace(), CLI_DIRECTORIES.KV);
|
|
10623
|
+
const mf = new Miniflare7({
|
|
10057
10624
|
modules: [{ type: "ESModule", path: "index.mjs", contents: "" }],
|
|
10058
|
-
kvNamespaces: [
|
|
10625
|
+
kvNamespaces: [CLOUDFLARE_BINDINGS.KV],
|
|
10059
10626
|
kvPersist: kvDir,
|
|
10060
10627
|
compatibilityDate: CLOUDFLARE_COMPATIBILITY_DATE
|
|
10061
10628
|
});
|
|
10062
10629
|
try {
|
|
10063
|
-
const kv = await mf.getKVNamespace(
|
|
10630
|
+
const kv = await mf.getKVNamespace(CLOUDFLARE_BINDINGS.KV);
|
|
10064
10631
|
const value = await kv.get(key);
|
|
10065
10632
|
if (value === null) {
|
|
10066
10633
|
const metadata2 = {
|
|
@@ -10140,8 +10707,8 @@ async function runKVInspect(key, options = {}) {
|
|
|
10140
10707
|
// src/commands/kv/list.ts
|
|
10141
10708
|
init_string();
|
|
10142
10709
|
init_constants2();
|
|
10143
|
-
import { join as
|
|
10144
|
-
import { Miniflare as
|
|
10710
|
+
import { join as join31 } from "path";
|
|
10711
|
+
import { Miniflare as Miniflare8 } from "miniflare";
|
|
10145
10712
|
async function runKVList(options = {}) {
|
|
10146
10713
|
try {
|
|
10147
10714
|
if (!options.raw && !options.json) {
|
|
@@ -10172,15 +10739,15 @@ async function runKVList(options = {}) {
|
|
|
10172
10739
|
}
|
|
10173
10740
|
process.exit(1);
|
|
10174
10741
|
}
|
|
10175
|
-
const kvDir =
|
|
10176
|
-
const mf = new
|
|
10742
|
+
const kvDir = join31(getWorkspace(), CLI_DIRECTORIES.KV);
|
|
10743
|
+
const mf = new Miniflare8({
|
|
10177
10744
|
modules: [{ type: "ESModule", path: "index.mjs", contents: "" }],
|
|
10178
|
-
kvNamespaces: [
|
|
10745
|
+
kvNamespaces: [CLOUDFLARE_BINDINGS.KV],
|
|
10179
10746
|
kvPersist: kvDir,
|
|
10180
10747
|
compatibilityDate: CLOUDFLARE_COMPATIBILITY_DATE
|
|
10181
10748
|
});
|
|
10182
10749
|
try {
|
|
10183
|
-
const kv = await mf.getKVNamespace(
|
|
10750
|
+
const kv = await mf.getKVNamespace(CLOUDFLARE_BINDINGS.KV);
|
|
10184
10751
|
const listResult = await kv.list();
|
|
10185
10752
|
const keyNames = listResult.keys?.map((k) => k.name) || [];
|
|
10186
10753
|
if (options.json) {
|
|
@@ -10221,9 +10788,9 @@ async function runKVList(options = {}) {
|
|
|
10221
10788
|
init_file_loader();
|
|
10222
10789
|
init_string();
|
|
10223
10790
|
init_constants2();
|
|
10224
|
-
import { join as
|
|
10225
|
-
import { confirm as
|
|
10226
|
-
import { Miniflare as
|
|
10791
|
+
import { join as join32 } from "path";
|
|
10792
|
+
import { confirm as confirm9 } from "@inquirer/prompts";
|
|
10793
|
+
import { Miniflare as Miniflare9 } from "miniflare";
|
|
10227
10794
|
async function runKVSeed(seedFile, options = {}) {
|
|
10228
10795
|
try {
|
|
10229
10796
|
if (!options.raw && !options.json) {
|
|
@@ -10287,15 +10854,15 @@ async function runKVSeed(seedFile, options = {}) {
|
|
|
10287
10854
|
}
|
|
10288
10855
|
process.exit(1);
|
|
10289
10856
|
}
|
|
10290
|
-
const kvDir =
|
|
10291
|
-
const mf = new
|
|
10857
|
+
const kvDir = join32(workspace, CLI_DIRECTORIES.KV);
|
|
10858
|
+
const mf = new Miniflare9({
|
|
10292
10859
|
modules: [{ type: "ESModule", path: "index.mjs", contents: "" }],
|
|
10293
|
-
kvNamespaces: [
|
|
10860
|
+
kvNamespaces: [CLOUDFLARE_BINDINGS.KV],
|
|
10294
10861
|
kvPersist: kvDir,
|
|
10295
10862
|
compatibilityDate: CLOUDFLARE_COMPATIBILITY_DATE
|
|
10296
10863
|
});
|
|
10297
10864
|
try {
|
|
10298
|
-
const kv = await mf.getKVNamespace(
|
|
10865
|
+
const kv = await mf.getKVNamespace(CLOUDFLARE_BINDINGS.KV);
|
|
10299
10866
|
const keysToSeed = Object.keys(seedData);
|
|
10300
10867
|
if (!options.force && !options.replace && !options.raw && !options.json) {
|
|
10301
10868
|
const existingKeys = [];
|
|
@@ -10310,7 +10877,7 @@ async function runKVSeed(seedFile, options = {}) {
|
|
|
10310
10877
|
`${existingKeys.length} ${pluralize(existingKeys.length, "key")} will be overwritten`
|
|
10311
10878
|
);
|
|
10312
10879
|
logger.newLine();
|
|
10313
|
-
const confirmed = await
|
|
10880
|
+
const confirmed = await confirm9({
|
|
10314
10881
|
message: "Continue seeding?",
|
|
10315
10882
|
default: false
|
|
10316
10883
|
});
|
|
@@ -10368,8 +10935,8 @@ async function runKVSeed(seedFile, options = {}) {
|
|
|
10368
10935
|
// src/commands/kv/set.ts
|
|
10369
10936
|
init_file_loader();
|
|
10370
10937
|
init_constants2();
|
|
10371
|
-
import { join as
|
|
10372
|
-
import { Miniflare as
|
|
10938
|
+
import { join as join33 } from "path";
|
|
10939
|
+
import { Miniflare as Miniflare10 } from "miniflare";
|
|
10373
10940
|
async function runKVSet(key, value, options = {}) {
|
|
10374
10941
|
try {
|
|
10375
10942
|
if (!options.raw && !options.json) {
|
|
@@ -10438,15 +11005,15 @@ async function runKVSet(key, value, options = {}) {
|
|
|
10438
11005
|
}
|
|
10439
11006
|
process.exit(1);
|
|
10440
11007
|
}
|
|
10441
|
-
const kvDir =
|
|
10442
|
-
const mf = new
|
|
11008
|
+
const kvDir = join33(getWorkspace(), CLI_DIRECTORIES.KV);
|
|
11009
|
+
const mf = new Miniflare10({
|
|
10443
11010
|
modules: [{ type: "ESModule", path: "index.mjs", contents: "" }],
|
|
10444
|
-
kvNamespaces: [
|
|
11011
|
+
kvNamespaces: [CLOUDFLARE_BINDINGS.KV],
|
|
10445
11012
|
kvPersist: kvDir,
|
|
10446
11013
|
compatibilityDate: CLOUDFLARE_COMPATIBILITY_DATE
|
|
10447
11014
|
});
|
|
10448
11015
|
try {
|
|
10449
|
-
const kv = await mf.getKVNamespace(
|
|
11016
|
+
const kv = await mf.getKVNamespace(CLOUDFLARE_BINDINGS.KV);
|
|
10450
11017
|
await kv.put(key, valueToSet);
|
|
10451
11018
|
if (options.json) {
|
|
10452
11019
|
logger.json({
|
|
@@ -10476,8 +11043,8 @@ async function runKVSet(key, value, options = {}) {
|
|
|
10476
11043
|
// src/commands/kv/stats.ts
|
|
10477
11044
|
init_string();
|
|
10478
11045
|
init_constants2();
|
|
10479
|
-
import { join as
|
|
10480
|
-
import { Miniflare as
|
|
11046
|
+
import { join as join34 } from "path";
|
|
11047
|
+
import { Miniflare as Miniflare11 } from "miniflare";
|
|
10481
11048
|
async function runKVStats(options = {}) {
|
|
10482
11049
|
try {
|
|
10483
11050
|
if (!options.raw && !options.json) {
|
|
@@ -10508,15 +11075,15 @@ async function runKVStats(options = {}) {
|
|
|
10508
11075
|
}
|
|
10509
11076
|
process.exit(1);
|
|
10510
11077
|
}
|
|
10511
|
-
const kvDir =
|
|
10512
|
-
const mf = new
|
|
11078
|
+
const kvDir = join34(getWorkspace(), CLI_DIRECTORIES.KV);
|
|
11079
|
+
const mf = new Miniflare11({
|
|
10513
11080
|
modules: [{ type: "ESModule", path: "index.mjs", contents: "" }],
|
|
10514
|
-
kvNamespaces: [
|
|
11081
|
+
kvNamespaces: [CLOUDFLARE_BINDINGS.KV],
|
|
10515
11082
|
kvPersist: kvDir,
|
|
10516
11083
|
compatibilityDate: CLOUDFLARE_COMPATIBILITY_DATE
|
|
10517
11084
|
});
|
|
10518
11085
|
try {
|
|
10519
|
-
const kv = await mf.getKVNamespace(
|
|
11086
|
+
const kv = await mf.getKVNamespace(CLOUDFLARE_BINDINGS.KV);
|
|
10520
11087
|
const listResult = await kv.list();
|
|
10521
11088
|
const keys = listResult.keys || [];
|
|
10522
11089
|
let totalSize = 0;
|
|
@@ -10623,87 +11190,246 @@ kvCommand.command("seed <file>").description("Seed KV namespace with key-value p
|
|
|
10623
11190
|
// src/commands/bucket/index.ts
|
|
10624
11191
|
import { Command as Command16 } from "commander";
|
|
10625
11192
|
|
|
10626
|
-
// src/commands/bucket/
|
|
11193
|
+
// src/commands/bucket/bulk.ts
|
|
10627
11194
|
init_constants2();
|
|
10628
|
-
import {
|
|
10629
|
-
import {
|
|
10630
|
-
|
|
10631
|
-
|
|
11195
|
+
import { existsSync as existsSync22, statSync as statSync3 } from "fs";
|
|
11196
|
+
import { join as join35 } from "path";
|
|
11197
|
+
import { Miniflare as Miniflare12 } from "miniflare";
|
|
11198
|
+
async function runBucketBulkRemote(directory, options) {
|
|
11199
|
+
const environment = ensureEnvironment(options.env);
|
|
11200
|
+
const client = await requireAuthenticatedClient();
|
|
11201
|
+
const workspace = getWorkspace();
|
|
11202
|
+
const deployedGame = await getDeployedGame(workspace);
|
|
11203
|
+
if (!deployedGame) {
|
|
10632
11204
|
if (!options.raw && !options.json) {
|
|
11205
|
+
logger.admonition("warning", "Deploy First", [
|
|
11206
|
+
`Deploy your game before accessing remote bucket: \`playcademy deploy\``
|
|
11207
|
+
]);
|
|
10633
11208
|
logger.newLine();
|
|
10634
11209
|
}
|
|
10635
|
-
|
|
10636
|
-
|
|
10637
|
-
|
|
10638
|
-
|
|
10639
|
-
|
|
10640
|
-
|
|
10641
|
-
|
|
10642
|
-
"For now, bucket commands only work with local development storage."
|
|
10643
|
-
]);
|
|
10644
|
-
logger.newLine();
|
|
10645
|
-
}
|
|
10646
|
-
process.exit(1);
|
|
11210
|
+
process.exit(1);
|
|
11211
|
+
}
|
|
11212
|
+
const { files, totalSize } = collectBulkFiles(directory);
|
|
11213
|
+
if (files.length === 0) {
|
|
11214
|
+
if (!options.raw && !options.json) {
|
|
11215
|
+
logger.warn("No files found to upload");
|
|
11216
|
+
logger.newLine();
|
|
10647
11217
|
}
|
|
10648
|
-
|
|
10649
|
-
|
|
10650
|
-
|
|
10651
|
-
|
|
10652
|
-
|
|
10653
|
-
|
|
10654
|
-
|
|
10655
|
-
|
|
11218
|
+
process.exit(0);
|
|
11219
|
+
}
|
|
11220
|
+
if (options.dryRun) {
|
|
11221
|
+
outputDryRunResults(files, totalSize, options.prefix, options.json, options.raw);
|
|
11222
|
+
return;
|
|
11223
|
+
}
|
|
11224
|
+
const game = await client.games.fetch(deployedGame.gameId);
|
|
11225
|
+
const uploaded = await uploadFilesRemote(
|
|
11226
|
+
files,
|
|
11227
|
+
game.slug,
|
|
11228
|
+
options.prefix,
|
|
11229
|
+
client.dev.games.bucket.put.bind(client.dev.games.bucket)
|
|
11230
|
+
);
|
|
11231
|
+
outputUploadResults(uploaded, totalSize, environment, options.prefix, options.json, options.raw);
|
|
11232
|
+
}
|
|
11233
|
+
async function runBucketBulkLocal(directory, options) {
|
|
11234
|
+
const config = await loadConfig();
|
|
11235
|
+
if (!hasBucketSetup(config)) {
|
|
11236
|
+
if (!options.raw && !options.json) {
|
|
11237
|
+
logger.error("Bucket storage is not configured");
|
|
11238
|
+
logger.newLine();
|
|
11239
|
+
logger.admonition("tip", "Getting Started", [
|
|
11240
|
+
"Run `playcademy bucket init` to enable bucket storage"
|
|
11241
|
+
]);
|
|
11242
|
+
logger.newLine();
|
|
10656
11243
|
}
|
|
10657
|
-
|
|
10658
|
-
|
|
11244
|
+
process.exit(1);
|
|
11245
|
+
}
|
|
11246
|
+
const { files, totalSize } = collectBulkFiles(directory);
|
|
11247
|
+
if (files.length === 0) {
|
|
11248
|
+
if (!options.raw && !options.json) {
|
|
11249
|
+
logger.warn("No files found to upload");
|
|
11250
|
+
logger.newLine();
|
|
11251
|
+
}
|
|
11252
|
+
process.exit(0);
|
|
11253
|
+
}
|
|
11254
|
+
if (options.dryRun) {
|
|
11255
|
+
outputDryRunResults(files, totalSize, options.prefix, options.json, options.raw);
|
|
11256
|
+
return;
|
|
11257
|
+
}
|
|
11258
|
+
const bucketDir = join35(getWorkspace(), CLI_DIRECTORIES.BUCKET);
|
|
11259
|
+
const mf = new Miniflare12({
|
|
11260
|
+
modules: [{ type: "ESModule", path: "index.mjs", contents: "" }],
|
|
11261
|
+
r2Buckets: [CLOUDFLARE_BINDINGS.BUCKET],
|
|
11262
|
+
r2Persist: bucketDir,
|
|
11263
|
+
compatibilityDate: CLOUDFLARE_COMPATIBILITY_DATE
|
|
11264
|
+
});
|
|
11265
|
+
try {
|
|
11266
|
+
const bucket = await mf.getR2Bucket(CLOUDFLARE_BINDINGS.BUCKET);
|
|
11267
|
+
const uploaded = await uploadFilesLocal(
|
|
11268
|
+
files,
|
|
11269
|
+
options.prefix,
|
|
11270
|
+
async (key, content, contentType) => {
|
|
11271
|
+
await bucket.put(key, content, {
|
|
11272
|
+
httpMetadata: {
|
|
11273
|
+
contentType
|
|
11274
|
+
}
|
|
11275
|
+
});
|
|
11276
|
+
}
|
|
11277
|
+
);
|
|
11278
|
+
outputUploadResults(
|
|
11279
|
+
uploaded,
|
|
11280
|
+
totalSize,
|
|
11281
|
+
void 0,
|
|
11282
|
+
options.prefix,
|
|
11283
|
+
options.json,
|
|
11284
|
+
options.raw
|
|
11285
|
+
);
|
|
11286
|
+
} finally {
|
|
11287
|
+
await mf.dispose();
|
|
11288
|
+
}
|
|
11289
|
+
}
|
|
11290
|
+
async function runBucketBulk(directory, options = {}) {
|
|
11291
|
+
try {
|
|
11292
|
+
if (!options.raw && !options.json) {
|
|
11293
|
+
logger.newLine();
|
|
11294
|
+
}
|
|
11295
|
+
if (!existsSync22(directory)) {
|
|
10659
11296
|
if (!options.raw && !options.json) {
|
|
10660
|
-
logger.error(
|
|
11297
|
+
logger.error(`Directory not found: ${directory}`);
|
|
10661
11298
|
logger.newLine();
|
|
10662
|
-
|
|
10663
|
-
|
|
10664
|
-
|
|
11299
|
+
}
|
|
11300
|
+
process.exit(1);
|
|
11301
|
+
}
|
|
11302
|
+
const stats = statSync3(directory);
|
|
11303
|
+
if (!stats.isDirectory()) {
|
|
11304
|
+
if (!options.raw && !options.json) {
|
|
11305
|
+
logger.error(`Not a directory: ${directory}`);
|
|
10665
11306
|
logger.newLine();
|
|
10666
11307
|
}
|
|
10667
11308
|
process.exit(1);
|
|
10668
11309
|
}
|
|
10669
|
-
|
|
10670
|
-
|
|
10671
|
-
|
|
10672
|
-
|
|
10673
|
-
|
|
10674
|
-
|
|
11310
|
+
if (options.remote) {
|
|
11311
|
+
await runBucketBulkRemote(directory, options);
|
|
11312
|
+
} else {
|
|
11313
|
+
await runBucketBulkLocal(directory, options);
|
|
11314
|
+
}
|
|
11315
|
+
} catch (error) {
|
|
11316
|
+
if (!options.raw && !options.json) {
|
|
11317
|
+
logger.error(
|
|
11318
|
+
`Failed to bulk upload: ${error instanceof Error ? error.message : String(error)}`
|
|
11319
|
+
);
|
|
11320
|
+
logger.newLine();
|
|
11321
|
+
}
|
|
11322
|
+
process.exit(1);
|
|
11323
|
+
}
|
|
11324
|
+
}
|
|
11325
|
+
|
|
11326
|
+
// src/commands/bucket/delete.ts
|
|
11327
|
+
init_constants2();
|
|
11328
|
+
import { join as join36 } from "path";
|
|
11329
|
+
import { Miniflare as Miniflare13 } from "miniflare";
|
|
11330
|
+
async function runBucketDeleteRemote(key, options) {
|
|
11331
|
+
const environment = ensureEnvironment(options.env);
|
|
11332
|
+
const client = await requireAuthenticatedClient();
|
|
11333
|
+
const workspace = getWorkspace();
|
|
11334
|
+
const deployedGame = await getDeployedGame(workspace);
|
|
11335
|
+
if (!deployedGame) {
|
|
11336
|
+
if (!options.raw && !options.json) {
|
|
11337
|
+
logger.admonition("warning", "Deploy First", [
|
|
11338
|
+
`Deploy your game before accessing remote bucket: \`playcademy deploy\``
|
|
11339
|
+
]);
|
|
11340
|
+
logger.newLine();
|
|
11341
|
+
}
|
|
11342
|
+
process.exit(1);
|
|
11343
|
+
}
|
|
11344
|
+
const game = await client.games.fetch(deployedGame.gameId);
|
|
11345
|
+
await client.dev.games.bucket.delete(game.slug, key);
|
|
11346
|
+
if (options.json) {
|
|
11347
|
+
logger.json({
|
|
11348
|
+
success: true,
|
|
11349
|
+
key,
|
|
11350
|
+
message: "File deleted successfully"
|
|
10675
11351
|
});
|
|
10676
|
-
|
|
10677
|
-
|
|
10678
|
-
|
|
10679
|
-
|
|
10680
|
-
|
|
10681
|
-
|
|
10682
|
-
|
|
10683
|
-
|
|
10684
|
-
|
|
10685
|
-
|
|
10686
|
-
|
|
10687
|
-
|
|
10688
|
-
|
|
10689
|
-
|
|
10690
|
-
|
|
10691
|
-
|
|
10692
|
-
|
|
10693
|
-
|
|
10694
|
-
|
|
10695
|
-
|
|
10696
|
-
|
|
10697
|
-
|
|
10698
|
-
|
|
10699
|
-
|
|
10700
|
-
|
|
10701
|
-
|
|
11352
|
+
return;
|
|
11353
|
+
}
|
|
11354
|
+
if (options.raw) {
|
|
11355
|
+
logger.raw(`Deleted ${key}`);
|
|
11356
|
+
return;
|
|
11357
|
+
}
|
|
11358
|
+
logger.newLine();
|
|
11359
|
+
logger.success(`Deleted '${key}' from ${environment}`);
|
|
11360
|
+
logger.newLine();
|
|
11361
|
+
}
|
|
11362
|
+
async function runBucketDeleteLocal(key, options) {
|
|
11363
|
+
if (!key) {
|
|
11364
|
+
if (!options.raw && !options.json) {
|
|
11365
|
+
logger.error("File key is required");
|
|
11366
|
+
logger.newLine();
|
|
11367
|
+
logger.admonition("tip", "Usage", ["`playcademy bucket delete <key>`"]);
|
|
11368
|
+
logger.newLine();
|
|
11369
|
+
}
|
|
11370
|
+
process.exit(1);
|
|
11371
|
+
}
|
|
11372
|
+
const config = await loadConfig();
|
|
11373
|
+
if (!hasBucketSetup(config)) {
|
|
11374
|
+
if (!options.raw && !options.json) {
|
|
11375
|
+
logger.error("Bucket storage is not configured");
|
|
11376
|
+
logger.newLine();
|
|
11377
|
+
logger.admonition("tip", "Getting Started", [
|
|
11378
|
+
"Run `playcademy bucket init` to enable bucket storage"
|
|
11379
|
+
]);
|
|
11380
|
+
logger.newLine();
|
|
11381
|
+
}
|
|
11382
|
+
process.exit(1);
|
|
11383
|
+
}
|
|
11384
|
+
const bucketDir = join36(getWorkspace(), CLI_DIRECTORIES.BUCKET);
|
|
11385
|
+
const mf = new Miniflare13({
|
|
11386
|
+
modules: [{ type: "ESModule", path: "index.mjs", contents: "" }],
|
|
11387
|
+
r2Buckets: [CLOUDFLARE_BINDINGS.BUCKET],
|
|
11388
|
+
r2Persist: bucketDir,
|
|
11389
|
+
compatibilityDate: CLOUDFLARE_COMPATIBILITY_DATE
|
|
11390
|
+
});
|
|
11391
|
+
try {
|
|
11392
|
+
const bucket = await mf.getR2Bucket(CLOUDFLARE_BINDINGS.BUCKET);
|
|
11393
|
+
const object = await bucket.get(key);
|
|
11394
|
+
if (!object) {
|
|
11395
|
+
if (!options.raw && !options.json) {
|
|
11396
|
+
logger.warn(`File '${key}' not found`);
|
|
11397
|
+
logger.newLine();
|
|
11398
|
+
logger.admonition("tip", "Hint", [
|
|
11399
|
+
"Use `playcademy bucket list` to see all available files"
|
|
11400
|
+
]);
|
|
11401
|
+
logger.newLine();
|
|
10702
11402
|
}
|
|
10703
|
-
|
|
11403
|
+
process.exit(1);
|
|
11404
|
+
}
|
|
11405
|
+
await bucket.delete(key);
|
|
11406
|
+
if (options.json) {
|
|
11407
|
+
logger.json({
|
|
11408
|
+
success: true,
|
|
11409
|
+
key,
|
|
11410
|
+
message: "File deleted successfully"
|
|
11411
|
+
});
|
|
11412
|
+
return;
|
|
11413
|
+
}
|
|
11414
|
+
if (options.raw) {
|
|
11415
|
+
logger.raw(`Deleted ${key}`);
|
|
11416
|
+
return;
|
|
11417
|
+
}
|
|
11418
|
+
logger.success(`Deleted '${key}'`);
|
|
11419
|
+
logger.newLine();
|
|
11420
|
+
} finally {
|
|
11421
|
+
await mf.dispose();
|
|
11422
|
+
}
|
|
11423
|
+
}
|
|
11424
|
+
async function runBucketDelete(key, options = {}) {
|
|
11425
|
+
try {
|
|
11426
|
+
if (!options.raw && !options.json) {
|
|
10704
11427
|
logger.newLine();
|
|
10705
|
-
}
|
|
10706
|
-
|
|
11428
|
+
}
|
|
11429
|
+
if (options.remote) {
|
|
11430
|
+
await runBucketDeleteRemote(key, options);
|
|
11431
|
+
} else {
|
|
11432
|
+
await runBucketDeleteLocal(key, options);
|
|
10707
11433
|
}
|
|
10708
11434
|
} catch (error) {
|
|
10709
11435
|
if (!options.raw && !options.json) {
|
|
@@ -10719,108 +11445,171 @@ async function runBucketDelete(key, options = {}) {
|
|
|
10719
11445
|
// src/commands/bucket/get.ts
|
|
10720
11446
|
init_constants2();
|
|
10721
11447
|
import { writeFileSync as writeFileSync10 } from "fs";
|
|
10722
|
-
import { join as
|
|
10723
|
-
import { Miniflare as
|
|
10724
|
-
async function
|
|
10725
|
-
|
|
11448
|
+
import { join as join37 } from "path";
|
|
11449
|
+
import { Miniflare as Miniflare14 } from "miniflare";
|
|
11450
|
+
async function runBucketGetRemote(key, options) {
|
|
11451
|
+
const environment = ensureEnvironment(options.env);
|
|
11452
|
+
const client = await requireAuthenticatedClient();
|
|
11453
|
+
const workspace = getWorkspace();
|
|
11454
|
+
const deployedGame = await getDeployedGame(workspace);
|
|
11455
|
+
if (!deployedGame) {
|
|
10726
11456
|
if (!options.raw && !options.json) {
|
|
11457
|
+
logger.admonition("warning", "Deploy First", [
|
|
11458
|
+
`Deploy your game before accessing remote bucket: \`playcademy deploy\``
|
|
11459
|
+
]);
|
|
10727
11460
|
logger.newLine();
|
|
10728
11461
|
}
|
|
10729
|
-
|
|
11462
|
+
process.exit(1);
|
|
11463
|
+
}
|
|
11464
|
+
const game = await client.games.fetch(deployedGame.gameId);
|
|
11465
|
+
let arrayBuffer;
|
|
11466
|
+
try {
|
|
11467
|
+
arrayBuffer = await client.dev.games.bucket.get(game.slug, key);
|
|
11468
|
+
} catch (error) {
|
|
11469
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
11470
|
+
if (errorMessage.includes("not found")) {
|
|
10730
11471
|
if (!options.raw && !options.json) {
|
|
11472
|
+
logger.warn(`File '${key}' not found in ${environment}`);
|
|
10731
11473
|
logger.newLine();
|
|
10732
|
-
logger.
|
|
10733
|
-
|
|
10734
|
-
logger.admonition("info", "Coming Soon", [
|
|
10735
|
-
"Remote bucket support is on the roadmap and will be available soon.",
|
|
10736
|
-
"For now, bucket commands only work with local development storage."
|
|
11474
|
+
logger.admonition("note", "Hint", [
|
|
11475
|
+
`Use \`playcademy bucket list --remote\` to see all available files`
|
|
10737
11476
|
]);
|
|
10738
11477
|
logger.newLine();
|
|
10739
11478
|
}
|
|
10740
11479
|
process.exit(1);
|
|
10741
11480
|
}
|
|
10742
|
-
|
|
11481
|
+
throw error;
|
|
11482
|
+
}
|
|
11483
|
+
if (options.json) {
|
|
11484
|
+
logger.json({
|
|
11485
|
+
key,
|
|
11486
|
+
size: arrayBuffer.byteLength,
|
|
11487
|
+
message: "Use --output to save file"
|
|
11488
|
+
});
|
|
11489
|
+
return;
|
|
11490
|
+
}
|
|
11491
|
+
if (options.output) {
|
|
11492
|
+
writeFileSync10(options.output, Buffer.from(arrayBuffer));
|
|
11493
|
+
if (!options.raw) {
|
|
11494
|
+
logger.newLine();
|
|
11495
|
+
logger.success(`Downloaded '${key}' from ${environment} to '${options.output}'`);
|
|
11496
|
+
logger.newLine();
|
|
11497
|
+
logger.data("Size", `${arrayBuffer.byteLength} bytes`, 1);
|
|
11498
|
+
logger.newLine();
|
|
11499
|
+
}
|
|
11500
|
+
return;
|
|
11501
|
+
}
|
|
11502
|
+
if (options.raw) {
|
|
11503
|
+
process.stdout.write(Buffer.from(arrayBuffer));
|
|
11504
|
+
return;
|
|
11505
|
+
}
|
|
11506
|
+
logger.newLine();
|
|
11507
|
+
logger.success(`File: ${key}`);
|
|
11508
|
+
logger.newLine();
|
|
11509
|
+
logger.data("Size", `${arrayBuffer.byteLength} bytes`, 1);
|
|
11510
|
+
logger.data("Environment", environment, 1);
|
|
11511
|
+
logger.newLine();
|
|
11512
|
+
logger.admonition("note", "Download File", [
|
|
11513
|
+
`Use \`playcademy bucket get ${key} --output path/to/file --remote\` to download`
|
|
11514
|
+
]);
|
|
11515
|
+
logger.newLine();
|
|
11516
|
+
}
|
|
11517
|
+
async function runBucketGetLocal(key, options) {
|
|
11518
|
+
if (!key) {
|
|
11519
|
+
if (!options.raw && !options.json) {
|
|
11520
|
+
logger.error("File key is required");
|
|
11521
|
+
logger.newLine();
|
|
11522
|
+
logger.admonition("note", "Usage", [
|
|
11523
|
+
"`playcademy bucket get <key> --output path/to/file`"
|
|
11524
|
+
]);
|
|
11525
|
+
logger.newLine();
|
|
11526
|
+
}
|
|
11527
|
+
process.exit(1);
|
|
11528
|
+
}
|
|
11529
|
+
const config = await loadConfig();
|
|
11530
|
+
if (!hasBucketSetup(config)) {
|
|
11531
|
+
if (!options.raw && !options.json) {
|
|
11532
|
+
logger.error("Bucket storage is not configured");
|
|
11533
|
+
logger.newLine();
|
|
11534
|
+
logger.admonition("tip", "Getting Started", [
|
|
11535
|
+
"Run `playcademy bucket init` to enable bucket storage"
|
|
11536
|
+
]);
|
|
11537
|
+
logger.newLine();
|
|
11538
|
+
}
|
|
11539
|
+
process.exit(1);
|
|
11540
|
+
}
|
|
11541
|
+
const bucketDir = join37(getWorkspace(), CLI_DIRECTORIES.BUCKET);
|
|
11542
|
+
const mf = new Miniflare14({
|
|
11543
|
+
modules: [{ type: "ESModule", path: "index.mjs", contents: "" }],
|
|
11544
|
+
r2Buckets: [CLOUDFLARE_BINDINGS.BUCKET],
|
|
11545
|
+
r2Persist: bucketDir,
|
|
11546
|
+
compatibilityDate: CLOUDFLARE_COMPATIBILITY_DATE
|
|
11547
|
+
});
|
|
11548
|
+
try {
|
|
11549
|
+
const bucket = await mf.getR2Bucket(CLOUDFLARE_BINDINGS.BUCKET);
|
|
11550
|
+
const object = await bucket.get(key);
|
|
11551
|
+
if (!object) {
|
|
10743
11552
|
if (!options.raw && !options.json) {
|
|
10744
|
-
logger.
|
|
11553
|
+
logger.warn(`Failed to get object: File '${key}' not found`);
|
|
10745
11554
|
logger.newLine();
|
|
10746
|
-
logger.admonition("tip", "
|
|
11555
|
+
logger.admonition("tip", "Hint", [
|
|
11556
|
+
"Use `playcademy bucket list` to see all available files"
|
|
11557
|
+
]);
|
|
10747
11558
|
logger.newLine();
|
|
10748
11559
|
}
|
|
10749
11560
|
process.exit(1);
|
|
10750
11561
|
}
|
|
10751
|
-
|
|
10752
|
-
|
|
10753
|
-
|
|
10754
|
-
|
|
11562
|
+
if (options.json) {
|
|
11563
|
+
const metadata = {
|
|
11564
|
+
key: object.key,
|
|
11565
|
+
size: object.size,
|
|
11566
|
+
uploaded: object.uploaded.toISOString(),
|
|
11567
|
+
httpMetadata: object.httpMetadata,
|
|
11568
|
+
customMetadata: object.customMetadata
|
|
11569
|
+
};
|
|
11570
|
+
logger.json(metadata);
|
|
11571
|
+
return;
|
|
11572
|
+
}
|
|
11573
|
+
if (options.output) {
|
|
11574
|
+
const buffer = await object.arrayBuffer();
|
|
11575
|
+
writeFileSync10(options.output, Buffer.from(buffer));
|
|
11576
|
+
if (!options.raw) {
|
|
11577
|
+
logger.success(`Downloaded '${key}' to '${options.output}'`);
|
|
10755
11578
|
logger.newLine();
|
|
10756
|
-
logger.
|
|
10757
|
-
|
|
10758
|
-
]);
|
|
11579
|
+
logger.data("Size", `${object.size} bytes`, 1);
|
|
11580
|
+
logger.data("Content-Type", object.httpMetadata?.contentType || "unknown", 1);
|
|
10759
11581
|
logger.newLine();
|
|
10760
11582
|
}
|
|
10761
|
-
|
|
11583
|
+
return;
|
|
10762
11584
|
}
|
|
10763
|
-
|
|
10764
|
-
|
|
10765
|
-
|
|
10766
|
-
|
|
10767
|
-
|
|
10768
|
-
|
|
10769
|
-
|
|
10770
|
-
|
|
10771
|
-
|
|
10772
|
-
|
|
10773
|
-
|
|
10774
|
-
|
|
10775
|
-
|
|
10776
|
-
|
|
10777
|
-
|
|
10778
|
-
|
|
10779
|
-
|
|
10780
|
-
|
|
10781
|
-
|
|
10782
|
-
|
|
10783
|
-
|
|
10784
|
-
|
|
10785
|
-
const metadata = {
|
|
10786
|
-
key: object.key,
|
|
10787
|
-
size: object.size,
|
|
10788
|
-
uploaded: object.uploaded.toISOString(),
|
|
10789
|
-
httpMetadata: object.httpMetadata,
|
|
10790
|
-
customMetadata: object.customMetadata
|
|
10791
|
-
};
|
|
10792
|
-
logger.json(metadata);
|
|
10793
|
-
return;
|
|
10794
|
-
}
|
|
10795
|
-
if (options.output) {
|
|
10796
|
-
const buffer = await object.arrayBuffer();
|
|
10797
|
-
writeFileSync10(options.output, Buffer.from(buffer));
|
|
10798
|
-
if (!options.raw) {
|
|
10799
|
-
logger.success(`Downloaded '${key}' to '${options.output}'`);
|
|
10800
|
-
logger.newLine();
|
|
10801
|
-
logger.data("Size", `${object.size} bytes`, 1);
|
|
10802
|
-
logger.data("Content-Type", object.httpMetadata?.contentType || "unknown", 1);
|
|
10803
|
-
logger.newLine();
|
|
10804
|
-
}
|
|
10805
|
-
return;
|
|
10806
|
-
}
|
|
10807
|
-
if (options.raw) {
|
|
10808
|
-
const text5 = await object.text();
|
|
10809
|
-
logger.raw(text5);
|
|
10810
|
-
return;
|
|
10811
|
-
}
|
|
10812
|
-
logger.success(`File: ${key}`);
|
|
10813
|
-
logger.newLine();
|
|
10814
|
-
logger.data("Size", `${object.size} bytes`, 1);
|
|
10815
|
-
logger.data("Content-Type", object.httpMetadata?.contentType || "unknown", 1);
|
|
10816
|
-
logger.data("Uploaded", new Date(object.uploaded).toLocaleString(), 1);
|
|
10817
|
-
logger.newLine();
|
|
10818
|
-
logger.admonition("tip", "Download File", [
|
|
10819
|
-
`Use \`playcademy bucket get ${key} --output <file>\` to download`
|
|
10820
|
-
]);
|
|
11585
|
+
if (options.raw) {
|
|
11586
|
+
const text5 = await object.text();
|
|
11587
|
+
logger.raw(text5);
|
|
11588
|
+
return;
|
|
11589
|
+
}
|
|
11590
|
+
logger.success(`File: ${key}`);
|
|
11591
|
+
logger.newLine();
|
|
11592
|
+
logger.data("Size", `${object.size} bytes`, 1);
|
|
11593
|
+
logger.data("Content-Type", object.httpMetadata?.contentType || "unknown", 1);
|
|
11594
|
+
logger.data("Uploaded", new Date(object.uploaded).toLocaleString(), 1);
|
|
11595
|
+
logger.newLine();
|
|
11596
|
+
logger.admonition("note", "Download File", [
|
|
11597
|
+
`Use \`playcademy bucket get ${key} --output path/to/file\` to download`
|
|
11598
|
+
]);
|
|
11599
|
+
logger.newLine();
|
|
11600
|
+
} finally {
|
|
11601
|
+
await mf.dispose();
|
|
11602
|
+
}
|
|
11603
|
+
}
|
|
11604
|
+
async function runBucketGet(key, options = {}) {
|
|
11605
|
+
try {
|
|
11606
|
+
if (!options.raw && !options.json) {
|
|
10821
11607
|
logger.newLine();
|
|
10822
|
-
}
|
|
10823
|
-
|
|
11608
|
+
}
|
|
11609
|
+
if (options.remote) {
|
|
11610
|
+
await runBucketGetRemote(key, options);
|
|
11611
|
+
} else {
|
|
11612
|
+
await runBucketGetLocal(key, options);
|
|
10824
11613
|
}
|
|
10825
11614
|
} catch (error) {
|
|
10826
11615
|
if (!options.raw && !options.json) {
|
|
@@ -10835,7 +11624,7 @@ async function runBucketGet(key, options = {}) {
|
|
|
10835
11624
|
|
|
10836
11625
|
// src/commands/bucket/init.ts
|
|
10837
11626
|
init_constants2();
|
|
10838
|
-
import { input as
|
|
11627
|
+
import { input as input10 } from "@inquirer/prompts";
|
|
10839
11628
|
init_writer();
|
|
10840
11629
|
init_loader2();
|
|
10841
11630
|
var sampleCustomRouteTemplate4 = loadTemplateString("api/sample-custom.ts");
|
|
@@ -10868,7 +11657,7 @@ async function runBucketInit() {
|
|
|
10868
11657
|
logger.success("Added bucket integration to config");
|
|
10869
11658
|
logger.newLine();
|
|
10870
11659
|
if (!hasLocalCustomRoutes(getWorkspace(), config)) {
|
|
10871
|
-
const apiDirectory = await
|
|
11660
|
+
const apiDirectory = await input10({
|
|
10872
11661
|
message: " \u2514\u2500 API routes directory:",
|
|
10873
11662
|
default: DEFAULT_API_ROUTES_DIRECTORY,
|
|
10874
11663
|
validate: (value) => {
|
|
@@ -10909,94 +11698,140 @@ async function runBucketInit() {
|
|
|
10909
11698
|
|
|
10910
11699
|
// src/commands/bucket/list.ts
|
|
10911
11700
|
init_constants2();
|
|
10912
|
-
import { join as
|
|
10913
|
-
import { Miniflare as
|
|
10914
|
-
async function
|
|
10915
|
-
|
|
11701
|
+
import { join as join38 } from "path";
|
|
11702
|
+
import { Miniflare as Miniflare15 } from "miniflare";
|
|
11703
|
+
async function runBucketListRemote(options) {
|
|
11704
|
+
const environment = ensureEnvironment(options.env);
|
|
11705
|
+
const client = await requireAuthenticatedClient();
|
|
11706
|
+
const workspace = getWorkspace();
|
|
11707
|
+
const deployedGame = await getDeployedGame(workspace);
|
|
11708
|
+
if (!deployedGame) {
|
|
10916
11709
|
if (!options.raw && !options.json) {
|
|
11710
|
+
logger.admonition("warning", "Deploy First", [
|
|
11711
|
+
`Deploy your game before accessing remote bucket: \`playcademy deploy\``
|
|
11712
|
+
]);
|
|
10917
11713
|
logger.newLine();
|
|
10918
11714
|
}
|
|
10919
|
-
|
|
10920
|
-
|
|
10921
|
-
|
|
10922
|
-
|
|
10923
|
-
|
|
10924
|
-
|
|
10925
|
-
|
|
10926
|
-
|
|
10927
|
-
|
|
10928
|
-
|
|
10929
|
-
|
|
10930
|
-
process.exit(1);
|
|
11715
|
+
process.exit(1);
|
|
11716
|
+
}
|
|
11717
|
+
const game = await client.games.fetch(deployedGame.gameId);
|
|
11718
|
+
const files = await client.dev.games.bucket.list(game.slug, options.prefix);
|
|
11719
|
+
if (options.json) {
|
|
11720
|
+
logger.json(files);
|
|
11721
|
+
return;
|
|
11722
|
+
}
|
|
11723
|
+
if (options.raw) {
|
|
11724
|
+
for (const file of files) {
|
|
11725
|
+
logger.raw(file.key);
|
|
10931
11726
|
}
|
|
10932
|
-
|
|
10933
|
-
|
|
10934
|
-
|
|
10935
|
-
|
|
10936
|
-
|
|
10937
|
-
|
|
10938
|
-
|
|
10939
|
-
|
|
10940
|
-
|
|
10941
|
-
|
|
10942
|
-
process.exit(1);
|
|
11727
|
+
return;
|
|
11728
|
+
}
|
|
11729
|
+
if (!options.raw && !options.json) {
|
|
11730
|
+
logger.newLine();
|
|
11731
|
+
}
|
|
11732
|
+
if (files.length === 0) {
|
|
11733
|
+
logger.remark("No files found in remote bucket");
|
|
11734
|
+
if (options.prefix) {
|
|
11735
|
+
logger.newLine();
|
|
11736
|
+
logger.data("Prefix", options.prefix, 1);
|
|
10943
11737
|
}
|
|
10944
|
-
|
|
10945
|
-
|
|
10946
|
-
|
|
10947
|
-
|
|
10948
|
-
|
|
10949
|
-
|
|
10950
|
-
|
|
10951
|
-
|
|
10952
|
-
|
|
10953
|
-
|
|
10954
|
-
|
|
10955
|
-
|
|
10956
|
-
|
|
10957
|
-
|
|
10958
|
-
|
|
10959
|
-
|
|
10960
|
-
|
|
10961
|
-
|
|
10962
|
-
|
|
10963
|
-
|
|
10964
|
-
|
|
10965
|
-
|
|
10966
|
-
|
|
10967
|
-
|
|
10968
|
-
|
|
10969
|
-
|
|
10970
|
-
|
|
10971
|
-
|
|
10972
|
-
|
|
10973
|
-
|
|
10974
|
-
|
|
10975
|
-
|
|
10976
|
-
|
|
10977
|
-
|
|
11738
|
+
logger.newLine();
|
|
11739
|
+
return;
|
|
11740
|
+
}
|
|
11741
|
+
logger.success(`Found ${files.length} file${files.length === 1 ? "" : "s"} in ${environment}`);
|
|
11742
|
+
if (options.prefix) {
|
|
11743
|
+
logger.data("Prefix", options.prefix, 1);
|
|
11744
|
+
}
|
|
11745
|
+
logger.newLine();
|
|
11746
|
+
logger.table(
|
|
11747
|
+
files.map((file) => ({
|
|
11748
|
+
Key: file.key,
|
|
11749
|
+
Size: formatBytes2(file.size),
|
|
11750
|
+
Uploaded: new Date(file.uploaded).toLocaleString()
|
|
11751
|
+
}))
|
|
11752
|
+
);
|
|
11753
|
+
logger.newLine();
|
|
11754
|
+
}
|
|
11755
|
+
async function runBucketListLocal(options) {
|
|
11756
|
+
const config = await loadConfig();
|
|
11757
|
+
if (!hasBucketSetup(config)) {
|
|
11758
|
+
if (!options.raw && !options.json) {
|
|
11759
|
+
logger.error("Bucket storage is not configured");
|
|
11760
|
+
logger.newLine();
|
|
11761
|
+
logger.admonition("tip", "Getting Started", [
|
|
11762
|
+
"Run `playcademy bucket init` to enable bucket storage"
|
|
11763
|
+
]);
|
|
11764
|
+
logger.newLine();
|
|
11765
|
+
}
|
|
11766
|
+
process.exit(1);
|
|
11767
|
+
}
|
|
11768
|
+
const bucketDir = join38(getWorkspace(), CLI_DIRECTORIES.BUCKET);
|
|
11769
|
+
const mf = new Miniflare15({
|
|
11770
|
+
modules: [{ type: "ESModule", path: "index.mjs", contents: "" }],
|
|
11771
|
+
r2Buckets: [CLOUDFLARE_BINDINGS.BUCKET],
|
|
11772
|
+
r2Persist: bucketDir,
|
|
11773
|
+
compatibilityDate: CLOUDFLARE_COMPATIBILITY_DATE
|
|
11774
|
+
});
|
|
11775
|
+
try {
|
|
11776
|
+
const bucket = await mf.getR2Bucket(CLOUDFLARE_BINDINGS.BUCKET);
|
|
11777
|
+
const listed = await bucket.list({ prefix: options.prefix });
|
|
11778
|
+
const files = listed.objects;
|
|
11779
|
+
if (options.json) {
|
|
11780
|
+
const fileData = files.map((obj) => ({
|
|
11781
|
+
key: obj.key,
|
|
11782
|
+
size: obj.size,
|
|
11783
|
+
uploaded: obj.uploaded.toISOString()
|
|
11784
|
+
}));
|
|
11785
|
+
logger.json(fileData);
|
|
11786
|
+
return;
|
|
11787
|
+
}
|
|
11788
|
+
if (options.raw) {
|
|
11789
|
+
for (const file of files) {
|
|
11790
|
+
logger.raw(file.key);
|
|
10978
11791
|
}
|
|
10979
|
-
|
|
11792
|
+
return;
|
|
11793
|
+
}
|
|
11794
|
+
if (files.length === 0) {
|
|
11795
|
+
logger.remark("No files found in bucket");
|
|
10980
11796
|
if (options.prefix) {
|
|
11797
|
+
logger.newLine();
|
|
10981
11798
|
logger.data("Prefix", options.prefix, 1);
|
|
10982
11799
|
}
|
|
10983
11800
|
logger.newLine();
|
|
10984
|
-
|
|
10985
|
-
|
|
10986
|
-
|
|
10987
|
-
|
|
10988
|
-
|
|
10989
|
-
|
|
10990
|
-
|
|
11801
|
+
return;
|
|
11802
|
+
}
|
|
11803
|
+
logger.success(`Found ${files.length} file${files.length === 1 ? "" : "s"}`);
|
|
11804
|
+
if (options.prefix) {
|
|
11805
|
+
logger.data("Prefix", options.prefix, 1);
|
|
11806
|
+
}
|
|
11807
|
+
logger.newLine();
|
|
11808
|
+
logger.table(
|
|
11809
|
+
files.map((obj) => ({
|
|
11810
|
+
Key: obj.key,
|
|
11811
|
+
Size: formatBytes2(obj.size),
|
|
11812
|
+
Uploaded: new Date(obj.uploaded).toLocaleString()
|
|
11813
|
+
}))
|
|
11814
|
+
);
|
|
11815
|
+
logger.newLine();
|
|
11816
|
+
if (listed.truncated) {
|
|
11817
|
+
logger.admonition("info", "Truncated Results", [
|
|
11818
|
+
"The list was truncated. Use --prefix to narrow down results."
|
|
11819
|
+
]);
|
|
10991
11820
|
logger.newLine();
|
|
10992
|
-
|
|
10993
|
-
|
|
10994
|
-
|
|
10995
|
-
|
|
10996
|
-
|
|
10997
|
-
|
|
10998
|
-
|
|
10999
|
-
|
|
11821
|
+
}
|
|
11822
|
+
} finally {
|
|
11823
|
+
await mf.dispose();
|
|
11824
|
+
}
|
|
11825
|
+
}
|
|
11826
|
+
async function runBucketList(options = {}) {
|
|
11827
|
+
try {
|
|
11828
|
+
if (!options.raw && !options.json) {
|
|
11829
|
+
logger.newLine();
|
|
11830
|
+
}
|
|
11831
|
+
if (options.remote) {
|
|
11832
|
+
await runBucketListRemote(options);
|
|
11833
|
+
} else {
|
|
11834
|
+
await runBucketListLocal(options);
|
|
11000
11835
|
}
|
|
11001
11836
|
} catch (error) {
|
|
11002
11837
|
if (!options.raw && !options.json) {
|
|
@@ -11008,7 +11843,7 @@ async function runBucketList(options = {}) {
|
|
|
11008
11843
|
process.exit(1);
|
|
11009
11844
|
}
|
|
11010
11845
|
}
|
|
11011
|
-
function
|
|
11846
|
+
function formatBytes2(bytes) {
|
|
11012
11847
|
if (bytes === 0) return "0 B";
|
|
11013
11848
|
const k = 1024;
|
|
11014
11849
|
const sizes = ["B", "KB", "MB", "GB"];
|
|
@@ -11018,94 +11853,137 @@ function formatBytes(bytes) {
|
|
|
11018
11853
|
|
|
11019
11854
|
// src/commands/bucket/put.ts
|
|
11020
11855
|
init_constants2();
|
|
11021
|
-
import { readFileSync as
|
|
11022
|
-
import { join as
|
|
11023
|
-
import { Miniflare as
|
|
11024
|
-
async function
|
|
11856
|
+
import { readFileSync as readFileSync10, statSync as statSync4 } from "fs";
|
|
11857
|
+
import { join as join39 } from "path";
|
|
11858
|
+
import { Miniflare as Miniflare16 } from "miniflare";
|
|
11859
|
+
async function runBucketPutRemote(key, filePath, options) {
|
|
11860
|
+
const environment = ensureEnvironment(options.env);
|
|
11861
|
+
const client = await requireAuthenticatedClient();
|
|
11862
|
+
const workspace = getWorkspace();
|
|
11863
|
+
const deployedGame = await getDeployedGame(workspace);
|
|
11864
|
+
if (!deployedGame) {
|
|
11865
|
+
if (!options.raw && !options.json) {
|
|
11866
|
+
logger.admonition("warning", "Deploy First", [
|
|
11867
|
+
`Deploy your game before accessing remote bucket: \`playcademy deploy\``
|
|
11868
|
+
]);
|
|
11869
|
+
logger.newLine();
|
|
11870
|
+
}
|
|
11871
|
+
process.exit(1);
|
|
11872
|
+
}
|
|
11873
|
+
let fileBuffer;
|
|
11874
|
+
let fileSize;
|
|
11025
11875
|
try {
|
|
11876
|
+
fileBuffer = readFileSync10(filePath);
|
|
11877
|
+
fileSize = statSync4(filePath).size;
|
|
11878
|
+
} catch {
|
|
11026
11879
|
if (!options.raw && !options.json) {
|
|
11880
|
+
logger.error(`File not found: ${filePath}`);
|
|
11027
11881
|
logger.newLine();
|
|
11028
11882
|
}
|
|
11029
|
-
|
|
11030
|
-
|
|
11031
|
-
|
|
11032
|
-
|
|
11033
|
-
|
|
11034
|
-
|
|
11035
|
-
|
|
11036
|
-
|
|
11037
|
-
|
|
11038
|
-
|
|
11039
|
-
|
|
11040
|
-
|
|
11883
|
+
process.exit(1);
|
|
11884
|
+
}
|
|
11885
|
+
const game = await client.games.fetch(deployedGame.gameId);
|
|
11886
|
+
const contentType = getContentType(filePath);
|
|
11887
|
+
await client.dev.games.bucket.put(game.slug, key, fileBuffer, contentType);
|
|
11888
|
+
if (options.json) {
|
|
11889
|
+
logger.json({
|
|
11890
|
+
success: true,
|
|
11891
|
+
key,
|
|
11892
|
+
size: fileSize,
|
|
11893
|
+
uploaded: (/* @__PURE__ */ new Date()).toISOString()
|
|
11894
|
+
});
|
|
11895
|
+
return;
|
|
11896
|
+
}
|
|
11897
|
+
if (options.raw) {
|
|
11898
|
+
logger.raw(`Uploaded ${key}`);
|
|
11899
|
+
return;
|
|
11900
|
+
}
|
|
11901
|
+
logger.newLine();
|
|
11902
|
+
logger.success(`Uploaded '${filePath}' to '${key}' in ${environment}`);
|
|
11903
|
+
logger.newLine();
|
|
11904
|
+
logger.data("Size", `${fileSize} bytes`, 1);
|
|
11905
|
+
logger.data("Content-Type", contentType, 1);
|
|
11906
|
+
logger.newLine();
|
|
11907
|
+
}
|
|
11908
|
+
async function runBucketPutLocal(key, filePath, options) {
|
|
11909
|
+
if (!key || !filePath) {
|
|
11910
|
+
if (!options.raw && !options.json) {
|
|
11911
|
+
logger.error("File key and path are required");
|
|
11912
|
+
logger.newLine();
|
|
11913
|
+
logger.admonition("tip", "Usage", ["`playcademy bucket put <key> <file>`"]);
|
|
11914
|
+
logger.newLine();
|
|
11041
11915
|
}
|
|
11042
|
-
|
|
11043
|
-
|
|
11044
|
-
|
|
11045
|
-
|
|
11046
|
-
|
|
11047
|
-
|
|
11048
|
-
|
|
11049
|
-
|
|
11916
|
+
process.exit(1);
|
|
11917
|
+
}
|
|
11918
|
+
const config = await loadConfig();
|
|
11919
|
+
if (!hasBucketSetup(config)) {
|
|
11920
|
+
if (!options.raw && !options.json) {
|
|
11921
|
+
logger.error("Bucket storage is not configured");
|
|
11922
|
+
logger.newLine();
|
|
11923
|
+
logger.admonition("tip", "Getting Started", [
|
|
11924
|
+
"Run `playcademy bucket init` to enable bucket storage"
|
|
11925
|
+
]);
|
|
11926
|
+
logger.newLine();
|
|
11050
11927
|
}
|
|
11051
|
-
|
|
11052
|
-
|
|
11053
|
-
|
|
11054
|
-
|
|
11055
|
-
|
|
11056
|
-
|
|
11057
|
-
|
|
11058
|
-
|
|
11059
|
-
|
|
11060
|
-
}
|
|
11061
|
-
|
|
11928
|
+
process.exit(1);
|
|
11929
|
+
}
|
|
11930
|
+
let fileBuffer;
|
|
11931
|
+
let fileSize;
|
|
11932
|
+
try {
|
|
11933
|
+
fileBuffer = readFileSync10(filePath);
|
|
11934
|
+
fileSize = statSync4(filePath).size;
|
|
11935
|
+
} catch {
|
|
11936
|
+
if (!options.raw && !options.json) {
|
|
11937
|
+
logger.error(`File not found: ${filePath}`);
|
|
11938
|
+
logger.newLine();
|
|
11062
11939
|
}
|
|
11063
|
-
|
|
11064
|
-
|
|
11065
|
-
|
|
11066
|
-
|
|
11067
|
-
|
|
11068
|
-
|
|
11069
|
-
|
|
11070
|
-
|
|
11071
|
-
|
|
11940
|
+
process.exit(1);
|
|
11941
|
+
}
|
|
11942
|
+
const bucketDir = join39(getWorkspace(), CLI_DIRECTORIES.BUCKET);
|
|
11943
|
+
const mf = new Miniflare16({
|
|
11944
|
+
modules: [{ type: "ESModule", path: "index.mjs", contents: "" }],
|
|
11945
|
+
r2Buckets: [CLOUDFLARE_BINDINGS.BUCKET],
|
|
11946
|
+
r2Persist: bucketDir,
|
|
11947
|
+
compatibilityDate: CLOUDFLARE_COMPATIBILITY_DATE
|
|
11948
|
+
});
|
|
11949
|
+
try {
|
|
11950
|
+
const bucket = await mf.getR2Bucket(CLOUDFLARE_BINDINGS.BUCKET);
|
|
11951
|
+
await bucket.put(key, new Uint8Array(fileBuffer).buffer, {
|
|
11952
|
+
httpMetadata: {
|
|
11953
|
+
contentType: getContentType(filePath)
|
|
11072
11954
|
}
|
|
11073
|
-
process.exit(1);
|
|
11074
|
-
}
|
|
11075
|
-
const bucketDir = join35(getWorkspace(), CLI_DIRECTORIES.BUCKET);
|
|
11076
|
-
const mf = new Miniflare14({
|
|
11077
|
-
modules: [{ type: "ESModule", path: "index.mjs", contents: "" }],
|
|
11078
|
-
r2Buckets: ["BUCKET"],
|
|
11079
|
-
r2Persist: bucketDir,
|
|
11080
|
-
compatibilityDate: CLOUDFLARE_COMPATIBILITY_DATE
|
|
11081
11955
|
});
|
|
11082
|
-
|
|
11083
|
-
|
|
11084
|
-
|
|
11085
|
-
|
|
11086
|
-
|
|
11087
|
-
|
|
11956
|
+
if (options.json) {
|
|
11957
|
+
logger.json({
|
|
11958
|
+
success: true,
|
|
11959
|
+
key,
|
|
11960
|
+
size: fileSize,
|
|
11961
|
+
uploaded: (/* @__PURE__ */ new Date()).toISOString()
|
|
11088
11962
|
});
|
|
11089
|
-
|
|
11090
|
-
|
|
11091
|
-
|
|
11092
|
-
|
|
11093
|
-
|
|
11094
|
-
|
|
11095
|
-
|
|
11096
|
-
|
|
11097
|
-
|
|
11098
|
-
|
|
11099
|
-
|
|
11100
|
-
|
|
11101
|
-
|
|
11102
|
-
|
|
11103
|
-
|
|
11104
|
-
|
|
11105
|
-
|
|
11963
|
+
return;
|
|
11964
|
+
}
|
|
11965
|
+
if (options.raw) {
|
|
11966
|
+
logger.raw(`Uploaded ${key}`);
|
|
11967
|
+
return;
|
|
11968
|
+
}
|
|
11969
|
+
logger.success(`Uploaded '${filePath}' to '${key}'`);
|
|
11970
|
+
logger.newLine();
|
|
11971
|
+
logger.data("Size", `${fileSize} bytes`, 1);
|
|
11972
|
+
logger.data("Content-Type", getContentType(filePath), 1);
|
|
11973
|
+
logger.newLine();
|
|
11974
|
+
} finally {
|
|
11975
|
+
await mf.dispose();
|
|
11976
|
+
}
|
|
11977
|
+
}
|
|
11978
|
+
async function runBucketPut(key, filePath, options = {}) {
|
|
11979
|
+
try {
|
|
11980
|
+
if (!options.raw && !options.json) {
|
|
11106
11981
|
logger.newLine();
|
|
11107
|
-
}
|
|
11108
|
-
|
|
11982
|
+
}
|
|
11983
|
+
if (options.remote) {
|
|
11984
|
+
await runBucketPutRemote(key, filePath, options);
|
|
11985
|
+
} else {
|
|
11986
|
+
await runBucketPutLocal(key, filePath, options);
|
|
11109
11987
|
}
|
|
11110
11988
|
} catch (error) {
|
|
11111
11989
|
if (!options.raw && !options.json) {
|
|
@@ -11117,58 +11995,44 @@ async function runBucketPut(key, filePath, options = {}) {
|
|
|
11117
11995
|
process.exit(1);
|
|
11118
11996
|
}
|
|
11119
11997
|
}
|
|
11120
|
-
function getContentType(filePath) {
|
|
11121
|
-
const ext = filePath.split(".").pop()?.toLowerCase();
|
|
11122
|
-
const types = {
|
|
11123
|
-
jpg: "image/jpeg",
|
|
11124
|
-
jpeg: "image/jpeg",
|
|
11125
|
-
png: "image/png",
|
|
11126
|
-
gif: "image/gif",
|
|
11127
|
-
webp: "image/webp",
|
|
11128
|
-
svg: "image/svg+xml",
|
|
11129
|
-
mp3: "audio/mpeg",
|
|
11130
|
-
wav: "audio/wav",
|
|
11131
|
-
ogg: "audio/ogg",
|
|
11132
|
-
mp4: "video/mp4",
|
|
11133
|
-
webm: "video/webm",
|
|
11134
|
-
pdf: "application/pdf",
|
|
11135
|
-
json: "application/json",
|
|
11136
|
-
txt: "text/plain",
|
|
11137
|
-
html: "text/html",
|
|
11138
|
-
css: "text/css",
|
|
11139
|
-
js: "application/javascript"
|
|
11140
|
-
};
|
|
11141
|
-
return types[ext || ""] || "application/octet-stream";
|
|
11142
|
-
}
|
|
11143
11998
|
|
|
11144
11999
|
// src/commands/bucket/index.ts
|
|
11145
12000
|
var bucketCommand = new Command16("bucket").description("Manage bucket storage integration").action(() => {
|
|
11146
12001
|
bucketCommand.help();
|
|
11147
12002
|
});
|
|
11148
12003
|
bucketCommand.command("init").description("Add bucket storage integration to your project").action(runBucketInit);
|
|
11149
|
-
bucketCommand.command("list").alias("ls").description("List files in
|
|
12004
|
+
bucketCommand.command("list").alias("ls").description("List files in bucket").option("--prefix <prefix>", "Filter files by key prefix").option("--raw", "Output file keys one per line, no formatting").option("--json", "Output as JSON array").option("--remote", "Use remote bucket instead of local").option(
|
|
11150
12005
|
"--env <environment>",
|
|
11151
12006
|
"Environment to use with --remote: staging (default) or production"
|
|
11152
12007
|
).action(runBucketList);
|
|
11153
|
-
bucketCommand.command("get <key>").description("Download a file from
|
|
12008
|
+
bucketCommand.command("get <key>").description("Download a file from bucket").option("-o, --output <path>", "Output file path (required for binary files)").option("--raw", "Output file content to stdout").option("--json", "Output metadata as JSON").option("--remote", "Use remote bucket instead of local").option(
|
|
11154
12009
|
"--env <environment>",
|
|
11155
12010
|
"Environment to use with --remote: staging (default) or production"
|
|
11156
12011
|
).action(runBucketGet);
|
|
11157
|
-
bucketCommand.command("put <key> <file>").description("Upload a file to
|
|
12012
|
+
bucketCommand.command("put <key> <file>").description("Upload a file to bucket").option("--raw", "Output minimal confirmation").option("--json", "Output result as JSON").option("--remote", "Use remote bucket instead of local").option(
|
|
11158
12013
|
"--env <environment>",
|
|
11159
12014
|
"Environment to use with --remote: staging (default) or production"
|
|
11160
12015
|
).action(runBucketPut);
|
|
11161
|
-
bucketCommand.command("delete <key>").alias("del").alias("rm").description("Delete a file from
|
|
12016
|
+
bucketCommand.command("delete <key>").alias("del").alias("rm").description("Delete a file from bucket").option("--raw", "Output minimal confirmation").option("--json", "Output result as JSON").option("--remote", "Use remote bucket instead of local").option(
|
|
11162
12017
|
"--env <environment>",
|
|
11163
12018
|
"Environment to use with --remote: staging (default) or production"
|
|
11164
12019
|
).action(runBucketDelete);
|
|
12020
|
+
bucketCommand.command("bulk <directory>").description(
|
|
12021
|
+
"Upload directory contents to bucket (preserves subdirectory structure, strips source directory name)"
|
|
12022
|
+
).option(
|
|
12023
|
+
"--prefix <prefix>",
|
|
12024
|
+
"Prefix for all uploaded keys (use to include source dir: --prefix assets)"
|
|
12025
|
+
).option("--dry-run", "Show what would be uploaded without uploading").option("--raw", "Output minimal confirmation").option("--json", "Output result as JSON").option("--remote", "Use remote bucket instead of local").option(
|
|
12026
|
+
"--env <environment>",
|
|
12027
|
+
"Environment to use with --remote: staging (default) or production"
|
|
12028
|
+
).action(runBucketBulk);
|
|
11165
12029
|
|
|
11166
12030
|
// src/commands/secret/index.ts
|
|
11167
12031
|
import { Command as Command20 } from "commander";
|
|
11168
12032
|
|
|
11169
12033
|
// src/commands/secret/delete.ts
|
|
11170
12034
|
init_src();
|
|
11171
|
-
import { confirm as
|
|
12035
|
+
import { confirm as confirm10 } from "@inquirer/prompts";
|
|
11172
12036
|
import { Command as Command17 } from "commander";
|
|
11173
12037
|
var deleteCommand2 = new Command17("delete").description("Delete a game secret").argument("<key>", "Secret key to delete").option("--env <environment>", "Environment (staging or production)").option("-f, --force", "Skip confirmation").action(async (key, options) => {
|
|
11174
12038
|
const { env } = options;
|
|
@@ -11188,7 +12052,7 @@ var deleteCommand2 = new Command17("delete").description("Delete a game secret")
|
|
|
11188
12052
|
}
|
|
11189
12053
|
const game = await client.games.fetch(deployedGame.gameId);
|
|
11190
12054
|
if (!options.force) {
|
|
11191
|
-
const confirmed = await
|
|
12055
|
+
const confirmed = await confirm10({
|
|
11192
12056
|
message: `Delete secret "${key}" from "${game.slug}" in ${environment}?`,
|
|
11193
12057
|
default: false
|
|
11194
12058
|
});
|
|
@@ -11354,7 +12218,7 @@ async function listProfilesAction() {
|
|
|
11354
12218
|
var listCommand3 = new Command22("list").alias("ls").description("List all stored authentication profiles").action(listProfilesAction);
|
|
11355
12219
|
|
|
11356
12220
|
// src/commands/profiles/remove.ts
|
|
11357
|
-
import { bold as
|
|
12221
|
+
import { bold as bold8 } from "colorette";
|
|
11358
12222
|
import { Command as Command23 } from "commander";
|
|
11359
12223
|
var removeCommand = new Command23("remove").alias("rm").description('Remove an authentication profile (defaults to "default")').argument("[name]", "Profile name to remove", "default").option("--env <environment>", "Environment to remove profile from (staging or production)").action(async (name, options) => {
|
|
11360
12224
|
const { env } = options;
|
|
@@ -11370,7 +12234,7 @@ var removeCommand = new Command23("remove").alias("rm").description('Remove an a
|
|
|
11370
12234
|
}
|
|
11371
12235
|
await removeProfile(environment, name);
|
|
11372
12236
|
logger.admonition("note", "Removed!", [
|
|
11373
|
-
`Profile ${
|
|
12237
|
+
`Profile ${bold8(name)} removed from ${environment}`,
|
|
11374
12238
|
environment === "production" ? `To re-authenticate run \`playcademy login --env ${environment}\`` : "To re-authenticate run `playcademy login`"
|
|
11375
12239
|
]);
|
|
11376
12240
|
logger.newLine();
|
|
@@ -11381,7 +12245,7 @@ var removeCommand = new Command23("remove").alias("rm").description('Remove an a
|
|
|
11381
12245
|
|
|
11382
12246
|
// src/commands/profiles/reset.ts
|
|
11383
12247
|
init_string();
|
|
11384
|
-
import { confirm as
|
|
12248
|
+
import { confirm as confirm11 } from "@inquirer/prompts";
|
|
11385
12249
|
import { Command as Command24 } from "commander";
|
|
11386
12250
|
var resetCommand = new Command24("reset").description(
|
|
11387
12251
|
"Remove all authentication profiles across all environments (requires confirmation)"
|
|
@@ -11419,7 +12283,7 @@ var resetCommand = new Command24("reset").description(
|
|
|
11419
12283
|
logger.newLine();
|
|
11420
12284
|
}
|
|
11421
12285
|
}
|
|
11422
|
-
const confirmed = await
|
|
12286
|
+
const confirmed = await confirm11({
|
|
11423
12287
|
message: "Are you sure you want to remove all profiles?",
|
|
11424
12288
|
default: false
|
|
11425
12289
|
});
|
|
@@ -11469,7 +12333,7 @@ import { Command as Command31 } from "commander";
|
|
|
11469
12333
|
|
|
11470
12334
|
// src/commands/timeback/cleanup.ts
|
|
11471
12335
|
init_src();
|
|
11472
|
-
import { confirm as
|
|
12336
|
+
import { confirm as confirm12 } from "@inquirer/prompts";
|
|
11473
12337
|
import { Command as Command26 } from "commander";
|
|
11474
12338
|
var cleanupCommand = new Command26("cleanup").description("Remove TimeBack integration for your game").option(
|
|
11475
12339
|
"--env <environment>",
|
|
@@ -11493,7 +12357,7 @@ var cleanupCommand = new Command26("cleanup").description("Remove TimeBack integ
|
|
|
11493
12357
|
return;
|
|
11494
12358
|
}
|
|
11495
12359
|
displayCleanupWarning(integration, game.displayName, logger);
|
|
11496
|
-
const confirmed = await
|
|
12360
|
+
const confirmed = await confirm12({
|
|
11497
12361
|
message: "Are you sure you want to remove TimeBack integration?",
|
|
11498
12362
|
default: false
|
|
11499
12363
|
});
|
|
@@ -11669,7 +12533,7 @@ var setupCommand = new Command28("setup").description("Set up TimeBack integrati
|
|
|
11669
12533
|
// src/commands/timeback/update.ts
|
|
11670
12534
|
init_src();
|
|
11671
12535
|
init_string();
|
|
11672
|
-
import { confirm as
|
|
12536
|
+
import { confirm as confirm13 } from "@inquirer/prompts";
|
|
11673
12537
|
import { green as green4, red as red3 } from "colorette";
|
|
11674
12538
|
import { Command as Command29 } from "commander";
|
|
11675
12539
|
var updateCommand = new Command29("update").description("Update TimeBack integration configuration for your game").option("--verbose, -v", "Output detailed information").option(
|
|
@@ -11750,7 +12614,7 @@ var updateCommand = new Command29("update").description("Update TimeBack integra
|
|
|
11750
12614
|
logger.data(change.label, `${red3(change.current)} \u2192 ${green4(change.next)}`, 1);
|
|
11751
12615
|
}
|
|
11752
12616
|
logger.newLine();
|
|
11753
|
-
const confirmed = await
|
|
12617
|
+
const confirmed = await confirm13({
|
|
11754
12618
|
message: `Update ${changeDetails.length} ${pluralize(changeDetails.length, "field")} in TimeBack?`,
|
|
11755
12619
|
default: false
|
|
11756
12620
|
});
|
|
@@ -11857,7 +12721,7 @@ import { Command as Command33 } from "commander";
|
|
|
11857
12721
|
init_src();
|
|
11858
12722
|
init_constants2();
|
|
11859
12723
|
import { writeFileSync as writeFileSync11 } from "fs";
|
|
11860
|
-
import { join as
|
|
12724
|
+
import { join as join40 } from "path";
|
|
11861
12725
|
import { Command as Command32 } from "commander";
|
|
11862
12726
|
var bundleCommand = new Command32("bundle").description("Bundle and inspect the game backend worker code (for debugging)").option("-o, --output <path>", "Output file path", CLI_DEFAULT_OUTPUTS.WORKER_BUNDLE).option("--minify", "Minify the output").option("--sourcemap", "Include source maps").action(async (options) => {
|
|
11863
12727
|
try {
|
|
@@ -11887,7 +12751,7 @@ var bundleCommand = new Command32("bundle").description("Bundle and inspect the
|
|
|
11887
12751
|
}),
|
|
11888
12752
|
(result) => `Bundled ${formatSize(result.code.length)}`
|
|
11889
12753
|
);
|
|
11890
|
-
const outputPath =
|
|
12754
|
+
const outputPath = join40(workspace, options.output);
|
|
11891
12755
|
writeFileSync11(outputPath, bundle.code, "utf-8");
|
|
11892
12756
|
logger.success(`Bundle saved to ${options.output}`);
|
|
11893
12757
|
logger.newLine();
|
|
@@ -11963,9 +12827,12 @@ export {
|
|
|
11963
12827
|
REQUIRED_FIELDS,
|
|
11964
12828
|
analyzeChanges,
|
|
11965
12829
|
bundleBackend,
|
|
12830
|
+
bundleSeedWorker,
|
|
11966
12831
|
calculateConfigDiff,
|
|
11967
12832
|
calculateDeploymentPlan,
|
|
11968
12833
|
checkTimebackSetup,
|
|
12834
|
+
collectBulkFiles,
|
|
12835
|
+
collectFiles,
|
|
11969
12836
|
compareIntegrationKeys,
|
|
11970
12837
|
confirmDeploymentPlan,
|
|
11971
12838
|
createClient,
|
|
@@ -11990,7 +12857,9 @@ export {
|
|
|
11990
12857
|
ensurePlaycademyGitignore,
|
|
11991
12858
|
ensurePlaycademyTypes,
|
|
11992
12859
|
ensureRootGitignore,
|
|
12860
|
+
executeSeedFile,
|
|
11993
12861
|
findConfigPath,
|
|
12862
|
+
formatBytes,
|
|
11994
12863
|
formatSize,
|
|
11995
12864
|
generateEntryCode,
|
|
11996
12865
|
generateJsConfig,
|
|
@@ -12001,8 +12870,10 @@ export {
|
|
|
12001
12870
|
getBackendSize,
|
|
12002
12871
|
getBaseUrl,
|
|
12003
12872
|
getBestUnit,
|
|
12873
|
+
getBucketKey,
|
|
12004
12874
|
getCallbackUrl,
|
|
12005
12875
|
getCliContext,
|
|
12876
|
+
getContentType,
|
|
12006
12877
|
getCurrentProfile,
|
|
12007
12878
|
getCustomRoutesDirectory,
|
|
12008
12879
|
getCustomRoutesHash,
|
|
@@ -12040,18 +12911,25 @@ export {
|
|
|
12040
12911
|
hashContent,
|
|
12041
12912
|
hashDirectory,
|
|
12042
12913
|
hashFile,
|
|
12914
|
+
importSeedModule,
|
|
12043
12915
|
importTypescriptDefault,
|
|
12044
12916
|
importTypescriptFile,
|
|
12045
12917
|
integrationChangeDetectors,
|
|
12918
|
+
isIgnoredByGitignore,
|
|
12046
12919
|
listProfiles,
|
|
12047
12920
|
loadAuthStore,
|
|
12048
12921
|
loadConfig,
|
|
12049
12922
|
loadDeployConfig,
|
|
12050
12923
|
loadGameStore,
|
|
12924
|
+
loadGitignorePatterns,
|
|
12051
12925
|
logAndExit,
|
|
12052
12926
|
logger,
|
|
12927
|
+
matchesGitignorePattern,
|
|
12053
12928
|
needsBackend,
|
|
12054
12929
|
normalizeEnvironment,
|
|
12930
|
+
normalizeGitignoreEntry,
|
|
12931
|
+
outputDryRunResults,
|
|
12932
|
+
outputUploadResults,
|
|
12055
12933
|
prepareDeploymentContext,
|
|
12056
12934
|
processConfigVariables,
|
|
12057
12935
|
promptForGameInfo,
|
|
@@ -12078,11 +12956,14 @@ export {
|
|
|
12078
12956
|
selectConfigFormat,
|
|
12079
12957
|
selectEnvironment,
|
|
12080
12958
|
setCliContext,
|
|
12959
|
+
shouldSkipFile,
|
|
12081
12960
|
startCallbackServer,
|
|
12082
12961
|
startDevServer,
|
|
12083
12962
|
startHotReload,
|
|
12084
12963
|
timebackChangeDetector,
|
|
12085
12964
|
updateConfigFile,
|
|
12965
|
+
uploadFilesLocal,
|
|
12966
|
+
uploadFilesRemote,
|
|
12086
12967
|
validateApiDirectoryDoesNotExist,
|
|
12087
12968
|
validateBuildPath,
|
|
12088
12969
|
validateConfig,
|