@easytwin/devkit 0.1.1 → 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/dist/index.d.ts CHANGED
@@ -5,7 +5,14 @@ declare const CONFIG_FILE_NAME = "easytwin.config.json";
5
5
  */
6
6
  declare const DEFAULT_BASE_URL = "http://saas-twin.k8s.dtstack.cn/";
7
7
  /** 官方测试环境域名。 */
8
- declare const TEST_BASE_URL = "http://saas-twin-test.k8s.dtstack.cn/";
8
+ declare const TEST_BASE_URL = "http://172.16.125.3:10100/";
9
+ /**
10
+ * 当前测试 OP 网关缺省头(与编辑器 curl 一致)。配置/环境变量可覆盖。
11
+ * 免网关接口到位后删除(D13)。
12
+ */
13
+ declare const TEST_OP_ACCOUNT_ID = "25";
14
+ declare const TEST_OP_USER_ID = "25";
15
+ declare const TEST_SPACE_ID = "54";
9
16
  /**
10
17
  * 官方 OSS(twin runtime baseOSSUrl)。系统资产由此拼出:
11
18
  * `{ossUrl}/easytwin/system/libs/webp-wasm.wasm`、
@@ -30,6 +37,24 @@ interface EasyTwinConfig {
30
37
  baseUrl?: string;
31
38
  /** twin runtime 资产根(baseOSSUrl);缺省官方 OSS,可覆盖为 CDN/自建存储。 */
32
39
  ossUrl?: string;
40
+ /** 过渡期 OP 网关头;免网关接口到位后删除(D13)。 */
41
+ opAccountId?: string;
42
+ opUserId?: string;
43
+ spaceId?: string;
44
+ /**
45
+ * 关联场景摘要,由 scene list / 场景树刷新写入(D17)。
46
+ * 不含场景 JSON 本体;下次 list 全量覆盖。
47
+ */
48
+ scenes?: ConfigScene[];
49
+ }
50
+ /** 写入 easytwin.config.json 的关联场景摘要(对应 listScenes 的可序列化子集)。 */
51
+ interface ConfigScene {
52
+ /** Scene Key,与 `easytwin scene pull <id>` 对应。 */
53
+ id: string;
54
+ name: string;
55
+ linkedSceneId?: string;
56
+ snapshotUrl?: string;
57
+ defaultLoading?: boolean;
33
58
  }
34
59
  /** 解析 + 环境变量覆盖后的最终配置。 */
