@dreamerbird/camera-studio 0.2.0 → 0.3.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.
Files changed (126) hide show
  1. package/dist/CameraScene.d.ts +1 -1
  2. package/dist/CameraScene.d.ts.map +1 -1
  3. package/dist/CameraScene.js +36 -6
  4. package/dist/PlacementManager.d.ts +15 -1
  5. package/dist/PlacementManager.d.ts.map +1 -1
  6. package/dist/PlacementManager.js +123 -14
  7. package/dist/agent/api.d.ts +5 -0
  8. package/dist/agent/api.d.ts.map +1 -1
  9. package/dist/agent/api.js +25 -0
  10. package/dist/agent/api.test.js +75 -1
  11. package/dist/agent/commands/assets.d.ts +5 -0
  12. package/dist/agent/commands/assets.d.ts.map +1 -1
  13. package/dist/agent/commands/assets.js +93 -21
  14. package/dist/agent/commands/assets.test.js +53 -0
  15. package/dist/agent/commands/materials.d.ts +18 -0
  16. package/dist/agent/commands/materials.d.ts.map +1 -0
  17. package/dist/agent/commands/materials.js +192 -0
  18. package/dist/agent/commands/materials.test.d.ts +2 -0
  19. package/dist/agent/commands/materials.test.d.ts.map +1 -0
  20. package/dist/agent/commands/materials.test.js +294 -0
  21. package/dist/agent/commands/modelRecovery.test.d.ts +2 -0
  22. package/dist/agent/commands/modelRecovery.test.d.ts.map +1 -0
  23. package/dist/agent/commands/modelRecovery.test.js +122 -0
  24. package/dist/agent/commands/models.d.ts +13 -0
  25. package/dist/agent/commands/models.d.ts.map +1 -1
  26. package/dist/agent/commands/models.js +98 -1
  27. package/dist/agent/commands/primitives.d.ts +27 -0
  28. package/dist/agent/commands/primitives.d.ts.map +1 -0
  29. package/dist/agent/commands/primitives.js +117 -0
  30. package/dist/agent/commands/primitives.test.d.ts +2 -0
  31. package/dist/agent/commands/primitives.test.d.ts.map +1 -0
  32. package/dist/agent/commands/primitives.test.js +135 -0
  33. package/dist/agent/expectedCommands.d.ts +1 -1
  34. package/dist/agent/expectedCommands.d.ts.map +1 -1
  35. package/dist/agent/expectedCommands.js +6 -0
  36. package/dist/agent/propAccess.d.ts +2 -0
  37. package/dist/agent/propAccess.d.ts.map +1 -1
  38. package/dist/agent/propAccess.js +21 -0
  39. package/dist/agent/registerCommands.d.ts.map +1 -1
  40. package/dist/agent/registerCommands.js +5 -1
  41. package/dist/agent/runtime/objectRuntime.d.ts +2 -0
  42. package/dist/agent/runtime/objectRuntime.d.ts.map +1 -1
  43. package/dist/agent/runtime/objectRuntime.js +15 -1
  44. package/dist/agent/runtime.d.ts +1 -0
  45. package/dist/agent/runtime.d.ts.map +1 -1
  46. package/dist/agent/runtime.js +2 -0
  47. package/dist/assetLibrary/dispose.d.ts +4 -2
  48. package/dist/assetLibrary/dispose.d.ts.map +1 -1
  49. package/dist/assetLibrary/dispose.js +7 -5
  50. package/dist/assetLibrary/gltfLoader.d.ts +2 -1
  51. package/dist/assetLibrary/gltfLoader.d.ts.map +1 -1
  52. package/dist/assetLibrary/gltfLoader.js +2 -2
  53. package/dist/assetLibrary/gltfResourceSet.d.ts +6 -0
  54. package/dist/assetLibrary/gltfResourceSet.d.ts.map +1 -0
  55. package/dist/assetLibrary/gltfResourceSet.js +27 -0
  56. package/dist/assetLibrary/gltfResourceSet.test.d.ts +2 -0
  57. package/dist/assetLibrary/gltfResourceSet.test.d.ts.map +1 -0
  58. package/dist/assetLibrary/gltfResourceSet.test.js +40 -0
  59. package/dist/assetLibrary/importModelFile.d.ts +5 -0
  60. package/dist/assetLibrary/importModelFile.d.ts.map +1 -1
  61. package/dist/assetLibrary/importModelFile.js +3 -16
  62. package/dist/assetLibrary/importModelFiles.d.ts +15 -0
  63. package/dist/assetLibrary/importModelFiles.d.ts.map +1 -0
  64. package/dist/assetLibrary/importModelFiles.js +58 -0
  65. package/dist/assetLibrary/importModelFiles.test.d.ts +2 -0
  66. package/dist/assetLibrary/importModelFiles.test.d.ts.map +1 -0
  67. package/dist/assetLibrary/importModelFiles.test.js +217 -0
  68. package/dist/assetLibrary/importPipeline.d.ts +15 -1
  69. package/dist/assetLibrary/importPipeline.d.ts.map +1 -1
  70. package/dist/assetLibrary/importPipeline.js +74 -38
  71. package/dist/assetLibrary/importPipeline.test.js +25 -0
  72. package/dist/assetLibrary/library.d.ts +1 -0
  73. package/dist/assetLibrary/library.d.ts.map +1 -1
  74. package/dist/assetLibrary/library.js +22 -1
  75. package/dist/assetLibrary/library.test.js +76 -0
  76. package/dist/bootstrap.d.ts +2 -1
  77. package/dist/bootstrap.d.ts.map +1 -1
  78. package/dist/bootstrap.js +69 -7
  79. package/dist/bootstrap.test.js +111 -0
  80. package/dist/config.d.ts +10 -1
  81. package/dist/config.d.ts.map +1 -1
  82. package/dist/hostFlows.d.ts +1 -0
  83. package/dist/hostFlows.d.ts.map +1 -1
  84. package/dist/hostFlows.js +9 -0
  85. package/dist/index.d.ts +10 -1
  86. package/dist/index.d.ts.map +1 -1
  87. package/dist/index.js +6 -1
  88. package/dist/materials/modelMaterials.d.ts +19 -0
  89. package/dist/materials/modelMaterials.d.ts.map +1 -0
  90. package/dist/materials/modelMaterials.js +253 -0
  91. package/dist/materials/modelMaterials.test.d.ts +2 -0
  92. package/dist/materials/modelMaterials.test.d.ts.map +1 -0
  93. package/dist/materials/modelMaterials.test.js +188 -0
  94. package/dist/materials/types.d.ts +20 -0
  95. package/dist/materials/types.d.ts.map +1 -0
  96. package/dist/materials/types.js +1 -0
  97. package/dist/materials/useModelMaterials.d.ts +10 -0
  98. package/dist/materials/useModelMaterials.d.ts.map +1 -0
  99. package/dist/materials/useModelMaterials.js +26 -0
  100. package/dist/materials/useModelMaterials.test.d.ts +2 -0
  101. package/dist/materials/useModelMaterials.test.d.ts.map +1 -0
  102. package/dist/materials/useModelMaterials.test.js +75 -0
  103. package/dist/poses.d.ts +38 -0
  104. package/dist/poses.d.ts.map +1 -0
  105. package/dist/poses.js +41 -0
  106. package/dist/poses.test.d.ts +2 -0
  107. package/dist/poses.test.d.ts.map +1 -0
  108. package/dist/poses.test.js +38 -0
  109. package/dist/primitives.d.ts +5 -0
  110. package/dist/primitives.d.ts.map +1 -0
  111. package/dist/primitives.js +15 -0
  112. package/dist/primitives.test.d.ts +2 -0
  113. package/dist/primitives.test.d.ts.map +1 -0
  114. package/dist/primitives.test.js +27 -0
  115. package/dist/reset.realStudio.test.d.ts +2 -0
  116. package/dist/reset.realStudio.test.d.ts.map +1 -0
  117. package/dist/reset.realStudio.test.js +60 -0
  118. package/dist/studioRoot.d.ts +4 -0
  119. package/dist/studioRoot.d.ts.map +1 -0
  120. package/dist/studioRoot.js +36 -0
  121. package/dist/studioRoot.test.d.ts +2 -0
  122. package/dist/studioRoot.test.d.ts.map +1 -0
  123. package/dist/studioRoot.test.js +62 -0
  124. package/dist/useCameraStudio.d.ts.map +1 -1
  125. package/dist/useCameraStudio.js +3 -2
  126. package/package.json +9 -1
