cajonzero 0.1.3 → 0.2.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/LICENSE +21 -21
- package/README.md +36 -53
- package/dist/bin/cj0.js +2145 -1553
- package/dist/catalog-BRO-mQoP.d.ts +67 -0
- package/dist/{config-B32NDXlr.d.ts → config-glwUbUbx.d.ts} +1 -1
- package/dist/core.d.ts +10 -7
- package/dist/core.js +15035 -312
- package/dist/index.d.ts +7 -5
- package/dist/index.js +31958 -9898
- package/dist/maps.d.ts +182 -0
- package/dist/maps.js +14062 -0
- package/dist/{providers-BwJKzGkd.d.ts → providers-Bu0-iMVs.d.ts} +114 -58
- package/dist/quickjs.wasm +0 -0
- package/dist/scaffold.d.ts +18 -15
- package/dist/scaffold.js +67 -45
- package/dist/serve.d.ts +2 -1
- package/dist/serve.js +32749 -10689
- package/dist/ui/assets/index-Bf4Kjuyg.js +4404 -0
- package/dist/ui/assets/index-ZzhH55rc.css +2 -0
- package/dist/ui/assets/{main-DTcEV4JE.js → main-DB66UjcY.js} +4 -4
- package/dist/ui/assets/{voxel.worker-CvX1GY4o.js → voxel.worker-BFiKMi1W.js} +1 -1
- package/dist/ui/index.html +2 -2
- package/package.json +103 -95
- package/dist/ui/assets/index-Bhv7LV8L.css +0 -2
- package/dist/ui/assets/index-CNHWg0_t.js +0 -4404
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Storage, StorageValue, Driver } from 'unstorage';
|
|
2
|
+
import { M as MapEntry } from './catalog-BRO-mQoP.js';
|
|
2
3
|
import * as gl_matrix from 'gl-matrix';
|
|
3
4
|
import { vec3, mat3 } from 'gl-matrix';
|
|
4
5
|
import { z } from 'zod';
|
|
@@ -144,6 +145,13 @@ interface AssetsBinding {
|
|
|
144
145
|
interface Env {
|
|
145
146
|
/** KV namespace: map code/asset KV and player data (unstorage KV adapter). */
|
|
146
147
|
readonly CAJONZERO_KV: KVNamespace;
|
|
148
|
+
/**
|
|
149
|
+
* Optional private KV namespace for server-only map scripts.
|
|
150
|
+
*
|
|
151
|
+
* Public seed packs strip `scripts`; this binding is the non-public half
|
|
152
|
+
* (`scripts:<slug>` → `cajonzero-scripts` JSON). Never served over HTTP.
|
|
153
|
+
*/
|
|
154
|
+
readonly CAJONZERO_SCRIPTS?: KVNamespace;
|
|
147
155
|
/** Durable Object namespace for per-room actors (`Room`). */
|
|
148
156
|
readonly ROOMS: DurableObjectNamespace;
|
|
149
157
|
/**
|
|
@@ -510,61 +518,6 @@ interface SessionRegistry {
|
|
|
510
518
|
current(accountId: string): Promise<SessionSlotRecord | undefined>;
|
|
511
519
|
}
|
|
512
520
|
|
|
513
|
-
/**
|
|
514
|
-
* cajonzero — the map catalog (`cajonzero/maps.json`).
|
|
515
|
-
*
|
|
516
|
-
* Maps are **not** stored by cajonzero. A `.boxplay` is unpacked by the operator
|
|
517
|
-
* and uploaded to object storage (OSS/CDN); `maps.json` only records where each
|
|
518
|
-
* map's unpacked root lives.
|
|
519
|
-
*
|
|
520
|
-
* Expected layout under `entry.root` (exactly the archive layout):
|
|
521
|
-
*
|
|
522
|
-
* ```text
|
|
523
|
-
* <root>/bundle.json
|
|
524
|
-
* <root>/worlds/<worldId>/manifest.json
|
|
525
|
-
* <root>/worlds/<worldId>/data/project-state.json
|
|
526
|
-
* <root>/worlds/<worldId>/data/blobs/<cid>
|
|
527
|
-
* ```
|
|
528
|
-
*
|
|
529
|
-
* Worker path: URL handling + validation only, no Node globals.
|
|
530
|
-
*/
|
|
531
|
-
/** The only catalog version this build understands. */
|
|
532
|
-
declare const MAP_CATALOG_VERSION = 1;
|
|
533
|
-
/** One map in the catalog. */
|
|
534
|
-
interface MapEntry {
|
|
535
|
-
/** Stable room/catalog id (`omega`, `drift`, …). */
|
|
536
|
-
readonly slug: string;
|
|
537
|
-
/** Unpacked map root, absolute `http(s)://…/` URL. */
|
|
538
|
-
readonly root: string;
|
|
539
|
-
/** `worlds/<worldId>` directory name; derived from `bundle.json` when absent. */
|
|
540
|
-
readonly worldId?: string;
|
|
541
|
-
/** Display name (falls back to the map's own manifest). */
|
|
542
|
-
readonly name?: string;
|
|
543
|
-
readonly author?: string;
|
|
544
|
-
readonly version?: string;
|
|
545
|
-
/** Optional content revision (e.g. `v1.0.4`); invalidates precomputed seeds. */
|
|
546
|
-
readonly etag?: string;
|
|
547
|
-
/** Cover image URL for the lobby. */
|
|
548
|
-
readonly cover?: string;
|
|
549
|
-
/** Optional CDN root for browser assets; defaults to {@link root}. */
|
|
550
|
-
readonly assetRoot?: string;
|
|
551
|
-
}
|
|
552
|
-
/** The `maps.json` document. */
|
|
553
|
-
interface MapCatalog {
|
|
554
|
-
readonly version: typeof MAP_CATALOG_VERSION;
|
|
555
|
-
readonly maps: readonly MapEntry[];
|
|
556
|
-
}
|
|
557
|
-
/** No maps configured (the scaffold default). */
|
|
558
|
-
declare const EMPTY_MAP_CATALOG: MapCatalog;
|
|
559
|
-
/**
|
|
560
|
-
* Validate a parsed `maps.json`.
|
|
561
|
-
*
|
|
562
|
-
* @throws {MapCatalogError} for a malformed document, entry, or duplicate slug.
|
|
563
|
-
*/
|
|
564
|
-
declare function parseMapCatalog(input: unknown): MapCatalog;
|
|
565
|
-
/** Look up a map by slug. */
|
|
566
|
-
declare function findMap(catalog: MapCatalog, slug: string): MapEntry | undefined;
|
|
567
|
-
|
|
568
521
|
declare class MuBuffer {
|
|
569
522
|
buffer: ArrayBuffer;
|
|
570
523
|
dataView: DataView;
|
|
@@ -2425,6 +2378,8 @@ interface SeedMesh {
|
|
|
2425
2378
|
duration: number;
|
|
2426
2379
|
}[];
|
|
2427
2380
|
renderBoxOffset?: [number, number, number];
|
|
2381
|
+
/** `voxelModel` | `gltfModel` (client model loader dispatch). */
|
|
2382
|
+
hashType?: string;
|
|
2428
2383
|
}
|
|
2429
2384
|
/** A map entity that should render a mesh (static scenery / vehicles). */
|
|
2430
2385
|
interface SeedRenderEntity {
|
|
@@ -2445,6 +2400,36 @@ interface SeedRender {
|
|
|
2445
2400
|
entities: SeedRenderEntity[];
|
|
2446
2401
|
warnings: string[];
|
|
2447
2402
|
}
|
|
2403
|
+
/** One server-side script module resolved from `scriptAssets`. */
|
|
2404
|
+
interface SeedScriptModule {
|
|
2405
|
+
/** Content hash (`data/blobs/<hash>`). */
|
|
2406
|
+
hash: string;
|
|
2407
|
+
/** UTF-8 module source. */
|
|
2408
|
+
source: string;
|
|
2409
|
+
/** Editor ordering hint (diagnostics only). */
|
|
2410
|
+
order: number;
|
|
2411
|
+
/** Logical name from `scriptAssets` (usually the file id). */
|
|
2412
|
+
name?: string;
|
|
2413
|
+
}
|
|
2414
|
+
/** Resolved server-side map scripts (`scriptIndex` + modules). */
|
|
2415
|
+
interface SeedScripts {
|
|
2416
|
+
/** Entry module key, e.g. `index.js` (empty when the map has no scripts). */
|
|
2417
|
+
index: string;
|
|
2418
|
+
modules: Record<string, SeedScriptModule>;
|
|
2419
|
+
/** Map catalog version/etag at pack time (private-pack cache key). */
|
|
2420
|
+
revision?: string;
|
|
2421
|
+
}
|
|
2422
|
+
/** Per-entity seed metadata used by the map-script runtime (name + tags). */
|
|
2423
|
+
interface SeedEntitySeedInfo {
|
|
2424
|
+
id: number;
|
|
2425
|
+
name: string;
|
|
2426
|
+
tags: string[];
|
|
2427
|
+
}
|
|
2428
|
+
/** One audio asset (path → content hash) for `world.sound` / `resources`. */
|
|
2429
|
+
interface SeedAudioAsset {
|
|
2430
|
+
path: string;
|
|
2431
|
+
hash: string;
|
|
2432
|
+
}
|
|
2448
2433
|
/** The resolved, pure world seed. */
|
|
2449
2434
|
interface WorldSeed {
|
|
2450
2435
|
version: number;
|
|
@@ -2463,6 +2448,12 @@ interface WorldSeed {
|
|
|
2463
2448
|
voxels: SeedVoxels | null;
|
|
2464
2449
|
/** Mesh/entity render projection (empty when the map has no models). */
|
|
2465
2450
|
render?: SeedRender;
|
|
2451
|
+
/** Server-side map scripts. Never include this in a public seed pack. */
|
|
2452
|
+
scripts?: SeedScripts;
|
|
2453
|
+
/** Entity names/tags used to seed the map-script entity table. */
|
|
2454
|
+
seedInfo?: SeedEntitySeedInfo[];
|
|
2455
|
+
/** Audio assets for `resources` / `world.sound`. */
|
|
2456
|
+
audioAssets?: SeedAudioAsset[];
|
|
2466
2457
|
/** Number of entities present in the map's `entitiesTree`. */
|
|
2467
2458
|
entityCount: number;
|
|
2468
2459
|
/** Human-readable record of anything skipped (never silently dropped). */
|
|
@@ -2655,6 +2646,32 @@ interface SettingsService {
|
|
|
2655
2646
|
/** Construct a {@link SettingsService} over a T4 `SettingsRepo`. */
|
|
2656
2647
|
declare function createSettingsService(options: CreateSettingsServiceOptions): SettingsService;
|
|
2657
2648
|
|
|
2649
|
+
type ProtocolMessageHandler = (sessionId: string, data: unknown, unreliable: boolean) => void;
|
|
2650
|
+
interface ProtocolBusOptions {
|
|
2651
|
+
/** Send reliable bytes on the player's game socket. */
|
|
2652
|
+
send(sessionId: string, bytes: Uint8Array, unreliable: boolean): void;
|
|
2653
|
+
}
|
|
2654
|
+
declare class ProtocolBus {
|
|
2655
|
+
private readonly options;
|
|
2656
|
+
private readonly inbound;
|
|
2657
|
+
private readonly outbound;
|
|
2658
|
+
private readonly inboundByBase;
|
|
2659
|
+
private readonly handlers;
|
|
2660
|
+
constructor(options: ProtocolBusOptions);
|
|
2661
|
+
/** Register a handler for one inbound protocol message. */
|
|
2662
|
+
on(protocol: string, message: string, handler: ProtocolMessageHandler): void;
|
|
2663
|
+
/**
|
|
2664
|
+
* Try to decode a post-game-net frame. Returns `true` when the id belongs to
|
|
2665
|
+
* this bus (even if no handler is registered), so `NetCodec` never logs it as
|
|
2666
|
+
* unknown. Returns `false` for game-net frames.
|
|
2667
|
+
*/
|
|
2668
|
+
tryDecode(sessionId: string, data: Uint8Array | string, unreliable: boolean): boolean;
|
|
2669
|
+
/** Encode one server→client message for `protocol`. */
|
|
2670
|
+
encode(protocol: string, message: string, payload: unknown): Uint8Array | null;
|
|
2671
|
+
/** Encode and send one server→client message. */
|
|
2672
|
+
send(sessionId: string, protocol: string, message: string, payload: unknown, unreliable?: boolean): boolean;
|
|
2673
|
+
}
|
|
2674
|
+
|
|
2658
2675
|
/**
|
|
2659
2676
|
* cajonzero — mudb `MuSocketServer`-compatible adapter for Cloudflare workerd (T8).
|
|
2660
2677
|
*
|
|
@@ -4941,6 +4958,8 @@ interface ScriptHost {
|
|
|
4941
4958
|
clearEvents(): void;
|
|
4942
4959
|
suspend(): void;
|
|
4943
4960
|
resume(): void;
|
|
4961
|
+
/** Optional teardown (QuickJS VM, timers). Called when the room is replaced. */
|
|
4962
|
+
dispose?(): void;
|
|
4944
4963
|
}
|
|
4945
4964
|
/** The Durable Object storage surface the room uses (structural). */
|
|
4946
4965
|
interface RoomStorage {
|
|
@@ -4976,6 +4995,14 @@ interface RoomOptions {
|
|
|
4976
4995
|
*/
|
|
4977
4996
|
emptyGraceMs?: number;
|
|
4978
4997
|
heartbeatIntervalMs?: number;
|
|
4998
|
+
/**
|
|
4999
|
+
* Drop a connection that has sent no frame for this long (ms). Defaults to
|
|
5000
|
+
* {@link DEFAULT_PLAYER_IDLE_TIMEOUT_MS}. This is the room's own liveness
|
|
5001
|
+
* check — a client that never sends a close frame must still be removed.
|
|
5002
|
+
*/
|
|
5003
|
+
playerIdleTimeoutMs?: number;
|
|
5004
|
+
/** How often to look for silent connections (ms). Defaults to 60 s. */
|
|
5005
|
+
idleSweepIntervalMs?: number;
|
|
4979
5006
|
maxStepsPerFrame?: number;
|
|
4980
5007
|
/** Simulation engine. Defaults to the registered factory or a null engine. */
|
|
4981
5008
|
engine?: RoomEngine;
|
|
@@ -5038,6 +5065,12 @@ declare class Room {
|
|
|
5038
5065
|
/** Tracks the async settings read that arms the grace timer at drain. */
|
|
5039
5066
|
private graceOps;
|
|
5040
5067
|
private readonly heartbeatIntervalMs;
|
|
5068
|
+
private readonly playerIdleTimeoutMs;
|
|
5069
|
+
private readonly idleSweepIntervalMs;
|
|
5070
|
+
/** Wall-clock of the last sweep for silent connections. */
|
|
5071
|
+
private lastIdleSweepAt;
|
|
5072
|
+
/** Last time an inbound frame was seen per session (liveness). */
|
|
5073
|
+
private readonly lastSeenAt;
|
|
5041
5074
|
private readonly maxStepsPerFrame;
|
|
5042
5075
|
private readonly manualClock;
|
|
5043
5076
|
private readonly createPair;
|
|
@@ -5045,6 +5078,8 @@ declare class Room {
|
|
|
5045
5078
|
private readonly secret;
|
|
5046
5079
|
/** Worker static-assets binding, used to read seed packs bundled at deploy. */
|
|
5047
5080
|
private readonly assets;
|
|
5081
|
+
private readonly scriptsKv;
|
|
5082
|
+
private readonly store;
|
|
5048
5083
|
private engine;
|
|
5049
5084
|
private script;
|
|
5050
5085
|
private readonly explicitScriptHost;
|
|
@@ -5052,6 +5087,7 @@ declare class Room {
|
|
|
5052
5087
|
private readonly sockets;
|
|
5053
5088
|
/** mudb wire codec: protocol envelope + netcode frames. */
|
|
5054
5089
|
private readonly codec;
|
|
5090
|
+
private readonly protocolBus;
|
|
5055
5091
|
private readonly modelCodec;
|
|
5056
5092
|
private readonly messageHandlers;
|
|
5057
5093
|
private readonly banChecker;
|
|
@@ -5159,6 +5195,14 @@ declare class Room {
|
|
|
5159
5195
|
private applyPendingEngineSnapshot;
|
|
5160
5196
|
private loadWorld;
|
|
5161
5197
|
private loadSeed;
|
|
5198
|
+
/**
|
|
5199
|
+
* Merge the private scripts pack (`CAJONZERO_SCRIPTS`) into a public seed.
|
|
5200
|
+
*
|
|
5201
|
+
* Public seed packs deliberately strip `scripts`; this binding is the
|
|
5202
|
+
* server-only half and is never served over HTTP. Missing/broken packs keep
|
|
5203
|
+
* the room playable without scripts.
|
|
5204
|
+
*/
|
|
5205
|
+
private attachPrivateScripts;
|
|
5162
5206
|
/**
|
|
5163
5207
|
* Run the full connect path and return a structured outcome (no `Response`,
|
|
5164
5208
|
* so tests can drive it without a workerd runtime). Steps: resolve the sid →
|
|
@@ -5177,7 +5221,6 @@ declare class Room {
|
|
|
5177
5221
|
private admitConnectionOnce;
|
|
5178
5222
|
private startSockets;
|
|
5179
5223
|
private registerSocket;
|
|
5180
|
-
/** Build the per-connection codec callback table (allocated once per socket). */
|
|
5181
5224
|
private createHandlers;
|
|
5182
5225
|
/**
|
|
5183
5226
|
* Decode one inbound frame. A protocol violation closes the socket exactly like
|
|
@@ -5275,6 +5318,17 @@ declare class Room {
|
|
|
5275
5318
|
* secret diff → pings → clear events.
|
|
5276
5319
|
*/
|
|
5277
5320
|
tickOnce(): void;
|
|
5321
|
+
/**
|
|
5322
|
+
* Drop connections the client never told us about.
|
|
5323
|
+
*
|
|
5324
|
+
* A player is normally removed by `removeClient` when the socket closes, but
|
|
5325
|
+
* a browser cannot be trusted to send that close frame: an SPA that tears the
|
|
5326
|
+
* engine down half-way, a sleeping laptop, a dropped mobile link or a killed
|
|
5327
|
+
* tab all leave the socket open from the room's point of view. Without this
|
|
5328
|
+
* sweep the player stays in the world for everyone else and keeps the
|
|
5329
|
+
* account's session slot.
|
|
5330
|
+
*/
|
|
5331
|
+
private sweepIdleConnections;
|
|
5278
5332
|
private buildContext;
|
|
5279
5333
|
private buildSecret;
|
|
5280
5334
|
private startTickLoop;
|
|
@@ -5312,6 +5366,8 @@ declare class Room {
|
|
|
5312
5366
|
get phase(): RoomPhase;
|
|
5313
5367
|
/** Current simulation tick. */
|
|
5314
5368
|
get tick(): number;
|
|
5369
|
+
/** Extra game-socket protocols (dialog/chat/gui/...) after `game-net`. */
|
|
5370
|
+
getProtocolBus(): ProtocolBus;
|
|
5315
5371
|
/** `true` once the empty-grace window has elapsed (heartbeat released). */
|
|
5316
5372
|
get isEvictable(): boolean;
|
|
5317
5373
|
/** `true` while the draining heartbeat is armed (the DO is pinned). */
|
|
@@ -5378,5 +5434,5 @@ declare function resolveEnvironment(env: Env): string | undefined;
|
|
|
5378
5434
|
declare function resolveRooms(env: Env): DurableObjectNamespace | undefined;
|
|
5379
5435
|
declare function resolveSettingDefaults(env: Env): SettingDefaults | undefined;
|
|
5380
5436
|
|
|
5381
|
-
export {
|
|
5382
|
-
export type { DurableObjectNamespace as D, EnvProvider as E, SessionsRepo as
|
|
5437
|
+
export { resolveSessionSecret as A, resolveSettingDefaults as B, resolveStore as C, setRuntimeProviders as F, setStorageFactory as G, Room as R, SETTINGS as f, SETTING_KEYS as g, SettingsError as j, configureDefaultKV as p, createMemoryStore as q, createRepos as r, createSettingsService as s, createStore as t, getRuntimeProviders as u, isSettingKey as v, memoryDriver as w, resolveAdminToken as x, resolveEnvironment as y, resolveRooms as z };
|
|
5438
|
+
export type { DurableObjectNamespace as D, EnvProvider as E, SessionsRepo as H, NetSecret as I, NetPublic as N, StorageSource as S, TimestampedClientInput as T, WorldSeed as W, SettingDefaults as a, Env as b, Repos as c, RoomOptions as d, RuntimeProviders as e, SettingDefinition as h, Settings as i, SettingsErrorCode as k, SettingsService as l, StorageFactory as m, Store as n, WorldSeedReader as o };
|
|
Binary file
|
package/dist/scaffold.d.ts
CHANGED
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
* ## Where configuration lives
|
|
11
11
|
*
|
|
12
12
|
* - `cajonzero/config.json` — cajonzero runtime config (room policy, map fetch policy).
|
|
13
|
-
* - `cajonzero/maps.json` — the map catalog;
|
|
14
|
-
*
|
|
13
|
+
* - `cajonzero/maps.json` — the map catalog; `cj0 add` writes `/maps/<slug>/` roots
|
|
14
|
+
* (static assets) and the operator may switch a root to an external CDN URL.
|
|
15
15
|
* - `wrangler.jsonc` — Cloudflare bindings (KV, Durable Object, assets).
|
|
16
16
|
*
|
|
17
17
|
* `buildScaffoldFiles()` is imported by BOTH the scaffolder (`createProject`)
|
|
@@ -62,7 +62,7 @@ declare const SCAFFOLD_KV_PLACEHOLDER_ID = "PLACEHOLDER_KV_ID";
|
|
|
62
62
|
declare const SCAFFOLD_ENTRY_CONTENT: string;
|
|
63
63
|
/** `cajonzero/config.json` — runtime policy; secrets stay in `wrangler secret`. */
|
|
64
64
|
declare const SCAFFOLD_CONFIG_CONTENT: string;
|
|
65
|
-
/** `cajonzero/maps.json` — empty by default;
|
|
65
|
+
/** `cajonzero/maps.json` — empty by default; `cj0 add` fills it. */
|
|
66
66
|
declare const SCAFFOLD_MAPS_CONTENT: string;
|
|
67
67
|
/**
|
|
68
68
|
* Render the complete, deterministically ordered set of files for a created
|
|
@@ -222,12 +222,14 @@ declare function applySetup(options: SetupOptions): SetupResult;
|
|
|
222
222
|
/** Marker written inside the target dir; excluded from the copy and the hash. */
|
|
223
223
|
declare const ASSETS_STAMP_FILE = ".cajonzero-assets.json";
|
|
224
224
|
/**
|
|
225
|
-
* Subdirectory of
|
|
226
|
-
*
|
|
225
|
+
* Subdirectory of the assets directory that holds `cj0 add` map imports.
|
|
226
|
+
* {@link syncPublicAssets} preserves it when re-syncing the packaged UI.
|
|
227
227
|
*/
|
|
228
|
-
declare const
|
|
229
|
-
/**
|
|
230
|
-
|
|
228
|
+
declare const ASSETS_MAPS_DIR = "maps";
|
|
229
|
+
/** Preserved file (keeps an otherwise empty `public/` in git). */
|
|
230
|
+
declare const ASSETS_KEEP_FILE = ".gitkeep";
|
|
231
|
+
/** Options for {@link syncPublicAssets}. */
|
|
232
|
+
interface SyncPublicAssetsOptions {
|
|
231
233
|
/** Project directory (default: `process.cwd()`). */
|
|
232
234
|
readonly cwd?: string;
|
|
233
235
|
/** Wrangler config, relative to `cwd` (default: `wrangler.jsonc`). */
|
|
@@ -242,8 +244,8 @@ interface PrepareWorkerAssetsOptions {
|
|
|
242
244
|
/** Copy even when the fingerprint already matches. */
|
|
243
245
|
readonly force?: boolean;
|
|
244
246
|
}
|
|
245
|
-
/** Result of a successful
|
|
246
|
-
interface
|
|
247
|
+
/** Result of a successful sync. */
|
|
248
|
+
interface SyncPublicAssetsResult {
|
|
247
249
|
/** Absolute source directory (the packaged UI). */
|
|
248
250
|
readonly sourceDir: string;
|
|
249
251
|
/** Absolute target directory (the project's `assets.directory`). */
|
|
@@ -260,13 +262,14 @@ interface PrepareWorkerAssetsResult {
|
|
|
260
262
|
/** Throw when `configPath` is missing or has no `assets.directory`. */
|
|
261
263
|
declare function readWranglerAssetsDirectory(configPath: string): string | undefined;
|
|
262
264
|
/**
|
|
263
|
-
*
|
|
264
|
-
*
|
|
265
|
+
* Copy cajonzero's packaged UI into the project's static-asset directory.
|
|
266
|
+
* Idempotent: a matching fingerprint is a no-op. Imported maps under
|
|
267
|
+
* `<target>/maps/` and a `.gitkeep` are preserved across the wipe.
|
|
265
268
|
*
|
|
266
269
|
* @throws when the packaged UI is missing, the config has no `assets.directory`
|
|
267
270
|
* and no override was given, or the target would overlap the project/source.
|
|
268
271
|
*/
|
|
269
|
-
declare function
|
|
272
|
+
declare function syncPublicAssets(options?: SyncPublicAssetsOptions): Promise<SyncPublicAssetsResult>;
|
|
270
273
|
|
|
271
|
-
export {
|
|
272
|
-
export type { CajonzeroPackageInfo, CreateProjectOptions,
|
|
274
|
+
export { ASSETS_KEEP_FILE, ASSETS_MAPS_DIR, ASSETS_STAMP_FILE, SCAFFOLD_COMPATIBILITY_DATE, SCAFFOLD_CONFIG_CONTENT, SCAFFOLD_ENTRY_CONTENT, SCAFFOLD_ENTRY_PATH, SCAFFOLD_KV_PLACEHOLDER_ID, SCAFFOLD_MAPS_CONTENT, SETUP_FIELDS, ScaffoldError, applySetup, buildScaffoldFiles, createProject, generateAdminToken, generateSecret, parseDevVars, parseJsoncObject, readCajonzeroPackage, readSetupValues, readWranglerAssetsDirectory, readWranglerKvNamespaceId, serializeDevVars, setWranglerKvNamespaceId, setWranglerVars, suggestedValue, syncPublicAssets, toPackageName };
|
|
275
|
+
export type { CajonzeroPackageInfo, CreateProjectOptions, ScaffoldErrorCode, ScaffoldFile, ScaffoldResult, ScaffoldTemplateOptions, SetupField, SetupKind, SetupOptions, SetupResult, SyncPublicAssetsOptions, SyncPublicAssetsResult };
|
package/dist/scaffold.js
CHANGED
|
@@ -72,7 +72,7 @@ var SCAFFOLD_CONFIG_CONTENT = `${JSON.stringify(
|
|
|
72
72
|
`;
|
|
73
73
|
var SCAFFOLD_MAPS_CONTENT = `${JSON.stringify({ version: 1, maps: [] }, null, 2)}
|
|
74
74
|
`;
|
|
75
|
-
var
|
|
75
|
+
var SCAFFOLD_PUBLIC_KEEP_PATH = "public/.gitkeep";
|
|
76
76
|
function packageJson(options) {
|
|
77
77
|
const manifest = {
|
|
78
78
|
name: options.packageName,
|
|
@@ -80,14 +80,12 @@ function packageJson(options) {
|
|
|
80
80
|
private: true,
|
|
81
81
|
type: "module",
|
|
82
82
|
scripts: {
|
|
83
|
-
dev:
|
|
84
|
-
|
|
85
|
-
//
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
// ready-to-deploy project. Seed packs are network work and stay out of it.
|
|
90
|
-
prepare: PREPARE_ASSETS
|
|
83
|
+
dev: "wrangler dev",
|
|
84
|
+
// `cj0 deploy` syncs the packaged UI, uploads the private map-script
|
|
85
|
+
// packs, then runs `wrangler deploy` — one command, no build chain.
|
|
86
|
+
deploy: "cj0 deploy",
|
|
87
|
+
sync: "cj0 sync",
|
|
88
|
+
maps: "cj0 list"
|
|
91
89
|
},
|
|
92
90
|
dependencies: {
|
|
93
91
|
cajonzero: options.cajonzeroRange,
|
|
@@ -112,11 +110,16 @@ function wranglerConfig(options) {
|
|
|
112
110
|
` "compatibility_date": ${JSON.stringify(options.compatibilityDate)},`,
|
|
113
111
|
" // Deliberately NO `nodejs_compat`: cajonzero's worker path is Node-free.",
|
|
114
112
|
' "compatibility_flags": [],',
|
|
115
|
-
" //
|
|
116
|
-
" //
|
|
113
|
+
" // QuickJS is a build-time-compiled WASM module; workerd forbids runtime",
|
|
114
|
+
" // WebAssembly codegen. Keep this rule when editing the config.",
|
|
115
|
+
' "rules": [',
|
|
116
|
+
' { "type": "CompiledWasm", "globs": ["**/*.wasm"], "fallthrough": true }',
|
|
117
|
+
" ],",
|
|
118
|
+
" // Static UI + imported maps (play lobby + owner admin console).",
|
|
119
|
+
" // `cj0 sync` writes the packaged UI here; `cj0 add` writes public/maps/.",
|
|
117
120
|
' "assets": {',
|
|
118
|
-
' "directory": "
|
|
119
|
-
" // Binding so the room can read seed packs
|
|
121
|
+
' "directory": "public",',
|
|
122
|
+
" // Binding so the room can read imported maps + seed packs at runtime.",
|
|
120
123
|
' "binding": "ASSETS",',
|
|
121
124
|
" // History routing: deep links (/play/x, /admin/bans) boot index.html.",
|
|
122
125
|
' "not_found_handling": "single-page-application",',
|
|
@@ -203,24 +206,25 @@ function readme(options) {
|
|
|
203
206
|
"",
|
|
204
207
|
"## \u5730\u56FE",
|
|
205
208
|
"",
|
|
206
|
-
"\u5730\u56FE\
|
|
207
|
-
"\u518D\u5728 `cajonzero/maps.json` \u767B\u8BB0\uFF1A",
|
|
209
|
+
"\u5730\u56FE\u5728\u672C\u5730\u5BFC\u5165\uFF0C\u968F worker \u4E00\u6B21\u90E8\u7F72\uFF08\u9759\u6001\u8D44\u6E90 `public/`\uFF09\uFF1A",
|
|
208
210
|
"",
|
|
209
|
-
"```
|
|
210
|
-
"
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
"
|
|
214
|
-
' "slug": "omega",',
|
|
215
|
-
' "root": "https://cdn.example.com/cajonzero/omega/",',
|
|
216
|
-
' "worldId": "project-omega",',
|
|
217
|
-
' "name": "Omega City Reloaded"',
|
|
218
|
-
" }",
|
|
219
|
-
" ]",
|
|
220
|
-
"}",
|
|
211
|
+
"```bash",
|
|
212
|
+
"npx cj0 add ./race.boxplay # \u89E3\u5305\u5230 public/maps/race/ \u5E76\u751F\u6210 seed",
|
|
213
|
+
"npx cj0 update race ./race-v2.boxplay # \u8986\u76D6\u5DF2\u6709 slug",
|
|
214
|
+
"npx cj0 list # \u67E5\u770B catalog + \u672C\u5730\u5BFC\u5165\u72B6\u6001",
|
|
215
|
+
"npx cj0 remove race # \u5220\u9664\u5730\u56FE\u3001\u79C1\u6709\u811A\u672C\u4E0E catalog \u6761\u76EE",
|
|
221
216
|
"```",
|
|
222
217
|
"",
|
|
223
|
-
"`
|
|
218
|
+
"`add/update` \u4F1A\uFF1A",
|
|
219
|
+
"",
|
|
220
|
+
"1. \u628A\u516C\u5F00\u5730\u56FE\u8D44\u6E90\u89E3\u5305\u5230 `public/maps/<slug>/`\uFF1B",
|
|
221
|
+
"2. \u5728\u672C\u5730\u89E3\u6790\u4E16\u754C\u56FE\u5E76\u5199\u5165 `public/maps/<slug>/seed.json.gz`\uFF1B",
|
|
222
|
+
"3. \u628A**\u670D\u52A1\u7AEF\u811A\u672C**\u5199\u5230 `cajonzero/private/<slug>.json.gz`\uFF0C\u4E0D\u8FDB\u5165 `public/`\uFF1B",
|
|
223
|
+
'4. \u5728 `cajonzero/maps.json` \u5199\u5165 `"root": "/maps/<slug>/"`\uFF0C\u5E76\u628A\u670D\u52A1\u7AEF\u811A\u672C\u6587\u4EF6\u8BB0\u5F55\u4E3A',
|
|
224
|
+
' `"scriptsFile": "cajonzero/private/<slug>.json.gz"`\uFF08\u8BE5\u76EE\u5F55\u4F1A\u63D0\u4EA4\uFF0CCF \u6784\u5EFA\u65F6 `cj0 deploy` \u53EF\u4E0A\u4F20\uFF09\u3002',
|
|
225
|
+
"",
|
|
226
|
+
"\u9700\u8981\u72EC\u7ACB CDN \u65F6\uFF0C\u624B\u52A8\u628A\u8BE5\u6761\u76EE\u7684 `root` \u6539\u6210 `https://cdn.example.com/.../` \u5373\u53EF\uFF1B",
|
|
227
|
+
"`cj0 update` \u9ED8\u8BA4\u4FDD\u7559\u4F60\u6539\u8FC7\u7684 `root`\uFF08`--reset-root` \u53EF\u6062\u590D\uFF09\u3002",
|
|
224
228
|
"",
|
|
225
229
|
"## \u90E8\u7F72",
|
|
226
230
|
"",
|
|
@@ -228,6 +232,9 @@ function readme(options) {
|
|
|
228
232
|
"npm run deploy",
|
|
229
233
|
"```",
|
|
230
234
|
"",
|
|
235
|
+
"`cj0 deploy` \u4F1A\u540C\u6B65\u6253\u5305\u7684 UI \u5230 `public/`\u3001\u4E0A\u4F20\u79C1\u6709\u811A\u672C\uFF0C\u7136\u540E\u6267\u884C",
|
|
236
|
+
"`wrangler deploy`\u3002\u9996\u6B21\u90E8\u7F72\u524D\u5148\u8FD0\u884C `npx cj0 setup`\u3002",
|
|
237
|
+
"",
|
|
231
238
|
"\u5927\u5385\u5728 `/`\uFF0C\u7BA1\u7406\u540E\u53F0\u5728 `/admin`\u3002",
|
|
232
239
|
""
|
|
233
240
|
].join("\n");
|
|
@@ -242,6 +249,7 @@ function buildScaffoldFiles(options) {
|
|
|
242
249
|
content: SCAFFOLD_CONFIG_CONTENT.replace("<project-name>", options.packageName)
|
|
243
250
|
},
|
|
244
251
|
{ path: "cajonzero/maps.json", content: SCAFFOLD_MAPS_CONTENT },
|
|
252
|
+
{ path: SCAFFOLD_PUBLIC_KEEP_PATH, content: "" },
|
|
245
253
|
{ path: ".gitignore", content: gitignore() },
|
|
246
254
|
{ path: "README.md", content: readme(options) }
|
|
247
255
|
];
|
|
@@ -683,7 +691,8 @@ function applySetup(options) {
|
|
|
683
691
|
return { configPath, devVarsPath, vars, secrets, ...kvId !== void 0 ? { kvId } : {} };
|
|
684
692
|
}
|
|
685
693
|
var ASSETS_STAMP_FILE = ".cajonzero-assets.json";
|
|
686
|
-
var
|
|
694
|
+
var ASSETS_MAPS_DIR = "maps";
|
|
695
|
+
var ASSETS_KEEP_FILE = ".gitkeep";
|
|
687
696
|
var DEFAULT_CONFIG = "wrangler.jsonc";
|
|
688
697
|
function resolvePackageRoot() {
|
|
689
698
|
try {
|
|
@@ -763,7 +772,7 @@ function assertSafeTarget(targetDir, sourceDir, configDir) {
|
|
|
763
772
|
throw new Error(`assets \u76EE\u5F55\u4E0D\u80FD\u5305\u542B\u9879\u76EE\u914D\u7F6E/cajonzero \u8D44\u6E90\u76EE\u5F55\uFF1A${targetDir}`);
|
|
764
773
|
}
|
|
765
774
|
}
|
|
766
|
-
async function
|
|
775
|
+
async function syncPublicAssets(options = {}) {
|
|
767
776
|
const cwd = options.cwd ?? process.cwd();
|
|
768
777
|
const configPath = path3.resolve(cwd, options.configPath ?? DEFAULT_CONFIG);
|
|
769
778
|
const configDir = path3.dirname(configPath);
|
|
@@ -794,17 +803,25 @@ async function prepareWorkerAssets(options = {}) {
|
|
|
794
803
|
bytes: source.bytes
|
|
795
804
|
};
|
|
796
805
|
}
|
|
797
|
-
const
|
|
798
|
-
const
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
806
|
+
const mapsDir = path3.join(targetDir, ASSETS_MAPS_DIR);
|
|
807
|
+
const mapsBackup = path3.join(configDir, `.cajonzero-maps-backup-${process.pid}`);
|
|
808
|
+
const keepFile = path3.join(targetDir, ASSETS_KEEP_FILE);
|
|
809
|
+
const keepBackup = path3.join(configDir, `.cajonzero-keep-backup-${process.pid}`);
|
|
810
|
+
if (!existsSync(mapsDir) && existsSync(mapsBackup)) {
|
|
811
|
+
mkdirSync(path3.dirname(mapsDir), { recursive: true });
|
|
812
|
+
renameSync(mapsBackup, mapsDir);
|
|
813
|
+
}
|
|
814
|
+
let hasMaps = false;
|
|
815
|
+
if (existsSync(mapsDir)) {
|
|
816
|
+
rmSync(mapsBackup, { recursive: true, force: true });
|
|
817
|
+
renameSync(mapsDir, mapsBackup);
|
|
818
|
+
hasMaps = true;
|
|
819
|
+
}
|
|
820
|
+
let hasKeep = false;
|
|
821
|
+
if (existsSync(keepFile)) {
|
|
822
|
+
rmSync(keepBackup, { force: true });
|
|
823
|
+
renameSync(keepFile, keepBackup);
|
|
824
|
+
hasKeep = true;
|
|
808
825
|
}
|
|
809
826
|
try {
|
|
810
827
|
rmSync(targetDir, { recursive: true, force: true });
|
|
@@ -815,10 +832,15 @@ async function prepareWorkerAssets(options = {}) {
|
|
|
815
832
|
filter: (from) => path3.basename(from) !== ASSETS_STAMP_FILE
|
|
816
833
|
});
|
|
817
834
|
} finally {
|
|
818
|
-
if (
|
|
835
|
+
if (hasMaps && existsSync(mapsBackup)) {
|
|
836
|
+
mkdirSync(targetDir, { recursive: true });
|
|
837
|
+
rmSync(mapsDir, { recursive: true, force: true });
|
|
838
|
+
renameSync(mapsBackup, mapsDir);
|
|
839
|
+
}
|
|
840
|
+
if (hasKeep && existsSync(keepBackup)) {
|
|
819
841
|
mkdirSync(targetDir, { recursive: true });
|
|
820
|
-
rmSync(
|
|
821
|
-
renameSync(
|
|
842
|
+
rmSync(keepFile, { force: true });
|
|
843
|
+
renameSync(keepBackup, keepFile);
|
|
822
844
|
}
|
|
823
845
|
}
|
|
824
846
|
const next = {
|
|
@@ -838,6 +860,6 @@ async function prepareWorkerAssets(options = {}) {
|
|
|
838
860
|
};
|
|
839
861
|
}
|
|
840
862
|
|
|
841
|
-
export {
|
|
863
|
+
export { ASSETS_KEEP_FILE, ASSETS_MAPS_DIR, ASSETS_STAMP_FILE, SCAFFOLD_COMPATIBILITY_DATE, SCAFFOLD_CONFIG_CONTENT, SCAFFOLD_ENTRY_CONTENT, SCAFFOLD_ENTRY_PATH, SCAFFOLD_KV_PLACEHOLDER_ID, SCAFFOLD_MAPS_CONTENT, SETUP_FIELDS, ScaffoldError, applySetup, buildScaffoldFiles, createProject, generateAdminToken, generateSecret, parseDevVars, parseJsoncObject, readCajonzeroPackage, readSetupValues, readWranglerAssetsDirectory, readWranglerKvNamespaceId, serializeDevVars, setWranglerKvNamespaceId, setWranglerVars, suggestedValue, syncPublicAssets, toPackageName };
|
|
842
864
|
//# sourceMappingURL=scaffold.js.map
|
|
843
865
|
//# sourceMappingURL=scaffold.js.map
|
package/dist/serve.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { ExecutionContext } from 'hono';
|
|
2
|
-
import { R as Room, D as DurableObjectNamespace, b as Env } from './providers-
|
|
2
|
+
import { R as Room, D as DurableObjectNamespace, b as Env } from './providers-Bu0-iMVs.js';
|
|
3
3
|
import { StorageSource, EnvProvider, SettingDefaults } from './core.js';
|
|
4
4
|
import 'unstorage';
|
|
5
|
+
import './catalog-BRO-mQoP.js';
|
|
5
6
|
import 'gl-matrix';
|
|
6
7
|
import 'zod';
|
|
7
8
|
|