cajonzero 0.1.2 → 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.
@@ -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';
@@ -131,6 +132,10 @@ interface R2Bucket {
131
132
  delete(key: string): Promise<void>;
132
133
  list(options?: unknown): Promise<unknown>;
133
134
  }
135
+ /** Structural stand-in for workerd's static-assets `Fetcher` binding. */
136
+ interface AssetsBinding {
137
+ fetch(input: RequestInfo | URL, init?: RequestInit): Promise<Response>;
138
+ }
134
139
  /**
135
140
  * Runtime bindings + secrets injected by the Cloudflare Workers runtime.
136
141
  *
@@ -140,8 +145,20 @@ interface R2Bucket {
140
145
  interface Env {
141
146
  /** KV namespace: map code/asset KV and player data (unstorage KV adapter). */
142
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;
143
155
  /** Durable Object namespace for per-room actors (`Room`). */
144
156
  readonly ROOMS: DurableObjectNamespace;
157
+ /**
158
+ * Static-assets binding (`assets.binding`). Optional: older deployments
159
+ * without it still work, they just cannot read the worker-bundled seed packs.
160
+ */
161
+ readonly ASSETS?: AssetsBinding;
145
162
  /** Optional R2 bucket for large map assets; absent in minimal deployments. */
146
163
  readonly CAJONZERO_R2?: R2Bucket;
147
164
  /** Admin bearer token guarding the management/ban API. Secret. */
@@ -501,59 +518,6 @@ interface SessionRegistry {
501
518
  current(accountId: string): Promise<SessionSlotRecord | undefined>;
502
519
  }
503
520
 
504
- /**
505
- * cajonzero — the map catalog (`cajonzero/maps.json`).
506
- *
507
- * Maps are **not** stored by cajonzero. A `.boxplay` is unpacked by the operator
508
- * and uploaded to object storage (OSS/CDN); `maps.json` only records where each
509
- * map's unpacked root lives.
510
- *
511
- * Expected layout under `entry.root` (exactly the archive layout):
512
- *
513
- * ```text
514
- * <root>/bundle.json
515
- * <root>/worlds/<worldId>/manifest.json
516
- * <root>/worlds/<worldId>/data/project-state.json
517
- * <root>/worlds/<worldId>/data/blobs/<cid>
518
- * ```
519
- *
520
- * Worker path: URL handling + validation only, no Node globals.
521
- */
522
- /** The only catalog version this build understands. */
523
- declare const MAP_CATALOG_VERSION = 1;
524
- /** One map in the catalog. */
525
- interface MapEntry {
526
- /** Stable room/catalog id (`omega`, `drift`, …). */
527
- readonly slug: string;
528
- /** Unpacked map root, absolute `http(s)://…/` URL. */
529
- readonly root: string;
530
- /** `worlds/<worldId>` directory name; derived from `bundle.json` when absent. */
531
- readonly worldId?: string;
532
- /** Display name (falls back to the map's own manifest). */
533
- readonly name?: string;
534
- readonly author?: string;
535
- readonly version?: string;
536
- /** Cover image URL for the lobby. */
537
- readonly cover?: string;
538
- /** Optional CDN root for browser assets; defaults to {@link root}. */
539
- readonly assetRoot?: string;
540
- }
541
- /** The `maps.json` document. */
542
- interface MapCatalog {
543
- readonly version: typeof MAP_CATALOG_VERSION;
544
- readonly maps: readonly MapEntry[];
545
- }
546
- /** No maps configured (the scaffold default). */
547
- declare const EMPTY_MAP_CATALOG: MapCatalog;
548
- /**
549
- * Validate a parsed `maps.json`.
550
- *
551
- * @throws {MapCatalogError} for a malformed document, entry, or duplicate slug.
552
- */
553
- declare function parseMapCatalog(input: unknown): MapCatalog;
554
- /** Look up a map by slug. */
555
- declare function findMap(catalog: MapCatalog, slug: string): MapEntry | undefined;
556
-
557
521
  declare class MuBuffer {
558
522
  buffer: ArrayBuffer;
559
523
  dataView: DataView;
@@ -2414,6 +2378,8 @@ interface SeedMesh {
2414
2378
  duration: number;
2415
2379
  }[];
2416
2380
  renderBoxOffset?: [number, number, number];
2381
+ /** `voxelModel` | `gltfModel` (client model loader dispatch). */
2382
+ hashType?: string;
2417
2383
  }
