@playcademy/sandbox 0.7.1-beta.6 → 0.7.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/cli.js +83 -25
- package/dist/server.js +83 -25
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1118,7 +1118,7 @@ var package_default;
|
|
|
1118
1118
|
var init_package = __esm(() => {
|
|
1119
1119
|
package_default = {
|
|
1120
1120
|
name: "@playcademy/sandbox",
|
|
1121
|
-
version: "0.7.1-beta.
|
|
1121
|
+
version: "0.7.1-beta.7",
|
|
1122
1122
|
description: "Local development server for Playcademy game development",
|
|
1123
1123
|
type: "module",
|
|
1124
1124
|
exports: {
|
|
@@ -32690,6 +32690,10 @@ var init_assessment_runtime_lock_util = __esm(() => {
|
|
|
32690
32690
|
});
|
|
32691
32691
|
|
|
32692
32692
|
// ../api-core/src/services/bucket.service.ts
|
|
32693
|
+
function hasPagingOptions(options) {
|
|
32694
|
+
return options.cursor !== undefined || options.limit !== undefined || options.delimiter !== undefined;
|
|
32695
|
+
}
|
|
32696
|
+
|
|
32693
32697
|
class BucketService {
|
|
32694
32698
|
deps;
|
|
32695
32699
|
constructor(deps) {
|
|
@@ -32710,16 +32714,18 @@ class BucketService {
|
|
|
32710
32714
|
getBucketName(slug) {
|
|
32711
32715
|
return getGameDeploymentId(slug, this.deps.sstStage);
|
|
32712
32716
|
}
|
|
32713
|
-
async listFiles(slug, user,
|
|
32717
|
+
async listFiles(slug, user, options = {}) {
|
|
32714
32718
|
const game2 = await this.deps.validateDeveloperAccessBySlug(user, slug);
|
|
32715
32719
|
const bucketName = this.getBucketName(game2.slug);
|
|
32716
|
-
const
|
|
32720
|
+
const paged = hasPagingOptions(options);
|
|
32721
|
+
const page = paged ? await this.deps.storage.listObjectsPage(bucketName, options) : { files: await this.deps.storage.listObjects(bucketName, options.prefix) };
|
|
32717
32722
|
setAttributes({
|
|
32718
32723
|
"app.bucket.operation": "list",
|
|
32719
|
-
"app.bucket.file_count": files.length,
|
|
32720
|
-
"app.bucket.key_prefix": BucketService.getKeyPrefix(prefix)
|
|
32724
|
+
"app.bucket.file_count": page.files.length,
|
|
32725
|
+
"app.bucket.key_prefix": BucketService.getKeyPrefix(options.prefix),
|
|
32726
|
+
"app.bucket.paged": paged
|
|
32721
32727
|
});
|
|
32722
|
-
return
|
|
32728
|
+
return page;
|
|
32723
32729
|
}
|
|
32724
32730
|
async getFile(slug, key, user) {
|
|
32725
32731
|
const game2 = await this.deps.validateDeveloperAccessBySlug(user, slug);
|
|
@@ -95256,6 +95262,13 @@ var init_cache_provider = __esm(() => {
|
|
|
95256
95262
|
cache = new Map;
|
|
95257
95263
|
});
|
|
95258
95264
|
|
|
95265
|
+
// ../utils/src/keys.ts
|
|
95266
|
+
function keyLevelEntry(key, prefix, delimiter) {
|
|
95267
|
+
const remainder = key.slice(prefix.length);
|
|
95268
|
+
const cut = remainder.indexOf(delimiter);
|
|
95269
|
+
return cut === -1 ? { name: key, rolled: false } : { name: prefix + remainder.slice(0, cut + delimiter.length), rolled: true };
|
|
95270
|
+
}
|
|
95271
|
+
|
|
95259
95272
|
// src/infrastructure/api/providers/storage.provider.ts
|
|
95260
95273
|
function getBucket(bucketName) {
|
|
95261
95274
|
let bucket = storage.get(bucketName);
|
|
@@ -95269,18 +95282,57 @@ function createSandboxStorageProvider() {
|
|
|
95269
95282
|
return {
|
|
95270
95283
|
async listObjects(bucketName, prefix) {
|
|
95271
95284
|
const bucket = getBucket(bucketName);
|
|
95285
|
+
const keys = [...bucket.keys()].filter((key) => !prefix || key.startsWith(prefix)).toSorted();
|
|
95286
|
+
return keys.map((key) => {
|
|
95287
|
+
const data = bucket.get(key);
|
|
95288
|
+
return {
|
|
95289
|
+
key,
|
|
95290
|
+
size: data.body.length,
|
|
95291
|
+
lastModified: new Date().toISOString(),
|
|
95292
|
+
contentType: data.contentType
|
|
95293
|
+
};
|
|
95294
|
+
});
|
|
95295
|
+
},
|
|
95296
|
+
async listObjectsPage(bucketName, options) {
|
|
95297
|
+
const { cursor: cursor2, delimiter } = options;
|
|
95298
|
+
const all = await this.listObjects(bucketName, options.prefix);
|
|
95299
|
+
let entries;
|
|
95300
|
+
if (delimiter) {
|
|
95301
|
+
const requestPrefix = options.prefix ?? "";
|
|
95302
|
+
const seen = new Set;
|
|
95303
|
+
entries = [];
|
|
95304
|
+
for (const file3 of all) {
|
|
95305
|
+
const entry = keyLevelEntry(file3.key, requestPrefix, delimiter);
|
|
95306
|
+
if (!entry.rolled) {
|
|
95307
|
+
entries.push({ name: entry.name, file: file3 });
|
|
95308
|
+
} else if (!seen.has(entry.name)) {
|
|
95309
|
+
seen.add(entry.name);
|
|
95310
|
+
entries.push({ name: entry.name });
|
|
95311
|
+
}
|
|
95312
|
+
}
|
|
95313
|
+
} else {
|
|
95314
|
+
entries = all.map((file3) => ({ name: file3.key, file: file3 }));
|
|
95315
|
+
}
|
|
95316
|
+
const remaining = cursor2 ? entries.filter((entry) => entry.name > cursor2) : entries;
|
|
95317
|
+
const limit = options.limit ?? 1000;
|
|
95318
|
+
const pageEntries = remaining.slice(0, limit);
|
|
95272
95319
|
const files = [];
|
|
95273
|
-
|
|
95274
|
-
|
|
95275
|
-
|
|
95276
|
-
|
|
95277
|
-
|
|
95278
|
-
|
|
95279
|
-
contentType: data.contentType
|
|
95280
|
-
});
|
|
95320
|
+
const prefixes = [];
|
|
95321
|
+
for (const entry of pageEntries) {
|
|
95322
|
+
if (entry.file) {
|
|
95323
|
+
files.push(entry.file);
|
|
95324
|
+
} else {
|
|
95325
|
+
prefixes.push(entry.name);
|
|
95281
95326
|
}
|
|
95282
95327
|
}
|
|
95283
|
-
|
|
95328
|
+
const page = { files };
|
|
95329
|
+
if (prefixes.length > 0) {
|
|
95330
|
+
page.prefixes = prefixes;
|
|
95331
|
+
}
|
|
95332
|
+
if (remaining.length > limit) {
|
|
95333
|
+
page.cursor = pageEntries[pageEntries.length - 1].name;
|
|
95334
|
+
}
|
|
95335
|
+
return page;
|
|
95284
95336
|
},
|
|
95285
95337
|
async getObject(bucketName, key) {
|
|
95286
95338
|
const bucket = getBucket(bucketName);
|
|
@@ -151126,6 +151178,17 @@ function requireUserId(userId) {
|
|
|
151126
151178
|
}
|
|
151127
151179
|
return userId;
|
|
151128
151180
|
}
|
|
151181
|
+
function parseLimitParam(url4, max2) {
|
|
151182
|
+
const raw2 = url4.searchParams.get("limit");
|
|
151183
|
+
if (raw2 === null) {
|
|
151184
|
+
return;
|
|
151185
|
+
}
|
|
151186
|
+
const limit = Number(raw2);
|
|
151187
|
+
if (!Number.isInteger(limit) || limit < 1 || limit > max2) {
|
|
151188
|
+
throw ApiError.badRequest(`limit must be an integer between 1 and ${max2}`);
|
|
151189
|
+
}
|
|
151190
|
+
return limit;
|
|
151191
|
+
}
|
|
151129
151192
|
var init_params_util = __esm(() => {
|
|
151130
151193
|
init_src5();
|
|
151131
151194
|
init_errors2();
|
|
@@ -151197,8 +151260,10 @@ var init_bucket_controller = __esm(() => {
|
|
|
151197
151260
|
}
|
|
151198
151261
|
const url4 = ctx.url;
|
|
151199
151262
|
const prefix2 = url4.searchParams.get("prefix") || undefined;
|
|
151200
|
-
const
|
|
151201
|
-
|
|
151263
|
+
const cursor2 = url4.searchParams.get("cursor") || undefined;
|
|
151264
|
+
const delimiter = url4.searchParams.get("delimiter") || undefined;
|
|
151265
|
+
const limit = parseLimitParam(url4, 1000);
|
|
151266
|
+
return ctx.services.bucket.listFiles(slug2, ctx.user, { prefix: prefix2, cursor: cursor2, limit, delimiter });
|
|
151202
151267
|
});
|
|
151203
151268
|
getFile = requireDeveloper(async (ctx) => {
|
|
151204
151269
|
const slug2 = ctx.params.slug;
|
|
@@ -151463,14 +151528,7 @@ var init_deployment_state_controller = __esm(() => {
|
|
|
151463
151528
|
});
|
|
151464
151529
|
history = requireDeveloper(async (ctx) => {
|
|
151465
151530
|
const slug2 = requireSlug(ctx.params.slug);
|
|
151466
|
-
const
|
|
151467
|
-
let limit;
|
|
151468
|
-
if (limitParam !== null) {
|
|
151469
|
-
limit = Number(limitParam);
|
|
151470
|
-
if (!Number.isInteger(limit) || limit < 1 || limit > 100) {
|
|
151471
|
-
throw ApiError.badRequest("limit must be an integer between 1 and 100");
|
|
151472
|
-
}
|
|
151473
|
-
}
|
|
151531
|
+
const limit = parseLimitParam(ctx.url, 100);
|
|
151474
151532
|
return ctx.services.deploymentState.history(slug2, ctx.user, { limit });
|
|
151475
151533
|
});
|
|
151476
151534
|
restorePoints = requireDeveloper(async (ctx) => {
|
package/dist/server.js
CHANGED
|
@@ -1117,7 +1117,7 @@ var package_default;
|
|
|
1117
1117
|
var init_package = __esm(() => {
|
|
1118
1118
|
package_default = {
|
|
1119
1119
|
name: "@playcademy/sandbox",
|
|
1120
|
-
version: "0.7.1-beta.
|
|
1120
|
+
version: "0.7.1-beta.7",
|
|
1121
1121
|
description: "Local development server for Playcademy game development",
|
|
1122
1122
|
type: "module",
|
|
1123
1123
|
exports: {
|
|
@@ -32689,6 +32689,10 @@ var init_assessment_runtime_lock_util = __esm(() => {
|
|
|
32689
32689
|
});
|
|
32690
32690
|
|
|
32691
32691
|
// ../api-core/src/services/bucket.service.ts
|
|
32692
|
+
function hasPagingOptions(options) {
|
|
32693
|
+
return options.cursor !== undefined || options.limit !== undefined || options.delimiter !== undefined;
|
|
32694
|
+
}
|
|
32695
|
+
|
|
32692
32696
|
class BucketService {
|
|
32693
32697
|
deps;
|
|
32694
32698
|
constructor(deps) {
|
|
@@ -32709,16 +32713,18 @@ class BucketService {
|
|
|
32709
32713
|
getBucketName(slug) {
|
|
32710
32714
|
return getGameDeploymentId(slug, this.deps.sstStage);
|
|
32711
32715
|
}
|
|
32712
|
-
async listFiles(slug, user,
|
|
32716
|
+
async listFiles(slug, user, options = {}) {
|
|
32713
32717
|
const game2 = await this.deps.validateDeveloperAccessBySlug(user, slug);
|
|
32714
32718
|
const bucketName = this.getBucketName(game2.slug);
|
|
32715
|
-
const
|
|
32719
|
+
const paged = hasPagingOptions(options);
|
|
32720
|
+
const page = paged ? await this.deps.storage.listObjectsPage(bucketName, options) : { files: await this.deps.storage.listObjects(bucketName, options.prefix) };
|
|
32716
32721
|
setAttributes({
|
|
32717
32722
|
"app.bucket.operation": "list",
|
|
32718
|
-
"app.bucket.file_count": files.length,
|
|
32719
|
-
"app.bucket.key_prefix": BucketService.getKeyPrefix(prefix)
|
|
32723
|
+
"app.bucket.file_count": page.files.length,
|
|
32724
|
+
"app.bucket.key_prefix": BucketService.getKeyPrefix(options.prefix),
|
|
32725
|
+
"app.bucket.paged": paged
|
|
32720
32726
|
});
|
|
32721
|
-
return
|
|
32727
|
+
return page;
|
|
32722
32728
|
}
|
|
32723
32729
|
async getFile(slug, key, user) {
|
|
32724
32730
|
const game2 = await this.deps.validateDeveloperAccessBySlug(user, slug);
|
|
@@ -95255,6 +95261,13 @@ var init_cache_provider = __esm(() => {
|
|
|
95255
95261
|
cache = new Map;
|
|
95256
95262
|
});
|
|
95257
95263
|
|
|
95264
|
+
// ../utils/src/keys.ts
|
|
95265
|
+
function keyLevelEntry(key, prefix, delimiter) {
|
|
95266
|
+
const remainder = key.slice(prefix.length);
|
|
95267
|
+
const cut = remainder.indexOf(delimiter);
|
|
95268
|
+
return cut === -1 ? { name: key, rolled: false } : { name: prefix + remainder.slice(0, cut + delimiter.length), rolled: true };
|
|
95269
|
+
}
|
|
95270
|
+
|
|
95258
95271
|
// src/infrastructure/api/providers/storage.provider.ts
|
|
95259
95272
|
function getBucket(bucketName) {
|
|
95260
95273
|
let bucket = storage.get(bucketName);
|
|
@@ -95268,18 +95281,57 @@ function createSandboxStorageProvider() {
|
|
|
95268
95281
|
return {
|
|
95269
95282
|
async listObjects(bucketName, prefix) {
|
|
95270
95283
|
const bucket = getBucket(bucketName);
|
|
95284
|
+
const keys = [...bucket.keys()].filter((key) => !prefix || key.startsWith(prefix)).toSorted();
|
|
95285
|
+
return keys.map((key) => {
|
|
95286
|
+
const data = bucket.get(key);
|
|
95287
|
+
return {
|
|
95288
|
+
key,
|
|
95289
|
+
size: data.body.length,
|
|
95290
|
+
lastModified: new Date().toISOString(),
|
|
95291
|
+
contentType: data.contentType
|
|
95292
|
+
};
|
|
95293
|
+
});
|
|
95294
|
+
},
|
|
95295
|
+
async listObjectsPage(bucketName, options) {
|
|
95296
|
+
const { cursor: cursor2, delimiter } = options;
|
|
95297
|
+
const all = await this.listObjects(bucketName, options.prefix);
|
|
95298
|
+
let entries;
|
|
95299
|
+
if (delimiter) {
|
|
95300
|
+
const requestPrefix = options.prefix ?? "";
|
|
95301
|
+
const seen = new Set;
|
|
95302
|
+
entries = [];
|
|
95303
|
+
for (const file3 of all) {
|
|
95304
|
+
const entry = keyLevelEntry(file3.key, requestPrefix, delimiter);
|
|
95305
|
+
if (!entry.rolled) {
|
|
95306
|
+
entries.push({ name: entry.name, file: file3 });
|
|
95307
|
+
} else if (!seen.has(entry.name)) {
|
|
95308
|
+
seen.add(entry.name);
|
|
95309
|
+
entries.push({ name: entry.name });
|
|
95310
|
+
}
|
|
95311
|
+
}
|
|
95312
|
+
} else {
|
|
95313
|
+
entries = all.map((file3) => ({ name: file3.key, file: file3 }));
|
|
95314
|
+
}
|
|
95315
|
+
const remaining = cursor2 ? entries.filter((entry) => entry.name > cursor2) : entries;
|
|
95316
|
+
const limit = options.limit ?? 1000;
|
|
95317
|
+
const pageEntries = remaining.slice(0, limit);
|
|
95271
95318
|
const files = [];
|
|
95272
|
-
|
|
95273
|
-
|
|
95274
|
-
|
|
95275
|
-
|
|
95276
|
-
|
|
95277
|
-
|
|
95278
|
-
contentType: data.contentType
|
|
95279
|
-
});
|
|
95319
|
+
const prefixes = [];
|
|
95320
|
+
for (const entry of pageEntries) {
|
|
95321
|
+
if (entry.file) {
|
|
95322
|
+
files.push(entry.file);
|
|
95323
|
+
} else {
|
|
95324
|
+
prefixes.push(entry.name);
|
|
95280
95325
|
}
|
|
95281
95326
|
}
|
|
95282
|
-
|
|
95327
|
+
const page = { files };
|
|
95328
|
+
if (prefixes.length > 0) {
|
|
95329
|
+
page.prefixes = prefixes;
|
|
95330
|
+
}
|
|
95331
|
+
if (remaining.length > limit) {
|
|
95332
|
+
page.cursor = pageEntries[pageEntries.length - 1].name;
|
|
95333
|
+
}
|
|
95334
|
+
return page;
|
|
95283
95335
|
},
|
|
95284
95336
|
async getObject(bucketName, key) {
|
|
95285
95337
|
const bucket = getBucket(bucketName);
|
|
@@ -151125,6 +151177,17 @@ function requireUserId(userId) {
|
|
|
151125
151177
|
}
|
|
151126
151178
|
return userId;
|
|
151127
151179
|
}
|
|
151180
|
+
function parseLimitParam(url4, max2) {
|
|
151181
|
+
const raw2 = url4.searchParams.get("limit");
|
|
151182
|
+
if (raw2 === null) {
|
|
151183
|
+
return;
|
|
151184
|
+
}
|
|
151185
|
+
const limit = Number(raw2);
|
|
151186
|
+
if (!Number.isInteger(limit) || limit < 1 || limit > max2) {
|
|
151187
|
+
throw ApiError.badRequest(`limit must be an integer between 1 and ${max2}`);
|
|
151188
|
+
}
|
|
151189
|
+
return limit;
|
|
151190
|
+
}
|
|
151128
151191
|
var init_params_util = __esm(() => {
|
|
151129
151192
|
init_src5();
|
|
151130
151193
|
init_errors2();
|
|
@@ -151196,8 +151259,10 @@ var init_bucket_controller = __esm(() => {
|
|
|
151196
151259
|
}
|
|
151197
151260
|
const url4 = ctx.url;
|
|
151198
151261
|
const prefix2 = url4.searchParams.get("prefix") || undefined;
|
|
151199
|
-
const
|
|
151200
|
-
|
|
151262
|
+
const cursor2 = url4.searchParams.get("cursor") || undefined;
|
|
151263
|
+
const delimiter = url4.searchParams.get("delimiter") || undefined;
|
|
151264
|
+
const limit = parseLimitParam(url4, 1000);
|
|
151265
|
+
return ctx.services.bucket.listFiles(slug2, ctx.user, { prefix: prefix2, cursor: cursor2, limit, delimiter });
|
|
151201
151266
|
});
|
|
151202
151267
|
getFile = requireDeveloper(async (ctx) => {
|
|
151203
151268
|
const slug2 = ctx.params.slug;
|
|
@@ -151462,14 +151527,7 @@ var init_deployment_state_controller = __esm(() => {
|
|
|
151462
151527
|
});
|
|
151463
151528
|
history = requireDeveloper(async (ctx) => {
|
|
151464
151529
|
const slug2 = requireSlug(ctx.params.slug);
|
|
151465
|
-
const
|
|
151466
|
-
let limit;
|
|
151467
|
-
if (limitParam !== null) {
|
|
151468
|
-
limit = Number(limitParam);
|
|
151469
|
-
if (!Number.isInteger(limit) || limit < 1 || limit > 100) {
|
|
151470
|
-
throw ApiError.badRequest("limit must be an integer between 1 and 100");
|
|
151471
|
-
}
|
|
151472
|
-
}
|
|
151530
|
+
const limit = parseLimitParam(ctx.url, 100);
|
|
151473
151531
|
return ctx.services.deploymentState.history(slug2, ctx.user, { limit });
|
|
151474
151532
|
});
|
|
151475
151533
|
restorePoints = requireDeveloper(async (ctx) => {
|