@pascal-app/core 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/events/bus.d.ts +38 -2
- package/dist/events/bus.d.ts.map +1 -1
- package/dist/hooks/scene-registry/scene-registry.d.ts +2 -0
- package/dist/hooks/scene-registry/scene-registry.d.ts.map +1 -1
- package/dist/hooks/scene-registry/scene-registry.js +2 -0
- package/dist/hooks/spatial-grid/spatial-grid-manager.d.ts.map +1 -1
- package/dist/hooks/spatial-grid/spatial-grid-manager.js +164 -6
- package/dist/index.d.ts +8 -15
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -14
- package/dist/lib/door-operation.d.ts +7 -0
- package/dist/lib/door-operation.d.ts.map +1 -0
- package/dist/lib/door-operation.js +25 -0
- package/dist/lib/slab-polygon.d.ts +3 -0
- package/dist/lib/slab-polygon.d.ts.map +1 -0
- package/dist/lib/slab-polygon.js +58 -0
- package/dist/material-library.d.ts +5 -3
- package/dist/material-library.d.ts.map +1 -1
- package/dist/material-library.js +26 -49
- package/dist/schema/asset-url.d.ts +34 -0
- package/dist/schema/asset-url.d.ts.map +1 -0
- package/dist/schema/asset-url.js +79 -0
- package/dist/schema/asset-url.test.d.ts +2 -0
- package/dist/schema/asset-url.test.d.ts.map +1 -0
- package/dist/schema/asset-url.test.js +138 -0
- package/dist/schema/index.d.ts +7 -5
- package/dist/schema/index.d.ts.map +1 -1
- package/dist/schema/index.js +5 -3
- package/dist/schema/material.d.ts +3 -2
- package/dist/schema/material.d.ts.map +1 -1
- package/dist/schema/material.js +13 -11
- package/dist/schema/nodes/ceiling.d.ts +1 -1
- package/dist/schema/nodes/column.d.ts +520 -0
- package/dist/schema/nodes/column.d.ts.map +1 -0
- package/dist/schema/nodes/column.js +385 -0
- package/dist/schema/nodes/door.d.ts +73 -1
- package/dist/schema/nodes/door.d.ts.map +1 -1
- package/dist/schema/nodes/door.js +39 -2
- package/dist/schema/nodes/fence.d.ts +1 -1
- package/dist/schema/nodes/guide.d.ts +17 -0
- package/dist/schema/nodes/guide.d.ts.map +1 -1
- package/dist/schema/nodes/guide.js +11 -1
- package/dist/schema/nodes/item.d.ts +8 -0
- package/dist/schema/nodes/item.d.ts.map +1 -1
- package/dist/schema/nodes/item.js +18 -1
- package/dist/schema/nodes/level.d.ts +1 -1
- package/dist/schema/nodes/level.d.ts.map +1 -1
- package/dist/schema/nodes/level.js +6 -0
- package/dist/schema/nodes/roof-segment.d.ts +1 -1
- package/dist/schema/nodes/roof.d.ts +4 -4
- package/dist/schema/nodes/scan.d.ts.map +1 -1
- package/dist/schema/nodes/scan.js +2 -1
- package/dist/schema/nodes/site.d.ts +1 -0
- package/dist/schema/nodes/site.d.ts.map +1 -1
- package/dist/schema/nodes/slab.d.ts +1 -1
- package/dist/schema/nodes/spawn.d.ts +24 -0
- package/dist/schema/nodes/spawn.d.ts.map +1 -0
- package/dist/schema/nodes/spawn.js +8 -0
- package/dist/schema/nodes/stair-segment.d.ts +1 -1
- package/dist/schema/nodes/stair.d.ts +8 -8
- package/dist/schema/nodes/wall.d.ts +3 -3
- package/dist/schema/nodes/window.d.ts +56 -1
- package/dist/schema/nodes/window.d.ts.map +1 -1
- package/dist/schema/nodes/window.js +29 -0
- package/dist/schema/types.d.ts +324 -21
- package/dist/schema/types.d.ts.map +1 -1
- package/dist/schema/types.js +4 -0
- package/dist/store/actions/node-actions.d.ts.map +1 -1
- package/dist/store/actions/node-actions.js +6 -5
- package/dist/store/use-interactive.d.ts +43 -0
- package/dist/store/use-interactive.d.ts.map +1 -1
- package/dist/store/use-interactive.js +66 -0
- package/dist/store/use-scene.d.ts.map +1 -1
- package/dist/store/use-scene.js +60 -2
- package/dist/systems/stair/stair-opening-sync.d.ts.map +1 -1
- package/dist/systems/stair/stair-opening-sync.js +81 -20
- package/dist/systems/stair/stair-opening-sync.test.d.ts +2 -0
- package/dist/systems/stair/stair-opening-sync.test.d.ts.map +1 -0
- package/dist/systems/stair/stair-opening-sync.test.js +65 -0
- package/dist/systems/stair/stair-system.js +1 -1
- package/package.json +31 -3
package/dist/material-library.js
CHANGED
|
@@ -1,35 +1,18 @@
|
|
|
1
|
-
import {
|
|
2
|
-
const
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
MaterialTargetSchema.enum.wall,
|
|
10
|
-
MaterialTargetSchema.enum.slab,
|
|
11
|
-
];
|
|
12
|
-
const STAIR_TARGETS = [
|
|
13
|
-
MaterialTargetSchema.enum.stair,
|
|
14
|
-
MaterialTargetSchema.enum['stair-segment'],
|
|
15
|
-
];
|
|
16
|
-
const STAIR_AND_FENCE_TARGETS = [
|
|
17
|
-
...STAIR_TARGETS,
|
|
18
|
-
MaterialTargetSchema.enum.fence,
|
|
19
|
-
];
|
|
20
|
-
const ROOF_TARGETS = [
|
|
21
|
-
MaterialTargetSchema.enum.roof,
|
|
22
|
-
MaterialTargetSchema.enum['roof-segment'],
|
|
23
|
-
];
|
|
24
|
-
const CEILING_TARGETS = [
|
|
25
|
-
MaterialTargetSchema.enum.ceiling,
|
|
1
|
+
import {} from './schema/material';
|
|
2
|
+
export const MATERIAL_CATEGORIES = [
|
|
3
|
+
'wood',
|
|
4
|
+
'wallpaper',
|
|
5
|
+
'parquet',
|
|
6
|
+
'granite',
|
|
7
|
+
'marble',
|
|
8
|
+
'other',
|
|
26
9
|
];
|
|
27
10
|
export const MATERIAL_CATALOG = [
|
|
28
11
|
{
|
|
29
12
|
id: 'wall-wood1',
|
|
30
13
|
label: 'Wood',
|
|
14
|
+
category: 'wood',
|
|
31
15
|
description: 'Warm wood finish',
|
|
32
|
-
targets: [...WALL_TARGETS, ...SLAB_TARGETS, ...STAIR_AND_FENCE_TARGETS, ...ROOF_TARGETS],
|
|
33
16
|
previewThumbnailUrl: '/material/wood1/wood1_thumbnail.webp',
|
|
34
17
|
preset: {
|
|
35
18
|
maps: {
|
|
@@ -63,8 +46,8 @@ export const MATERIAL_CATALOG = [
|
|
|
63
46
|
{
|
|
64
47
|
id: 'wall-wood2',
|
|
65
48
|
label: 'Wood',
|
|
49
|
+
category: 'wood',
|
|
66
50
|
description: 'Textured wood finish',
|
|
67
|
-
targets: [...WALL_TARGETS, ...SLAB_TARGETS, ...STAIR_AND_FENCE_TARGETS, ...ROOF_TARGETS],
|
|
68
51
|
previewThumbnailUrl: '/material/wood2/wood2_thumbnail.webp',
|
|
69
52
|
preset: {
|
|
70
53
|
maps: {
|
|
@@ -99,8 +82,8 @@ export const MATERIAL_CATALOG = [
|
|
|
99
82
|
{
|
|
100
83
|
id: 'wall-wood3',
|
|
101
84
|
label: 'Wood',
|
|
85
|
+
category: 'wood',
|
|
102
86
|
description: 'Knotted timber finish',
|
|
103
|
-
targets: [...WALL_TARGETS, ...SLAB_TARGETS, ...STAIR_AND_FENCE_TARGETS, ...ROOF_TARGETS],
|
|
104
87
|
previewThumbnailUrl: '/material/wood3/wood3_thumbnail.webp',
|
|
105
88
|
preset: {
|
|
106
89
|
maps: {
|
|
@@ -133,8 +116,8 @@ export const MATERIAL_CATALOG = [
|
|
|
133
116
|
{
|
|
134
117
|
id: 'wall-wood4',
|
|
135
118
|
label: 'Wood',
|
|
119
|
+
category: 'wood',
|
|
136
120
|
description: 'Oak stretcher finish',
|
|
137
|
-
targets: [...WALL_TARGETS, ...SLAB_TARGETS, ...STAIR_AND_FENCE_TARGETS],
|
|
138
121
|
previewThumbnailUrl: '/material/wood4/wood4_thumbnail.webp',
|
|
139
122
|
preset: {
|
|
140
123
|
maps: {
|
|
@@ -167,8 +150,8 @@ export const MATERIAL_CATALOG = [
|
|
|
167
150
|
{
|
|
168
151
|
id: 'wall-wood5',
|
|
169
152
|
label: 'Wood',
|
|
153
|
+
category: 'wood',
|
|
170
154
|
description: 'Rich grain wood finish',
|
|
171
|
-
targets: [...WALL_TARGETS, ...SLAB_TARGETS, ...STAIR_AND_FENCE_TARGETS],
|
|
172
155
|
previewThumbnailUrl: '/material/wood5/wood5_thumnail.webp',
|
|
173
156
|
preset: {
|
|
174
157
|
maps: {
|
|
@@ -203,8 +186,8 @@ export const MATERIAL_CATALOG = [
|
|
|
203
186
|
{
|
|
204
187
|
id: 'wall-granite1',
|
|
205
188
|
label: 'Granite',
|
|
189
|
+
category: 'granite',
|
|
206
190
|
description: 'Polished granite finish',
|
|
207
|
-
targets: SLAB_TARGETS,
|
|
208
191
|
previewThumbnailUrl: '/material/granite1/granite_thumbnail.webp',
|
|
209
192
|
preset: {
|
|
210
193
|
maps: {
|
|
@@ -237,8 +220,8 @@ export const MATERIAL_CATALOG = [
|
|
|
237
220
|
{
|
|
238
221
|
id: 'wall-marble1',
|
|
239
222
|
label: 'Marble',
|
|
223
|
+
category: 'marble',
|
|
240
224
|
description: 'Smooth marble finish',
|
|
241
|
-
targets: [...SLAB_TARGETS, ...STAIR_AND_FENCE_TARGETS],
|
|
242
225
|
previewThumbnailUrl: '/material/marble1/marble1_thumbnail.webp',
|
|
243
226
|
preset: {
|
|
244
227
|
maps: {
|
|
@@ -271,8 +254,8 @@ export const MATERIAL_CATALOG = [
|
|
|
271
254
|
{
|
|
272
255
|
id: 'wall-marble2',
|
|
273
256
|
label: 'Marble',
|
|
257
|
+
category: 'marble',
|
|
274
258
|
description: 'Soft marble finish',
|
|
275
|
-
targets: [...SLAB_TARGETS, ...STAIR_AND_FENCE_TARGETS],
|
|
276
259
|
previewThumbnailUrl: '/material/marble2/marble2_thumbnail.webp',
|
|
277
260
|
preset: {
|
|
278
261
|
maps: {
|
|
@@ -305,8 +288,8 @@ export const MATERIAL_CATALOG = [
|
|
|
305
288
|
{
|
|
306
289
|
id: 'wall-parquet1',
|
|
307
290
|
label: 'Parquet',
|
|
291
|
+
category: 'parquet',
|
|
308
292
|
description: 'Parquet wood finish',
|
|
309
|
-
targets: SLAB_TARGETS,
|
|
310
293
|
previewThumbnailUrl: '/material/parquet1/parquet_thumnail.webp',
|
|
311
294
|
preset: {
|
|
312
295
|
maps: {
|
|
@@ -339,8 +322,8 @@ export const MATERIAL_CATALOG = [
|
|
|
339
322
|
{
|
|
340
323
|
id: 'wall-parquet2',
|
|
341
324
|
label: 'Parquet',
|
|
325
|
+
category: 'parquet',
|
|
342
326
|
description: 'Soft parquet finish',
|
|
343
|
-
targets: SLAB_TARGETS,
|
|
344
327
|
previewThumbnailUrl: '/material/parquet2/parquet2_thumbnail.webp',
|
|
345
328
|
preset: {
|
|
346
329
|
maps: {
|
|
@@ -373,8 +356,8 @@ export const MATERIAL_CATALOG = [
|
|
|
373
356
|
{
|
|
374
357
|
id: 'wall-wallpaper1',
|
|
375
358
|
label: 'Wallpaper',
|
|
359
|
+
category: 'wallpaper',
|
|
376
360
|
description: 'Soft wallpaper finish',
|
|
377
|
-
targets: WALL_TARGETS,
|
|
378
361
|
previewThumbnailUrl: '/material/wallpaper1/wallpaper1_thumbnail.webp',
|
|
379
362
|
preset: {
|
|
380
363
|
maps: {
|
|
@@ -408,8 +391,8 @@ export const MATERIAL_CATALOG = [
|
|
|
408
391
|
{
|
|
409
392
|
id: 'wall-wallpaper2',
|
|
410
393
|
label: 'Wallpaper',
|
|
394
|
+
category: 'wallpaper',
|
|
411
395
|
description: 'Decorative wallpaper finish',
|
|
412
|
-
targets: WALL_TARGETS,
|
|
413
396
|
previewThumbnailUrl: '/material/wallpaper2/wallpaper2_thumnail.webp',
|
|
414
397
|
preset: {
|
|
415
398
|
maps: {
|
|
@@ -442,8 +425,8 @@ export const MATERIAL_CATALOG = [
|
|
|
442
425
|
{
|
|
443
426
|
id: 'wall-wallpaper3',
|
|
444
427
|
label: 'Wallpaper',
|
|
428
|
+
category: 'wallpaper',
|
|
445
429
|
description: 'Patterned wallpaper finish',
|
|
446
|
-
targets: WALL_TARGETS,
|
|
447
430
|
previewThumbnailUrl: '/material/wallpaper3/wallpaper3_thumbnail.webp',
|
|
448
431
|
preset: {
|
|
449
432
|
maps: {
|
|
@@ -476,14 +459,8 @@ export const MATERIAL_CATALOG = [
|
|
|
476
459
|
{
|
|
477
460
|
id: 'preset-white',
|
|
478
461
|
label: 'White',
|
|
462
|
+
category: 'other',
|
|
479
463
|
description: 'Clean painted finish',
|
|
480
|
-
targets: [
|
|
481
|
-
...WALL_TARGETS,
|
|
482
|
-
...SLAB_TARGETS,
|
|
483
|
-
...ROOF_TARGETS,
|
|
484
|
-
...STAIR_AND_FENCE_TARGETS,
|
|
485
|
-
...CEILING_TARGETS,
|
|
486
|
-
],
|
|
487
464
|
previewColor: '#ffffff',
|
|
488
465
|
preset: {
|
|
489
466
|
maps: {},
|
|
@@ -514,8 +491,8 @@ export const MATERIAL_CATALOG = [
|
|
|
514
491
|
{
|
|
515
492
|
id: 'preset-metal',
|
|
516
493
|
label: 'Metal',
|
|
494
|
+
category: 'other',
|
|
517
495
|
description: 'Brushed metal finish',
|
|
518
|
-
targets: [...WALL_TARGETS, ...SLAB_TARGETS],
|
|
519
496
|
previewColor: '#c0c0c0',
|
|
520
497
|
preset: {
|
|
521
498
|
maps: {},
|
|
@@ -546,8 +523,8 @@ export const MATERIAL_CATALOG = [
|
|
|
546
523
|
{
|
|
547
524
|
id: 'preset-glass',
|
|
548
525
|
label: 'Glass',
|
|
526
|
+
category: 'other',
|
|
549
527
|
description: 'Light glass finish',
|
|
550
|
-
targets: [...WALL_TARGETS, ...SLAB_TARGETS],
|
|
551
528
|
previewColor: '#87ceeb',
|
|
552
529
|
preset: {
|
|
553
530
|
maps: {},
|
|
@@ -576,8 +553,8 @@ export const MATERIAL_CATALOG = [
|
|
|
576
553
|
},
|
|
577
554
|
},
|
|
578
555
|
];
|
|
579
|
-
export function
|
|
580
|
-
return MATERIAL_CATALOG.filter((item) => item.
|
|
556
|
+
export function getMaterialsForCategory(category) {
|
|
557
|
+
return MATERIAL_CATALOG.filter((item) => item.category === category);
|
|
581
558
|
}
|
|
582
559
|
export function getCatalogMaterialById(id) {
|
|
583
560
|
if (!id)
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/**
|
|
3
|
+
* Scheme allowlist for asset-like URLs embedded in scene graphs.
|
|
4
|
+
*
|
|
5
|
+
* Phase 3 security audit: `scan.url`, `guide.url`, `material.texture.url`, and
|
|
6
|
+
* `item.asset.src` were previously bare `z.string()`. That meant an
|
|
7
|
+
* attacker-crafted scene loaded in the editor could beacon to arbitrary URLs
|
|
8
|
+
* (e.g. `javascript:`, `file:///etc/passwd`, `http://169.254.169.254/...`).
|
|
9
|
+
*
|
|
10
|
+
* This validator rejects URLs that don't match the scheme allowlist below.
|
|
11
|
+
*/
|
|
12
|
+
declare const ALLOWED_SCHEMES: readonly ["asset:", "blob:", "https:", "data:image/"];
|
|
13
|
+
/**
|
|
14
|
+
* Optional environment variable that narrows which `https:` origins are
|
|
15
|
+
* accepted. Set to a comma-separated list (e.g. `https://cdn.pascal.app`).
|
|
16
|
+
* When unset, any `https:` origin is permitted.
|
|
17
|
+
*/
|
|
18
|
+
export declare const ALLOWED_ORIGINS_ENV = "PASCAL_ALLOWED_ASSET_ORIGINS";
|
|
19
|
+
/**
|
|
20
|
+
* Zod validator for asset-style URL fields. Accepts:
|
|
21
|
+
* - `asset://…` internal handles
|
|
22
|
+
* - `blob:…` in-memory references
|
|
23
|
+
* - `data:image/…` inline images (not `data:text/html` or other types)
|
|
24
|
+
* - `/…` app-relative paths
|
|
25
|
+
* - `https://…` public URLs (optionally narrowed to an env allowlist)
|
|
26
|
+
* - `http://localhost[:port]/…` or `http://127.0.0.1/…` for local dev
|
|
27
|
+
*
|
|
28
|
+
* Rejects every other scheme, including `javascript:`, `file:`, `ftp:`,
|
|
29
|
+
* and `data:text/html`, as well as empty strings and non-URL garbage.
|
|
30
|
+
*/
|
|
31
|
+
export declare const AssetUrl: z.ZodString;
|
|
32
|
+
export type AssetUrl = z.infer<typeof AssetUrl>;
|
|
33
|
+
export { ALLOWED_SCHEMES };
|
|
34
|
+
//# sourceMappingURL=asset-url.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"asset-url.d.ts","sourceRoot":"","sources":["../../src/schema/asset-url.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB;;;;;;;;;GASG;AACH,QAAA,MAAM,eAAe,uDAAwD,CAAA;AAE7E;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,iCAAiC,CAAA;AAuCjE;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,QAAQ,aAGnB,CAAA;AAEF,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,QAAQ,CAAC,CAAA;AAG/C,OAAO,EAAE,eAAe,EAAE,CAAA"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/**
|
|
3
|
+
* Scheme allowlist for asset-like URLs embedded in scene graphs.
|
|
4
|
+
*
|
|
5
|
+
* Phase 3 security audit: `scan.url`, `guide.url`, `material.texture.url`, and
|
|
6
|
+
* `item.asset.src` were previously bare `z.string()`. That meant an
|
|
7
|
+
* attacker-crafted scene loaded in the editor could beacon to arbitrary URLs
|
|
8
|
+
* (e.g. `javascript:`, `file:///etc/passwd`, `http://169.254.169.254/...`).
|
|
9
|
+
*
|
|
10
|
+
* This validator rejects URLs that don't match the scheme allowlist below.
|
|
11
|
+
*/
|
|
12
|
+
const ALLOWED_SCHEMES = ['asset:', 'blob:', 'https:', 'data:image/'];
|
|
13
|
+
/**
|
|
14
|
+
* Optional environment variable that narrows which `https:` origins are
|
|
15
|
+
* accepted. Set to a comma-separated list (e.g. `https://cdn.pascal.app`).
|
|
16
|
+
* When unset, any `https:` origin is permitted.
|
|
17
|
+
*/
|
|
18
|
+
export const ALLOWED_ORIGINS_ENV = 'PASCAL_ALLOWED_ASSET_ORIGINS';
|
|
19
|
+
// Narrow access to the environment variable without requiring @types/node in
|
|
20
|
+
// this package. The core package ships to both browser and Node contexts.
|
|
21
|
+
function readAllowedOrigins() {
|
|
22
|
+
const g = globalThis;
|
|
23
|
+
const value = g.process?.env?.[ALLOWED_ORIGINS_ENV];
|
|
24
|
+
if (!value)
|
|
25
|
+
return undefined;
|
|
26
|
+
const list = value
|
|
27
|
+
.split(',')
|
|
28
|
+
.map((s) => s.trim())
|
|
29
|
+
.filter((s) => s.length > 0);
|
|
30
|
+
return list.length > 0 ? list : undefined;
|
|
31
|
+
}
|
|
32
|
+
function isAllowedAssetUrl(url) {
|
|
33
|
+
if (typeof url !== 'string' || url.length === 0)
|
|
34
|
+
return false;
|
|
35
|
+
if (url.startsWith('asset://'))
|
|
36
|
+
return true; // internal handle
|
|
37
|
+
if (url.startsWith('blob:'))
|
|
38
|
+
return true; // in-memory reference
|
|
39
|
+
if (url.startsWith('data:image/'))
|
|
40
|
+
return true; // inline image only (never data:text/html)
|
|
41
|
+
if (url.startsWith('/'))
|
|
42
|
+
return true; // app-relative path
|
|
43
|
+
try {
|
|
44
|
+
const parsed = new URL(url);
|
|
45
|
+
if (parsed.protocol !== 'https:' && parsed.protocol !== 'http:')
|
|
46
|
+
return false;
|
|
47
|
+
// http is only permitted for localhost development
|
|
48
|
+
if (parsed.protocol === 'http:' && !['localhost', '127.0.0.1'].includes(parsed.hostname)) {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
// optional env-driven origin allowlist (only enforced for https URLs)
|
|
52
|
+
if (parsed.protocol === 'https:') {
|
|
53
|
+
const allowlist = readAllowedOrigins();
|
|
54
|
+
if (allowlist)
|
|
55
|
+
return allowlist.includes(parsed.origin);
|
|
56
|
+
}
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Zod validator for asset-style URL fields. Accepts:
|
|
65
|
+
* - `asset://…` internal handles
|
|
66
|
+
* - `blob:…` in-memory references
|
|
67
|
+
* - `data:image/…` inline images (not `data:text/html` or other types)
|
|
68
|
+
* - `/…` app-relative paths
|
|
69
|
+
* - `https://…` public URLs (optionally narrowed to an env allowlist)
|
|
70
|
+
* - `http://localhost[:port]/…` or `http://127.0.0.1/…` for local dev
|
|
71
|
+
*
|
|
72
|
+
* Rejects every other scheme, including `javascript:`, `file:`, `ftp:`,
|
|
73
|
+
* and `data:text/html`, as well as empty strings and non-URL garbage.
|
|
74
|
+
*/
|
|
75
|
+
export const AssetUrl = z.string().refine(isAllowedAssetUrl, {
|
|
76
|
+
message: 'URL must be asset://, blob:, data:image/, /path, or https://. http://localhost allowed for dev.',
|
|
77
|
+
});
|
|
78
|
+
// re-export the scheme allowlist for documentation / downstream validators
|
|
79
|
+
export { ALLOWED_SCHEMES };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"asset-url.test.d.ts","sourceRoot":"","sources":["../../src/schema/asset-url.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
// @ts-expect-error — bun:test is provided by the Bun runtime; core does not
|
|
2
|
+
// depend on @types/bun so the import type is unresolved at compile time.
|
|
3
|
+
// The tsconfig in packages/core still emits this file; the @ts-expect-error
|
|
4
|
+
// keeps the build green while letting `bun test` pick it up normally.
|
|
5
|
+
import { afterEach, beforeEach, describe, expect, test } from 'bun:test';
|
|
6
|
+
import { ALLOWED_ORIGINS_ENV, AssetUrl } from './asset-url';
|
|
7
|
+
function isValid(url) {
|
|
8
|
+
return AssetUrl.safeParse(url).success;
|
|
9
|
+
}
|
|
10
|
+
describe('AssetUrl', () => {
|
|
11
|
+
describe('allowed URLs', () => {
|
|
12
|
+
const cases = [
|
|
13
|
+
['asset://abc', 'internal asset handle'],
|
|
14
|
+
['asset://catalog/items/chair-1', 'nested asset handle'],
|
|
15
|
+
['blob:http://example.com/uuid-1234', 'blob URL with http inner'],
|
|
16
|
+
['blob:https://example.com/uuid-5678', 'blob URL with https inner'],
|
|
17
|
+
['https://cdn.example.com/a.glb', 'https CDN URL'],
|
|
18
|
+
['https://cdn.example.com/models/chair.glb?v=2', 'https URL with query string'],
|
|
19
|
+
['http://localhost:3000/x', 'http localhost with port'],
|
|
20
|
+
['http://localhost/x', 'http localhost without port'],
|
|
21
|
+
['http://127.0.0.1:8080/texture.png', 'http 127.0.0.1 loopback'],
|
|
22
|
+
['/public/a.glb', 'app-relative path'],
|
|
23
|
+
['/material/wood1/albedoMap_basecolor.jpg', 'relative path deep'],
|
|
24
|
+
['data:image/png;base64,AAA', 'inline PNG data URL'],
|
|
25
|
+
['data:image/jpeg;base64,/9j/', 'inline JPEG data URL'],
|
|
26
|
+
['data:image/webp;base64,UklGR', 'inline WebP data URL'],
|
|
27
|
+
['data:image/svg+xml,%3Csvg%3E', 'inline SVG data URL'],
|
|
28
|
+
];
|
|
29
|
+
for (const [url, label] of cases) {
|
|
30
|
+
test(`accepts ${label}: ${url}`, () => {
|
|
31
|
+
expect(isValid(url)).toBe(true);
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
describe('rejected URLs', () => {
|
|
36
|
+
const cases = [
|
|
37
|
+
['javascript:alert(1)', 'javascript scheme'],
|
|
38
|
+
['JAVASCRIPT:alert(1)', 'javascript scheme uppercase'],
|
|
39
|
+
['file:///etc/passwd', 'file scheme'],
|
|
40
|
+
['file://C:/Windows/System32/config', 'file scheme Windows'],
|
|
41
|
+
['http://evil.com/', 'non-loopback http'],
|
|
42
|
+
['http://example.com:3000/x', 'http on non-loopback host'],
|
|
43
|
+
['http://169.254.169.254/latest/meta-data/', 'http on link-local (cloud metadata)'],
|
|
44
|
+
['data:text/html,<script>alert(1)</script>', 'data text/html'],
|
|
45
|
+
['data:application/javascript,alert(1)', 'data application/javascript'],
|
|
46
|
+
['data:text/plain,hi', 'data text/plain'],
|
|
47
|
+
['ftp://a.b.com', 'ftp scheme'],
|
|
48
|
+
['ws://example.com/', 'websocket scheme'],
|
|
49
|
+
['vbscript:msgbox', 'vbscript scheme'],
|
|
50
|
+
['', 'empty string'],
|
|
51
|
+
['not a url at all', 'non-url string'],
|
|
52
|
+
['://missing-scheme', 'malformed'],
|
|
53
|
+
];
|
|
54
|
+
for (const [url, label] of cases) {
|
|
55
|
+
test(`rejects ${label}: ${url}`, () => {
|
|
56
|
+
expect(isValid(url)).toBe(false);
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
describe(`env allowlist via ${ALLOWED_ORIGINS_ENV}`, () => {
|
|
61
|
+
const g = globalThis;
|
|
62
|
+
const original = g.process?.env?.[ALLOWED_ORIGINS_ENV];
|
|
63
|
+
beforeEach(() => {
|
|
64
|
+
if (g.process?.env)
|
|
65
|
+
delete g.process.env[ALLOWED_ORIGINS_ENV];
|
|
66
|
+
});
|
|
67
|
+
afterEach(() => {
|
|
68
|
+
if (!g.process?.env)
|
|
69
|
+
return;
|
|
70
|
+
if (original === undefined) {
|
|
71
|
+
delete g.process.env[ALLOWED_ORIGINS_ENV];
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
g.process.env[ALLOWED_ORIGINS_ENV] = original;
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
test('single origin allowlist accepts matching https URL', () => {
|
|
78
|
+
if (!g.process?.env)
|
|
79
|
+
return; // browser-only runtime
|
|
80
|
+
g.process.env[ALLOWED_ORIGINS_ENV] = 'https://cdn.pascal.app';
|
|
81
|
+
expect(isValid('https://cdn.pascal.app/a.glb')).toBe(true);
|
|
82
|
+
expect(isValid('https://cdn.pascal.app/deep/path?q=1')).toBe(true);
|
|
83
|
+
});
|
|
84
|
+
test('single origin allowlist rejects non-matching https URL', () => {
|
|
85
|
+
if (!g.process?.env)
|
|
86
|
+
return;
|
|
87
|
+
g.process.env[ALLOWED_ORIGINS_ENV] = 'https://cdn.pascal.app';
|
|
88
|
+
expect(isValid('https://cdn.other.com/a.glb')).toBe(false);
|
|
89
|
+
expect(isValid('https://attacker.example.com/x')).toBe(false);
|
|
90
|
+
});
|
|
91
|
+
test('multi-origin allowlist accepts any listed origin', () => {
|
|
92
|
+
if (!g.process?.env)
|
|
93
|
+
return;
|
|
94
|
+
g.process.env[ALLOWED_ORIGINS_ENV] = 'https://cdn.pascal.app, https://assets.pascal.app';
|
|
95
|
+
expect(isValid('https://cdn.pascal.app/a.glb')).toBe(true);
|
|
96
|
+
expect(isValid('https://assets.pascal.app/tex.webp')).toBe(true);
|
|
97
|
+
expect(isValid('https://third.example.com/x')).toBe(false);
|
|
98
|
+
});
|
|
99
|
+
test('allowlist ignores trailing / in URL path (origin match only)', () => {
|
|
100
|
+
if (!g.process?.env)
|
|
101
|
+
return;
|
|
102
|
+
g.process.env[ALLOWED_ORIGINS_ENV] = 'https://cdn.pascal.app';
|
|
103
|
+
expect(isValid('https://cdn.pascal.app/')).toBe(true);
|
|
104
|
+
expect(isValid('https://cdn.pascal.app')).toBe(true);
|
|
105
|
+
});
|
|
106
|
+
test('empty allowlist behaves like unset', () => {
|
|
107
|
+
if (!g.process?.env)
|
|
108
|
+
return;
|
|
109
|
+
g.process.env[ALLOWED_ORIGINS_ENV] = '';
|
|
110
|
+
expect(isValid('https://cdn.other.com/a.glb')).toBe(true);
|
|
111
|
+
});
|
|
112
|
+
test('allowlist does not restrict non-https schemes', () => {
|
|
113
|
+
if (!g.process?.env)
|
|
114
|
+
return;
|
|
115
|
+
g.process.env[ALLOWED_ORIGINS_ENV] = 'https://cdn.pascal.app';
|
|
116
|
+
// these should still pass because they match earlier scheme-based branches
|
|
117
|
+
expect(isValid('asset://x')).toBe(true);
|
|
118
|
+
expect(isValid('blob:https://example.com/abc')).toBe(true);
|
|
119
|
+
expect(isValid('data:image/png;base64,AAA')).toBe(true);
|
|
120
|
+
expect(isValid('/public/a.glb')).toBe(true);
|
|
121
|
+
expect(isValid('http://localhost:3000/x')).toBe(true);
|
|
122
|
+
});
|
|
123
|
+
test('allowlist rejects subdomain spoofing', () => {
|
|
124
|
+
if (!g.process?.env)
|
|
125
|
+
return;
|
|
126
|
+
g.process.env[ALLOWED_ORIGINS_ENV] = 'https://cdn.pascal.app';
|
|
127
|
+
expect(isValid('https://cdn.pascal.app.evil.com/x')).toBe(false);
|
|
128
|
+
expect(isValid('https://evil.com/cdn.pascal.app')).toBe(false);
|
|
129
|
+
});
|
|
130
|
+
test('allowlist respects ports', () => {
|
|
131
|
+
if (!g.process?.env)
|
|
132
|
+
return;
|
|
133
|
+
g.process.env[ALLOWED_ORIGINS_ENV] = 'https://cdn.pascal.app:8443';
|
|
134
|
+
expect(isValid('https://cdn.pascal.app:8443/x')).toBe(true);
|
|
135
|
+
expect(isValid('https://cdn.pascal.app/x')).toBe(false);
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
});
|
package/dist/schema/index.d.ts
CHANGED
|
@@ -5,25 +5,27 @@ export type { MaterialMapProperties, MaterialMaps, MaterialPresetPayload, Materi
|
|
|
5
5
|
export { DEFAULT_MATERIALS, MaterialMapPropertiesSchema, MaterialMapsSchema, MaterialPreset, MaterialPresetPayloadSchema, MaterialProperties, MaterialSchema, MaterialTarget, resolveMaterial, TextureWrapMode, } from './material';
|
|
6
6
|
export { BuildingNode } from './nodes/building';
|
|
7
7
|
export { CeilingNode } from './nodes/ceiling';
|
|
8
|
+
export { COLUMN_PRESETS, ColumnBaseStyle, ColumnCapitalStyle, ColumnCarvingPlacement, ColumnCrossSection, ColumnNode, ColumnPanelShape, type ColumnPresetId, ColumnRingPlacement, ColumnShaftDetail, ColumnShaftProfile, ColumnStyle, } from './nodes/column';
|
|
8
9
|
export { DoorNode, DoorSegment } from './nodes/door';
|
|
9
10
|
export { FenceBaseStyle, FenceNode, FenceStyle } from './nodes/fence';
|
|
10
|
-
export { GuideNode } from './nodes/guide';
|
|
11
|
+
export { GuideNode, GuideScaleReference } from './nodes/guide';
|
|
11
12
|
export type { AnimationEffect, Asset, AssetInput, Control, Effect, Interactive, LightEffect, SliderControl, TemperatureControl, ToggleControl, } from './nodes/item';
|
|
12
|
-
export { getScaledDimensions, ItemNode } from './nodes/item';
|
|
13
|
+
export { getScaledDimensions, ItemNode, isLowProfileItemSurface, LOW_PROFILE_ITEM_SURFACE_MAX_HEIGHT, } from './nodes/item';
|
|
13
14
|
export { LevelNode } from './nodes/level';
|
|
14
|
-
export { getEffectiveRoofSurfaceMaterial, RoofNode } from './nodes/roof';
|
|
15
15
|
export type { RoofSurfaceMaterialRole, RoofSurfaceMaterialSpec } from './nodes/roof';
|
|
16
|
+
export { getEffectiveRoofSurfaceMaterial, RoofNode } from './nodes/roof';
|
|
16
17
|
export { RoofSegmentNode, RoofType } from './nodes/roof-segment';
|
|
17
18
|
export { ScanNode } from './nodes/scan';
|
|
18
19
|
export { SiteNode } from './nodes/site';
|
|
19
20
|
export { SlabNode } from './nodes/slab';
|
|
20
|
-
export {
|
|
21
|
+
export { SpawnNode } from './nodes/spawn';
|
|
21
22
|
export type { StairSurfaceMaterialRole, StairSurfaceMaterialSpec } from './nodes/stair';
|
|
23
|
+
export { getEffectiveStairSurfaceMaterial, StairNode, StairRailingMode, StairSlabOpeningMode, StairTopLandingMode, StairType, } from './nodes/stair';
|
|
22
24
|
export { AttachmentSide, StairSegmentNode, StairSegmentType } from './nodes/stair-segment';
|
|
23
25
|
export { SurfaceHoleMetadata } from './nodes/surface-hole-metadata';
|
|
24
26
|
export type { WallSurfaceMaterialSpec, WallSurfaceSide } from './nodes/wall';
|
|
25
27
|
export { getEffectiveWallSurfaceMaterial, getWallSurfaceMaterialSignature, WallNode, } from './nodes/wall';
|
|
26
|
-
export { WindowNode } from './nodes/window';
|
|
28
|
+
export { WindowNode, WindowType } from './nodes/window';
|
|
27
29
|
export { ZoneNode } from './nodes/zone';
|
|
28
30
|
export type { AnyNodeId, AnyNodeType } from './types';
|
|
29
31
|
export { AnyNode } from './types';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/schema/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAA;AAE3E,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AAEvC,OAAO,EAAE,KAAK,UAAU,EAAE,KAAK,YAAY,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAA;AACxF,YAAY,EACV,qBAAqB,EACrB,YAAY,EACZ,qBAAqB,EACrB,cAAc,IAAI,mBAAmB,EACrC,eAAe,IAAI,oBAAoB,GACxC,MAAM,YAAY,CAAA;AAEnB,OAAO,EACL,iBAAiB,EACjB,2BAA2B,EAC3B,kBAAkB,EAClB,cAAc,EACd,2BAA2B,EAC3B,kBAAkB,EAClB,cAAc,EACd,cAAc,EACd,eAAe,EACf,eAAe,GAChB,MAAM,YAAY,CAAA;AACnB,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAC7C,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AACpD,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AACrE,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/schema/index.ts"],"names":[],"mappings":"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"}
|
package/dist/schema/index.js
CHANGED
|
@@ -8,10 +8,11 @@ export { generateCollectionId } from './collections';
|
|
|
8
8
|
export { DEFAULT_MATERIALS, MaterialMapPropertiesSchema, MaterialMapsSchema, MaterialPreset, MaterialPresetPayloadSchema, MaterialProperties, MaterialSchema, MaterialTarget, resolveMaterial, TextureWrapMode, } from './material';
|
|
9
9
|
export { BuildingNode } from './nodes/building';
|
|
10
10
|
export { CeilingNode } from './nodes/ceiling';
|
|
11
|
+
export { COLUMN_PRESETS, ColumnBaseStyle, ColumnCapitalStyle, ColumnCarvingPlacement, ColumnCrossSection, ColumnNode, ColumnPanelShape, ColumnRingPlacement, ColumnShaftDetail, ColumnShaftProfile, ColumnStyle, } from './nodes/column';
|
|
11
12
|
export { DoorNode, DoorSegment } from './nodes/door';
|
|
12
13
|
export { FenceBaseStyle, FenceNode, FenceStyle } from './nodes/fence';
|
|
13
|
-
export { GuideNode } from './nodes/guide';
|
|
14
|
-
export { getScaledDimensions, ItemNode } from './nodes/item';
|
|
14
|
+
export { GuideNode, GuideScaleReference } from './nodes/guide';
|
|
15
|
+
export { getScaledDimensions, ItemNode, isLowProfileItemSurface, LOW_PROFILE_ITEM_SURFACE_MAX_HEIGHT, } from './nodes/item';
|
|
15
16
|
export { LevelNode } from './nodes/level';
|
|
16
17
|
export { getEffectiveRoofSurfaceMaterial, RoofNode } from './nodes/roof';
|
|
17
18
|
export { RoofSegmentNode, RoofType } from './nodes/roof-segment';
|
|
@@ -19,11 +20,12 @@ export { ScanNode } from './nodes/scan';
|
|
|
19
20
|
// Nodes
|
|
20
21
|
export { SiteNode } from './nodes/site';
|
|
21
22
|
export { SlabNode } from './nodes/slab';
|
|
23
|
+
export { SpawnNode } from './nodes/spawn';
|
|
22
24
|
export { getEffectiveStairSurfaceMaterial, StairNode, StairRailingMode, StairSlabOpeningMode, StairTopLandingMode, StairType, } from './nodes/stair';
|
|
23
25
|
export { AttachmentSide, StairSegmentNode, StairSegmentType } from './nodes/stair-segment';
|
|
24
26
|
export { SurfaceHoleMetadata } from './nodes/surface-hole-metadata';
|
|
25
27
|
export { getEffectiveWallSurfaceMaterial, getWallSurfaceMaterialSignature, WallNode, } from './nodes/wall';
|
|
26
|
-
export { WindowNode } from './nodes/window';
|
|
28
|
+
export { WindowNode, WindowType } from './nodes/window';
|
|
27
29
|
export { ZoneNode } from './nodes/zone';
|
|
28
30
|
// Union types
|
|
29
31
|
export { AnyNode } from './types';
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
export declare const MaterialPreset: z.ZodEnum<{
|
|
3
|
-
custom: "custom";
|
|
4
3
|
white: "white";
|
|
5
4
|
brick: "brick";
|
|
6
5
|
concrete: "concrete";
|
|
@@ -10,6 +9,7 @@ export declare const MaterialPreset: z.ZodEnum<{
|
|
|
10
9
|
plaster: "plaster";
|
|
11
10
|
tile: "tile";
|
|
12
11
|
marble: "marble";
|
|
12
|
+
custom: "custom";
|
|
13
13
|
}>;
|
|
14
14
|
export type MaterialPreset = z.infer<typeof MaterialPreset>;
|
|
15
15
|
export declare const MaterialProperties: z.ZodObject<{
|
|
@@ -28,7 +28,6 @@ export type MaterialProperties = z.infer<typeof MaterialProperties>;
|
|
|
28
28
|
export declare const MaterialSchema: z.ZodObject<{
|
|
29
29
|
id: z.ZodOptional<z.ZodString>;
|
|
30
30
|
preset: z.ZodOptional<z.ZodEnum<{
|
|
31
|
-
custom: "custom";
|
|
32
31
|
white: "white";
|
|
33
32
|
brick: "brick";
|
|
34
33
|
concrete: "concrete";
|
|
@@ -38,6 +37,7 @@ export declare const MaterialSchema: z.ZodObject<{
|
|
|
38
37
|
plaster: "plaster";
|
|
39
38
|
tile: "tile";
|
|
40
39
|
marble: "marble";
|
|
40
|
+
custom: "custom";
|
|
41
41
|
}>>;
|
|
42
42
|
properties: z.ZodOptional<z.ZodObject<{
|
|
43
43
|
color: z.ZodDefault<z.ZodString>;
|
|
@@ -65,6 +65,7 @@ export declare const MaterialTarget: z.ZodEnum<{
|
|
|
65
65
|
stair: "stair";
|
|
66
66
|
"stair-segment": "stair-segment";
|
|
67
67
|
fence: "fence";
|
|
68
|
+
column: "column";
|
|
68
69
|
slab: "slab";
|
|
69
70
|
ceiling: "ceiling";
|
|
70
71
|
door: "door";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"material.d.ts","sourceRoot":"","sources":["../../src/schema/material.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;
|
|
1
|
+
{"version":3,"file":"material.d.ts","sourceRoot":"","sources":["../../src/schema/material.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAGvB,eAAO,MAAM,cAAc;;;;;;;;;;;EAWzB,CAAA;AACF,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAA;AAE3D,eAAO,MAAM,kBAAkB;;;;;;;;;;;iBAO7B,CAAA;AACF,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAA;AAEnE,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAWzB,CAAA;AACF,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAA;AAE3D,eAAO,MAAM,cAAc;;;;;;;;;;;;EAYzB,CAAA;AACF,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAA;AAE3D,eAAO,MAAM,eAAe;;;;EAAsD,CAAA;AAClF,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAA;AAE7D,eAAO,MAAM,kBAAkB;;;;;;;;;;;iBAW7B,CAAA;AACF,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAA;AAE7D,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAqBtC,CAAA;AACF,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,2BAA2B,CAAC,CAAA;AAE/E,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAGtC,CAAA;AACF,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,2BAA2B,CAAC,CAAA;AAE/E,eAAO,MAAM,iBAAiB,EAAE,MAAM,CAAC,cAAc,EAAE,kBAAkB,CAiFxE,CAAA;AAED,wBAAgB,eAAe,CAAC,QAAQ,CAAC,EAAE,cAAc,GAAG,kBAAkB,CAiB7E"}
|
package/dist/schema/material.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
+
import { AssetUrl } from './asset-url';
|
|
2
3
|
export const MaterialPreset = z.enum([
|
|
3
4
|
'white',
|
|
4
5
|
'brick',
|
|
@@ -25,7 +26,7 @@ export const MaterialSchema = z.object({
|
|
|
25
26
|
properties: MaterialProperties.optional(),
|
|
26
27
|
texture: z
|
|
27
28
|
.object({
|
|
28
|
-
url:
|
|
29
|
+
url: AssetUrl,
|
|
29
30
|
repeat: z.tuple([z.number(), z.number()]).optional(),
|
|
30
31
|
scale: z.number().optional(),
|
|
31
32
|
})
|
|
@@ -38,6 +39,7 @@ export const MaterialTarget = z.enum([
|
|
|
38
39
|
'stair',
|
|
39
40
|
'stair-segment',
|
|
40
41
|
'fence',
|
|
42
|
+
'column',
|
|
41
43
|
'slab',
|
|
42
44
|
'ceiling',
|
|
43
45
|
'door',
|
|
@@ -45,16 +47,16 @@ export const MaterialTarget = z.enum([
|
|
|
45
47
|
]);
|
|
46
48
|
export const TextureWrapMode = z.enum(['Repeat', 'ClampToEdge', 'MirroredRepeat']);
|
|
47
49
|
export const MaterialMapsSchema = z.object({
|
|
48
|
-
albedoMap:
|
|
49
|
-
metalnessMap:
|
|
50
|
-
roughnessMap:
|
|
51
|
-
normalMap:
|
|
52
|
-
displacementMap:
|
|
53
|
-
aoMap:
|
|
54
|
-
emissiveMap:
|
|
55
|
-
bumpMap:
|
|
56
|
-
alphaMap:
|
|
57
|
-
lightMap:
|
|
50
|
+
albedoMap: AssetUrl.optional(),
|
|
51
|
+
metalnessMap: AssetUrl.optional(),
|
|
52
|
+
roughnessMap: AssetUrl.optional(),
|
|
53
|
+
normalMap: AssetUrl.optional(),
|
|
54
|
+
displacementMap: AssetUrl.optional(),
|
|
55
|
+
aoMap: AssetUrl.optional(),
|
|
56
|
+
emissiveMap: AssetUrl.optional(),
|
|
57
|
+
bumpMap: AssetUrl.optional(),
|
|
58
|
+
alphaMap: AssetUrl.optional(),
|
|
59
|
+
lightMap: AssetUrl.optional(),
|
|
58
60
|
});
|
|
59
61
|
export const MaterialMapPropertiesSchema = z.object({
|
|
60
62
|
color: z.string().default('#ffffff'),
|
|
@@ -21,7 +21,6 @@ export declare const CeilingNode: z.ZodObject<{
|
|
|
21
21
|
material: z.ZodOptional<z.ZodObject<{
|
|
22
22
|
id: z.ZodOptional<z.ZodString>;
|
|
23
23
|
preset: z.ZodOptional<z.ZodEnum<{
|
|
24
|
-
custom: "custom";
|
|
25
24
|
white: "white";
|
|
26
25
|
brick: "brick";
|
|
27
26
|
concrete: "concrete";
|
|
@@ -31,6 +30,7 @@ export declare const CeilingNode: z.ZodObject<{
|
|
|
31
30
|
plaster: "plaster";
|
|
32
31
|
tile: "tile";
|
|
33
32
|
marble: "marble";
|
|
33
|
+
custom: "custom";
|
|
34
34
|
}>>;
|
|
35
35
|
properties: z.ZodOptional<z.ZodObject<{
|
|
36
36
|
color: z.ZodDefault<z.ZodString>;
|