@@ -1,19 +1,6 @@
1
- /**
2
- * 宿主外部模型入库:File → 既有导入管线(planImport/executeImport)。
3
- * 放置管线只认库条目(按 id 解析 blob),外部模型必须真实入库,
4
- * 姿势/骨架匹配/持久化全部照常。library/deps 可注入(测试用)。
5
- */
6
- import { planImport, executeImport, realImportDeps } from './importPipeline';
1
+ import { importModelFiles } from './importModelFiles';
7
2
  import { getLibrary } from './library';
8
- export async function importModelFile(file, library = getLibrary(), deps = realImportDeps()) {
9
- const before = new Set((await library.listEntries('model')).map((e) => e.id));
10
- const plan = await planImport([file], library, deps);
11
- // 宿主场景无"相似条目"交互,一律保留为新条目
12
- await executeImport(plan, plan.similar.map(() => 'keep'), library);
13
- const models = await library.listEntries('model');
14
- const created = models.find((m) => !before.has(m.id));
15
- if (!created || created.kind !== 'model') {
16
- throw new Error('[hostFlows] 模型导入失败:未找到新建条目');
17
- }
3
+ export async function importModelFile(file, library = getLibrary(), deps) {
4
+ const [created] = await importModelFiles([file], library, deps);
18
5
  return created;
19
6
  }
@@ -0,0 +1,15 @@
1
+ import { type ImportDeps } from './importPipeline';
2
+ import { type Library } from './library';
3
+ import type { ModelEntry } from './types';
4
+ export type ImportFileFailure = {
5
+ file: string;
6
+ message: string;
7
+ };
8
+ export declare class ImportModelFilesError extends Error {
9
+ readonly entries: ModelEntry[];
10
+ readonly failedItems: ImportFileFailure[];
11
+ readonly cause: unknown;
12
+ constructor(entries: ModelEntry[], failedItems: ImportFileFailure[], cause: unknown);
13
+ }
14
+ export declare function importModelFiles(files: File[], library?: Library, deps?: ImportDeps): Promise<ModelEntry[]>;
15
+ //# sourceMappingURL=importModelFiles.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"importModelFiles.d.ts","sourceRoot":"","sources":["../../src/assetLibrary/importModelFiles.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,UAAU,EAEhB,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAAa,KAAK,OAAO,EAAC,MAAM,WAAW,CAAA;AAClD,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,SAAS,CAAA;AAEvC,MAAM,MAAM,iBAAiB,GAAG;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAC,CAAA;AAE/D,qBAAa,qBAAsB,SAAQ,KAAK;IAE5C,QAAQ,CAAC,OAAO,EAAE,UAAU,EAAE;IAC9B,QAAQ,CAAC,WAAW,EAAE,iBAAiB,EAAE;IACzC,QAAQ,CAAC,KAAK,EAAE,OAAO;gBAFd,OAAO,EAAE,UAAU,EAAE,EACrB,WAAW,EAAE,iBAAiB,EAAE,EAChC,KAAK,EAAE,OAAO;CAS1B;AASD,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,IAAI,EAAE,EACb,OAAO,GAAE,OAAsB,EAC/B,IAAI,CAAC,EAAE,UAAU,GAChB,OAAO,CAAC,UAAU,EAAE,CAAC,CAkDvB"}
@@ -0,0 +1,58 @@
1
+ import { executeImport, ImportItemWriteError, planImport, realImportDeps, } from './importPipeline';
2
+ import { getLibrary } from './library';
3
+ export class ImportModelFilesError extends Error {
4
+ constructor(entries, failedItems, cause) {
5
+ super(`模型导入部分失败: ${failedItems
6
+ .map((item) => `${item.file}: ${item.message}`)
7
+ .join('; ')}`);
8
+ this.entries = entries;
9
+ this.failedItems = failedItems;
10
+ this.cause = cause;
11
+ this.name = 'ImportModelFilesError';
12
+ }
13
+ }
14
+ function failureOf(item) {
15
+ return {
16
+ file: item.sourceFile ?? item.name,
17
+ message: item.type === 'skip' ? item.reason : '写入失败',
18
+ };
19
+ }
20
+ export async function importModelFiles(files, library = getLibrary(), deps) {
21
+ const before = new Set((await library.listEntries('model')).map((e) => e.id));
22
+ const modelFiles = files.filter((file) => /\.(glb|gltf|fbx)$/i.test(file.name));
23
+ const plan = await planImport(modelFiles, library, deps ?? realImportDeps(files));
24
+ const failedItems = plan.items
25
+ .filter((item) => item.type === 'skip' && !item.duplicate)
26
+ .map(failureOf);
27
+ let executeError;
28
+ try {
29
+ await executeImport(plan, plan.similar.map(() => 'keep'), library);
30
+ }
31
+ catch (error) {
32
+ executeError = error;
33
+ if (error instanceof ImportItemWriteError) {
34
+ const cause = error.cause;
35
+ failedItems.push({
36
+ ...failureOf(error.item),
37
+ message: cause instanceof Error ? cause.message : String(cause),
38
+ });
39
+ }
40
+ else {
41
+ failedItems.push({
42
+ file: 'unknown',
43
+ message: error instanceof Error ? error.message : String(error),
44
+ });
45
+ }
46
+ }
47
+ const entries = (await library.listEntries('model')).filter((entry) => entry.kind === 'model' && !before.has(entry.id));
48
+ if (executeError || failedItems.length > 0) {
49
+ const cause = executeError instanceof ImportItemWriteError
50
+ ? executeError.cause
51
+ : executeError;
52
+ throw new ImportModelFilesError(entries, failedItems, cause);
53
+ }
54
+ if (entries.length === 0) {
55
+ throw new Error('[hostFlows] 模型导入失败:未找到新建条目');
56
+ }
57
+ return entries;
58
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=importModelFiles.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"importModelFiles.test.d.ts","sourceRoot":"","sources":["../../src/assetLibrary/importModelFiles.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,217 @@
1
+ import { BoxGeometry, Group, Mesh, MeshBasicMaterial } from 'three';
2
+ import { importModelFiles } from './importModelFiles';
3
+ import { Library } from './library';
4
+ const tinyPng = Buffer.from('iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII=', 'base64');
5
+ function triangleGltf() {
6
+ const document = {
7
+ asset: { version: '2.0' },
8
+ scene: 0,
9
+ scenes: [{ nodes: [0] }],
10
+ nodes: [{ mesh: 0 }],
11
+ meshes: [
12
+ {
13
+ primitives: [{ attributes: { POSITION: 0 }, material: 0, mode: 4 }],
14
+ },
15
+ ],
16
+ materials: [
17
+ {
18
+ pbrMetallicRoughness: {
19
+ baseColorTexture: { index: 0 },
20
+ metallicFactor: 0,
21
+ roughnessFactor: 1,
22
+ },
23
+ },
24
+ ],
25
+ textures: [{ source: 0 }],
26
+ images: [{ uri: 'textures/tiny.png' }],
27
+ buffers: [{ uri: 'geometry/triangle.bin', byteLength: 36 }],
28
+ bufferViews: [{ buffer: 0, byteOffset: 0, byteLength: 36 }],
29
+ accessors: [
30
+ {
31
+ bufferView: 0,
32
+ componentType: 5126,
33
+ count: 3,
34
+ type: 'VEC3',
35
+ min: [0, 0, 0],
36
+ max: [1, 1, 0],
37
+ },
38
+ ],
39
+ };
40
+ return new File([JSON.stringify(document)], 'triangle.gltf', {
41
+ type: 'model/gltf+json',
42
+ });
43
+ }
44
+ function triangleBin() {
45
+ const bytes = new ArrayBuffer(36);
46
+ const positions = new Float32Array(bytes);
47
+ positions.set([0, 0, 0, 1, 0, 0, 0, 1, 0]);
48
+ return new File([bytes], 'triangle.bin', {
49
+ type: 'application/octet-stream',
50
+ });
51
+ }
52
+ function tinyPngFile() {
53
+ return new File([tinyPng], 'tiny.png', { type: 'image/png' });
54
+ }
55
+ function memoryBackend() {
56
+ const entries = new Map();
57
+ const blobs = new Map();
58
+ const backend = {
59
+ id: 'mock',
60
+ listEntries: async (kind) => [...entries.values()].filter((entry) => !kind || entry.kind === kind),
61
+ getEntry: async (id) => entries.get(id),
62
+ putEntry: async (entry) => void entries.set(entry.id, entry),
63
+ deleteEntry: async (id) => void entries.delete(id),
64
+ putBlob: async (blob) => {
65
+ const id = `blob-${blobs.size}`;
66
+ blobs.set(id, blob);
67
+ return id;
68
+ },
69
+ getBlobUrl: async () => 'blob:stored',
70
+ deleteBlob: async (id) => void blobs.delete(id),
71
+ listBlobIds: async () => [...blobs.keys()],
72
+ getRigAliases: async () => [],
73
+ putRigAlias: async () => { },
74
+ };
75
+ return { backend, entries, blobs };
76
+ }
77
+ function modelDeps(names) {
78
+ return {
79
+ load: async (file) => {
80
+ if (!names.includes(file.name))
81
+ throw new Error('无法解析');
82
+ const root = new Group();
83
+ root.name = file.name;
84
+ root.add(new Mesh(new BoxGeometry(), new MeshBasicMaterial()));
85
+ return { root, animations: [] };
86
+ },
87
+ exportModel: async (root) => new TextEncoder().encode(root.name).buffer,
88
+ exportAnimation: async () => new TextEncoder().encode('anim').buffer,
89
+ };
90
+ }
91
+ function gltfJsonChunk(glb) {
92
+ const view = new DataView(glb);
93
+ const jsonLength = view.getUint32(12, true);
94
+ expect(view.getUint32(16, true)).toBe(0x4e4f534a);
95
+ return JSON.parse(new TextDecoder().decode(new Uint8Array(glb, 20, jsonLength)));
96
+ }
97
+ describe('importModelFiles', () => {
98
+ const originalFetch = globalThis.fetch;
99
+ const originalSelf = globalThis.self;
100
+ const originalCreateImageBitmap = globalThis.createImageBitmap;
101
+ const originalImageData = globalThis.ImageData;
102
+ const originalCreateObjectURL = URL.createObjectURL;
103
+ const originalRevokeObjectURL = URL.revokeObjectURL;
104
+ const originalCreateElement = document.createElement;
105
+ let objectUrls;
106
+ beforeEach(() => {
107
+ globalThis.self = globalThis;
108
+ let nextId = 0;
109
+ objectUrls = new Map();
110
+ URL.createObjectURL = jest.fn((blob) => {
111
+ const url = `blob:test-${++nextId}`;
112
+ objectUrls.set(url, blob);
113
+ return url;
114
+ });
115
+ URL.revokeObjectURL = jest.fn((url) => {
116
+ objectUrls.delete(url);
117
+ });
118
+ globalThis.fetch = jest.fn(async (input) => {
119
+ const url = typeof input === 'string' || input instanceof URL
120
+ ? String(input)
121
+ : input.url;
122
+ const blob = objectUrls.get(url);
123
+ if (!blob)
124
+ throw new Error(`未登记的测试 URL: ${url}`);
125
+ return {
126
+ ok: true,
127
+ status: 200,
128
+ statusText: 'OK',
129
+ url,
130
+ headers: { get: () => null },
131
+ arrayBuffer: () => blob.arrayBuffer(),
132
+ blob: async () => blob,
133
+ };
134
+ });
135
+ globalThis.createImageBitmap = jest.fn(async () => ({
136
+ data: new Uint8ClampedArray([255, 255, 255, 255]),
137
+ width: 1,
138
+ height: 1,
139
+ close: jest.fn(),
140
+ }));
141
+ globalThis.ImageData = class {
142
+ constructor(data, width, height) {
143
+ this.data = data;
144
+ this.width = width;
145
+ this.height = height;
146
+ }
147
+ };
148
+ document.createElement = jest.fn(() => ({
149
+ width: 0,
150
+ height: 0,
151
+ getContext: () => ({
152
+ translate: jest.fn(),
153
+ scale: jest.fn(),
154
+ drawImage: jest.fn(),
155
+ putImageData: jest.fn(),
156
+ }),
157
+ toBlob: (callback) => callback(new Blob([tinyPng], { type: 'image/png' })),
158
+ }));
159
+ });
160
+ afterEach(() => {
161
+ globalThis.fetch = originalFetch;
162
+ globalThis.self = originalSelf;
163
+ globalThis.createImageBitmap = originalCreateImageBitmap;
164
+ globalThis.ImageData = originalImageData;
165
+ URL.createObjectURL = originalCreateObjectURL;
166
+ URL.revokeObjectURL = originalRevokeObjectURL;
167
+ if (originalCreateElement)
168
+ document.createElement = originalCreateElement;
169
+ else
170
+ Reflect.deleteProperty(document, 'createElement');
171
+ });
172
+ it('把相对 buffer/image 一起装入一个自包含 GLB,并回收全部临时 URL', async () => {
173
+ const { backend, entries, blobs } = memoryBackend();
174
+ const library = new Library({ sources: [backend] });
175
+ const imported = await importModelFiles([triangleGltf(), triangleBin(), tinyPngFile()], library);
176
+ expect(imported).toHaveLength(1);
177
+ expect(imported[0]).toMatchObject({
178
+ kind: 'model',
179
+ name: 'triangle',
180
+ vertexCount: 3,
181
+ });
182
+ expect(entries.size).toBe(1);
183
+ const glb = await blobs.get(imported[0].blobId).arrayBuffer();
184
+ expect(new DataView(glb).getUint32(0, true)).toBe(0x46546c67);
185
+ const json = gltfJsonChunk(glb);
186
+ expect(json.buffers[0].uri).toBeUndefined();
187
+ expect(json.images[0].uri).toBeUndefined();
188
+ expect(json.images[0].bufferView).toEqual(expect.any(Number));
189
+ expect(URL.createObjectURL).toHaveBeenCalledTimes(2);
190
+ expect(URL.revokeObjectURL).toHaveBeenCalledTimes(2);
191
+ expect(objectUrls.size).toBe(0);
192
+ });
193
+ it('引用的 bin 缺失时不创建任何新条目,并回收已创建的 URL', async () => {
194
+ const { backend, entries } = memoryBackend();
195
+ const library = new Library({ sources: [backend] });
196
+ await expect(importModelFiles([triangleGltf(), tinyPngFile()], library)).rejects.toThrow();
197
+ expect(entries.size).toBe(0);
198
+ expect(objectUrls.size).toBe(0);
199
+ expect(URL.revokeObjectURL).toHaveBeenCalledWith(expect.stringMatching(/^blob:test-/));
200
+ });
201
+ it('多个模型根全部成功时按原数组契约返回全部新条目', async () => {
202
+ const { backend } = memoryBackend();
203
+ const library = new Library({ sources: [backend] });
204
+ const imported = await importModelFiles([new File(['a'], 'a.gltf'), new File(['b'], 'b.gltf')], library, modelDeps(['a.gltf', 'b.gltf']));
205
+ expect(imported.map((entry) => entry.name)).toEqual(['a', 'b']);
206
+ expect(await library.listEntries('model')).toHaveLength(2);
207
+ });
208
+ it('混合成功时保留成功条目并报告失败文件及原因', async () => {
209
+ const { backend } = memoryBackend();
210
+ const library = new Library({ sources: [backend] });
211
+ await expect(importModelFiles([new File(['a'], 'a.gltf'), new File(['x'], 'broken.gltf')], library, modelDeps(['a.gltf']))).rejects.toMatchObject({
212
+ entries: [expect.objectContaining({ kind: 'model', name: 'a' })],
213
+ failedItems: [{ file: 'broken.gltf', message: expect.any(String) }],
214
+ });
215
+ expect((await library.listEntries('model')).map((entry) => entry.name)).toEqual(['a']);
216
+ });
217
+ });
@@ -12,10 +12,11 @@ export type ImportDeps = {
12
12
  exportModel: (root: Object3D) => Promise<ArrayBuffer>;
13
13
  exportAnimation: (root: Object3D, clip: AnimationClip) => Promise<ArrayBuffer>;
14
14
  };
15
- export declare const realImportDeps: () => ImportDeps;
15
+ export declare const realImportDeps: (files?: File[]) => ImportDeps;
16
16
  export type ImportItem = {
17
17
  type: 'model';
18
18
  name: string;
19
+ sourceFile?: string;
19
20
  rig: string;
20
21
  contentHash: string;
21
22
  boneCount: number;
@@ -24,6 +25,7 @@ export type ImportItem = {
24
25
  } | {
25
26
  type: 'animation';
26
27
  name: string;
28
+ sourceFile?: string;
27
29
  rig: string;
28
30
  contentHash: string;
29
31
  duration: number;
@@ -31,12 +33,15 @@ export type ImportItem = {
31
33
  } | {
32
34
  type: 'pose';
33
35
  name: string;
36
+ sourceFile?: string;
34
37
  rig: string;
35
38
  bones: PoseEntry['bones'];
36
39
  } | {
37
40
  type: 'skip';
38
41
  name: string;
42
+ sourceFile?: string;
39
43
  reason: string;
44
+ duplicate?: boolean;
40
45
  };
41
46
  /** 哈希不同但同族同结构的模型,入库前要用户选 reuse/keep */
42
47
  export type SimilarMatch = {
@@ -56,6 +61,15 @@ export declare function baseName(fileName: string): string;
56
61
  * 第二层:哈希不同但同族 + 顶点/骨骼数相同 → 记入 similar 交给用户。
57
62
  */
58
63
  export declare function planImport(files: File[], library: Pick<Library, 'listEntries'>, deps: ImportDeps, tr?: TFunction): Promise<ImportPlan>;
64
+ export declare class ImportItemWriteError extends Error {
65
+ readonly item: Exclude<ImportItem, {
66
+ type: 'skip';
67
+ }>;
68
+ readonly cause: unknown;
69
+ constructor(item: Exclude<ImportItem, {
70
+ type: 'skip';
71
+ }>, cause: unknown);
72
+ }
59
73
  /** 落库:choices 与 plan.similar 一一对应,'reuse' 丢弃对应 model 项 */
60
74
  export declare function executeImport(plan: ImportPlan, choices: Array<'reuse' | 'keep'>, library: Library): Promise<void>;
61
75
  //# sourceMappingURL=importPipeline.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"importPipeline.d.ts","sourceRoot":"","sources":["../../src/assetLibrary/importPipeline.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,aAAa,EAAE,KAAK,EAAE,QAAQ,EAAC,MAAM,OAAO,CAAA;AACzD,OAAO,EAAY,KAAK,SAAS,EAAC,MAAM,0BAA0B,CAAA;AAKlE,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,WAAW,CAAA;AAEtC,OAAO,KAAK,EAA6B,SAAS,EAAC,MAAM,SAAS,CAAA;AAElE,MAAM,MAAM,WAAW,GAAG;IAAC,IAAI,EAAE,KAAK,CAAC;IAAC,UAAU,EAAE,aAAa,EAAE,CAAA;CAAC,CAAA;AAEpE,+DAA+D;AAC/D,MAAM,MAAM,UAAU,GAAG;IACvB,IAAI,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,WAAW,CAAC,CAAA;IAC1C,WAAW,EAAE,CAAC,IAAI,EAAE,QAAQ,KAAK,OAAO,CAAC,WAAW,CAAC,CAAA;IACrD,eAAe,EAAE,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,aAAa,KAAK,OAAO,CAAC,WAAW,CAAC,CAAA;CAC/E,CAAA;AAED,eAAO,MAAM,cAAc,EAAE,MAAM,UAIjC,CAAA;AAmCF,MAAM,MAAM,UAAU,GAClB;IACE,IAAI,EAAE,OAAO,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,GAAG,EAAE,MAAM,CAAA;IACX,WAAW,EAAE,MAAM,CAAA;IACnB,SAAS,EAAE,MAAM,CAAA;IACjB,WAAW,EAAE,MAAM,CAAA;IACnB,GAAG,EAAE,WAAW,CAAA;CACjB,GACD;IACE,IAAI,EAAE,WAAW,CAAA;IACjB,IAAI,EAAE,MAAM,CAAA;IACZ,GAAG,EAAE,MAAM,CAAA;IACX,WAAW,EAAE,MAAM,CAAA;IACnB,QAAQ,EAAE,MAAM,CAAA;IAChB,GAAG,EAAE,WAAW,CAAA;CACjB,GACD;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,SAAS,CAAC,OAAO,CAAC,CAAA;CAAC,GACpE;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAC,CAAA;AAEhD,uCAAuC;AACvC,MAAM,MAAM,YAAY,GAAG;IACzB,KAAK,EAAE,MAAM,CAAA;IACb,YAAY,EAAE,MAAM,CAAA;IACpB,OAAO,EAAE,MAAM,CAAA;CAChB,CAAA;AAED,MAAM,MAAM,UAAU,GAAG;IACvB,KAAK,EAAE,UAAU,EAAE,CAAA;IACnB,OAAO,EAAE,YAAY,EAAE,CAAA;IACvB,OAAO,EAAE,MAAM,CAAA;CAChB,CAAA;AAED,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEjD;AAuBD;;;;GAIG;AACH,wBAAsB,UAAU,CAC9B,KAAK,EAAE,IAAI,EAAE,EACb,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,aAAa,CAAC,EACrC,IAAI,EAAE,UAAU,EAChB,EAAE,GAAE,SAAqB,GACxB,OAAO,CAAC,UAAU,CAAC,CAsJrB;AAED,0DAA0D;AAC1D,wBAAsB,aAAa,CACjC,IAAI,EAAE,UAAU,EAChB,OAAO,EAAE,KAAK,CAAC,OAAO,GAAG,MAAM,CAAC,EAChC,OAAO,EAAE,OAAO,GACf,OAAO,CAAC,IAAI,CAAC,CAgDf"}
1
+ {"version":3,"file":"importPipeline.d.ts","sourceRoot":"","sources":["../../src/assetLibrary/importPipeline.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,aAAa,EAAE,KAAK,EAAE,QAAQ,EAAC,MAAM,OAAO,CAAA;AACzD,OAAO,EAAY,KAAK,SAAS,EAAC,MAAM,0BAA0B,CAAA;AAMlE,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,WAAW,CAAA;AAEtC,OAAO,KAAK,EAA6B,SAAS,EAAC,MAAM,SAAS,CAAA;AAElE,MAAM,MAAM,WAAW,GAAG;IAAC,IAAI,EAAE,KAAK,CAAC;IAAC,UAAU,EAAE,aAAa,EAAE,CAAA;CAAC,CAAA;AAEpE,+DAA+D;AAC/D,MAAM,MAAM,UAAU,GAAG;IACvB,IAAI,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,WAAW,CAAC,CAAA;IAC1C,WAAW,EAAE,CAAC,IAAI,EAAE,QAAQ,KAAK,OAAO,CAAC,WAAW,CAAC,CAAA;IACrD,eAAe,EAAE,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,aAAa,KAAK,OAAO,CAAC,WAAW,CAAC,CAAA;CAC/E,CAAA;AAED,eAAO,MAAM,cAAc,EAAE,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,KAAK,UAI/C,CAAA;AAkDF,MAAM,MAAM,UAAU,GAClB;IACE,IAAI,EAAE,OAAO,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,GAAG,EAAE,MAAM,CAAA;IACX,WAAW,EAAE,MAAM,CAAA;IACnB,SAAS,EAAE,MAAM,CAAA;IACjB,WAAW,EAAE,MAAM,CAAA;IACnB,GAAG,EAAE,WAAW,CAAA;CACjB,GACD;IACE,IAAI,EAAE,WAAW,CAAA;IACjB,IAAI,EAAE,MAAM,CAAA;IACZ,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,GAAG,EAAE,MAAM,CAAA;IACX,WAAW,EAAE,MAAM,CAAA;IACnB,QAAQ,EAAE,MAAM,CAAA;IAChB,GAAG,EAAE,WAAW,CAAA;CACjB,GACD;IACE,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,SAAS,CAAC,OAAO,CAAC,CAAA;CAC1B,GACD;IACE,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB,CAAA;AAEL,uCAAuC;AACvC,MAAM,MAAM,YAAY,GAAG;IACzB,KAAK,EAAE,MAAM,CAAA;IACb,YAAY,EAAE,MAAM,CAAA;IACpB,OAAO,EAAE,MAAM,CAAA;CAChB,CAAA;AAED,MAAM,MAAM,UAAU,GAAG;IACvB,KAAK,EAAE,UAAU,EAAE,CAAA;IACnB,OAAO,EAAE,YAAY,EAAE,CAAA;IACvB,OAAO,EAAE,MAAM,CAAA;CAChB,CAAA;AAED,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEjD;AAuBD;;;;GAIG;AACH,wBAAsB,UAAU,CAC9B,KAAK,EAAE,IAAI,EAAE,EACb,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,aAAa,CAAC,EACrC,IAAI,EAAE,UAAU,EAChB,EAAE,GAAE,SAAqB,GACxB,OAAO,CAAC,UAAU,CAAC,CAkKrB;AAED,qBAAa,oBAAqB,SAAQ,KAAK;IAE3C,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,UAAU,EAAE;QAAC,IAAI,EAAE,MAAM,CAAA;KAAC,CAAC;IAClD,QAAQ,CAAC,KAAK,EAAE,OAAO;gBADd,IAAI,EAAE,OAAO,CAAC,UAAU,EAAE;QAAC,IAAI,EAAE,MAAM,CAAA;KAAC,CAAC,EACzC,KAAK,EAAE,OAAO;CAS1B;AAED,0DAA0D;AAC1D,wBAAsB,aAAa,CACjC,IAAI,EAAE,UAAU,EAChB,OAAO,EAAE,KAAK,CAAC,OAAO,GAAG,MAAM,CAAC,EAChC,OAAO,EAAE,OAAO,GACf,OAAO,CAAC,IAAI,CAAC,CAoDf"}
@@ -1,17 +1,28 @@
1
1
  import { translate } from '@dreamerbird/studio/i18n';
2
2
  import { classifyModel, validatePoseJson } from './classify';
3
3
  import { createGLTFLoader } from './gltfLoader';
4
+ import { createResourceUrlModifier } from './gltfResourceSet';
4
5
  import { exportAnimationGLB, exportModelGLB } from './exportGLB';
5
6
  import { hashBytes } from './hash';
6
7
  import { collectBoneNames, meshStats, rigIdOf } from './rig';
7
- export const realImportDeps = () => ({
8
- load: defaultLoad,
8
+ export const realImportDeps = (files) => ({
9
+ load: (file) => defaultLoad(file, files),
9
10
  exportModel: exportModelGLB,
10
11
  exportAnimation: exportAnimationGLB,
11
12
  });
12
- async function defaultLoad(file) {
13
+ async function defaultLoad(file, resourceFiles) {
13
14
  const { FBXLoader } = await import('three-stdlib');
14
15
  const { LoadingManager } = await import('three');
16
+ if (resourceFiles && /\.gltf$/i.test(file.name)) {
17
+ const resources = createResourceUrlModifier(resourceFiles);
18
+ try {
19
+ const gltf = await createGLTFLoader(resources.manager).parseAsync(await file.text(), '');
20
+ return { root: gltf.scene, animations: gltf.animations };
21
+ }
22
+ finally {
23
+ resources.dispose();
24
+ }
25
+ }
15
26
  const url = URL.createObjectURL(file);
16
27
  try {
17
28
  if (/\.glb$|\.gltf$/i.test(file.name)) {
@@ -81,6 +92,7 @@ export async function planImport(files, library, deps, tr = translate) {
81
92
  items.push({
82
93
  type: 'skip',
83
94
  name: file.name,
95
+ sourceFile: file.name,
84
96
  reason: tr('pg.import.reason.badPoseJson'),
85
97
  });
86
98
  }
@@ -88,6 +100,7 @@ export async function planImport(files, library, deps, tr = translate) {
88
100
  items.push({
89
101
  type: 'pose',
90
102
  name: baseName(file.name),
103
+ sourceFile: file.name,
91
104
  rig: parsed.rig,
92
105
  bones: parsed.bones,
93
106
  });
@@ -102,6 +115,7 @@ export async function planImport(files, library, deps, tr = translate) {
102
115
  items.push({
103
116
  type: 'skip',
104
117
  name: file.name,
118
+ sourceFile: file.name,
105
119
  reason: tr('pg.import.reason.parseFailed'),
106
120
  });
107
121
  continue;
@@ -111,6 +125,7 @@ export async function planImport(files, library, deps, tr = translate) {
111
125
  items.push({
112
126
  type: 'skip',
113
127
  name: file.name,
128
+ sourceFile: file.name,
114
129
  reason: tr('pg.import.reason.noContent'),
115
130
  });
116
131
  continue;
@@ -128,6 +143,7 @@ export async function planImport(files, library, deps, tr = translate) {
128
143
  items.push({
129
144
  type: 'skip',
130
145
  name: baseName(file.name),
146
+ sourceFile: file.name,
131
147
  reason: tr('pg.import.reason.modelExportFailed'),
132
148
  });
133
149
  }
@@ -140,6 +156,7 @@ export async function planImport(files, library, deps, tr = translate) {
140
156
  const index = items.push({
141
157
  type: 'model',
142
158
  name: baseName(file.name),
159
+ sourceFile: file.name,
143
160
  rig,
144
161
  contentHash,
145
162
  boneCount,
@@ -163,7 +180,9 @@ export async function planImport(files, library, deps, tr = translate) {
163
180
  items.push({
164
181
  type: 'skip',
165
182
  name: baseName(file.name),
183
+ sourceFile: file.name,
166
184
  reason: tr('pg.import.reason.modelExists', { name: dup.name }),
185
+ duplicate: true,
167
186
  });
168
187
  }
169
188
  // dup 命中:模型跳过,下面的动作照常提取
@@ -180,6 +199,7 @@ export async function planImport(files, library, deps, tr = translate) {
180
199
  items.push({
181
200
  type: 'skip',
182
201
  name: `${baseName(file.name)}/${clip.name}`,
202
+ sourceFile: file.name,
183
203
  reason: tr('pg.import.reason.animationExportFailed'),
184
204
  });
185
205
  continue;
@@ -189,13 +209,16 @@ export async function planImport(files, library, deps, tr = translate) {
189
209
  items.push({
190
210
  type: 'skip',
191
211
  name: `${baseName(file.name)}/${clip.name}`,
212
+ sourceFile: file.name,
192
213
  reason: tr('pg.import.reason.animationExists'),
214
+ duplicate: true,
193
215
  });
194
216
  continue;
195
217
  }
196
218
  items.push({
197
219
  type: 'animation',
198
220
  name: clip.name || baseName(file.name),
221
+ sourceFile: file.name,
199
222
  rig,
200
223
  contentHash,
201
224
  duration: clip.duration,
@@ -205,6 +228,14 @@ export async function planImport(files, library, deps, tr = translate) {
205
228
  }
206
229
  return { items, similar, summary: summarize(items, tr) };
207
230
  }
231
+ export class ImportItemWriteError extends Error {
232
+ constructor(item, cause) {
233
+ super(`导入项 ${item.name} 写入失败: ${cause instanceof Error ? cause.message : String(cause)}`);
234
+ this.item = item;
235
+ this.cause = cause;
236
+ this.name = 'ImportItemWriteError';
237
+ }
238
+ }
208
239
  /** 落库:choices 与 plan.similar 一一对应,'reuse' 丢弃对应 model 项 */
209
240
  export async function executeImport(plan, choices, library) {
210
241
  const drop = new Set(plan.similar.filter((_, i) => choices[i] === 'reuse').map((s) => s.index));
@@ -212,42 +243,47 @@ export async function executeImport(plan, choices, library) {
212
243
  const item = plan.items[i];
213
244
  if (item.type === 'skip')
214
245
  continue;
215
- if (item.type === 'model') {
216
- if (drop.has(i))
217
- continue;
218
- await library.putBlobWithEntry(new Blob([item.glb]), (blobId) => ({
219
- id: newId(),
220
- kind: 'model',
221
- name: item.name,
222
- rig: item.rig,
223
- blobId,
224
- contentHash: item.contentHash,
225
- boneCount: item.boneCount,
226
- vertexCount: item.vertexCount,
227
- createdAt: Date.now(),
228
- }));
229
- }
230
- else if (item.type === 'animation') {
231
- await library.putBlobWithEntry(new Blob([item.glb]), (blobId) => ({
232
- id: newId(),
233
- kind: 'animation',
234
- name: item.name,
235
- rig: item.rig,
236
- blobId,
237
- contentHash: item.contentHash,
238
- duration: item.duration,
239
- createdAt: Date.now(),
240
- }));
246
+ try {
247
+ if (item.type === 'model') {
248
+ if (drop.has(i))
249
+ continue;
250
+ await library.putBlobWithEntry(new Blob([item.glb]), (blobId) => ({
251
+ id: newId(),
252
+ kind: 'model',
253
+ name: item.name,
254
+ rig: item.rig,
255
+ blobId,
256
+ contentHash: item.contentHash,
257
+ boneCount: item.boneCount,
258
+ vertexCount: item.vertexCount,
259
+ createdAt: Date.now(),
260
+ }));
261
+ }
262
+ else if (item.type === 'animation') {
263
+ await library.putBlobWithEntry(new Blob([item.glb]), (blobId) => ({
264
+ id: newId(),
265
+ kind: 'animation',
266
+ name: item.name,
267
+ rig: item.rig,
268
+ blobId,
269
+ contentHash: item.contentHash,
270
+ duration: item.duration,
271
+ createdAt: Date.now(),
272
+ }));
273
+ }
274
+ else {
275
+ await library.putEntry({
276
+ id: newId(),
277
+ kind: 'pose',
278
+ name: item.name,
279
+ rig: item.rig,
280
+ bones: item.bones,
281
+ createdAt: Date.now(),
282
+ });
283
+ }
241
284
  }
242
- else {
243
- await library.putEntry({
244
- id: newId(),
245
- kind: 'pose',
246
- name: item.name,
247
- rig: item.rig,
248
- bones: item.bones,
249
- createdAt: Date.now(),
250
- });
285
+ catch (error) {
286
+ throw new ImportItemWriteError(item, error);
251
287
  }
252
288
  }
253
289
  }
@@ -185,4 +185,29 @@ describe('executeImport', () => {
185
185
  await executeImport(plan, ['keep'], lib);
186
186
  expect((await backend.listEntries('model')).length).toBe(1);
187
187
  });
188
+ it('第二个模型写库失败时保留实际失败项与原始错误', async () => {
189
+ const backend = memoryBackend();
190
+ let writes = 0;
191
+ backend.putBlob = async () => {
192
+ writes++;
193
+ if (writes === 2)
194
+ throw new Error('disk full');
195
+ return `blob-${writes}`;
196
+ };
197
+ const lib = new Library({ sources: [backend] });
198
+ const deps = depsFor({
199
+ 'a.fbx': { root: skinnedModel('Hips'), animations: [] },
200
+ 'b.fbx': { root: skinnedModel('Spine'), animations: [] },
201
+ });
202
+ deps.exportModel = async (root) => {
203
+ const names = [];
204
+ root.traverse((object) => names.push(object.name));
205
+ return new TextEncoder().encode(names.join('|')).buffer;
206
+ };
207
+ const plan = await planImportZh([file('a.fbx'), file('b.fbx')], backend, deps);
208
+ await expect(executeImport(plan, [], lib)).rejects.toMatchObject({
209
+ item: { name: 'b', sourceFile: 'b.fbx' },
210
+ cause: new Error('disk full'),
211
+ });
212
+ });
188
213
  });
@@ -84,6 +84,7 @@ export declare class Library {
84
84
  listBlobIds(): Promise<string[]>;
85
85
  /** 所有条目引用的 blob id 集合(模型 blobId + thumbnailId) */
86
86
  private referencedBlobIds;
87
+ private referencedBlobIdsForRollback;
87
88
  /** 删条目并清理它的 blob;blob 被其他条目共享时保留 */
88
89
  deleteEntryDeep(id: string): Promise<void>;
89
90
  /** 清理无条目引用的孤儿 blob,返回删除数量 */
@@ -1 +1 @@
1
- {"version":3,"file":"library.d.ts","sourceRoot":"","sources":["../../src/assetLibrary/library.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"library.d.ts","sourceRoot":"","sources":["../../src/assetLibrary/library.ts"],"names":[],"mappings":"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"}