playcademy 0.28.1-beta.6 → 0.28.1-beta.7

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/bucket.js CHANGED
@@ -44,7 +44,7 @@ var GAME_API_ROUTES_DIRECTORY = join2(GAME_SERVER_ROOT_DIRECTORY, "api");
44
44
  // ../better-auth/package.json
45
45
  var package_default = {
46
46
  name: "@playcademy/better-auth",
47
- version: "0.0.21-beta.6",
47
+ version: "0.0.21-beta.7",
48
48
  type: "module",
49
49
  exports: {
50
50
  "./server": {
package/dist/cli.js CHANGED
@@ -1207,7 +1207,7 @@ var SAMPLE_BUCKET_FILENAME = "bucket.ts";
1207
1207
  // ../better-auth/package.json
1208
1208
  var package_default = {
1209
1209
  name: "@playcademy/better-auth",
1210
- version: "0.0.21-beta.6",
1210
+ version: "0.0.21-beta.7",
1211
1211
  type: "module",
1212
1212
  exports: {
1213
1213
  "./server": {
@@ -3042,7 +3042,7 @@ import { existsSync as existsSync11, mkdirSync as mkdirSync5, readFileSync as re
3042
3042
  import { join as join13 } from "node:path";
3043
3043
 
3044
3044
  // src/version.ts
3045
- var cliVersion = false ? "0.0.0-dev" : "0.28.1-beta.6";
3045
+ var cliVersion = false ? "0.0.0-dev" : "0.28.1-beta.7";
3046
3046
 
3047
3047
  // src/lib/init/database.ts
3048
3048
  var drizzleConfigTemplate = loadTemplateString("database/drizzle-config.ts");
package/dist/constants.js CHANGED
@@ -21,7 +21,7 @@ var SAMPLE_BUCKET_FILENAME = "bucket.ts";
21
21
  // ../better-auth/package.json
22
22
  var package_default = {
23
23
  name: "@playcademy/better-auth",
24
- version: "0.0.21-beta.6",
24
+ version: "0.0.21-beta.7",
25
25
  type: "module",
26
26
  exports: {
27
27
  "./server": {
package/dist/db.js CHANGED
@@ -2335,7 +2335,7 @@ var GAME_API_ROUTES_DIRECTORY = join2(GAME_SERVER_ROOT_DIRECTORY, "api");
2335
2335
  // ../better-auth/package.json
2336
2336
  var package_default = {
2337
2337
  name: "@playcademy/better-auth",
2338
- version: "0.0.21-beta.6",
2338
+ version: "0.0.21-beta.7",
2339
2339
  type: "module",
2340
2340
  exports: {
2341
2341
  "./server": {
package/dist/index.d.ts CHANGED
@@ -206,6 +206,8 @@ interface BucketListOptions extends BaseBucketOptions {
206
206
  prefix?: string;
207
207
  /** Show the literal stored R2 keys (`_assets/sprites/hero.a1b2c3d4.svg`) instead of logical paths */
208
208
  literal?: boolean;
209
+ /** List every object under the prefix instead of one directory level */
210
+ recursive?: boolean;
209
211
  }
210
212
  /**
211
213
  * Options for the bucket get command
@@ -257,6 +259,19 @@ interface BucketObjectRef {
257
259
  key: string;
258
260
  size: number;
259
261
  }
262
+ /** One listed object, as the list command displays it. */
263
+ interface ListedObject {
264
+ key: string;
265
+ size: number;
266
+ lastModified: string;
267
+ }
268
+ /** One directory level of a bucket: directory rows plus the files at that level. */
269
+ interface BucketLevelView {
270
+ /** Directory rows (ending with the delimiter), sorted */
271
+ prefixes: string[];
272
+ /** Files at this level, sorted by key */
273
+ files: ListedObject[];
274
+ }
260
275
  /**
261
276
  * Content-addressable asset manifest: maps logical paths to bare content-hashed
262
277
  * keys. Persisted to the bucket as `_manifest.json` (transport-free — the
@@ -1787,4 +1802,4 @@ interface RunShellOptions {
1787
1802
  env?: NodeJS.ProcessEnv;
1788
1803
  }
1789
1804
 
1790
- export type { ApiConfig, ApiErrorResponse, ApiKeyListItem, ApiKeyWithSecret, ApiRequestOptions, ApplySecretsOptions, AssetManifest, AuthProfile, AuthStore, AuthStrategy, AvailableUpdate, BackendDiff, BaseKVOptions, BlockedCode, BucketAdapter, BucketGetOptions, BucketListOptions, BucketMigrateMode, BucketObjectRef, BucketPutOptions, BucketSyncOptions, BuildDiff, BundleOptions, CallbackServerResult, CheckSecretsOptions, CollectedFile, CompatibilityKey, CompatibilityManifest, ConfigDiff, CreateApiKeyResponse, CustomRoutesIntegrationOptions, DashboardConfig, DatabaseIntegrationOptions, DependencyCheck, DeployConfig, DeployNewGameOptions, DeployedGameInfo, DeploymentChanges, DeploymentContext, DeploymentDiffOptions, DeploymentPlan, DeploymentResult, DiscoveredDependency, EngineConfig, EngineType, EnvironmentAuthProfiles, GameBackendBundle, GameBackendDeploymentMetadata, GameBackendFeatures, GameDevServerOptions, GameRuntimePaths, GameStore, HashedFile, InstalledVersions, IntegrationChangeDetector, IntegrationChangeDetectors, IntegrationConfigChange, IntegrationsConfig, IntegrationsDiff, KVClearOptions, KVDeleteOptions, KVDumpOptions, KVGetOptions, KVInspectOptions, KVListOptions, KVSeedOptions, KVSetOptions, KVStatsOptions, KeyMetadata, KeyStats, LoadConfigResult, LogEntry, LogFilters, LogHistoryQuery, LogHistoryResult, LogStreamConfig, LogStreamUrlOptions, LoginCredentials, LoginResponse, MissingSecret, PlaycademyConfig, PluginLogger, PreviewOptions, PreviewResponse, ProjectDirectoryInfo, QueueConfig, RunShellOptions, RuntimeManifest, ScaffoldResult, SecretCommandOptions, SecretListOptions, SecretPushOptions, SecretsSyncOptions, SecretsSyncResult, SignInResponse, SsoCallbackData, Template, TemplateFramework, TemplateHook, TemplateHookOptions, TemplateSource, TimebackBaseConfig, TimebackCourseConfigWithOverrides, TimebackIntegrationConfig, TokenType, UpdateCommand, UpdateExistingGameOptions, Violation, WorkspaceDependencies };
1805
+ export type { ApiConfig, ApiErrorResponse, ApiKeyListItem, ApiKeyWithSecret, ApiRequestOptions, ApplySecretsOptions, AssetManifest, AuthProfile, AuthStore, AuthStrategy, AvailableUpdate, BackendDiff, BaseKVOptions, BlockedCode, BucketAdapter, BucketGetOptions, BucketLevelView, BucketListOptions, BucketMigrateMode, BucketObjectRef, BucketPutOptions, BucketSyncOptions, BuildDiff, BundleOptions, CallbackServerResult, CheckSecretsOptions, CollectedFile, CompatibilityKey, CompatibilityManifest, ConfigDiff, CreateApiKeyResponse, CustomRoutesIntegrationOptions, DashboardConfig, DatabaseIntegrationOptions, DependencyCheck, DeployConfig, DeployNewGameOptions, DeployedGameInfo, DeploymentChanges, DeploymentContext, DeploymentDiffOptions, DeploymentPlan, DeploymentResult, DiscoveredDependency, EngineConfig, EngineType, EnvironmentAuthProfiles, GameBackendBundle, GameBackendDeploymentMetadata, GameBackendFeatures, GameDevServerOptions, GameRuntimePaths, GameStore, HashedFile, InstalledVersions, IntegrationChangeDetector, IntegrationChangeDetectors, IntegrationConfigChange, IntegrationsConfig, IntegrationsDiff, KVClearOptions, KVDeleteOptions, KVDumpOptions, KVGetOptions, KVInspectOptions, KVListOptions, KVSeedOptions, KVSetOptions, KVStatsOptions, KeyMetadata, KeyStats, ListedObject, LoadConfigResult, LogEntry, LogFilters, LogHistoryQuery, LogHistoryResult, LogStreamConfig, LogStreamUrlOptions, LoginCredentials, LoginResponse, MissingSecret, PlaycademyConfig, PluginLogger, PreviewOptions, PreviewResponse, ProjectDirectoryInfo, QueueConfig, RunShellOptions, RuntimeManifest, ScaffoldResult, SecretCommandOptions, SecretListOptions, SecretPushOptions, SecretsSyncOptions, SecretsSyncResult, SignInResponse, SsoCallbackData, Template, TemplateFramework, TemplateHook, TemplateHookOptions, TemplateSource, TimebackBaseConfig, TimebackCourseConfigWithOverrides, TimebackIntegrationConfig, TokenType, UpdateCommand, UpdateExistingGameOptions, Violation, WorkspaceDependencies };
package/dist/index.js CHANGED
@@ -2346,7 +2346,7 @@ var SAMPLE_BUCKET_FILENAME = "bucket.ts";
2346
2346
  // ../better-auth/package.json
2347
2347
  var package_default = {
2348
2348
  name: "@playcademy/better-auth",
2349
- version: "0.0.21-beta.6",
2349
+ version: "0.0.21-beta.7",
2350
2350
  type: "module",
2351
2351
  exports: {
2352
2352
  "./server": {
@@ -6429,7 +6429,7 @@ import { existsSync as existsSync10, mkdirSync as mkdirSync2, readFileSync as re
6429
6429
  import { join as join13 } from "node:path";
6430
6430
 
6431
6431
  // src/version.ts
6432
- var cliVersion = false ? "0.0.0-dev" : "0.28.1-beta.6";
6432
+ var cliVersion = false ? "0.0.0-dev" : "0.28.1-beta.7";
6433
6433
 
6434
6434
  // src/lib/init/database.ts
6435
6435
  var drizzleConfigTemplate = loadTemplateString("database/drizzle-config.ts");
@@ -26777,6 +26777,29 @@ async function withLocalBucket(fn) {
26777
26777
  await session.dispose();
26778
26778
  }
26779
26779
  }
26780
+ async function listLocalObjects(bucket, options = {}) {
26781
+ const objects = [];
26782
+ const prefixes = /* @__PURE__ */ new Set();
26783
+ let cursor2;
26784
+ do {
26785
+ const listOptions = { prefix: options.prefix };
26786
+ if (options.delimiter) {
26787
+ listOptions.delimiter = options.delimiter;
26788
+ }
26789
+ if (cursor2) {
26790
+ listOptions.cursor = cursor2;
26791
+ }
26792
+ const listed = await bucket.list(listOptions);
26793
+ for (const entry of listed.delimitedPrefixes) {
26794
+ prefixes.add(entry);
26795
+ }
26796
+ for (const obj of listed.objects) {
26797
+ objects.push({ key: obj.key, size: obj.size, lastModified: obj.uploaded.toISOString() });
26798
+ }
26799
+ cursor2 = listed.truncated ? listed.cursor : void 0;
26800
+ } while (cursor2);
26801
+ return { objects, prefixes: [...prefixes].toSorted() };
26802
+ }
26780
26803
 
26781
26804
  // src/lib/bucket/dev.ts
26782
26805
  var ASSET_DEV_ROUTE_PREFIX = ASSET_ROUTE_PREFIX;
@@ -26843,6 +26866,342 @@ function buildManifest(hashedFiles) {
26843
26866
  return { version: 1, files };
26844
26867
  }
26845
26868
 
26869
+ // ../utils/src/keys.ts
26870
+ function keyLevelEntry(key, prefix, delimiter) {
26871
+ const remainder = key.slice(prefix.length);
26872
+ const cut = remainder.indexOf(delimiter);
26873
+ return cut === -1 ? { name: key, rolled: false } : { name: prefix + remainder.slice(0, cut + delimiter.length), rolled: true };
26874
+ }
26875
+
26876
+ // src/lib/bucket/level.ts
26877
+ var LEVEL_DELIMITER = "/";
26878
+ function byKey(left, right) {
26879
+ if (left.key === right.key) {
26880
+ return 0;
26881
+ }
26882
+ return left.key < right.key ? -1 : 1;
26883
+ }
26884
+ function rollUpLevel(files, prefix) {
26885
+ const prefixes = /* @__PURE__ */ new Set();
26886
+ const level = [];
26887
+ for (const file of files) {
26888
+ const entry = keyLevelEntry(file.key, prefix, LEVEL_DELIMITER);
26889
+ if (entry.rolled) {
26890
+ prefixes.add(entry.name);
26891
+ } else {
26892
+ level.push(file);
26893
+ }
26894
+ }
26895
+ return {
26896
+ prefixes: [...prefixes].toSorted(),
26897
+ files: level.toSorted(byKey)
26898
+ };
26899
+ }
26900
+ function mergeLevelViews(a, b) {
26901
+ const files = /* @__PURE__ */ new Map();
26902
+ for (const file of [...a.files, ...b.files]) {
26903
+ files.set(file.key, file);
26904
+ }
26905
+ return {
26906
+ prefixes: [.../* @__PURE__ */ new Set([...a.prefixes, ...b.prefixes])].toSorted(),
26907
+ files: [...files.values()].toSorted(byKey)
26908
+ };
26909
+ }
26910
+
26911
+ // src/lib/bucket/resolve.ts
26912
+ var MANIFEST_OBJECT_KEY = `${ASSET_PREFIX}${MANIFEST_KEY}`;
26913
+ function parseManifest(text4) {
26914
+ if (!text4) {
26915
+ return null;
26916
+ }
26917
+ try {
26918
+ const parsed = JSON.parse(text4);
26919
+ return parsed.files && typeof parsed.files === "object" ? parsed : null;
26920
+ } catch {
26921
+ return null;
26922
+ }
26923
+ }
26924
+ function resolveBucketKey(key, manifestText) {
26925
+ const manifest = parseManifest(manifestText);
26926
+ const hashedKey = manifest?.files[key];
26927
+ return hashedKey ? `${ASSET_PREFIX}${hashedKey}` : key;
26928
+ }
26929
+ function manifestLogicalPaths(manifestText) {
26930
+ const manifest = parseManifest(manifestText);
26931
+ return manifest ? Object.keys(manifest.files) : [];
26932
+ }
26933
+ function createLogicalKeyMapper(manifestText) {
26934
+ const manifest = parseManifest(manifestText);
26935
+ if (!manifest) {
26936
+ return (rawKey) => rawKey;
26937
+ }
26938
+ const logicalByHashed = new Map(
26939
+ Object.entries(manifest.files).map(([logical, hashed]) => [hashed, logical])
26940
+ );
26941
+ return (rawKey) => {
26942
+ if (!rawKey.startsWith(ASSET_PREFIX)) {
26943
+ return rawKey;
26944
+ }
26945
+ return logicalByHashed.get(rawKey.slice(ASSET_PREFIX.length)) ?? rawKey;
26946
+ };
26947
+ }
26948
+ async function readLocalManifest(bucket) {
26949
+ const object = await bucket.get(MANIFEST_OBJECT_KEY);
26950
+ return object ? await object.text() : null;
26951
+ }
26952
+ async function readRemoteManifest(client, slug) {
26953
+ try {
26954
+ const buffer = await client.dev.games.bucket.get(slug, MANIFEST_OBJECT_KEY);
26955
+ return new TextDecoder().decode(buffer);
26956
+ } catch {
26957
+ return null;
26958
+ }
26959
+ }
26960
+ function isManifestKey(rawKey) {
26961
+ return rawKey === MANIFEST_OBJECT_KEY;
26962
+ }
26963
+
26964
+ // src/lib/bucket/list-flow.ts
26965
+ function isMachineOutput(options) {
26966
+ return Boolean(options.raw || options.json);
26967
+ }
26968
+ function isFlat(options) {
26969
+ return Boolean(options.recursive) || isMachineOutput(options);
26970
+ }
26971
+ function presentWith(toLogical) {
26972
+ return (objects) => objects.filter((obj) => !isManifestKey(obj.key)).map((obj) => ({ ...obj, key: toLogical(obj.key) }));
26973
+ }
26974
+ function presentObjects(objects, manifestText, literal) {
26975
+ if (literal) {
26976
+ return objects;
26977
+ }
26978
+ return presentWith(createLogicalKeyMapper(manifestText))(objects);
26979
+ }
26980
+ function toListingRow(file) {
26981
+ return {
26982
+ Key: file.key,
26983
+ Size: formatBytes(file.size),
26984
+ Uploaded: new Date(file.lastModified).toLocaleString()
26985
+ };
26986
+ }
26987
+ function renderEmptyListing(location, prefix) {
26988
+ logger.remark(`No files found in ${location}`);
26989
+ if (prefix) {
26990
+ logger.newLine();
26991
+ logger.data("Prefix", prefix, 1);
26992
+ }
26993
+ logger.newLine();
26994
+ }
26995
+ function isEmptyLevel(view) {
26996
+ return view.prefixes.length === 0 && view.files.length === 0;
26997
+ }
26998
+ function renderLevel(view, options, location) {
26999
+ if (isEmptyLevel(view)) {
27000
+ renderEmptyListing(location, options.prefix);
27001
+ return;
27002
+ }
27003
+ const parts = [];
27004
+ if (view.prefixes.length > 0) {
27005
+ parts.push(
27006
+ `${view.prefixes.length} ${pluralize(view.prefixes.length, "directory", "directories")}`
27007
+ );
27008
+ }
27009
+ if (view.files.length > 0) {
27010
+ parts.push(`${view.files.length} ${pluralize(view.files.length, "file")}`);
27011
+ }
27012
+ logger.success(`Found ${parts.join(" and ")} in ${location}`);
27013
+ if (options.prefix) {
27014
+ logger.data("Prefix", options.prefix, 1);
27015
+ }
27016
+ logger.newLine();
27017
+ logger.table([
27018
+ ...view.prefixes.map((entry) => ({ Key: entry, Size: "-", Uploaded: "-" })),
27019
+ ...view.files.map(toListingRow)
27020
+ ]);
27021
+ logger.newLine();
27022
+ if (view.prefixes.length > 0) {
27023
+ logger.remark(
27024
+ "Directories show one level. Descend with --prefix, or pass -r for everything."
27025
+ );
27026
+ logger.newLine();
27027
+ }
27028
+ }
27029
+ function renderFlat(files, options, location, heading) {
27030
+ if (options.json) {
27031
+ logger.json(files);
27032
+ return;
27033
+ }
27034
+ if (options.raw) {
27035
+ for (const file of files) {
27036
+ logger.stdout(file.key);
27037
+ }
27038
+ return;
27039
+ }
27040
+ if (files.length === 0) {
27041
+ renderEmptyListing(location, options.prefix);
27042
+ return;
27043
+ }
27044
+ if (heading) {
27045
+ logger.success(heading);
27046
+ }
27047
+ if (options.prefix) {
27048
+ logger.data("Prefix", options.prefix, 1);
27049
+ }
27050
+ logger.newLine();
27051
+ logger.table(files.map(toListingRow));
27052
+ logger.newLine();
27053
+ }
27054
+ function assetListingPrefix(prefix) {
27055
+ return ASSET_PREFIX + prefix.slice(0, prefix.lastIndexOf(LEVEL_DELIMITER) + 1);
27056
+ }
27057
+ async function assembleLogicalLevel(input2) {
27058
+ const present = presentWith(createLogicalKeyMapper(input2.manifestText));
27059
+ const logicalPaths = manifestLogicalPaths(input2.manifestText);
27060
+ const runtimePrefixes = logicalPaths.length > 0 ? input2.rawLevel.prefixes.filter((entry) => entry !== ASSET_PREFIX) : input2.rawLevel.prefixes;
27061
+ const assetDirs = /* @__PURE__ */ new Set();
27062
+ let hasLeafAssets = false;
27063
+ for (const path4 of logicalPaths) {
27064
+ if (path4.startsWith(input2.prefix)) {
27065
+ const entry = keyLevelEntry(path4, input2.prefix, LEVEL_DELIMITER);
27066
+ if (entry.rolled) {
27067
+ assetDirs.add(entry.name);
27068
+ } else {
27069
+ hasLeafAssets = true;
27070
+ }
27071
+ }
27072
+ }
27073
+ const assetLevel = hasLeafAssets ? await input2.listAssetLevel(assetListingPrefix(input2.prefix)) : { prefixes: [], files: [] };
27074
+ const leafFiles = present(assetLevel.files).filter((file) => file.key.startsWith(input2.prefix));
27075
+ const runtimeLevel = {
27076
+ prefixes: runtimePrefixes,
27077
+ files: present(input2.rawLevel.files)
27078
+ };
27079
+ return mergeLevelViews(runtimeLevel, {
27080
+ prefixes: [...assetDirs].toSorted(),
27081
+ files: leafFiles
27082
+ });
27083
+ }
27084
+ async function fetchRemoteLevel(client, slug, prefix) {
27085
+ const prefixes = /* @__PURE__ */ new Set();
27086
+ const files = [];
27087
+ let cursor2;
27088
+ do {
27089
+ const page = await client.dev.games.bucket.listPage(slug, {
27090
+ prefix,
27091
+ cursor: cursor2,
27092
+ delimiter: LEVEL_DELIMITER
27093
+ });
27094
+ for (const entry of page.prefixes ?? []) {
27095
+ prefixes.add(entry);
27096
+ }
27097
+ for (const file of page.files) {
27098
+ files.push(file);
27099
+ }
27100
+ cursor2 = page.cursor;
27101
+ } while (cursor2);
27102
+ return { prefixes: [...prefixes].toSorted(), files };
27103
+ }
27104
+ async function listRemoteLevel(options) {
27105
+ const environment = ensureEnvironment(options.env);
27106
+ const client = await requireAuthenticatedClient();
27107
+ const game = await resolveGameFromConfig(client, { silent: false });
27108
+ const manifestPromise = options.literal ? null : readRemoteManifest(client, game.slug);
27109
+ const rawLevel = await fetchRemoteLevel(client, game.slug, options.prefix);
27110
+ if (!manifestPromise) {
27111
+ renderLevel(rawLevel, options, environment);
27112
+ return;
27113
+ }
27114
+ const view = await assembleLogicalLevel({
27115
+ rawLevel,
27116
+ manifestText: await manifestPromise,
27117
+ prefix: options.prefix ?? "",
27118
+ listAssetLevel: (assetsPrefix) => fetchRemoteLevel(client, game.slug, assetsPrefix)
27119
+ });
27120
+ renderLevel(view, options, environment);
27121
+ }
27122
+ async function listLocalLevel(options) {
27123
+ const view = await withLocalBucket(async (bucket) => {
27124
+ const listed = await listLocalObjects(bucket, {
27125
+ prefix: options.prefix,
27126
+ delimiter: LEVEL_DELIMITER
27127
+ });
27128
+ const rawLevel = { prefixes: listed.prefixes, files: listed.objects };
27129
+ if (options.literal) {
27130
+ return rawLevel;
27131
+ }
27132
+ return assembleLogicalLevel({
27133
+ rawLevel,
27134
+ manifestText: await readLocalManifest(bucket),
27135
+ prefix: options.prefix ?? "",
27136
+ listAssetLevel: async (assetsPrefix) => {
27137
+ const assets = await listLocalObjects(bucket, {
27138
+ prefix: assetsPrefix,
27139
+ delimiter: LEVEL_DELIMITER
27140
+ });
27141
+ return { prefixes: assets.prefixes, files: assets.objects };
27142
+ }
27143
+ });
27144
+ });
27145
+ renderLevel(view, options, "bucket");
27146
+ }
27147
+ async function listRemoteFlat(options) {
27148
+ const environment = ensureEnvironment(options.env);
27149
+ const client = await requireAuthenticatedClient();
27150
+ const game = await resolveGameFromConfig(client, { silent: isMachineOutput(options) });
27151
+ const rawFiles = await client.dev.games.bucket.list(game.slug, options.prefix);
27152
+ const manifestText = options.literal ? null : await readRemoteManifest(client, game.slug);
27153
+ const files = presentObjects(rawFiles, manifestText, Boolean(options.literal));
27154
+ renderFlat(
27155
+ files,
27156
+ options,
27157
+ environment,
27158
+ `Found ${files.length} ${pluralize(files.length, "file")} in ${environment}`
27159
+ );
27160
+ }
27161
+ async function listLocalFlat(options) {
27162
+ const { rawFiles, manifestText } = await withLocalBucket(async (bucket) => {
27163
+ const listed = await listLocalObjects(bucket, { prefix: options.prefix });
27164
+ return {
27165
+ rawFiles: listed.objects,
27166
+ manifestText: options.literal ? null : await readLocalManifest(bucket)
27167
+ };
27168
+ });
27169
+ const files = presentObjects(rawFiles, manifestText, Boolean(options.literal));
27170
+ renderFlat(files, options, "bucket");
27171
+ }
27172
+ async function runRemoteBucketList(options) {
27173
+ if (!isMachineOutput(options)) {
27174
+ logger.newLine();
27175
+ }
27176
+ if (isFlat(options)) {
27177
+ await listRemoteFlat(options);
27178
+ } else {
27179
+ await listRemoteLevel(options);
27180
+ }
27181
+ }
27182
+ async function runLocalBucketList(options) {
27183
+ const config = await loadConfig();
27184
+ if (!hasBucketSetup(config)) {
27185
+ if (!isMachineOutput(options)) {
27186
+ logger.error("Bucket storage is not configured");
27187
+ logger.admonition("tip", "Getting Started", [
27188
+ "Run `playcademy bucket init` to enable bucket storage",
27189
+ "",
27190
+ "Learn more: <<https://docs.playcademy.net/platform/integrations/bucket>>"
27191
+ ]);
27192
+ }
27193
+ process.exit(1);
27194
+ }
27195
+ if (!isMachineOutput(options)) {
27196
+ logger.newLine();
27197
+ }
27198
+ if (isFlat(options)) {
27199
+ await listLocalFlat(options);
27200
+ } else {
27201
+ await listLocalLevel(options);
27202
+ }
27203
+ }
27204
+
26846
27205
  // src/lib/bucket/migrate.ts
26847
27206
  import { bold as bold13, cyan as cyan7 } from "colorette";
26848
27207
  var SAMPLE_LIMIT = 10;
@@ -27027,55 +27386,6 @@ function outputSyncResults({
27027
27386
  logger.newLine();
27028
27387
  }
27029
27388
 
27030
- // src/lib/bucket/resolve.ts
27031
- var MANIFEST_OBJECT_KEY = `${ASSET_PREFIX}${MANIFEST_KEY}`;
27032
- function parseManifest(text4) {
27033
- if (!text4) {
27034
- return null;
27035
- }
27036
- try {
27037
- const parsed = JSON.parse(text4);
27038
- return parsed.files && typeof parsed.files === "object" ? parsed : null;
27039
- } catch {
27040
- return null;
27041
- }
27042
- }
27043
- function resolveBucketKey(key, manifestText) {
27044
- const manifest = parseManifest(manifestText);
27045
- const hashedKey = manifest?.files[key];
27046
- return hashedKey ? `${ASSET_PREFIX}${hashedKey}` : key;
27047
- }
27048
- function createLogicalKeyMapper(manifestText) {
27049
- const manifest = parseManifest(manifestText);
27050
- if (!manifest) {
27051
- return (rawKey) => rawKey;
27052
- }
27053
- const logicalByHashed = new Map(
27054
- Object.entries(manifest.files).map(([logical, hashed]) => [hashed, logical])
27055
- );
27056
- return (rawKey) => {
27057
- if (!rawKey.startsWith(ASSET_PREFIX)) {
27058
- return rawKey;
27059
- }
27060
- return logicalByHashed.get(rawKey.slice(ASSET_PREFIX.length)) ?? rawKey;
27061
- };
27062
- }
27063
- async function readLocalManifest(bucket) {
27064
- const object = await bucket.get(MANIFEST_OBJECT_KEY);
27065
- return object ? await object.text() : null;
27066
- }
27067
- async function readRemoteManifest(client, slug) {
27068
- try {
27069
- const buffer = await client.dev.games.bucket.get(slug, MANIFEST_OBJECT_KEY);
27070
- return new TextDecoder().decode(buffer);
27071
- } catch {
27072
- return null;
27073
- }
27074
- }
27075
- function isManifestKey(rawKey) {
27076
- return rawKey === MANIFEST_OBJECT_KEY;
27077
- }
27078
-
27079
27389
  // src/lib/bucket/sync.ts
27080
27390
  import { dim as dim13 } from "colorette";
27081
27391
  var R2_ERROR_HINTS = {
@@ -27259,16 +27569,8 @@ function createPresignedAdapter(gameSlug, ops) {
27259
27569
  function createLocalAdapter(bucket) {
27260
27570
  return {
27261
27571
  async list() {
27262
- const objects = [];
27263
- let cursor2;
27264
- do {
27265
- const page = await bucket.list(cursor2 ? { cursor: cursor2 } : {});
27266
- for (const obj of page.objects) {
27267
- objects.push({ key: obj.key, size: obj.size });
27268
- }
27269
- cursor2 = page.truncated ? page.cursor : void 0;
27270
- } while (cursor2);
27271
- return objects;
27572
+ const { objects } = await listLocalObjects(bucket);
27573
+ return objects.map((obj) => ({ key: obj.key, size: obj.size }));
27272
27574
  },
27273
27575
  async put(key, content, contentType) {
27274
27576
  await bucket.put(key, new Uint8Array(content), { httpMetadata: { contentType } });
@@ -28755,6 +29057,7 @@ export {
28755
29057
  GAME_METADATA_DRIFT_LABELS,
28756
29058
  GAME_METRICS_RESOLVER_PATH,
28757
29059
  HISTORY_FETCH_TIMEOUT_MS,
29060
+ LEVEL_DELIMITER,
28758
29061
  MANAGED_PACKAGES,
28759
29062
  MANIFEST_OBJECT_KEY,
28760
29063
  METRICS_RESOLVER_EXTENSIONS,
@@ -28771,6 +29074,7 @@ export {
28771
29074
  analyzeChanges,
28772
29075
  applyEngineSelection,
28773
29076
  applySecretsChanges,
29077
+ assembleLogicalLevel,
28774
29078
  assertDestructiveConfirmToken,
28775
29079
  assertRemoteWhenEnvGiven,
28776
29080
  assessmentFixturePath,
@@ -29027,6 +29331,7 @@ export {
29027
29331
  isStrategyExplicit,
29028
29332
  isVitePluginInstalled,
29029
29333
  listBookmarks,
29334
+ listLocalObjects,
29030
29335
  listProfiles,
29031
29336
  loadAssessmentFixtureBundle,
29032
29337
  loadAuthStore,
@@ -29046,11 +29351,13 @@ export {
29046
29351
  logAndExit,
29047
29352
  logDeploymentPlanDebug,
29048
29353
  logger,
29354
+ manifestLogicalPaths,
29049
29355
  matchCoursesToIntegrations,
29050
29356
  matchRestorePoint,
29051
29357
  matchesFilters,
29052
29358
  matchesGitignorePattern,
29053
29359
  maybeShowUpdateNudge,
29360
+ mergeLevelViews,
29054
29361
  migrateManagedLines,
29055
29362
  migrationSnapshotPath,
29056
29363
  needsSchemaAdoption,
@@ -29157,9 +29464,12 @@ export {
29157
29464
  resolveSchemaStrategy,
29158
29465
  resolveUpgrade,
29159
29466
  restoreUnsupportedLines,
29467
+ rollUpLevel,
29160
29468
  rollbackDisplayName,
29161
29469
  runEmailPasswordLogin,
29162
29470
  runInit,
29471
+ runLocalBucketList,
29472
+ runRemoteBucketList,
29163
29473
  runShell,
29164
29474
  runSsoLogin,
29165
29475
  saveAuthStore,
@@ -1,7 +1,7 @@
1
1
  {
2
- "cliVersion": "0.28.1-beta.6",
3
- "sdkVersion": "0.16.1-beta.6",
4
- "runtimeBuildId": "0a295619c459",
5
- "inputFingerprint": "0a295619c459fabba64e443c7824867a149bce88a5cfee63d7a97852609a617e",
2
+ "cliVersion": "0.28.1-beta.7",
3
+ "sdkVersion": "0.16.1-beta.7",
4
+ "runtimeBuildId": "75a119bffe23",
5
+ "inputFingerprint": "75a119bffe23266fa650f391e9f0bde94d563188b28b69da5641ab4d287dd782",
6
6
  "entry": "index.js"
7
7
  }
@@ -6839,9 +6839,9 @@ var init_list = __esm({
6839
6839
  // ../edge-play/src/game/lib/metadata.ts
6840
6840
  function getRuntimeMetadata() {
6841
6841
  return {
6842
- cliVersion: true ? "0.28.1-beta.6" : "0.0.0-dev",
6843
- sdkVersion: true ? "0.16.1-beta.6" : "0.0.0-dev",
6844
- buildId: true ? "0a295619c459" : "dev-source"
6842
+ cliVersion: true ? "0.28.1-beta.7" : "0.0.0-dev",
6843
+ sdkVersion: true ? "0.16.1-beta.7" : "0.0.0-dev",
6844
+ buildId: true ? "75a119bffe23" : "dev-source"
6845
6845
  };
6846
6846
  }
6847
6847
  var init_metadata = __esm({
@@ -1,7 +1,7 @@
1
1
  {
2
- "cliVersion": "0.28.1-beta.6",
3
- "sdkVersion": "0.16.1-beta.6",
4
- "runtimeBuildId": "0a295619c459",
5
- "inputFingerprint": "0a295619c459fabba64e443c7824867a149bce88a5cfee63d7a97852609a617e",
2
+ "cliVersion": "0.28.1-beta.7",
3
+ "sdkVersion": "0.16.1-beta.7",
4
+ "runtimeBuildId": "75a119bffe23",
5
+ "inputFingerprint": "75a119bffe23266fa650f391e9f0bde94d563188b28b69da5641ab4d287dd782",
6
6
  "entry": "index.js"
7
7
  }
package/dist/utils.js CHANGED
@@ -383,7 +383,7 @@ var DASHBOARD_API_ROUTES_DIRECTORY = "api";
383
383
  // ../better-auth/package.json
384
384
  var package_default = {
385
385
  name: "@playcademy/better-auth",
386
- version: "0.0.21-beta.6",
386
+ version: "0.0.21-beta.7",
387
387
  type: "module",
388
388
  exports: {
389
389
  "./server": {
@@ -2827,7 +2827,7 @@ import { existsSync as existsSync9, mkdirSync as mkdirSync2, writeFileSync as wr
2827
2827
  import { dirname as dirname4, join as join14 } from "node:path";
2828
2828
 
2829
2829
  // src/version.ts
2830
- var cliVersion = false ? "0.0.0-dev" : "0.28.1-beta.6";
2830
+ var cliVersion = false ? "0.0.0-dev" : "0.28.1-beta.7";
2831
2831
 
2832
2832
  // src/lib/build/binary-resource.ts
2833
2833
  function writeFileTree(baseDir, files) {
package/dist/version.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // src/version.ts
2
- var cliVersion = false ? "0.0.0-dev" : "0.28.1-beta.6";
2
+ var cliVersion = false ? "0.0.0-dev" : "0.28.1-beta.7";
3
3
  export {
4
4
  cliVersion
5
5
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "playcademy",
3
- "version": "0.28.1-beta.6",
3
+ "version": "0.28.1-beta.7",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {
@@ -55,7 +55,7 @@
55
55
  },
56
56
  "dependencies": {
57
57
  "@inquirer/prompts": "^7.8.6",
58
- "@playcademy/sdk": "0.16.1-beta.6",
58
+ "@playcademy/sdk": "0.16.1-beta.7",
59
59
  "chokidar": "^4.0.3",
60
60
  "colorette": "^2.0.20",
61
61
  "commander": "^14.0.1",