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/core.d.ts
CHANGED
|
@@ -1,31 +1,10 @@
|
|
|
1
|
-
import { M as MapEntry, W as WorldSeed } from './providers-
|
|
2
|
-
export { c as EMPTY_MAP_CATALOG, E as EnvProvider, d as MapCatalog, e as Repos, R as Room, f as RoomOptions, g as RuntimeProviders, h as SETTINGS, i as SETTING_KEYS, a as SettingDefaults, j as SettingDefinition, k as Settings, l as SettingsError, m as SettingsErrorCode, n as SettingsService, o as StorageFactory, S as StorageSource, p as Store, q as WorldSeedReader, r as configureDefaultKV, s as createMemoryStore, t as createRepos, u as createSettingsService, v as createStore, w as findMap, x as getRuntimeProviders, y as isSettingKey, z as memoryDriver, A as parseMapCatalog, B as resolveAdminToken, C as resolveEnvironment, F as
|
|
3
|
-
export { C as CajonzeroConfig, D as DEFAULT_CONFIG, G as GAME_NET_INBOUND_BASE, a as GAME_NET_OUTBOUND_BASE, I as INBOUND_LAYOUT, M as MAX_INBOUND_FRAME_BYTES, b as MapsConfig, N as NetCodec, c as NetCodecError, d as NetCodecErrorCode, e as NetCodecHandlers, f as NetCodecOptions, O as OFFICIAL_PREFIX, g as OUTBOUND_LAYOUT, P as ProtocolDirection, h as ProtocolLayout, i as ProtocolSchemaLike, R as RoomConfig, j as chainLayouts, l as layoutMessages, k as layoutProtocol, m as matchesLayout, n as messageIds, o as messageNameAt, r as readNetFrameHeader, p as readNetMessageType, q as resolveConfig } from './config-
|
|
1
|
+
import { M as MapEntry, W as WorldSeed } from './providers-BX7e4pNW.js';
|
|
2
|
+
export { c as EMPTY_MAP_CATALOG, E as EnvProvider, d as MapCatalog, e as Repos, R as Room, f as RoomOptions, g as RuntimeProviders, h as SETTINGS, i as SETTING_KEYS, a as SettingDefaults, j as SettingDefinition, k as Settings, l as SettingsError, m as SettingsErrorCode, n as SettingsService, o as StorageFactory, S as StorageSource, p as Store, q as WorldSeedReader, r as configureDefaultKV, s as createMemoryStore, t as createRepos, u as createSettingsService, v as createStore, w as findMap, x as getRuntimeProviders, y as isSettingKey, z as memoryDriver, A as parseMapCatalog, B as resolveAdminToken, C as resolveEnvironment, F as resolveRooms, G as resolveSessionSecret, H as resolveSettingDefaults, I as resolveStore, J as setRuntimeProviders, K as setStorageFactory } from './providers-BX7e4pNW.js';
|
|
3
|
+
export { C as CajonzeroConfig, D as DEFAULT_CONFIG, G as GAME_NET_INBOUND_BASE, a as GAME_NET_OUTBOUND_BASE, I as INBOUND_LAYOUT, M as MAX_INBOUND_FRAME_BYTES, b as MapsConfig, N as NetCodec, c as NetCodecError, d as NetCodecErrorCode, e as NetCodecHandlers, f as NetCodecOptions, O as OFFICIAL_PREFIX, g as OUTBOUND_LAYOUT, P as ProtocolDirection, h as ProtocolLayout, i as ProtocolSchemaLike, R as RoomConfig, j as chainLayouts, l as layoutMessages, k as layoutProtocol, m as matchesLayout, n as messageIds, o as messageNameAt, r as readNetFrameHeader, p as readNetMessageType, q as resolveConfig } from './config-BOzAyP7m.js';
|
|
4
4
|
import 'unstorage';
|
|
5
5
|
import 'gl-matrix';
|
|
6
6
|
import 'zod';
|
|
7
7
|
|
|
8
|
-
/**
|
|
9
|
-
* cajonzero — resolved-seed cache.
|
|
10
|
-
*
|
|
11
|
-
* Reading a map straight from object storage costs one request per graph node
|
|
12
|
-
* plus one per voxel chunk (dozens of subrequests). The resolved
|
|
13
|
-
* {@link WorldSeed} is tiny by comparison (a few hundred KB), so it is cached in
|
|
14
|
-
* the deployment KV the first time a map revision is loaded and read back for
|
|
15
|
-
* every later cold start.
|
|
16
|
-
*
|
|
17
|
-
* The cache is keyed by **slug + revision (etag)**. Without a revision we do not
|
|
18
|
-
* cache, because a re-uploaded map would otherwise be served stale forever.
|
|
19
|
-
*
|
|
20
|
-
* Worker path: `btoa`/`atob` only (no Node `Buffer`).
|
|
21
|
-
*/
|
|
22
|
-
|
|
23
|
-
/** The subset of a KV namespace the cache needs (structural). */
|
|
24
|
-
interface SeedCacheKv {
|
|
25
|
-
get(key: string): Promise<string | null>;
|
|
26
|
-
put(key: string, value: string, options?: unknown): Promise<void>;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
8
|
/**
|
|
30
9
|
* cajonzero — HTTP map source.
|
|
31
10
|
*
|
|
@@ -35,8 +14,8 @@ interface SeedCacheKv {
|
|
|
35
14
|
* voxel chunk blobs. Meshes/audio are never downloaded by the server — the
|
|
36
15
|
* browser loads those straight from the same root.
|
|
37
16
|
*
|
|
38
|
-
* The
|
|
39
|
-
*
|
|
17
|
+
* The seed is resolved on demand from object storage: map bytes stay on the
|
|
18
|
+
* CDN, never in the deployment KV.
|
|
40
19
|
*
|
|
41
20
|
* Worker path: `fetch`, `AbortController`, `TextDecoder` only.
|
|
42
21
|
*/
|
|
@@ -62,10 +41,6 @@ interface HttpMapOptions {
|
|
|
62
41
|
maxDownloadBytes?: number;
|
|
63
42
|
/** Parallel voxel-chunk reads. Default 8. */
|
|
64
43
|
concurrency?: number;
|
|
65
|
-
/** KV handle used for the resolved-seed cache. */
|
|
66
|
-
kv?: SeedCacheKv;
|
|
67
|
-
/** Seed cache TTL (seconds); `0` disables it. */
|
|
68
|
-
cacheTtlSeconds?: number;
|
|
69
44
|
}
|
|
70
45
|
/**
|
|
71
46
|
* A {@link WorldSeedReader} over one unpacked map root.
|
|
@@ -91,8 +66,9 @@ declare class HttpMapSource {
|
|
|
91
66
|
/**
|
|
92
67
|
* Load one map entry into a resolved {@link WorldSeed}.
|
|
93
68
|
*
|
|
94
|
-
*
|
|
95
|
-
*
|
|
69
|
+
* Reads `bundle.json`/manifest and the project graph straight from object
|
|
70
|
+
* storage. Nothing is cached server-side: map bytes belong on the CDN, not in
|
|
71
|
+
* the deployment KV.
|
|
96
72
|
*/
|
|
97
73
|
declare function loadWorldSeedFromHttp(entry: MapEntry, options?: HttpMapOptions): Promise<WorldSeed>;
|
|
98
74
|
|
package/dist/core.js
CHANGED
|
@@ -4989,7 +4989,6 @@ var KEY_PREFIX = {
|
|
|
4989
4989
|
account: "account",
|
|
4990
4990
|
session: "session",
|
|
4991
4991
|
ban: "ban",
|
|
4992
|
-
ratelimit: "ratelimit",
|
|
4993
4992
|
settings: "settings",
|
|
4994
4993
|
mapStorage: "mapstorage"
|
|
4995
4994
|
};
|
|
@@ -5021,9 +5020,6 @@ function banAccountKey(subjectId) {
|
|
|
5021
5020
|
function banIdentityKey(kind, hash) {
|
|
5022
5021
|
return `ban:identity:${kind}:${seg2(hash)}`;
|
|
5023
5022
|
}
|
|
5024
|
-
function ratelimitKey(scope, hash) {
|
|
5025
|
-
return `ratelimit:${seg2(scope)}:${seg2(hash)}`;
|
|
5026
|
-
}
|
|
5027
5023
|
function settingsKey(key) {
|
|
5028
5024
|
return `settings:${seg2(key)}`;
|
|
5029
5025
|
}
|
|
@@ -5066,12 +5062,6 @@ function parseKey(key) {
|
|
|
5066
5062
|
}
|
|
5067
5063
|
return void 0;
|
|
5068
5064
|
}
|
|
5069
|
-
case KEY_PREFIX.ratelimit: {
|
|
5070
|
-
if (parts2.length !== 3) return void 0;
|
|
5071
|
-
const scope = decode(parts2[1]);
|
|
5072
|
-
const hash = decode(parts2[2]);
|
|
5073
|
-
return scope === void 0 || hash === void 0 ? void 0 : { kind: "ratelimit", scope, hash };
|
|
5074
|
-
}
|
|
5075
5065
|
case KEY_PREFIX.settings: {
|
|
5076
5066
|
if (parts2.length !== 2) return void 0;
|
|
5077
5067
|
const settingKey = decode(parts2[1]);
|
|
@@ -5247,7 +5237,6 @@ function parseEntry(value, index) {
|
|
|
5247
5237
|
const author = optionalString(record.author, `maps[${index}].author`);
|
|
5248
5238
|
const version = optionalString(record.version, `maps[${index}].version`);
|
|
5249
5239
|
const cover = optionalString(record.cover, `maps[${index}].cover`);
|
|
5250
|
-
const etag = optionalString(record.etag, `maps[${index}].etag`);
|
|
5251
5240
|
return {
|
|
5252
5241
|
slug,
|
|
5253
5242
|
root,
|
|
@@ -5256,7 +5245,6 @@ function parseEntry(value, index) {
|
|
|
5256
5245
|
...author !== void 0 ? { author } : {},
|
|
5257
5246
|
...version !== void 0 ? { version } : {},
|
|
5258
5247
|
...cover !== void 0 ? { cover } : {},
|
|
5259
|
-
...etag !== void 0 ? { etag } : {},
|
|
5260
5248
|
...assetRoot !== void 0 ? { assetRoot: normalizeRootUrl(assetRoot) } : {}
|
|
5261
5249
|
};
|
|
5262
5250
|
}
|
|
@@ -13853,79 +13841,24 @@ async function resolveWorldSeed(source, options = {}) {
|
|
|
13853
13841
|
};
|
|
13854
13842
|
}
|
|
13855
13843
|
|
|
13856
|
-
// src/core/maps/
|
|
13857
|
-
var
|
|
13858
|
-
function
|
|
13859
|
-
const safeRevision = encodeURIComponent(revision).slice(0, 160);
|
|
13860
|
-
return `${SEED_CACHE_PREFIX}:${encodeURIComponent(slug)}:${safeRevision}`;
|
|
13861
|
-
}
|
|
13862
|
-
function toBase64(bytes) {
|
|
13863
|
-
let binary = "";
|
|
13864
|
-
const block = 32768;
|
|
13865
|
-
for (let offset = 0; offset < bytes.length; offset += block) {
|
|
13866
|
-
binary += String.fromCharCode(...bytes.subarray(offset, offset + block));
|
|
13867
|
-
}
|
|
13868
|
-
return btoa(binary);
|
|
13869
|
-
}
|
|
13870
|
-
function fromBase64(value) {
|
|
13871
|
-
const binary = atob(value);
|
|
13872
|
-
const bytes = new Uint8Array(binary.length);
|
|
13873
|
-
for (let i = 0; i < binary.length; i += 1) {
|
|
13874
|
-
bytes[i] = binary.charCodeAt(i);
|
|
13875
|
-
}
|
|
13876
|
-
return bytes;
|
|
13877
|
-
}
|
|
13878
|
-
function encode(seed) {
|
|
13879
|
-
const wire = {
|
|
13880
|
-
version: WORLD_SEED_VERSION,
|
|
13881
|
-
seed: {
|
|
13882
|
-
...seed,
|
|
13883
|
-
voxels: seed.voxels === null ? null : {
|
|
13884
|
-
shape: seed.voxels.shape,
|
|
13885
|
-
chunkCount: seed.voxels.chunkCount,
|
|
13886
|
-
chunkBlobs: seed.voxels.chunkBlobs.map(toBase64),
|
|
13887
|
-
chunkHashes: seed.voxels.chunkHashes.slice()
|
|
13888
|
-
}
|
|
13889
|
-
}
|
|
13890
|
-
};
|
|
13891
|
-
return JSON.stringify(wire);
|
|
13892
|
-
}
|
|
13893
|
-
function decode2(raw) {
|
|
13844
|
+
// src/core/maps/block-info.ts
|
|
13845
|
+
var BLOCK_INFO_HASH = "QmW2E9E8ipYUifsCfkMj5SULYMYbFQvP6BQxo52atXw7Zj";
|
|
13846
|
+
function decodeBlockInfo(bytes) {
|
|
13894
13847
|
try {
|
|
13895
|
-
|
|
13896
|
-
if (wire.version !== WORLD_SEED_VERSION || typeof wire.seed !== "object" || wire.seed === null) {
|
|
13897
|
-
return null;
|
|
13898
|
-
}
|
|
13899
|
-
const { voxels, ...rest } = wire.seed;
|
|
13900
|
-
return {
|
|
13901
|
-
...rest,
|
|
13902
|
-
voxels: voxels === null ? null : {
|
|
13903
|
-
shape: voxels.shape,
|
|
13904
|
-
chunkCount: voxels.chunkCount,
|
|
13905
|
-
chunkBlobs: voxels.chunkBlobs.map(fromBase64),
|
|
13906
|
-
chunkHashes: Array.isArray(voxels.chunkHashes) ? voxels.chunkHashes : []
|
|
13907
|
-
}
|
|
13908
|
-
};
|
|
13848
|
+
return BlockInfoSchema.patch(BlockInfoSchema.identity, new MuReadStream(bytes));
|
|
13909
13849
|
} catch {
|
|
13910
13850
|
return null;
|
|
13911
13851
|
}
|
|
13912
13852
|
}
|
|
13913
|
-
async function
|
|
13853
|
+
async function loadBlockInfo(reader, worldId, hash = BLOCK_INFO_HASH) {
|
|
13914
13854
|
try {
|
|
13915
|
-
const
|
|
13916
|
-
|
|
13855
|
+
const bytes = await reader.read(`worlds/${worldId}/data/blobs/${hash}`);
|
|
13856
|
+
if (bytes === null || bytes.length === 0) return null;
|
|
13857
|
+
return decodeBlockInfo(bytes);
|
|
13917
13858
|
} catch {
|
|
13918
13859
|
return null;
|
|
13919
13860
|
}
|
|
13920
13861
|
}
|
|
13921
|
-
async function writeCachedSeed(kv, key, seed, ttlSeconds) {
|
|
13922
|
-
if (ttlSeconds <= 0) return;
|
|
13923
|
-
try {
|
|
13924
|
-
const options = ttlSeconds >= 60 ? { expirationTtl: ttlSeconds } : void 0;
|
|
13925
|
-
await kv.put(key, encode(seed), options);
|
|
13926
|
-
} catch {
|
|
13927
|
-
}
|
|
13928
|
-
}
|
|
13929
13862
|
|
|
13930
13863
|
// src/core/maps/http.ts
|
|
13931
13864
|
var MapSourceError = class extends Error {
|
|
@@ -14045,12 +13978,6 @@ async function resolveWorldId(source) {
|
|
|
14045
13978
|
return assertWorldId(candidate);
|
|
14046
13979
|
}
|
|
14047
13980
|
async function loadWorldSeedFromHttp(entry, options = {}) {
|
|
14048
|
-
const revision = entry.etag ?? entry.version;
|
|
14049
|
-
const cacheKey = options.kv !== void 0 && revision !== void 0 ? seedCacheKey(entry.slug, revision) : void 0;
|
|
14050
|
-
if (cacheKey !== void 0 && options.kv !== void 0) {
|
|
14051
|
-
const cached = await readCachedSeed(options.kv, cacheKey);
|
|
14052
|
-
if (cached !== null) return cached;
|
|
14053
|
-
}
|
|
14054
13981
|
const source = new HttpMapSource(entry.root, options);
|
|
14055
13982
|
const worldId = entry.worldId ?? await resolveWorldId(source);
|
|
14056
13983
|
const manifest = await source.readJson(
|
|
@@ -14059,14 +13986,13 @@ async function loadWorldSeedFromHttp(entry, options = {}) {
|
|
|
14059
13986
|
if (manifest === null) {
|
|
14060
13987
|
fail2("MAP_NO_WORLD", `worlds/${worldId}/manifest.json is missing or not JSON`);
|
|
14061
13988
|
}
|
|
14062
|
-
|
|
13989
|
+
return resolveWorldSeed(
|
|
14063
13990
|
{ worldId, manifest, reader: source },
|
|
14064
13991
|
{ concurrency: options.concurrency ?? DEFAULT_CONCURRENCY }
|
|
14065
|
-
)
|
|
14066
|
-
|
|
14067
|
-
|
|
14068
|
-
}
|
|
14069
|
-
return seed;
|
|
13992
|
+
).then(async (seed) => {
|
|
13993
|
+
const blockInfo = await loadBlockInfo(source, worldId);
|
|
13994
|
+
return blockInfo === null ? seed : { ...seed, blockInfo };
|
|
13995
|
+
});
|
|
14070
13996
|
}
|
|
14071
13997
|
var MEBIBYTE = 1024 * 1024;
|
|
14072
13998
|
var ZERO_PLAYER_TIMEOUT_DEFAULT_MS = 48e4;
|
|
@@ -15278,34 +15204,6 @@ function banDetails(input, at) {
|
|
|
15278
15204
|
const expiresAt = input.expiresAt ?? (input.durationSeconds === void 0 ? void 0 : at + input.durationSeconds * 1e3);
|
|
15279
15205
|
return { reason: input.reason, expiresAt, createdBy: input.createdBy };
|
|
15280
15206
|
}
|
|
15281
|
-
function createRateLimitsRepo(store, now) {
|
|
15282
|
-
const repo = {
|
|
15283
|
-
async increment(scope, hash, options = {}) {
|
|
15284
|
-
const windowSeconds = Math.max(1, options.windowSeconds ?? 60);
|
|
15285
|
-
const amount = options.amount ?? 1;
|
|
15286
|
-
const at = now();
|
|
15287
|
-
const current = await repo.get(scope, hash);
|
|
15288
|
-
const windowStart = current !== void 0 && current.expiresAt > at ? current.windowStart : at;
|
|
15289
|
-
const expiresAt = windowStart + windowSeconds * 1e3;
|
|
15290
|
-
const next = {
|
|
15291
|
-
count: (current !== void 0 && current.expiresAt > at ? current.count : 0) + amount,
|
|
15292
|
-
windowStart,
|
|
15293
|
-
expiresAt
|
|
15294
|
-
};
|
|
15295
|
-
const ttl = Math.max(1, Math.ceil((expiresAt - at) / 1e3));
|
|
15296
|
-
await store.setItem(ratelimitKey(scope, hash), next, { ttl });
|
|
15297
|
-
return next;
|
|
15298
|
-
},
|
|
15299
|
-
async get(scope, hash) {
|
|
15300
|
-
const record = await store.getItem(ratelimitKey(scope, hash));
|
|
15301
|
-
return record ?? void 0;
|
|
15302
|
-
},
|
|
15303
|
-
async reset(scope, hash) {
|
|
15304
|
-
await store.removeItem(ratelimitKey(scope, hash));
|
|
15305
|
-
}
|
|
15306
|
-
};
|
|
15307
|
-
return repo;
|
|
15308
|
-
}
|
|
15309
15207
|
function createSettingsRepo(store) {
|
|
15310
15208
|
return {
|
|
15311
15209
|
async get(key) {
|
|
@@ -15570,7 +15468,6 @@ function createRepos(store, options = {}) {
|
|
|
15570
15468
|
accounts: createAccountsRepo(store, now),
|
|
15571
15469
|
sessions: createSessionsRepo(store, now),
|
|
15572
15470
|
bans: createBansRepo(store, now),
|
|
15573
|
-
ratelimits: createRateLimitsRepo(store, now),
|
|
15574
15471
|
settings: createSettingsRepo(store),
|
|
15575
15472
|
mapStorage: (scope, namespace) => createMapStorageRepo(store, {
|
|
15576
15473
|
scope,
|
|
@@ -15670,9 +15567,6 @@ function resolveAdminToken(env) {
|
|
|
15670
15567
|
function resolveEnvironment(env) {
|
|
15671
15568
|
return providers.environment?.(env);
|
|
15672
15569
|
}
|
|
15673
|
-
function resolveMapSeedKv(env) {
|
|
15674
|
-
return providers.mapSeedKv?.(env);
|
|
15675
|
-
}
|
|
15676
15570
|
function resolveRooms(env) {
|
|
15677
15571
|
return providers.rooms?.(env);
|
|
15678
15572
|
}
|
|
@@ -15698,7 +15592,8 @@ function createSnapshot(input) {
|
|
|
15698
15592
|
frameSkip: input.frameSkip,
|
|
15699
15593
|
seed: input.seed ?? 0,
|
|
15700
15594
|
engine: input.engine,
|
|
15701
|
-
clients: input.clients.map((client) => ({ ...client }))
|
|
15595
|
+
clients: input.clients.map((client) => ({ ...client })),
|
|
15596
|
+
...input.map !== void 0 ? { map: { ...input.map } } : {}
|
|
15702
15597
|
};
|
|
15703
15598
|
}
|
|
15704
15599
|
function serializeSnapshot(snapshot) {
|
|
@@ -15717,9 +15612,19 @@ function deserializeSnapshot(serialized) {
|
|
|
15717
15612
|
frameSkip: parsed.frameSkip,
|
|
15718
15613
|
seed: parsed.seed,
|
|
15719
15614
|
engine: parsed.engine,
|
|
15720
|
-
clients: parsed.clients.map((client) => ({ ...client }))
|
|
15615
|
+
clients: parsed.clients.map((client) => ({ ...client })),
|
|
15616
|
+
...parsed.map !== void 0 && parsed.map !== null ? {
|
|
15617
|
+
map: {
|
|
15618
|
+
slug: parsed.map.slug,
|
|
15619
|
+
root: parsed.map.root,
|
|
15620
|
+
...parsed.map.worldId !== void 0 ? { worldId: parsed.map.worldId } : {}
|
|
15621
|
+
}
|
|
15622
|
+
} : {}
|
|
15721
15623
|
};
|
|
15722
15624
|
}
|
|
15625
|
+
function snapshotMatchesMap(snapshot, map) {
|
|
15626
|
+
return snapshot !== void 0 && snapshot.slug === map.slug && snapshot.root === map.root && (snapshot.worldId ?? null) === (map.worldId ?? null);
|
|
15627
|
+
}
|
|
15723
15628
|
|
|
15724
15629
|
// src/core/room/skin-sync.ts
|
|
15725
15630
|
var ROOM_SKIN_UPDATE_PARAM = "cajonzeroSkinUpdate";
|
|
@@ -16620,9 +16525,7 @@ function parseMapBootstrap(url) {
|
|
|
16620
16525
|
return void 0;
|
|
16621
16526
|
}
|
|
16622
16527
|
}
|
|
16623
|
-
const etag = textParam(url, "cajonzeroEtag");
|
|
16624
16528
|
const version = textParam(url, "cajonzeroVersion");
|
|
16625
|
-
const cacheTtlSeconds = numberParam(url, "cajonzeroCacheTtl", 0, 31536e3);
|
|
16626
16529
|
const maxDownloadBytes = numberParam(url, "cajonzeroMaxBytes", 1024, 1024 * 1024 * 1024);
|
|
16627
16530
|
const concurrency = numberParam(url, "cajonzeroConcurrency", 1, 64);
|
|
16628
16531
|
const requestTimeoutMs = numberParam(url, "cajonzeroTimeout", 100, 12e4);
|
|
@@ -16630,9 +16533,7 @@ function parseMapBootstrap(url) {
|
|
|
16630
16533
|
slug,
|
|
16631
16534
|
root,
|
|
16632
16535
|
...worldId !== void 0 ? { worldId } : {},
|
|
16633
|
-
...etag !== void 0 ? { etag } : {},
|
|
16634
16536
|
...version !== void 0 ? { version } : {},
|
|
16635
|
-
...cacheTtlSeconds !== void 0 ? { cacheTtlSeconds } : {},
|
|
16636
16537
|
...maxDownloadBytes !== void 0 ? { maxDownloadBytes } : {},
|
|
16637
16538
|
...concurrency !== void 0 ? { concurrency } : {},
|
|
16638
16539
|
...requestTimeoutMs !== void 0 ? { requestTimeoutMs } : {}
|
|
@@ -16679,7 +16580,6 @@ var Room = class {
|
|
|
16679
16580
|
script;
|
|
16680
16581
|
explicitScriptHost;
|
|
16681
16582
|
mapLoader;
|
|
16682
|
-
seedCacheKv;
|
|
16683
16583
|
sockets;
|
|
16684
16584
|
/** mudb wire codec: protocol envelope + netcode frames. */
|
|
16685
16585
|
codec;
|
|
@@ -16721,6 +16621,8 @@ var Room = class {
|
|
|
16721
16621
|
mapLoading;
|
|
16722
16622
|
worldReady = false;
|
|
16723
16623
|
snapshotRestored = false;
|
|
16624
|
+
/** One-shot guard for the "proof without sessionSecret" diagnostic. */
|
|
16625
|
+
guestWarningLogged = false;
|
|
16724
16626
|
persistence;
|
|
16725
16627
|
socketsStarted = false;
|
|
16726
16628
|
perf = { minPing: 0, maxPing: 0, avgPing: 0, pingCount: 0 };
|
|
@@ -16732,6 +16634,10 @@ var Room = class {
|
|
|
16732
16634
|
inboundIds = /* @__PURE__ */ new Map();
|
|
16733
16635
|
/** Snapshot parked by `init()` until the seeded engine exists. */
|
|
16734
16636
|
pendingEngineSnapshot = null;
|
|
16637
|
+
/** Map identity stored with the parked snapshot (absent on legacy snapshots). */
|
|
16638
|
+
pendingEngineMap;
|
|
16639
|
+
/** Identity of the map the current engine was seeded from. */
|
|
16640
|
+
seededMap;
|
|
16735
16641
|
heartbeatBeats = 0;
|
|
16736
16642
|
ticksRun = 0;
|
|
16737
16643
|
lastTickError;
|
|
@@ -16759,7 +16665,6 @@ var Room = class {
|
|
|
16759
16665
|
this.explicitScriptHost = options.scriptHost !== void 0;
|
|
16760
16666
|
this.script = options.scriptHost ?? this.engine;
|
|
16761
16667
|
this.mapBootstrap = options.map;
|
|
16762
|
-
this.seedCacheKv = resolveMapSeedKv(env);
|
|
16763
16668
|
this.mapLoader = options.loadMapSeed ?? ((bootstrap) => this.loadSeed(bootstrap));
|
|
16764
16669
|
this.registryTtlSeconds = options.registryTtlSeconds ?? DEFAULT_SESSION_SLOT_TTL_SECONDS;
|
|
16765
16670
|
const banCacheTtlMs = options.banCacheTtlMs ?? DEFAULT_BAN_CACHE_TTL_MS2;
|
|
@@ -16813,6 +16718,7 @@ var Room = class {
|
|
|
16813
16718
|
this.tickValue = snapshot.tick;
|
|
16814
16719
|
this.frameSkip = snapshot.frameSkip;
|
|
16815
16720
|
this.pendingEngineSnapshot = snapshot.engine;
|
|
16721
|
+
this.pendingEngineMap = snapshot.map;
|
|
16816
16722
|
this.snapshotRestored = true;
|
|
16817
16723
|
}
|
|
16818
16724
|
try {
|
|
@@ -16937,11 +16843,30 @@ var Room = class {
|
|
|
16937
16843
|
}
|
|
16938
16844
|
await this.mapLoading;
|
|
16939
16845
|
}
|
|
16940
|
-
/**
|
|
16846
|
+
/**
|
|
16847
|
+
* Apply a snapshot parked by `init()` exactly once.
|
|
16848
|
+
*
|
|
16849
|
+
* A snapshot describes the world of the map it was captured from. Restoring
|
|
16850
|
+
* one that came from another map (or from a room that never had a map) would
|
|
16851
|
+
* replace the freshly seeded entities with nothing, leaving terrain but no
|
|
16852
|
+
* models — so it is dropped instead. Dropping it also resets the tick
|
|
16853
|
+
* counters, which `init()` had adopted optimistically.
|
|
16854
|
+
*/
|
|
16941
16855
|
applyPendingEngineSnapshot() {
|
|
16942
16856
|
if (this.pendingEngineSnapshot === null) return;
|
|
16943
|
-
this.
|
|
16857
|
+
const pending = this.pendingEngineSnapshot;
|
|
16858
|
+
const pendingMap = this.pendingEngineMap;
|
|
16944
16859
|
this.pendingEngineSnapshot = null;
|
|
16860
|
+
this.pendingEngineMap = void 0;
|
|
16861
|
+
if (this.seededMap !== void 0) {
|
|
16862
|
+
if (!snapshotMatchesMap(pendingMap, this.seededMap)) {
|
|
16863
|
+
this.tickValue = 0;
|
|
16864
|
+
this.frameSkip = 0;
|
|
16865
|
+
clearServerNetState(this.net, 0);
|
|
16866
|
+
return;
|
|
16867
|
+
}
|
|
16868
|
+
}
|
|
16869
|
+
this.engine.restore(pending);
|
|
16945
16870
|
}
|
|
16946
16871
|
async loadWorld(bootstrap) {
|
|
16947
16872
|
try {
|
|
@@ -16957,6 +16882,7 @@ var Room = class {
|
|
|
16957
16882
|
const engine = factory({ worldSeed: seed });
|
|
16958
16883
|
this.engine = engine;
|
|
16959
16884
|
if (!this.explicitScriptHost) this.script = engine;
|
|
16885
|
+
this.seededMap = { slug: bootstrap.slug, root: bootstrap.root, worldId: seed.mapId };
|
|
16960
16886
|
this.applyPendingEngineSnapshot();
|
|
16961
16887
|
this.worldReady = true;
|
|
16962
16888
|
this.logger.log(`cajonzero: seeded room "${bootstrap.slug}" from "${seed.mapId}"`);
|
|
@@ -16968,8 +16894,6 @@ var Room = class {
|
|
|
16968
16894
|
}
|
|
16969
16895
|
loadSeed(bootstrap) {
|
|
16970
16896
|
return loadWorldSeedFromHttp(bootstrap, {
|
|
16971
|
-
...this.seedCacheKv !== void 0 ? { kv: this.seedCacheKv } : {},
|
|
16972
|
-
cacheTtlSeconds: bootstrap.cacheTtlSeconds ?? 0,
|
|
16973
16897
|
...bootstrap.maxDownloadBytes !== void 0 ? { maxDownloadBytes: bootstrap.maxDownloadBytes } : {},
|
|
16974
16898
|
...bootstrap.concurrency !== void 0 ? { concurrency: bootstrap.concurrency } : {},
|
|
16975
16899
|
...bootstrap.requestTimeoutMs !== void 0 ? { requestTimeoutMs: bootstrap.requestTimeoutMs } : {}
|
|
@@ -17044,6 +16968,13 @@ var Room = class {
|
|
|
17044
16968
|
this.pendingIdentities.set(sessionId, identity2);
|
|
17045
16969
|
}
|
|
17046
16970
|
} else {
|
|
16971
|
+
const proof = extractSessionProof(request.headers.get("sec-websocket-protocol"));
|
|
16972
|
+
if (proof !== void 0 && !this.guestWarningLogged) {
|
|
16973
|
+
this.guestWarningLogged = true;
|
|
16974
|
+
this.logger.error(
|
|
16975
|
+
"cajonzero: a session proof was supplied but no sessionSecret is configured; players join as guest. Pass serve({ sessionSecret: (env) => env.<SECRET> })."
|
|
16976
|
+
);
|
|
16977
|
+
}
|
|
17047
16978
|
identity2 = guestIdentity(sessionId);
|
|
17048
16979
|
}
|
|
17049
16980
|
const ip = resolveClientIp(request);
|
|
@@ -17705,7 +17636,8 @@ var Room = class {
|
|
|
17705
17636
|
tick: this.tickValue,
|
|
17706
17637
|
frameSkip: this.frameSkip,
|
|
17707
17638
|
engine: this.engine.capture(),
|
|
17708
|
-
clients: [...this.connections.values()].map(toSnapshotClient)
|
|
17639
|
+
clients: [...this.connections.values()].map(toSnapshotClient),
|
|
17640
|
+
...this.seededMap !== void 0 ? { map: { ...this.seededMap } } : {}
|
|
17709
17641
|
});
|
|
17710
17642
|
}
|
|
17711
17643
|
/**
|
|
@@ -17818,7 +17750,6 @@ var DEFAULT_CONFIG = {
|
|
|
17818
17750
|
admin: { path: "/admin" },
|
|
17819
17751
|
room: { tickRate: 64, emptyGraceMs: 48e4 },
|
|
17820
17752
|
maps: {
|
|
17821
|
-
cacheTtlSeconds: 86400,
|
|
17822
17753
|
maxDownloadBytes: 32 * 1024 * 1024,
|
|
17823
17754
|
concurrency: 8,
|
|
17824
17755
|
requestTimeoutMs: 15e3
|
|
@@ -17877,13 +17808,6 @@ function resolveConfig(input) {
|
|
|
17877
17808
|
)
|
|
17878
17809
|
},
|
|
17879
17810
|
maps: {
|
|
17880
|
-
cacheTtlSeconds: integer(
|
|
17881
|
-
maps.cacheTtlSeconds,
|
|
17882
|
-
DEFAULT_CONFIG.maps.cacheTtlSeconds,
|
|
17883
|
-
"maps.cacheTtlSeconds",
|
|
17884
|
-
0,
|
|
17885
|
-
31536e3
|
|
17886
|
-
),
|
|
17887
17811
|
maxDownloadBytes: integer(
|
|
17888
17812
|
maps.maxDownloadBytes,
|
|
17889
17813
|
DEFAULT_CONFIG.maps.maxDownloadBytes,
|
|
@@ -17912,6 +17836,6 @@ function resolveConfig(input) {
|
|
|
17912
17836
|
// src/core.ts
|
|
17913
17837
|
var CORE_ENTRYPOINT = "cajonzero/core";
|
|
17914
17838
|
|
|
17915
|
-
export { CORE_ENTRYPOINT, DEFAULT_CONFIG, EMPTY_MAP_CATALOG, GAME_NET_INBOUND_BASE, GAME_NET_OUTBOUND_BASE, HttpMapSource, INBOUND_LAYOUT, MAX_INBOUND_FRAME_BYTES, MapSourceError, NetCodec, NetCodecError, OFFICIAL_PREFIX, OUTBOUND_LAYOUT, Room, SETTINGS, SETTING_KEYS, SettingsError, chainLayouts, configureDefaultKV, createMemoryStore, createRepos, createSettingsService, createStore, findMap, getRuntimeProviders, isSettingKey, layoutMessages, layoutProtocol, loadWorldSeedFromHttp, matchesLayout, memoryDriver, messageIds, messageNameAt, parseMapCatalog, readNetFrameHeader, readNetMessageType, resolveAdminToken, resolveConfig, resolveEnvironment,
|
|
17839
|
+
export { CORE_ENTRYPOINT, DEFAULT_CONFIG, EMPTY_MAP_CATALOG, GAME_NET_INBOUND_BASE, GAME_NET_OUTBOUND_BASE, HttpMapSource, INBOUND_LAYOUT, MAX_INBOUND_FRAME_BYTES, MapSourceError, NetCodec, NetCodecError, OFFICIAL_PREFIX, OUTBOUND_LAYOUT, Room, SETTINGS, SETTING_KEYS, SettingsError, chainLayouts, configureDefaultKV, createMemoryStore, createRepos, createSettingsService, createStore, findMap, getRuntimeProviders, isSettingKey, layoutMessages, layoutProtocol, loadWorldSeedFromHttp, matchesLayout, memoryDriver, messageIds, messageNameAt, parseMapCatalog, readNetFrameHeader, readNetMessageType, resolveAdminToken, resolveConfig, resolveEnvironment, resolveRooms, resolveSessionSecret, resolveSettingDefaults, resolveStore, setRuntimeProviders, setStorageFactory };
|
|
17916
17840
|
//# sourceMappingURL=core.js.map
|
|
17917
17841
|
//# sourceMappingURL=core.js.map
|
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { Context, Hono } from 'hono';
|
|
2
2
|
import { ContentfulStatusCode } from 'hono/utils/http-status';
|
|
3
|
-
import { b as Env, d as MapCatalog, e as Repos,
|
|
3
|
+
import { b as Env, d as MapCatalog, e as Repos, L as SessionsRepo, D as DurableObjectNamespace } from './providers-BX7e4pNW.js';
|
|
4
4
|
import { Store, SettingDefaults } from './core.js';
|
|
5
|
-
export { c as EMPTY_MAP_CATALOG, M as MapEntry, R as Room, w as findMap, A as parseMapCatalog } from './providers-
|
|
6
|
-
import { C as CajonzeroConfig } from './config-
|
|
7
|
-
export { D as DEFAULT_CONFIG, G as GAME_NET_INBOUND_BASE, a as GAME_NET_OUTBOUND_BASE, b as MapsConfig, N as NetCodec, e as NetCodecHandlers, R as RoomConfig, q as resolveConfig } from './config-
|
|
5
|
+
export { c as EMPTY_MAP_CATALOG, M as MapEntry, R as Room, w as findMap, A as parseMapCatalog } from './providers-BX7e4pNW.js';
|
|
6
|
+
import { C as CajonzeroConfig } from './config-BOzAyP7m.js';
|
|
7
|
+
export { D as DEFAULT_CONFIG, G as GAME_NET_INBOUND_BASE, a as GAME_NET_OUTBOUND_BASE, b as MapsConfig, N as NetCodec, e as NetCodecHandlers, R as RoomConfig, q as resolveConfig } from './config-BOzAyP7m.js';
|
|
8
8
|
export { DO_CLASSES, ServeOptions, WorkersEntry, WorkersModule, serve } from './serve.js';
|
|
9
9
|
import 'unstorage';
|
|
10
10
|
import 'gl-matrix';
|
|
@@ -18,7 +18,7 @@ import 'zod';
|
|
|
18
18
|
* can read the version without creating a circular import.
|
|
19
19
|
*/
|
|
20
20
|
declare const NAME = "cajonzero";
|
|
21
|
-
declare const VERSION = "0.1.
|
|
21
|
+
declare const VERSION = "0.1.1";
|
|
22
22
|
|
|
23
23
|
/** The authenticated principal carried by a login session (T11 supplies it). */
|
|
24
24
|
interface SessionIdentity {
|
|
@@ -90,7 +90,6 @@ interface AppDeps {
|
|
|
90
90
|
readonly sessionSecret?: string;
|
|
91
91
|
readonly adminToken?: string;
|
|
92
92
|
readonly environment?: string;
|
|
93
|
-
readonly mapSeedKv?: KVNamespace;
|
|
94
93
|
readonly rooms?: DurableObjectNamespace;
|
|
95
94
|
readonly settingDefaults?: SettingDefaults;
|
|
96
95
|
}
|
|
@@ -116,7 +115,6 @@ interface CreateAppOptions {
|
|
|
116
115
|
readonly sessionSecret?: string;
|
|
117
116
|
readonly adminToken?: string;
|
|
118
117
|
readonly environment?: string;
|
|
119
|
-
readonly mapSeedKv?: KVNamespace;
|
|
120
118
|
readonly rooms?: DurableObjectNamespace;
|
|
121
119
|
readonly settingDefaults?: SettingDefaults;
|
|
122
120
|
}
|