@pascal-app/core 1.0.0-beta.5 → 1.0.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 (231) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +23 -0
  3. package/dist/capture/index.d.ts +3 -0
  4. package/dist/capture/index.d.ts.map +1 -0
  5. package/dist/capture/index.js +2 -0
  6. package/dist/capture/schema.d.ts +417 -0
  7. package/dist/capture/schema.d.ts.map +1 -0
  8. package/dist/capture/schema.js +348 -0
  9. package/dist/capture/source.d.ts +60 -0
  10. package/dist/capture/source.d.ts.map +1 -0
  11. package/dist/capture/source.js +254 -0
  12. package/dist/events/bus.d.ts +55 -7
  13. package/dist/events/bus.d.ts.map +1 -1
  14. package/dist/events/hidden-wall-pointer-hold.d.ts +28 -0
  15. package/dist/events/hidden-wall-pointer-hold.d.ts.map +1 -0
  16. package/dist/events/hidden-wall-pointer-hold.js +37 -0
  17. package/dist/hooks/spatial-grid/spatial-grid-sync.d.ts +2785 -1
  18. package/dist/hooks/spatial-grid/spatial-grid-sync.d.ts.map +1 -1
  19. package/dist/hooks/spatial-grid/spatial-grid-sync.js +132 -19
  20. package/dist/hooks/spatial-grid/support-host-patch.d.ts +45 -1
  21. package/dist/hooks/spatial-grid/support-host-patch.d.ts.map +1 -1
  22. package/dist/hooks/spatial-grid/support-host-patch.js +171 -6
  23. package/dist/index.d.ts +14 -6
  24. package/dist/index.d.ts.map +1 -1
  25. package/dist/index.js +16 -5
  26. package/dist/lib/asset-storage.d.ts.map +1 -1
  27. package/dist/lib/asset-storage.js +4 -1
  28. package/dist/lib/polygon-union.d.ts +4 -0
  29. package/dist/lib/polygon-union.d.ts.map +1 -0
  30. package/dist/lib/polygon-union.js +306 -0
  31. package/dist/lib/roof-overlap.d.ts +32 -0
  32. package/dist/lib/roof-overlap.d.ts.map +1 -0
  33. package/dist/lib/roof-overlap.js +72 -0
  34. package/dist/lib/slab-polygon.d.ts +35 -2
  35. package/dist/lib/slab-polygon.d.ts.map +1 -1
  36. package/dist/lib/slab-polygon.js +133 -27
  37. package/dist/lib/space-detection.d.ts +11 -0
  38. package/dist/lib/space-detection.d.ts.map +1 -1
  39. package/dist/lib/space-detection.js +42 -14
  40. package/dist/registry/handles.d.ts +24 -3
  41. package/dist/registry/handles.d.ts.map +1 -1
  42. package/dist/registry/index.d.ts +3 -4
  43. package/dist/registry/index.d.ts.map +1 -1
  44. package/dist/registry/index.js +1 -2
  45. package/dist/registry/registry.d.ts +13 -6
  46. package/dist/registry/registry.d.ts.map +1 -1
  47. package/dist/registry/registry.js +37 -4
  48. package/dist/registry/scene-api.d.ts +16 -0
  49. package/dist/registry/scene-api.d.ts.map +1 -1
  50. package/dist/registry/scene-api.js +49 -1
  51. package/dist/registry/types.d.ts +226 -13
  52. package/dist/registry/types.d.ts.map +1 -1
  53. package/dist/schema/__bench__/node-parsers.bench.d.ts +24 -0
  54. package/dist/schema/__bench__/node-parsers.bench.d.ts.map +1 -0
  55. package/dist/schema/__bench__/node-parsers.bench.js +314 -0
  56. package/dist/schema/__fixtures__/node-fixtures.d.ts +28 -0
  57. package/dist/schema/__fixtures__/node-fixtures.d.ts.map +1 -0
  58. package/dist/schema/__fixtures__/node-fixtures.js +125 -0
  59. package/dist/schema/base.d.ts +1 -1
  60. package/dist/schema/base.d.ts.map +1 -1
  61. package/dist/schema/base.js +8 -1
  62. package/dist/schema/compiled-node-parsers.d.ts +40 -0
  63. package/dist/schema/compiled-node-parsers.d.ts.map +1 -0
  64. package/dist/schema/compiled-node-parsers.js +95 -0
  65. package/dist/schema/index.d.ts +19 -15
  66. package/dist/schema/index.d.ts.map +1 -1
  67. package/dist/schema/index.js +17 -12
  68. package/dist/schema/material.d.ts +2 -1
  69. package/dist/schema/material.d.ts.map +1 -1
  70. package/dist/schema/material.js +1 -0
  71. package/dist/schema/nodes/automatic-downspout.d.ts +17 -0
  72. package/dist/schema/nodes/automatic-downspout.d.ts.map +1 -0
  73. package/dist/schema/nodes/automatic-downspout.js +237 -0
  74. package/dist/schema/nodes/block.d.ts +107 -0
  75. package/dist/schema/nodes/block.d.ts.map +1 -0
  76. package/dist/schema/nodes/block.js +207 -0
  77. package/dist/schema/nodes/box-vent.d.ts +8 -2
  78. package/dist/schema/nodes/box-vent.d.ts.map +1 -1
  79. package/dist/schema/nodes/box-vent.js +2 -0
  80. package/dist/schema/nodes/building.d.ts +1 -1
  81. package/dist/schema/nodes/cabinet.d.ts +25 -3
  82. package/dist/schema/nodes/cabinet.d.ts.map +1 -1
  83. package/dist/schema/nodes/cabinet.js +26 -5
  84. package/dist/schema/nodes/ceiling.d.ts +1 -1
  85. package/dist/schema/nodes/chimney.d.ts +2 -2
  86. package/dist/schema/nodes/column.d.ts +6 -6
  87. package/dist/schema/nodes/construction-dimension.d.ts +4 -4
  88. package/dist/schema/nodes/cupola.d.ts +9 -1
  89. package/dist/schema/nodes/cupola.d.ts.map +1 -1
  90. package/dist/schema/nodes/cupola.js +2 -0
  91. package/dist/schema/nodes/door.d.ts +1 -1
  92. package/dist/schema/nodes/dormer.d.ts +44 -1
  93. package/dist/schema/nodes/dormer.d.ts.map +1 -1
  94. package/dist/schema/nodes/dormer.js +131 -7
  95. package/dist/schema/nodes/downspout.d.ts +11 -1
  96. package/dist/schema/nodes/downspout.d.ts.map +1 -1
  97. package/dist/schema/nodes/downspout.js +24 -0
  98. package/dist/schema/nodes/duct-fitting.d.ts +18 -1
  99. package/dist/schema/nodes/duct-fitting.d.ts.map +1 -1
  100. package/dist/schema/nodes/duct-fitting.js +25 -4
  101. package/dist/schema/nodes/duct-segment.d.ts +23 -1
  102. package/dist/schema/nodes/duct-segment.d.ts.map +1 -1
  103. package/dist/schema/nodes/duct-segment.js +20 -0
  104. package/dist/schema/nodes/duct-terminal.d.ts +1 -1
  105. package/dist/schema/nodes/elevator.d.ts +1 -1
  106. package/dist/schema/nodes/eyebrow-vent.d.ts +8 -2
  107. package/dist/schema/nodes/eyebrow-vent.d.ts.map +1 -1
  108. package/dist/schema/nodes/eyebrow-vent.js +2 -0
  109. package/dist/schema/nodes/fence.d.ts +1 -1
  110. package/dist/schema/nodes/guide.d.ts +1 -1
  111. package/dist/schema/nodes/gutter.d.ts +36 -2
  112. package/dist/schema/nodes/gutter.d.ts.map +1 -1
  113. package/dist/schema/nodes/gutter.js +308 -1
  114. package/dist/schema/nodes/hanger-overrides.d.ts +7 -0
  115. package/dist/schema/nodes/hanger-overrides.d.ts.map +1 -0
  116. package/dist/schema/nodes/hanger-overrides.js +6 -0
  117. package/dist/schema/nodes/hvac-equipment.d.ts +1 -1
  118. package/dist/schema/nodes/item.d.ts +4 -3
  119. package/dist/schema/nodes/item.d.ts.map +1 -1
  120. package/dist/schema/nodes/item.js +5 -0
  121. package/dist/schema/nodes/lean-to-extension.d.ts +212 -0
  122. package/dist/schema/nodes/lean-to-extension.d.ts.map +1 -0
  123. package/dist/schema/nodes/lean-to-extension.js +114 -0
  124. package/dist/schema/nodes/level.d.ts +2 -2
  125. package/dist/schema/nodes/level.d.ts.map +1 -1
  126. package/dist/schema/nodes/lineset.d.ts +1 -1
  127. package/dist/schema/nodes/liquid-line.d.ts +1 -1
  128. package/dist/schema/nodes/measurement.d.ts +1 -1
  129. package/dist/schema/nodes/pipe-fitting.d.ts +9 -1
  130. package/dist/schema/nodes/pipe-fitting.d.ts.map +1 -1
  131. package/dist/schema/nodes/pipe-fitting.js +6 -2
  132. package/dist/schema/nodes/pipe-segment.d.ts +23 -1
  133. package/dist/schema/nodes/pipe-segment.d.ts.map +1 -1
  134. package/dist/schema/nodes/pipe-segment.js +20 -0
  135. package/dist/schema/nodes/pipe-trap.d.ts +1 -1
  136. package/dist/schema/nodes/ridge-vent.d.ts +1 -1
  137. package/dist/schema/nodes/ridge-vent.d.ts.map +1 -1
  138. package/dist/schema/nodes/ridge-vent.js +4 -1
  139. package/dist/schema/nodes/roof-segment-shape.d.ts +4 -0
  140. package/dist/schema/nodes/roof-segment-shape.d.ts.map +1 -1
  141. package/dist/schema/nodes/roof-segment-shape.js +64 -1
  142. package/dist/schema/nodes/roof-segment-walls.d.ts +3 -1
  143. package/dist/schema/nodes/roof-segment-walls.d.ts.map +1 -1
  144. package/dist/schema/nodes/roof-segment-walls.js +1 -1
  145. package/dist/schema/nodes/roof-segment.d.ts +41 -1
  146. package/dist/schema/nodes/roof-segment.d.ts.map +1 -1
  147. package/dist/schema/nodes/roof-segment.js +79 -2
  148. package/dist/schema/nodes/roof.d.ts +22 -1
  149. package/dist/schema/nodes/roof.d.ts.map +1 -1
  150. package/dist/schema/nodes/roof.js +14 -0
  151. package/dist/schema/nodes/scan.d.ts +19 -2
  152. package/dist/schema/nodes/scan.d.ts.map +1 -1
  153. package/dist/schema/nodes/scan.js +11 -1
  154. package/dist/schema/nodes/shelf.d.ts +2 -2
  155. package/dist/schema/nodes/site.d.ts +1 -1
  156. package/dist/schema/nodes/skylight.d.ts +1 -1
  157. package/dist/schema/nodes/slab.d.ts +1 -1
  158. package/dist/schema/nodes/solar-panel.d.ts +1 -1
  159. package/dist/schema/nodes/spawn.d.ts +1 -1
  160. package/dist/schema/nodes/stair-segment.d.ts +1 -1
  161. package/dist/schema/nodes/stair.d.ts +1 -1
  162. package/dist/schema/nodes/structural-grid.d.ts +1 -1
  163. package/dist/schema/nodes/turbine-vent.d.ts +7 -1
  164. package/dist/schema/nodes/turbine-vent.d.ts.map +1 -1
  165. package/dist/schema/nodes/turbine-vent.js +2 -0
  166. package/dist/schema/nodes/wall.d.ts +4 -4
  167. package/dist/schema/nodes/wall.d.ts.map +1 -1
  168. package/dist/schema/nodes/wall.js +7 -1
  169. package/dist/schema/nodes/window.d.ts +10 -3
  170. package/dist/schema/nodes/window.d.ts.map +1 -1
  171. package/dist/schema/nodes/window.js +4 -0
  172. package/dist/schema/nodes/zone.d.ts +2 -2
  173. package/dist/schema/nodes/zone.js +1 -1
  174. package/dist/schema/types.d.ts +484 -109
  175. package/dist/schema/types.d.ts.map +1 -1
  176. package/dist/schema/types.js +27 -1
  177. package/dist/services/hosting.d.ts +2 -2
  178. package/dist/services/hosting.d.ts.map +1 -1
  179. package/dist/services/hosting.js +4 -4
  180. package/dist/services/index.d.ts +1 -1
  181. package/dist/services/index.d.ts.map +1 -1
  182. package/dist/services/index.js +1 -1
  183. package/dist/services/system-graph.d.ts +11 -0
  184. package/dist/services/system-graph.d.ts.map +1 -1
  185. package/dist/services/system-graph.js +35 -5
  186. package/dist/store/actions/node-actions.d.ts +7 -0
  187. package/dist/store/actions/node-actions.d.ts.map +1 -1
  188. package/dist/store/actions/node-actions.js +429 -17
  189. package/dist/store/history-invalidation.d.ts +3 -0
  190. package/dist/store/history-invalidation.d.ts.map +1 -0
  191. package/dist/store/history-invalidation.js +72 -0
  192. package/dist/store/scene-hydration.d.ts +5 -0
  193. package/dist/store/scene-hydration.d.ts.map +1 -0
  194. package/dist/store/scene-hydration.js +57 -0
  195. package/dist/store/use-scene.d.ts +3 -0
  196. package/dist/store/use-scene.d.ts.map +1 -1
  197. package/dist/store/use-scene.js +332 -64
  198. package/dist/systems/roof/roof-elevation-system.d.ts +3 -0
  199. package/dist/systems/roof/roof-elevation-system.d.ts.map +1 -0
  200. package/dist/systems/roof/roof-elevation-system.js +94 -0
  201. package/dist/systems/roof/roof-elevation.d.ts +4 -0
  202. package/dist/systems/roof/roof-elevation.d.ts.map +1 -0
  203. package/dist/systems/roof/roof-elevation.js +95 -0
  204. package/dist/systems/roof/roof-footprint.d.ts +17 -0
  205. package/dist/systems/roof/roof-footprint.d.ts.map +1 -0
  206. package/dist/systems/roof/roof-footprint.js +83 -0
  207. package/dist/systems/stair/stair-flight.d.ts +17 -0
  208. package/dist/systems/stair/stair-flight.d.ts.map +1 -0
  209. package/dist/systems/stair/stair-flight.js +27 -0
  210. package/dist/systems/stair/stair-opening-preview.d.ts +1555 -1328
  211. package/dist/systems/stair/stair-opening-preview.d.ts.map +1 -1
  212. package/dist/systems/stair/stair-opening-system.d.ts +1 -0
  213. package/dist/systems/stair/stair-opening-system.d.ts.map +1 -1
  214. package/dist/systems/stair/stair-opening-system.js +93 -96
  215. package/dist/systems/stair/stair-rise.d.ts.map +1 -1
  216. package/dist/systems/stair/stair-rise.js +20 -21
  217. package/dist/systems/wall/wall-curve.d.ts +1 -0
  218. package/dist/systems/wall/wall-curve.d.ts.map +1 -1
  219. package/dist/systems/wall/wall-curve.js +73 -0
  220. package/dist/systems/wall/wall-footprint.d.ts +1 -0
  221. package/dist/systems/wall/wall-footprint.d.ts.map +1 -1
  222. package/dist/systems/wall/wall-footprint.js +1 -0
  223. package/dist/utils/clone-scene-graph.d.ts.map +1 -1
  224. package/dist/utils/clone-scene-graph.js +26 -0
  225. package/dist/validation/validate-build-json.d.ts +3 -0
  226. package/dist/validation/validate-build-json.d.ts.map +1 -1
  227. package/dist/validation/validate-build-json.js +49 -2
  228. package/package.json +10 -3
  229. package/dist/systems/elevator/elevator-runtime-system.d.ts +0 -2
  230. package/dist/systems/elevator/elevator-runtime-system.d.ts.map +0 -1
  231. package/dist/systems/elevator/elevator-runtime-system.js +0 -8