2418
2384
  /** A map entity that should render a mesh (static scenery / vehicles). */
2419
2385
  interface SeedRenderEntity {
@@ -2434,6 +2400,36 @@ interface SeedRender {
2434
2400
  entities: SeedRenderEntity[];
2435
2401
  warnings: string[];
2436
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
+ }
2437
2433
  /** The resolved, pure world seed. */
2438
2434
  interface WorldSeed {
2439
2435
  version: number;
@@ -2452,6 +2448,12 @@ interface WorldSeed {
2452
2448
  voxels: SeedVoxels | null;
2453
2449
  /** Mesh/entity render projection (empty when the map has no models). */
2454
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[];
2455
2457
  /** Number of entities present in the map's `entitiesTree`. */
2456
2458
  entityCount: number;
2457
2459
  /** Human-readable record of anything skipped (never silently dropped). */
@@ -2644,6 +2646,32 @@ interface SettingsService {
2644
2646
  /** Construct a {@link SettingsService} over a T4 `SettingsRepo`. */
2645
2647
  declare function createSettingsService(options: CreateSettingsServiceOptions): SettingsService;
2646
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
+
2647
2675
  /**
2648
2676
  * cajonzero — mudb `MuSocketServer`-compatible adapter for Cloudflare workerd (T8).
2649
2677
  *
@@ -4930,6 +4958,8 @@ interface ScriptHost {
4930
4958
  clearEvents(): void;
4931
4959
  suspend(): void;
4932
4960
  resume(): void;
4961
+ /** Optional teardown (QuickJS VM, timers). Called when the room is replaced. */
4962
+ dispose?(): void;
4933
4963
  }
4934
4964
  /** The Durable Object storage surface the room uses (structural). */
4935
4965
  interface RoomStorage {
@@ -4965,6 +4995,14 @@ interface RoomOptions {
4965
4995
  */
4966
4996
  emptyGraceMs?: number;
4967
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;
4968
5006
  maxStepsPerFrame?: number;
4969
5007
  /** Simulation engine. Defaults to the registered factory or a null engine. */
4970
5008
  engine?: RoomEngine;
@@ -5027,11 +5065,21 @@ declare class Room {
5027
5065
  /** Tracks the async settings read that arms the grace timer at drain. */
5028
5066
  private graceOps;
5029
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;
5030
5074
  private readonly maxStepsPerFrame;
5031
5075
  private readonly manualClock;
5032
5076
  private readonly createPair;
5033
5077
  private readonly logger;
5034
5078
  private readonly secret;
5079
+ /** Worker static-assets binding, used to read seed packs bundled at deploy. */
5080
+ private readonly assets;
5081
+ private readonly scriptsKv;
5082
+ private readonly store;
5035
5083
  private engine;
5036
5084
  private script;
5037
5085
  private readonly explicitScriptHost;
@@ -5039,6 +5087,7 @@ declare class Room {
5039
5087
  private readonly sockets;
5040
5088
  /** mudb wire codec: protocol envelope + netcode frames. */
5041
5089
  private readonly codec;
5090
+ private readonly protocolBus;
5042
5091
  private readonly modelCodec;
5043
5092
  private readonly messageHandlers;
5044
5093
  private readonly banChecker;
@@ -5094,6 +5143,10 @@ declare class Room {
5094
5143
  private pendingEngineMap;
5095
5144
  /** Identity of the map the current engine was seeded from. */
5096
5145
  private seededMap;
5146
+ /** Non-fatal seed warnings (missing blobs, skipped entities, …). */
5147
+ private seedWarnings;
5148
+ /** Last map-load failure; cleared on a successful seed. */
5149
+ private mapLoadError;
5097
5150
  private heartbeatBeats;
5098
5151
  private ticksRun;
5099
5152
  private lastTickError;
@@ -5142,6 +5195,14 @@ declare class Room {
5142
5195
  private applyPendingEngineSnapshot;
5143
5196
  private loadWorld;
5144
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;
5145
5206
  /**
5146
5207
  * Run the full connect path and return a structured outcome (no `Response`,
5147
5208
  * so tests can drive it without a workerd runtime). Steps: resolve the sid →
@@ -5160,7 +5221,6 @@ declare class Room {
5160
5221
  private admitConnectionOnce;
5161
5222
  private startSockets;
5162
5223
  private registerSocket;
5163
- /** Build the per-connection codec callback table (allocated once per socket). */
5164
5224
  private createHandlers;
5165
5225
  /**
5166
5226
  * Decode one inbound frame. A protocol violation closes the socket exactly like
@@ -5258,6 +5318,17 @@ declare class Room {
5258
5318
  * secret diff → pings → clear events.
5259
5319
  */
5260
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;
5261
5332
  private buildContext;
5262
5333
  private buildSecret;
5263
5334
  private startTickLoop;
@@ -5295,6 +5366,8 @@ declare class Room {
5295
5366
  get phase(): RoomPhase;
5296
5367
  /** Current simulation tick. */
5297
5368
  get tick(): number;
5369
+ /** Extra game-socket protocols (dialog/chat/gui/...) after `game-net`. */
5370
+ getProtocolBus(): ProtocolBus;
5298
5371
  /** `true` once the empty-grace window has elapsed (heartbeat released). */
5299
5372
  get isEvictable(): boolean;
5300
5373
  /** `true` while the draining heartbeat is armed (the DO is pinned). */
@@ -5361,5 +5434,5 @@ declare function resolveEnvironment(env: Env): string | undefined;
5361
5434
  declare function resolveRooms(env: Env): DurableObjectNamespace | undefined;
5362
5435
  declare function resolveSettingDefaults(env: Env): SettingDefaults | undefined;
5363
5436
 
5364
- export { parseMapCatalog as A, resolveAdminToken as B, resolveEnvironment as C, resolveRooms as F, resolveSessionSecret as G, resolveSettingDefaults as H, resolveStore as I, setRuntimeProviders as J, setStorageFactory as K, Room as R, EMPTY_MAP_CATALOG as c, SETTINGS as h, SETTING_KEYS as i, SettingsError as l, configureDefaultKV as r, createMemoryStore as s, createRepos as t, createSettingsService as u, createStore as v, findMap as w, getRuntimeProviders as x, isSettingKey as y, memoryDriver as z };
5365
- export type { DurableObjectNamespace as D, EnvProvider as E, SessionsRepo as L, MapEntry as M, NetPublic as N, NetSecret as O, StorageSource as S, TimestampedClientInput as T, WorldSeed as W, SettingDefaults as a, Env as b, MapCatalog as d, Repos as e, RoomOptions as f, RuntimeProviders as g, SettingDefinition as j, Settings as k, SettingsErrorCode as m, SettingsService as n, StorageFactory as o, Store as p, WorldSeedReader as q };
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
@@ -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; entries point at unpacked map roots
14
- * hosted on OSS/CDN. Maps are never stored in the project.
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; see the README for an entry. */
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
@@ -147,7 +147,7 @@ declare function toPackageName(folder: string): string;
147
147
  declare function createProject(folder: string, options?: CreateProjectOptions): ScaffoldResult;
148
148
 
149
149
  /** Where one setup value is written. */
150
- type SetupKind = "var" | "secret";
150
+ type SetupKind = "var" | "secret" | "kv";
151
151
  /** One configurable value. */
152
152
  interface SetupField {
153
153
  readonly name: string;
@@ -171,6 +171,8 @@ interface SetupResult {
171
171
  readonly vars: Record<string, string>;
172
172
  /** Secrets written to `.dev.vars`. */
173
173
  readonly secrets: Record<string, string>;
174
+ /** KV namespace id written to `wrangler.jsonc` (when provided). */
175
+ readonly kvId?: string;
174
176
  }
175
177
  interface SetupOptions {
176
178
  readonly cwd?: string;
@@ -189,6 +191,19 @@ declare function suggestedValue(field: SetupField): string | undefined;
189
191
  declare function parseDevVars(text: string): Record<string, string>;
190
192
  /** Serialize `.dev.vars` (stable order, trailing newline). */
191
193
  declare function serializeDevVars(values: Record<string, string>): string;
194
+ /** Strip `//` / block comments and trailing commas so a JSONC object can be parsed. */
195
+ declare function parseJsoncObject(text: string): Record<string, unknown>;
196
+ /**
197
+ * Read the KV namespace id bound to `binding` from a wrangler config.
198
+ * Returns `undefined` when the binding is absent or the id is the placeholder.
199
+ */
200
+ declare function readWranglerKvNamespaceId(raw: string, binding?: string): string | undefined;
201
+ /**
202
+ * Set the `id` of the `kv_namespaces` entry bound to `binding`, preserving
203
+ * comments and unrelated JSONC formatting. Adds the entry (or the whole
204
+ * `kv_namespaces` array) when missing.
205
+ */
206
+ declare function setWranglerKvNamespaceId(raw: string, binding: string, id: string): string;
192
207
  /**
193
208
  * Merge `vars` into the `wrangler.jsonc` `"vars"` object.
194
209
  *
@@ -204,5 +219,57 @@ declare function readSetupValues(cwd: string, configPath: string, devVarsPath: s
204
219
  */
205
220
  declare function applySetup(options: SetupOptions): SetupResult;
206
221
 
207
- export { 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, readCajonzeroPackage, readSetupValues, serializeDevVars, setWranglerVars, suggestedValue, toPackageName };
208
- export type { CajonzeroPackageInfo, CreateProjectOptions, ScaffoldErrorCode, ScaffoldFile, ScaffoldResult, ScaffoldTemplateOptions, SetupField, SetupKind, SetupOptions, SetupResult };
222
+ /** Marker written inside the target dir; excluded from the copy and the hash. */
223
+ declare const ASSETS_STAMP_FILE = ".cajonzero-assets.json";
224
+ /**
225
+ * Subdirectory of the assets directory that holds `cj0 add` map imports.
226
+ * {@link syncPublicAssets} preserves it when re-syncing the packaged UI.
227
+ */
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 {
233
+ /** Project directory (default: `process.cwd()`). */
234
+ readonly cwd?: string;
235
+ /** Wrangler config, relative to `cwd` (default: `wrangler.jsonc`). */
236
+ readonly configPath?: string;
237
+ /**
238
+ * Target directory, relative to the config's directory. Overrides
239
+ * `assets.directory` from the config.
240
+ */
241
+ readonly assetsDir?: string;
242
+ /** Source tree override (tests). Defaults to the installed package's `dist/ui`. */
243
+ readonly sourceDir?: string;
244
+ /** Copy even when the fingerprint already matches. */
245
+ readonly force?: boolean;
246
+ }
247
+ /** Result of a successful sync. */
248
+ interface SyncPublicAssetsResult {
249
+ /** Absolute source directory (the packaged UI). */
250
+ readonly sourceDir: string;
251
+ /** Absolute target directory (the project's `assets.directory`). */
252
+ readonly targetDir: string;
253
+ /** Content fingerprint of the source tree. */
254
+ readonly fingerprint: string;
255
+ /** `false` when the target was already up to date. */
256
+ readonly copied: boolean;
257
+ /** Number of files in the source tree. */
258
+ readonly files: number;
259
+ /** Total uncompressed bytes in the source tree. */
260
+ readonly bytes: number;
261
+ }
262
+ /** Throw when `configPath` is missing or has no `assets.directory`. */
263
+ declare function readWranglerAssetsDirectory(configPath: string): string | undefined;
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.
268
+ *
269
+ * @throws when the packaged UI is missing, the config has no `assets.directory`
270
+ * and no override was given, or the target would overlap the project/source.
271
+ */
272
+ declare function syncPublicAssets(options?: SyncPublicAssetsOptions): Promise<SyncPublicAssetsResult>;
273
+
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 };