deepspace 0.15.0 → 0.17.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/worker.js CHANGED
@@ -288,15 +288,6 @@ var MSG = {
288
288
  ACK: "records.ack",
289
289
  LIST_SCHEMAS: "records.list_schemas",
290
290
  RESUBSCRIBE: "records.resubscribe",
291
- // ---- GameRoom --------------------------------------------------------
292
- GAME_STATE: "game.state",
293
- GAME_INPUT: "game.input",
294
- GAME_PLAYER_JOIN: "game.player_join",
295
- GAME_PLAYER_LEAVE: "game.player_leave",
296
- GAME_PLAYER_READY: "game.player_ready",
297
- GAME_START: "game.start",
298
- GAME_END: "game.end",
299
- GAME_TICK: "game.tick",
300
291
  // ---- CanvasRoom ------------------------------------------------------
301
292
  CANVAS_SHAPES: "canvas.shapes",
302
293
  CANVAS_ADD: "canvas.add",
@@ -1006,11 +997,6 @@ var clientBuild = {
1006
997
  // Yjs
1007
998
  yjsJoin: (collection, recordId, fieldName) => ({ type: MSG.YJS_JOIN, payload: { collection, recordId, fieldName } }),
1008
999
  yjsLeave: (collection, recordId, fieldName) => ({ type: MSG.YJS_LEAVE, payload: { collection, recordId, fieldName } }),
1009
- // Game
1010
- gameInput: (action, data = {}) => ({ type: MSG.GAME_INPUT, payload: { action, data } }),
1011
- gamePlayerReady: () => ({ type: MSG.GAME_PLAYER_READY, payload: EMPTY }),
1012
- gameStart: () => ({ type: MSG.GAME_START, payload: EMPTY }),
1013
- gameEnd: () => ({ type: MSG.GAME_END, payload: EMPTY }),
1014
1000
  // Canvas — `CANVAS_ADD` / `CANVAS_VIEWPORT` payloads are flat (the shape
1015
1001
  // or viewport object is the whole payload).
1016
1002
  canvasAdd: (shape) => ({ type: MSG.CANVAS_ADD, payload: shape }),
@@ -1062,14 +1048,6 @@ var serverBuild = {
1062
1048
  type: MSG.YJS_JOIN,
1063
1049
  payload: { collection, recordId, fieldName, canWrite }
1064
1050
  }),
1065
- // Game
1066
- gameState: (state, tick, players, running) => ({ type: MSG.GAME_STATE, payload: { state, tick, players, running } }),
1067
- gameTick: (state, tick) => ({ type: MSG.GAME_TICK, payload: { state, tick } }),
1068
- gameStart: (state, tick) => ({ type: MSG.GAME_START, payload: { state, tick } }),
1069
- gameEnd: (state, tick) => ({ type: MSG.GAME_END, payload: { state, tick } }),
1070
- gamePlayerJoin: (player) => ({ type: MSG.GAME_PLAYER_JOIN, payload: { player } }),
1071
- gamePlayerLeave: (userId) => ({ type: MSG.GAME_PLAYER_LEAVE, payload: { userId } }),
1072
- gamePlayerReady: (userId) => ({ type: MSG.GAME_PLAYER_READY, payload: { userId } }),
1073
1051
  // Canvas
1074
1052
  canvasShapes: (shapes, viewports) => ({ type: MSG.CANVAS_SHAPES, payload: { shapes, viewports } }),
1075
1053
  canvasAdd: (shape) => ({ type: MSG.CANVAS_ADD, payload: { shape } }),
@@ -2795,136 +2773,6 @@ var RecordRoom = class extends BaseRoom {
2795
2773
  );
2796
2774
  `);
2797
2775
  this.ensureAllCollectionTables();
2798
- await this.migrateUsersTableIfExists();
2799
- await this.migrateRecordsTable();
2800
- }
2801
- async migrateUsersTableIfExists() {
2802
- try {
2803
- const tableCheck = this.sql.exec(
2804
- `SELECT name FROM sqlite_master WHERE type='table' AND name='users'`
2805
- );
2806
- if (tableCheck.toArray().length === 0) {
2807
- return;
2808
- }
2809
- const oldUsers = this.sql.exec(`SELECT * FROM users`).toArray();
2810
- if (oldUsers.length === 0) {
2811
- this.sql.exec(`DROP TABLE IF EXISTS users`);
2812
- return;
2813
- }
2814
- const now = (/* @__PURE__ */ new Date()).toISOString();
2815
- for (const row of oldUsers) {
2816
- const r = row;
2817
- const existing = this.sql.exec(`SELECT 1 FROM c_users WHERE _row_id = ?`, r.user_id).toArray();
2818
- if (existing.length > 0) continue;
2819
- this.sql.exec(
2820
- `INSERT INTO c_users (_row_id, _created_by, _created_at, _updated_at, col_email, col_name, col_imageurl, col_role, col_createdat, col_lastseenat) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
2821
- r.user_id,
2822
- r.user_id,
2823
- r.created_at,
2824
- now,
2825
- r.email,
2826
- r.name,
2827
- r.image_url || null,
2828
- r.role,
2829
- r.created_at,
2830
- r.last_seen_at
2831
- );
2832
- }
2833
- this.sql.exec(`DROP TABLE IF EXISTS users`);
2834
- } catch (error) {
2835
- console.error(`[RecordRoom] Users table migration error:`, error);
2836
- }
2837
- }
2838
- async migrateRecordsTable() {
2839
- try {
2840
- const tableCheck = this.sql.exec(
2841
- `SELECT name FROM sqlite_master WHERE type='table' AND name='records'`
2842
- );
2843
- if (tableCheck.toArray().length === 0) return;
2844
- const rows = this.sql.exec(`SELECT * FROM records`).toArray();
2845
- if (rows.length === 0) {
2846
- this.sql.exec(`DROP TABLE IF EXISTS records`);
2847
- return;
2848
- }
2849
- const prepared = [];
2850
- const blocked = {
2851
- missingSchema: 0,
2852
- invalidData: 0,
2853
- targetConflict: 0
2854
- };
2855
- for (const row of rows) {
2856
- const r = row;
2857
- const schema = this.schemaRegistry.get(r.collection);
2858
- if (!schema || !schema.columns) {
2859
- blocked.missingSchema++;
2860
- continue;
2861
- }
2862
- const tbl = collectionTableName(r.collection);
2863
- const tblExists = this.sql.exec(`SELECT name FROM sqlite_master WHERE type='table' AND name=?`, tbl).toArray().length > 0;
2864
- if (!tblExists) {
2865
- this.ensureCollectionTable(schema);
2866
- }
2867
- const existing = this.sql.exec(`SELECT 1 FROM "${tbl}" WHERE _row_id = ?`, r.record_id).toArray();
2868
- if (existing.length > 0) {
2869
- blocked.targetConflict++;
2870
- continue;
2871
- }
2872
- let data;
2873
- try {
2874
- data = JSON.parse(r.data);
2875
- } catch {
2876
- blocked.invalidData++;
2877
- continue;
2878
- }
2879
- if (data === null || typeof data !== "object" || Array.isArray(data)) {
2880
- blocked.invalidData++;
2881
- continue;
2882
- }
2883
- const columns = schema.columns.map(resolveColumn);
2884
- const colValues = dataToColumnValues(data, columns);
2885
- const colIds = Object.keys(colValues);
2886
- const allCols = [
2887
- "_row_id",
2888
- "_created_by",
2889
- "_created_at",
2890
- "_updated_at",
2891
- ...colIds.map((c) => `"${c}"`)
2892
- ];
2893
- const placeholders = allCols.map(() => "?").join(", ");
2894
- const params = [
2895
- r.record_id,
2896
- r.created_by,
2897
- r.created_at,
2898
- r.updated_at,
2899
- ...colIds.map((c) => colValues[c])
2900
- ];
2901
- prepared.push({
2902
- sql: `INSERT INTO "${tbl}" (${allCols.join(", ")}) VALUES (${placeholders})`,
2903
- params
2904
- });
2905
- }
2906
- const blockedCount = blocked.missingSchema + blocked.invalidData + blocked.targetConflict;
2907
- if (blockedCount > 0) {
2908
- console.error(
2909
- `[RecordRoom] Legacy records migration blocked; no records migrated and the records table was retained for retry (${blockedCount} blocked: ${blocked.missingSchema} missing schema, ${blocked.invalidData} invalid data, ${blocked.targetConflict} target conflict)`
2910
- );
2911
- return;
2912
- }
2913
- this.state.storage.transactionSync(() => {
2914
- for (const record of prepared) {
2915
- this.sql.exec(record.sql, ...record.params);
2916
- }
2917
- this.sql.exec(`DROP TABLE IF EXISTS records`);
2918
- });
2919
- console.log(
2920
- `[RecordRoom] Migrated ${prepared.length} records from document-mode; legacy records table removed`
2921
- );
2922
- } catch (error) {
2923
- console.error(
2924
- `[RecordRoom] Legacy records migration failed; no records migrated and the records table was retained for retry:`,
2925
- error
2926
- );
2927
- }
2928
2776
  }
