deepspace 0.16.0 → 0.18.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/CHANGELOG.md +247 -1
- package/README.md +18 -41
- package/dist/cli.js +1499 -1327
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +4 -157
- package/dist/index.js +248 -326
- package/dist/index.js.map +1 -1
- package/dist/server.d.ts +4 -137
- package/dist/server.js +3 -412
- package/dist/server.js.map +1 -1
- package/dist/worker.d.ts +5 -210
- package/dist/worker.js +3 -419
- package/dist/worker.js.map +1 -1
- package/features/documents/src/LibrarySidebar.tsx +6 -8
- package/features/documents/src/editor/useDocEditor.ts +3 -8
- package/features/landing/feature.json +1 -1
- package/features/messaging/src/components/chat/MessageItem.tsx +83 -34
- package/features/messaging/src/hooks/useChatChannel.ts +2 -8
- package/package.json +2 -2
package/dist/server.d.ts
CHANGED
|
@@ -1466,14 +1466,12 @@ declare function runMigrations(db: D1Database, migrations: readonly string[]): P
|
|
|
1466
1466
|
* Wire protocol constants.
|
|
1467
1467
|
*
|
|
1468
1468
|
* The JSON WebSocket protocol uses dotted string identifiers (e.g.
|
|
1469
|
-
* `"
|
|
1469
|
+
* `"records.query"`) as the `type` discriminator. All message types are
|
|
1470
1470
|
* grouped under a single `MSG` object so imports stay tidy:
|
|
1471
1471
|
*
|
|
1472
1472
|
* import { MSG, dispatch, clientBuild } from 'deepspace'
|
|
1473
1473
|
*
|
|
1474
1474
|
* dispatch<ServerMessage>(raw, {
|
|
1475
|
-
* [MSG.GAME_STATE]: (p) => { ... },
|
|
1476
|
-
* [MSG.GAME_TICK]: (p) => { ... },
|
|
1477
1475
|
* })
|
|
1478
1476
|
*
|
|
1479
1477
|
* Each key's value is the on-wire string — grep-friendly, self-
|
|
@@ -1502,14 +1500,6 @@ declare const MSG: {
|
|
|
1502
1500
|
readonly ACK: "records.ack";
|
|
1503
1501
|
readonly LIST_SCHEMAS: "records.list_schemas";
|
|
1504
1502
|
readonly RESUBSCRIBE: "records.resubscribe";
|
|
1505
|
-
readonly GAME_STATE: "game.state";
|
|
1506
|
-
readonly GAME_INPUT: "game.input";
|
|
1507
|
-
readonly GAME_PLAYER_JOIN: "game.player_join";
|
|
1508
|
-
readonly GAME_PLAYER_LEAVE: "game.player_leave";
|
|
1509
|
-
readonly GAME_PLAYER_READY: "game.player_ready";
|
|
1510
|
-
readonly GAME_START: "game.start";
|
|
1511
|
-
readonly GAME_END: "game.end";
|
|
1512
|
-
readonly GAME_TICK: "game.tick";
|
|
1513
1503
|
readonly CANVAS_SHAPES: "canvas.shapes";
|
|
1514
1504
|
readonly CANVAS_ADD: "canvas.add";
|
|
1515
1505
|
readonly CANVAS_MOVE: "canvas.move";
|
|
@@ -1582,7 +1572,7 @@ declare const MSG: {
|
|
|
1582
1572
|
* ---------------
|
|
1583
1573
|
*
|
|
1584
1574
|
* Some message types carry different payloads depending on who's sending.
|
|
1585
|
-
* `MSG.
|
|
1575
|
+
* `MSG.RECORDS_RESUBSCRIBE`, for example, is `{}` when the client asks to
|
|
1586
1576
|
* but `{ state, tick }` when the server broadcasts the start event.
|
|
1587
1577
|
* `MSG.CANVAS_ADD` is a flat shape dict on the way in and a `{ shape }`
|
|
1588
1578
|
* wrapper on the way out. Modelling these with one union would force
|
|
@@ -1660,26 +1650,6 @@ type ServerMessage = BaseMessage<typeof MSG.QUERY_RESULT, {
|
|
|
1660
1650
|
recordId: string;
|
|
1661
1651
|
fieldName: string;
|
|
1662
1652
|
canWrite: boolean;
|
|
1663
|
-
}> | BaseMessage<typeof MSG.GAME_STATE, {
|
|
1664
|
-
state: unknown;
|
|
1665
|
-
tick: number;
|
|
1666
|
-
players: unknown[];
|
|
1667
|
-
running: boolean;
|
|
1668
|
-
}> | BaseMessage<typeof MSG.GAME_TICK, {
|
|
1669
|
-
state: unknown;
|
|
1670
|
-
tick: number;
|
|
1671
|
-
}> | BaseMessage<typeof MSG.GAME_START, {
|
|
1672
|
-
state: unknown;
|
|
1673
|
-
tick: number;
|
|
1674
|
-
}> | BaseMessage<typeof MSG.GAME_END, {
|
|
1675
|
-
state: unknown;
|
|
1676
|
-
tick: number;
|
|
1677
|
-
}> | BaseMessage<typeof MSG.GAME_PLAYER_JOIN, {
|
|
1678
|
-
player: unknown;
|
|
1679
|
-
}> | BaseMessage<typeof MSG.GAME_PLAYER_LEAVE, {
|
|
1680
|
-
userId: string;
|
|
1681
|
-
}> | BaseMessage<typeof MSG.GAME_PLAYER_READY, {
|
|
1682
|
-
userId: string;
|
|
1683
1653
|
}> | BaseMessage<typeof MSG.CANVAS_SHAPES, {
|
|
1684
1654
|
shapes: unknown[];
|
|
1685
1655
|
viewports: unknown[];
|
|
@@ -2087,8 +2057,6 @@ declare class RecordRoom<E = Record<string, unknown>> extends BaseRoom<E> {
|
|
|
2087
2057
|
private _fetchTiming;
|
|
2088
2058
|
private ensureInitialized;
|
|
2089
2059
|
private initializeDatabase;
|
|
2090
|
-
private migrateUsersTableIfExists;
|
|
2091
|
-
private migrateRecordsTable;
|
|
2092
2060
|
private ensureCollectionTable;
|
|
2093
2061
|
private ensureAllCollectionTables;
|
|
2094
2062
|
protected onConnect(ws: WebSocket, user: UserAttachment): Promise<ConnectionAttachment>;
|
|
@@ -2156,106 +2124,6 @@ declare class YjsRoom<E = Record<string, unknown>> extends BaseRoom<E> {
|
|
|
2156
2124
|
private broadcastRaw;
|
|
2157
2125
|
}
|
|
2158
2126
|
|
|
2159
|
-
/**
|
|
2160
|
-
* GameRoom — Authoritative game loop Durable Object.
|
|
2161
|
-
*
|
|
2162
|
-
* Extends BaseRoom with:
|
|
2163
|
-
* - Alarm-based tick loop with configurable interval
|
|
2164
|
-
* - Player management (join, leave, ready state)
|
|
2165
|
-
* - Input collection per tick, authoritative state computation
|
|
2166
|
-
* - State broadcast to all connected players
|
|
2167
|
-
*
|
|
2168
|
-
* Subclasses implement game logic via lifecycle hooks:
|
|
2169
|
-
* onTick, onPlayerJoin, onPlayerLeave, onGameStart, onGameEnd
|
|
2170
|
-
*
|
|
2171
|
-
* Message types: game.*
|
|
2172
|
-
*/
|
|
2173
|
-
|
|
2174
|
-
interface GameRoomConfig {
|
|
2175
|
-
/** Ticks per second (default: 20) */
|
|
2176
|
-
tickRate?: number;
|
|
2177
|
-
/** Minimum players to start (default: 1) */
|
|
2178
|
-
minPlayers?: number;
|
|
2179
|
-
/** Maximum players (default: unlimited) */
|
|
2180
|
-
maxPlayers?: number;
|
|
2181
|
-
}
|
|
2182
|
-
interface Player {
|
|
2183
|
-
userId: string;
|
|
2184
|
-
userName: string;
|
|
2185
|
-
ready: boolean;
|
|
2186
|
-
connectedAt: string;
|
|
2187
|
-
data: Record<string, unknown>;
|
|
2188
|
-
}
|
|
2189
|
-
interface GameInput {
|
|
2190
|
-
userId: string;
|
|
2191
|
-
action: string;
|
|
2192
|
-
data: Record<string, unknown>;
|
|
2193
|
-
tick: number;
|
|
2194
|
-
}
|
|
2195
|
-
interface GameAttachment extends UserAttachment {
|
|
2196
|
-
joinedAt: string;
|
|
2197
|
-
/** True for member/admin roles; false for viewers, unauthenticated anon, spectators. */
|
|
2198
|
-
canWrite: boolean;
|
|
2199
|
-
}
|
|
2200
|
-
declare abstract class GameRoom<E = Record<string, unknown>> extends BaseRoom<E> {
|
|
2201
|
-
private config;
|
|
2202
|
-
private players;
|
|
2203
|
-
private inputBuffer;
|
|
2204
|
-
private currentTick;
|
|
2205
|
-
private gameState;
|
|
2206
|
-
private running;
|
|
2207
|
-
private initialized;
|
|
2208
|
-
constructor(state: DurableObjectState, env: unknown, config?: GameRoomConfig);
|
|
2209
|
-
private ensureInitialized;
|
|
2210
|
-
private persistState;
|
|
2211
|
-
protected onConnect(ws: WebSocket, user: UserAttachment): GameAttachment;
|
|
2212
|
-
protected onMessage(ws: WebSocket, user: UserAttachment, message: {
|
|
2213
|
-
type: string;
|
|
2214
|
-
[key: string]: unknown;
|
|
2215
|
-
}): Promise<void>;
|
|
2216
|
-
protected onDisconnect(_ws: WebSocket, user: UserAttachment): void;
|
|
2217
|
-
protected onAlarm(): Promise<void>;
|
|
2218
|
-
private checkAutoStart;
|
|
2219
|
-
private startGame;
|
|
2220
|
-
private stopGame;
|
|
2221
|
-
protected getGameState(): Record<string, unknown>;
|
|
2222
|
-
protected setGameState(state: Record<string, unknown>): void;
|
|
2223
|
-
protected getPlayers(): Player[];
|
|
2224
|
-
protected isRunning(): boolean;
|
|
2225
|
-
protected getCurrentTick(): number;
|
|
2226
|
-
/**
|
|
2227
|
-
* Called each tick with current state and collected inputs.
|
|
2228
|
-
* Return the new game state, or undefined to keep current state.
|
|
2229
|
-
*/
|
|
2230
|
-
protected abstract onTick(state: Record<string, unknown>, inputs: GameInput[], tick: number): Record<string, unknown> | undefined | Promise<Record<string, unknown> | undefined>;
|
|
2231
|
-
/** Called when a player connects */
|
|
2232
|
-
protected onPlayerJoin(_player: Player): void;
|
|
2233
|
-
/** Called when a player disconnects */
|
|
2234
|
-
protected onPlayerLeave(_player: Player): void;
|
|
2235
|
-
/** Called when the game starts */
|
|
2236
|
-
protected onGameStart(): void;
|
|
2237
|
-
/** Called when the game ends */
|
|
2238
|
-
protected onGameEnd(_finalState: Record<string, unknown>): void;
|
|
2239
|
-
/**
|
|
2240
|
-
* Called once when the DO first hydrates persisted state from storage.
|
|
2241
|
-
* Receives the parsed state blob as it was written by a previous build.
|
|
2242
|
-
* Return the state object to install as `gameState`.
|
|
2243
|
-
*
|
|
2244
|
-
* Subclasses with evolving schemas should override this hook to:
|
|
2245
|
-
* - merge new fields onto a default template,
|
|
2246
|
-
* - upgrade shapes across versioned states,
|
|
2247
|
-
* - or discard stale blobs entirely by returning a fresh object.
|
|
2248
|
-
*
|
|
2249
|
-
* The default implementation is a pass-through, preserving the legacy
|
|
2250
|
-
* "stored blob is gospel" behavior for subclasses that don't care.
|
|
2251
|
-
*
|
|
2252
|
-
* If JSON parsing of the stored blob fails this hook is NOT called — the
|
|
2253
|
-
* DO starts with an empty state and the subclass's `onGameStart` (or
|
|
2254
|
-
* first `onTick`) is responsible for initializing.
|
|
2255
|
-
*/
|
|
2256
|
-
protected onHydrateState(stored: Record<string, unknown>): Record<string, unknown>;
|
|
2257
|
-
}
|
|
2258
|
-
|
|
2259
2127
|
/**
|
|
2260
2128
|
* CanvasRoom — Spatial canvas Durable Object (tldraw-style).
|
|
2261
2129
|
*
|
|
@@ -2619,11 +2487,10 @@ type DOManifest = DOManifestEntry[];
|
|
|
2619
2487
|
* @example
|
|
2620
2488
|
* const manifest = [
|
|
2621
2489
|
* { binding: 'RECORD_ROOMS', className: 'AppRecordRoom', sqlite: true },
|
|
2622
|
-
* { binding: 'GAME_ROOMS', className: 'AppGameRoom', sqlite: true },
|
|
2623
2490
|
* ] as const satisfies DOManifest
|
|
2624
2491
|
*
|
|
2625
2492
|
* type Env = BaseEnv & DOBindings<typeof manifest>
|
|
2626
|
-
* // => { RECORD_ROOMS: DurableObjectNamespace
|
|
2493
|
+
* // => { RECORD_ROOMS: DurableObjectNamespace }
|
|
2627
2494
|
*/
|
|
2628
2495
|
type DOBindings<T extends readonly DOManifestEntry[]> = {
|
|
2629
2496
|
[K in T[number]['binding']]: DurableObjectNamespace;
|
|
@@ -4666,4 +4533,4 @@ declare class RefundError extends Error {
|
|
|
4666
4533
|
constructor(message: string, status: number);
|
|
4667
4534
|
}
|
|
4668
4535
|
|
|
4669
|
-
export { ACCOUNT_STORAGE_LIMIT_BYTES, AI_CHATS_SCHEMA, AI_MESSAGES_SCHEMA, ALLOWED_BINDING_TYPES, APP_ID_RE, APP_NAME_RULES, AUTO_PROVISIONABLE_TYPES, AUTO_PROVISION_SENTINEL, type ActionContext, type ActionHandler, type ActionResult, type ActionTools, type ApiWorkerEnv, type AppNameResolution, type AppNameValidation, type AuthWorkerEnv, BASE_USERS_SCHEMA, BUILT_IN_TOOLS, BaseRoom, CHANNELS_SCHEMA, CHANNEL_INVITATIONS_SCHEMA, CHANNEL_MEMBERS_SCHEMA, CONVERSATION_SCHEMAS, COST_RATES, CancelSubscriptionError, type CancelSubscriptionOpts, type CancelSubscriptionResult, CanvasRoom, type CanvasShape, type ChatContextConfig, type ChatMessageRow, type ChatRow, type ChatTurn, type CollectionPermissionSummary, type CollectionSchema, type ColumnDefinition, type ColumnInterpretation, type ComposioToolsOptions, type ConvMemberData, type ConvMessageData, type ConvReactionData, type ConvReadCursorData, type ConvVoteData, type ConversationStateData, type CronContext, type CronExecution, CronRoom, type CronRoomConfig, type CronTask, type CustomBinding, type CustomBindingManifest, DEFAULT_CONTEXT_CONFIG, DEFAULT_DO_MANIFEST, DEFAULT_QUERY_LIMIT, DEPLOYED_APPS_DEFAULTS, DIRECTORY_SCHEMAS, type DOBindings, type DOManifest, type DOManifestEntry, type DebugApiContext, type DeepSpaceAIEnv, type DeepSpaceAIOptions, type DeepSpaceAgentDiagnosticContext, DeepSpaceAgentModelError, DeepSpaceAgentProfileError, type DeepSpaceAgentStream, type DeepSpaceAgentStreamOptions, type DeepSpaceAuth, type DeepSpaceAuthConfig, type DirectoryCommunityData, type DirectoryConversationData, type DirectoryMembershipData, type DirectoryPostData, type DoMigrationDirective, type DoMigrationPlan, type ExistingDOBinding, GLOBAL_DO_TYPES, GLOBAL_DO_TYPE_NAMES, type
|
|
4536
|
+
export { ACCOUNT_STORAGE_LIMIT_BYTES, AI_CHATS_SCHEMA, AI_MESSAGES_SCHEMA, ALLOWED_BINDING_TYPES, APP_ID_RE, APP_NAME_RULES, AUTO_PROVISIONABLE_TYPES, AUTO_PROVISION_SENTINEL, type ActionContext, type ActionHandler, type ActionResult, type ActionTools, type ApiWorkerEnv, type AppNameResolution, type AppNameValidation, type AuthWorkerEnv, BASE_USERS_SCHEMA, BUILT_IN_TOOLS, BaseRoom, CHANNELS_SCHEMA, CHANNEL_INVITATIONS_SCHEMA, CHANNEL_MEMBERS_SCHEMA, CONVERSATION_SCHEMAS, COST_RATES, CancelSubscriptionError, type CancelSubscriptionOpts, type CancelSubscriptionResult, CanvasRoom, type CanvasShape, type ChatContextConfig, type ChatMessageRow, type ChatRow, type ChatTurn, type CollectionPermissionSummary, type CollectionSchema, type ColumnDefinition, type ColumnInterpretation, type ComposioToolsOptions, type ConvMemberData, type ConvMessageData, type ConvReactionData, type ConvReadCursorData, type ConvVoteData, type ConversationStateData, type CronContext, type CronExecution, CronRoom, type CronRoomConfig, type CronTask, type CustomBinding, type CustomBindingManifest, DEFAULT_CONTEXT_CONFIG, DEFAULT_DO_MANIFEST, DEFAULT_QUERY_LIMIT, DEPLOYED_APPS_DEFAULTS, DIRECTORY_SCHEMAS, type DOBindings, type DOManifest, type DOManifestEntry, type DebugApiContext, type DeepSpaceAIEnv, type DeepSpaceAIOptions, type DeepSpaceAgentDiagnosticContext, DeepSpaceAgentModelError, DeepSpaceAgentProfileError, type DeepSpaceAgentStream, type DeepSpaceAgentStreamOptions, type DeepSpaceAuth, type DeepSpaceAuthConfig, type DirectoryCommunityData, type DirectoryConversationData, type DirectoryMembershipData, type DirectoryPostData, type DoMigrationDirective, type DoMigrationPlan, type ExistingDOBinding, GLOBAL_DO_TYPES, GLOBAL_DO_TYPE_NAMES, type GetActionData, type GlobalDOType, type Job, type JobContext, JobRoom, type JobRoomConfig, type JobStatus, type JwtClaims, type JwtVerifierConfig, MAX_APP_FILE_BYTES, MAX_DEPLOY_ASSET_FILE_BYTES, MAX_UPLOAD_PARTS, MAX_UPLOAD_REQUEST_BYTES, MESSAGES_SCHEMA, type MutateActionData, type PermissionAnalysis, type PermissionContext, type PermissionLevel, type PermissionSource, type PlanInfo, type PlatformWorkerEnv, type PrefixResult, type PresencePeer, PresenceRoom, type QueryActionData, REACTIONS_SCHEMA, READ_RECEIPTS_SCHEMA, REGISTRY_INSTANCE, RESERVED_BINDING_NAMES, RESERVED_COLLECTION_NAMES, RESOURCE_ID_RE, type RecordContext, RecordRoom, type RecordRoomConfig, RefundError, type RefundOpts, type RefundResult, RegistryClientError, type ResolvedColumn, type ResolvedPermission, type RolePermissions, type RunMigrationsResult, STRICT_APP_ID_RE, SYSTEM_COLLECTION_SCHEMAS, SYSTEM_MANAGED_COLUMNS, SchemaRegistry, type ScopeContext, type ScopedR2Auth, type ScopedR2Config, type ScopedR2Handler, type ScreenshotEnv, type ScreenshotResult, type SharedConnection, type StorageAdmission, type StoredRecord, SubscriptionAuthError, type SubscriptionContext, type SubscriptionRead, SubscriptionRequiredError, type SubscriptionStatus, type Summarizer, TEST_ACCOUNT_EMAIL_SUFFIX, type TokenDebugInfo, type ToolResult, type ToolSchema, type ToolsApiContext, UPLOAD_PART_BYTES, USERS_COLUMNS, type User, type UserAttachment, type UserContext, VOTING_SCHEMAS, type ValidationError, type VerifiedAuth, type VerifyOutcome, type VerifyResult, type Viewport, WORKSPACE_SCHEMAS, type YjsContext, YjsRoom, analyzePermissions, apiWorkerFetch, appendMessage, applyAiToolDefaults, applySlidingWindow, authWorkerFetch, bindingManifestFromOutputConfig, broadcastChange, broadcastYjsUpdate, buildCronContext, buildTableSelect, buildUiParts, callRegistry, canCreate, canDelete, canRead, canUpdate, cancelSubscription, capToolResultSize, captureScreenshot, checkFieldPermissions, coerceValue, collectionTableName, columnId, composioTools, computeDoMigration, computeHmacHex, createChat, createDeepSpaceAI, createDeepSpaceAuth, createScopedR2Handler, dataToColumnValues, decodeJwtPayload, deepSpaceAgentErrorSummary, deleteChatCascade, deleteRecord, enqueueJob, executeQuery, formatBytes, getAllUsers, getChat, getGlobalDOSchemas, getGlobalDOType, getOrCreateYjsDoc, getRecord, getRolePermissions, getSubscription, getUser, getYjsDocKey, handleApiRequest, handleDelete, handlePut, handleSetRole, handleSubscribe, handleToolsRequest, handleUnsubscribe, handleUserList, handleUserUpdate, handleYjsBinaryMessage, handleYjsJoin, handleYjsLeave, isAutoProvision, isFilesVerbPath, isOwner, isTestAccountClaims, isTestAccountEmail, isTestAccountTier, lintSchema, loadMessages, makeDefaultSummarizer, matchOrigin, meterAi, meterUsage, meterVectorize, noopPermissionContext, parseQuotaLimit, platformCorsPatterns, platformWorkerFetch, prepareMessagesWithCompaction, priceBindingUsageEvent, putRecord, readRecord, recordMatchesSubscription, refundInvoice, registerUser, registryErrorJson, registryStub, requireSubscription, resolveAppName, resolveColumn, rowToData, runMigrations, saveYjsDoc, storageLimitForTier, storageQuotaMessage, streamDeepSpaceAgent, timingSafeEqualHex, timingSafeEqualStrings, totalChars, truncateOldToolResults, turnsToCoreMessages, unwrapToolOutput, updateChat, validateAppName, validateBindingManifest, validateDoManifest, verifyJwt, workspaceAccountsSchema, workspaceContentSharesSchema, workspaceEmailHandlesSchema, workspaceFormResponsesSchema, workspacePeopleSchema, workspaceProjectsSchema, workspaceTagsSchema, workspaceTasksSchema, workspaceTeamMembersSchema, workspaceTeamsSchema, workspaceTransactionsSchema };
|
package/dist/server.js
CHANGED
|
@@ -2220,15 +2220,6 @@ var MSG = {
|
|
|
2220
2220
|
ACK: "records.ack",
|
|
2221
2221
|
LIST_SCHEMAS: "records.list_schemas",
|
|
2222
2222
|
RESUBSCRIBE: "records.resubscribe",
|
|
2223
|
-
// ---- GameRoom --------------------------------------------------------
|
|
2224
|
-
GAME_STATE: "game.state",
|
|
2225
|
-
GAME_INPUT: "game.input",
|
|
2226
|
-
GAME_PLAYER_JOIN: "game.player_join",
|
|
2227
|
-
GAME_PLAYER_LEAVE: "game.player_leave",
|
|
2228
|
-
GAME_PLAYER_READY: "game.player_ready",
|
|
2229
|
-
GAME_START: "game.start",
|
|
2230
|
-
GAME_END: "game.end",
|
|
2231
|
-
GAME_TICK: "game.tick",
|
|
2232
2223
|
// ---- CanvasRoom ------------------------------------------------------
|
|
2233
2224
|
CANVAS_SHAPES: "canvas.shapes",
|
|
2234
2225
|
CANVAS_ADD: "canvas.add",
|
|
@@ -2722,14 +2713,6 @@ var serverBuild = {
|
|
|
2722
2713
|
type: MSG.YJS_JOIN,
|
|
2723
2714
|
payload: { collection, recordId, fieldName, canWrite }
|
|
2724
2715
|
}),
|
|
2725
|
-
// Game
|
|
2726
|
-
gameState: (state, tick, players, running) => ({ type: MSG.GAME_STATE, payload: { state, tick, players, running } }),
|
|
2727
|
-
gameTick: (state, tick) => ({ type: MSG.GAME_TICK, payload: { state, tick } }),
|
|
2728
|
-
gameStart: (state, tick) => ({ type: MSG.GAME_START, payload: { state, tick } }),
|
|
2729
|
-
gameEnd: (state, tick) => ({ type: MSG.GAME_END, payload: { state, tick } }),
|
|
2730
|
-
gamePlayerJoin: (player) => ({ type: MSG.GAME_PLAYER_JOIN, payload: { player } }),
|
|
2731
|
-
gamePlayerLeave: (userId) => ({ type: MSG.GAME_PLAYER_LEAVE, payload: { userId } }),
|
|
2732
|
-
gamePlayerReady: (userId) => ({ type: MSG.GAME_PLAYER_READY, payload: { userId } }),
|
|
2733
2716
|
// Canvas
|
|
2734
2717
|
canvasShapes: (shapes, viewports) => ({ type: MSG.CANVAS_SHAPES, payload: { shapes, viewports } }),
|
|
2735
2718
|
canvasAdd: (shape) => ({ type: MSG.CANVAS_ADD, payload: { shape } }),
|
|
@@ -4325,136 +4308,6 @@ var RecordRoom = class extends BaseRoom {
|
|
|
4325
4308
|
);
|
|
4326
4309
|
`);
|
|
4327
4310
|
this.ensureAllCollectionTables();
|
|
4328
|
-
await this.migrateUsersTableIfExists();
|
|
4329
|
-
await this.migrateRecordsTable();
|
|
4330
|
-
}
|
|
4331
|
-
async migrateUsersTableIfExists() {
|
|
4332
|
-
try {
|
|
4333
|
-
const tableCheck = this.sql.exec(
|
|
4334
|
-
`SELECT name FROM sqlite_master WHERE type='table' AND name='users'`
|
|
4335
|
-
);
|
|
4336
|
-
if (tableCheck.toArray().length === 0) {
|
|
4337
|
-
return;
|
|
4338
|
-
}
|
|
4339
|
-
const oldUsers = this.sql.exec(`SELECT * FROM users`).toArray();
|
|
4340
|
-
if (oldUsers.length === 0) {
|
|
4341
|
-
this.sql.exec(`DROP TABLE IF EXISTS users`);
|
|
4342
|
-
return;
|
|
4343
|
-
}
|
|
4344
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
4345
|
-
for (const row of oldUsers) {
|
|
4346
|
-
const r = row;
|
|
4347
|
-
const existing = this.sql.exec(`SELECT 1 FROM c_users WHERE _row_id = ?`, r.user_id).toArray();
|
|
4348
|
-
if (existing.length > 0) continue;
|
|
4349
|
-
this.sql.exec(
|
|
4350
|
-
`INSERT INTO c_users (_row_id, _created_by, _created_at, _updated_at, col_email, col_name, col_imageurl, col_role, col_createdat, col_lastseenat) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
4351
|
-
r.user_id,
|
|
4352
|
-
r.user_id,
|
|
4353
|
-
r.created_at,
|
|
4354
|
-
now,
|
|
4355
|
-
r.email,
|
|
4356
|
-
r.name,
|
|
4357
|
-
r.image_url || null,
|
|
4358
|
-
r.role,
|
|
4359
|
-
r.created_at,
|
|
4360
|
-
r.last_seen_at
|
|
4361
|
-
);
|
|
4362
|
-
}
|
|
4363
|
-
this.sql.exec(`DROP TABLE IF EXISTS users`);
|
|
4364
|
-
} catch (error) {
|
|
4365
|
-
console.error(`[RecordRoom] Users table migration error:`, error);
|
|
4366
|
-
}
|
|
4367
|
-
}
|
|
4368
|
-
async migrateRecordsTable() {
|
|
4369
|
-
try {
|
|
4370
|
-
const tableCheck = this.sql.exec(
|
|
4371
|
-
`SELECT name FROM sqlite_master WHERE type='table' AND name='records'`
|
|
4372
|
-
);
|
|
4373
|
-
if (tableCheck.toArray().length === 0) return;
|
|
4374
|
-
const rows = this.sql.exec(`SELECT * FROM records`).toArray();
|
|
4375
|
-
if (rows.length === 0) {
|
|
4376
|
-
this.sql.exec(`DROP TABLE IF EXISTS records`);
|
|
4377
|
-
return;
|
|
4378
|
-
}
|
|
4379
|
-
const prepared = [];
|
|
4380
|
-
const blocked = {
|
|
4381
|
-
missingSchema: 0,
|
|
4382
|
-
invalidData: 0,
|
|
4383
|
-
targetConflict: 0
|
|
4384
|
-
};
|
|
4385
|
-
for (const row of rows) {
|
|
4386
|
-
const r = row;
|
|
4387
|
-
const schema = this.schemaRegistry.get(r.collection);
|
|
4388
|
-
if (!schema || !schema.columns) {
|
|
4389
|
-
blocked.missingSchema++;
|
|
4390
|
-
continue;
|
|
4391
|
-
}
|
|
4392
|
-
const tbl = collectionTableName(r.collection);
|
|
4393
|
-
const tblExists = this.sql.exec(`SELECT name FROM sqlite_master WHERE type='table' AND name=?`, tbl).toArray().length > 0;
|
|
4394
|
-
if (!tblExists) {
|
|
4395
|
-
this.ensureCollectionTable(schema);
|
|
4396
|
-
}
|
|
4397
|
-
const existing = this.sql.exec(`SELECT 1 FROM "${tbl}" WHERE _row_id = ?`, r.record_id).toArray();
|
|
4398
|
-
if (existing.length > 0) {
|
|
4399
|
-
blocked.targetConflict++;
|
|
4400
|
-
continue;
|
|
4401
|
-
}
|
|
4402
|
-
let data;
|
|
4403
|
-
try {
|
|
4404
|
-
data = JSON.parse(r.data);
|
|
4405
|
-
} catch {
|
|
4406
|
-
blocked.invalidData++;
|
|
4407
|
-
continue;
|
|
4408
|
-
}
|
|
4409
|
-
if (data === null || typeof data !== "object" || Array.isArray(data)) {
|
|
4410
|
-
blocked.invalidData++;
|
|
4411
|
-
continue;
|
|
4412
|
-
}
|
|
4413
|
-
const columns = schema.columns.map(resolveColumn);
|
|
4414
|
-
const colValues = dataToColumnValues(data, columns);
|
|
4415
|
-
const colIds = Object.keys(colValues);
|
|
4416
|
-
const allCols = [
|
|
4417
|
-
"_row_id",
|
|
4418
|
-
"_created_by",
|
|
4419
|
-
"_created_at",
|
|
4420
|
-
"_updated_at",
|
|
4421
|
-
...colIds.map((c) => `"${c}"`)
|
|
4422
|
-
];
|
|
4423
|
-
const placeholders = allCols.map(() => "?").join(", ");
|
|
4424
|
-
const params = [
|
|
4425
|
-
r.record_id,
|
|
4426
|
-
r.created_by,
|
|
4427
|
-
r.created_at,
|
|
4428
|
-
r.updated_at,
|
|
4429
|
-
...colIds.map((c) => colValues[c])
|
|
4430
|
-
];
|
|
4431
|
-
prepared.push({
|
|
4432
|
-
sql: `INSERT INTO "${tbl}" (${allCols.join(", ")}) VALUES (${placeholders})`,
|
|
4433
|
-
params
|
|
4434
|
-
});
|
|
4435
|
-
}
|
|
4436
|
-
const blockedCount = blocked.missingSchema + blocked.invalidData + blocked.targetConflict;
|
|
4437
|
-
if (blockedCount > 0) {
|
|
4438
|
-
console.error(
|
|
4439
|
-
`[RecordRoom] Legacy records migration blocked; no records migrated and the records table was retained for retry (${blockedCount} blocked: ${blocked.missingSchema} missing schema, ${blocked.invalidData} invalid data, ${blocked.targetConflict} target conflict)`
|
|
4440
|
-
);
|
|
4441
|
-
return;
|
|
4442
|
-
}
|
|
4443
|
-
this.state.storage.transactionSync(() => {
|
|
4444
|
-
for (const record of prepared) {
|
|
4445
|
-
this.sql.exec(record.sql, ...record.params);
|
|
4446
|
-
}
|
|
4447
|
-
this.sql.exec(`DROP TABLE IF EXISTS records`);
|
|
4448
|
-
});
|
|
4449
|
-
console.log(
|
|
4450
|
-
`[RecordRoom] Migrated ${prepared.length} records from document-mode; legacy records table removed`
|
|
4451
|
-
);
|
|
4452
|
-
} catch (error) {
|
|
4453
|
-
console.error(
|
|
4454
|
-
`[RecordRoom] Legacy records migration failed; no records migrated and the records table was retained for retry:`,
|
|
4455
|
-
error
|
|
4456
|
-
);
|
|
4457
|
-
}
|
|
4458
4311
|
}
|
|
4459
4312
|
// ============================================================================
|
|
4460
4313
|
// Table-Mode Schema Management
|
|
@@ -4931,6 +4784,9 @@ var YjsRoom = class extends BaseRoom {
|
|
|
4931
4784
|
}
|
|
4932
4785
|
};
|
|
4933
4786
|
|
|
4787
|
+
// src/server/rooms/canvas-room.ts
|
|
4788
|
+
import * as Y5 from "yjs";
|
|
4789
|
+
|
|
4934
4790
|
// src/shared/roles.ts
|
|
4935
4791
|
var ROLES = {
|
|
4936
4792
|
VIEWER: "viewer",
|
|
@@ -4938,271 +4794,7 @@ var ROLES = {
|
|
|
4938
4794
|
ADMIN: "admin"
|
|
4939
4795
|
};
|
|
4940
4796
|
|
|
4941
|
-
// src/server/rooms/game-room.ts
|
|
4942
|
-
var GAME_WRITE_TYPES = /* @__PURE__ */ new Set([
|
|
4943
|
-
MSG.GAME_INPUT,
|
|
4944
|
-
MSG.GAME_PLAYER_READY,
|
|
4945
|
-
MSG.GAME_START,
|
|
4946
|
-
MSG.GAME_END
|
|
4947
|
-
]);
|
|
4948
|
-
var GameRoom = class extends BaseRoom {
|
|
4949
|
-
config;
|
|
4950
|
-
players = /* @__PURE__ */ new Map();
|
|
4951
|
-
inputBuffer = [];
|
|
4952
|
-
currentTick = 0;
|
|
4953
|
-
gameState = {};
|
|
4954
|
-
running = false;
|
|
4955
|
-
initialized = false;
|
|
4956
|
-
constructor(state, env, config = {}) {
|
|
4957
|
-
super(state, env);
|
|
4958
|
-
this.config = {
|
|
4959
|
-
tickRate: config.tickRate ?? 20,
|
|
4960
|
-
minPlayers: config.minPlayers ?? 1,
|
|
4961
|
-
maxPlayers: config.maxPlayers ?? Infinity
|
|
4962
|
-
};
|
|
4963
|
-
}
|
|
4964
|
-
ensureInitialized() {
|
|
4965
|
-
if (this.initialized) return;
|
|
4966
|
-
this.initialized = true;
|
|
4967
|
-
this.sql.exec(`
|
|
4968
|
-
CREATE TABLE IF NOT EXISTS game_state (
|
|
4969
|
-
id INTEGER PRIMARY KEY CHECK (id = 1),
|
|
4970
|
-
state TEXT NOT NULL,
|
|
4971
|
-
tick INTEGER NOT NULL DEFAULT 0,
|
|
4972
|
-
updated_at TEXT NOT NULL
|
|
4973
|
-
)
|
|
4974
|
-
`);
|
|
4975
|
-
const rows = this.sql.exec("SELECT state, tick FROM game_state WHERE id = 1").toArray();
|
|
4976
|
-
if (rows.length > 0) {
|
|
4977
|
-
try {
|
|
4978
|
-
const parsed = JSON.parse(rows[0].state);
|
|
4979
|
-
this.gameState = this.onHydrateState(parsed);
|
|
4980
|
-
this.currentTick = rows[0].tick;
|
|
4981
|
-
} catch {
|
|
4982
|
-
}
|
|
4983
|
-
}
|
|
4984
|
-
}
|
|
4985
|
-
persistState() {
|
|
4986
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
4987
|
-
this.sql.exec(
|
|
4988
|
-
`INSERT INTO game_state (id, state, tick, updated_at) VALUES (1, ?, ?, ?)
|
|
4989
|
-
ON CONFLICT(id) DO UPDATE SET state = ?, tick = ?, updated_at = ?`,
|
|
4990
|
-
JSON.stringify(this.gameState),
|
|
4991
|
-
this.currentTick,
|
|
4992
|
-
now,
|
|
4993
|
-
JSON.stringify(this.gameState),
|
|
4994
|
-
this.currentTick,
|
|
4995
|
-
now
|
|
4996
|
-
);
|
|
4997
|
-
}
|
|
4998
|
-
// ==========================================================================
|
|
4999
|
-
// BaseRoom Lifecycle
|
|
5000
|
-
// ==========================================================================
|
|
5001
|
-
onConnect(ws, user) {
|
|
5002
|
-
this.ensureInitialized();
|
|
5003
|
-
const role = user.role ?? ROLES.VIEWER;
|
|
5004
|
-
const canWrite = role === ROLES.MEMBER || role === ROLES.ADMIN;
|
|
5005
|
-
const attachment = {
|
|
5006
|
-
...user,
|
|
5007
|
-
joinedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
5008
|
-
canWrite
|
|
5009
|
-
};
|
|
5010
|
-
this.sendTo(ws, { type: MSG.AUTH, payload: { canWrite } });
|
|
5011
|
-
if (!canWrite) {
|
|
5012
|
-
this.sendTo(ws, {
|
|
5013
|
-
type: MSG.GAME_STATE,
|
|
5014
|
-
payload: {
|
|
5015
|
-
state: this.gameState,
|
|
5016
|
-
tick: this.currentTick,
|
|
5017
|
-
players: Array.from(this.players.values()),
|
|
5018
|
-
running: this.running
|
|
5019
|
-
}
|
|
5020
|
-
});
|
|
5021
|
-
return attachment;
|
|
5022
|
-
}
|
|
5023
|
-
const player = {
|
|
5024
|
-
userId: user.userId,
|
|
5025
|
-
userName: user.userName,
|
|
5026
|
-
ready: false,
|
|
5027
|
-
connectedAt: attachment.joinedAt,
|
|
5028
|
-
data: {}
|
|
5029
|
-
};
|
|
5030
|
-
if (this.config.maxPlayers !== Infinity && this.players.size >= this.config.maxPlayers) {
|
|
5031
|
-
this.sendTo(ws, { type: MSG.ERROR, payload: { error: "Game is full" } });
|
|
5032
|
-
return attachment;
|
|
5033
|
-
}
|
|
5034
|
-
this.players.set(user.userId, player);
|
|
5035
|
-
this.sendTo(ws, {
|
|
5036
|
-
type: MSG.GAME_STATE,
|
|
5037
|
-
payload: {
|
|
5038
|
-
state: this.gameState,
|
|
5039
|
-
tick: this.currentTick,
|
|
5040
|
-
players: Array.from(this.players.values()),
|
|
5041
|
-
running: this.running
|
|
5042
|
-
}
|
|
5043
|
-
});
|
|
5044
|
-
this.broadcast({ type: MSG.GAME_PLAYER_JOIN, payload: { player } }, ws);
|
|
5045
|
-
this.onPlayerJoin(player);
|
|
5046
|
-
return attachment;
|
|
5047
|
-
}
|
|
5048
|
-
async onMessage(ws, user, message) {
|
|
5049
|
-
this.ensureInitialized();
|
|
5050
|
-
const { type, payload } = message;
|
|
5051
|
-
if (GAME_WRITE_TYPES.has(type) && !user.canWrite) {
|
|
5052
|
-
this.sendTo(ws, {
|
|
5053
|
-
type: MSG.ERROR,
|
|
5054
|
-
payload: { error: "Write access denied: spectators cannot drive the game" }
|
|
5055
|
-
});
|
|
5056
|
-
return;
|
|
5057
|
-
}
|
|
5058
|
-
switch (type) {
|
|
5059
|
-
case MSG.GAME_INPUT: {
|
|
5060
|
-
this.inputBuffer.push({
|
|
5061
|
-
userId: user.userId,
|
|
5062
|
-
action: payload.action,
|
|
5063
|
-
data: payload.data ?? {},
|
|
5064
|
-
tick: this.currentTick
|
|
5065
|
-
});
|
|
5066
|
-
break;
|
|
5067
|
-
}
|
|
5068
|
-
case MSG.GAME_PLAYER_READY: {
|
|
5069
|
-
const player = this.players.get(user.userId);
|
|
5070
|
-
if (player) {
|
|
5071
|
-
player.ready = true;
|
|
5072
|
-
this.broadcast({ type: MSG.GAME_PLAYER_READY, payload: { userId: user.userId } });
|
|
5073
|
-
this.checkAutoStart();
|
|
5074
|
-
}
|
|
5075
|
-
break;
|
|
5076
|
-
}
|
|
5077
|
-
case MSG.GAME_START: {
|
|
5078
|
-
if (!this.running) {
|
|
5079
|
-
this.startGame();
|
|
5080
|
-
}
|
|
5081
|
-
break;
|
|
5082
|
-
}
|
|
5083
|
-
case MSG.GAME_END: {
|
|
5084
|
-
if (this.running) {
|
|
5085
|
-
this.stopGame();
|
|
5086
|
-
}
|
|
5087
|
-
break;
|
|
5088
|
-
}
|
|
5089
|
-
default:
|
|
5090
|
-
this.sendTo(ws, { type: MSG.ERROR, payload: { error: `Unknown game message type: ${type}` } });
|
|
5091
|
-
}
|
|
5092
|
-
}
|
|
5093
|
-
onDisconnect(_ws, user) {
|
|
5094
|
-
const player = this.players.get(user.userId);
|
|
5095
|
-
if (player) {
|
|
5096
|
-
this.players.delete(user.userId);
|
|
5097
|
-
this.broadcast({ type: MSG.GAME_PLAYER_LEAVE, payload: { userId: user.userId } });
|
|
5098
|
-
this.onPlayerLeave(player);
|
|
5099
|
-
if (this.running && this.players.size === 0) {
|
|
5100
|
-
this.stopGame();
|
|
5101
|
-
}
|
|
5102
|
-
}
|
|
5103
|
-
}
|
|
5104
|
-
async onAlarm() {
|
|
5105
|
-
if (!this.running) return;
|
|
5106
|
-
const inputs = this.inputBuffer.splice(0);
|
|
5107
|
-
this.currentTick++;
|
|
5108
|
-
const newState = await this.onTick(this.gameState, inputs, this.currentTick);
|
|
5109
|
-
if (newState !== void 0) {
|
|
5110
|
-
this.gameState = newState;
|
|
5111
|
-
}
|
|
5112
|
-
if (this.currentTick % 10 === 0) {
|
|
5113
|
-
this.persistState();
|
|
5114
|
-
}
|
|
5115
|
-
this.broadcast({
|
|
5116
|
-
type: MSG.GAME_TICK,
|
|
5117
|
-
payload: {
|
|
5118
|
-
state: this.gameState,
|
|
5119
|
-
tick: this.currentTick
|
|
5120
|
-
}
|
|
5121
|
-
});
|
|
5122
|
-
if (this.running) {
|
|
5123
|
-
const intervalMs = 1e3 / this.config.tickRate;
|
|
5124
|
-
this.state.storage.setAlarm(Date.now() + intervalMs);
|
|
5125
|
-
}
|
|
5126
|
-
}
|
|
5127
|
-
// ==========================================================================
|
|
5128
|
-
// Game Control
|
|
5129
|
-
// ==========================================================================
|
|
5130
|
-
checkAutoStart() {
|
|
5131
|
-
if (this.running) return;
|
|
5132
|
-
const readyCount = Array.from(this.players.values()).filter((p) => p.ready).length;
|
|
5133
|
-
if (readyCount >= this.config.minPlayers && readyCount === this.players.size) {
|
|
5134
|
-
this.startGame();
|
|
5135
|
-
}
|
|
5136
|
-
}
|
|
5137
|
-
startGame() {
|
|
5138
|
-
this.running = true;
|
|
5139
|
-
this.currentTick = 0;
|
|
5140
|
-
this.inputBuffer = [];
|
|
5141
|
-
this.onGameStart();
|
|
5142
|
-
this.broadcast({ type: MSG.GAME_START, payload: { state: this.gameState, tick: 0 } });
|
|
5143
|
-
const intervalMs = 1e3 / this.config.tickRate;
|
|
5144
|
-
this.state.storage.setAlarm(Date.now() + intervalMs);
|
|
5145
|
-
}
|
|
5146
|
-
stopGame() {
|
|
5147
|
-
this.running = false;
|
|
5148
|
-
this.persistState();
|
|
5149
|
-
this.onGameEnd(this.gameState);
|
|
5150
|
-
this.broadcast({ type: MSG.GAME_END, payload: { state: this.gameState, tick: this.currentTick } });
|
|
5151
|
-
}
|
|
5152
|
-
// ==========================================================================
|
|
5153
|
-
// Protected Accessors (for subclasses)
|
|
5154
|
-
// ==========================================================================
|
|
5155
|
-
getGameState() {
|
|
5156
|
-
return this.gameState;
|
|
5157
|
-
}
|
|
5158
|
-
setGameState(state) {
|
|
5159
|
-
this.gameState = state;
|
|
5160
|
-
}
|
|
5161
|
-
getPlayers() {
|
|
5162
|
-
return Array.from(this.players.values());
|
|
5163
|
-
}
|
|
5164
|
-
isRunning() {
|
|
5165
|
-
return this.running;
|
|
5166
|
-
}
|
|
5167
|
-
getCurrentTick() {
|
|
5168
|
-
return this.currentTick;
|
|
5169
|
-
}
|
|
5170
|
-
/** Called when a player connects */
|
|
5171
|
-
onPlayerJoin(_player) {
|
|
5172
|
-
}
|
|
5173
|
-
/** Called when a player disconnects */
|
|
5174
|
-
onPlayerLeave(_player) {
|
|
5175
|
-
}
|
|
5176
|
-
/** Called when the game starts */
|
|
5177
|
-
onGameStart() {
|
|
5178
|
-
}
|
|
5179
|
-
/** Called when the game ends */
|
|
5180
|
-
onGameEnd(_finalState) {
|
|
5181
|
-
}
|
|
5182
|
-
/**
|
|
5183
|
-
* Called once when the DO first hydrates persisted state from storage.
|
|
5184
|
-
* Receives the parsed state blob as it was written by a previous build.
|
|
5185
|
-
* Return the state object to install as `gameState`.
|
|
5186
|
-
*
|
|
5187
|
-
* Subclasses with evolving schemas should override this hook to:
|
|
5188
|
-
* - merge new fields onto a default template,
|
|
5189
|
-
* - upgrade shapes across versioned states,
|
|
5190
|
-
* - or discard stale blobs entirely by returning a fresh object.
|
|
5191
|
-
*
|
|
5192
|
-
* The default implementation is a pass-through, preserving the legacy
|
|
5193
|
-
* "stored blob is gospel" behavior for subclasses that don't care.
|
|
5194
|
-
*
|
|
5195
|
-
* If JSON parsing of the stored blob fails this hook is NOT called — the
|
|
5196
|
-
* DO starts with an empty state and the subclass's `onGameStart` (or
|
|
5197
|
-
* first `onTick`) is responsible for initializing.
|
|
5198
|
-
*/
|
|
5199
|
-
onHydrateState(stored) {
|
|
5200
|
-
return stored;
|
|
5201
|
-
}
|
|
5202
|
-
};
|
|
5203
|
-
|
|
5204
4797
|
// src/server/rooms/canvas-room.ts
|
|
5205
|
-
import * as Y5 from "yjs";
|
|
5206
4798
|
var CANVAS_WRITE_TYPES = /* @__PURE__ */ new Set([
|
|
5207
4799
|
MSG.CANVAS_ADD,
|
|
5208
4800
|
MSG.CANVAS_MOVE,
|
|
@@ -8033,7 +7625,6 @@ export {
|
|
|
8033
7625
|
DeepSpaceAgentProfileError,
|
|
8034
7626
|
GLOBAL_DO_TYPES,
|
|
8035
7627
|
GLOBAL_DO_TYPE_NAMES,
|
|
8036
|
-
GameRoom,
|
|
8037
7628
|
JobRoom,
|
|
8038
7629
|
MAX_APP_FILE_BYTES,
|
|
8039
7630
|
MAX_DEPLOY_ASSET_FILE_BYTES,
|