cajonzero 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -22
- package/dist/bin/cj0.js +404 -92
- package/dist/{config-Che_6xEE.d.ts → config-BOzAyP7m.d.ts} +1 -3
- package/dist/core.d.ts +8 -32
- package/dist/core.js +65 -141
- package/dist/index.d.ts +5 -7
- package/dist/index.js +6270 -6341
- package/dist/{providers-CJgLgWh4.d.ts → providers-BX7e4pNW.d.ts} +110 -30
- package/dist/scaffold.d.ts +60 -2
- package/dist/scaffold.js +307 -84
- package/dist/serve.d.ts +2 -4
- package/dist/serve.js +137 -208
- package/dist/ui/assets/index-Bhv7LV8L.css +2 -0
- package/dist/ui/assets/index-CaAHje8X.js +4404 -0
- package/dist/ui/assets/{main-BwrBUsrr.js → main-BeABKxzY.js} +22 -22
- package/dist/ui/index.html +2 -2
- package/package.json +7 -6
- package/dist/bin/cj0.js.map +0 -1
- package/dist/core.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/scaffold.js.map +0 -1
- package/dist/serve.js.map +0 -1
- package/dist/ui/assets/index-BLz2Y_Tv.js +0 -4405
- package/dist/ui/assets/index-W1HlDaw6.css +0 -2
package/dist/serve.js
CHANGED
|
@@ -5343,7 +5343,6 @@ var KEY_PREFIX = {
|
|
|
5343
5343
|
account: "account",
|
|
5344
5344
|
session: "session",
|
|
5345
5345
|
ban: "ban",
|
|
5346
|
-
ratelimit: "ratelimit",
|
|
5347
5346
|
settings: "settings",
|
|
5348
5347
|
mapStorage: "mapstorage"
|
|
5349
5348
|
};
|
|
@@ -5375,9 +5374,6 @@ function banAccountKey(subjectId) {
|
|
|
5375
5374
|
function banIdentityKey(kind, hash) {
|
|
5376
5375
|
return `ban:identity:${kind}:${seg2(hash)}`;
|
|
5377
5376
|
}
|
|
5378
|
-
function ratelimitKey(scope, hash) {
|
|
5379
|
-
return `ratelimit:${seg2(scope)}:${seg2(hash)}`;
|
|
5380
|
-
}
|
|
5381
5377
|
function settingsKey(key) {
|
|
5382
5378
|
return `settings:${seg2(key)}`;
|
|
5383
5379
|
}
|
|
@@ -5420,12 +5416,6 @@ function parseKey(key) {
|
|
|
5420
5416
|
}
|
|
5421
5417
|
return void 0;
|
|
5422
5418
|
}
|
|
5423
|
-
case KEY_PREFIX.ratelimit: {
|
|
5424
|
-
if (parts2.length !== 3) return void 0;
|
|
5425
|
-
const scope = decode(parts2[1]);
|
|
5426
|
-
const hash = decode(parts2[2]);
|
|
5427
|
-
return scope === void 0 || hash === void 0 ? void 0 : { kind: "ratelimit", scope, hash };
|
|
5428
|
-
}
|
|
5429
5419
|
case KEY_PREFIX.settings: {
|
|
5430
5420
|
if (parts2.length !== 2) return void 0;
|
|
5431
5421
|
const settingKey = decode(parts2[1]);
|
|
@@ -5649,7 +5639,6 @@ function parseEntry(value, index) {
|
|
|
5649
5639
|
const author = optionalString(record.author, `maps[${index}].author`);
|
|
5650
5640
|
const version = optionalString(record.version, `maps[${index}].version`);
|
|
5651
5641
|
const cover = optionalString(record.cover, `maps[${index}].cover`);
|
|
5652
|
-
const etag = optionalString(record.etag, `maps[${index}].etag`);
|
|
5653
5642
|
return {
|
|
5654
5643
|
slug,
|
|
5655
5644
|
root,
|
|
@@ -5658,7 +5647,6 @@ function parseEntry(value, index) {
|
|
|
5658
5647
|
...author !== void 0 ? { author } : {},
|
|
5659
5648
|
...version !== void 0 ? { version } : {},
|
|
5660
5649
|
...cover !== void 0 ? { cover } : {},
|
|
5661
|
-
...etag !== void 0 ? { etag } : {},
|
|
5662
5650
|
...assetRoot !== void 0 ? { assetRoot: normalizeRootUrl(assetRoot) } : {}
|
|
5663
5651
|
};
|
|
5664
5652
|
}
|
|
@@ -14282,79 +14270,24 @@ function buildInitialWorld(seed) {
|
|
|
14282
14270
|
return world;
|
|
14283
14271
|
}
|
|
14284
14272
|
|
|
14285
|
-
// src/core/maps/
|
|
14286
|
-
var
|
|
14287
|
-
function
|
|
14288
|
-
const safeRevision = encodeURIComponent(revision).slice(0, 160);
|
|
14289
|
-
return `${SEED_CACHE_PREFIX}:${encodeURIComponent(slug)}:${safeRevision}`;
|
|
14290
|
-
}
|
|
14291
|
-
function toBase64(bytes) {
|
|
14292
|
-
let binary = "";
|
|
14293
|
-
const block = 32768;
|
|
14294
|
-
for (let offset = 0; offset < bytes.length; offset += block) {
|
|
14295
|
-
binary += String.fromCharCode(...bytes.subarray(offset, offset + block));
|
|
14296
|
-
}
|
|
14297
|
-
return btoa(binary);
|
|
14298
|
-
}
|
|
14299
|
-
function fromBase64(value) {
|
|
14300
|
-
const binary = atob(value);
|
|
14301
|
-
const bytes = new Uint8Array(binary.length);
|
|
14302
|
-
for (let i = 0; i < binary.length; i += 1) {
|
|
14303
|
-
bytes[i] = binary.charCodeAt(i);
|
|
14304
|
-
}
|
|
14305
|
-
return bytes;
|
|
14306
|
-
}
|
|
14307
|
-
function encode(seed) {
|
|
14308
|
-
const wire = {
|
|
14309
|
-
version: WORLD_SEED_VERSION,
|
|
14310
|
-
seed: {
|
|
14311
|
-
...seed,
|
|
14312
|
-
voxels: seed.voxels === null ? null : {
|
|
14313
|
-
shape: seed.voxels.shape,
|
|
14314
|
-
chunkCount: seed.voxels.chunkCount,
|
|
14315
|
-
chunkBlobs: seed.voxels.chunkBlobs.map(toBase64),
|
|
14316
|
-
chunkHashes: seed.voxels.chunkHashes.slice()
|
|
14317
|
-
}
|
|
14318
|
-
}
|
|
14319
|
-
};
|
|
14320
|
-
return JSON.stringify(wire);
|
|
14321
|
-
}
|
|
14322
|
-
function decode2(raw) {
|
|
14273
|
+
// src/core/maps/block-info.ts
|
|
14274
|
+
var BLOCK_INFO_HASH = "QmW2E9E8ipYUifsCfkMj5SULYMYbFQvP6BQxo52atXw7Zj";
|
|
14275
|
+
function decodeBlockInfo(bytes) {
|
|
14323
14276
|
try {
|
|
14324
|
-
|
|
14325
|
-
if (wire.version !== WORLD_SEED_VERSION || typeof wire.seed !== "object" || wire.seed === null) {
|
|
14326
|
-
return null;
|
|
14327
|
-
}
|
|
14328
|
-
const { voxels, ...rest } = wire.seed;
|
|
14329
|
-
return {
|
|
14330
|
-
...rest,
|
|
14331
|
-
voxels: voxels === null ? null : {
|
|
14332
|
-
shape: voxels.shape,
|
|
14333
|
-
chunkCount: voxels.chunkCount,
|
|
14334
|
-
chunkBlobs: voxels.chunkBlobs.map(fromBase64),
|
|
14335
|
-
chunkHashes: Array.isArray(voxels.chunkHashes) ? voxels.chunkHashes : []
|
|
14336
|
-
}
|
|
14337
|
-
};
|
|
14277
|
+
return BlockInfoSchema.patch(BlockInfoSchema.identity, new MuReadStream(bytes));
|
|
14338
14278
|
} catch {
|
|
14339
14279
|
return null;
|
|
14340
14280
|
}
|
|
14341
14281
|
}
|
|
14342
|
-
async function
|
|
14282
|
+
async function loadBlockInfo(reader, worldId, hash = BLOCK_INFO_HASH) {
|
|
14343
14283
|
try {
|
|
14344
|
-
const
|
|
14345
|
-
|
|
14284
|
+
const bytes = await reader.read(`worlds/${worldId}/data/blobs/${hash}`);
|
|
14285
|
+
if (bytes === null || bytes.length === 0) return null;
|
|
14286
|
+
return decodeBlockInfo(bytes);
|
|
14346
14287
|
} catch {
|
|
14347
14288
|
return null;
|
|
14348
14289
|
}
|
|
14349
14290
|
}
|
|
14350
|
-
async function writeCachedSeed(kv, key, seed, ttlSeconds) {
|
|
14351
|
-
if (ttlSeconds <= 0) return;
|
|
14352
|
-
try {
|
|
14353
|
-
const options = ttlSeconds >= 60 ? { expirationTtl: ttlSeconds } : void 0;
|
|
14354
|
-
await kv.put(key, encode(seed), options);
|
|
14355
|
-
} catch {
|
|
14356
|
-
}
|
|
14357
|
-
}
|
|
14358
14291
|
|
|
14359
14292
|
// src/core/maps/http.ts
|
|
14360
14293
|
var MapSourceError = class extends Error {
|
|
@@ -14474,12 +14407,6 @@ async function resolveWorldId(source) {
|
|
|
14474
14407
|
return assertWorldId(candidate);
|
|
14475
14408
|
}
|
|
14476
14409
|
async function loadWorldSeedFromHttp(entry, options = {}) {
|
|
14477
|
-
const revision = entry.etag ?? entry.version;
|
|
14478
|
-
const cacheKey = options.kv !== void 0 && revision !== void 0 ? seedCacheKey(entry.slug, revision) : void 0;
|
|
14479
|
-
if (cacheKey !== void 0 && options.kv !== void 0) {
|
|
14480
|
-
const cached = await readCachedSeed(options.kv, cacheKey);
|
|
14481
|
-
if (cached !== null) return cached;
|
|
14482
|
-
}
|
|
14483
14410
|
const source = new HttpMapSource(entry.root, options);
|
|
14484
14411
|
const worldId = entry.worldId ?? await resolveWorldId(source);
|
|
14485
14412
|
const manifest = await source.readJson(
|
|
@@ -14488,14 +14415,13 @@ async function loadWorldSeedFromHttp(entry, options = {}) {
|
|
|
14488
14415
|
if (manifest === null) {
|
|
14489
14416
|
fail2("MAP_NO_WORLD", `worlds/${worldId}/manifest.json is missing or not JSON`);
|
|
14490
14417
|
}
|
|
14491
|
-
|
|
14418
|
+
return resolveWorldSeed(
|
|
14492
14419
|
{ worldId, manifest, reader: source },
|
|
14493
14420
|
{ concurrency: options.concurrency ?? DEFAULT_CONCURRENCY }
|
|
14494
|
-
)
|
|
14495
|
-
|
|
14496
|
-
|
|
14497
|
-
}
|
|
14498
|
-
return seed;
|
|
14421
|
+
).then(async (seed) => {
|
|
14422
|
+
const blockInfo = await loadBlockInfo(source, worldId);
|
|
14423
|
+
return blockInfo === null ? seed : { ...seed, blockInfo };
|
|
14424
|
+
});
|
|
14499
14425
|
}
|
|
14500
14426
|
var MEBIBYTE = 1024 * 1024;
|
|
14501
14427
|
var ZERO_PLAYER_TIMEOUT_DEFAULT_MS = 48e4;
|
|
@@ -15637,34 +15563,6 @@ function banDetails(input, at) {
|
|
|
15637
15563
|
const expiresAt = input.expiresAt ?? (input.durationSeconds === void 0 ? void 0 : at + input.durationSeconds * 1e3);
|
|
15638
15564
|
return { reason: input.reason, expiresAt, createdBy: input.createdBy };
|
|
15639
15565
|
}
|
|
15640
|
-
function createRateLimitsRepo(store, now) {
|
|
15641
|
-
const repo = {
|
|
15642
|
-
async increment(scope, hash, options = {}) {
|
|
15643
|
-
const windowSeconds = Math.max(1, options.windowSeconds ?? 60);
|
|
15644
|
-
const amount = options.amount ?? 1;
|
|
15645
|
-
const at = now();
|
|
15646
|
-
const current = await repo.get(scope, hash);
|
|
15647
|
-
const windowStart = current !== void 0 && current.expiresAt > at ? current.windowStart : at;
|
|
15648
|
-
const expiresAt = windowStart + windowSeconds * 1e3;
|
|
15649
|
-
const next = {
|
|
15650
|
-
count: (current !== void 0 && current.expiresAt > at ? current.count : 0) + amount,
|
|
15651
|
-
windowStart,
|
|
15652
|
-
expiresAt
|
|
15653
|
-
};
|
|
15654
|
-
const ttl = Math.max(1, Math.ceil((expiresAt - at) / 1e3));
|
|
15655
|
-
await store.setItem(ratelimitKey(scope, hash), next, { ttl });
|
|
15656
|
-
return next;
|
|
15657
|
-
},
|
|
15658
|
-
async get(scope, hash) {
|
|
15659
|
-
const record = await store.getItem(ratelimitKey(scope, hash));
|
|
15660
|
-
return record ?? void 0;
|
|
15661
|
-
},
|
|
15662
|
-
async reset(scope, hash) {
|
|
15663
|
-
await store.removeItem(ratelimitKey(scope, hash));
|
|
15664
|
-
}
|
|
15665
|
-
};
|
|
15666
|
-
return repo;
|
|
15667
|
-
}
|
|
15668
15566
|
function createSettingsRepo(store) {
|
|
15669
15567
|
return {
|
|
15670
15568
|
async get(key) {
|
|
@@ -15929,7 +15827,6 @@ function createRepos(store, options = {}) {
|
|
|
15929
15827
|
accounts: createAccountsRepo(store, now),
|
|
15930
15828
|
sessions: createSessionsRepo(store, now),
|
|
15931
15829
|
bans: createBansRepo(store, now),
|
|
15932
|
-
ratelimits: createRateLimitsRepo(store, now),
|
|
15933
15830
|
settings: createSettingsRepo(store),
|
|
15934
15831
|
mapStorage: (scope, namespace) => createMapStorageRepo(store, {
|
|
15935
15832
|
scope,
|
|
@@ -16013,9 +15910,6 @@ function resolveAdminToken(env) {
|
|
|
16013
15910
|
function resolveEnvironment(env) {
|
|
16014
15911
|
return providers.environment?.(env);
|
|
16015
15912
|
}
|
|
16016
|
-
function resolveMapSeedKv(env) {
|
|
16017
|
-
return providers.mapSeedKv?.(env);
|
|
16018
|
-
}
|
|
16019
15913
|
function resolveRooms(env) {
|
|
16020
15914
|
return providers.rooms?.(env);
|
|
16021
15915
|
}
|
|
@@ -16041,7 +15935,8 @@ function createSnapshot(input) {
|
|
|
16041
15935
|
frameSkip: input.frameSkip,
|
|
16042
15936
|
seed: input.seed ?? 0,
|
|
16043
15937
|
engine: input.engine,
|
|
16044
|
-
clients: input.clients.map((client) => ({ ...client }))
|
|
15938
|
+
clients: input.clients.map((client) => ({ ...client })),
|
|
15939
|
+
...input.map !== void 0 ? { map: { ...input.map } } : {}
|
|
16045
15940
|
};
|
|
16046
15941
|
}
|
|
16047
15942
|
function serializeSnapshot(snapshot2) {
|
|
@@ -16060,9 +15955,19 @@ function deserializeSnapshot(serialized) {
|
|
|
16060
15955
|
frameSkip: parsed.frameSkip,
|
|
16061
15956
|
seed: parsed.seed,
|
|
16062
15957
|
engine: parsed.engine,
|
|
16063
|
-
clients: parsed.clients.map((client) => ({ ...client }))
|
|
15958
|
+
clients: parsed.clients.map((client) => ({ ...client })),
|
|
15959
|
+
...parsed.map !== void 0 && parsed.map !== null ? {
|
|
15960
|
+
map: {
|
|
15961
|
+
slug: parsed.map.slug,
|
|
15962
|
+
root: parsed.map.root,
|
|
15963
|
+
...parsed.map.worldId !== void 0 ? { worldId: parsed.map.worldId } : {}
|
|
15964
|
+
}
|
|
15965
|
+
} : {}
|
|
16064
15966
|
};
|
|
16065
15967
|
}
|
|
15968
|
+
function snapshotMatchesMap(snapshot2, map) {
|
|
15969
|
+
return snapshot2 !== void 0 && snapshot2.slug === map.slug && snapshot2.root === map.root && (snapshot2.worldId ?? null) === (map.worldId ?? null);
|
|
15970
|
+
}
|
|
16066
15971
|
|
|
16067
15972
|
// src/core/room/skin-sync.ts
|
|
16068
15973
|
var ROOM_SKIN_UPDATE_PARAM = "cajonzeroSkinUpdate";
|
|
@@ -23620,9 +23525,7 @@ function parseMapBootstrap(url) {
|
|
|
23620
23525
|
return void 0;
|
|
23621
23526
|
}
|
|
23622
23527
|
}
|
|
23623
|
-
const etag = textParam(url, "cajonzeroEtag");
|
|
23624
23528
|
const version = textParam(url, "cajonzeroVersion");
|
|
23625
|
-
const cacheTtlSeconds = numberParam(url, "cajonzeroCacheTtl", 0, 31536e3);
|
|
23626
23529
|
const maxDownloadBytes = numberParam(url, "cajonzeroMaxBytes", 1024, 1024 * 1024 * 1024);
|
|
23627
23530
|
const concurrency = numberParam(url, "cajonzeroConcurrency", 1, 64);
|
|
23628
23531
|
const requestTimeoutMs = numberParam(url, "cajonzeroTimeout", 100, 12e4);
|
|
@@ -23630,9 +23533,7 @@ function parseMapBootstrap(url) {
|
|
|
23630
23533
|
slug,
|
|
23631
23534
|
root,
|
|
23632
23535
|
...worldId !== void 0 ? { worldId } : {},
|
|
23633
|
-
...etag !== void 0 ? { etag } : {},
|
|
23634
23536
|
...version !== void 0 ? { version } : {},
|
|
23635
|
-
...cacheTtlSeconds !== void 0 ? { cacheTtlSeconds } : {},
|
|
23636
23537
|
...maxDownloadBytes !== void 0 ? { maxDownloadBytes } : {},
|
|
23637
23538
|
...concurrency !== void 0 ? { concurrency } : {},
|
|
23638
23539
|
...requestTimeoutMs !== void 0 ? { requestTimeoutMs } : {}
|
|
@@ -23679,7 +23580,6 @@ var Room = class {
|
|
|
23679
23580
|
script;
|
|
23680
23581
|
explicitScriptHost;
|
|
23681
23582
|
mapLoader;
|
|
23682
|
-
seedCacheKv;
|
|
23683
23583
|
sockets;
|
|
23684
23584
|
/** mudb wire codec: protocol envelope + netcode frames. */
|
|
23685
23585
|
codec;
|
|
@@ -23721,6 +23621,8 @@ var Room = class {
|
|
|
23721
23621
|
mapLoading;
|
|
23722
23622
|
worldReady = false;
|
|
23723
23623
|
snapshotRestored = false;
|
|
23624
|
+
/** One-shot guard for the "proof without sessionSecret" diagnostic. */
|
|
23625
|
+
guestWarningLogged = false;
|
|
23724
23626
|
persistence;
|
|
23725
23627
|
socketsStarted = false;
|
|
23726
23628
|
perf = { minPing: 0, maxPing: 0, avgPing: 0, pingCount: 0 };
|
|
@@ -23732,6 +23634,10 @@ var Room = class {
|
|
|
23732
23634
|
inboundIds = /* @__PURE__ */ new Map();
|
|
23733
23635
|
/** Snapshot parked by `init()` until the seeded engine exists. */
|
|
23734
23636
|
pendingEngineSnapshot = null;
|
|
23637
|
+
/** Map identity stored with the parked snapshot (absent on legacy snapshots). */
|
|
23638
|
+
pendingEngineMap;
|
|
23639
|
+
/** Identity of the map the current engine was seeded from. */
|
|
23640
|
+
seededMap;
|
|
23735
23641
|
heartbeatBeats = 0;
|
|
23736
23642
|
ticksRun = 0;
|
|
23737
23643
|
lastTickError;
|
|
@@ -23759,7 +23665,6 @@ var Room = class {
|
|
|
23759
23665
|
this.explicitScriptHost = options.scriptHost !== void 0;
|
|
23760
23666
|
this.script = options.scriptHost ?? this.engine;
|
|
23761
23667
|
this.mapBootstrap = options.map;
|
|
23762
|
-
this.seedCacheKv = resolveMapSeedKv(env);
|
|
23763
23668
|
this.mapLoader = options.loadMapSeed ?? ((bootstrap) => this.loadSeed(bootstrap));
|
|
23764
23669
|
this.registryTtlSeconds = options.registryTtlSeconds ?? DEFAULT_SESSION_SLOT_TTL_SECONDS;
|
|
23765
23670
|
const banCacheTtlMs = options.banCacheTtlMs ?? DEFAULT_BAN_CACHE_TTL_MS2;
|
|
@@ -23813,6 +23718,7 @@ var Room = class {
|
|
|
23813
23718
|
this.tickValue = snapshot2.tick;
|
|
23814
23719
|
this.frameSkip = snapshot2.frameSkip;
|
|
23815
23720
|
this.pendingEngineSnapshot = snapshot2.engine;
|
|
23721
|
+
this.pendingEngineMap = snapshot2.map;
|
|
23816
23722
|
this.snapshotRestored = true;
|
|
23817
23723
|
}
|
|
23818
23724
|
try {
|
|
@@ -23937,11 +23843,30 @@ var Room = class {
|
|
|
23937
23843
|
}
|
|
23938
23844
|
await this.mapLoading;
|
|
23939
23845
|
}
|
|
23940
|
-
/**
|
|
23846
|
+
/**
|
|
23847
|
+
* Apply a snapshot parked by `init()` exactly once.
|
|
23848
|
+
*
|
|
23849
|
+
* A snapshot describes the world of the map it was captured from. Restoring
|
|
23850
|
+
* one that came from another map (or from a room that never had a map) would
|
|
23851
|
+
* replace the freshly seeded entities with nothing, leaving terrain but no
|
|
23852
|
+
* models — so it is dropped instead. Dropping it also resets the tick
|
|
23853
|
+
* counters, which `init()` had adopted optimistically.
|
|
23854
|
+
*/
|
|
23941
23855
|
applyPendingEngineSnapshot() {
|
|
23942
23856
|
if (this.pendingEngineSnapshot === null) return;
|
|
23943
|
-
this.
|
|
23857
|
+
const pending = this.pendingEngineSnapshot;
|
|
23858
|
+
const pendingMap = this.pendingEngineMap;
|
|
23944
23859
|
this.pendingEngineSnapshot = null;
|
|
23860
|
+
this.pendingEngineMap = void 0;
|
|
23861
|
+
if (this.seededMap !== void 0) {
|
|
23862
|
+
if (!snapshotMatchesMap(pendingMap, this.seededMap)) {
|
|
23863
|
+
this.tickValue = 0;
|
|
23864
|
+
this.frameSkip = 0;
|
|
23865
|
+
clearServerNetState(this.net, 0);
|
|
23866
|
+
return;
|
|
23867
|
+
}
|
|
23868
|
+
}
|
|
23869
|
+
this.engine.restore(pending);
|
|
23945
23870
|
}
|
|
23946
23871
|
async loadWorld(bootstrap) {
|
|
23947
23872
|
try {
|
|
@@ -23957,6 +23882,7 @@ var Room = class {
|
|
|
23957
23882
|
const engine = factory({ worldSeed: seed });
|
|
23958
23883
|
this.engine = engine;
|
|
23959
23884
|
if (!this.explicitScriptHost) this.script = engine;
|
|
23885
|
+
this.seededMap = { slug: bootstrap.slug, root: bootstrap.root, worldId: seed.mapId };
|
|
23960
23886
|
this.applyPendingEngineSnapshot();
|
|
23961
23887
|
this.worldReady = true;
|
|
23962
23888
|
this.logger.log(`cajonzero: seeded room "${bootstrap.slug}" from "${seed.mapId}"`);
|
|
@@ -23968,8 +23894,6 @@ var Room = class {
|
|
|
23968
23894
|
}
|
|
23969
23895
|
loadSeed(bootstrap) {
|
|
23970
23896
|
return loadWorldSeedFromHttp(bootstrap, {
|
|
23971
|
-
...this.seedCacheKv !== void 0 ? { kv: this.seedCacheKv } : {},
|
|
23972
|
-
cacheTtlSeconds: bootstrap.cacheTtlSeconds ?? 0,
|
|
23973
23897
|
...bootstrap.maxDownloadBytes !== void 0 ? { maxDownloadBytes: bootstrap.maxDownloadBytes } : {},
|
|
23974
23898
|
...bootstrap.concurrency !== void 0 ? { concurrency: bootstrap.concurrency } : {},
|
|
23975
23899
|
...bootstrap.requestTimeoutMs !== void 0 ? { requestTimeoutMs: bootstrap.requestTimeoutMs } : {}
|
|
@@ -24044,6 +23968,13 @@ var Room = class {
|
|
|
24044
23968
|
this.pendingIdentities.set(sessionId, identity2);
|
|
24045
23969
|
}
|
|
24046
23970
|
} else {
|
|
23971
|
+
const proof = extractSessionProof(request.headers.get("sec-websocket-protocol"));
|
|
23972
|
+
if (proof !== void 0 && !this.guestWarningLogged) {
|
|
23973
|
+
this.guestWarningLogged = true;
|
|
23974
|
+
this.logger.error(
|
|
23975
|
+
"cajonzero: a session proof was supplied but no sessionSecret is configured; players join as guest. Pass serve({ sessionSecret: (env) => env.<SECRET> })."
|
|
23976
|
+
);
|
|
23977
|
+
}
|
|
24047
23978
|
identity2 = guestIdentity(sessionId);
|
|
24048
23979
|
}
|
|
24049
23980
|
const ip = resolveClientIp(request);
|
|
@@ -24705,7 +24636,8 @@ var Room = class {
|
|
|
24705
24636
|
tick: this.tickValue,
|
|
24706
24637
|
frameSkip: this.frameSkip,
|
|
24707
24638
|
engine: this.engine.capture(),
|
|
24708
|
-
clients: [...this.connections.values()].map(toSnapshotClient)
|
|
24639
|
+
clients: [...this.connections.values()].map(toSnapshotClient),
|
|
24640
|
+
...this.seededMap !== void 0 ? { map: { ...this.seededMap } } : {}
|
|
24709
24641
|
});
|
|
24710
24642
|
}
|
|
24711
24643
|
/**
|
|
@@ -25078,6 +25010,65 @@ var PhysicsZoneIndex = class {
|
|
|
25078
25010
|
}
|
|
25079
25011
|
};
|
|
25080
25012
|
|
|
25013
|
+
// src/vendor/mudb/box-schema/voxel/blocks.ts
|
|
25014
|
+
function fillAndZero(x, count) {
|
|
25015
|
+
x.length = 0;
|
|
25016
|
+
for (let i = 0; i < count; ++i) {
|
|
25017
|
+
x.push(0);
|
|
25018
|
+
}
|
|
25019
|
+
}
|
|
25020
|
+
function unpackBlockIndex(blockInfo, outIndex) {
|
|
25021
|
+
let maxId = 0;
|
|
25022
|
+
for (let i = 0; i < blockInfo.ids.length; ++i) {
|
|
25023
|
+
maxId = Math.max(blockInfo.ids[i], maxId);
|
|
25024
|
+
}
|
|
25025
|
+
fillAndZero(outIndex.fluid, maxId);
|
|
25026
|
+
fillAndZero(outIndex.mass, maxId);
|
|
25027
|
+
fillAndZero(outIndex.friction, maxId);
|
|
25028
|
+
fillAndZero(outIndex.restitution, maxId);
|
|
25029
|
+
fillAndZero(outIndex.texture, 6 * maxId);
|
|
25030
|
+
fillAndZero(outIndex.emissive, maxId);
|
|
25031
|
+
fillAndZero(outIndex.velocity, 3 * maxId);
|
|
25032
|
+
outIndex.name.length = 0;
|
|
25033
|
+
outIndex.valid.length = 0;
|
|
25034
|
+
for (let i = 0; i < maxId; ++i) {
|
|
25035
|
+
outIndex.name.push("");
|
|
25036
|
+
outIndex.valid.push(false);
|
|
25037
|
+
}
|
|
25038
|
+
outIndex.fluidInfo.length = 0;
|
|
25039
|
+
outIndex.id = {};
|
|
25040
|
+
for (let i = 0; i < blockInfo.ids.length; ++i) {
|
|
25041
|
+
const id = blockInfo.ids[i];
|
|
25042
|
+
const name = blockInfo.names[i];
|
|
25043
|
+
outIndex.id[name] = id;
|
|
25044
|
+
outIndex.name[id] = name;
|
|
25045
|
+
outIndex.valid[id] = true;
|
|
25046
|
+
outIndex.emissive[id] = blockInfo.emissive[i];
|
|
25047
|
+
outIndex.restitution[id] = blockInfo.restitution[i];
|
|
25048
|
+
outIndex.friction[id] = blockInfo.friction[i];
|
|
25049
|
+
for (let j = 0; j < 6; ++j) {
|
|
25050
|
+
outIndex.texture[6 * id + j] = blockInfo.texture[6 * i + j] | blockInfo.animLength[6 * i + j] << 24;
|
|
25051
|
+
}
|
|
25052
|
+
for (let j = 0; j < 3; ++j) {
|
|
25053
|
+
outIndex.velocity[3 * id + j] = blockInfo.velocity[3 * i + j];
|
|
25054
|
+
}
|
|
25055
|
+
}
|
|
25056
|
+
if (!outIndex.isFluid) {
|
|
25057
|
+
outIndex.isFluid = new Uint8Array(4095);
|
|
25058
|
+
}
|
|
25059
|
+
for (let i = 0; i < 4095; ++i) {
|
|
25060
|
+
outIndex.isFluid[i] = 0;
|
|
25061
|
+
}
|
|
25062
|
+
outIndex.fluidInfo.push(0);
|
|
25063
|
+
for (let i = 0; i < blockInfo.fluids.length; ++i) {
|
|
25064
|
+
const { id, info, mass } = blockInfo.fluids[i];
|
|
25065
|
+
outIndex.fluid[id] = i + 1;
|
|
25066
|
+
outIndex.fluidInfo.push(info);
|
|
25067
|
+
outIndex.mass[id] = mass;
|
|
25068
|
+
outIndex.isFluid[id] = 1;
|
|
25069
|
+
}
|
|
25070
|
+
}
|
|
25071
|
+
|
|
25081
25072
|
// src/vendor/mudb/box-schema/voxel/box-decode.ts
|
|
25082
25073
|
function signDecode(x) {
|
|
25083
25074
|
if (x & 1) {
|
|
@@ -25558,14 +25549,19 @@ function createEmptyVoxelHandles() {
|
|
|
25558
25549
|
)
|
|
25559
25550
|
};
|
|
25560
25551
|
}
|
|
25561
|
-
function buildVoxelHandles(voxels) {
|
|
25562
|
-
const blockIndex = createSolidBlockIndex();
|
|
25552
|
+
function buildVoxelHandles(voxels, blockInfo) {
|
|
25553
|
+
const blockIndex = blockInfo === void 0 ? createSolidBlockIndex() : createBlockIndexFromInfo(blockInfo);
|
|
25563
25554
|
const collision = VoxelCollisionSchema.clone(
|
|
25564
25555
|
VoxelCollisionSchema.identity
|
|
25565
25556
|
);
|
|
25566
25557
|
intializeCollision(blockIndex, collision, voxels);
|
|
25567
25558
|
return { blockIndex, collision };
|
|
25568
25559
|
}
|
|
25560
|
+
function createBlockIndexFromInfo(blockInfo) {
|
|
25561
|
+
const blockIndex = BlockIndexSchema.clone(BlockIndexSchema.identity);
|
|
25562
|
+
unpackBlockIndex(blockInfo, blockIndex);
|
|
25563
|
+
return blockIndex;
|
|
25564
|
+
}
|
|
25569
25565
|
function countSolidVoxels(voxels) {
|
|
25570
25566
|
const data = voxels.data;
|
|
25571
25567
|
let count = 0;
|
|
@@ -25781,7 +25777,7 @@ function createPlayEngine(options = {}) {
|
|
|
25781
25777
|
options.worldSeed.voxels.shape,
|
|
25782
25778
|
options.worldSeed.voxels.chunkBlobs
|
|
25783
25779
|
) : null;
|
|
25784
|
-
const { blockIndex, collision } = options.voxelHandles ?? (decodedVoxels ? buildVoxelHandles(decodedVoxels) : createEmptyVoxelHandles());
|
|
25780
|
+
const { blockIndex, collision } = options.voxelHandles ?? (decodedVoxels ? buildVoxelHandles(decodedVoxels, options.worldSeed?.blockInfo) : createEmptyVoxelHandles());
|
|
25785
25781
|
const zoneIndex = new PhysicsZoneIndex();
|
|
25786
25782
|
let lastContact = ContactIndexSchema.alloc();
|
|
25787
25783
|
const historyRing = /* @__PURE__ */ new Map();
|
|
@@ -26174,7 +26170,6 @@ var DEFAULT_CONFIG = {
|
|
|
26174
26170
|
admin: { path: "/admin" },
|
|
26175
26171
|
room: { tickRate: 64, emptyGraceMs: 48e4 },
|
|
26176
26172
|
maps: {
|
|
26177
|
-
cacheTtlSeconds: 86400,
|
|
26178
26173
|
maxDownloadBytes: 32 * 1024 * 1024,
|
|
26179
26174
|
concurrency: 8,
|
|
26180
26175
|
requestTimeoutMs: 15e3
|
|
@@ -26233,13 +26228,6 @@ function resolveConfig(input) {
|
|
|
26233
26228
|
)
|
|
26234
26229
|
},
|
|
26235
26230
|
maps: {
|
|
26236
|
-
cacheTtlSeconds: integer(
|
|
26237
|
-
maps.cacheTtlSeconds,
|
|
26238
|
-
DEFAULT_CONFIG.maps.cacheTtlSeconds,
|
|
26239
|
-
"maps.cacheTtlSeconds",
|
|
26240
|
-
0,
|
|
26241
|
-
31536e3
|
|
26242
|
-
),
|
|
26243
26231
|
maxDownloadBytes: integer(
|
|
26244
26232
|
maps.maxDownloadBytes,
|
|
26245
26233
|
DEFAULT_CONFIG.maps.maxDownloadBytes,
|
|
@@ -26295,8 +26283,6 @@ function validationHook(code, status = 400) {
|
|
|
26295
26283
|
|
|
26296
26284
|
// src/core/identity/account-routes.ts
|
|
26297
26285
|
var SESSION_COOKIE_NAME = "cajonzero_session";
|
|
26298
|
-
var RATE_LIMIT_MAX_ATTEMPTS = 5;
|
|
26299
|
-
var RATE_LIMIT_WINDOW_SECONDS = 300;
|
|
26300
26286
|
var USERNAME_PATTERN = /^[a-zA-Z][a-zA-Z0-9_]{2,31}$/;
|
|
26301
26287
|
var MIN_PASSWORD_LENGTH = 10;
|
|
26302
26288
|
var MAX_PASSWORD_LENGTH = 128;
|
|
@@ -26365,22 +26351,6 @@ function clientIp(request) {
|
|
|
26365
26351
|
}
|
|
26366
26352
|
return "unknown";
|
|
26367
26353
|
}
|
|
26368
|
-
async function enforceAttempts(c, deps, attempts) {
|
|
26369
|
-
let retryAfter = null;
|
|
26370
|
-
for (const attempt of attempts) {
|
|
26371
|
-
const state = await deps.ratelimits.increment(attempt.scope, attempt.key, {
|
|
26372
|
-
windowSeconds: RATE_LIMIT_WINDOW_SECONDS
|
|
26373
|
-
});
|
|
26374
|
-
if (state.count > RATE_LIMIT_MAX_ATTEMPTS) {
|
|
26375
|
-
const seconds = Math.max(1, Math.ceil((state.expiresAt - deps.now()) / 1e3));
|
|
26376
|
-
retryAfter = retryAfter === null ? seconds : Math.max(retryAfter, seconds);
|
|
26377
|
-
}
|
|
26378
|
-
}
|
|
26379
|
-
if (retryAfter !== null) {
|
|
26380
|
-
c.header("Retry-After", String(retryAfter));
|
|
26381
|
-
throw new HttpError(429, "rate_limited");
|
|
26382
|
-
}
|
|
26383
|
-
}
|
|
26384
26354
|
async function issueSession(c, deps, account, ip) {
|
|
26385
26355
|
const minted = await mintSessionToken(
|
|
26386
26356
|
{
|
|
@@ -26413,10 +26383,6 @@ function accountRoutes(deps) {
|
|
|
26413
26383
|
const username = body.username;
|
|
26414
26384
|
const password = body.password;
|
|
26415
26385
|
const ip = clientIp(c.req.raw);
|
|
26416
|
-
await enforceAttempts(c, deps, [
|
|
26417
|
-
{ scope: "register-ip", key: ip },
|
|
26418
|
-
{ scope: "register-account", key: username.toLowerCase() }
|
|
26419
|
-
]);
|
|
26420
26386
|
const saltBytes = randomSalt();
|
|
26421
26387
|
const passwordHash = await derivePassword(password, saltBytes);
|
|
26422
26388
|
let account;
|
|
@@ -26441,11 +26407,6 @@ function accountRoutes(deps) {
|
|
|
26441
26407
|
const username = body.username;
|
|
26442
26408
|
const password = body.password;
|
|
26443
26409
|
const ip = clientIp(c.req.raw);
|
|
26444
|
-
const attempts = [{ scope: "login-ip", key: ip }];
|
|
26445
|
-
if (username.length > 0) {
|
|
26446
|
-
attempts.push({ scope: "login-account", key: username.toLowerCase() });
|
|
26447
|
-
}
|
|
26448
|
-
await enforceAttempts(c, deps, attempts);
|
|
26449
26410
|
const account = username.length > 0 ? await deps.accounts.getByUsername(username) : void 0;
|
|
26450
26411
|
if (account === void 0 || account.disabled) {
|
|
26451
26412
|
await dummyVerify(password);
|
|
@@ -26612,12 +26573,12 @@ var STATE_CHANGING_METHODS = /* @__PURE__ */ new Set([
|
|
|
26612
26573
|
"DELETE"
|
|
26613
26574
|
]);
|
|
26614
26575
|
var ENCODER = new TextEncoder();
|
|
26615
|
-
function
|
|
26576
|
+
function encode(text) {
|
|
26616
26577
|
return ENCODER.encode(text);
|
|
26617
26578
|
}
|
|
26618
26579
|
async function adminTokenMatches(provided, expected) {
|
|
26619
26580
|
const [a, b] = await Promise.all([hashToken(provided), hashToken(expected)]);
|
|
26620
|
-
return timingSafeEqual(
|
|
26581
|
+
return timingSafeEqual(encode(a), encode(b));
|
|
26621
26582
|
}
|
|
26622
26583
|
function readBearer(header) {
|
|
26623
26584
|
if (header === null || header === void 0) return "";
|
|
@@ -26696,7 +26657,7 @@ function assertCsrf(c, allowedOrigins) {
|
|
|
26696
26657
|
if (cookie === void 0 || header === void 0 || header === "") {
|
|
26697
26658
|
throw new HttpError(403, "csrf");
|
|
26698
26659
|
}
|
|
26699
|
-
if (!timingSafeEqual(
|
|
26660
|
+
if (!timingSafeEqual(encode(cookie), encode(header))) {
|
|
26700
26661
|
throw new HttpError(403, "csrf");
|
|
26701
26662
|
}
|
|
26702
26663
|
}
|
|
@@ -26863,7 +26824,7 @@ function toPublicMap(entry) {
|
|
|
26863
26824
|
...entry.worldId !== void 0 ? { worldId: entry.worldId } : {}
|
|
26864
26825
|
};
|
|
26865
26826
|
}
|
|
26866
|
-
function mountMapRoutes(app, catalog
|
|
26827
|
+
function mountMapRoutes(app, catalog) {
|
|
26867
26828
|
app.get("/api/maps", (c) => {
|
|
26868
26829
|
c.header("Cache-Control", "public, max-age=60");
|
|
26869
26830
|
return c.json({
|
|
@@ -26879,30 +26840,10 @@ function mountMapRoutes(app, catalog, options = {}) {
|
|
|
26879
26840
|
c.header("Cache-Control", "public, max-age=60");
|
|
26880
26841
|
return c.json({ map: toPublicMap(entry) });
|
|
26881
26842
|
});
|
|
26882
|
-
app.get("/api/maps/:slug/seed", async (c) => {
|
|
26883
|
-
const entry = findMap(catalog, c.req.param("slug"));
|
|
26884
|
-
if (entry === void 0) {
|
|
26885
|
-
return c.json({ error: "map_not_found" }, 404);
|
|
26886
|
-
}
|
|
26887
|
-
try {
|
|
26888
|
-
const seed = await loadWorldSeedFromHttp(entry, {
|
|
26889
|
-
kv: options.kv,
|
|
26890
|
-
cacheTtlSeconds: options.cacheTtlSeconds,
|
|
26891
|
-
concurrency: options.concurrency,
|
|
26892
|
-
requestTimeoutMs: options.requestTimeoutMs,
|
|
26893
|
-
fetch: options.fetch
|
|
26894
|
-
});
|
|
26895
|
-
c.header("Cache-Control", "public, max-age=300");
|
|
26896
|
-
return c.json({ seed });
|
|
26897
|
-
} catch (error) {
|
|
26898
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
26899
|
-
return c.json({ error: "map_seed_failed", message }, 502);
|
|
26900
|
-
}
|
|
26901
|
-
});
|
|
26902
26843
|
}
|
|
26903
26844
|
|
|
26904
26845
|
// src/version.ts
|
|
26905
|
-
var VERSION = "0.1.
|
|
26846
|
+
var VERSION = "0.1.1";
|
|
26906
26847
|
|
|
26907
26848
|
// src/core/server/room-gateway.ts
|
|
26908
26849
|
var CONTAINER_PATTERN3 = /^[A-Za-z0-9][A-Za-z0-9_-]{0,127}$/;
|
|
@@ -26975,10 +26916,8 @@ function writeMapBootstrap(url, entry, deps) {
|
|
|
26975
26916
|
url.searchParams.set("cajonzeroMap", entry.slug);
|
|
26976
26917
|
url.searchParams.set("cajonzeroRoot", entry.root);
|
|
26977
26918
|
if (entry.worldId !== void 0) url.searchParams.set("cajonzeroWorld", entry.worldId);
|
|
26978
|
-
if (entry.etag !== void 0) url.searchParams.set("cajonzeroEtag", entry.etag);
|
|
26979
26919
|
if (entry.version !== void 0) url.searchParams.set("cajonzeroVersion", entry.version);
|
|
26980
26920
|
const { maps, room } = deps.config;
|
|
26981
|
-
url.searchParams.set("cajonzeroCacheTtl", String(maps.cacheTtlSeconds));
|
|
26982
26921
|
url.searchParams.set("cajonzeroMaxBytes", String(maps.maxDownloadBytes));
|
|
26983
26922
|
url.searchParams.set("cajonzeroConcurrency", String(maps.concurrency));
|
|
26984
26923
|
url.searchParams.set("cajonzeroTimeout", String(maps.requestTimeoutMs));
|
|
@@ -27005,12 +26944,7 @@ function registerRoutes(app, deps) {
|
|
|
27005
26944
|
})
|
|
27006
26945
|
);
|
|
27007
26946
|
mountRoomGateway(app, deps);
|
|
27008
|
-
mountMapRoutes(app, deps.maps
|
|
27009
|
-
kv: deps.mapSeedKv,
|
|
27010
|
-
cacheTtlSeconds: deps.config.maps.cacheTtlSeconds,
|
|
27011
|
-
concurrency: deps.config.maps.concurrency,
|
|
27012
|
-
requestTimeoutMs: deps.config.maps.requestTimeoutMs
|
|
27013
|
-
});
|
|
26947
|
+
mountMapRoutes(app, deps.maps);
|
|
27014
26948
|
const repos = deps.repos ?? (deps.store !== void 0 ? createRepos(deps.store, { now: deps.now }) : void 0);
|
|
27015
26949
|
const getSession = deps.getSession ?? (repos !== void 0 ? createCookieSessionReader({
|
|
27016
26950
|
accounts: repos.accounts,
|
|
@@ -27033,7 +26967,6 @@ function registerRoutes(app, deps) {
|
|
|
27033
26967
|
now: deps.now,
|
|
27034
26968
|
accounts: repos.accounts,
|
|
27035
26969
|
sessions: repos.sessions,
|
|
27036
|
-
ratelimits: repos.ratelimits,
|
|
27037
26970
|
getSession,
|
|
27038
26971
|
sessionSecret: deps.sessionSecret,
|
|
27039
26972
|
environment: deps.environment,
|
|
@@ -27094,7 +27027,6 @@ function createApp(options = {}) {
|
|
|
27094
27027
|
sessionSecret: options.sessionSecret,
|
|
27095
27028
|
adminToken: options.adminToken,
|
|
27096
27029
|
environment: options.environment,
|
|
27097
|
-
mapSeedKv: options.mapSeedKv,
|
|
27098
27030
|
rooms: options.rooms,
|
|
27099
27031
|
settingDefaults: options.settingDefaults
|
|
27100
27032
|
};
|
|
@@ -27189,7 +27121,6 @@ function buildApp(env, options) {
|
|
|
27189
27121
|
const sessionSecret = resolveSessionSecret(env);
|
|
27190
27122
|
const adminToken = resolveAdminToken(env);
|
|
27191
27123
|
const environment = resolveEnvironment(env);
|
|
27192
|
-
const mapSeedKv = resolveMapSeedKv(env);
|
|
27193
27124
|
const rooms = resolveRooms(env);
|
|
27194
27125
|
const settingDefaults = resolveSettingDefaults(env);
|
|
27195
27126
|
return createApp({
|
|
@@ -27198,7 +27129,6 @@ function buildApp(env, options) {
|
|
|
27198
27129
|
...sessionSecret !== void 0 ? { sessionSecret } : {},
|
|
27199
27130
|
...adminToken !== void 0 ? { adminToken } : {},
|
|
27200
27131
|
...environment !== void 0 ? { environment } : {},
|
|
27201
|
-
...mapSeedKv !== void 0 ? { mapSeedKv } : {},
|
|
27202
27132
|
...rooms !== void 0 ? { rooms } : {},
|
|
27203
27133
|
...settingDefaults !== void 0 ? { settingDefaults } : {}
|
|
27204
27134
|
});
|
|
@@ -27216,7 +27146,6 @@ function serve(options = {}) {
|
|
|
27216
27146
|
sessionSecret: options.sessionSecret,
|
|
27217
27147
|
adminToken: options.adminToken,
|
|
27218
27148
|
environment: options.environment,
|
|
27219
|
-
mapSeedKv: options.mapSeedKv,
|
|
27220
27149
|
rooms: options.rooms,
|
|
27221
27150
|
settings: options.settings
|
|
27222
27151
|
});
|