2929
2777
  // ============================================================================
2930
2778
  // Table-Mode Schema Management
@@ -3401,6 +3249,9 @@ var YjsRoom = class extends BaseRoom {
3401
3249
  }
3402
3250
  };
3403
3251
 
3252
+ // src/server/rooms/canvas-room.ts
3253
+ import * as Y5 from "yjs";
3254
+
3404
3255
  // src/shared/roles.ts
3405
3256
  var ROLES = {
3406
3257
  VIEWER: "viewer",
@@ -3408,271 +3259,7 @@ var ROLES = {
3408
3259
  ADMIN: "admin"
3409
3260
  };
3410
3261
 
3411
- // src/server/rooms/game-room.ts
3412
- var GAME_WRITE_TYPES = /* @__PURE__ */ new Set([
3413
- MSG.GAME_INPUT,
3414
- MSG.GAME_PLAYER_READY,
3415
- MSG.GAME_START,
3416
- MSG.GAME_END
3417
- ]);
3418
- var GameRoom = class extends BaseRoom {
3419
- config;
3420
- players = /* @__PURE__ */ new Map();
3421
- inputBuffer = [];
3422
- currentTick = 0;
3423
- gameState = {};
3424
- running = false;
3425
- initialized = false;
3426
- constructor(state, env, config = {}) {
3427
- super(state, env);
3428
- this.config = {
3429
- tickRate: config.tickRate ?? 20,
3430
- minPlayers: config.minPlayers ?? 1,
3431
- maxPlayers: config.maxPlayers ?? Infinity
3432
- };
3433
- }
3434
- ensureInitialized() {
3435
- if (this.initialized) return;
3436
- this.initialized = true;
3437
- this.sql.exec(`
3438
- CREATE TABLE IF NOT EXISTS game_state (
3439
- id INTEGER PRIMARY KEY CHECK (id = 1),
3440
- state TEXT NOT NULL,
3441
- tick INTEGER NOT NULL DEFAULT 0,
3442
- updated_at TEXT NOT NULL
3443
- )
3444
- `);
3445
- const rows = this.sql.exec("SELECT state, tick FROM game_state WHERE id = 1").toArray();
3446
- if (rows.length > 0) {
3447
- try {
3448
- const parsed = JSON.parse(rows[0].state);
3449
- this.gameState = this.onHydrateState(parsed);
3450
- this.currentTick = rows[0].tick;
3451
- } catch {
3452
- }
3453
- }
3454
- }
3455
- persistState() {
3456
- const now = (/* @__PURE__ */ new Date()).toISOString();
3457
- this.sql.exec(
3458
- `INSERT INTO game_state (id, state, tick, updated_at) VALUES (1, ?, ?, ?)
3459
- ON CONFLICT(id) DO UPDATE SET state = ?, tick = ?, updated_at = ?`,
3460
- JSON.stringify(this.gameState),
3461
- this.currentTick,
3462
- now,
3463
- JSON.stringify(this.gameState),
3464
- this.currentTick,
3465
- now
3466
- );
3467
- }
3468
- // ==========================================================================
3469
- // BaseRoom Lifecycle
3470
- // ==========================================================================
3471
- onConnect(ws, user) {
3472
- this.ensureInitialized();
3473
- const role = user.role ?? ROLES.VIEWER;
3474
- const canWrite = role === ROLES.MEMBER || role === ROLES.ADMIN;
3475
- const attachment = {
3476
- ...user,
3477
- joinedAt: (/* @__PURE__ */ new Date()).toISOString(),
3478
- canWrite
3479
- };
3480
- this.sendTo(ws, { type: MSG.AUTH, payload: { canWrite } });
3481
- if (!canWrite) {
3482
- this.sendTo(ws, {
3483
- type: MSG.GAME_STATE,
3484
- payload: {
3485
- state: this.gameState,
3486
- tick: this.currentTick,
3487
- players: Array.from(this.players.values()),
3488
- running: this.running
3489
- }
3490
- });
3491
- return attachment;
3492
- }
3493
- const player = {
3494
- userId: user.userId,
3495
- userName: user.userName,
3496
- ready: false,
3497
- connectedAt: attachment.joinedAt,
3498
- data: {}
3499
- };
3500
- if (this.config.maxPlayers !== Infinity && this.players.size >= this.config.maxPlayers) {
3501
- this.sendTo(ws, { type: MSG.ERROR, payload: { error: "Game is full" } });
3502
- return attachment;
3503
- }
3504
- this.players.set(user.userId, player);
3505
- this.sendTo(ws, {
3506
- type: MSG.GAME_STATE,
3507
- payload: {
3508
- state: this.gameState,
3509
- tick: this.currentTick,
3510
- players: Array.from(this.players.values()),
3511
- running: this.running
3512
- }
3513
- });
3514
- this.broadcast({ type: MSG.GAME_PLAYER_JOIN, payload: { player } }, ws);
3515
- this.onPlayerJoin(player);
3516
- return attachment;
3517
- }
3518
- async onMessage(ws, user, message) {
3519
- this.ensureInitialized();
3520
- const { type, payload } = message;
3521
- if (GAME_WRITE_TYPES.has(type) && !user.canWrite) {
3522
- this.sendTo(ws, {
3523
- type: MSG.ERROR,
3524
- payload: { error: "Write access denied: spectators cannot drive the game" }
3525
- });
3526
- return;
3527
- }
3528
- switch (type) {
3529
- case MSG.GAME_INPUT: {
3530
- this.inputBuffer.push({
3531
- userId: user.userId,
3532
- action: payload.action,
3533
- data: payload.data ?? {},
3534
- tick: this.currentTick
3535
- });
3536
- break;
3537
- }
3538
- case MSG.GAME_PLAYER_READY: {
3539
- const player = this.players.get(user.userId);
3540
- if (player) {
3541
- player.ready = true;
3542
- this.broadcast({ type: MSG.GAME_PLAYER_READY, payload: { userId: user.userId } });
3543
- this.checkAutoStart();
3544
- }
3545
- break;
3546
- }
3547
- case MSG.GAME_START: {
3548
- if (!this.running) {
3549
- this.startGame();
3550
- }
3551
- break;
3552
- }
3553
- case MSG.GAME_END: {
3554
- if (this.running) {
3555
- this.stopGame();
3556
- }
3557
- break;
3558
- }
3559
- default:
3560
- this.sendTo(ws, { type: MSG.ERROR, payload: { error: `Unknown game message type: ${type}` } });
3561
- }
3562
- }
3563
- onDisconnect(_ws, user) {
3564
- const player = this.players.get(user.userId);
3565
- if (player) {
3566
- this.players.delete(user.userId);
3567
- this.broadcast({ type: MSG.GAME_PLAYER_LEAVE, payload: { userId: user.userId } });
3568
- this.onPlayerLeave(player);
3569
- if (this.running && this.players.size === 0) {
3570
- this.stopGame();
3571
- }
3572
- }
3573
- }
3574
- async onAlarm() {
3575
- if (!this.running) return;
3576
- const inputs = this.inputBuffer.splice(0);
3577
- this.currentTick++;
3578
- const newState = await this.onTick(this.gameState, inputs, this.currentTick);
3579
- if (newState !== void 0) {
3580
- this.gameState = newState;
3581
- }
3582
- if (this.currentTick % 10 === 0) {
3583
- this.persistState();
3584
- }
3585
- this.broadcast({
3586
- type: MSG.GAME_TICK,
3587
- payload: {
3588
- state: this.gameState,
3589
- tick: this.currentTick
3590
- }
3591
- });
3592
- if (this.running) {
3593
- const intervalMs = 1e3 / this.config.tickRate;
3594
- this.state.storage.setAlarm(Date.now() + intervalMs);
3595
- }
3596
- }
3597
- // ==========================================================================
3598
- // Game Control
3599
- // ==========================================================================
3600
- checkAutoStart() {
3601
- if (this.running) return;
3602
- const readyCount = Array.from(this.players.values()).filter((p) => p.ready).length;
3603
- if (readyCount >= this.config.minPlayers && readyCount === this.players.size) {
3604
- this.startGame();
3605
- }
3606
- }
3607
- startGame() {
3608
- this.running = true;
3609
- this.currentTick = 0;
3610
- this.inputBuffer = [];
3611
- this.onGameStart();
3612
- this.broadcast({ type: MSG.GAME_START, payload: { state: this.gameState, tick: 0 } });
3613
- const intervalMs = 1e3 / this.config.tickRate;
3614
- this.state.storage.setAlarm(Date.now() + intervalMs);
3615
- }
3616
- stopGame() {
3617
- this.running = false;
3618
- this.persistState();
3619
- this.onGameEnd(this.gameState);
3620
- this.broadcast({ type: MSG.GAME_END, payload: { state: this.gameState, tick: this.currentTick } });
3621
- }
3622
- // ==========================================================================
3623
- // Protected Accessors (for subclasses)
3624
- // ==========================================================================
3625
- getGameState() {
3626
- return this.gameState;
3627
- }
3628
- setGameState(state) {
3629
- this.gameState = state;
3630
- }
3631
- getPlayers() {
3632
- return Array.from(this.players.values());
3633
- }
3634
- isRunning() {
3635
- return this.running;
3636
- }
3637
- getCurrentTick() {
3638
- return this.currentTick;
3639
- }
3640
- /** Called when a player connects */
3641
- onPlayerJoin(_player) {
3642
- }
3643
- /** Called when a player disconnects */
3644
- onPlayerLeave(_player) {
3645
- }
3646
- /** Called when the game starts */
3647
- onGameStart() {
3648
- }
3649
- /** Called when the game ends */
3650
- onGameEnd(_finalState) {
3651
- }
3652
- /**
3653
- * Called once when the DO first hydrates persisted state from storage.
3654
- * Receives the parsed state blob as it was written by a previous build.
3655
- * Return the state object to install as `gameState`.
3656
- *
3657
- * Subclasses with evolving schemas should override this hook to:
3658
- * - merge new fields onto a default template,
3659
- * - upgrade shapes across versioned states,
3660
- * - or discard stale blobs entirely by returning a fresh object.
3661
- *
3662
- * The default implementation is a pass-through, preserving the legacy
3663
- * "stored blob is gospel" behavior for subclasses that don't care.
3664
- *
3665
- * If JSON parsing of the stored blob fails this hook is NOT called — the
3666
- * DO starts with an empty state and the subclass's `onGameStart` (or
3667
- * first `onTick`) is responsible for initializing.
3668
- */
3669
- onHydrateState(stored) {
3670
- return stored;
3671
- }
3672
- };
3673
-
3674
3262
  // src/server/rooms/canvas-room.ts
3675
- import * as Y5 from "yjs";
3676
3263
  var CANVAS_WRITE_TYPES = /* @__PURE__ */ new Set([
3677
3264
  MSG.CANVAS_ADD,
3678
3265
  MSG.CANVAS_MOVE,
@@ -6018,7 +5605,6 @@ var RESERVED_COLLECTION_NAMES = new Set(
6018
5605
  // src/shared/protocol/app-migrations.ts
6019
5606
  var APP_MIGRATION_ID_RE = /^[a-z0-9][a-z0-9._-]{0,127}$/;
6020
5607
  var MAX_APP_MIGRATION_IDS = 256;
6021
- var CANONICAL_APP_IDENTITY_MIGRATION_ID = "2026-08-canonical-app-identity-wire";
6022
5608
  var WORKER_OWNED_NOT_FOUND_MIGRATION_ID = "2026-08-worker-owned-not-found";
6023
5609
  function validateAppMigrationIds(value) {
6024
5610
  if (!Array.isArray(value)) {
@@ -6317,19 +5903,21 @@ var MAX_UPLOAD_REQUEST_BYTES = 25 * 1024 * 1024;
6317
5903
  var UPLOAD_PART_BYTES = 20 * 1024 * 1024;
6318
5904
  var MAX_UPLOAD_PARTS = Math.ceil(MAX_APP_FILE_BYTES / UPLOAD_PART_BYTES);
6319
5905
  var MAX_BASE64_UPLOAD_BYTES = Math.floor(MAX_UPLOAD_REQUEST_BYTES * 3 / 4);
6320
- var APP_STORAGE_LIMIT_BYTES = {
5906
+ var GIB = 1024 * 1024 * 1024;
5907
+ var ACCOUNT_STORAGE_LIMIT_BYTES = {
6321
5908
  test: 0,
6322
- free: 128 * 1024 * 1024,
6323
- starter: 512 * 1024 * 1024,
6324
- premium: 2 * 1024 * 1024 * 1024,
6325
- admin: 10 * 1024 * 1024 * 1024
5909
+ free: 1 * GIB,
5910
+ starter: 10 * GIB,
5911
+ premium: 30 * GIB,
5912
+ admin: 100 * GIB
6326
5913
  };
6327
5914
  function storageLimitForTier(tier) {
6328
- if (tier && Object.hasOwn(APP_STORAGE_LIMIT_BYTES, tier)) {
6329
- return APP_STORAGE_LIMIT_BYTES[tier];
5915
+ if (tier && Object.hasOwn(ACCOUNT_STORAGE_LIMIT_BYTES, tier)) {
5916
+ return ACCOUNT_STORAGE_LIMIT_BYTES[tier];
6330
5917
  }
6331
- return APP_STORAGE_LIMIT_BYTES.free;
5918
+ return ACCOUNT_STORAGE_LIMIT_BYTES.free;
6332
5919
  }
5920
+ var REPO_STORE_LIMIT_BYTES = 256 * 1024 * 1024;
6333
5921
  function storageQuotaMessage(incomingBytes, usedBytes, limitBytes) {
6334
5922
  const free = Math.max(0, limitBytes - usedBytes);
6335
5923
  return `This upload needs ${formatBytes(incomingBytes)} but the app's file storage has ${formatBytes(free)} free (${formatBytes(usedBytes)} of ${formatBytes(limitBytes)} used). Delete files with \`deepspace app files rm <key>\`, or upgrade the owner's plan.`;
@@ -6420,7 +6008,7 @@ function declaredLength(request, what) {
6420
6008
  function isKeyWithinPrefix(key, prefix) {
6421
6009
  return key.startsWith(prefix);
6422
6010
  }
6423
- async function allocationUsage(bucket, prefix) {
6011
+ async function prefixUsage(bucket, prefix) {
6424
6012
  let total = 0;
6425
6013
  let cursor;
6426
6014
  do {
@@ -6430,6 +6018,13 @@ async function allocationUsage(bucket, prefix) {
6430
6018
  } while (cursor !== void 0);
6431
6019
  return total;
6432
6020
  }
6021
+ async function allocationUsage(bucket, storage) {
6022
+ const siblings = storage.siblingPrefixes ? await storage.siblingPrefixes() : [];
6023
+ if (siblings === null) return null;
6024
+ const prefixes = [storage.prefix, ...siblings.filter((p) => p !== storage.prefix)];
6025
+ const totals = await Promise.all(prefixes.map((prefix) => prefixUsage(bucket, prefix)));
6026
+ return totals.reduce((sum, bytes) => sum + bytes, 0);
6027
+ }
6433
6028
  async function admitStorage(bucket, storage, incomingBytes, replacesKey) {
6434
6029
  if (!storage) return null;
6435
6030
  const limit = await storage.limitBytes();
@@ -6440,7 +6035,14 @@ async function admitStorage(bucket, storage, incomingBytes, replacesKey) {
6440
6035
  "storage_limit_unavailable"
6441
6036
  );
6442
6037
  }
6443
- const stored = await allocationUsage(bucket, storage.prefix);
6038
+ const stored = await allocationUsage(bucket, storage);
6039
+ if (stored === null) {
6040
+ return fail(
6041
+ 503,
6042
+ "The storage already used by this account could not be measured; nothing was uploaded. Retry shortly.",
6043
+ "storage_limit_unavailable"
6044
+ );
6045
+ }
6444
6046
  const replaced = replacesKey === null ? 0 : (await bucket.head(replacesKey))?.size ?? 0;
6445
6047
  const used = stored - replaced;
6446
6048
  if (used + incomingBytes <= limit) return null;
@@ -6456,7 +6058,11 @@ async function admitAssembledObject(bucket, storage, key, objectBytes) {
6456
6058
  console.error("[files:quota] limit unavailable at complete; keeping", key);
6457
6059
  return null;
6458
6060
  }
6459
- const stored = await allocationUsage(bucket, storage.prefix);
6061
+ const stored = await allocationUsage(bucket, storage);
6062
+ if (stored === null) {
6063
+ console.error("[files:quota] account usage unmeasurable at complete; keeping", key);
6064
+ return null;
6065
+ }
6460
6066
  if (stored <= limit) return null;
6461
6067
  await bucket.delete(key).catch(() => void 0);
6462
6068
  return fail(
@@ -6853,9 +6459,10 @@ async function handleList(bucket, prefix, url, scope, auth) {
6853
6459
  });
6854
6460
  let storage;
6855
6461
  if (auth.storage) {
6856
- storage = { usedBytes: await allocationUsage(bucket, auth.storage.prefix) };
6462
+ const usedBytes = await allocationUsage(bucket, auth.storage);
6463
+ if (usedBytes !== null) storage = { usedBytes };
6857
6464
  const limitBytes = await auth.storage.limitBytes();
6858
- if (limitBytes !== null) storage.limitBytes = limitBytes;
6465
+ if (storage && limitBytes !== null) storage.limitBytes = limitBytes;
6859
6466
  }
6860
6467
  return Response.json(
6861
6468
  { files, truncated: listed.truncated, ...storage ? { storage } : {} },
@@ -9462,13 +9069,13 @@ var APP_LOG_EVENT_KEYS = [
9462
9069
  "exception"
9463
9070
  ];
9464
9071
  export {
9072
+ ACCOUNT_STORAGE_LIMIT_BYTES,
9465
9073
  AI_CHATS_SCHEMA,
9466
9074
  AI_MESSAGES_SCHEMA,
9467
9075
  ALLOWED_BINDING_TYPES,
9468
9076
  APP_ID_RE,
9469
9077
  APP_LOG_EVENT_KEYS,
9470
9078
  APP_NAME_RULES,
9471
- APP_STORAGE_LIMIT_BYTES,
9472
9079
  ASSET_NOT_FOUND_HANDLING_VALUES,
9473
9080
  AUTO_PROVISIONABLE_TYPES,
9474
9081
  AUTO_PROVISION_SENTINEL,
@@ -9477,7 +9084,6 @@ export {
9477
9084
  BROWSER_PROXY_ROUTES,
9478
9085
  BUILT_IN_TOOLS,
9479
9086
  BaseRoom,
9480
- CANONICAL_APP_IDENTITY_MIGRATION_ID,
9481
9087
  CHANNELS_SCHEMA,
9482
9088
  CHANNEL_INVITATIONS_SCHEMA,
9483
9089
  CHANNEL_MEMBERS_SCHEMA,
@@ -9499,7 +9105,6 @@ export {
9499
9105
  DeepSpaceAgentProfileError,
9500
9106
  GLOBAL_DO_TYPES,
9501
9107
  GLOBAL_DO_TYPE_NAMES,
9502
- GameRoom,
9503
9108
  JobRoom,
9504
9109
  LOG_LEVELS,
9505
9110
  MAX_APP_FILE_BYTES,
@@ -9520,6 +9125,7 @@ export {
9520
9125
  READ_RECEIPTS_SCHEMA,
9521
9126
  REGISTRY_INSTANCE,
9522
9127
  RELEASE_STAMP_PATH,
9128
+ REPO_STORE_LIMIT_BYTES,
9523
9129
  REQUIRED_COMPATIBILITY_FLAGS,
9524
9130
  RESERVED_BINDING_NAMES,
9525
9131
  RESERVED_COLLECTION_NAMES,