@@ -0,0 +1,348 @@
1
+ import { z } from 'zod';
2
+ const MetadataSchema = z.record(z.string(), z.unknown());
3
+ export const CaptureSessionLocatorSchema = z.object({
4
+ sessionId: z.string().min(1),
5
+ manifestUrl: z.string().min(1).optional(),
6
+ schemaVersion: z.number().int().positive().optional(),
7
+ revisionId: z.string().min(1).optional(),
8
+ });
9
+ export const DeviceMotionSampleSchema = z.object({
10
+ segment: z.number().int().nonnegative(),
11
+ timestamp: z.number().nonnegative(),
12
+ transform: z.array(z.number()).length(16),
13
+ });
14
+ export const DeviceMotionTrajectorySchema = z.object({
15
+ coordinateSystem: z.string().min(1),
16
+ samples: z.array(DeviceMotionSampleSchema).min(2),
17
+ });
18
+ export const ArkitDeviceMotionTrajectorySchema = DeviceMotionTrajectorySchema.extend({
19
+ coordinateSystem: z.literal('arkit-world'),
20
+ });
21
+ export const PointCloudPayloadSchema = z
22
+ .object({
23
+ coordinateSystem: z.string().min(1),
24
+ positions: z.array(z.number().finite()).min(3),
25
+ colors: z.array(z.number().finite()).optional(),
26
+ })
27
+ .superRefine((payload, context) => {
28
+ if (payload.positions.length % 3 !== 0) {
29
+ context.addIssue({
30
+ code: 'custom',
31
+ message: 'Point-cloud positions must contain XYZ triples.',
32
+ path: ['positions'],
33
+ });
34
+ }
35
+ if (payload.colors && payload.colors.length !== payload.positions.length) {
36
+ context.addIssue({
37
+ code: 'custom',
38
+ message: 'Point-cloud colors must match the positions array length.',
39
+ path: ['colors'],
40
+ });
41
+ }
42
+ });
43
+ export const ArkitPointCloudPayloadSchema = PointCloudPayloadSchema.safeExtend({
44
+ coordinateSystem: z.literal('arkit-world'),
45
+ });
46
+ const MAX_SURFACE_MESH_VERTICES = 65_535;
47
+ const MAX_SURFACE_MESH_FACES = 20_000;
48
+ export const SurfaceMeshPayloadSchema = z
49
+ .object({
50
+ version: z.literal(1),
51
+ coordinateSystem: z.string().min(1),
52
+ representation: z.literal('quantized-indexed-triangle-mesh'),
53
+ appearance: z.literal('camera-vertex-color'),
54
+ vertexCount: z.number().int().positive().max(MAX_SURFACE_MESH_VERTICES),
55
+ faceCount: z.number().int().positive().max(MAX_SURFACE_MESH_FACES),
56
+ boundsMin: z.array(z.number().finite()).length(3),
57
+ boundsMax: z.array(z.number().finite()).length(3),
58
+ positionEncoding: z.literal('uint16x3-base64-little-endian'),
59
+ colorEncoding: z.literal('uint8x3-base64-srgb'),
60
+ indexEncoding: z.literal('uint16x3-base64-little-endian'),
61
+ positions: z.string().min(1).max(524_280),
62
+ colors: z.string().min(1).max(262_140),
63
+ indices: z
64
+ .string()
65
+ .min(1)
66
+ .max(MAX_SURFACE_MESH_FACES * 8),
67
+ })
68
+ .superRefine((payload, context) => {
69
+ if (payload.vertexCount > payload.faceCount * 3) {
70
+ context.addIssue({
71
+ code: 'custom',
72
+ message: 'Surface meshes cannot contain more than three vertices per face.',
73
+ path: ['vertexCount'],
74
+ });
75
+ }
76
+ for (let axis = 0; axis < 3; axis += 1) {
77
+ if ((payload.boundsMax[axis] ?? 0) < (payload.boundsMin[axis] ?? 0)) {
78
+ context.addIssue({
79
+ code: 'custom',
80
+ message: 'Surface-mesh maximum bounds must not be below minimum bounds.',
81
+ path: ['boundsMax', axis],
82
+ });
83
+ }
84
+ }
85
+ const positionBytes = decodeBase64(payload.positions);
86
+ const colorBytes = decodeBase64(payload.colors);
87
+ const indexBytes = decodeBase64(payload.indices);
88
+ validateSurfaceMeshByteLength(positionBytes, payload.vertexCount * 3 * 2, 'positions', context);
89
+ validateSurfaceMeshByteLength(colorBytes, payload.vertexCount * 3, 'colors', context);
90
+ validateSurfaceMeshByteLength(indexBytes, payload.faceCount * 3 * 2, 'indices', context);
91
+ if (indexBytes?.byteLength === payload.faceCount * 3 * 2) {
92
+ const indices = new DataView(indexBytes.buffer, indexBytes.byteOffset, indexBytes.byteLength);
93
+ for (let offset = 0; offset < indexBytes.byteLength; offset += 2) {
94
+ if (indices.getUint16(offset, true) >= payload.vertexCount) {
95
+ context.addIssue({
96
+ code: 'custom',
97
+ message: 'Surface-mesh indices must reference an existing vertex.',
98
+ path: ['indices'],
99
+ });
100
+ break;
101
+ }
102
+ }
103
+ }
104
+ });
105
+ export const ArkitSurfaceMeshPayloadSchema = SurfaceMeshPayloadSchema.safeExtend({
106
+ coordinateSystem: z.literal('arkit-world'),
107
+ });
108
+ export const CaptureTimeRangeSchema = z
109
+ .object({
110
+ start: z.number().nonnegative(),
111
+ end: z.number().nonnegative(),
112
+ })
113
+ .refine((range) => range.end >= range.start, {
114
+ message: 'Capture time ranges must end at or after they start.',
115
+ path: ['end'],
116
+ });
117
+ export const CaptureArtifactReferenceSchema = z.object({
118
+ id: z.string().min(1),
119
+ uri: z.string().min(1).optional(),
120
+ mediaType: z.string().min(1),
121
+ byteLength: z.number().int().nonnegative().optional(),
122
+ sha256: z.string().min(1).optional(),
123
+ frameId: z.string().min(1).optional(),
124
+ timeRange: CaptureTimeRangeSchema.optional(),
125
+ metadata: MetadataSchema.optional(),
126
+ });
127
+ export const CaptureStreamDescriptorSchema = z.object({
128
+ id: z.string().min(1),
129
+ kind: z.string().min(1),
130
+ role: z.string().min(1).optional(),
131
+ availability: z.enum(['pending', 'live', 'ready', 'failed']).default('ready'),
132
+ frameId: z.string().min(1).optional(),
133
+ clockId: z.string().min(1).optional(),
134
+ artifact: CaptureArtifactReferenceSchema.optional(),
135
+ inline: z.unknown().optional(),
136
+ metadata: MetadataSchema.optional(),
137
+ });
138
+ export const CaptureClockSchema = z.object({
139
+ id: z.string().min(1),
140
+ timebase: z.enum(['seconds', 'milliseconds', 'microseconds', 'nanoseconds']),
141
+ epoch: z.string().min(1).optional(),
142
+ });
143
+ export const CaptureCoordinateFrameSchema = z.object({
144
+ id: z.string().min(1),
145
+ parentId: z.string().min(1).optional(),
146
+ convention: z.string().min(1),
147
+ transform: z.array(z.number()).length(16).optional(),
148
+ });
149
+ export const CaptureSessionManifestV1Schema = z.object({
150
+ schemaVersion: z.literal(1),
151
+ sessionId: z.string().min(1),
152
+ projectId: z.string().min(1),
153
+ streams: z.object({
154
+ roomModel: z
155
+ .object({
156
+ kind: z.literal('room-model'),
157
+ mediaType: z.literal('model/vnd.usdz+zip'),
158
+ url: z.string().min(1),
159
+ })
160
+ .optional(),
161
+ deviceMotion: z
162
+ .object({
163
+ kind: z.literal('device-motion'),
164
+ trajectory: ArkitDeviceMotionTrajectorySchema,
165
+ })
166
+ .optional(),
167
+ pointCloud: z
168
+ .object({
169
+ kind: z.literal('point-cloud'),
170
+ points: ArkitPointCloudPayloadSchema,
171
+ })
172
+ .optional(),
173
+ surfaceMesh: z
174
+ .object({
175
+ kind: z.literal('surface-mesh'),
176
+ mesh: ArkitSurfaceMeshPayloadSchema,
177
+ })
178
+ .optional(),
179
+ }),
180
+ });
181
+ export const CaptureSessionManifestV2Schema = z
182
+ .object({
183
+ schemaVersion: z.literal(2),
184
+ sessionId: z.string().min(1),
185
+ projectId: z.string().min(1).optional(),
186
+ revisionId: z.string().min(1).optional(),
187
+ state: z.enum(['live', 'finalizing', 'ready', 'failed']).default('ready'),
188
+ clocks: z.array(CaptureClockSchema).default([]),
189
+ coordinateFrames: z.array(CaptureCoordinateFrameSchema).default([]),
190
+ streams: z.array(CaptureStreamDescriptorSchema),
191
+ metadata: MetadataSchema.optional(),
192
+ })
193
+ .superRefine(validateUniqueSessionIds);
194
+ export const CaptureSessionManifestSchema = z.union([
195
+ CaptureSessionManifestV1Schema,
196
+ CaptureSessionManifestV2Schema,
197
+ ]);
198
+ export const CaptureSessionDescriptorSchema = z
199
+ .object({
200
+ schemaVersion: z.number().int().positive(),
201
+ sessionId: z.string().min(1),
202
+ projectId: z.string().min(1).optional(),
203
+ revisionId: z.string().min(1).optional(),
204
+ state: z.enum(['live', 'finalizing', 'ready', 'failed']),
205
+ clocks: z.array(CaptureClockSchema),
206
+ coordinateFrames: z.array(CaptureCoordinateFrameSchema),
207
+ streams: z.array(CaptureStreamDescriptorSchema),
208
+ metadata: MetadataSchema.optional(),
209
+ })
210
+ .superRefine(validateUniqueSessionIds);
211
+ export function normalizeCaptureSessionManifest(value) {
212
+ const manifest = CaptureSessionManifestSchema.parse(value);
213
+ if (manifest.schemaVersion === 2)
214
+ return CaptureSessionDescriptorSchema.parse(manifest);
215
+ const streams = [];
216
+ if (manifest.streams.roomModel) {
217
+ streams.push({
218
+ id: 'room-model',
219
+ kind: manifest.streams.roomModel.kind,
220
+ role: 'model',
221
+ availability: 'ready',
222
+ artifact: {
223
+ id: `${manifest.sessionId}:room-model`,
224
+ mediaType: manifest.streams.roomModel.mediaType,
225
+ uri: manifest.streams.roomModel.url,
226
+ },
227
+ });
228
+ }
229
+ if (manifest.streams.deviceMotion) {
230
+ streams.push({
231
+ id: 'device-motion',
232
+ kind: manifest.streams.deviceMotion.kind,
233
+ role: 'deviceMotion',
234
+ availability: 'ready',
235
+ inline: manifest.streams.deviceMotion.trajectory,
236
+ });
237
+ }
238
+ if (manifest.streams.pointCloud) {
239
+ streams.push({
240
+ id: 'point-cloud',
241
+ kind: manifest.streams.pointCloud.kind,
242
+ role: 'pointCloud',
243
+ availability: 'ready',
244
+ inline: manifest.streams.pointCloud.points,
245
+ });
246
+ }
247
+ if (manifest.streams.surfaceMesh) {
248
+ streams.push({
249
+ id: 'surface-mesh',
250
+ kind: manifest.streams.surfaceMesh.kind,
251
+ role: 'surfaceMesh',
252
+ availability: 'ready',
253
+ inline: manifest.streams.surfaceMesh.mesh,
254
+ });
255
+ }
256
+ return CaptureSessionDescriptorSchema.parse({
257
+ schemaVersion: manifest.schemaVersion,
258
+ sessionId: manifest.sessionId,
259
+ projectId: manifest.projectId,
260
+ state: 'ready',
261
+ clocks: [],
262
+ coordinateFrames: [],
263
+ streams,
264
+ });
265
+ }
266
+ export function captureLayerKey(stream) {
267
+ if (stream.role)
268
+ return stream.role;
269
+ if (stream.kind === 'room-model')
270
+ return 'model';
271
+ if (stream.kind === 'device-motion')
272
+ return 'deviceMotion';
273
+ if (stream.kind === 'point-cloud')
274
+ return 'pointCloud';
275
+ if (stream.kind === 'surface-mesh')
276
+ return 'surfaceMesh';
277
+ if (stream.kind === 'gaussian-splat')
278
+ return 'splat';
279
+ return stream.kind;
280
+ }
281
+ export function captureStreamLabel(stream) {
282
+ const key = captureLayerKey(stream);
283
+ if (key === 'model')
284
+ return '3D model';
285
+ if (key === 'deviceMotion')
286
+ return 'Device motion';
287
+ if (key === 'pointCloud')
288
+ return 'Point cloud';
289
+ if (key === 'surfaceMesh')
290
+ return 'Surface mesh';
291
+ if (key === 'splat')
292
+ return 'Gaussian splat';
293
+ return key
294
+ .replace(/([a-z])([A-Z])/g, '$1 $2')
295
+ .replace(/[-_]+/g, ' ')
296
+ .replace(/^./, (value) => value.toUpperCase());
297
+ }
298
+ function validateSurfaceMeshByteLength(bytes, expectedLength, path, context) {
299
+ if (bytes?.byteLength === expectedLength)
300
+ return;
301
+ context.addIssue({
302
+ code: 'custom',
303
+ message: `Surface-mesh ${path} must contain exactly ${expectedLength} decoded bytes.`,
304
+ path: [path],
305
+ });
306
+ }
307
+ function decodeBase64(value) {
308
+ if (value.length % 4 !== 0 ||
309
+ !/^(?:[A-Za-z\d+/]{4})*(?:[A-Za-z\d+/]{2}==|[A-Za-z\d+/]{3}=)?$/.test(value)) {
310
+ return null;
311
+ }
312
+ const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
313
+ const padding = value.endsWith('==') ? 2 : value.endsWith('=') ? 1 : 0;
314
+ const output = new Uint8Array((value.length / 4) * 3 - padding);
315
+ let outputIndex = 0;
316
+ for (let index = 0; index < value.length; index += 4) {
317
+ const a = alphabet.indexOf(value[index] ?? '');
318
+ const b = alphabet.indexOf(value[index + 1] ?? '');
319
+ const c = value[index + 2] === '=' ? 0 : alphabet.indexOf(value[index + 2] ?? '');
320
+ const d = value[index + 3] === '=' ? 0 : alphabet.indexOf(value[index + 3] ?? '');
321
+ const bits = a * 262_144 + b * 4096 + c * 64 + d;
322
+ if (outputIndex < output.length)
323
+ output[outputIndex++] = Math.floor(bits / 65_536) % 256;
324
+ if (outputIndex < output.length)
325
+ output[outputIndex++] = Math.floor(bits / 256) % 256;
326
+ if (outputIndex < output.length)
327
+ output[outputIndex++] = bits % 256;
328
+ }
329
+ return output;
330
+ }
331
+ function validateUniqueSessionIds(value, context) {
332
+ validateUniqueIds(value.streams, 'streams', context);
333
+ validateUniqueIds(value.clocks, 'clocks', context);
334
+ validateUniqueIds(value.coordinateFrames, 'coordinateFrames', context);
335
+ }
336
+ function validateUniqueIds(values, path, context) {
337
+ const seen = new Set();
338
+ values.forEach((value, index) => {
339
+ if (seen.has(value.id)) {
340
+ context.addIssue({
341
+ code: 'custom',
342
+ message: `Duplicate capture ${path} id: ${value.id}`,
343
+ path: [path, index, 'id'],
344
+ });
345
+ }
346
+ seen.add(value.id);
347
+ });
348
+ }
@@ -0,0 +1,60 @@
1
+ import { z } from 'zod';
2
+ import { type CaptureArtifactReference, type CaptureSessionDescriptor, type CaptureSessionLocator } from './schema';
3
+ export declare const CaptureStreamPacketSchema: z.ZodObject<{
4
+ protocolVersion: z.ZodLiteral<1>;
5
+ sessionId: z.ZodString;
6
+ streamId: z.ZodString;
7
+ generation: z.ZodNumber;
8
+ sequence: z.ZodNumber;
9
+ timestamp: z.ZodNumber;
10
+ frameId: z.ZodOptional<z.ZodString>;
11
+ keyframe: z.ZodOptional<z.ZodBoolean>;
12
+ bounds: z.ZodOptional<z.ZodTuple<[z.ZodNumber, z.ZodNumber, z.ZodNumber, z.ZodNumber, z.ZodNumber, z.ZodNumber], null>>;
13
+ payload: z.ZodUnknown;
14
+ }, z.core.$strip>;
15
+ export type CaptureStreamPacket = z.infer<typeof CaptureStreamPacketSchema>;
16
+ export type CaptureSourceEvent = {
17
+ type: 'descriptor';
18
+ descriptor: CaptureSessionDescriptor;
19
+ } | {
20
+ type: 'packet';
21
+ packet: CaptureStreamPacket;
22
+ } | {
23
+ type: 'closed';
24
+ };
25
+ export type CaptureArtifactResolution = {
26
+ url: string;
27
+ dispose?: () => void;
28
+ };
29
+ export type CaptureSubscriptionOptions = {
30
+ signal?: AbortSignal;
31
+ streamIds?: readonly string[];
32
+ };
33
+ export interface CaptureSource {
34
+ describe(signal?: AbortSignal): Promise<CaptureSessionDescriptor>;
35
+ resolveArtifact?(artifact: CaptureArtifactReference, signal?: AbortSignal): Promise<CaptureArtifactResolution>;
36
+ subscribe?(options?: CaptureSubscriptionOptions): AsyncIterable<CaptureSourceEvent>;
37
+ }
38
+ export type CaptureSourceResolver = (locator: CaptureSessionLocator) => CaptureSource | Promise<CaptureSource>;
39
+ export type HttpCaptureSourceOptions = {
40
+ credentials?: RequestCredentials;
41
+ fetch?: typeof globalThis.fetch;
42
+ headers?: HeadersInit;
43
+ manifestUrl?: (locator: CaptureSessionLocator) => string;
44
+ resolveArtifact?: (artifact: CaptureArtifactReference, signal?: AbortSignal) => Promise<CaptureArtifactResolution>;
45
+ };
46
+ export type PushCaptureSourceOptions = {
47
+ maxQueuedEventsPerSubscriber?: number;
48
+ };
49
+ export declare function createHttpCaptureSource(locatorInput: CaptureSessionLocator, options?: HttpCaptureSourceOptions): CaptureSource;
50
+ export declare class PushCaptureSource implements CaptureSource {
51
+ #private;
52
+ constructor(descriptor: CaptureSessionDescriptor, options?: PushCaptureSourceOptions);
53
+ describe(): Promise<CaptureSessionDescriptor>;
54
+ resolveArtifact(artifact: CaptureArtifactReference): Promise<CaptureArtifactResolution>;
55
+ subscribe(options?: CaptureSubscriptionOptions): AsyncIterable<CaptureSourceEvent>;
56
+ updateDescriptor(descriptor: CaptureSessionDescriptor): void;
57
+ publishPacket(packetInput: CaptureStreamPacket): void;
58
+ close(): void;
59
+ }
60
+ //# sourceMappingURL=source.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"source.d.ts","sourceRoot":"","sources":["../../src/capture/source.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,EACL,KAAK,wBAAwB,EAC7B,KAAK,wBAAwB,EAE7B,KAAK,qBAAqB,EAG3B,MAAM,UAAU,CAAA;AAEjB,eAAO,MAAM,yBAAyB;;;;;;;;;;;iBAapC,CAAA;AAEF,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAA;AAE3E,MAAM,MAAM,kBAAkB,GAC1B;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,UAAU,EAAE,wBAAwB,CAAA;CAAE,GAC5D;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,mBAAmB,CAAA;CAAE,GAC/C;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,CAAA;AAEtB,MAAM,MAAM,yBAAyB,GAAG;IACtC,GAAG,EAAE,MAAM,CAAA;IACX,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;CACrB,CAAA;AAED,MAAM,MAAM,0BAA0B,GAAG;IACvC,MAAM,CAAC,EAAE,WAAW,CAAA;IACpB,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CAC9B,CAAA;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,wBAAwB,CAAC,CAAA;IACjE,eAAe,CAAC,CACd,QAAQ,EAAE,wBAAwB,EAClC,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,yBAAyB,CAAC,CAAA;IACrC,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,0BAA0B,GAAG,aAAa,CAAC,kBAAkB,CAAC,CAAA;CACpF;AAED,MAAM,MAAM,qBAAqB,GAAG,CAClC,OAAO,EAAE,qBAAqB,KAC3B,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC,CAAA;AAE3C,MAAM,MAAM,wBAAwB,GAAG;IACrC,WAAW,CAAC,EAAE,kBAAkB,CAAA;IAChC,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAA;IAC/B,OAAO,CAAC,EAAE,WAAW,CAAA;IACrB,WAAW,CAAC,EAAE,CAAC,OAAO,EAAE,qBAAqB,KAAK,MAAM,CAAA;IACxD,eAAe,CAAC,EAAE,CAChB,QAAQ,EAAE,wBAAwB,EAClC,MAAM,CAAC,EAAE,WAAW,KACjB,OAAO,CAAC,yBAAyB,CAAC,CAAA;CACxC,CAAA;AAED,MAAM,MAAM,wBAAwB,GAAG;IACrC,4BAA4B,CAAC,EAAE,MAAM,CAAA;CACtC,CAAA;AAED,wBAAgB,uBAAuB,CACrC,YAAY,EAAE,qBAAqB,EACnC,OAAO,GAAE,wBAA6B,GACrC,aAAa,CAwCf;AAmCD,qBAAa,iBAAkB,YAAW,aAAa;;gBAMzC,UAAU,EAAE,wBAAwB,EAAE,OAAO,GAAE,wBAA6B;IAKlF,QAAQ,IAAI,OAAO,CAAC,wBAAwB,CAAC;IAI7C,eAAe,CAAC,QAAQ,EAAE,wBAAwB,GAAG,OAAO,CAAC,yBAAyB,CAAC;IAK7F,SAAS,CAAC,OAAO,GAAE,0BAA+B,GAAG,aAAa,CAAC,kBAAkB,CAAC;IAyBtF,gBAAgB,CAAC,UAAU,EAAE,wBAAwB,GAAG,IAAI;IAU5D,aAAa,CAAC,WAAW,EAAE,mBAAmB,GAAG,IAAI;IAYrD,KAAK,IAAI,IAAI;CAqBd"}
@@ -0,0 +1,254 @@
1
+ import { z } from 'zod';
2
+ import { CaptureSessionDescriptorSchema, CaptureSessionLocatorSchema, normalizeCaptureSessionManifest, } from './schema';
3
+ export const CaptureStreamPacketSchema = z.object({
4
+ protocolVersion: z.literal(1),
5
+ sessionId: z.string().min(1),
6
+ streamId: z.string().min(1),
7
+ generation: z.number().int().nonnegative(),
8
+ sequence: z.number().int().nonnegative(),
9
+ timestamp: z.number().nonnegative(),
10
+ frameId: z.string().min(1).optional(),
11
+ keyframe: z.boolean().optional(),
12
+ bounds: z
13
+ .tuple([z.number(), z.number(), z.number(), z.number(), z.number(), z.number()])
14
+ .optional(),
15
+ payload: z.unknown(),
16
+ });
17
+ export function createHttpCaptureSource(locatorInput, options = {}) {
18
+ const locator = CaptureSessionLocatorSchema.parse(locatorInput);
19
+ const manifestUrl = locator.manifestUrl ?? options.manifestUrl?.(locator);
20
+ if (!manifestUrl)
21
+ throw new Error(`Capture session ${locator.sessionId} has no manifest URL.`);
22
+ let descriptorPromise = null;
23
+ const loadDescriptor = async () => {
24
+ const fetcher = options.fetch ?? globalThis.fetch;
25
+ const response = await fetcher(manifestUrl, {
26
+ credentials: options.credentials,
27
+ headers: options.headers,
28
+ });
29
+ if (!response.ok)
30
+ throw new Error(`Capture session ${locator.sessionId} is unavailable.`);
31
+ const descriptor = normalizeCaptureSessionManifest(await response.json());
32
+ if (descriptor.sessionId !== locator.sessionId) {
33
+ throw new Error(`Capture manifest session does not match ${locator.sessionId}.`);
34
+ }
35
+ if (locator.schemaVersion && descriptor.schemaVersion !== locator.schemaVersion) {
36
+ throw new Error(`Capture manifest schema does not match version ${locator.schemaVersion}.`);
37
+ }
38
+ if (locator.revisionId && descriptor.revisionId !== locator.revisionId) {
39
+ throw new Error(`Capture manifest revision does not match ${locator.revisionId}.`);
40
+ }
41
+ return descriptor;
42
+ };
43
+ return {
44
+ describe(signal) {
45
+ descriptorPromise ??= loadDescriptor().catch((cause) => {
46
+ descriptorPromise = null;
47
+ throw cause;
48
+ });
49
+ return waitForPromise(descriptorPromise, signal).then(cloneCaptureDescriptor);
50
+ },
51
+ async resolveArtifact(artifact, signal) {
52
+ if (options.resolveArtifact)
53
+ return options.resolveArtifact(artifact, signal);
54
+ if (!artifact.uri)
55
+ throw new Error(`Capture artifact ${artifact.id} has no URI.`);
56
+ return { url: resolveArtifactUri(artifact.uri, manifestUrl) };
57
+ },
58
+ };
59
+ }
60
+ function waitForPromise(promise, signal) {
61
+ if (!signal)
62
+ return promise;
63
+ if (signal.aborted)
64
+ return Promise.reject(abortError());
65
+ return new Promise((resolve, reject) => {
66
+ const onAbort = () => reject(abortError());
67
+ signal.addEventListener('abort', onAbort, { once: true });
68
+ void promise.then(resolve, reject).finally(() => signal.removeEventListener('abort', onAbort));
69
+ });
70
+ }
71
+ function abortError() {
72
+ const error = new Error('The capture request was aborted.');
73
+ error.name = 'AbortError';
74
+ return error;
75
+ }
76
+ function resolveArtifactUri(uri, manifestUrl) {
77
+ try {
78
+ const base = typeof globalThis.location === 'undefined'
79
+ ? new URL(manifestUrl)
80
+ : new URL(manifestUrl, globalThis.location.href);
81
+ return new URL(uri, base).toString();
82
+ }
83
+ catch {
84
+ return uri;
85
+ }
86
+ }
87
+ export class PushCaptureSource {
88
+ #closed = false;
89
+ #descriptor;
90
+ #maxQueuedEventsPerSubscriber;
91
+ #subscribers = new Set();
92
+ constructor(descriptor, options = {}) {
93
+ this.#descriptor = cloneCaptureDescriptor(descriptor);
94
+ this.#maxQueuedEventsPerSubscriber = Math.max(1, options.maxQueuedEventsPerSubscriber ?? 32);
95
+ }
96
+ async describe() {
97
+ return cloneCaptureDescriptor(this.#descriptor);
98
+ }
99
+ async resolveArtifact(artifact) {
100
+ if (!artifact.uri)
101
+ throw new Error(`Capture artifact ${artifact.id} has no URI.`);
102
+ return { url: artifact.uri };
103
+ }
104
+ subscribe(options = {}) {
105
+ let cleanupAbort = () => { };
106
+ let subscriber;
107
+ const iterator = new EventIterator(() => {
108
+ cleanupAbort();
109
+ this.#subscribers.delete(subscriber);
110
+ }, this.#maxQueuedEventsPerSubscriber);
111
+ subscriber = {
112
+ iterator,
113
+ streamIds: options.streamIds ? new Set(options.streamIds) : null,
114
+ };
115
+ this.#subscribers.add(subscriber);
116
+ if (this.#closed) {
117
+ iterator.close({ type: 'closed' });
118
+ }
119
+ else if (options.signal) {
120
+ if (options.signal.aborted)
121
+ iterator.finish();
122
+ else {
123
+ const onAbort = () => iterator.finish();
124
+ options.signal.addEventListener('abort', onAbort, { once: true });
125
+ cleanupAbort = () => options.signal?.removeEventListener('abort', onAbort);
126
+ }
127
+ }
128
+ return iterator;
129
+ }
130
+ updateDescriptor(descriptor) {
131
+ if (this.#closed)
132
+ return;
133
+ const nextDescriptor = cloneCaptureDescriptor(descriptor);
134
+ if (nextDescriptor.sessionId !== this.#descriptor.sessionId) {
135
+ throw new Error('A capture source cannot change session identity.');
136
+ }
137
+ this.#descriptor = nextDescriptor;
138
+ this.#publish({ type: 'descriptor', descriptor: cloneCaptureDescriptor(nextDescriptor) });
139
+ }
140
+ publishPacket(packetInput) {
141
+ if (this.#closed)
142
+ return;
143
+ const packet = CaptureStreamPacketSchema.parse(packetInput);
144
+ if (packet.sessionId !== this.#descriptor.sessionId) {
145
+ throw new Error(`Capture packet does not belong to ${this.#descriptor.sessionId}.`);
146
+ }
147
+ if (!this.#descriptor.streams.some((stream) => stream.id === packet.streamId)) {
148
+ throw new Error(`Capture packet references unknown stream ${packet.streamId}.`);
149
+ }
150
+ this.#publish({ type: 'packet', packet });
151
+ }
152
+ close() {
153
+ if (this.#closed)
154
+ return;
155
+ this.#closed = true;
156
+ for (const subscriber of this.#subscribers) {
157
+ subscriber.iterator.close({ type: 'closed' });
158
+ }
159
+ this.#subscribers.clear();
160
+ }
161
+ #publish(event) {
162
+ for (const subscriber of this.#subscribers) {
163
+ if (event.type === 'packet' &&
164
+ subscriber.streamIds &&
165
+ !subscriber.streamIds.has(event.packet.streamId)) {
166
+ continue;
167
+ }
168
+ subscriber.iterator.push(cloneCaptureSourceEvent(event));
169
+ }
170
+ }
171
+ }
172
+ class EventIterator {
173
+ #done = false;
174
+ #maxQueuedEvents;
175
+ #onFinish;
176
+ #queue = [];
177
+ #waiters = [];
178
+ constructor(onFinish, maxQueuedEvents) {
179
+ this.#onFinish = onFinish;
180
+ this.#maxQueuedEvents = maxQueuedEvents;
181
+ }
182
+ [Symbol.asyncIterator]() {
183
+ return this;
184
+ }
185
+ next() {
186
+ const event = this.#queue.shift();
187
+ if (event)
188
+ return Promise.resolve({ done: false, value: event });
189
+ if (this.#done)
190
+ return Promise.resolve({ done: true, value: undefined });
191
+ return new Promise((resolve) => this.#waiters.push(resolve));
192
+ }
193
+ return() {
194
+ this.finish();
195
+ return Promise.resolve({ done: true, value: undefined });
196
+ }
197
+ push(event) {
198
+ if (this.#done)
199
+ return;
200
+ const waiter = this.#waiters.shift();
201
+ if (waiter)
202
+ waiter({ done: false, value: event });
203
+ else {
204
+ this.#queue.push(event);
205
+ this.#trimQueue();
206
+ }
207
+ }
208
+ close(event) {
209
+ if (this.#done)
210
+ return;
211
+ this.#done = true;
212
+ this.#queue = [];
213
+ const waiter = this.#waiters.shift();
214
+ if (waiter)
215
+ waiter({ done: false, value: event });
216
+ else
217
+ this.#queue.push(event);
218
+ for (const pending of this.#waiters.splice(0))
219
+ pending({ done: true, value: undefined });
220
+ this.#onFinish();
221
+ }
222
+ finish() {
223
+ if (this.#done) {
224
+ this.#queue = [];
225
+ return;
226
+ }
227
+ this.#done = true;
228
+ this.#queue = [];
229
+ this.#onFinish();
230
+ for (const waiter of this.#waiters.splice(0))
231
+ waiter({ done: true, value: undefined });
232
+ }
233
+ #trimQueue() {
234
+ while (this.#queue.length > this.#maxQueuedEvents) {
235
+ const packetIndex = this.#queue.findIndex((event) => event.type === 'packet');
236
+ this.#queue.splice(packetIndex >= 0 ? packetIndex : 0, 1);
237
+ }
238
+ }
239
+ }
240
+ function cloneCaptureDescriptor(descriptor) {
241
+ return CaptureSessionDescriptorSchema.parse(structuredClone(descriptor));
242
+ }
243
+ function cloneCaptureSourceEvent(event) {
244
+ if (event.type === 'descriptor') {
245
+ return { type: 'descriptor', descriptor: cloneCaptureDescriptor(event.descriptor) };
246
+ }
247
+ if (event.type === 'packet') {
248
+ return {
249
+ type: 'packet',
250
+ packet: CaptureStreamPacketSchema.parse(structuredClone(event.packet)),
251
+ };
252
+ }
253
+ return { type: 'closed' };
254
+ }