35
60
  interface ResolvedConfig {
@@ -38,9 +63,13 @@ interface ResolvedConfig {
38
63
  baseUrl: string;
39
64
  /** twin runtime baseOSSUrl(系统库 draco/basis/webp、custom script 与相对路径资产);缺省官方 OSS。 */
40
65
  ossUrl: string;
41
- /** 本地测试模式:appId/appSecret 均为 "test" 时启用,scene/upload 走本地 mock 不发请求。 */
66
+ /** 本地测试模式:appId/appSecret 均为 "test" 时启用,scene/upload/pull 走本地 mock 不发请求。 */
42
67
  mock: boolean;
43
68
  source: "file" | "env";
69
+ /** 过渡期 OP 网关头;env=test 时缺省 25/25/54。免网关接口到位后删除(D13)。 */
70
+ opAccountId?: string;
71
+ opUserId?: string;
72
+ spaceId?: string;
44
73
  }
45
74
  declare class ConfigError extends Error {
46
75
  constructor(message: string);
@@ -67,19 +96,29 @@ interface InitResult {
67
96
  }
68
97
  /** init 的 lib 实现:生成配置文件 + 追加 gitignore(与插件配置向导共用同一实现)。 */
69
98
  declare function initConfig(input: EasyTwinConfig, cwd: string): Promise<InitResult>;
99
+ /** 把场景摘要写入配置 `scenes`(全量覆盖该数组,保留其余字段)。 */
100
+ declare function writeConfigScenes(cwd: string, scenes: ConfigScene[]): Promise<void>;
70
101
 
71
102
  /**
72
- * TODO(swagger): 认证头名称、endpoint 路径、请求/响应结构一律以内部 swagger 为准。
73
- * 以下常量为占位约定;swagger 到位后在 client.ts / scene.ts / upload.ts 集中修订,不扩散到其它文件。
103
+ * 认证与路径以内部 swagger 为准(标签:SDK 应用场景 / SDK 应用代码 / SDK Runtime)。
104
+ * 全仓唯一认证头注入点:`x-app-secret` = App Secret。
105
+ * 过渡期另注入 OP 网关头 op-account-id / op-user-id / space-id(D13,免网关接口到位后删除)。
106
+ * 场景/代码路径参数名为 applicationId;DevKit 传入配置里的 App ID。
74
107
  */
75
- declare const AUTH_HEADER = "Authorization";
76
- declare const BEARER_PREFIX = "Bearer";
77
- /** TODO(swagger): 应用标识头名待定(上传目标空间由 App ID 决定)。 */
78
- declare const APP_ID_HEADER = "X-Easytwin-App-Id";
108
+ declare const AUTH_HEADER = "x-app-secret";
109
+ /** 过渡期 OP 网关头;免网关接口到位后删除(D13)。 */
110
+ declare const OP_ACCOUNT_ID_HEADER = "op-account-id";
111
+ declare const OP_USER_ID_HEADER = "op-user-id";
112
+ declare const SPACE_ID_HEADER = "space-id";
79
113
  declare const ENDPOINTS: {
80
- readonly scenes: "/api/scenes";
81
- readonly scene: (id: string) => string;
82
- readonly upload: "/api/upload";
114
+ /** GET 已关联场景列表。 */
115
+ readonly linkedScenes: (applicationId: string) => string;
116
+ /** GET 工作区全部代码文件。 */
117
+ readonly workspaceCode: (applicationId: string) => string;
118
+ /** GET 工作区文件约束。 */
119
+ readonly workspaceConfig: (applicationId: string) => string;
120
+ /** POST 新建 / PATCH 批量更新 / DELETE 批量删除。 */
121
+ readonly workspaceCodeFiles: (applicationId: string) => string;
83
122
  };
84
123
  declare class EasyTwinApiError extends Error {
85
124
  readonly status: number;
@@ -87,17 +126,23 @@ declare class EasyTwinApiError extends Error {
87
126
  constructor(status: number, message: string, body?: unknown);
88
127
  }
89
128
  interface RequestOptions {
90
- method?: "GET" | "POST" | "PUT" | "DELETE";
129
+ method?: "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
91
130
  headers?: Record<string, string>;
92
131
  body?: string | null;
93
132
  signal?: AbortSignal;
94
133
  }
95
134
  declare class EasyTwinClient {
96
135
  readonly baseUrl: string;
97
- /** 本地测试模式:true scene/upload 走本地 mock,不发网络请求(见 config.ts)。 */
136
+ /** twin runtime / 场景快照资产根(baseOSSUrl)。 */
137
+ readonly ossUrl: string;
138
+ /** 接入凭证 App ID;同时作为场景/代码 API 的 applicationId 路径参数。 */
139
+ readonly appId: string;
140
+ /** 本地测试模式:true 时 scene/upload/pull 走本地 mock,不发网络请求(见 config.ts)。 */
98
141
  readonly mock: boolean;
99
- private readonly appId;
100
142
  private readonly appSecret;
143
+ private readonly opAccountId?;
144
+ private readonly opUserId?;
145
+ private readonly spaceId?;
101
146
  constructor(config: ResolvedConfig);
102
147
  /** 全仓唯一认证头注入点。 */
103
148
  private authHeaders;
@@ -115,21 +160,49 @@ declare class EasyTwinClient {
115
160
  private handleStatus;
116
161
  }
117
162
 
163
+ /** swagger `SdkApplicationLinkedSceneVo`。 */
164
+ interface LinkedScene {
165
+ /** 关联记录 ID。 */
166
+ id: string;
167
+ /** SDK 业务标识 Scene Key(list/pull 的主键)。 */
168
+ sceneKey: string;
169
+ name: string;
170
+ defaultLoading: boolean;
171
+ sourceSceneId: string;
172
+ sourceProjectId: string;
173
+ sourceSceneName: string;
174
+ sourceProjectName: string;
175
+ sourceLost: boolean;
176
+ /** 场景快照 JSON 的 OSS 相对路径(或绝对 URL)。 */
177
+ snapshotUrl: string;
178
+ snapshotUpdatedAt: string;
179
+ }
118
180
  interface SceneSummary {
181
+ /** Scene Key,与 `easytwin scene pull <id>` 对应。 */
119
182
  id: string;
120
183
  name: string;
184
+ linkedSceneId?: string;
185
+ snapshotUrl?: string;
186
+ defaultLoading?: boolean;
121
187
  }
122
188
  interface SceneDetail {
123
189
  id: string;
124
190
  name: string;
125
191
  /**
126
- * 服务端返回的场景 JSON 原始内容。
192
+ * 场景快照 JSON 原始内容。
127
193
  * 结构以 easytwin-runtime 的 SceneJson 为准(见 skills/easytwin-scene)。
128
194
  */
129
195
  payload: unknown;
130
196
  }
197
+ /** 从信封/Runtime VO/数组中取出场景列表。 */
198
+ declare function extractSceneArray(data: unknown): unknown[];
199
+ /** 把 swagger 关联场景 / Runtime scenes 规范为 LinkedScene[]。 */
200
+ declare function normalizeLinkedScenes(data: unknown): LinkedScene[];
131
201
  declare function normalizeSceneList(data: unknown): SceneSummary[];
132
- declare function normalizeSceneDetail(data: unknown): SceneDetail;
202
+ /** list 结果收成配置里的 scenes 摘要(省略空可选字段) */
203
+ declare function toConfigScenes(scenes: SceneSummary[]): ConfigScene[];
204
+ /** 拼接场景快照地址:绝对 URL 原样使用,否则挂到 ossUrl 下。 */
205
+ declare function resolveSnapshotUrl(ossUrl: string, snapshotUrl: string): string;
133
206
  /** devkit 包内本地测试场景文件名(4.4 本地测试模式)。 */
134
207
  declare const EXAMPLE_SCENE_FILE = "scene.example.json";
135
208
  /** 本地测试模式下场景列表展示的名字(示例文件本身不含场景级 name)。 */
@@ -147,6 +220,7 @@ declare function deriveExampleSceneId(payload: unknown): string;
147
220
  declare function exampleSceneSummary(exampleFile?: string): Promise<SceneSummary>;
148
221
  declare function listScenes(client: EasyTwinClient, options?: {
149
222
  exampleFile?: string;
223
+ cwd?: string;
150
224
  }): Promise<SceneSummary[]>;
151
225
  declare function pullScene(client: EasyTwinClient, id: string, options?: {
152
226
  exampleFile?: string;
@@ -191,15 +265,89 @@ interface CollectedFile {
191
265
  absPath: string;
192
266
  size: number;
193
267
  }
268
+ /** swagger `SdkApplicationWorkspaceCodeConfigVo`。 */
269
+ interface WorkspaceCodeConfig {
270
+ allowedFileExtensions: string[];
271
+ maxCodeFiles: number;
272
+ maxCodeDirectoryDepth: number;
273
+ }
274
+ /** swagger `SdkApplicationWorkspaceCodeFileVo`。 */
275
+ interface WorkspaceCodeFile {
276
+ id: string;
277
+ filePath: string;
278
+ content: string;
279
+ }
194
280
  /** 递归收集目录下全部文件(默认跳过 .git),按相对路径升序排列,保证顺序稳定。 */
195
281
  declare function collectFiles(dir: string, ignore?: (relPath: string) => boolean): Promise<CollectedFile[]>;
196
282
  declare function buildMultipartBody(boundary: string, fields: Record<string, string>, file: {
197
283
  name: string;
198
284
  content: Buffer;
199
285
  }): Buffer;
200
- /** 全量覆盖上传目录:逐文件 multipart 上传,带进度回调(供插件进度条)。本地测试模式(mock)时退化为 dry-run。 */
286
+ declare function normalizePath(relPath: string): string;
287
+ declare function normalizeWorkspaceConfig(data: unknown): WorkspaceCodeConfig;
288
+ declare function normalizeWorkspaceFiles(data: unknown): WorkspaceCodeFile[];
289
+ /** 目录深度:根文件为 0,`src/a.ts` 为 1,`src/utils/a.ts` 为 2。 */
290
+ declare function directoryDepth(relPath: string): number;
291
+ declare function assertUploadable(files: CollectedFile[], config: WorkspaceCodeConfig): void;
292
+ /**
293
+ * 全量覆盖上传目录:对照工作区代码文件(GET/POST/PATCH/DELETE)使远端与本地一致。
294
+ * 本地测试模式(mock)时退化为 dry-run。
295
+ */
201
296
  declare function uploadDirectory(client: EasyTwinClient, dir: string, options?: UploadOptions): Promise<UploadResult>;
202
297
 
298
+ declare const DEFAULT_ENTRY_PATH = "src/main.ts";
299
+ /** 与 easytwin-render 可上传子集示例对齐的默认 TwinApp 子类入口。 */
300
+ declare const DEFAULT_MAIN_TS = "import { TwinApp, type TwinAppContext } from \"@easytwin/apps\";\n\nexport default class App extends TwinApp {\n async init(ctx: TwinAppContext) {\n // engine / container \u5DF2\u6709;scene / camera \u4E3A null\n void ctx;\n }\n\n async onSceneLoaded(ctx: TwinAppContext) {\n // \u573A\u666F\u5B57\u6BB5\u6709\u503C;\u5728\u6B64\u52A0\u7269\u4F53 / \u7ED1\u4E8B\u4EF6,\u5E76\u7528 ctx.sceneCleanup \u5BF9\u79F0\u62C6\u9664\n void ctx;\n }\n\n onUpdate(ctx: TwinAppContext, delta: number, elapsed: number) {\n void ctx;\n void delta;\n void elapsed;\n }\n\n onDispose(ctx: TwinAppContext) {\n void ctx;\n }\n}\n";
301
+ type WorkspaceChangeKind = "identical" | "remote-only" | "local-only" | "modified" | "seed";
302
+ interface WorkspaceFileChange {
303
+ path: string;
304
+ kind: WorkspaceChangeKind;
305
+ localContent?: string;
306
+ remoteContent?: string;
307
+ }
308
+ interface WorkspacePullPlan {
309
+ remoteEmpty: boolean;
310
+ seededDefaults: boolean;
311
+ mock?: boolean;
312
+ skippedRemotePaths: string[];
313
+ changes: WorkspaceFileChange[];
314
+ }
315
+ interface WorkspacePullOptions {
316
+ /** 用远端内容覆盖内容冲突的本地文件;仅本地文件仍不删除。 */
317
+ force?: boolean;
318
+ /** 只算计划,不写盘。 */
319
+ dryRun?: boolean;
320
+ ignore?: (relPath: string) => boolean;
321
+ }
322
+ interface WorkspacePullResult {
323
+ plan: WorkspacePullPlan;
324
+ written: string[];
325
+ skippedConflicts: string[];
326
+ dryRun?: boolean;
327
+ mock?: boolean;
328
+ }
329
+ declare function defaultPullIgnore(relPath: string): boolean;
330
+ /** 拒绝逃逸、空路径与凭据文件,避免远端路径写到工作区外。 */
331
+ declare function isSafeRelPath(relPath: string): boolean;
332
+ /**
333
+ * 对照远端工作区代码与本地目录,算出 diff 计划。
334
+ * mock 或远端无有效文件时,本地缺省入口视为 seed。
335
+ */
336
+ declare function planWorkspacePull(client: EasyTwinClient, dir: string, options?: Pick<WorkspacePullOptions, "ignore">): Promise<WorkspacePullPlan>;
337
+ interface WorkspacePullApplyResult {
338
+ written: string[];
339
+ skippedConflicts: string[];
340
+ }
341
+ /** 按计划写盘:seed 与 remote-only 始终写入;modified 仅 force 时覆盖;不删 local-only。 */
342
+ declare function applyWorkspacePull(dir: string, plan: WorkspacePullPlan, options?: {
343
+ force?: boolean;
344
+ }): Promise<WorkspacePullApplyResult>;
345
+ declare function pullWorkspace(client: EasyTwinClient, dir: string, options?: WorkspacePullOptions): Promise<WorkspacePullResult>;
346
+ declare function formatWorkspacePullPlan(plan: WorkspacePullPlan): string;
347
+ declare function formatWorkspacePullResult(result: WorkspacePullResult): string;
348
+ declare function workspacePullHasConflicts(plan: WorkspacePullPlan): boolean;
349
+ declare function workspacePullPendingWrites(plan: WorkspacePullPlan, force?: boolean): string[];
350
+
203
351
  type SyncTarget = "cursor" | "claude" | "codex" | "qoder";
204
352
  type SyncTargetArg = SyncTarget | "all";
205
353
  /** 六件套清单(5.1),顺序即输出顺序。 */
@@ -229,7 +377,9 @@ declare const META_FILE_NAME = ".easytwin-meta.json";
229
377
  /** 用户项目内 runtime 类型落地目录(posix)。 */
230
378
  declare const EASYTWIN_TYPES_DIR = ".easytwin/types";
231
379
  declare const MINIMAL_TSCONFIG: string;
232
- declare const TSCONFIG_PATHS_HINT = "\u5DF2\u6709 tsconfig.json,\u672A\u6539\u52A8\u3002\u8BF7\u5728 compilerOptions \u4E2D\u52A0\u5165:\n \"skipLibCheck\": true,\n \"paths\": {\n \"@easytwin/runtime\": [\".easytwin/types\"]\n }";
380
+ declare const TSCONFIG_PATHS_HINT = "\u5DF2\u6709 tsconfig.json,\u672A\u6539\u52A8\u3002\u8BF7\u5728 compilerOptions \u4E2D\u52A0\u5165:\n \"skipLibCheck\": true,\n \"paths\": {\n \"@easytwin/runtime\": [\".easytwin/types\"],\n \"@easytwin/apps\": [\".easytwin/types/apps\"]\n }";
381
+ declare const APPS_TYPES_FILE = "apps.d.ts";
382
+ declare const APPS_DTS = "import type { RuntimeEngine, RuntimeScene, SceneManager } from \"@easytwin/runtime\";\n\nexport type TwinAppContext = {\n app: {\n id: string;\n mode: \"preview\" | \"publish\";\n };\n engine: RuntimeEngine;\n container: HTMLElement;\n runtimeScene: RuntimeScene | null;\n scene: RuntimeScene[\"sceneObject\"] | null;\n camera: RuntimeScene[\"camera\"][\"main\"] | null;\n sceneManager: {\n currentSceneId: string;\n runtime: SceneManager | null;\n loadScene(sceneId: string): Promise<void>;\n };\n logger: {\n log(...args: unknown[]): void;\n info(...args: unknown[]): void;\n warn(...args: unknown[]): void;\n error(...args: unknown[]): void;\n };\n assets: {\n text(path: string): Promise<string>;\n json<T = unknown>(path: string): Promise<T>;\n };\n cleanup(fn: () => void | Promise<void>): void;\n sceneCleanup(fn: () => void | Promise<void>): void;\n};\n\nexport declare abstract class TwinApp {\n init?(ctx: TwinAppContext): void | Promise<void>;\n onUpdate?(ctx: TwinAppContext, delta: number, elapsed: number): void;\n onBeforeSceneUnload?(ctx: TwinAppContext): void | Promise<void>;\n onSceneLoaded?(ctx: TwinAppContext): void | Promise<void>;\n onDispose?(ctx: TwinAppContext): void | Promise<void>;\n onError?(ctx: TwinAppContext, error: unknown): boolean | void;\n}\n\nexport declare function defineApp<T>(app: T): T;\n";
233
383
  declare function buildRuntimeTypesContent(sourceDts: string): string;
234
384
  declare function normalizeTargets(target?: SyncTargetArg | SyncTarget[]): SyncTarget[];
235
385
  /** skills 源目录默认解析:CLI 下为 devkit 包内 skills/。插件 bundle 到 CJS 后 import.meta.url 为空,
@@ -265,8 +415,9 @@ declare function detectSkillsStatus(cwd: string, sourceDir?: string): Promise<Sk
265
415
  declare const USER_ENTRY = "src/main.ts";
266
416
  /** CLI 缺省输出路径(相对工作区根)。 */
267
417
  declare const DEFAULT_BUNDLE_OUT = "dist/main.js";
268
- /** 白名单唯一允许的裸模块。 */
418
+ /** 白名单允许的裸模块。 */
269
419
  declare const RUNTIME_MODULE = "@easytwin/runtime";
420
+ declare const APPS_MODULE = "@easytwin/apps";
270
421
  declare class BundleError extends Error {
271
422
  constructor(message: string);
272
423
  }
@@ -279,7 +430,7 @@ interface BundleResult {
279
430
  code: string;
280
431
  warnings: string[];
281
432
  }
282
- /** 打包工作区 src/main.ts。产物标准 ESM + inline sourcemap;仅允许依赖 @easytwin/runtime。 */
433
+ /** 打包工作区 src/main.ts。产物标准 ESM + inline sourcemap;仅允许 @easytwin/runtime 与 @easytwin/apps。 */
283
434
  declare function bundleUserCode(options: BundleUserCodeOptions): Promise<BundleResult>;
284
435
  /** 若工作区尚未同步 runtime 类型,返回提示文案;已同步则返回 undefined。 */
285
436
  declare function typesMissingHint(cwd: string): Promise<string | undefined>;
@@ -294,4 +445,142 @@ declare function extractInlineSourceMap(code: string): SourceMapJson | undefined
294
445
  */
295
446
  declare function remapErrorStack(stack: string, bundledCode: string): string;
296
447
 
297
- export { APP_ID_HEADER, AUTH_HEADER, BEARER_PREFIX, BundleError, type BundleResult, type BundleUserCodeOptions, CODEX_MARKER_BEGIN, CODEX_MARKER_END, CONFIG_FILE_NAME, type CollectedFile, ConfigError, DEFAULT_BASE_URL, DEFAULT_BUNDLE_OUT, DEFAULT_OSS_URL, EASYTWIN_TYPES_DIR, ENDPOINTS, EXAMPLE_SCENE_FILE, EasyTwinApiError, EasyTwinClient, type EasyTwinConfig, type EasyTwinEnv, GITIGNORE_ENTRY, GITIGNORE_FILE_NAME, type GitignoreResult, type InitResult, META_FILE_NAME, MINIMAL_TSCONFIG, MOCK_APP_ID, MOCK_APP_SECRET, MOCK_SCENE_NAME, RUNTIME_MODULE, type RequestOptions, type ResolvedConfig, SKILL_NAMES, type SceneDetail, type SceneSummary, type SceneTreeNode, type SkillsStatus, type SkillsTargetStatus, type SyncAction, type SyncEntrySummary, type SyncOptions, type SyncSkillsResult, type SyncSummary, type SyncTarget, type SyncTargetArg, TEST_BASE_URL, TSCONFIG_PATHS_HINT, type TypesSyncSummary, USER_ENTRY, type UploadOptions, type UploadProgress, type UploadResult, appendGitignore, buildMultipartBody, buildRuntimeTypesContent, bundleUserCode, collectFiles, configFilePath, deriveExampleSceneId, detectSkillsStatus, exampleSceneSummary, extractInlineSourceMap, initConfig, isMockCredentials, listScenes, loadConfig, loadExampleScene, normalizeSceneDetail, normalizeSceneList, normalizeTargets, parseConfig, parseSceneStructure, pullScene, readConfigFile, readDevkitVersion, remapErrorStack, resolveConfig, resolveExampleScenePath, resolveRuntimeTypesSourceFile, resolveSkillsSourceDir, saveSceneJson, syncSkills, typesMissingHint, uploadDirectory, validateConfigShape, writeConfigFile };
448
+ /** 在线 TwinApp 编译 stub 露出的 `@easytwin/runtime` 导出名。本地整包 external,超出此集合只 warning。 */
449
+ declare const PORTABLE_RUNTIME_EXPORTS: readonly ["THREE", "RuntimeEngine", "SceneManager", "LoadSceneMode", "convertObjToComponentJson"];
450
+ type PortableRuntimeExport = (typeof PORTABLE_RUNTIME_EXPORTS)[number];
451
+ type TwinAppEngine = {
452
+ container: HTMLElement;
453
+ time: {
454
+ deltaTime: number;
455
+ elapsedTime: number;
456
+ };
457
+ mainScene?: TwinAppRuntimeScene | null;
458
+ getManager(ctor: unknown): TwinAppSceneManager | null;
459
+ destroy(): void;
460
+ };
461
+ type TwinAppRuntimeScene = {
462
+ sceneObject?: {
463
+ add(object: unknown): void;
464
+ remove(object: unknown): void;
465
+ } | null;
466
+ camera?: {
467
+ main?: unknown;
468
+ } | null;
469
+ };
470
+ type TwinAppSceneManager = {
471
+ loadScene(...args: unknown[]): Promise<unknown>;
472
+ };
473
+ type TwinAppContext = {
474
+ app: {
475
+ id: string;
476
+ mode: "preview" | "publish";
477
+ };
478
+ engine: TwinAppEngine;
479
+ container: HTMLElement;
480
+ runtimeScene: TwinAppRuntimeScene | null;
481
+ scene: TwinAppRuntimeScene["sceneObject"] | null;
482
+ camera: unknown | null;
483
+ sceneManager: {
484
+ currentSceneId: string;
485
+ runtime: TwinAppSceneManager | null;
486
+ loadScene(sceneId: string): Promise<void>;
487
+ };
488
+ logger: {
489
+ log(...args: unknown[]): void;
490
+ info(...args: unknown[]): void;
491
+ warn(...args: unknown[]): void;
492
+ error(...args: unknown[]): void;
493
+ };
494
+ assets: {
495
+ text(path: string): Promise<string>;
496
+ json<T = unknown>(path: string): Promise<T>;
497
+ };
498
+ cleanup(fn: () => void | Promise<void>): void;
499
+ sceneCleanup(fn: () => void | Promise<void>): void;
500
+ };
501
+ declare abstract class TwinApp {
502
+ init?(ctx: TwinAppContext): void | Promise<void>;
503
+ onUpdate?(ctx: TwinAppContext, delta: number, elapsed: number): void;
504
+ onBeforeSceneUnload?(ctx: TwinAppContext): void | Promise<void>;
505
+ onSceneLoaded?(ctx: TwinAppContext): void | Promise<void>;
506
+ onDispose?(ctx: TwinAppContext): void | Promise<void>;
507
+ onError?(ctx: TwinAppContext, error: unknown): boolean | void;
508
+ }
509
+ declare function defineApp<T>(app: T): T;
510
+ /** 把用户模块 default 导出收成 TwinApp 实例。函数式 `main` 不认。 */
511
+ declare function createAppInstance(appExport: unknown): TwinApp;
512
+ declare function portableRuntimeWarning(names: Iterable<string>): string | undefined;
513
+
514
+ /**
515
+ * 把 ctx.assets 的相对路径落到工作区磁盘。规范化后必须仍在 cwd 内。
516
+ */
517
+ declare function resolveWorkspaceAssetPath(cwd: string, relPath: string): string;
518
+
519
+ declare const LOCAL_LOAD_SCENE_ERROR = "\u672C\u5730\u9884\u89C8\u5355\u573A\u666F,\u4E0D\u80FD\u8C03\u7528 sceneManager.loadScene";
520
+ declare const MISSING_TICK_ERROR = "\u5F53\u524D runtime \u4E0D\u652F\u6301\u5F15\u64CE\u65F6\u949F(\u7F3A\u5C11 registerEngineTickListener)\u3002\u65E0\u6CD5\u8FD0\u884C onUpdate\u3002";
521
+ type TwinAppTickListener = (engine: TwinAppEngine) => void;
522
+ type TwinAppRuntimeModule = {
523
+ RuntimeEngine: {
524
+ create(config: Record<string, unknown>): Promise<TwinAppEngine>;
525
+ };
526
+ SceneManager: unknown;
527
+ LoadSceneMode: {
528
+ Single: unknown;
529
+ };
530
+ RuntimeSceneMode: {
531
+ Publish: unknown;
532
+ };
533
+ registerEngineTickListener?: (engine: TwinAppEngine, listener: TwinAppTickListener) => void;
534
+ unregisterEngineTickListener?: (engine: TwinAppEngine, listener: TwinAppTickListener) => void;
535
+ };
536
+ type TwinAppPreviewHostOptions = {
537
+ runtime: TwinAppRuntimeModule;
538
+ containerId: string;
539
+ ossUrl: string;
540
+ appId: string;
541
+ sceneId: string;
542
+ sceneJson: unknown;
543
+ customComponentDeps: Record<string, unknown>;
544
+ loadScene(engine: TwinAppEngine, sceneJson: unknown): Promise<void>;
545
+ readAsset(path: string): Promise<string>;
546
+ importUserModule?(code: string): Promise<{
547
+ default: unknown;
548
+ }>;
549
+ log?: (line: string) => void;
550
+ };
551
+ declare class TwinAppPreviewHost {
552
+ private readonly options;
553
+ private app;
554
+ private engine;
555
+ private disposed;
556
+ /** 用户应用已经成功 onSceneLoaded。 */
557
+ private scenePresented;
558
+ private tickAttached;
559
+ private sceneLoadTask;
560
+ private ctx;
561
+ private cleanups;
562
+ private sceneCleanups;
563
+ private warnedAsyncUpdate;
564
+ private userBlobUrl;
565
+ private currentSceneId;
566
+ private readonly onEngineTick;
567
+ constructor(options: TwinAppPreviewHostOptions);
568
+ getEngine(): TwinAppEngine | null;
569
+ boot(): Promise<void>;
570
+ run(code: string): Promise<void>;
571
+ dispose(): Promise<void>;
572
+ private assertTickApi;
573
+ private importUser;
574
+ private loadCurrentScene;
575
+ private handleTick;
576
+ private handleUpdateError;
577
+ private failRun;
578
+ private attachTick;
579
+ private detachTick;
580
+ private teardownApp;
581
+ private unloadUserScene;
582
+ private runHooks;
583
+ private getContext;
584
+ }
585
+
586
+ export { APPS_DTS, APPS_MODULE, APPS_TYPES_FILE, AUTH_HEADER, BundleError, type BundleResult, type BundleUserCodeOptions, CODEX_MARKER_BEGIN, CODEX_MARKER_END, CONFIG_FILE_NAME, type CollectedFile, ConfigError, type ConfigScene, DEFAULT_BASE_URL, DEFAULT_BUNDLE_OUT, DEFAULT_ENTRY_PATH, DEFAULT_MAIN_TS, DEFAULT_OSS_URL, EASYTWIN_TYPES_DIR, ENDPOINTS, EXAMPLE_SCENE_FILE, EasyTwinApiError, EasyTwinClient, type EasyTwinConfig, type EasyTwinEnv, GITIGNORE_ENTRY, GITIGNORE_FILE_NAME, type GitignoreResult, type InitResult, LOCAL_LOAD_SCENE_ERROR, type LinkedScene, META_FILE_NAME, MINIMAL_TSCONFIG, MISSING_TICK_ERROR, MOCK_APP_ID, MOCK_APP_SECRET, MOCK_SCENE_NAME, OP_ACCOUNT_ID_HEADER, OP_USER_ID_HEADER, PORTABLE_RUNTIME_EXPORTS, type PortableRuntimeExport, RUNTIME_MODULE, type RequestOptions, type ResolvedConfig, SKILL_NAMES, SPACE_ID_HEADER, type SceneDetail, type SceneSummary, type SceneTreeNode, type SkillsStatus, type SkillsTargetStatus, type SyncAction, type SyncEntrySummary, type SyncOptions, type SyncSkillsResult, type SyncSummary, type SyncTarget, type SyncTargetArg, TEST_BASE_URL, TEST_OP_ACCOUNT_ID, TEST_OP_USER_ID, TEST_SPACE_ID, TSCONFIG_PATHS_HINT, TwinApp, type TwinAppContext, type TwinAppEngine, TwinAppPreviewHost, type TwinAppPreviewHostOptions, type TwinAppRuntimeModule, type TwinAppRuntimeScene, type TwinAppSceneManager, type TwinAppTickListener, type TypesSyncSummary, USER_ENTRY, type UploadOptions, type UploadProgress, type UploadResult, type WorkspaceChangeKind, type WorkspaceCodeConfig, type WorkspaceCodeFile, type WorkspaceFileChange, type WorkspacePullApplyResult, type WorkspacePullOptions, type WorkspacePullPlan, type WorkspacePullResult, appendGitignore, applyWorkspacePull, assertUploadable, buildMultipartBody, buildRuntimeTypesContent, bundleUserCode, collectFiles, configFilePath, createAppInstance, defaultPullIgnore, defineApp, deriveExampleSceneId, detectSkillsStatus, directoryDepth, exampleSceneSummary, extractInlineSourceMap, extractSceneArray, formatWorkspacePullPlan, formatWorkspacePullResult, initConfig, isMockCredentials, isSafeRelPath, listScenes, loadConfig, loadExampleScene, normalizeLinkedScenes, normalizePath, normalizeSceneList, normalizeTargets, normalizeWorkspaceConfig, normalizeWorkspaceFiles, parseConfig, parseSceneStructure, planWorkspacePull, portableRuntimeWarning, pullScene, pullWorkspace, readConfigFile, readDevkitVersion, remapErrorStack, resolveConfig, resolveExampleScenePath, resolveRuntimeTypesSourceFile, resolveSkillsSourceDir, resolveSnapshotUrl, resolveWorkspaceAssetPath, saveSceneJson, syncSkills, toConfigScenes, typesMissingHint, uploadDirectory, validateConfigShape, workspacePullHasConflicts, workspacePullPendingWrites, writeConfigFile, writeConfigScenes };