Spaces:
Running on RTX PRO 6000
Running on RTX PRO 6000
Explorer slim-ui-9d95b298 (download selection carried to the Space's own tab, clearer folder hint) + caches for the 100-user target (indexing #80 at 6adbe77)
Browse filesDist 9d95b298 = 7b12d13c (#83) + 9d95b298. #80: verdict L2 4M (config.py), Redis --maxmemory 6gb volatile-lru, /llm_parse nginx cache per day, parse LRU off, /metrics + pipeline/cache_metrics.py. Runtime files on prod's rails (nginx -t on 1.22/1.24; supervisor 4.2.5 parse + sh -n on every program). Rollback: ~/dev/hf-space-work/batch-1015/rollback-a8ebc429.
- docker/hf-space/nginx.conf.template +145 -7
- docker/hf-space/supervisord-gpu.conf +31 -2
- docker/hf-space/supervisord.conf +31 -2
- pipeline/cache_metrics.py +260 -0
- pipeline/config.py +4 -3
- services/explorer/dist/build-info.json +3 -3
- services/explorer/dist/index.html +1 -1
- services/explorer/dist/static/js/298.4bcf08c3.chunk.js +1 -0
- services/explorer/dist/static/js/hash-wasm.d37b139f.chunk.js +2 -0
- services/explorer/dist/static/js/hash-wasm.d37b139f.chunk.js.LICENSE.txt +5 -0
- services/explorer/dist/static/js/main.846b9fc7.js +0 -0
- services/explorer/dist/static/js/main.846b9fc7.js.LICENSE.txt +39 -0
- services/explorer/dist/static/usd-reader/81290bc/esm/errors.js +15 -0
- services/explorer/dist/static/usd-reader/81290bc/esm/hub-prefetch.js +94 -0
- services/explorer/dist/static/usd-reader/81290bc/esm/load-core.js +760 -0
- services/explorer/dist/static/usd-reader/81290bc/esm/worker.js +150 -0
- services/explorer/dist/static/usd-reader/81290bc/wasm/usd_wasm.js +760 -0
- services/explorer/dist/static/usd-reader/81290bc/wasm/usd_wasm_bg.wasm +3 -0
- services/explorer/dist/third-party-notices.txt +1 -1
docker/hf-space/nginx.conf.template
CHANGED
|
@@ -34,9 +34,61 @@
|
|
| 34 |
# nothing in this image pre-creates a parent — /tmp/nginx-cache/slim-stats fails `nginx -t`. The
|
| 35 |
# `levels=` subdirectories are different: nginx creates those itself on the first write.
|
| 36 |
proxy_cache_path /tmp/slim-stats-cache levels=1 keys_zone=slim_stats_cache:2m max_size=256m inactive=1h use_temp_path=off;
|
| 37 |
-
# Thumbnails (/images): ~1,500 JPEGs of 27-52 KB (~75 MB)
|
| 38 |
-
# /tmp, so every deploy, restart or sleep starts it cold.
|
| 39 |
-
proxy_cache_path /tmp/slim-images-cache levels=1:2 keys_zone=slim_images_cache:10m max_size=
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 40 |
# Library media (/library_media/ below): a file asked for under its ?v= (its content hash) never changes; the
|
| 41 |
# manifest (no ?v=) revalidates, so a new fetch at the next container start shows at once.
|
| 42 |
map $arg_v $slim_library_cache {
|
|
@@ -148,12 +200,17 @@ server {
|
|
| 148 |
# UI/ReDoc can request sub-resources under their own path.
|
| 149 |
location = /health { proxy_pass http://127.0.0.1:8000; }
|
| 150 |
location = /openapi.json { proxy_pass http://127.0.0.1:8000; }
|
| 151 |
-
#
|
| 152 |
-
#
|
| 153 |
-
#
|
|
|
|
| 154 |
location = /metrics {
|
|
|
|
|
|
|
|
|
|
|
|
|
| 155 |
default_type application/json;
|
| 156 |
-
return
|
| 157 |
}
|
| 158 |
location /docs { proxy_pass http://127.0.0.1:8000; }
|
| 159 |
location /redoc { proxy_pass http://127.0.0.1:8000; }
|
|
@@ -178,6 +235,10 @@ server {
|
|
| 178 |
# add_header inside one of our locations replaces his server-level headers for THOSE responses
|
| 179 |
# — /images and the stats cache re-declare his three CORS lines, /config.js and /index.html
|
| 180 |
# (same-origin UI files) do not. Applied by slim/devspace/deploy.sh.
|
|
|
|
|
|
|
|
|
|
|
|
|
| 181 |
client_max_body_size 32m; # query-image searches POST a base64 JPEG (nginx default 1 MB)
|
| 182 |
gzip_types text/css application/javascript application/json image/svg+xml; # stock gzip covers text/html only
|
| 183 |
|
|
@@ -280,6 +341,83 @@ server {
|
|
| 280 |
add_header Access-Control-Allow-Methods "GET, POST, OPTIONS" always;
|
| 281 |
add_header Access-Control-Allow-Headers "Content-Type, Authorization" always;
|
| 282 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 283 |
# Our 404s are JSON like the API's own (a bare `return 404;` would be nginx's text/html error
|
| 284 |
# page): reachable only from the locations below, so nothing of his changes.
|
| 285 |
location @slim_not_found {
|
|
|
|
| 34 |
# nothing in this image pre-creates a parent — /tmp/nginx-cache/slim-stats fails `nginx -t`. The
|
| 35 |
# `levels=` subdirectories are different: nginx creates those itself on the first write.
|
| 36 |
proxy_cache_path /tmp/slim-stats-cache levels=1 keys_zone=slim_stats_cache:2m max_size=256m inactive=1h use_temp_path=off;
|
| 37 |
+
# Thumbnails (/images): ~1,500 JPEGs of 27-52 KB (~75 MB) per view set; 5g leaves room for every view and size
|
| 38 |
+
# the Explorer asks for. Lives in the container's /tmp, so every deploy, restart or sleep starts it cold.
|
| 39 |
+
proxy_cache_path /tmp/slim-images-cache levels=1:2 keys_zone=slim_images_cache:10m max_size=5g inactive=7d use_temp_path=off;
|
| 40 |
+
# Query parses (/llm_parse/query, below): one entry per day and request body, kept 24 h. The day is in the key
|
| 41 |
+
# because the parser's prompt carries today's date: "made last week" parses differently tomorrow. Sized for a day at
|
| 42 |
+
# 100 users (~186k new keys: 1 MB of zone holds ~8k keys; each entry takes at least one 4 KB block on disk).
|
| 43 |
+
proxy_cache_path /tmp/slim-parse-cache levels=1:2 keys_zone=slim_parse_cache:24m max_size=1g inactive=24h use_temp_path=off;
|
| 44 |
+
# The Explorer's background count probes (/search_hybrid, below) for 30 min. A user's search is never cached: every
|
| 45 |
+
# one reaches deepsearch-api, whose usage telemetry must see it (owner, 2026-10-15).
|
| 46 |
+
# All the caches' caps add up to ~6.3 GB of the container's disk (the Space's storage limit counts it).
|
| 47 |
+
proxy_cache_path /tmp/slim-count-cache levels=1:2 keys_zone=slim_count_cache:2m max_size=64m inactive=30m use_temp_path=off;
|
| 48 |
+
# Today's date for the parse key, in nginx's time zone, which is the parser's (date.today()): the container sets no
|
| 49 |
+
# TZ, so both read UTC.
|
| 50 |
+
map $time_iso8601 $slim_today {
|
| 51 |
+
default "";
|
| 52 |
+
"~^(\d{4}-\d{2}-\d{2})" $1;
|
| 53 |
+
}
|
| 54 |
+
# proxy_cache_methods POST ADDS POST (nginx caches GET and HEAD anyway): anything but a POST bypasses those caches
|
| 55 |
+
# and is never stored.
|
| 56 |
+
map $request_method $slim_not_post {
|
| 57 |
+
default 1;
|
| 58 |
+
POST "";
|
| 59 |
+
}
|
| 60 |
+
# A count probe is the Explorer's (utils/backendCounts.js): x-simready-cache-intent: 1, its service-account Basic user
|
| 61 |
+
# simready-central-svc-user, and no x-api-key. deepsearch-api's search telemetry (search_query_total) records the
|
| 62 |
+
# query's username from exactly these headers: the API key's "admin_access" first, else the Basic user. So a cached
|
| 63 |
+
# probe hides only service-account events, never a user's search. Anything else (a user's search, the header alone,
|
| 64 |
+
# another user) reaches the API. Case-sensitive, as the telemetry's username is.
|
| 65 |
+
map "$http_x_simready_cache_intent|$remote_user|$http_x_api_key" $slim_count_probe {
|
| 66 |
+
default "";
|
| 67 |
+
"~^1\|simready-central-svc-user\|$" 1;
|
| 68 |
+
}
|
| 69 |
+
# Never cached, even for a probe: a body with a cursor or a non-zero offset (a later page), or with an image to
|
| 70 |
+
# search by (an image vector query, image_similarity_search), or one that asks the API to validate its results
|
| 71 |
+
# (validate_results: missing verdicts would stick). JSON escapes a quote inside a string, so the words in a query
|
| 72 |
+
# cannot match these.
|
| 73 |
+
map $request_body $slim_probe_skip {
|
| 74 |
+
default "";
|
| 75 |
+
"~\"cursor\"\s*:\s*(?!null\b)" 1;
|
| 76 |
+
"~\"offset\"\s*:\s*0*[1-9]" 1;
|
| 77 |
+
"~\"query_type\"\s*:\s*\"image\"" 1;
|
| 78 |
+
"~\"image_similarity_search\"\s*:\s*(?!null\b)" 1;
|
| 79 |
+
"~\"validate_results\"\s*:\s*true" 1;
|
| 80 |
+
}
|
| 81 |
+
# /metrics' nginx counts (pipeline/cache_metrics.py): one syslog datagram per request of a cached route, carrying
|
| 82 |
+
# the cache and $upstream_cache_status; nothing of the request itself. The source is $slim_count_probe ("" or 1)
|
| 83 |
+
# then the URI: /search_hybrid counts only as a probe, so a user's search sends nothing.
|
| 84 |
+
map "$slim_count_probe$request_uri" $slim_cache_route {
|
| 85 |
+
default "";
|
| 86 |
+
"~^1?/llm_parse/query(\?|$)" parse;
|
| 87 |
+
"~^1/search_hybrid(\?|$)" count;
|
| 88 |
+
"~^1?/images(\?|$)" images;
|
| 89 |
+
"~^1?/search/stats/usd_properties(\?|$)" stats;
|
| 90 |
+
}
|
| 91 |
+
log_format slim_cache_status '$slim_cache_route $upstream_cache_status';
|
| 92 |
# Library media (/library_media/ below): a file asked for under its ?v= (its content hash) never changes; the
|
| 93 |
# manifest (no ?v=) revalidates, so a new fetch at the next container start shows at once.
|
| 94 |
map $arg_v $slim_library_cache {
|
|
|
|
| 200 |
# UI/ReDoc can request sub-resources under their own path.
|
| 201 |
location = /health { proxy_pass http://127.0.0.1:8000; }
|
| 202 |
location = /openapi.json { proxy_pass http://127.0.0.1:8000; }
|
| 203 |
+
# /metrics is NOT deepsearch-api's (127.0.0.1:8000/metrics stays private to
|
| 204 |
+
# the container): it is pipeline/cache_metrics.py's page, an allow-list of
|
| 205 |
+
# cache hit/miss counters (supervisord program cache-metrics). Not up yet:
|
| 206 |
+
# a JSON 503, never the SPA's index.html.
|
| 207 |
location = /metrics {
|
| 208 |
+
proxy_pass http://127.0.0.1:8030/metrics;
|
| 209 |
+
error_page 502 504 = @slim_metrics_unavailable;
|
| 210 |
+
}
|
| 211 |
+
location @slim_metrics_unavailable {
|
| 212 |
default_type application/json;
|
| 213 |
+
return 503 '{"detail":"cache metrics are not running"}';
|
| 214 |
}
|
| 215 |
location /docs { proxy_pass http://127.0.0.1:8000; }
|
| 216 |
location /redoc { proxy_pass http://127.0.0.1:8000; }
|
|
|
|
| 235 |
# add_header inside one of our locations replaces his server-level headers for THOSE responses
|
| 236 |
# — /images and the stats cache re-declare his three CORS lines, /config.js and /index.html
|
| 237 |
# (same-origin UI files) do not. Applied by slim/devspace/deploy.sh.
|
| 238 |
+
# Also here (2026-10-15, for 100 users): the parse cache `= /llm_parse/query` and the count-probe cache, which
|
| 239 |
+
# `= /search_hybrid` routes probes to (each takes his prefix's requests like `= /images`; a user's search keeps
|
| 240 |
+
# his rewrite + proxy_pass, uncached), and a server-level access_log that feeds the /metrics page in place of the
|
| 241 |
+
# stock file log (his `= /metrics` 404 now serves it; deepsearch-api's own metrics stay private).
|
| 242 |
client_max_body_size 32m; # query-image searches POST a base64 JPEG (nginx default 1 MB)
|
| 243 |
gzip_types text/css application/javascript application/json image/svg+xml; # stock gzip covers text/html only
|
| 244 |
|
|
|
|
| 341 |
add_header Access-Control-Allow-Methods "GET, POST, OPTIONS" always;
|
| 342 |
add_header Access-Control-Allow-Headers "Content-Type, Authorization" always;
|
| 343 |
}
|
| 344 |
+
# The two POST caches below (parses, count probes) share these rules, ported from SimReady Central's gateway: the
|
| 345 |
+
# key holds the raw request body; POST only ($slim_not_post); 200s only (the API answers a failed parse or search
|
| 346 |
+
# with an error status); the API's no-store is ignored for the cache and still reaches the browser. SHARED by
|
| 347 |
+
# every member, keyed on the body alone: valid ONLY while the image runs with ENABLE_ACCESS_VERIFICATION=False,
|
| 348 |
+
# STORAGE_REQUIRE_AUTH=False and verify_access=false (every member sees the same results;
|
| 349 |
+
# tests/test_hf_space_caches.py checks both Dockerfiles). A body past client_body_buffer_size spills to disk and
|
| 350 |
+
# leaves $request_body empty: $request_body_file (set only then) keeps it out, else all such bodies would share
|
| 351 |
+
# one key. proxy_buffer_size must hold the cache file's header with its key, or nginx stores entries it never
|
| 352 |
+
# reads back. proxy_cache_lock: concurrent identical requests wait up to 15 s for the first one (lock_age too: a
|
| 353 |
+
# parse can outlast nginx's default 5 s) instead of all reaching the API.
|
| 354 |
+
#
|
| 355 |
+
# Query parsing: his /llm_parse/ rewrite + proxy_pass (this exact match wins over his prefix) plus the cache.
|
| 356 |
+
# A parse costs 0.5-9 s on the endpoint and depends only on the body and the day (the prompt's $today): the
|
| 357 |
+
# key is day + URI + body, kept 24 h. A prompt or model change is a restart, which empties /tmp.
|
| 358 |
+
location = /llm_parse/query {
|
| 359 |
+
if ($request_method = OPTIONS) { add_header Content-Length 0 always; add_header Content-Type "text/plain" always; return 204; }
|
| 360 |
+
rewrite ^/llm_parse/(.*)$ /v3/deepsearch/llm_parse/$1 break;
|
| 361 |
+
proxy_pass http://127.0.0.1:8000;
|
| 362 |
+
proxy_cache slim_parse_cache;
|
| 363 |
+
proxy_cache_key "$slim_today|$request_uri|$request_body";
|
| 364 |
+
proxy_cache_bypass $slim_not_post $request_body_file;
|
| 365 |
+
proxy_no_cache $slim_not_post $request_body_file;
|
| 366 |
+
proxy_cache_valid 200 24h;
|
| 367 |
+
proxy_cache_methods POST;
|
| 368 |
+
proxy_ignore_headers Cache-Control Expires;
|
| 369 |
+
proxy_cache_lock on;
|
| 370 |
+
proxy_cache_lock_timeout 15s;
|
| 371 |
+
proxy_cache_lock_age 15s;
|
| 372 |
+
client_body_buffer_size 32k;
|
| 373 |
+
proxy_buffer_size 60k;
|
| 374 |
+
proxy_buffers 16 8k;
|
| 375 |
+
proxy_hide_header X-Cache-Status;
|
| 376 |
+
add_header X-Cache-Status $upstream_cache_status always;
|
| 377 |
+
add_header Access-Control-Allow-Origin "*" always;
|
| 378 |
+
add_header Access-Control-Allow-Methods "GET, POST, OPTIONS" always;
|
| 379 |
+
add_header Access-Control-Allow-Headers "Content-Type, Authorization" always;
|
| 380 |
+
}
|
| 381 |
+
# Searches: NEVER cached (owner, 2026-10-15). Every search a user sends takes his /search_hybrid rewrite +
|
| 382 |
+
# proxy_pass, unchanged, and reaches deepsearch-api, whose usage telemetry (search_query_total) must see each
|
| 383 |
+
# one. This exact match exists only to send the Explorer's count probes ($slim_count_probe) to their cache.
|
| 384 |
+
location = /search_hybrid {
|
| 385 |
+
if ($request_method = OPTIONS) { add_header Content-Length 0 always; add_header Content-Type "text/plain" always; return 204; }
|
| 386 |
+
if ($slim_count_probe) { rewrite ^ /_slim_count_probe last; }
|
| 387 |
+
rewrite ^/search_hybrid(.*)$ /v3/deepsearch/search$1 break;
|
| 388 |
+
proxy_pass http://127.0.0.1:8000;
|
| 389 |
+
}
|
| 390 |
+
# The Explorer's background count probes (limit-1 and file-name searches for its totals; SimReady Central's
|
| 391 |
+
# gateway caches them the same way): their own zone, 30 min, stale while one request refreshes an entry. Never a
|
| 392 |
+
# later page, an image search or validate_results ($slim_probe_skip).
|
| 393 |
+
location = /_slim_count_probe {
|
| 394 |
+
internal;
|
| 395 |
+
rewrite ^ /v3/deepsearch/search break;
|
| 396 |
+
proxy_pass http://127.0.0.1:8000;
|
| 397 |
+
proxy_cache slim_count_cache;
|
| 398 |
+
proxy_cache_key "$request_uri|$request_body";
|
| 399 |
+
proxy_cache_bypass $slim_not_post $request_body_file $slim_probe_skip;
|
| 400 |
+
proxy_no_cache $slim_not_post $request_body_file $slim_probe_skip;
|
| 401 |
+
proxy_cache_valid 200 30m;
|
| 402 |
+
proxy_cache_use_stale updating;
|
| 403 |
+
proxy_cache_methods POST;
|
| 404 |
+
proxy_ignore_headers Cache-Control Expires;
|
| 405 |
+
proxy_cache_lock on;
|
| 406 |
+
proxy_cache_lock_timeout 15s;
|
| 407 |
+
proxy_cache_lock_age 15s;
|
| 408 |
+
client_body_buffer_size 32k;
|
| 409 |
+
proxy_buffer_size 60k;
|
| 410 |
+
proxy_buffers 16 8k;
|
| 411 |
+
proxy_hide_header X-Cache-Status;
|
| 412 |
+
add_header X-Cache-Status $upstream_cache_status always;
|
| 413 |
+
add_header Access-Control-Allow-Origin "*" always;
|
| 414 |
+
add_header Access-Control-Allow-Methods "GET, POST, OPTIONS" always;
|
| 415 |
+
add_header Access-Control-Allow-Headers "Content-Type, Authorization" always;
|
| 416 |
+
}
|
| 417 |
+
# A cached route's request goes to /metrics' counts (see $slim_cache_route). This server-level access_log
|
| 418 |
+
# replaces nginx.conf's file log (/var/log/nginx/access.log): nothing rotated it and nobody can read it in a
|
| 419 |
+
# Space, yet every request grew it on the container's disk.
|
| 420 |
+
access_log syslog:server=127.0.0.1:8031,tag=slimcache,nohostname slim_cache_status if=$slim_cache_route;
|
| 421 |
# Our 404s are JSON like the API's own (a bare `return 404;` would be nginx's text/html error
|
| 422 |
# page): reachable only from the locations below, so nothing of his changes.
|
| 423 |
location @slim_not_found {
|
docker/hf-space/supervisord-gpu.conf
CHANGED
|
@@ -27,7 +27,12 @@ stderr_logfile=/dev/stderr
|
|
| 27 |
stderr_logfile_maxbytes=0
|
| 28 |
|
| 29 |
[program:redis]
|
| 30 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 31 |
user=1000
|
| 32 |
autorestart=true
|
| 33 |
startsecs=3
|
|
@@ -160,7 +165,13 @@ stderr_logfile_maxbytes=0
|
|
| 160 |
; pipeline/hf_space_seed.py, same "don't exec uvicorn until every backend
|
| 161 |
; this process depends on is actually ready" rule the cpu-basic/NVCF
|
| 162 |
; variant already follows for OpenSearch.
|
| 163 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 164 |
directory=/app
|
| 165 |
user=1000
|
| 166 |
autorestart=true
|
|
@@ -170,6 +181,24 @@ stdout_logfile_maxbytes=0
|
|
| 170 |
stderr_logfile=/dev/stderr
|
| 171 |
stderr_logfile_maxbytes=0
|
| 172 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 173 |
[program:nginx]
|
| 174 |
; See docker/hf-space/supervisord.conf's own copy (identical command). Never put
|
| 175 |
; a space before a ";" or "#" in a command: supervisord reads it as an inline
|
|
|
|
| 27 |
stderr_logfile_maxbytes=0
|
| 28 |
|
| 29 |
[program:redis]
|
| 30 |
+
; Holds only deepsearch-api's caches, all in DB 0 by key prefix: the VLM verdicts (usdsearch:vlmval:v1, no TTL,
|
| 31 |
+
; capped at USDSEARCH_VISION_VALIDATION_CACHE_MAX_ENTRIES by the app's own LRU), the RRF page rankings behind
|
| 32 |
+
; search cursors (usdsearch:rrfpage:v1, 15-min TTL) and the image-id resolutions (TTL). No indexing streams run
|
| 33 |
+
; here. --maxmemory 6gb is a guard above the 4M verdicts (~1.8 GB); volatile-lru evicts only keys with a TTL,
|
| 34 |
+
; the two caches a miss recomputes, never a verdict or an LRU index. Nothing is saved: a restart starts cold.
|
| 35 |
+
command=/usr/bin/redis-server --port 6379 --databases 32 --save "" --stop-writes-on-bgsave-error no --dir /tmp --maxmemory 6gb --maxmemory-policy volatile-lru
|
| 36 |
user=1000
|
| 37 |
autorestart=true
|
| 38 |
startsecs=3
|
|
|
|
| 165 |
; pipeline/hf_space_seed.py, same "don't exec uvicorn until every backend
|
| 166 |
; this process depends on is actually ready" rule the cpu-basic/NVCF
|
| 167 |
; variant already follows for OpenSearch.
|
| 168 |
+
; PROMETHEUS_MULTIPROC_DIR (emptied at every start): the workers share their
|
| 169 |
+
; metrics through files there, so a counter is the sum over all workers;
|
| 170 |
+
; [program:cache-metrics] reads its cache counters from them.
|
| 171 |
+
; USDSEARCH_LLM_PARSING_CACHE_SIZE 0 (a Space variable overrides it): no
|
| 172 |
+
; per-worker parse LRU. Its key has no date, so after midnight it answered
|
| 173 |
+
; "made last week" with yesterday's parse; nginx caches parses per day instead.
|
| 174 |
+
command=/usr/bin/env -u PYTHONPATH /bin/sh -c "until curl -sf http://localhost:8003/v2/health/ready >/dev/null 2>&1; do sleep 2; done; cd /app/hf-space-pipeline && /app/.venv/bin/python -m pipeline.hf_space_seed && cd /app && rm -rf /tmp/deepsearch-api-prometheus && mkdir -p /tmp/deepsearch-api-prometheus && exec env PROMETHEUS_MULTIPROC_DIR=/tmp/deepsearch-api-prometheus USDSEARCH_LLM_PARSING_CACHE_SIZE=\"${USDSEARCH_LLM_PARSING_CACHE_SIZE:-0}\" /app/.venv/bin/python -m uvicorn deepsearch_api.main:app --host 127.0.0.1 --port 8000 --workers \"${DEEPSEARCH_API_WORKERS:-1}\""
|
| 175 |
directory=/app
|
| 176 |
user=1000
|
| 177 |
autorestart=true
|
|
|
|
| 181 |
stderr_logfile=/dev/stderr
|
| 182 |
stderr_logfile_maxbytes=0
|
| 183 |
|
| 184 |
+
[program:cache-metrics]
|
| 185 |
+
; The cache hit/miss counters Space members read at /metrics (nginx proxies it
|
| 186 |
+
; to 127.0.0.1:8030): deepsearch-api's cache counters summed over its workers
|
| 187 |
+
; (verdicts, rankings, image resolutions) and nginx's proxy-cache outcomes per
|
| 188 |
+
; cache, which nginx sends here as one syslog datagram per request
|
| 189 |
+
; (127.0.0.1:8031). Nothing else; a summary line goes to the log every 5 min.
|
| 190 |
+
; See pipeline/cache_metrics.py.
|
| 191 |
+
; env -u PYTHONPATH: the Triton base image's DALI wheel dir shadows the venv's typing_extensions.
|
| 192 |
+
command=/usr/bin/env -u PYTHONPATH /bin/sh -c "cd /app/hf-space-pipeline && exec /app/.venv/bin/python -m pipeline.cache_metrics"
|
| 193 |
+
directory=/app
|
| 194 |
+
user=1000
|
| 195 |
+
autorestart=true
|
| 196 |
+
startsecs=2
|
| 197 |
+
stdout_logfile=/dev/stdout
|
| 198 |
+
stdout_logfile_maxbytes=0
|
| 199 |
+
stderr_logfile=/dev/stderr
|
| 200 |
+
stderr_logfile_maxbytes=0
|
| 201 |
+
|
| 202 |
[program:nginx]
|
| 203 |
; See docker/hf-space/supervisord.conf's own copy (identical command). Never put
|
| 204 |
; a space before a ";" or "#" in a command: supervisord reads it as an inline
|
docker/hf-space/supervisord.conf
CHANGED
|
@@ -30,7 +30,12 @@ stderr_logfile=/dev/stderr
|
|
| 30 |
stderr_logfile_maxbytes=0
|
| 31 |
|
| 32 |
[program:redis]
|
| 33 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 34 |
user=1000
|
| 35 |
autorestart=true
|
| 36 |
startsecs=3
|
|
@@ -178,7 +183,14 @@ stderr_logfile_maxbytes=0
|
|
| 178 |
; time. A seeding failure (e.g. no published run yet, or bad AWS creds)
|
| 179 |
; correctly counts as this program failing to start, same as any other
|
| 180 |
; startup error here.
|
| 181 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 182 |
directory=/app
|
| 183 |
user=1000
|
| 184 |
autorestart=true
|
|
@@ -188,6 +200,23 @@ stdout_logfile_maxbytes=0
|
|
| 188 |
stderr_logfile=/dev/stderr
|
| 189 |
stderr_logfile_maxbytes=0
|
| 190 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 191 |
[program:nginx]
|
| 192 |
; nginx is the *only* process bound to the externally-proxied port, and
|
| 193 |
; Hugging Face's own Space "ready" detection is just "does something answer
|
|
|
|
| 30 |
stderr_logfile_maxbytes=0
|
| 31 |
|
| 32 |
[program:redis]
|
| 33 |
+
; Holds only deepsearch-api's caches, all in DB 0 by key prefix: the VLM verdicts (usdsearch:vlmval:v1, no TTL,
|
| 34 |
+
; capped at USDSEARCH_VISION_VALIDATION_CACHE_MAX_ENTRIES by the app's own LRU), the RRF page rankings behind
|
| 35 |
+
; search cursors (usdsearch:rrfpage:v1, 15-min TTL) and the image-id resolutions (TTL). No indexing streams run
|
| 36 |
+
; here. --maxmemory 6gb is a guard above the 4M verdicts (~1.8 GB); volatile-lru evicts only keys with a TTL,
|
| 37 |
+
; the two caches a miss recomputes, never a verdict or an LRU index. Nothing is saved: a restart starts cold.
|
| 38 |
+
command=/usr/bin/redis-server --port 6379 --databases 32 --save "" --stop-writes-on-bgsave-error no --dir /tmp --maxmemory 6gb --maxmemory-policy volatile-lru
|
| 39 |
user=1000
|
| 40 |
autorestart=true
|
| 41 |
startsecs=3
|
|
|
|
| 183 |
; time. A seeding failure (e.g. no published run yet, or bad AWS creds)
|
| 184 |
; correctly counts as this program failing to start, same as any other
|
| 185 |
; startup error here.
|
| 186 |
+
;
|
| 187 |
+
; PROMETHEUS_MULTIPROC_DIR (emptied at every start): the workers share their
|
| 188 |
+
; metrics through files there, so a counter is the sum over all workers;
|
| 189 |
+
; [program:cache-metrics] reads its cache counters from them.
|
| 190 |
+
; USDSEARCH_LLM_PARSING_CACHE_SIZE 0 (a Space variable overrides it): no
|
| 191 |
+
; per-worker parse LRU. Its key has no date, so after midnight it answered
|
| 192 |
+
; "made last week" with yesterday's parse; nginx caches parses per day instead.
|
| 193 |
+
command=/bin/sh -c "cd /app/hf-space-pipeline && /app/.venv/bin/python -m pipeline.hf_space_seed && cd /app && rm -rf /tmp/deepsearch-api-prometheus && mkdir -p /tmp/deepsearch-api-prometheus && exec env PROMETHEUS_MULTIPROC_DIR=/tmp/deepsearch-api-prometheus USDSEARCH_LLM_PARSING_CACHE_SIZE=\"${USDSEARCH_LLM_PARSING_CACHE_SIZE:-0}\" /app/.venv/bin/python -m uvicorn deepsearch_api.main:app --host 127.0.0.1 --port 8000 --workers \"${DEEPSEARCH_API_WORKERS:-1}\""
|
| 194 |
directory=/app
|
| 195 |
user=1000
|
| 196 |
autorestart=true
|
|
|
|
| 200 |
stderr_logfile=/dev/stderr
|
| 201 |
stderr_logfile_maxbytes=0
|
| 202 |
|
| 203 |
+
[program:cache-metrics]
|
| 204 |
+
; The cache hit/miss counters Space members read at /metrics (nginx proxies it
|
| 205 |
+
; to 127.0.0.1:8030): deepsearch-api's cache counters summed over its workers
|
| 206 |
+
; (verdicts, rankings, image resolutions) and nginx's proxy-cache outcomes per
|
| 207 |
+
; cache, which nginx sends here as one syslog datagram per request
|
| 208 |
+
; (127.0.0.1:8031). Nothing else; a summary line goes to the log every 5 min.
|
| 209 |
+
; See pipeline/cache_metrics.py.
|
| 210 |
+
command=/bin/sh -c "cd /app/hf-space-pipeline && exec /app/.venv/bin/python -m pipeline.cache_metrics"
|
| 211 |
+
directory=/app
|
| 212 |
+
user=1000
|
| 213 |
+
autorestart=true
|
| 214 |
+
startsecs=2
|
| 215 |
+
stdout_logfile=/dev/stdout
|
| 216 |
+
stdout_logfile_maxbytes=0
|
| 217 |
+
stderr_logfile=/dev/stderr
|
| 218 |
+
stderr_logfile_maxbytes=0
|
| 219 |
+
|
| 220 |
[program:nginx]
|
| 221 |
; nginx is the *only* process bound to the externally-proxied port, and
|
| 222 |
; Hugging Face's own Space "ready" detection is just "does something answer
|
pipeline/cache_metrics.py
ADDED
|
@@ -0,0 +1,260 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Cache hit/miss counters for the Space's members, at /metrics.
|
| 2 |
+
|
| 3 |
+
The Space's caches are sized from a model (docs/hf-space-deployment.md, "Caches"); this program makes the hit rates
|
| 4 |
+
readable so the model can be checked. It runs under supervisord (program ``cache-metrics``) and serves ONE page,
|
| 5 |
+
``GET http://127.0.0.1:8030/metrics``, which nginx proxies at ``/metrics`` (docker/hf-space/nginx.conf.template).
|
| 6 |
+
The page holds only these counters, in Prometheus' text format:
|
| 7 |
+
|
| 8 |
+
- deepsearch-api's cache counters, summed over its uvicorn workers. The deepsearch-api program runs with
|
| 9 |
+
``PROMETHEUS_MULTIPROC_DIR=/tmp/deepsearch-api-prometheus`` (emptied at every start), so each worker writes its
|
| 10 |
+
metrics to files there; this reads the allow-listed families from them (``ALLOWED``): the VLM verdict cache's
|
| 11 |
+
lookups by outcome (``l1_hit`` in the worker, ``l2_hit`` in Redis, ``miss``) and its size, the rankings the API
|
| 12 |
+
keeps in Redis behind result cursors (every search still reaches the API), and the thumbnail id resolutions.
|
| 13 |
+
deepsearch-api's own /metrics (request paths, latencies, process data) stays private to the container.
|
| 14 |
+
- nginx's proxy-cache outcomes per cache (``slim_nginx_cache_requests_total{cache, status}``; status as nginx's
|
| 15 |
+
``$upstream_cache_status``: HIT, MISS, EXPIRED, BYPASS, UPDATING, STALE, REVALIDATED). The caches are parses,
|
| 16 |
+
the Explorer's count probes, thumbnails and property stats; a user's search is never cached and never counted
|
| 17 |
+
here. nginx sends one syslog datagram per request of a cached route to 127.0.0.1:8031 carrying just
|
| 18 |
+
``<cache> <status>``; no URL, query, body or header ever reaches this process.
|
| 19 |
+
|
| 20 |
+
Every ``CACHE_METRICS_LOG_SECONDS`` (300) it also prints one summary line to the log when anything changed. Nothing
|
| 21 |
+
is kept: a restart starts the counts at zero, as it does the caches. Standard library only, except the reader of
|
| 22 |
+
deepsearch-api's files (prometheus_client, from the Space venv): without it the page still carries nginx's counts
|
| 23 |
+
and says ``slim_deepsearch_metrics_available 0``.
|
| 24 |
+
|
| 25 |
+
It must not stay down: while nothing listens on the UDP port, nginx writes one "send() failed ... while logging to
|
| 26 |
+
syslog" line per cached request to /var/log/nginx/error.log. So it never exits on its own (a port it cannot bind is
|
| 27 |
+
retried every 5 s) and supervisord restarts it if it dies.
|
| 28 |
+
"""
|
| 29 |
+
|
| 30 |
+
import os
|
| 31 |
+
import re
|
| 32 |
+
import socket
|
| 33 |
+
import threading
|
| 34 |
+
import time
|
| 35 |
+
from collections import defaultdict
|
| 36 |
+
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
|
| 37 |
+
from typing import Dict, Iterable, List, Optional, Tuple
|
| 38 |
+
|
| 39 |
+
HOST = "127.0.0.1"
|
| 40 |
+
HTTP_PORT = int(os.environ.get("CACHE_METRICS_PORT", "8030"))
|
| 41 |
+
SYSLOG_PORT = int(os.environ.get("CACHE_METRICS_SYSLOG_PORT", "8031"))
|
| 42 |
+
PROM_DIR = os.environ.get("CACHE_METRICS_PROM_DIR", "/tmp/deepsearch-api-prometheus")
|
| 43 |
+
LOG_SECONDS = float(os.environ.get("CACHE_METRICS_LOG_SECONDS", "300"))
|
| 44 |
+
|
| 45 |
+
# deepsearch-api's metric families served here (multiprocess family names: a counter's without "_total"). All are
|
| 46 |
+
# labelled by `outcome` only; anything else in the files never leaves the container.
|
| 47 |
+
ALLOWED = {
|
| 48 |
+
"vlm_validation_cache_events": "counter",
|
| 49 |
+
"vlm_validation_cache_entries": "gauge",
|
| 50 |
+
"search_ranking_cache_events": "counter",
|
| 51 |
+
"image_resolution_cache_events": "counter",
|
| 52 |
+
}
|
| 53 |
+
# The caches nginx logs (nginx.conf.template's $slim_cache_route) and the statuses $upstream_cache_status takes.
|
| 54 |
+
ROUTES = ("parse", "count", "images", "stats")
|
| 55 |
+
STATUSES = ("HIT", "MISS", "EXPIRED", "STALE", "UPDATING", "REVALIDATED", "BYPASS")
|
| 56 |
+
_LINE = re.compile(r"slimcache: (\w+) ([A-Z]+|-)\s*$")
|
| 57 |
+
|
| 58 |
+
|
| 59 |
+
def parse_datagram(data: bytes) -> Optional[Tuple[str, str]]:
|
| 60 |
+
"""``(cache, status)`` from one nginx syslog datagram, else None.
|
| 61 |
+
|
| 62 |
+
nginx sends ``<PRI>Mmm dd hh:mm:ss slimcache: <cache> <status>`` (``nohostname``). A request no cache saw
|
| 63 |
+
(status ``-``: a CORS preflight) and anything unexpected are dropped.
|
| 64 |
+
"""
|
| 65 |
+
match = _LINE.search(data.decode("utf-8", "replace"))
|
| 66 |
+
if not match:
|
| 67 |
+
return None
|
| 68 |
+
route, status = match.groups()
|
| 69 |
+
if route not in ROUTES or status not in STATUSES:
|
| 70 |
+
return None
|
| 71 |
+
return route, status
|
| 72 |
+
|
| 73 |
+
|
| 74 |
+
class NginxCounts:
|
| 75 |
+
"""Thread-safe ``{(cache, status): count}``."""
|
| 76 |
+
|
| 77 |
+
def __init__(self) -> None:
|
| 78 |
+
self._lock = threading.Lock()
|
| 79 |
+
self._counts: Dict[Tuple[str, str], int] = defaultdict(int)
|
| 80 |
+
|
| 81 |
+
def add(self, cache: str, status: str) -> None:
|
| 82 |
+
with self._lock:
|
| 83 |
+
self._counts[(cache, status)] += 1
|
| 84 |
+
|
| 85 |
+
def snapshot(self) -> Dict[Tuple[str, str], int]:
|
| 86 |
+
with self._lock:
|
| 87 |
+
return dict(self._counts)
|
| 88 |
+
|
| 89 |
+
|
| 90 |
+
def deepsearch_families(path: str) -> Optional[Dict[str, Dict[Tuple[Tuple[str, str], ...], float]]]:
|
| 91 |
+
"""``{family: {labels: value}}`` for the ALLOWED families in deepsearch-api's multiprocess files, or None when
|
| 92 |
+
they cannot be read (no prometheus_client, no directory yet). Counters are summed over the workers (the
|
| 93 |
+
collector does it); the gauge is the same Redis count in every worker, so its per-process copies collapse to
|
| 94 |
+
their maximum."""
|
| 95 |
+
if not os.path.isdir(path):
|
| 96 |
+
return None
|
| 97 |
+
try:
|
| 98 |
+
from prometheus_client.multiprocess import MultiProcessCollector
|
| 99 |
+
except ImportError:
|
| 100 |
+
return None
|
| 101 |
+
out: Dict[str, Dict[Tuple[Tuple[str, str], ...], float]] = {}
|
| 102 |
+
try: # the constructor checks the directory again: deepsearch-api's restart may have just emptied it
|
| 103 |
+
metrics = list(MultiProcessCollector(None, path=path).collect())
|
| 104 |
+
except Exception as exc: # noqa: BLE001 - a worker mid-write or a removed file: say "unavailable", never crash
|
| 105 |
+
print(f"==> cache metrics: cannot read {path} ({type(exc).__name__}: {str(exc)[:200]})", flush=True)
|
| 106 |
+
return None
|
| 107 |
+
for metric in metrics:
|
| 108 |
+
kind = ALLOWED.get(metric.name)
|
| 109 |
+
if kind is None:
|
| 110 |
+
continue
|
| 111 |
+
values = out.setdefault(metric.name, {})
|
| 112 |
+
for sample in metric.samples:
|
| 113 |
+
if kind == "counter" and not sample.name.endswith("_total"):
|
| 114 |
+
continue # no _created in multiprocess mode; skip anything else a newer client might add
|
| 115 |
+
labels = tuple(sorted((k, v) for k, v in sample.labels.items() if k != "pid"))
|
| 116 |
+
if kind == "gauge":
|
| 117 |
+
values[labels] = max(values.get(labels, float("-inf")), sample.value)
|
| 118 |
+
else:
|
| 119 |
+
values[labels] = values.get(labels, 0.0) + sample.value
|
| 120 |
+
return out
|
| 121 |
+
|
| 122 |
+
|
| 123 |
+
def _labels(pairs: Iterable[Tuple[str, str]]) -> str:
|
| 124 |
+
body = ",".join(f'{k}="{_escape(v)}"' for k, v in pairs)
|
| 125 |
+
return "{" + body + "}" if body else ""
|
| 126 |
+
|
| 127 |
+
|
| 128 |
+
def _escape(value: str) -> str:
|
| 129 |
+
return value.replace("\\", "\\\\").replace("\n", "\\n").replace('"', '\\"')
|
| 130 |
+
|
| 131 |
+
|
| 132 |
+
def _number(value: float) -> str:
|
| 133 |
+
return str(int(value)) if float(value).is_integer() else repr(float(value))
|
| 134 |
+
|
| 135 |
+
|
| 136 |
+
def render(nginx: Dict[Tuple[str, str], int], families) -> str:
|
| 137 |
+
"""The /metrics page (Prometheus text format 0.0.4)."""
|
| 138 |
+
lines: List[str] = [
|
| 139 |
+
"# HELP slim_nginx_cache_requests_total Requests to the Space's nginx proxy caches by cache and "
|
| 140 |
+
"$upstream_cache_status, since this process started.",
|
| 141 |
+
"# TYPE slim_nginx_cache_requests_total counter",
|
| 142 |
+
]
|
| 143 |
+
for (cache, status), count in sorted(nginx.items()):
|
| 144 |
+
lines.append(f"slim_nginx_cache_requests_total{_labels([('cache', cache), ('status', status)])} {count}")
|
| 145 |
+
lines += [
|
| 146 |
+
"# HELP slim_deepsearch_metrics_available 1 when deepsearch-api's cache counters below were readable.",
|
| 147 |
+
"# TYPE slim_deepsearch_metrics_available gauge",
|
| 148 |
+
f"slim_deepsearch_metrics_available {0 if families is None else 1}",
|
| 149 |
+
]
|
| 150 |
+
for name in sorted(families or {}):
|
| 151 |
+
kind = ALLOWED[name]
|
| 152 |
+
sample = f"{name}_total" if kind == "counter" else name
|
| 153 |
+
lines.append(f"# TYPE {sample} {kind}")
|
| 154 |
+
for labels, value in sorted(families[name].items()):
|
| 155 |
+
lines.append(f"{sample}{_labels(labels)} {_number(value)}")
|
| 156 |
+
return "\n".join(lines) + "\n"
|
| 157 |
+
|
| 158 |
+
|
| 159 |
+
def summary(nginx: Dict[Tuple[str, str], int], families) -> str:
|
| 160 |
+
"""One log line: verdict outcomes and each nginx cache's statuses."""
|
| 161 |
+
parts = []
|
| 162 |
+
verdicts = (families or {}).get("vlm_validation_cache_events", {})
|
| 163 |
+
if verdicts:
|
| 164 |
+
by = {dict(labels).get("outcome", ""): value for labels, value in verdicts.items()}
|
| 165 |
+
total = sum(by.values())
|
| 166 |
+
hits = by.get("l1_hit", 0) + by.get("l2_hit", 0)
|
| 167 |
+
parts.append("verdicts " + " ".join(f"{k}={_number(v)}" for k, v in sorted(by.items()))
|
| 168 |
+
+ (f" (hit {100 * hits / total:.1f}%)" if total else ""))
|
| 169 |
+
ranking = (families or {}).get("search_ranking_cache_events", {})
|
| 170 |
+
if ranking:
|
| 171 |
+
parts.append("rankings " + " ".join(f"{dict(k).get('outcome', '')}={_number(v)}"
|
| 172 |
+
for k, v in sorted(ranking.items())))
|
| 173 |
+
for cache in ROUTES:
|
| 174 |
+
counts = {status: n for (c, status), n in nginx.items() if c == cache}
|
| 175 |
+
if counts:
|
| 176 |
+
total = sum(counts.values())
|
| 177 |
+
parts.append(f"nginx {cache} " + " ".join(f"{s}={n}" for s, n in sorted(counts.items()))
|
| 178 |
+
+ f" (hit {100 * counts.get('HIT', 0) / total:.1f}%)")
|
| 179 |
+
if not parts:
|
| 180 |
+
return ""
|
| 181 |
+
if families is None:
|
| 182 |
+
parts.append("deepsearch-api counters unavailable")
|
| 183 |
+
return "==> cache metrics: " + " | ".join(parts)
|
| 184 |
+
|
| 185 |
+
|
| 186 |
+
def serve_syslog(counts: NginxCounts, sock: socket.socket) -> None:
|
| 187 |
+
while True:
|
| 188 |
+
data, _ = sock.recvfrom(4096)
|
| 189 |
+
parsed = parse_datagram(data)
|
| 190 |
+
if parsed:
|
| 191 |
+
counts.add(*parsed)
|
| 192 |
+
|
| 193 |
+
|
| 194 |
+
def make_handler(counts: NginxCounts, prom_dir: str):
|
| 195 |
+
class Handler(BaseHTTPRequestHandler):
|
| 196 |
+
def do_GET(self) -> None: # noqa: N802 - http.server's name
|
| 197 |
+
if self.path.split("?", 1)[0] != "/metrics":
|
| 198 |
+
self.send_error(404)
|
| 199 |
+
return
|
| 200 |
+
body = render(counts.snapshot(), deepsearch_families(prom_dir)).encode()
|
| 201 |
+
self.send_response(200)
|
| 202 |
+
self.send_header("Content-Type", "text/plain; version=0.0.4; charset=utf-8")
|
| 203 |
+
self.send_header("Content-Length", str(len(body)))
|
| 204 |
+
self.send_header("Cache-Control", "no-store")
|
| 205 |
+
self.end_headers()
|
| 206 |
+
self.wfile.write(body)
|
| 207 |
+
|
| 208 |
+
def log_message(self, *args) -> None: # one line per scrape would drown the Space log
|
| 209 |
+
pass
|
| 210 |
+
|
| 211 |
+
return Handler
|
| 212 |
+
|
| 213 |
+
|
| 214 |
+
def log_loop(counts: NginxCounts, prom_dir: str, every: float) -> None:
|
| 215 |
+
last = None
|
| 216 |
+
while True:
|
| 217 |
+
time.sleep(every)
|
| 218 |
+
nginx, families = counts.snapshot(), deepsearch_families(prom_dir)
|
| 219 |
+
state = (sorted(nginx.items()), repr(families))
|
| 220 |
+
line = summary(nginx, families)
|
| 221 |
+
if line and state != last:
|
| 222 |
+
print(line, flush=True)
|
| 223 |
+
last = state
|
| 224 |
+
|
| 225 |
+
|
| 226 |
+
def bind(make, what: str):
|
| 227 |
+
"""``make()``, retried every 5 s while the port is taken: exiting would leave nginx logging errors."""
|
| 228 |
+
while True:
|
| 229 |
+
try:
|
| 230 |
+
return make()
|
| 231 |
+
except OSError as exc:
|
| 232 |
+
print(f"==> cache metrics: cannot bind {what} ({exc}), trying again in 5 s", flush=True)
|
| 233 |
+
time.sleep(5)
|
| 234 |
+
|
| 235 |
+
|
| 236 |
+
def udp_socket() -> socket.socket:
|
| 237 |
+
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
| 238 |
+
try:
|
| 239 |
+
sock.bind((HOST, SYSLOG_PORT))
|
| 240 |
+
except OSError:
|
| 241 |
+
sock.close()
|
| 242 |
+
raise
|
| 243 |
+
return sock
|
| 244 |
+
|
| 245 |
+
|
| 246 |
+
def main() -> None:
|
| 247 |
+
counts = NginxCounts()
|
| 248 |
+
udp = bind(udp_socket, f"udp {HOST}:{SYSLOG_PORT}")
|
| 249 |
+
server = bind(lambda: ThreadingHTTPServer((HOST, HTTP_PORT), make_handler(counts, PROM_DIR)),
|
| 250 |
+
f"http {HOST}:{HTTP_PORT}")
|
| 251 |
+
threading.Thread(target=serve_syslog, args=(counts, udp), daemon=True).start()
|
| 252 |
+
if LOG_SECONDS > 0:
|
| 253 |
+
threading.Thread(target=log_loop, args=(counts, PROM_DIR, LOG_SECONDS), daemon=True).start()
|
| 254 |
+
print(f"==> cache metrics: http://{HOST}:{HTTP_PORT}/metrics, nginx syslog on udp {HOST}:{SYSLOG_PORT}, "
|
| 255 |
+
f"deepsearch-api files in {PROM_DIR}", flush=True)
|
| 256 |
+
server.serve_forever()
|
| 257 |
+
|
| 258 |
+
|
| 259 |
+
if __name__ == "__main__":
|
| 260 |
+
main()
|
pipeline/config.py
CHANGED
|
@@ -400,9 +400,10 @@ class Config:
|
|
| 400 |
"USDSEARCH_VISION_VALIDATION_LOGPROB_ASSET_FACTS": json.dumps(["path", "vlm_metadata_caption"]),
|
| 401 |
"USDSEARCH_VISION_VALIDATION_LOGPROB_ASSET_PATH_ROOTS": json.dumps(VALIDATION_ASSET_PATH_ROOTS),
|
| 402 |
"USDSEARCH_VISION_VALIDATION_LOGPROB_IMAGE_TEXT_QUERY": "true",
|
| 403 |
-
# The Redis verdict cache (on: REDIS_URL is set) holds
|
| 404 |
-
#
|
| 405 |
-
|
|
|
|
| 406 |
}
|
| 407 |
|
| 408 |
# ── VLM metadata extraction from thumbnails (indexing-time plugin) ──────
|
|
|
|
| 400 |
"USDSEARCH_VISION_VALIDATION_LOGPROB_ASSET_FACTS": json.dumps(["path", "vlm_metadata_caption"]),
|
| 401 |
"USDSEARCH_VISION_VALIDATION_LOGPROB_ASSET_PATH_ROOTS": json.dumps(VALIDATION_ASSET_PATH_ROOTS),
|
| 402 |
"USDSEARCH_VISION_VALIDATION_LOGPROB_IMAGE_TEXT_QUERY": "true",
|
| 403 |
+
# The Redis verdict cache (on: REDIS_URL is set) holds 4M verdicts: ~1.8 GB at the measured 463 B
|
| 404 |
+
# each, and 2-3 h of history at 100 users (250k held ~9 min). The Space's Redis caps itself at
|
| 405 |
+
# 6 GB (--maxmemory, volatile-lru: verdicts carry no TTL, so Redis never evicts them).
|
| 406 |
+
"USDSEARCH_VISION_VALIDATION_CACHE_MAX_ENTRIES": "4000000",
|
| 407 |
}
|
| 408 |
|
| 409 |
# ── VLM metadata extraction from thumbnails (indexing-time plugin) ──────
|
services/explorer/dist/build-info.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
| 1 |
{
|
| 2 |
"product": "simready-central-slim-explorer",
|
| 3 |
-
"version": "slim-ui-
|
| 4 |
-
"bundle_id": "main.
|
| 5 |
-
"built_at": "2026-10-
|
| 6 |
"flags": {"public_mode": true, "email_auth": false, "create_ui": false, "hierarchy_editor": false, "create_search": false, "auth_ui": false, "credentials_ui": false, "index_management": false, "inference_backend": "hub", "vlm_asset_refs": false, "validation_image_max_px": 448, "validation_max_retries": 0, "validation_max_concurrent": 32, "validation_tail_concurrent": 8, "validation_eager_count": 50, "validation_batch_stream": true, "library_idle_prefetch": false, "validation_score_scale": "percent", "parse_gate_fields": true, "parse_fast_path": true, "featured_landing": true, "hf_download_commands": true, "dependency_views": true, "model_viewer": false, "library_viewer": true, "library_media": "runtime", "spell_correction": false, "downloads": "runtime", "submit_content": "runtime", "third_party_notices": "runtime"}
|
| 7 |
}
|
|
|
|
| 1 |
{
|
| 2 |
"product": "simready-central-slim-explorer",
|
| 3 |
+
"version": "slim-ui-9d95b298",
|
| 4 |
+
"bundle_id": "main.846b9fc7.js",
|
| 5 |
+
"built_at": "2026-10-15T18:17:42Z",
|
| 6 |
"flags": {"public_mode": true, "email_auth": false, "create_ui": false, "hierarchy_editor": false, "create_search": false, "auth_ui": false, "credentials_ui": false, "index_management": false, "inference_backend": "hub", "vlm_asset_refs": false, "validation_image_max_px": 448, "validation_max_retries": 0, "validation_max_concurrent": 32, "validation_tail_concurrent": 8, "validation_eager_count": 50, "validation_batch_stream": true, "library_idle_prefetch": false, "validation_score_scale": "percent", "parse_gate_fields": true, "parse_fast_path": true, "featured_landing": true, "hf_download_commands": true, "dependency_views": true, "model_viewer": false, "library_viewer": true, "library_media": "runtime", "spell_correction": false, "downloads": "runtime", "submit_content": "runtime", "third_party_notices": "runtime"}
|
| 7 |
}
|
services/explorer/dist/index.html
CHANGED
|
@@ -1 +1 @@
|
|
| 1 |
-
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="/ds.png"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="SimReady Central — SimReady asset search"/><meta name="ui-version" content="slim-ui-
|
|
|
|
| 1 |
+
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="/ds.png"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="SimReady Central — SimReady asset search"/><meta name="ui-version" content="slim-ui-9d95b298"><script src="/config.js"></script><title>SimReady Central</title><script defer="defer" src="/static/js/main.846b9fc7.js"></script><link href="/static/css/main.01671ca7.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
|
services/explorer/dist/static/js/298.4bcf08c3.chunk.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
"use strict";(self.webpackChunkdeepsearch_ui=self.webpackChunkdeepsearch_ui||[]).push([[298],{298(e,t,o){o.r(t),o.d(t,{COLLIDERS_LAYER:()=>_,HD_LAYER:()=>A,LOCAL:()=>k,NORMAL_MODES:()=>ie,OPENPBR_CORE_MAPS:()=>J,OPENPBR_EXT_MAPS:()=>Y,READER_TEXTURES:()=>P,RECYCLE_BYTES:()=>U,ROOT_KEY:()=>x,ROOT_LAYER:()=>S,SLOTS:()=>G,WARM_KEY:()=>L,WebUsdError:()=>R,_readerState:()=>De,_resetWebUsdReader:()=>ze,colorSpaceOf:()=>X,compactRecord:()=>Z,compactThickness:()=>ae,expected:()=>We,fallbackWarning:()=>ve,fileKey:()=>N,flipV:()=>$,geometryArrays:()=>le,isWebUsdError:()=>O,loadWebUsd:()=>Fe,lowBitLog2:()=>ee,mapUrl:()=>z,materialGaps:()=>ge,materialParams:()=>ye,openpbrOnly:()=>fe,physicsResult:()=>Te,pieceOf:()=>W,planHints:()=>D,quantizeLattice:()=>se,roleOf:()=>K,rootLayerText:()=>j,setWebUsdReader:()=>_e,siblingUrl:()=>F,snormNormals:()=>re,tierLayers:()=>T,uvDequant:()=>ne,uvMatrix:()=>de,warmWebUsdReader:()=>Ce,webUsdReaderFailure:()=>C,webUsdReaderSet:()=>xe});var s=o(986),r=o(379),n=o(1);const a="/Asset",i="".concat(a,"/Bodies"),l="".concat(a,"/Joints"),c=["simready"],u={version:1,frame:"gltf",units:{length:"m",angle:"deg",mass:"kg"}},d={kind:["simready:kind",!1],sequence:["simready:sequence",!1],order:["simready:order",!1],fixed_base:["simready:fixedBase",!1],static_reason:["simready:staticReason",!1],poses:["simready:poses",!0],pose_problems:["simready:poseProblems",!0],physics_variants:["simready:physicsVariants",!0],selftest:["simready:selftest",!0]},p={PhysicsRevoluteJoint:"revolute",PhysicsPrismaticJoint:"prismatic",PhysicsFixedJoint:"fixed"},m=new Set(["revolute","prismatic"]),h=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),f=e=>String(e).split("/").pop(),y=e=>String(e).slice(0,String(e).lastIndexOf("/"));function v(e){const[t,o,s,r]=e.map(Number);return[1-2*(s*s+r*r),2*(o*s+t*r),2*(o*r-t*s)]}function g(e,t){if(!e)throw new Error("webUsdPhysics: ".concat(t))}function b(e){const t=(0,r.A)({},(null===e||void 0===e?void 0:e.attributes)||{});for(const[o,s]of Object.entries((null===e||void 0===e?void 0:e.unreadable)||{}))g("string[]"===s,"".concat(e.path,".").concat(o,": the reader could not read it (").concat(s||"no type",")")),t[o]=[];return t}function w(e,t){const o=p[e.type];g(o,"".concat(e.path,": not a joint of the profile (").concat(e.type,")"));const s=b(e),r=e.relationships||{},n=new Set(e.apiSchemas||[]),a={};for(const[p,m]of Object.entries(s))!p.startsWith("physics:")&&!p.startsWith("simready:")||p.startsWith("physics:body")||p.startsWith("drive:")||(a[p]=m);const i={};for(const[p,m]of Object.entries(r))p.startsWith("simready:")&&(i[p]=m.map(f));const l=e=>r[e]&&r[e].length?f(r[e][0]):null;let c=null;for(const p of["angular","linear"]){var u,d;if(!n.has("PhysicsDriveAPI:".concat(p)))continue;const e=e=>s["drive:".concat(p,":physics:").concat(e)],t="drive:".concat(p,":physics:maxForce");c={stiffness:null!==(u=e("stiffness"))&&void 0!==u?u:0,damping:null!==(d=e("damping"))&&void 0!==d?d:0,maxForce:h(s,t)?s[t]:null}}const y={id:f(e.path),type:o,body0:l("physics:body0"),body1:l("physics:body1"),label:h(a,"simready:label")?a["simready:label"]:null};t&&h(a,"simready:name")&&(y.name=a["simready:name"]),h(a,"simready:lockedFrom")&&(y.locked_from=a["simready:lockedFrom"]);const w=e=>h(a,e)?a[e]:null;if(m.has(o)){const t=h(a,"simready:rest")?a["simready:rest"]:0;g(Array.isArray(a["physics:localRot0"]),"".concat(e.path,": no physics:localRot0")),g(Array.isArray(a["physics:localPos0"]),"".concat(e.path,": no physics:localPos0"));const o=e=>"number"===typeof a[e]?a[e]+t:null;if(Object.assign(y,{axis:v(a["physics:localRot0"]),pivot:[...a["physics:localPos0"]],unit:w("simready:unit"),lower:o("physics:lowerLimit"),upper:o("physics:upperLimit"),rest:w("simready:rest"),home:w("simready:home"),far:w("simready:far"),partial:w("simready:partial"),drive:null}),c){const e=c.stiffness||0,t=c.damping||0,o=c.maxForce;y.drive={type:e>0?"position":t>0?"velocity":"none",stiffness:e,damping:t,max_force:"number"===typeof o&&Number.isFinite(o)?o:null}}h(a,"simready:range")&&(y.range=[...a["simready:range"]]);for(const e of["mimic","coupled"])h(i,"simready:".concat(e,"Of"))&&(y[e]={of:i["simready:".concat(e,"Of")][0],gearing:a["simready:".concat(e,"Gearing")],offset:a["simready:".concat(e,"Offset")]},"coupled"===e&&(y[e].source=w("simready:coupledSource")));h(a,"simready:loop")&&(y.loop=JSON.parse(a["simready:loop"])),a["physics:excludeFromArticulation"]&&(y.closes=!0)}let M=null;if(h(a,"simready:tree")){const t=i["simready:treeParent"]&&i["simready:treeParent"].length?i["simready:treeParent"]:[null];g(i["simready:treeChild"]&&i["simready:treeChild"].length,"".concat(e.path,": no simready:treeChild")),M=[a["simready:tree"],{joint:y.id,parent:t[0],child:i["simready:treeChild"][0],inverse:!!a["simready:treeInverse"]}]}return{row:y,tree:M}}const M=["warnings"],S="asset.usdc",A="hd.usdc",_="colliders.usdc",x="simready-web.usda",L="simready-warm.usda",k="local:///",U=268435456,P="none";class R extends Error{constructor(e,t){let{cause:o,url:s,status:r,fatal:n}=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};super(t),this.name="WebUsdError",this.code=e,void 0!==o&&(this.cause=o),void 0!==s&&(this.url=s),void 0!==r&&(this.status=r),n&&(this.fatal=!0)}}const O=e=>e instanceof R;let B=null;function E(e,t){let o=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};return B=new R(e,t,(0,r.A)((0,r.A)({},o),{},{fatal:!0})),B}const C=()=>B,I=/\/Bodies\/(b\d+)\/(?:lo|hd)\/(m\d+)$/;function W(e){const t=I.exec(e||"");return t?{body:t[1],name:t[1]+t[2]}:null}function j(){const e=2===(arguments.length>0&&void 0!==arguments[0]?arguments[0]:1)?"full":"preview";return["#usda 1.0","(",' defaultPrim = "Asset"'," metersPerUnit = 1",' upAxis = "Y"'," subLayers = ["," @./".concat(S,"@")," ]",")","",'over "Asset" ('," variants = {",' string lod = "'.concat(e,'"'),' string textures = "web"'," }",")","{","}",""].join("\n")}const T=function(){return 2===(arguments.length>0&&void 0!==arguments[0]?arguments[0]:1)?[S,A]:[S]},N=e=>String(e).split(/[?#]/)[0];function F(e,t){const o=new URL(e,t);return o.search||(o.search=new URL(t).search),o.href}function z(e,t){return String(e).startsWith(k)?F(String(e).slice(k.length).replace(/^\/+/,""),t):new URL(e,t).href}function D(e,t){const o=new Map;for(const s of e||[]){if("string"!==typeof s||!s.trim())continue;const e=F(s.trim(),t),r=N(e);o.has(r)||o.set(r,e)}return o}const G={diffuseColor:"map",emissiveColor:"emissiveMap",roughness:"roughnessMap",metallic:"metalnessMap",occlusion:"aoMap",opacity:"alphaMap",normal:"normalMap"},q={map:"rgb",emissiveMap:"rgb",roughnessMap:"g",metalnessMap:"b",aoMap:"r",alphaMap:"g",normalMap:"rgb",transmissionMap:"r",clearcoatMap:"r",clearcoatRoughnessMap:"g",clearcoatNormalMap:"rgb",specularIntensityMap:"a",specularColorMap:"rgb",sheenColorMap:"rgb",sheenRoughnessMap:"a"},J={base_color:"map",base_metalness:"metalnessMap",specular_roughness:"roughnessMap",geometry_normal:"normalMap",emission_color:"emissiveMap",geometry_opacity:"alphaMap"},Y={transmission_weight:"transmissionMap",coat_weight:"clearcoatMap",coat_roughness:"clearcoatRoughnessMap",geometry_coat_normal:"clearcoatNormalMap",specular_weight:"specularIntensityMap",specular_color:"specularColorMap",fuzz_color:"sheenColorMap",fuzz_roughness:"sheenRoughnessMap"},H=new Set(["map","emissiveMap","sheenColorMap","specularColorMap"]),K=e=>H.has(e)?"color":"data",X=e=>"color"===e?"srgb":"",V=(e,t)=>Math.abs(e-t)<1e-6,Q={r:0,g:1,b:2,a:3};function $(e){for(let t=1;t<e.length;t+=2)e[t]=1-e[t];return e}function Z(e,t){var o,s;if(!0===e)return!0;if(Array.isArray(e))return 3===e.length&&e.every(e=>Number.isInteger(e)&&e>0);if(e&&"object"===typeof e)return!!e.bits||Number.isInteger(e.points_log2);let r=null===t||void 0===t||null===(o=t.customLayerData)||void 0===o||null===(s=o.simready)||void 0===s?void 0:s.tiers;if("string"===typeof r)try{r=JSON.parse(r)}catch(n){r=null}return!(!r||"object"!==typeof r||!r.compact)}function ee(e){const t=new Uint32Array(e.buffer,e.byteOffset,e.length);let o=1/0;for(let s=0;s<t.length;s+=1){const e=t[s];if(0===(2147483647&e)){if(0!==e)return null;continue}const r=e>>>23&255;if(255===r)return null;const n=r?8388607&e|8388608:8388607&e,a=(r||1)-150+(31-Math.clz32(n&-n));a<o&&(o=a)}return o===1/0?0:o}const te=[-32768,32767],oe=[0,65535];function se(e,t){let o=arguments.length>2&&void 0!==arguments[2]?arguments[2]:t;const s=e.length/t;if(!(s>0)||!Number.isInteger(s))return null;const r=ee(e);if(null===r)return null;const n=2**-r,a=new Array(t).fill(1/0),i=new Array(t).fill(-1/0);for(let m=0,h=0;m<s;m+=1)for(let o=0;o<t;o+=1,h+=1){const t=e[h]*n;t<a[o]&&(a[o]=t),t>i[o]&&(i[o]=t)}const l=Math.min(...a),c=Math.max(...i);let u=null,d=new Array(t).fill(0);if(l>=te[0]&&c<=te[1])u=Int16Array;else if(l>=oe[0]&&c<=oe[1])u=Uint16Array;else{if(!a.every((e,t)=>i[t]-e<=oe[1]))return null;u=Uint16Array,d=a.slice()}const p=new u(s*o);for(let m=0,h=0;m<s;m+=1)for(let s=0;s<t;s+=1,h+=1)p[m*o+s]=e[h]*n-d[s];return{array:p,k:r,offset:d,min:a.map((e,t)=>e-d[t]),max:i.map((e,t)=>e-d[t])}}function re(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:8;const o=16===t?Int16Array:Int8Array,s=16===t?32767:127,r=e.length/3,n=new o(4*r);for(let a=0;a<r;a+=1)for(let t=0;t<3;t+=1){const o=Math.max(-1,Math.min(1,e[3*a+t]||0));n[4*a+t]=Math.sign(o)*Math.floor(Math.abs(o)*s+.5)}return n}const ne=e=>{let{k:t,offset:o}=e;const s=2**t;return[s,0,o[0]*s,0,s,o[1]*s,0,0,1].map(e=>e+0)},ae=(e,t)=>e/2**t,ie={int8:8,int16:16,float:0};function le(e,t){let o=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"int8";const s=(e.uvs||[]).map($),r=e=>e?(e.array||e).byteLength:0,n=r(e.positions)+r(e.normals)+s.reduce((e,t)=>e+t.byteLength,0),a={position:e.positions,normal:e.normals,uvs:s.slice(),positionLattice:null,uvLattice:null};if(t){var i;a.positionLattice=se(e.positions,3,4),a.positionLattice&&(a.position=a.positionLattice);const t=null!==(i=ie[o])&&void 0!==i?i:8;t&&e.normals&&(a.normal={array:re(e.normals,t),bits:t}),s[0]&&(a.uvLattice=se(s[0],2,2),a.uvLattice&&(a.uvs[0]=a.uvLattice))}return a.bytes={float:n,upload:r(a.position)+r(a.normal)+a.uvs.reduce((e,t)=>e+r(t),0)},a}const ce=(e,t)=>[0,1,2].flatMap(o=>[0,1,2].map(s=>e[3*o]*t[s]+e[3*o+1]*t[3+s]+e[3*o+2]*t[6+s])),ue=[1,0,0,0,-1,1,0,0,1];function de(e){const[t,o]=(null===e||void 0===e?void 0:e.uvScale)||[1,1],[s,r]=(null===e||void 0===e?void 0:e.uvTranslation)||[0,0],n=((null===e||void 0===e?void 0:e.uvRotation)||0)*Math.PI/180;if(1===t&&1===o&&0===s&&0===r&&0===n)return null;const a=Math.cos(n),i=Math.sin(n);return ce(ce(ue,[a*t,-i*o,s,i*t,a*o,r,0,0,1]),ue).map(e=>e+0)}const pe={mirror:"mirror",clamp:"clamp",black:"clamp"},me={specular_weight:"specularIntensity",specular_color:"specularColor",specular_ior:"ior",transmission_weight:"transmission",transmission_color:"attenuationColor",transmission_depth:"attenuationDistance",coat_weight:"clearcoat",coat_roughness:"clearcoatRoughness",fuzz_color:"sheenColor",fuzz_roughness:"sheenRoughness",specular_roughness_anisotropy:"anisotropy"},he={base_weight:1,base_color:[.8,.8,.8],base_metalness:0,specular_roughness:.3,geometry_opacity:1,emission_color:[1,1,1]},fe=e=>"fallback"===(null===e||void 0===e?void 0:e.kind)&&!(null===e||void 0===e||!e.openpbr);function ye(e){var t,o,s,r;const n=e&&e.openpbr||{},a=e&&e.simready||{},i=e&&e.maps||{},l={name:(null===e||void 0===e?void 0:e.path)||"",color:[...(null===e||void 0===e?void 0:e.color)||[1,1,1]],opacity:null!==(t=null===e||void 0===e?void 0:e.opacity)&&void 0!==t?t:1,roughness:null!==(o=null===e||void 0===e?void 0:e.roughness)&&void 0!==o?o:1,metalness:null!==(s=null===e||void 0===e?void 0:e.metallic)&&void 0!==s?s:1,emissive:[...(null===e||void 0===e?void 0:e.emissive)||[0,0,0]],emissiveIntensity:1,alphaMode:"OPAQUE",alphaTest:0,transparent:!1,depthWrite:!0,doubleSided:null,normalScale:1,aoMapIntensity:1,physical:{},maps:{},gaps:[]},c=(e,t)=>{l.maps[e]={path:t.path,role:K(e),wrap:[pe[t.wrapS]||"repeat",pe[t.wrapT]||"repeat"],matrix:de(t)};const o=q[e];o&&t.channel!==o&&l.gaps.push("".concat(e," reads ").concat(t.channel,", three samples ").concat(o))},u=e=>e.channel in Q?e.scale[Q[e.channel]]:e.scale[0],d=i.diffuseColor;let p=!1;for(const[b,w]of Object.entries(i)){const t=G[b];t&&w&&w.path?(w.uvSet&&"st"!==w.uvSet&&l.gaps.push("".concat(b," samples primvar ").concat(w.uvSet,", not st")),"diffuseColor"===b?(l.color=[0,1,2].map(t=>{var o,s;return(null!==(o=null===(s=e.color)||void 0===s?void 0:s[t])&&void 0!==o?o:1)*w.scale[t]}),c(t,w)):"emissiveColor"===b?(l.emissive=[0,1,2].map(e=>w.scale[e]),c(t,w)):"roughness"===b?(l.roughness=u(w),c(t,w)):"metallic"===b?(l.metalness=u(w),c(t,w)):"occlusion"===b?(l.aoMapIntensity=u(w),c(t,w)):"normal"===b?(V(w.scale[0],2)&&V(w.bias[0],-1)||l.gaps.push("normal map not at scale 2 / bias -1"),c(t,w)):"opacity"===b&&(p=!0,l.opacity=u(w),d&&d.path===w.path&&"a"===w.channel||c(t,w)),"normal"!==b&&"occlusion"!==b&&w.bias&&w.bias.some(e=>!V(e,0))&&l.gaps.push("".concat(b," has a bias"))):l.gaps.push("".concat(b,": no three.js map"))}const m=fe(e),h=new Set(e&&e.openpbrTextured||[]),f=e&&e.openpbrMaps||{},y=new Set,v=(e,t)=>{var o;const s=f[e];s&&s.path&&(s.uvSet&&"st"!==s.uvSet&&l.gaps.push("".concat(e," samples ").concat(s.uvSet,", not st")),s.unsupported&&l.gaps.push("".concat(e,": ").concat(s.unsupported)),y.add(e),"alphaMap"===t&&"a"===s.channel&&(null===(o=f.base_color)||void 0===o?void 0:o.path)===s.path||c(t,s))};if(m){const t=(e,t)=>t(n[e])?n[e]:he[e],o=e=>"number"===typeof e,s=e=>Array.isArray(e)&&3===e.length,r=t("base_weight",o);l.color=t("base_color",s).map(e=>e*r),l.metalness=t("base_metalness",o),l.roughness=t("specular_roughness",o),l.opacity=t("geometry_opacity",o);const a=void 0!==n.emission_color||n.emission_luminance>0;l.emissive=a?[...t("emission_color",s)]:[0,0,0],p=h.has("geometry_opacity");for(const[e,n]of Object.entries(J))v(e,n);for(const e of h)Object.hasOwn(he,e)&&!y.has(e)&&l.gaps.push("".concat(e,": its map is not read (factor only)"));"number"!==typeof e.normalScale||y.has("geometry_normal")||l.gaps.push("geometry_normal: its map is not read")}for(const[b,w]of Object.entries(Y))v(b,w);l.alphaMode=a.alphaMode||((null===e||void 0===e?void 0:e.opacityThreshold)>0?"MASK":p||l.opacity<1?"BLEND":"OPAQUE"),"MASK"===l.alphaMode&&(l.alphaTest=null!==(r=a.alphaCutoff)&&void 0!==r?r:(null===e||void 0===e?void 0:e.opacityThreshold)>0?e.opacityThreshold:.5),"BLEND"===l.alphaMode&&(l.transparent=!0,l.depthWrite=!1),"boolean"===typeof a.doubleSided&&(l.doubleSided=a.doubleSided),"number"===typeof(null===e||void 0===e?void 0:e.normalScale)&&(l.normalScale=e.normalScale),"number"===typeof a.occlusionStrength&&(l.aoMapIntensity=a.occlusionStrength);for(const[b,w]of Object.entries(me))void 0!==n[b]&&(l.physical[w]=n[b]);for(const b of h)me[b]&&!y.has(b)&&l.gaps.push("".concat(b,": its map is not read (factor only)"));n.fuzz_weight>0&&(l.physical.sheen=1),"number"===typeof a.thickness&&(l.physical.thickness=a.thickness),n.geometry_thin_walled&&(l.physical.thickness=0),"number"===typeof a.anisotropyRotation&&(l.physical.anisotropyRotation=a.anisotropyRotation);const g=n.emission_luminance;return"number"===typeof g&&g>0&&(l.emissiveIntensity=g,m||(l.emissive=l.emissive.map(e=>e/g))),l}function ve(e){const t=(e||[]).filter(e=>"fallback"===(null===e||void 0===e?void 0:e.kind)&&e.path&&!fe(e));return t.length?{code:"material-fallback",path:t[0].path,message:"".concat(t.length," material(s) have no ")+"UsdPreviewSurface, OpenPBR surface or supported MDL material and show as grey"}:null}function ge(e){var t;const o=[];return null!==e&&void 0!==e&&e.openpbr||o.push("openpbr: specular weight/colour, ior, transmission, coat, fuzz, anisotropy, emission luminance"),null!==e&&void 0!==e&&e.simready||o.push("simready: alphaMode, alphaCutoff, doubleSided, occlusionStrength, thickness, anisotropyRotation"),"number"!==typeof(null===e||void 0===e?void 0:e.normalScale)&&null!==e&&void 0!==e&&null!==(t=e.maps)&&void 0!==t&&t.normal&&o.push("normal scale"),o}let be=null,we=null,Me=null,Se=null,Ae=0;function _e(e){Se&&Pe(Se),Se=null,we=null,Me=null,be=e||null}const xe=()=>!!be,Le=function(e,t){let o=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};return new R("fetch","webUsdLoader: the reader's WASM did not load: ".concat(t),(0,r.A)({url:String(e)},o))};function ke(){if(!be)return Promise.reject(new R("reader","webUsdLoader: no reader set"));if(!we){const e=performance.now(),t=be,o=Promise.resolve().then(()=>t.compile?t.compile():async function(e){let t;try{const o=await fetch(e);if(!o.ok)throw Le(e,"HTTP ".concat(o.status),{status:o.status});t=await o.arrayBuffer()}catch(o){throw O(o)?o:Le(e,(null===o||void 0===o?void 0:o.message)||String(o),{cause:o})}if(!(0,n.Hr)(t))throw new Error("not WebAssembly (a page served in its place?)");return WebAssembly.compile(t)}(t.wasmUrl)).then(t=>(Me=performance.now()-e,t)).catch(e=>{if(O(e)&&"fetch"===e.code)throw e;throw E("reader","webUsdLoader: could not compile the reader's WASM: ".concat((null===e||void 0===e?void 0:e.message)||e),{cause:e,url:t.wasmUrl&&String(t.wasmUrl)})});o.catch(()=>{we===o&&(we=null)}),we=o}return we}function Ue(){let e;try{e=be.createWorker?be.createWorker():new Worker(be.workerUrl,{type:"module"})}catch(t){throw E("reader","webUsdLoader: could not start the reader's worker: ".concat((null===t||void 0===t?void 0:t.message)||t),{cause:t})}return Ae+=1,{worker:e,dead:!1,ready:Promise.resolve(!0)}}function Pe(e){e&&!e.dead&&(e.dead=!0,e.worker.onmessage=null,e.worker.onerror=null,e.worker.terminate())}const Re={fetch:"fetch",compose:"compose",aborted:"aborted",worker:"reader"};function Oe(e,t,o,s){let r=arguments.length>4&&void 0!==arguments[4]?arguments[4]:{};return new Promise((n,a)=>{const{worker:i}=e;let l=0,c=!1;r.posted=!1;const u=t=>{c||(c=!0,null===s||void 0===s||s.removeEventListener("abort",d),i.onmessage=null,i.onerror=null,t?(r.posted&&Pe(e),a(t)):n(l))};function d(){u(new R("aborted","webUsdLoader: the load was aborted",{url:t.url}))}if(null!==s&&void 0!==s&&s.aborted)d();else{null===s||void 0===s||s.addEventListener("abort",d,{once:!0}),i.onmessage=e=>{var t,s,r;let{data:n}=e;if(!c&&n)if("texture"===n.type&&(null===(t=n.bitmap)||void 0===t||null===(s=t.close)||void 0===s||s.call(t)),"scene"===n.type&&(l=(null===(r=n.stats)||void 0===r?void 0:r.wasmMemoryBytes)||0),"done"!==n.type)if("error"!==n.type)try{o(n)}catch(a){u(O(a)?a:new R("compose","webUsdLoader: could not build the scene: ".concat((null===a||void 0===a?void 0:a.message)||a),{cause:a}))}else u(new R(Re[n.code]||"compose","webUsdLoader: ".concat(n.message),{url:n.url,status:n.status}));else u(null)},i.onerror=e=>{var o;null===e||void 0===e||null===(o=e.preventDefault)||void 0===o||o.call(e),(e=>!(!e||!(e.message||e.filename||e.error)))(e)?u(E("reader","webUsdLoader: the reader's worker failed: ".concat((null===e||void 0===e?void 0:e.message)||"error"))):u(new R("fetch","webUsdLoader: the reader's worker did not load its script",{url:t.url}))};try{i.postMessage(t),r.posted=!0}catch(p){u(new R("reader","webUsdLoader: could not post to the reader's worker: ".concat((null===p||void 0===p?void 0:p.message)||p),{cause:p}))}}})}function Be(e,t){e.dead||(Se||t>U?Pe(e):Se=e)}let Ee=null;function Ce(){if(!be)return Promise.resolve(!1);if(Se){const e=Se;return e.ready.then(t=>t&&!e.dead)}if(Ee)return Ee;const e=ke().then(e=>{if(Se)return Se.ready;const t=Ue();return t.ready=Oe(t,(e=>({url:k+L,wasmModule:e,textures:P,files:new Map([[L,new Blob(['#usda 1.0\n(\n defaultPrim = "Asset"\n)\n\ndef Xform "Asset"\n{\n}\n'],{type:"text/plain"})]])}))(e),()=>{}).then(()=>!0,()=>(Se===t&&(Se=null),Pe(t),!1)),Se=t,t.ready}).catch(()=>!1).finally(()=>{Ee===e&&(Ee=null)});return Ee=e,e}function Ie(e){let{ktx2:t,fetchFn:o,headers:s,signal:r,t0:n}=e;const a=new Map;let i=null;const l=(e,l)=>{const c=N(e);if(a.has(c))return a.get(c);const u={url:e,hinted:l,used:!1,startMs:performance.now()-n,readyMs:null,texture:null,error:null,derived:new Map};return u.promise=Promise.all([(i||(i=Promise.resolve("function"===typeof t?t():t).then(e=>{if(!e)throw new R("textures","webUsdLoader: maps need the page's KTX2 loader");return e})),i),Promise.resolve(o(e,{signal:r,headers:s,credentials:"same-origin"})).then(t=>{if(!t.ok)throw new R("textures","webUsdLoader: map ".concat(e,": HTTP ").concat(t.status),{url:e,status:t.status});return t.arrayBuffer()})]).then(e=>{let[t,o]=e;return((e,t)=>new Promise((o,s)=>e.parse(t,o,s)))(t,o)}).then(e=>(u.texture=e,u.readyMs=performance.now()-n,e)).catch(t=>{throw u.error=O(t)?t:new R(null!==r&&void 0!==r&&r.aborted?"aborted":"textures","webUsdLoader: map ".concat(e,": ").concat((null===t||void 0===t?void 0:t.message)||t),{cause:t,url:e}),u.error}),u.promise.catch(()=>{}),a.set(c,u),u};return{files:a,start:l,use(e){const t=l(e,!1);return t.used=!0,t},settle:()=>Promise.all([...a.values()].filter(e=>e.used).map(e=>e.promise)),texture(e,t,o,s,r){const n=a.get(N(t)),i=n.texture,l="color"===o?e.SRGBColorSpace:e.NoColorSpace,c=t=>"mirror"===t?e.MirroredRepeatWrapping:"clamp"===t?e.ClampToEdgeWrapping:e.RepeatWrapping,u="".concat(l,"|").concat(s.join(","),"|").concat(r?r.join(","):"");if(n.derived.size||(i.flipY=!1,i.colorSpace=l,i.magFilter=e.LinearFilter,i.minFilter=e.LinearMipmapLinearFilter,i.wrapS=c(s[0]),i.wrapT=c(s[1]),r&&(i.matrixAutoUpdate=!1,i.matrix.set(...r)),i.needsUpdate=!0,n.derived.set(u,i)),!n.derived.has(u)){const e=i.clone();e.colorSpace=l,e.wrapS=c(s[0]),e.wrapT=c(s[1]),e.matrixAutoUpdate=!r,r?e.matrix.set(...r):e.matrix.identity(),e.needsUpdate=!0,n.derived.set(u,e)}return n.derived.get(u)},all:()=>[...a.values()].flatMap(e=>[...e.derived.values()]),unused:()=>[...a.values()].filter(e=>!e.used&&e.texture).map(e=>e.texture)}}const We=e=>"".concat((null===e||void 0===e?void 0:e.path)||""," ").concat((null===e||void 0===e?void 0:e.message)||"").includes(_);function je(e,t){let{maps:o,base:r,tier:n,compact:a=null,normals:i="int8"}=t;const l=new e.Group;l.name="usd";const c=new Map,u=[],d=new Map,p=[],m=[];let h=null,f=[],y=new Map,v=!1;const g={meshes:0,triangles:0,loose:0},b={compact:!1,geometries:0,position:0,normal:0,uv:0,floatBytes:0,uploadBytes:0,ms:0},w=t=>{if(!c.has(t)){const o=new e.Group;o.name=t,c.set(t,o),l.add(o)}return c.get(t)},S=function(t,o,s){let n=arguments.length>3&&void 0!==arguments[3]?arguments[3]:null,a=arguments.length>4&&void 0!==arguments[4]?arguments[4]:null;const i=f[t],l=n&&Object.keys(i.maps).length?n.join(","):"",c=null!==a&&i.physical.thickness>0?a:"",u="".concat(t,"|").concat(o,"|").concat(s,"|").concat(l,"|").concat(c);if(!d.has(u)){const t=function(e,t,o){var s;let r=!(arguments.length>3&&void 0!==arguments[3])||arguments[3];const n=new e.MeshPhysicalMaterial;n.name=t.name,n.color.setRGB(t.color[0],t.color[1],t.color[2],e.LinearSRGBColorSpace),n.opacity=t.opacity,n.roughness=t.roughness,n.metalness=t.metalness,n.emissive.setRGB(t.emissive[0],t.emissive[1],t.emissive[2],e.LinearSRGBColorSpace),n.emissiveIntensity=t.emissiveIntensity,n.transparent=t.transparent,n.depthWrite=t.depthWrite,n.alphaTest=t.alphaTest,n.side=(null!==(s=t.doubleSided)&&void 0!==s?s:o)?e.DoubleSide:e.FrontSide,n.normalScale.set(t.normalScale,r?-t.normalScale:t.normalScale),r&&(n.clearcoatNormalScale.y*=-1),n.aoMapIntensity=t.aoMapIntensity;for(const[i,l]of Object.entries(t.physical)){var a;null!==(a=n[i])&&void 0!==a&&a.isColor&&Array.isArray(l)?n[i].setRGB(l[0],l[1],l[2],e.LinearSRGBColorSpace):"number"===typeof l&&(n[i]=l)}return n}(e,i,o,s);""!==c&&(t.thickness=ae(i.physical.thickness,a));for(const[e,o]of Object.entries(i.maps)){const s=l?o.matrix?ce(o.matrix,n).map(e=>e+0):n:o.matrix;p.push([t,e,z(o.path,r),o.role,o.wrap,s])}d.set(u,t)}return d.get(u)};let A=null;const _=[];return{root:l,bodies:c,geometries:u,materials:d,warnings:m,receive:t=>{if("meta"===t.type)(e=>{h=e.meta,v=Z(a,h),b.compact=v,f=(h.materials||[]).map(ye);for(const t of f){for(const e of t.gaps)m.push({code:"material",message:"".concat(t.name,": ").concat(e)});for(const e of Object.values(t.maps))o.use(z(e.path,r))}y=new Map;for(const t of h.instances||[]){const e=W(t.path);e&&w(e.body),y.has(t.geometry)||y.set(t.geometry,[]),y.get(t.geometry).push(t)}for(const t of h.warnings||[])if("material-fallback"===t.code){const e=ve(h.materials);e&&m.push(e)}else We(t)||m.push(t)})(t);else if("geometry"===t.type)(t=>{var o;let{index:s,meta:r,arrays:n}=t;if(!r)return;if(!n)throw new Error("a geometry without its arrays");const a=new e.BufferGeometry,c=performance.now(),d=le(n,v,i);b.ms+=performance.now()-c;const p=d.positionLattice;let h=null;if(p){a.setAttribute("position",new e.InterleavedBufferAttribute(new e.InterleavedBuffer(p.array,4),3,0,!1));const t=2**p.k;h=(new e.Matrix4).makeScale(t,t,t).setPosition(p.offset[0]*t,p.offset[1]*t,p.offset[2]*t),a.boundingBox=new e.Box3(new e.Vector3(...p.min),new e.Vector3(...p.max))}else a.setAttribute("position",new e.BufferAttribute(d.position,3)),a.boundingBox=(new e.Box3).setFromArray(r.bounds);null!==(o=d.normal)&&void 0!==o&&o.bits?a.setAttribute("normal",new e.InterleavedBufferAttribute(new e.InterleavedBuffer(d.normal.array,4),3,0,!0)):d.normal&&a.setAttribute("normal",new e.BufferAttribute(d.normal,3)),d.uvs.forEach((t,o)=>a.setAttribute(o?"uv".concat(o):"uv",new e.BufferAttribute(t.array||t,2,!1)));const f=d.uvLattice?ne(d.uvLattice):null;var M;a.setIndex(new e.BufferAttribute(n.indices,1)),a.boundingSphere=a.boundingBox.getBoundingSphere(new e.Sphere),v&&(b.geometries+=1,b.position+=p?1:0,b.normal+=null!==(M=d.normal)&&void 0!==M&&M.bits?1:0,b.uv+=f?1:0),b.floatBytes+=d.bytes.float,b.uploadBytes+=d.bytes.upload,r.groups.length>1&&r.groups.forEach((e,t)=>{let[o,s]=e;return a.addGroup(o,s,t)}),r.hasColors&&m.push({code:"vertex-colors",message:"geometry ".concat(s,": vertex colours ignored")}),u.push(a);const A=r.groups.reduce((e,t)=>{let[,o]=t;return e+o/3},0),_=void 0===a.attributes.tangent;for(const i of y.get(s)||[]){const t=r.groups.map(e=>{let[,,t]=e;return S(void 0!==t&&Object.hasOwn(i.subsets||{},t)?i.subsets[t]:i.material,!!i.doubleSided,_,f,p?p.k:null)}),o=new e.Mesh(a,t.length>1?t:t[0]),s=W(i.path);o.name=s?s.name:i.path.split("/").pop(),o.matrix.fromArray(i.matrix),h&&o.matrix.multiply(h),o.matrix.decompose(o.position,o.quaternion,o.scale),s?w(s.body).add(o):(g.loose+=1,l.add(o)),g.meshes+=1,g.triangles+=A}})(t);else if("collider"===t.type){var n,c;_.push({meta:t.meta,points:(null===(n=t.arrays)||void 0===n?void 0:n.points)||null,indices:(null===(c=t.arrays)||void 0===c?void 0:c.indices)||null})}else if("scene"===t.type){const e=t.stats||{},{warnings:o}=e,r=(0,s.A)(e,M);A=r;for(const t of o||[])We(t)||m.push(t)}},attachMaps:()=>{for(const[t,s,r,n,a,i]of p)t[s]=o.texture(e,r,n,a,i);for(const e of d.values())e.needsUpdate=!0},counts:g,attrs:b,colliders:_,stats:()=>A,meta:()=>h,tier:n}}function Te(e,t,o){let s=arguments.length>3&&void 0!==arguments[3]?arguments[3]:[];const r={asked:!!e,read:!1,colliders:(null===o||void 0===o?void 0:o.length)||0,problems:[]};if(!e)return{articulation:null,info:r};if(null===t||void 0===t||!t.physics)return r.problems.push("the reader reports no physics (a reader without UsdPhysics)"),{articulation:null,info:r};r.read=!0;let n=null;try{n=function(e){var t,o;let s=arguments.length>1&&void 0!==arguments[1]?arguments[1]:[];g(e&&Array.isArray(e.prims),"no physics in the reader's meta"),g(!e.root||e.root.path===a,"the default prim is ".concat(null===(t=e.root)||void 0===t?void 0:t.path,", not ").concat(a));const r=b(new Map(e.prims.map(e=>[e.path,e])).get(a)),n=JSON.parse(JSON.stringify(u)),c={};for(const[a,[i,l]]of Object.entries(d))h(r,i)&&(c[a]=l?JSON.parse(r[i]):r[i]);const p=null===(o=e.root)||void 0===o?void 0:o.extentsHint;Array.isArray(p)&&p.length>=2&&(n.bbox=[[...p[0]],[...p[1]]]),h(c,"kind")&&(n.kind=c.kind,delete c.kind);const m="robot"===n.kind,v=[],M=new Set;for(const a of e.prims){const e=f(a.path);if(y(a.path)!==i||!e.startsWith("b")||"Xform"!==a.type)continue;const t=b(a),o=new Set(a.apiSchemas||[]);g(h(t,"simready:role")&&h(t,"simready:colliders"),"".concat(a.path,": no simready:role / simready:colliders")),v.push({id:e,role:t["simready:role"],rigid:o.has("PhysicsRigidBodyAPI"),mass_kg:o.has("PhysicsMassAPI")&&h(t,"physics:mass")?t["physics:mass"]:null,colliders:Math.trunc(Number(t["simready:colliders"]))}),M.add(e)}const S=[];for(const a of s){var A;const e=(null===a||void 0===a||null===(A=a.meta)||void 0===A?void 0:A.path)||"",t=e.split("/");if(6!==t.length||y(y(y(e)))!==i||"collision"!==t[4])continue;if(!M.has(t[3]))continue;const o=a.points||new Float32Array(0),s=a.indices||new Uint32Array(0),r=[];for(let a=0;a+2<o.length;a+=3)r.push([o[a],o[a+1],o[a+2]]);const n=[];for(let a=0;a<s.length;a+=3)n.push(Array.from(s.subarray(a,Math.min(a+3,s.length))));S.push([t[5],{body:t[3],points:r,faces:n}])}S.sort((e,t)=>e[0]<t[0]?-1:e[0]>t[0]?1:0);const _=[],x=[];for(const a of e.prims){if(y(a.path)!==l)continue;const{row:e,tree:t}=w(a,m);_.push(e),t&&x.push(t)}return x.sort((e,t)=>e[0]-t[0]),n.sequence=h(c,"sequence")?c.sequence:null,n.order=h(c,"order")?c.order:[],delete c.sequence,delete c.order,n.bodies=v,n.joints=_,n.tree=x.map(e=>{let[,t]=e;return t}),n.colliders=S.map(e=>{let[,t]=e;return t}),n.selftest=h(c,"selftest")?c.selftest:[],delete c.selftest,Object.assign(n,c),n}(t.physics,o||[]),r.problems.push(...function(e){const t=((null===e||void 0===e?void 0:e.bodies)||[]).reduce((e,t)=>e+(Number(t.colliders)||0),0),o=((null===e||void 0===e?void 0:e.colliders)||[]).length;return t===o?[]:["".concat(t," colliders declared, ").concat(o," read")]}(n))}catch(c){r.problems.push((null===c||void 0===c?void 0:c.message)||String(c))}return r.problems.length&&(n=null,s.push({code:"physics",message:"articulation not read from the USD: ".concat(r.problems.join("; "))})),{articulation:n,info:r}}async function Ne(e,t,o){let s,{signal:r,headers:n}=o;try{s=await e(t,{signal:r,headers:n,credentials:"same-origin"})}catch(a){throw new R(null!==r&&void 0!==r&&r.aborted?"aborted":"fetch","webUsdLoader: ".concat(t,": ").concat((null===a||void 0===a?void 0:a.message)||a),{cause:a,url:t})}if(!s.ok)throw new R("fetch","webUsdLoader: ".concat(t,": HTTP ").concat(s.status),{url:t,status:s.status});return s.blob()}async function Fe(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};const{tier:s=1,ktx2:n=null,ktx2Hint:a=null,signal:i=null,headers:l,onStage:u=null,compact:d=null,normals:p="int8",physics:m=!1,colliders:h=!0}=t,f=!!m&&1===s,y=t.fetchFn||function(){return fetch(...arguments)},v=performance.now(),g={},b=e=>{g[e]=Math.round(10*(performance.now()-v))/10,null===u||void 0===u||u(e,g[e])};if(!be)throw new R("reader","webUsdLoader: no reader set");if(null!==i&&void 0!==i&&i.aborted)throw new R("aborted","webUsdLoader: the load was aborted",{url:e});const w=new URL(e,"undefined"===typeof window?void 0:window.location.href).href,M=new AbortController,A=()=>M.abort(i.reason);null===i||void 0===i||i.addEventListener("abort",A,{once:!0});const L=Ie({ktx2:n,fetchFn:y,headers:l,signal:M.signal,t0:v});for(const o of D(a,w).values())L.start(o,!0);a&&b("hintStarted");const U=T(s),B=Promise.all(U.map(e=>Ne(y,e===S?w:F(e,w),{signal:M.signal,headers:l})));B.catch(()=>{});const E=f&&h?Ne(y,F(_,w),{signal:M.signal,headers:l}).catch(()=>null):Promise.resolve(null),C=Promise.all([o.e(435),o.e(408)]).then(o.bind(o,408)),I=null===Me,W=async function(){const e=await ke(),t=Se;return Se=null,t&&(await t.ready,!t.dead)?{slot:t,module:e}:{slot:Ue(),module:e}}();W.catch(()=>{});let N=null,z=!1;const G={posted:!1};let q=null;const J=()=>{if(M.signal.aborted)throw new R("aborted","webUsdLoader: the load was aborted",{url:e})};try{const[{slot:t,module:o},n,a,i]=await Promise.all([W,B,C,E]);N=t,z=!0,I&&null!==Me&&(g.wasmCompile=Math.round(10*Me)/10),b("ready"),J(),q=je(a,{maps:L,base:w,tier:s,compact:d,normals:p});const l=new Map([[x,new Blob([j(s)],{type:"text/plain"})]]);U.forEach((e,t)=>l.set(e,n[t])),i&&l.set(_,i);const u={url:k+x,wasmModule:o,textures:P,files:l};f&&(u.physics={namespaces:c});if(Be(N,await Oe(N,u,q.receive,M.signal,G)),N=null,b("geometry"),J(),!q.bodies.size)throw new R("shape","webUsdLoader: no piece under /Asset/Bodies",{url:e});const m=Te(f,q.meta(),q.colliders,q.warnings);f&&b("physics"),await L.settle(),J(),b("textures"),J(),q.attachMaps();for(const e of L.unused())e.dispose();b("total"),J();const h=q.stats()||{},y=L.all(),v=[...L.files.values()],S=()=>{q.geometries.forEach(e=>e.dispose());for(const e of q.materials.values())e.dispose();y.forEach(e=>e.dispose())};return{scene:q.root,bodies:q.bodies,materials:[...q.materials.values()],textures:y,articulation:m.articulation,info:{tier:s,meshes:q.counts.meshes,triangles:q.counts.triangles,loose:q.counts.loose,bodies:q.bodies.size,geometries:q.geometries.length,materials:q.materials.size,maps:v.filter(e=>e.used).length,hinted:v.filter(e=>e.hinted).length,hintMissed:v.filter(e=>e.used&&!e.hinted).length,hintUnused:v.filter(e=>!e.used).length,mapFiles:v.map(e=>({url:e.url,hinted:e.hinted,used:e.used,startMs:Math.round(e.startMs),readyMs:null===e.readyMs?null:Math.round(e.readyMs)})),reader:h,warnings:q.warnings,attributes:(0,r.A)((0,r.A)({},q.attrs),{},{ms:Math.round(10*q.attrs.ms)/10}),physics:m.info},timings:g,dispose:S}}catch(Y){if(M.abort(),N?G.posted?Pe(N):Be(N,0):z||W.then(e=>Be(e.slot,0),()=>{}),q){q.geometries.forEach(e=>e.dispose());for(const e of q.materials.values())e.dispose()}const t=new Set(L.all());if(L.files.forEach(e=>{e.texture?t.add(e.texture):e.promise.then(e=>e.dispose(),()=>{})}),t.forEach(e=>e.dispose()),O(Y))throw Y;throw new R(null!==i&&void 0!==i&&i.aborted?"aborted":"compose","webUsdLoader: ".concat((null===Y||void 0===Y?void 0:Y.message)||Y),{cause:Y,url:e})}finally{null===i||void 0===i||i.removeEventListener("abort",A)}}function ze(){_e(null),Ee=null,Ae=0,B=null}const De=()=>({spawned:Ae,kept:!!Se,compiled:!!we})}}]);
|
services/explorer/dist/static/js/hash-wasm.d37b139f.chunk.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*! For license information please see hash-wasm.d37b139f.chunk.js.LICENSE.txt */
|
| 2 |
+
"use strict";(self.webpackChunkdeepsearch_ui=self.webpackChunkdeepsearch_ui||[]).push([[324],{441(A,I,g){g.d(I,{createSHA1:()=>R,createSHA256:()=>J});var B;function Q(A,I,g,B){return new(g||(g=Promise))(function(Q,E){function i(A){try{d(B.next(A))}catch(I){E(I)}}function c(A){try{d(B.throw(A))}catch(I){E(I)}}function d(A){var I;A.done?Q(A.value):(I=A.value,I instanceof g?I:new g(function(A){A(I)})).then(i,c)}d((B=B.apply(A,I||[])).next())})}"function"===typeof SuppressedError&&SuppressedError;class E{constructor(){this.mutex=Promise.resolve()}lock(){let A=()=>{};return this.mutex=this.mutex.then(()=>new Promise(A)),new Promise(I=>{A=I})}dispatch(A){return Q(this,void 0,void 0,function*(){const I=yield this.lock();try{return yield Promise.resolve(A())}finally{I()}})}}const i="undefined"!==typeof globalThis?globalThis:"undefined"!==typeof self?self:"undefined"!==typeof window?window:g.g,c=null!==(B=i.Buffer)&&void 0!==B?B:null,d=i.TextEncoder?new i.TextEncoder:null;function n(A,I){return(15&A)+(A>>6|A>>3&8)<<4|(15&I)+(I>>6|I>>3&8)}function a(A,I){const g=I.length>>1;for(let B=0;B<g;B++){const g=B<<1;A[B]=n(I.charCodeAt(g),I.charCodeAt(g+1))}}const o="a".charCodeAt(0)-10,y="0".charCodeAt(0);function C(A,I,g){let B=0;for(let Q=0;Q<g;Q++){let g=I[Q]>>>4;A[B++]=g>9?g+o:g+y,g=15&I[Q],A[B++]=g>9?g+o:g+y}return String.fromCharCode.apply(null,A)}const N=null!==c?A=>{if("string"===typeof A){const I=c.from(A,"utf8");return new Uint8Array(I.buffer,I.byteOffset,I.length)}if(c.isBuffer(A))return new Uint8Array(A.buffer,A.byteOffset,A.length);if(ArrayBuffer.isView(A))return new Uint8Array(A.buffer,A.byteOffset,A.byteLength);throw new Error("Invalid data type!")}:A=>{if("string"===typeof A)return d.encode(A);if(ArrayBuffer.isView(A))return new Uint8Array(A.buffer,A.byteOffset,A.byteLength);throw new Error("Invalid data type!")},e="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",D=new Uint8Array(256);for(let k=0;k<64;k++)D[e.charCodeAt(k)]=k;function F(A){let I=Math.floor(.75*A.length);const g=A.length;return"="===A[g-1]&&(I-=1,"="===A[g-2]&&(I-=1)),I}function q(A){const I=F(A),g=A.length,B=new Uint8Array(I);let Q=0;for(let E=0;E<g;E+=4){const I=D[A.charCodeAt(E)],g=D[A.charCodeAt(E+1)],i=D[A.charCodeAt(E+2)],c=D[A.charCodeAt(E+3)];B[Q]=I<<2|g>>4,Q+=1,B[Q]=(15&g)<<4|i>>2,Q+=1,B[Q]=(3&i)<<6|63&c,Q+=1}return B}const z=16384,t=new E,H=new Map;function h(A,I){return Q(this,void 0,void 0,function*(){let g=null,B=null,E=!1;if("undefined"===typeof WebAssembly)throw new Error("WebAssembly is not supported in this environment!");const i=()=>new DataView(g.exports.memory.buffer).getUint32(g.exports.STATE_SIZE,!0),c=t.dispatch(()=>Q(this,void 0,void 0,function*(){if(!H.has(A.name)){const I=q(A.data),g=WebAssembly.compile(I);H.set(A.name,g)}const I=yield H.get(A.name);g=yield WebAssembly.instantiate(I,{})})),d=function(){let A=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null;E=!0,g.exports.Hash_Init(A)},o=A=>{if(!E)throw new Error("update() called before init()");(A=>{let I=0;for(;I<A.length;){const Q=A.subarray(I,I+z);I+=Q.length,B.set(Q),g.exports.Hash_Update(Q.length)}})(N(A))},y=new Uint8Array(2*I),e=function(A){let Q=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null;if(!E)throw new Error("digest() called before init()");return E=!1,g.exports.Hash_Final(Q),"binary"===A?B.slice(0,I):C(y,B,I)},D=A=>"string"===typeof A?A.length<4096:A.byteLength<z;let F=D;switch(A.name){case"argon2":case"scrypt":F=()=>!0;break;case"blake2b":case"blake2s":F=(A,I)=>I<=512&&D(A);break;case"blake3":F=(A,I)=>0===I&&D(A);break;case"xxhash64":case"xxhash3":case"xxhash128":case"crc64":F=()=>!1}return yield(()=>Q(this,void 0,void 0,function*(){g||(yield c);const A=g.exports.Hash_GetBuffer(),I=g.exports.memory.buffer;B=new Uint8Array(I,A,z)}))(),{getMemory:()=>B,writeMemory:function(A){let I=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0;B.set(A,I)},getExports:()=>g.exports,setMemorySize:A=>{g.exports.Hash_SetMemorySize(A);const I=g.exports.Hash_GetBuffer(),Q=g.exports.memory.buffer;B=new Uint8Array(Q,I,A)},init:d,update:o,digest:e,save:()=>{if(!E)throw new Error("save() can only be called after init() and before digest()");const I=g.exports.Hash_GetState(),B=i(),Q=g.exports.memory.buffer,c=new Uint8Array(Q,I,B),d=new Uint8Array(4+B);return a(d,A.hash),d.set(c,4),d},load:I=>{if(!(I instanceof Uint8Array))throw new Error("load() expects an Uint8Array generated by save()");const B=g.exports.Hash_GetState(),Q=i(),c=4+Q,d=g.exports.memory.buffer;if(I.length!==c)throw new Error("Bad state length (expected ".concat(c," bytes, got ").concat(I.length,")"));if(!function(A,I){if(A.length!==2*I.length)return!1;for(let g=0;g<I.length;g++){const B=g<<1;if(I[g]!==n(A.charCodeAt(B),A.charCodeAt(B+1)))return!1}return!0}(A.hash,I.subarray(0,4)))throw new Error("This state was written by an incompatible hash implementation");const a=I.subarray(4);new Uint8Array(d,B,Q).set(a),E=!0},calculate:function(A){let Q=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null,E=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null;if(!F(A,Q))return d(Q),o(A),e("hex",E);const i=N(A);return B.set(i),g.exports.Hash_Calculate(i.length,Q,E),C(y,B,I)},hashLength:I}})}new E;new E;new DataView(new ArrayBuffer(4));new E;new E;new E;new E;new Uint8Array(8);new E;new E;var M={name:"sha1",data:"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",hash:"6b530c24"};new E;function R(){return h(M,20).then(A=>{A.init();const I={init:()=>(A.init(),I),update:g=>(A.update(g),I),digest:I=>A.digest(I),save:()=>A.save(),load:g=>(A.load(g),I),blockSize:64,digestSize:20};return I})}new E;new E;var G={name:"sha256",data:"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c2pBx6KerX1qIhkgASADcyACcSABIANxcyABQR53IAFBE3dzIAFBCndzaiAaaiICaiIJIBMgEnNxIBJzaiAJQRp3IAlBFXdzIAlBB3dzakHRxqk2aiIaIAIgAXMgA3EgAiABcXMgAkEedyACQRN3cyACQQp3c2ogGGoiA2oiESAJIBNzcSATc2ogEUEadyARQRV3cyARQQd3c2pB59KkoQFqIhggAyACcyABcSADIAJxcyADQR53IANBE3dzIANBCndzaiAUaiIBaiISIBEgCXNxIAlzaiASQRp3IBJBFXdzIBJBB3dzakGFldy9AmoiFCABIANzIAJxIAEgA3FzIAFBHncgAUETd3MgAUEKd3NqIBdqIgJqIhMgI2ogJiASaiAiIBFqICUgCWogEyASIBFzcSARc2ogE0EadyATQRV3cyATQQd3c2pBuMLs8AJqIhcgAiABcyADcSACIAFxcyACQR53IAJBE3dzIAJBCndzaiAZaiIDaiIJIBMgEnNxIBJzaiAJQRp3IAlBFXdzIAlBB3dzakH827HpBGoiGSADIAJzIAFxIAMgAnFzIANBHncgA0ETd3MgA0EKd3NqIBpqIgFqIhEgCSATc3EgE3NqIBFBGncgEUEVd3MgEUEHd3NqQZOa4JkFaiIaIAEgA3MgAnEgASADcXMgAUEedyABQRN3cyABQQp3c2ogGGoiAmoiEiARIAlzcSAJc2ogEkEadyASQRV3cyASQQd3c2pB1OapqAZqIhggAiABcyADcSACIAFxcyACQR53IAJBE3dzIAJBCndzaiAUaiIDaiITaiAoIBJqICQgEWogJyAJaiATIBIgEXNxIBFzaiATQRp3IBNBFXdzIBNBB3dzakG7laizB2oiFCADIAJzIAFxIAMgAnFzIANBHncgA0ETd3MgA0EKd3NqIBdqIgFqIgkgEyASc3EgEnNqIAlBGncgCUEVd3MgCUEHd3NqQa6Si454aiIXIAEgA3MgAnEgASADcXMgAUEedyABQRN3cyABQQp3c2ogGWoiAmoiESAJIBNzcSATc2ogEUEadyARQRV3cyARQQd3c2pBhdnIk3lqIhkgAiABcyADcSACIAFxcyACQR53IAJBE3dzIAJBCndzaiAaaiIDaiISIBEgCXNxIAlzaiASQRp3IBJBFXdzIBJBB3dzakGh0f+VemoiGiADIAJzIAFxIAMgAnFzIANBHncgA0ETd3MgA0EKd3NqIBhqIgFqIhNqICogEmogLSARaiApIAlqIBMgEiARc3EgEXNqIBNBGncgE0EVd3MgE0EHd3NqQcvM6cB6aiIYIAEgA3MgAnEgASADcXMgAUEedyABQRN3cyABQQp3c2ogFGoiAmoiCSATIBJzcSASc2ogCUEadyAJQRV3cyAJQQd3c2pB8JauknxqIhQgAiABcyADcSACIAFxcyACQR53IAJBE3dzIAJBCndzaiAXaiIDaiIRIAkgE3NxIBNzaiARQRp3IBFBFXdzIBFBB3dzakGjo7G7fGoiFyADIAJzIAFxIAMgAnFzIANBHncgA0ETd3MgA0EKd3NqIBlqIgFqIhIgESAJc3EgCXNqIBJBGncgEkEVd3MgEkEHd3NqQZnQy4x9aiIZIAEgA3MgAnEgASADcXMgAUEedyABQRN3cyABQQp3c2ogGmoiAmoiE2ogMCASaiAvIBFqICsgCWogEyASIBFzcSARc2ogE0EadyATQRV3cyATQQd3c2pBpIzktH1qIhogAiABcyADcSACIAFxcyACQR53IAJBE3dzIAJBCndzaiAYaiIDaiIJIBMgEnNxIBJzaiAJQRp3IAlBFXdzIAlBB3dzakGF67igf2oiGCADIAJzIAFxIAMgAnFzIANBHncgA0ETd3MgA0EKd3NqIBRqIgFqIhEgCSATc3EgE3NqIBFBGncgEUEVd3MgEUEHd3NqQfDAqoMBaiIUIAEgA3MgAnEgASADcXMgAUEedyABQRN3cyABQQp3c2ogF2oiAmoiEiARIAlzcSAJc2ogEkEadyASQRV3cyASQQd3c2pBloKTzQFqIhcgAiABcyADcSACIAFxcyACQR53IAJBE3dzIAJBCndzaiAZaiIDaiITIDZqIDIgEmogNSARaiAxIAlqIBMgEiARc3EgEXNqIBNBGncgE0EVd3MgE0EHd3NqQYjY3fEBaiIZIAMgAnMgAXEgAyACcXMgA0EedyADQRN3cyADQQp3c2ogGmoiAWoiCSATIBJzcSASc2ogCUEadyAJQRV3cyAJQQd3c2pBzO6hugJqIhogASADcyACcSABIANxcyABQR53IAFBE3dzIAFBCndzaiAYaiICaiIRIAkgE3NxIBNzaiARQRp3IBFBFXdzIBFBB3dzakG1+cKlA2oiGCACIAFzIANxIAIgAXFzIAJBHncgAkETd3MgAkEKd3NqIBRqIgNqIhIgESAJc3EgCXNqIBJBGncgEkEVd3MgEkEHd3NqQbOZ8MgDaiIUIAMgAnMgAXEgAyACcXMgA0EedyADQRN3cyADQQp3c2ogF2oiAWoiE2ogLEEZdyAsQQ53cyAsQQN2cyAoaiA0aiAzQQ93IDNBDXdzIDNBCnZzaiIXIBJqIDcgEWogMyAJaiATIBIgEXNxIBFzaiATQRp3IBNBFXdzIBNBB3dzakHK1OL2BGoiGyABIANzIAJxIAEgA3FzIAFBHncgAUETd3MgAUEKd3NqIBlqIgJqIgkgEyASc3EgEnNqIAlBGncgCUEVd3MgCUEHd3NqQc+U89wFaiIZIAIgAXMgA3EgAiABcXMgAkEedyACQRN3cyACQQp3c2ogGmoiA2oiESAJIBNzcSATc2ogEUEadyARQRV3cyARQQd3c2pB89+5wQZqIhogAyACcyABcSADIAJxcyADQR53IANBE3dzIANBCndzaiAYaiIBaiISIBEgCXNxIAlzaiASQRp3IBJBFXdzIBJBB3dzakHuhb6kB2oiHCABIANzIAJxIAEgA3FzIAFBHncgAUETd3MgAUEKd3NqIBRqIgJqIhNqIC5BGXcgLkEOd3MgLkEDdnMgKmogNmogLUEZdyAtQQ53cyAtQQN2cyApaiA1aiAXQQ93IBdBDXdzIBdBCnZzaiIUQQ93IBRBDXdzIBRBCnZzaiIYIBJqIDkgEWogFCAJaiATIBIgEXNxIBFzaiATQRp3IBNBFXdzIBNBB3dzakHvxpXFB2oiCSACIAFzIANxIAIgAXFzIAJBHncgAkETd3MgAkEKd3NqIBtqIgNqIhEgEyASc3EgEnNqIBFBGncgEUEVd3MgEUEHd3NqQZTwoaZ4aiIbIAMgAnMgAXEgAyACcXMgA0EedyADQRN3cyADQQp3c2ogGWoiAWoiEiARIBNzcSATc2ogEkEadyASQRV3cyASQQd3c2pBiISc5nhqIhkgASADcyACcSABIANxcyABQR53IAFBE3dzIAFBCndzaiAaaiICaiITIBIgEXNxIBFzaiATQRp3IBNBFXdzIBNBB3dzakH6//uFeWoiGiACIAFzIANxIAIgAXFzIAJBHncgAkETd3MgAkEKd3NqIBxqIgNqIhQgPGo2AuSJAUEAID8gAyACcyABcSADIAJxcyADQR53IANBE3dzIANBCndzaiAJaiIBIANzIAJxIAEgA3FzIAFBHncgAUETd3MgAUEKd3NqIBtqIgIgAXMgA3EgAiABcXMgAkEedyACQRN3cyACQQp3c2ogGWoiAyACcyABcSADIAJxcyADQR53IANBE3dzIANBCndzaiAaaiIJajYC1IkBQQAgPSAvQRl3IC9BDndzIC9BA3ZzICtqIDdqIBhBD3cgGEENd3MgGEEKdnNqIhggEWogFCATIBJzcSASc2ogFEEadyAUQRV3cyAUQQd3c2pB69nBonpqIhkgAWoiEWo2AuCJAUEAIEEgCSADcyACcSAJIANxcyAJQR53IAlBE3dzIAlBCndzaiAZaiIBajYC0IkBQQAgPiAwQRl3IDBBDndzIDBBA3ZzIC9qIBdqIDpBD3cgOkENd3MgOkEKdnNqIBJqIBEgFCATc3EgE3NqIBFBGncgEUEVd3MgEUEHd3NqQffH5vd7aiIXIAJqIhJqNgLciQFBACBDIAEgCXMgA3EgASAJcXMgAUEedyABQRN3cyABQQp3c2ogF2oiAmo2AsyJAUEAIDsgNEEZdyA0QQ53cyA0QQN2cyAwaiA4aiAYQQ93IBhBDXdzIBhBCnZzaiATaiASIBEgFHNxIBRzaiASQRp3IBJBFXdzIBJBB3dzakHy8cWzfGoiESADamo2AtiJAUEAIAAgAiABcyAJcSACIAFxcyACQR53IAJBE3dzIAJBCndzaiARamo2AsiJAQuyBgIEfwF+QQAoAsCJASIAQQJ2QQ9xIgFBAnRBgIkBaiICIAIoAgBBfyAAQQN0IgB0QX9zcUGAASAAdHM2AgACQAJAAkAgAUEOSQ0AAkAgAUEORw0AQQBBADYCvIkBC0GAiQEQA0EAIQIMAQsgAUENRg0BIAFBAWohAgsgAiEDAkBBBiACa0EHcSIARQ0AIAIgAGohAyACQQJ0QYCJAWohAQNAIAFBADYCACABQQRqIQEgAEF/aiIADQALCyACQXlqQQdJDQAgA0ECdCEBA0AgAUGYiQFqQgA3AgAgAUGQiQFqQgA3AgAgAUGIiQFqQgA3AgAgAUGAiQFqQgA3AgAgAUEgaiIBQThHDQALC0EAIQFBAEEAKQPAiQEiBKciAEEbdCAAQQt0QYCA/AdxciAAQQV2QYD+A3EgAEEDdEEYdnJyNgK8iQFBACAEQh2IpyIAQRh0IABBgP4DcUEIdHIgAEEIdkGA/gNxIABBGHZycjYCuIkBQYCJARADQQBBACgC5IkBIgBBGHQgAEGA/gNxQQh0ciAAQQh2QYD+A3EgAEEYdnJyNgLkiQFBAEEAKALgiQEiAEEYdCAAQYD+A3FBCHRyIABBCHZBgP4DcSAAQRh2cnI2AuCJAUEAQQAoAtyJASIAQRh0IABBgP4DcUEIdHIgAEEIdkGA/gNxIABBGHZycjYC3IkBQQBBACgC2IkBIgBBGHQgAEGA/gNxQQh0ciAAQQh2QYD+A3EgAEEYdnJyNgLYiQFBAEEAKALUiQEiAEEYdCAAQYD+A3FBCHRyIABBCHZBgP4DcSAAQRh2cnI2AtSJAUEAQQAoAtCJASIAQRh0IABBgP4DcUEIdHIgAEEIdkGA/gNxIABBGHZycjYC0IkBQQBBACgCzIkBIgBBGHQgAEGA/gNxQQh0ciAAQQh2QYD+A3EgAEEYdnJyNgLMiQFBAEEAKALIiQEiAEEYdCAAQYD+A3FBCHRyIABBCHZBgP4DcSAAQRh2cnI2AsiJAQJAQQAoAuiJASICRQ0AQQAhAANAIAFBgAlqIAFByIkBai0AADoAACABQQFqIQEgAiAAQQFqIgBB/wFxSw0ACwsLBgBBgIkBC6MBAEEAQgA3A8CJAUEAQRxBICABQeABRiIBGzYC6IkBQQBCp5/mp8b0k/2+f0Krs4/8kaOz8NsAIAEbNwPgiQFBAEKxloD+n6KFrOgAQv+kuYjFkdqCm38gARs3A9iJAUEAQpe6w4OTp5aHd0Ly5rvjo6f9p6V/IAEbNwPQiQFBAELYvZaI/KC1vjZC58yn0NbQ67O7fyABGzcDyIkBIAAQAhAECwsLAQBBgAgLBHAAAAA=",hash:"8c18dd94"};new E;new E;function J(){return h(G,32).then(A=>{A.init(256);const I={init:()=>(A.init(256),I),update:g=>(A.update(g),I),digest:I=>A.digest(I),save:()=>A.save(),load:g=>(A.load(g),I),blockSize:64,digestSize:32};return I})}new E;new E;new E;new E;new Uint8Array(8);new E;new Uint8Array(8);new E;new Uint8Array(8);new E;new E;new E}}]);
|
services/explorer/dist/static/js/hash-wasm.d37b139f.chunk.js.LICENSE.txt
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*!
|
| 2 |
+
* hash-wasm (https://www.npmjs.com/package/hash-wasm)
|
| 3 |
+
* (c) Dani Biro
|
| 4 |
+
* @license MIT
|
| 5 |
+
*/
|
services/explorer/dist/static/js/main.846b9fc7.js
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
services/explorer/dist/static/js/main.846b9fc7.js.LICENSE.txt
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/**
|
| 2 |
+
* @license React
|
| 3 |
+
* react-dom.production.min.js
|
| 4 |
+
*
|
| 5 |
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
| 6 |
+
*
|
| 7 |
+
* This source code is licensed under the MIT license found in the
|
| 8 |
+
* LICENSE file in the root directory of this source tree.
|
| 9 |
+
*/
|
| 10 |
+
|
| 11 |
+
/**
|
| 12 |
+
* @license React
|
| 13 |
+
* react-jsx-runtime.production.min.js
|
| 14 |
+
*
|
| 15 |
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
| 16 |
+
*
|
| 17 |
+
* This source code is licensed under the MIT license found in the
|
| 18 |
+
* LICENSE file in the root directory of this source tree.
|
| 19 |
+
*/
|
| 20 |
+
|
| 21 |
+
/**
|
| 22 |
+
* @license React
|
| 23 |
+
* react.production.min.js
|
| 24 |
+
*
|
| 25 |
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
| 26 |
+
*
|
| 27 |
+
* This source code is licensed under the MIT license found in the
|
| 28 |
+
* LICENSE file in the root directory of this source tree.
|
| 29 |
+
*/
|
| 30 |
+
|
| 31 |
+
/**
|
| 32 |
+
* @license React
|
| 33 |
+
* scheduler.production.min.js
|
| 34 |
+
*
|
| 35 |
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
| 36 |
+
*
|
| 37 |
+
* This source code is licensed under the MIT license found in the
|
| 38 |
+
* LICENSE file in the root directory of this source tree.
|
| 39 |
+
*/
|
services/explorer/dist/static/usd-reader/81290bc/esm/errors.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/** Why a load failed: `aborted`, `fetch` (root layer or a resource limit), `compose`, `worker` or `webgl`. */
|
| 2 |
+
export class UsdLoadError extends Error {
|
| 3 |
+
name = "UsdLoadError";
|
| 4 |
+
code;
|
| 5 |
+
constructor(code, message, { url, status, cause } = {}) {
|
| 6 |
+
super(message, cause === undefined ? undefined : { cause });
|
| 7 |
+
this.code = code;
|
| 8 |
+
if (url !== undefined) {
|
| 9 |
+
this.url = url;
|
| 10 |
+
}
|
| 11 |
+
if (status !== undefined) {
|
| 12 |
+
this.status = status;
|
| 13 |
+
}
|
| 14 |
+
}
|
| 15 |
+
}
|
services/explorer/dist/static/usd-reader/81290bc/esm/hub-prefetch.js
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// The layers of a Hub package, listed with one tree-API call, so a load can
|
| 2 |
+
// request them all at once instead of discovering them a round trip at a time.
|
| 3 |
+
const RESOLVE = /^(https:\/\/(?:huggingface\.co|hf\.co))\/((?:datasets\/|spaces\/)?)([^/?#]+\/[^/?#]+)\/resolve\/([^/?#]+)\/([^?#]+)$/;
|
| 4 |
+
const LAYER = /\.(usd|usda|usdc)$/i;
|
| 5 |
+
const SIMREADY_PACKAGE = "com.nvidia.simready.packaging.json";
|
| 6 |
+
const MAX_FILES = 256;
|
| 7 |
+
const MAX_BYTES = 64 * 2 ** 20;
|
| 8 |
+
/**
|
| 9 |
+
* The USD layers of the package holding a Hub `resolve` URL, as `{ url, size }`:
|
| 10 |
+
* the directory with a SimReady packaging manifest among the root's parent
|
| 11 |
+
* and grandparent, else everything under the root's own directory. `eager`
|
| 12 |
+
* when a manifest declares the package, so its layers are worth requesting
|
| 13 |
+
* before the root is read. No layers, without a request, for a root at the
|
| 14 |
+
* top of its repo or any other URL, and none if the listing fails: the load then discovers layers as usual.
|
| 15 |
+
*/
|
| 16 |
+
export async function hubPackageLayers(rootUrl, request) {
|
| 17 |
+
const match = rootUrl.split(/[?#]/)[0].match(RESOLVE);
|
| 18 |
+
const none = { layers: [], eager: false };
|
| 19 |
+
if (!match) {
|
| 20 |
+
return none;
|
| 21 |
+
}
|
| 22 |
+
const [, origin, prefix, repo, revision, path] = match;
|
| 23 |
+
const parent = path.split("/").slice(0, -1);
|
| 24 |
+
// A root at the top of a repo would list, and preload, the whole repo.
|
| 25 |
+
if (!parent.length) {
|
| 26 |
+
return none;
|
| 27 |
+
}
|
| 28 |
+
const listed = parent.length > 1 ? parent.slice(0, -1) : parent;
|
| 29 |
+
try {
|
| 30 |
+
const response = await request(`${origin}/api/${prefix || "models/"}${repo}/tree/${revision}/${listed.join("/")}?recursive=true`);
|
| 31 |
+
if (!response.ok) {
|
| 32 |
+
return none;
|
| 33 |
+
}
|
| 34 |
+
const entries = await response.json();
|
| 35 |
+
const decoded = parent.map(decodeURIComponent);
|
| 36 |
+
const manifest = [decoded, decoded.slice(0, -1)].find((dir) => dir.length >= listed.length && entries.some((e) => e.path === [...dir, SIMREADY_PACKAGE].join("/")));
|
| 37 |
+
const depth = (manifest ?? decoded).length;
|
| 38 |
+
const packageDir = decoded
|
| 39 |
+
.slice(0, depth)
|
| 40 |
+
.map((name) => name + "/")
|
| 41 |
+
.join("");
|
| 42 |
+
// As the root spells it, so URLs match the ones composition resolves.
|
| 43 |
+
const base = `${origin}/${prefix}${repo}/resolve/${revision}/${parent
|
| 44 |
+
.slice(0, depth)
|
| 45 |
+
.map((name) => name + "/")
|
| 46 |
+
.join("")}`;
|
| 47 |
+
const layers = [];
|
| 48 |
+
let bytes = 0;
|
| 49 |
+
for (const { type, path: file, size } of entries) {
|
| 50 |
+
if (type !== "file" || !file.startsWith(packageDir) || !LAYER.test(file)) {
|
| 51 |
+
continue;
|
| 52 |
+
}
|
| 53 |
+
if (layers.length >= MAX_FILES || bytes + size > MAX_BYTES) {
|
| 54 |
+
continue;
|
| 55 |
+
}
|
| 56 |
+
bytes += size;
|
| 57 |
+
layers.push({
|
| 58 |
+
url: new URL(file.slice(packageDir.length).replace(/[%#?]/g, encodeURIComponent), base).href,
|
| 59 |
+
size,
|
| 60 |
+
});
|
| 61 |
+
}
|
| 62 |
+
return { layers, eager: !!manifest };
|
| 63 |
+
}
|
| 64 |
+
catch {
|
| 65 |
+
return none;
|
| 66 |
+
}
|
| 67 |
+
}
|
| 68 |
+
/**
|
| 69 |
+
* A Hub `resolve` URL pinned to the commit its branch or tag points at now,
|
| 70 |
+
* so every layer and texture of one load (all resolved against the root)
|
| 71 |
+
* comes from the same commit even if the repo is pushed to meanwhile. Unchanged,
|
| 72 |
+
* without a request, for a commit or any other URL, and if the lookup fails.
|
| 73 |
+
*/
|
| 74 |
+
export async function pinHubRevision(rootUrl, request) {
|
| 75 |
+
const match = rootUrl.split(/[?#]/)[0].match(RESOLVE);
|
| 76 |
+
if (!match) {
|
| 77 |
+
return rootUrl;
|
| 78 |
+
}
|
| 79 |
+
const [, origin, prefix, repo, revision] = match;
|
| 80 |
+
if (/^[0-9a-f]{40}$/.test(revision)) {
|
| 81 |
+
return rootUrl;
|
| 82 |
+
}
|
| 83 |
+
try {
|
| 84 |
+
const response = await request(`${origin}/api/${prefix || "models/"}${repo}/revision/${revision}?expand%5B%5D=sha`);
|
| 85 |
+
const { sha } = response.ok ? await response.json() : {};
|
| 86 |
+
if (!/^[0-9a-f]{40}$/.test(sha ?? "")) {
|
| 87 |
+
return rootUrl;
|
| 88 |
+
}
|
| 89 |
+
return rootUrl.replace(`/resolve/${revision}/`, `/resolve/${sha}/`);
|
| 90 |
+
}
|
| 91 |
+
catch {
|
| 92 |
+
return rootUrl;
|
| 93 |
+
}
|
| 94 |
+
}
|
services/explorer/dist/static/usd-reader/81290bc/esm/load-core.js
ADDED
|
@@ -0,0 +1,760 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { UsdLoadError } from "./errors.js";
|
| 2 |
+
/** The load options' defaults, and the largest image side read at all. SECURITY.md documents the limits. */
|
| 3 |
+
export const DEFAULTS = {
|
| 4 |
+
textures: "preview",
|
| 5 |
+
maxTextureSize: 1024,
|
| 6 |
+
maxConcurrentFetches: 16,
|
| 7 |
+
maxLayerBytes: 768 * 2 ** 20,
|
| 8 |
+
maxLayers: 1024,
|
| 9 |
+
maxInstances: 100000,
|
| 10 |
+
maxTriangles: 20e6,
|
| 11 |
+
maxTextureBytes: 512 * 2 ** 20,
|
| 12 |
+
maxImageSize: 16384,
|
| 13 |
+
};
|
| 14 |
+
/** Loads and composes the stage at `rootUrl`. */
|
| 15 |
+
export async function composeStage({ UsdLoader, fetchBytes, rootUrl, maxConcurrentFetches = DEFAULTS.maxConcurrentFetches, maxLayerBytes = DEFAULTS.maxLayerBytes, maxLayers = DEFAULTS.maxLayers, maxInstances = DEFAULTS.maxInstances, allowedOrigins, preload, onProgress = () => { }, physics, }) {
|
| 16 |
+
const root = rootUrl.split(/[?#]/)[0];
|
| 17 |
+
const urlOf = (path) => (path === root ? rootUrl : path);
|
| 18 |
+
const loader = new UsdLoader();
|
| 19 |
+
if (physics) {
|
| 20 |
+
loader.setPhysics([...physics]);
|
| 21 |
+
}
|
| 22 |
+
const stats = {
|
| 23 |
+
layers: 0,
|
| 24 |
+
layerBytes: 0,
|
| 25 |
+
missing: 0,
|
| 26 |
+
rounds: 0,
|
| 27 |
+
fetchMs: 0,
|
| 28 |
+
parseMs: 0,
|
| 29 |
+
composeMs: 0,
|
| 30 |
+
warnings: [],
|
| 31 |
+
};
|
| 32 |
+
const started = new Map();
|
| 33 |
+
const progress = () => onProgress({ stage: "layers", loaded: stats.layers + stats.missing, total: started.size, bytes: stats.layerBytes });
|
| 34 |
+
const throttle = limiter(maxConcurrentFetches);
|
| 35 |
+
// One budget for every layer body, charged as its bytes arrive, so fetches
|
| 36 |
+
// in parallel cannot each count on the whole remainder.
|
| 37 |
+
let heldBytes = 0;
|
| 38 |
+
const charge = (bytes, path) => {
|
| 39 |
+
heldBytes += bytes;
|
| 40 |
+
if (heldBytes > maxLayerBytes) {
|
| 41 |
+
throw resourceLimit(`layers exceed maxLayerBytes (${maxLayerBytes} bytes) at ${path}`);
|
| 42 |
+
}
|
| 43 |
+
};
|
| 44 |
+
// Re-fetched layers replace their earlier bytes, so count each path once.
|
| 45 |
+
const layerSizes = new Map();
|
| 46 |
+
// Speculative fetches by URL, dropped once composition is done. One that
|
| 47 |
+
// has not started when its layer is asked for, or that failed, gives way to
|
| 48 |
+
// the regular fetch, so the result is the same as without them. Their
|
| 49 |
+
// bytes are charged as they arrive, and stay charged once used.
|
| 50 |
+
const preloaded = new Map();
|
| 51 |
+
let composed = false;
|
| 52 |
+
// Every distinct layer URL requested, preloads included, for maxLayers.
|
| 53 |
+
const requested = new Set();
|
| 54 |
+
const startPreload = (layers) => {
|
| 55 |
+
let bytes = 0;
|
| 56 |
+
for (const { url, size } of layers) {
|
| 57 |
+
const key = urlKey(url);
|
| 58 |
+
bytes += size;
|
| 59 |
+
if (composed || bytes > maxLayerBytes) {
|
| 60 |
+
break;
|
| 61 |
+
}
|
| 62 |
+
if (requested.has(key)) {
|
| 63 |
+
continue;
|
| 64 |
+
}
|
| 65 |
+
if (requested.size >= maxLayers) {
|
| 66 |
+
break;
|
| 67 |
+
}
|
| 68 |
+
requested.add(key);
|
| 69 |
+
const entry = { started: false, charged: 0 };
|
| 70 |
+
preloaded.set(key, entry);
|
| 71 |
+
// Unused once composed: the next chunk cancels the body.
|
| 72 |
+
const budget = (bytes) => {
|
| 73 |
+
if (composed) {
|
| 74 |
+
throw new Error("composed without it");
|
| 75 |
+
}
|
| 76 |
+
entry.charged += bytes;
|
| 77 |
+
charge(bytes, url);
|
| 78 |
+
};
|
| 79 |
+
entry.bytes = throttle(async () => {
|
| 80 |
+
if (composed || preloaded.get(key) !== entry) {
|
| 81 |
+
return null;
|
| 82 |
+
}
|
| 83 |
+
entry.started = true;
|
| 84 |
+
const bytes = await fetchBytes(url, budget);
|
| 85 |
+
if (bytes) {
|
| 86 |
+
budget(bytes.byteLength - entry.charged);
|
| 87 |
+
}
|
| 88 |
+
return bytes;
|
| 89 |
+
}, { later: true }).catch(() => {
|
| 90 |
+
heldBytes -= entry.charged;
|
| 91 |
+
entry.charged = 0;
|
| 92 |
+
return null;
|
| 93 |
+
});
|
| 94 |
+
}
|
| 95 |
+
};
|
| 96 |
+
const takePreloaded = (path) => {
|
| 97 |
+
const entry = preloaded.get(urlKey(path));
|
| 98 |
+
preloaded.delete(urlKey(path));
|
| 99 |
+
return entry?.started ? entry : null;
|
| 100 |
+
};
|
| 101 |
+
// Jobs in flight. A job queues its dependencies here rather than awaiting
|
| 102 |
+
// them, so layers that reference each other cannot wait on each other.
|
| 103 |
+
const pending = [];
|
| 104 |
+
const drain = async () => {
|
| 105 |
+
while (pending.length) {
|
| 106 |
+
await Promise.all(pending.splice(0));
|
| 107 |
+
}
|
| 108 |
+
};
|
| 109 |
+
const fetchLayer = (path) => {
|
| 110 |
+
if (loader.has(path) || started.has(path)) {
|
| 111 |
+
return;
|
| 112 |
+
}
|
| 113 |
+
requested.add(urlKey(path));
|
| 114 |
+
if (requested.size > maxLayers) {
|
| 115 |
+
throw resourceLimit(`more than maxLayers (${maxLayers}) layer files at ${path}`);
|
| 116 |
+
}
|
| 117 |
+
const { refused } = requestPolicy(urlOf(path), rootUrl, allowedOrigins);
|
| 118 |
+
if (refused) {
|
| 119 |
+
started.set(path, Promise.resolve());
|
| 120 |
+
stats.missing++;
|
| 121 |
+
stats.warnings.push({ code: "layer-missing", message: `layer not fetched: ${refused}`, path });
|
| 122 |
+
loader.markUnavailable(path);
|
| 123 |
+
progress();
|
| 124 |
+
return;
|
| 125 |
+
}
|
| 126 |
+
const job = (async () => {
|
| 127 |
+
const t0 = performance.now();
|
| 128 |
+
heldBytes -= layerSizes.get(path) ?? 0;
|
| 129 |
+
layerSizes.delete(path);
|
| 130 |
+
let charged = 0;
|
| 131 |
+
const budget = (bytes) => {
|
| 132 |
+
charged += bytes;
|
| 133 |
+
charge(bytes, path);
|
| 134 |
+
};
|
| 135 |
+
// Any fetch failure, HTTP or network: the root fails the load, any
|
| 136 |
+
// other layer is left out with a warning.
|
| 137 |
+
let bytes = null;
|
| 138 |
+
let failure = null;
|
| 139 |
+
try {
|
| 140 |
+
const entry = takePreloaded(path);
|
| 141 |
+
bytes = entry && (await entry.bytes);
|
| 142 |
+
if (entry && bytes) {
|
| 143 |
+
charged = entry.charged;
|
| 144 |
+
}
|
| 145 |
+
bytes ??= await throttle(() => fetchBytes(urlOf(path), budget));
|
| 146 |
+
}
|
| 147 |
+
catch (error) {
|
| 148 |
+
heldBytes -= charged;
|
| 149 |
+
// HTTP errors carry a status; network errors are TypeErrors (as from fetch).
|
| 150 |
+
if (error?.status === undefined && !(error instanceof TypeError)) {
|
| 151 |
+
throw error;
|
| 152 |
+
}
|
| 153 |
+
failure = error;
|
| 154 |
+
}
|
| 155 |
+
stats.fetchMs = Math.max(stats.fetchMs, performance.now() - t0);
|
| 156 |
+
if (!bytes) {
|
| 157 |
+
if (path === root) {
|
| 158 |
+
const status = failure?.status ?? (failure ? undefined : 404);
|
| 159 |
+
throw new UsdLoadError("fetch", `could not fetch ${rootUrl}${status ? ` (HTTP ${status})` : ""}`, {
|
| 160 |
+
url: rootUrl,
|
| 161 |
+
status,
|
| 162 |
+
cause: failure ?? undefined,
|
| 163 |
+
});
|
| 164 |
+
}
|
| 165 |
+
stats.missing++;
|
| 166 |
+
stats.warnings.push({
|
| 167 |
+
code: "layer-missing",
|
| 168 |
+
message: `layer not found: ${failure?.message ?? urlOf(path)}`,
|
| 169 |
+
path: urlOf(path),
|
| 170 |
+
});
|
| 171 |
+
loader.markUnavailable(path);
|
| 172 |
+
progress();
|
| 173 |
+
return;
|
| 174 |
+
}
|
| 175 |
+
charge(bytes.byteLength - charged, path);
|
| 176 |
+
layerSizes.set(path, bytes.byteLength);
|
| 177 |
+
stats.layers++;
|
| 178 |
+
stats.layerBytes += bytes.byteLength;
|
| 179 |
+
const t1 = performance.now();
|
| 180 |
+
let deps;
|
| 181 |
+
try {
|
| 182 |
+
deps = loader.addLayer(path, bytes);
|
| 183 |
+
}
|
| 184 |
+
catch (error) {
|
| 185 |
+
// After a trap the module is unusable: the load fails.
|
| 186 |
+
if (isTrap(error)) {
|
| 187 |
+
throw error;
|
| 188 |
+
}
|
| 189 |
+
// An unreadable layer is left out; composition carries on without it.
|
| 190 |
+
stats.warnings.push({
|
| 191 |
+
code: "layer-unreadable",
|
| 192 |
+
message: String(error.message || error),
|
| 193 |
+
path: urlOf(path),
|
| 194 |
+
});
|
| 195 |
+
loader.markUnavailable(path);
|
| 196 |
+
progress();
|
| 197 |
+
return;
|
| 198 |
+
}
|
| 199 |
+
finally {
|
| 200 |
+
stats.parseMs += performance.now() - t1;
|
| 201 |
+
}
|
| 202 |
+
progress();
|
| 203 |
+
for (const dep of deps) {
|
| 204 |
+
fetchLayer(dep);
|
| 205 |
+
}
|
| 206 |
+
})();
|
| 207 |
+
started.set(path, job);
|
| 208 |
+
pending.push(job);
|
| 209 |
+
};
|
| 210 |
+
fetchLayer(root);
|
| 211 |
+
// A root without dependencies needs nothing else from its directory.
|
| 212 |
+
const rootHasDependencies = () => (started.get(root) ?? Promise.resolve()).then(() => started.size > 1, () => false);
|
| 213 |
+
preload?.then(async ({ layers, eager }) => (eager || (await rootHasDependencies())) && startPreload(layers));
|
| 214 |
+
await drain();
|
| 215 |
+
if (!loader.has(root)) {
|
| 216 |
+
const reason = stats.warnings.find((w) => w.path === rootUrl)?.message;
|
| 217 |
+
throw new UsdLoadError("compose", `could not read ${rootUrl}${reason ? `: ${reason}` : ""}`, { url: rootUrl });
|
| 218 |
+
}
|
| 219 |
+
for (;;) {
|
| 220 |
+
stats.rounds++;
|
| 221 |
+
onProgress({ stage: "compose", round: stats.rounds });
|
| 222 |
+
const t0 = performance.now();
|
| 223 |
+
const missing = loader.compose(root, maxInstances);
|
| 224 |
+
stats.composeMs += performance.now() - t0;
|
| 225 |
+
if (!missing.length) {
|
| 226 |
+
break;
|
| 227 |
+
}
|
| 228 |
+
if (stats.rounds > 16) {
|
| 229 |
+
throw new UsdLoadError("compose", `composition still missing layers: ${missing.join(", ")}`);
|
| 230 |
+
}
|
| 231 |
+
// The list also names layers the failed attempt consumed; fetch them again.
|
| 232 |
+
for (const path of missing) {
|
| 233 |
+
started.delete(path);
|
| 234 |
+
}
|
| 235 |
+
missing.forEach(fetchLayer);
|
| 236 |
+
await drain();
|
| 237 |
+
}
|
| 238 |
+
composed = true;
|
| 239 |
+
const scene = loader.takeScene();
|
| 240 |
+
loader.free();
|
| 241 |
+
const meta = JSON.parse(scene.meta());
|
| 242 |
+
return { scene, meta, stats };
|
| 243 |
+
}
|
| 244 |
+
/**
|
| 245 |
+
* What the page is told about a failed load. Fetch and resource-limit errors
|
| 246 |
+
* keep their code, url and status; anything the WASM side throws is a
|
| 247 |
+
* composition failure. Running out of WASM memory (4 GiB at most) reads as a
|
| 248 |
+
* scene too large to load: an allocation that fails while reading a layer
|
| 249 |
+
* reports "out of memory", one that aborts traps as a bare `unreachable`. A
|
| 250 |
+
* Rust panic, which also traps as `unreachable`, gives its message instead,
|
| 251 |
+
* read with `lastPanic` (the module's export). Overflowing the stack, the WASM one (an
|
| 252 |
+
* out-of-bounds access) or the engine's, means layers nested too deeply to read.
|
| 253 |
+
*/
|
| 254 |
+
export function loadFailure(error, wasmMemoryBytes, lastPanic) {
|
| 255 |
+
const { code = "compose", url, status } = (error ?? {});
|
| 256 |
+
const message = String(error?.message || error);
|
| 257 |
+
const failure = (detail) => ({ code, message: detail, url, status });
|
| 258 |
+
if (code !== "compose") {
|
| 259 |
+
return failure(message);
|
| 260 |
+
}
|
| 261 |
+
const tooLarge = () => failure(`scene too large to load: ran out of memory (${(wasmMemoryBytes / 2 ** 30).toFixed(1)} GiB of WebAssembly memory in use): ${message}`);
|
| 262 |
+
if (OUT_OF_MEMORY.test(message) || (error instanceof WebAssembly.RuntimeError && wasmMemoryBytes > 3 * 2 ** 30)) {
|
| 263 |
+
return tooLarge();
|
| 264 |
+
}
|
| 265 |
+
if (!isTrap(error)) {
|
| 266 |
+
return failure(message);
|
| 267 |
+
}
|
| 268 |
+
const panic = readPanic(lastPanic);
|
| 269 |
+
if (panic) {
|
| 270 |
+
return failure(`${message}: ${panic}`);
|
| 271 |
+
}
|
| 272 |
+
if (/out of bounds|call stack|recursion/i.test(message)) {
|
| 273 |
+
return failure(`stack overflow: the layers nest too deeply to read (${message})`);
|
| 274 |
+
}
|
| 275 |
+
// Rust aborts on a failed allocation without a panic: a bare `unreachable`.
|
| 276 |
+
if (/unreachable/i.test(message)) {
|
| 277 |
+
return tooLarge();
|
| 278 |
+
}
|
| 279 |
+
return failure(message);
|
| 280 |
+
}
|
| 281 |
+
/** Messages of allocations that failed, in Rust or in the engine. */
|
| 282 |
+
export const OUT_OF_MEMORY = /out of memory|memory allocation|allocation failed|memory size exceeded|could not allocate/i;
|
| 283 |
+
/** Reading the panic calls into the trapped module, which can trap again (an exhausted stack does). */
|
| 284 |
+
function readPanic(lastPanic) {
|
| 285 |
+
try {
|
| 286 |
+
return lastPanic?.();
|
| 287 |
+
}
|
| 288 |
+
catch {
|
| 289 |
+
return undefined;
|
| 290 |
+
}
|
| 291 |
+
}
|
| 292 |
+
/** A WebAssembly trap or an exhausted engine call stack: the module is no longer usable. */
|
| 293 |
+
function isTrap(error) {
|
| 294 |
+
return (error instanceof WebAssembly.RuntimeError ||
|
| 295 |
+
error instanceof RangeError ||
|
| 296 |
+
error?.name === "InternalError");
|
| 297 |
+
}
|
| 298 |
+
function resourceLimit(detail) {
|
| 299 |
+
return new UsdLoadError("fetch", `resource limit exceeded: ${detail}`);
|
| 300 |
+
}
|
| 301 |
+
/** Runs at most `max` of the given tasks at once; tasks marked `later` wait for the others. */
|
| 302 |
+
export function limiter(max) {
|
| 303 |
+
let active = 0;
|
| 304 |
+
const queue = [];
|
| 305 |
+
const later = [];
|
| 306 |
+
const next = () => {
|
| 307 |
+
if (active >= max) {
|
| 308 |
+
return;
|
| 309 |
+
}
|
| 310 |
+
const job = queue.shift() ?? later.shift();
|
| 311 |
+
if (!job) {
|
| 312 |
+
return;
|
| 313 |
+
}
|
| 314 |
+
active++;
|
| 315 |
+
const { task, resolve, reject } = job;
|
| 316 |
+
task()
|
| 317 |
+
.then(resolve, reject)
|
| 318 |
+
.finally(() => {
|
| 319 |
+
active--;
|
| 320 |
+
next();
|
| 321 |
+
});
|
| 322 |
+
};
|
| 323 |
+
return (task, { later: low = false } = {}) => new Promise((resolve, reject) => {
|
| 324 |
+
(low ? later : queue).push({ task, resolve: resolve, reject });
|
| 325 |
+
next();
|
| 326 |
+
});
|
| 327 |
+
}
|
| 328 |
+
/** A layer URL as fetch would spell it, so an authored `a b.usd` matches a listed `a%20b.usd`. */
|
| 329 |
+
function urlKey(url) {
|
| 330 |
+
try {
|
| 331 |
+
return new URL(url).href;
|
| 332 |
+
}
|
| 333 |
+
catch {
|
| 334 |
+
return url;
|
| 335 |
+
}
|
| 336 |
+
}
|
| 337 |
+
/**
|
| 338 |
+
* Fetches a body, passing each chunk's size to `budget` as it arrives and
|
| 339 |
+
* giving up (cancelling the body) when `budget` throws. An HTTP error throws a
|
| 340 |
+
* `fetch` UsdLoadError carrying the status. `fetchFn` is the global fetch or a
|
| 341 |
+
* stand-in with the same contract. Rate limiting (429) and server errors
|
| 342 |
+
* (5xx) are retried with backoff, as the Hub answers bursts with 429.
|
| 343 |
+
*/
|
| 344 |
+
export async function fetchLimited(url, budget, { fetchFn = fetch, retries = 3, retryDelayMs = 500, } = {}) {
|
| 345 |
+
let response = await fetchFn(url);
|
| 346 |
+
for (let attempt = 0; attempt < retries && (response.status === 429 || response.status >= 500); attempt++) {
|
| 347 |
+
response.body?.cancel().catch(() => { });
|
| 348 |
+
const retryAfterMs = Number(response.headers?.get("retry-after")) * 1000;
|
| 349 |
+
const delay = retryAfterMs > 0 ? Math.min(retryAfterMs, 10_000) : retryDelayMs * 2 ** attempt * (1 + Math.random());
|
| 350 |
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
| 351 |
+
response = await fetchFn(url);
|
| 352 |
+
}
|
| 353 |
+
if (!response.ok) {
|
| 354 |
+
throw new UsdLoadError("fetch", `HTTP ${response.status} for ${url}`, { url, status: response.status });
|
| 355 |
+
}
|
| 356 |
+
if (!response.body) {
|
| 357 |
+
return new Uint8Array();
|
| 358 |
+
}
|
| 359 |
+
const reader = response.body.getReader();
|
| 360 |
+
const chunks = [];
|
| 361 |
+
let size = 0;
|
| 362 |
+
for (;;) {
|
| 363 |
+
const { done, value } = await reader.read();
|
| 364 |
+
if (done) {
|
| 365 |
+
break;
|
| 366 |
+
}
|
| 367 |
+
try {
|
| 368 |
+
budget(value.byteLength);
|
| 369 |
+
}
|
| 370 |
+
catch (error) {
|
| 371 |
+
await reader.cancel();
|
| 372 |
+
throw error;
|
| 373 |
+
}
|
| 374 |
+
size += value.byteLength;
|
| 375 |
+
chunks.push(value);
|
| 376 |
+
}
|
| 377 |
+
const out = new Uint8Array(size);
|
| 378 |
+
let offset = 0;
|
| 379 |
+
for (const chunk of chunks) {
|
| 380 |
+
out.set(chunk, offset);
|
| 381 |
+
offset += chunk.byteLength;
|
| 382 |
+
}
|
| 383 |
+
return out;
|
| 384 |
+
}
|
| 385 |
+
/**
|
| 386 |
+
* Size of a PNG, JPEG or WebP from its header, without decoding, and whether
|
| 387 |
+
* it is color: 8-bit RGB(A) or palette, rather than greyscale or 16-bit data
|
| 388 |
+
* (the images `sourceColorSpace = "auto"` decodes as sRGB; WebP is always
|
| 389 |
+
* color). Null for other formats, whose size cannot be checked before decoding.
|
| 390 |
+
*/
|
| 391 |
+
export function imageInfo(b) {
|
| 392 |
+
const v = new DataView(b.buffer, b.byteOffset, b.byteLength);
|
| 393 |
+
const ascii = (at, text) => [...text].every((c, i) => b[at + i] === c.charCodeAt(0));
|
| 394 |
+
if (b.length > 25 && b[0] === 0x89 && ascii(1, "PNG")) {
|
| 395 |
+
const [bitDepth, colorType] = [b[24], b[25]];
|
| 396 |
+
const color = colorType === 3 || (bitDepth === 8 && (colorType === 2 || colorType === 6));
|
| 397 |
+
return { width: v.getUint32(16), height: v.getUint32(20), color };
|
| 398 |
+
}
|
| 399 |
+
if (b[0] === 0xff && b[1] === 0xd8) {
|
| 400 |
+
let i = 2;
|
| 401 |
+
while (i + 9 < b.length) {
|
| 402 |
+
if (b[i] !== 0xff) {
|
| 403 |
+
return null;
|
| 404 |
+
}
|
| 405 |
+
const marker = b[i + 1];
|
| 406 |
+
const length = (b[i + 2] << 8) | b[i + 3];
|
| 407 |
+
const isFrame = marker >= 0xc0 && marker <= 0xcf && marker !== 0xc4 && marker !== 0xc8 && marker !== 0xcc;
|
| 408 |
+
if (isFrame) {
|
| 409 |
+
return {
|
| 410 |
+
height: (b[i + 5] << 8) | b[i + 6],
|
| 411 |
+
width: (b[i + 7] << 8) | b[i + 8],
|
| 412 |
+
color: b[i + 4] === 8 && b[i + 9] >= 3,
|
| 413 |
+
};
|
| 414 |
+
}
|
| 415 |
+
i += 2 + length;
|
| 416 |
+
}
|
| 417 |
+
return null;
|
| 418 |
+
}
|
| 419 |
+
if (b.length >= 30 && ascii(0, "RIFF") && ascii(8, "WEBP")) {
|
| 420 |
+
// The first chunk: lossy (VP8), lossless (VP8L) or extended (VP8X).
|
| 421 |
+
if (ascii(12, "VP8 ")) {
|
| 422 |
+
return { width: v.getUint16(26, true) & 0x3fff, height: v.getUint16(28, true) & 0x3fff, color: true };
|
| 423 |
+
}
|
| 424 |
+
if (ascii(12, "VP8L")) {
|
| 425 |
+
const bits = v.getUint32(21, true);
|
| 426 |
+
return { width: (bits & 0x3fff) + 1, height: ((bits >>> 14) & 0x3fff) + 1, color: true };
|
| 427 |
+
}
|
| 428 |
+
if (ascii(12, "VP8X")) {
|
| 429 |
+
const u24 = (at) => b[at] | (b[at + 1] << 8) | (b[at + 2] << 16);
|
| 430 |
+
return { width: u24(24) + 1, height: u24(27) + 1, color: true };
|
| 431 |
+
}
|
| 432 |
+
}
|
| 433 |
+
return null;
|
| 434 |
+
}
|
| 435 |
+
// A trailing dot names the same host (`huggingface.co.`), so it matches too.
|
| 436 |
+
const HUB_HOST = /^(huggingface\.co|hf\.co)\.?$/;
|
| 437 |
+
const HUB_CDN = /\.hf\.co\.?$/;
|
| 438 |
+
// Paths of Hub repo files, of the tree listing the prefetch reads and of the
|
| 439 |
+
// revision lookup that pins a load to one commit: the only Hub URLs a load
|
| 440 |
+
// requests, never other `/api/*` endpoints or account pages. The last group is
|
| 441 |
+
// the revision.
|
| 442 |
+
const HUB_FILE = /^\/(?:(datasets|spaces)\/)?([\w.-]+)\/([\w.-]+)\/resolve\/([^/]*)/;
|
| 443 |
+
const HUB_TREE = /^\/api\/(datasets|models|spaces)\/([\w.-]+)\/([\w.-]+)\/(?:tree|revision)\/([^/]*)/;
|
| 444 |
+
// First path segments of Hub pages and endpoints: never a model's owner.
|
| 445 |
+
const HUB_RESERVED = new Set([
|
| 446 |
+
"api",
|
| 447 |
+
"oauth",
|
| 448 |
+
"settings",
|
| 449 |
+
"login",
|
| 450 |
+
"logout",
|
| 451 |
+
"join",
|
| 452 |
+
"docs",
|
| 453 |
+
"models",
|
| 454 |
+
"datasets",
|
| 455 |
+
"spaces",
|
| 456 |
+
"organizations",
|
| 457 |
+
"new",
|
| 458 |
+
"pricing",
|
| 459 |
+
"blog",
|
| 460 |
+
"papers",
|
| 461 |
+
"posts",
|
| 462 |
+
"collections",
|
| 463 |
+
"notifications",
|
| 464 |
+
"search",
|
| 465 |
+
"chat",
|
| 466 |
+
"learn",
|
| 467 |
+
"tasks",
|
| 468 |
+
"enterprise",
|
| 469 |
+
"billing",
|
| 470 |
+
"static-proxy",
|
| 471 |
+
"avatars",
|
| 472 |
+
"front",
|
| 473 |
+
]);
|
| 474 |
+
/** The path match of a Hub file or tree-listing URL (`[, type, owner, repo, revision]`), else null. */
|
| 475 |
+
function hubMatch(url) {
|
| 476 |
+
if (!HUB_HOST.test(url.hostname) || url.protocol !== "https:") {
|
| 477 |
+
return null;
|
| 478 |
+
}
|
| 479 |
+
const file = url.pathname.match(HUB_FILE);
|
| 480 |
+
if (file && (file[1] || !HUB_RESERVED.has(file[2].toLowerCase()))) {
|
| 481 |
+
return file;
|
| 482 |
+
}
|
| 483 |
+
return url.pathname.match(HUB_TREE);
|
| 484 |
+
}
|
| 485 |
+
/** `type/owner/repo` of a Hub file or tree-listing URL, else null. */
|
| 486 |
+
function hubRepo(url) {
|
| 487 |
+
const match = hubMatch(url);
|
| 488 |
+
return match && `${match[1] ?? "models"}/${match[2]}/${match[3]}`;
|
| 489 |
+
}
|
| 490 |
+
/**
|
| 491 |
+
* A URL on hf.co, the Hub's short domain, as the huggingface.co URL it
|
| 492 |
+
* redirects to: fetched directly, a request keeps its headers (a redirect
|
| 493 |
+
* to another origin drops them) and its credentials scope stays the same.
|
| 494 |
+
*/
|
| 495 |
+
export function canonicalUrl(url) {
|
| 496 |
+
try {
|
| 497 |
+
const parsed = new URL(url);
|
| 498 |
+
if (!/^hf\.co\.?$/.test(parsed.hostname)) {
|
| 499 |
+
return url;
|
| 500 |
+
}
|
| 501 |
+
parsed.hostname = "huggingface.co";
|
| 502 |
+
return parsed.href;
|
| 503 |
+
}
|
| 504 |
+
catch {
|
| 505 |
+
return url;
|
| 506 |
+
}
|
| 507 |
+
}
|
| 508 |
+
/** The scheme of files given with the `files` option: `local:///<key>`, the key percent-encoded. */
|
| 509 |
+
export const LOCAL = "local:";
|
| 510 |
+
/** A `files` key as the load spells it: `/` separators, no leading `./` or `/`. */
|
| 511 |
+
export function localKey(key) {
|
| 512 |
+
return key.replace(/\\/g, "/").replace(/^(?:\.?\/)+/, "");
|
| 513 |
+
}
|
| 514 |
+
/** The URL a `files` key loads as; relative asset paths in the file resolve against it. */
|
| 515 |
+
export function localUrl(key) {
|
| 516 |
+
return `${LOCAL}///${localKey(key).split("/").map(encodeURIComponent).join("/")}`;
|
| 517 |
+
}
|
| 518 |
+
/** The `files` key a `local:` URL names. */
|
| 519 |
+
export function keyOfLocalUrl(url) {
|
| 520 |
+
return decodeURIComponent(new URL(url).pathname.slice(1));
|
| 521 |
+
}
|
| 522 |
+
/**
|
| 523 |
+
* How a load rooted at `rootUrl` may request `url`: `{ refused }` with the
|
| 524 |
+
* reason, or the fetch options to use. Every request a load makes goes
|
| 525 |
+
* through this first, then through {@link fetchWithPolicy}. Only the
|
| 526 |
+
* requested URL is checked: fetches follow redirects (a Hub `resolve` URL
|
| 527 |
+
* redirects to its CDN, which the Hub controls), but never with the caller's
|
| 528 |
+
* headers off the Hub.
|
| 529 |
+
*
|
| 530 |
+
* - hf.co URLs are checked as the huggingface.co URLs they redirect to.
|
| 531 |
+
* - The root URL itself, as the caller gave it, is always allowed.
|
| 532 |
+
* - A `local:` root (the `files` option) may read other `local:` URLs, which
|
| 533 |
+
* are looked up in its files and never fetched; no other root may.
|
| 534 |
+
* - Only http(s), with no user name or password in the URL.
|
| 535 |
+
* - Origins: the root's, those in `allowedOrigins` (`'*'` for any) and, for a
|
| 536 |
+
* root on the Hugging Face Hub, the Hub and its CDN hosts.
|
| 537 |
+
* - On huggingface.co and hf.co, only repo files (`…/resolve/…`) and tree
|
| 538 |
+
* listings, under a user or organization name (not `/api/…`, `/oauth/…`
|
| 539 |
+
* and other Hub pages), with no encoded slashes outside the revision (a
|
| 540 |
+
* pull request's is `refs%2Fpr%2F1`).
|
| 541 |
+
* - Credentials (cookies and the caller's headers) go only to the root's own
|
| 542 |
+
* origin or, for a Hub root, only to the root's own repo.
|
| 543 |
+
*/
|
| 544 |
+
export function requestPolicy(url, rootUrl, allowedOrigins = []) {
|
| 545 |
+
const refused = refusal(canonicalUrl(url), canonicalUrl(rootUrl), allowedOrigins);
|
| 546 |
+
if (refused) {
|
| 547 |
+
return { refused };
|
| 548 |
+
}
|
| 549 |
+
return {
|
| 550 |
+
credentials: credentialed(new URL(canonicalUrl(url)), new URL(canonicalUrl(rootUrl))) ? "same-origin" : "omit",
|
| 551 |
+
referrerPolicy: "no-referrer",
|
| 552 |
+
};
|
| 553 |
+
}
|
| 554 |
+
function refusal(url, rootUrl, allowedOrigins) {
|
| 555 |
+
if (url === rootUrl) {
|
| 556 |
+
return null;
|
| 557 |
+
}
|
| 558 |
+
let target;
|
| 559 |
+
try {
|
| 560 |
+
target = new URL(url);
|
| 561 |
+
}
|
| 562 |
+
catch {
|
| 563 |
+
return `not a URL: ${url}`;
|
| 564 |
+
}
|
| 565 |
+
const root = new URL(rootUrl);
|
| 566 |
+
if (root.protocol === LOCAL && target.protocol === LOCAL) {
|
| 567 |
+
return null;
|
| 568 |
+
}
|
| 569 |
+
if (target.protocol !== "http:" && target.protocol !== "https:") {
|
| 570 |
+
return `only http(s) URLs are fetched: ${url}`;
|
| 571 |
+
}
|
| 572 |
+
if (target.username || target.password) {
|
| 573 |
+
return `URLs with credentials are not fetched: ${url}`;
|
| 574 |
+
}
|
| 575 |
+
const hub = HUB_HOST.test(target.hostname);
|
| 576 |
+
if (hub && !hubFile(target)) {
|
| 577 |
+
return `only Hub repo files are fetched from ${target.host}: ${url}`;
|
| 578 |
+
}
|
| 579 |
+
const fromHub = HUB_HOST.test(root.hostname) && (hub || HUB_CDN.test(target.hostname)) && target.protocol === "https:";
|
| 580 |
+
if (target.origin === root.origin ||
|
| 581 |
+
fromHub ||
|
| 582 |
+
allowedOrigins.includes("*") ||
|
| 583 |
+
allowedOrigins.includes(target.origin)) {
|
| 584 |
+
return null;
|
| 585 |
+
}
|
| 586 |
+
return `its origin is not in allowedOrigins: ${url}`;
|
| 587 |
+
}
|
| 588 |
+
/** A Hub repo file or tree listing with no encoded slash or backslash, but for a `%2F` in its revision. */
|
| 589 |
+
function hubFile(url) {
|
| 590 |
+
const match = hubMatch(url);
|
| 591 |
+
if (!match) {
|
| 592 |
+
return false;
|
| 593 |
+
}
|
| 594 |
+
const revisionStart = match[0].length - match[4].length;
|
| 595 |
+
const outside = url.pathname.slice(0, revisionStart) + url.pathname.slice(match[0].length);
|
| 596 |
+
return !/%2f|%5c/i.test(outside) && !/%5c/i.test(match[4]);
|
| 597 |
+
}
|
| 598 |
+
function credentialed(target, root) {
|
| 599 |
+
// Every `local:` URL's origin is the string "null", which would match any other's.
|
| 600 |
+
if (root.protocol === LOCAL) {
|
| 601 |
+
return false;
|
| 602 |
+
}
|
| 603 |
+
if (target.origin !== root.origin) {
|
| 604 |
+
return false;
|
| 605 |
+
}
|
| 606 |
+
const repo = hubRepo(root);
|
| 607 |
+
return HUB_HOST.test(root.hostname) ? !!repo && hubRepo(target) === repo : true;
|
| 608 |
+
}
|
| 609 |
+
/**
|
| 610 |
+
* Fetches `url` under `policy` (see {@link requestPolicy}), sending `headers`
|
| 611 |
+
* only where credentials may go. A request carrying them does not follow a
|
| 612 |
+
* redirect with them: unless it is on the Hub (whose redirects stay on its own
|
| 613 |
+
* hosts), it is not followed, and the URL is fetched again without headers or
|
| 614 |
+
* cookies, for the browser to follow.
|
| 615 |
+
*/
|
| 616 |
+
export async function fetchWithPolicy(url, policy, headers) {
|
| 617 |
+
const sendHeaders = policy.credentials === "same-origin" && !!headers && Object.keys(headers).length > 0;
|
| 618 |
+
if (!sendHeaders) {
|
| 619 |
+
return fetch(url, policy);
|
| 620 |
+
}
|
| 621 |
+
if (HUB_HOST.test(new URL(url).hostname)) {
|
| 622 |
+
return fetch(url, { ...policy, headers });
|
| 623 |
+
}
|
| 624 |
+
const response = await fetch(url, { ...policy, headers, redirect: "manual" });
|
| 625 |
+
if (response.type !== "opaqueredirect" && !(response.status >= 300 && response.status < 400)) {
|
| 626 |
+
return response;
|
| 627 |
+
}
|
| 628 |
+
response.body?.cancel().catch(() => { });
|
| 629 |
+
return fetch(url, { ...policy, credentials: "omit" });
|
| 630 |
+
}
|
| 631 |
+
/**
|
| 632 |
+
* Reads each geometry out of WASM in turn, so only one mesh's arrays are in
|
| 633 |
+
* WASM memory at a time, and calls `onGeometry(index, meta, arrays)` with
|
| 634 |
+
* JS-owned typed arrays (`meta` and `arrays` are null for a mesh with nothing
|
| 635 |
+
* drawable, or left out). Triangles count as drawn, once per instance:
|
| 636 |
+
* meshes that would take them past `maxTriangles` are left out unread.
|
| 637 |
+
* Releases the stage afterwards. Returns warnings: `triangle-limit` for
|
| 638 |
+
* meshes left out, `nothing-drawable` when no mesh had anything to draw.
|
| 639 |
+
*/
|
| 640 |
+
export function readGeometries(scene, meta, onGeometry, { maxTriangles = DEFAULTS.maxTriangles } = {}) {
|
| 641 |
+
const instances = Array.from({ length: meta.geometryCount }, () => 0);
|
| 642 |
+
for (const { geometry } of meta.instances) {
|
| 643 |
+
instances[geometry]++;
|
| 644 |
+
}
|
| 645 |
+
let drawn = 0;
|
| 646 |
+
let left = maxTriangles;
|
| 647 |
+
const skipped = [];
|
| 648 |
+
for (let i = 0; i < meta.geometryCount; i++) {
|
| 649 |
+
// Not drawn anywhere (e.g. all its instances past maxInstances).
|
| 650 |
+
if (!instances[i]) {
|
| 651 |
+
onGeometry(i, null, null);
|
| 652 |
+
continue;
|
| 653 |
+
}
|
| 654 |
+
const json = scene.read(i, Math.min(Math.floor(left / instances[i]), 2 ** 32 - 1));
|
| 655 |
+
const g = json && JSON.parse(json);
|
| 656 |
+
if (!g || "overBudget" in g) {
|
| 657 |
+
if (g) {
|
| 658 |
+
skipped.push(g.path);
|
| 659 |
+
}
|
| 660 |
+
onGeometry(i, null, null);
|
| 661 |
+
continue;
|
| 662 |
+
}
|
| 663 |
+
drawn++;
|
| 664 |
+
left = Math.max(0, left - instances[i] * g.groups.reduce((n, [, count]) => n + count / 3, 0));
|
| 665 |
+
onGeometry(i, g, {
|
| 666 |
+
positions: scene.positions(),
|
| 667 |
+
normals: scene.normals(),
|
| 668 |
+
uvs: g.uvSets.map((_, k) => scene.uvs(k)),
|
| 669 |
+
colors: g.hasColors ? scene.colors() : null,
|
| 670 |
+
indices: g.maxIndex < 65536 ? scene.indices16() : scene.indices(),
|
| 671 |
+
});
|
| 672 |
+
}
|
| 673 |
+
scene.finish();
|
| 674 |
+
const warnings = [];
|
| 675 |
+
if (skipped.length) {
|
| 676 |
+
warnings.push({
|
| 677 |
+
code: "triangle-limit",
|
| 678 |
+
message: `${skipped.length} meshes left out: past maxTriangles (${maxTriangles}) drawn`,
|
| 679 |
+
path: skipped[0],
|
| 680 |
+
});
|
| 681 |
+
}
|
| 682 |
+
if (!drawn) {
|
| 683 |
+
warnings.push({
|
| 684 |
+
code: "nothing-drawable",
|
| 685 |
+
message: "nothing to draw: the stage has no visible meshes with geometry",
|
| 686 |
+
});
|
| 687 |
+
}
|
| 688 |
+
return warnings;
|
| 689 |
+
}
|
| 690 |
+
/**
|
| 691 |
+
* Reads the colliders of a scene composed with `physics` (`SceneMeta.physics.colliderCount`), one at a time, and calls
|
| 692 |
+
* `onCollider(index, meta, arrays)` with JS-owned typed arrays: its points as authored and its faces fan-triangulated.
|
| 693 |
+
* Reads nothing for a scene composed without it. Call it before `scene.free()`; each collider reads once.
|
| 694 |
+
*/
|
| 695 |
+
export function readColliders(scene, onCollider) {
|
| 696 |
+
const count = scene.colliderCount();
|
| 697 |
+
for (let i = 0; i < count; i++) {
|
| 698 |
+
const meta = JSON.parse(scene.readCollider(i));
|
| 699 |
+
onCollider(i, meta, { points: scene.positions(), indices: scene.indices() });
|
| 700 |
+
}
|
| 701 |
+
return count;
|
| 702 |
+
}
|
| 703 |
+
/**
|
| 704 |
+
* Images stored inside a USDZ package (they cannot be fetched by URL) among
|
| 705 |
+
* the texture `jobs` (see {@link textureJobs}), each read once, by path, all
|
| 706 |
+
* together at most `maxBytes`. One that cannot be read maps to its error, so
|
| 707 |
+
* it fails as that texture rather than the whole load.
|
| 708 |
+
*/
|
| 709 |
+
export function takePackagedTextures(scene, jobs, { maxBytes = Infinity } = {}) {
|
| 710 |
+
const out = new Map();
|
| 711 |
+
let left = maxBytes;
|
| 712 |
+
for (const { path } of jobs) {
|
| 713 |
+
if (!path.includes("[")) {
|
| 714 |
+
continue;
|
| 715 |
+
}
|
| 716 |
+
try {
|
| 717 |
+
const bytes = scene.packagedFile(path, left);
|
| 718 |
+
if (bytes) {
|
| 719 |
+
out.set(path, bytes);
|
| 720 |
+
}
|
| 721 |
+
left -= bytes?.byteLength ?? 0;
|
| 722 |
+
}
|
| 723 |
+
catch (error) {
|
| 724 |
+
out.set(path, error);
|
| 725 |
+
}
|
| 726 |
+
}
|
| 727 |
+
return out;
|
| 728 |
+
}
|
| 729 |
+
/** Long-side cap for data maps (roughness, metallic, occlusion, ...) in `preview` mode. */
|
| 730 |
+
const PREVIEW_DATA_SIZE = 512;
|
| 731 |
+
/**
|
| 732 |
+
* The texture files to load and the size to decode each to, base colors first.
|
| 733 |
+
* `preview`: base color up to `maxSize`, other maps up to 512 px, no normal
|
| 734 |
+
* maps. `full`: every map, including normals, up to `maxSize`. `none`: nothing.
|
| 735 |
+
*/
|
| 736 |
+
export function textureJobs(meta, { textures, maxSize }) {
|
| 737 |
+
if (textures === "none") {
|
| 738 |
+
return [];
|
| 739 |
+
}
|
| 740 |
+
const full = textures === "full";
|
| 741 |
+
const dataSize = full ? maxSize : Math.min(maxSize, PREVIEW_DATA_SIZE);
|
| 742 |
+
const tiers = [
|
| 743 |
+
[["diffuseColor"], maxSize],
|
| 744 |
+
[["opacity", "emissiveColor", "roughness", "metallic", "occlusion"], dataSize],
|
| 745 |
+
[full ? ["normal"] : [], maxSize],
|
| 746 |
+
];
|
| 747 |
+
const jobs = new Map();
|
| 748 |
+
for (const [inputs, size] of tiers) {
|
| 749 |
+
for (const m of meta.materials) {
|
| 750 |
+
for (const input of inputs) {
|
| 751 |
+
const path = m.maps[input]?.path;
|
| 752 |
+
// A file shared by several inputs is decoded once, at the largest size asked.
|
| 753 |
+
if (path) {
|
| 754 |
+
jobs.set(path, Math.max(jobs.get(path) ?? 0, size));
|
| 755 |
+
}
|
| 756 |
+
}
|
| 757 |
+
}
|
| 758 |
+
}
|
| 759 |
+
return [...jobs].map(([path, size]) => ({ path, size }));
|
| 760 |
+
}
|
services/explorer/dist/static/usd-reader/81290bc/esm/worker.js
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Loads, composes and extracts a USD stage off the main thread, then streams
|
| 2 |
+
// textures as downscaled ImageBitmaps. One worker per load: the page
|
| 3 |
+
// terminates it when done, disposed or aborted, which releases all WASM memory.
|
| 4 |
+
import init, { lastPanic, UsdLoader } from "../wasm/usd_wasm.js";
|
| 5 |
+
import { hubPackageLayers, pinHubRevision } from "./hub-prefetch.js";
|
| 6 |
+
import { DEFAULTS, LOCAL, canonicalUrl, composeStage, fetchLimited, fetchWithPolicy, imageInfo, keyOfLocalUrl, limiter, loadFailure, readColliders, readGeometries, requestPolicy, takePackagedTextures, textureJobs, } from "./load-core.js";
|
| 7 |
+
// Textures in flight at once (fetch and decode): decoding a large image
|
| 8 |
+
// briefly holds it at full size, so wide parallelism spikes memory.
|
| 9 |
+
const TEXTURE_CONCURRENCY = 4;
|
| 10 |
+
// Longest side of an image read at all: larger ones are refused from their
|
| 11 |
+
// header, before decoding (WebGL's own limit is commonly 16384 too).
|
| 12 |
+
const MAX_IMAGE_SIZE = DEFAULTS.maxImageSize;
|
| 13 |
+
self.onmessage = async ({ data }) => {
|
| 14 |
+
const { url, wasmModule, maxTextureSize = DEFAULTS.maxTextureSize, textures = DEFAULTS.textures, maxConcurrentFetches = DEFAULTS.maxConcurrentFetches, maxLayerBytes, maxTextureBytes = DEFAULTS.maxTextureBytes, maxLayers, maxInstances, maxTriangles, allowedOrigins, headers, files, physics, } = data;
|
| 15 |
+
// Every request (layer, texture, Hub listing) goes through here, and
|
| 16 |
+
// through the request policy first. The caller's headers go only where
|
| 17 |
+
// cookies may, and never through a redirect off the Hub.
|
| 18 |
+
const request = async (target) => {
|
| 19 |
+
target = canonicalUrl(target);
|
| 20 |
+
const policy = requestPolicy(target, url, allowedOrigins);
|
| 21 |
+
// Reads like a network failure: a missing layer or a failed texture.
|
| 22 |
+
if (policy.refused !== undefined) {
|
| 23 |
+
throw new TypeError(`request refused: ${policy.refused}`);
|
| 24 |
+
}
|
| 25 |
+
if (target.startsWith(LOCAL)) {
|
| 26 |
+
const file = files?.get(keyOfLocalUrl(target));
|
| 27 |
+
return file ? new Response(file) : new Response(null, { status: 404 });
|
| 28 |
+
}
|
| 29 |
+
return fetchWithPolicy(target, policy, headers);
|
| 30 |
+
};
|
| 31 |
+
const fetchBytes = (target, budget) => fetchLimited(target, budget, { fetchFn: request });
|
| 32 |
+
// One budget for every texture, packaged ones first, then each fetched
|
| 33 |
+
// body as its bytes arrive. Bytes of a body cut short stay charged: they
|
| 34 |
+
// were downloaded.
|
| 35 |
+
let textureBytes = 0;
|
| 36 |
+
const chargeTexture = (bytes) => {
|
| 37 |
+
textureBytes += bytes;
|
| 38 |
+
if (textureBytes > maxTextureBytes) {
|
| 39 |
+
throw new Error(`textures exceed maxTextureBytes (${maxTextureBytes} bytes)`);
|
| 40 |
+
}
|
| 41 |
+
};
|
| 42 |
+
const progress = (p) => self.postMessage({ type: "progress", progress: p });
|
| 43 |
+
let wasmMemory;
|
| 44 |
+
try {
|
| 45 |
+
const t0 = performance.now();
|
| 46 |
+
// Looked up while the WASM module initializes.
|
| 47 |
+
const rootUrl = pinHubRevision(url, request);
|
| 48 |
+
const preload = rootUrl.then((root) => hubPackageLayers(root, request));
|
| 49 |
+
const wasm = await init({ module_or_path: wasmModule });
|
| 50 |
+
wasmMemory = wasm.memory;
|
| 51 |
+
const tInit = performance.now();
|
| 52 |
+
const { scene, meta, stats } = await composeStage({
|
| 53 |
+
UsdLoader,
|
| 54 |
+
fetchBytes,
|
| 55 |
+
rootUrl: await rootUrl,
|
| 56 |
+
maxConcurrentFetches,
|
| 57 |
+
maxLayerBytes,
|
| 58 |
+
maxLayers,
|
| 59 |
+
maxInstances,
|
| 60 |
+
allowedOrigins,
|
| 61 |
+
preload,
|
| 62 |
+
onProgress: progress,
|
| 63 |
+
physics: physics?.namespaces,
|
| 64 |
+
});
|
| 65 |
+
stats.initMs = tInit - t0;
|
| 66 |
+
self.postMessage({ type: "meta", meta });
|
| 67 |
+
// One mesh at a time: each is transferred (not copied) as soon as it is read.
|
| 68 |
+
const onGeometry = (index, g, arrays) => {
|
| 69 |
+
const transfer = arrays
|
| 70 |
+
? [arrays.positions, arrays.normals, arrays.colors, arrays.indices, ...arrays.uvs]
|
| 71 |
+
.filter((a) => !!a)
|
| 72 |
+
.map((a) => a.buffer)
|
| 73 |
+
: [];
|
| 74 |
+
self.postMessage({ type: "geometry", index, meta: g, arrays }, transfer);
|
| 75 |
+
progress({ stage: "geometry", loaded: index + 1, total: meta.geometryCount });
|
| 76 |
+
};
|
| 77 |
+
const warnings = readGeometries(scene, meta, onGeometry, { maxTriangles });
|
| 78 |
+
// Then the colliders (only when asked for), each transferred as it is read.
|
| 79 |
+
readColliders(scene, (index, c, arrays) => self.postMessage({ type: "collider", index, meta: c, arrays }, [arrays.points.buffer, arrays.indices.buffer]));
|
| 80 |
+
const jobs = textureJobs(meta, { textures, maxSize: maxTextureSize });
|
| 81 |
+
const packaged = takePackagedTextures(scene, jobs, { maxBytes: maxTextureBytes });
|
| 82 |
+
for (const entry of packaged.values()) {
|
| 83 |
+
if (!(entry instanceof Error)) {
|
| 84 |
+
textureBytes += entry.byteLength;
|
| 85 |
+
}
|
| 86 |
+
}
|
| 87 |
+
scene.free();
|
| 88 |
+
stats.warnings.push(...warnings);
|
| 89 |
+
stats.totalMs = performance.now() - t0;
|
| 90 |
+
stats.wasmMemoryBytes = wasm.memory.buffer.byteLength;
|
| 91 |
+
self.postMessage({ type: "scene", stats: stats });
|
| 92 |
+
let loaded = 0;
|
| 93 |
+
let bytes = 0;
|
| 94 |
+
progress({ stage: "textures", loaded, total: jobs.length, bytes });
|
| 95 |
+
// The limiter runs jobs in order, so base colors come first.
|
| 96 |
+
const throttle = limiter(Math.min(maxConcurrentFetches, TEXTURE_CONCURRENCY));
|
| 97 |
+
await Promise.all(jobs.map(({ path, size }) => throttle(async () => {
|
| 98 |
+
try {
|
| 99 |
+
const entry = packaged.get(path);
|
| 100 |
+
if (entry instanceof Error) {
|
| 101 |
+
throw entry;
|
| 102 |
+
}
|
| 103 |
+
// A packaged path is never a URL to fetch.
|
| 104 |
+
if (!entry && path.includes("[")) {
|
| 105 |
+
throw new Error(`not found in its package: ${path}`);
|
| 106 |
+
}
|
| 107 |
+
const image = entry ?? (await fetchBytes(path, chargeTexture));
|
| 108 |
+
bytes += image.byteLength;
|
| 109 |
+
const { bitmap, color } = await decodeTexture(image, size);
|
| 110 |
+
self.postMessage({ type: "texture", path, bitmap, color }, [bitmap]);
|
| 111 |
+
}
|
| 112 |
+
catch (error) {
|
| 113 |
+
self.postMessage({ type: "texture", path, error: String(error?.message || error) });
|
| 114 |
+
}
|
| 115 |
+
progress({ stage: "textures", loaded: ++loaded, total: jobs.length, bytes });
|
| 116 |
+
})));
|
| 117 |
+
self.postMessage({ type: "done" });
|
| 118 |
+
}
|
| 119 |
+
catch (error) {
|
| 120 |
+
self.postMessage({ type: "error", ...loadFailure(error, wasmMemory?.buffer.byteLength ?? 0, lastPanic) });
|
| 121 |
+
}
|
| 122 |
+
};
|
| 123 |
+
/**
|
| 124 |
+
* Decodes a PNG, JPEG or WebP straight to at most `maxSize` px on its long
|
| 125 |
+
* side, and tells whether it holds color (what `sourceColorSpace = "auto"`
|
| 126 |
+
* decodes as sRGB). Images whose size the header does not give, or that are
|
| 127 |
+
* too large, are refused before decoding.
|
| 128 |
+
*/
|
| 129 |
+
async function decodeTexture(bytes, maxSize) {
|
| 130 |
+
const info = imageInfo(bytes);
|
| 131 |
+
if (!info) {
|
| 132 |
+
throw new Error("unsupported image format: only PNG, JPEG and WebP are read");
|
| 133 |
+
}
|
| 134 |
+
if (Math.max(info.width, info.height) > MAX_IMAGE_SIZE) {
|
| 135 |
+
throw new Error(`image too large: ${info.width}x${info.height} (at most ${MAX_IMAGE_SIZE} px a side)`);
|
| 136 |
+
}
|
| 137 |
+
// USD texture coordinates put (0,0) at the bottom-left, three.js's default.
|
| 138 |
+
const options = {
|
| 139 |
+
imageOrientation: "flipY",
|
| 140 |
+
premultiplyAlpha: "none",
|
| 141 |
+
colorSpaceConversion: "none",
|
| 142 |
+
};
|
| 143 |
+
const scale = Math.min(1, maxSize / Math.max(info.width, info.height));
|
| 144 |
+
if (scale < 1) {
|
| 145 |
+
options.resizeWidth = Math.max(1, Math.round(info.width * scale));
|
| 146 |
+
options.resizeHeight = Math.max(1, Math.round(info.height * scale));
|
| 147 |
+
options.resizeQuality = "high";
|
| 148 |
+
}
|
| 149 |
+
return { bitmap: await createImageBitmap(new Blob([bytes]), options), color: info.color };
|
| 150 |
+
}
|
services/explorer/dist/static/usd-reader/81290bc/wasm/usd_wasm.js
ADDED
|
@@ -0,0 +1,760 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/* @ts-self-types="./usd_wasm.d.ts" */
|
| 2 |
+
|
| 3 |
+
export class UsdLoader {
|
| 4 |
+
__destroy_into_raw() {
|
| 5 |
+
const ptr = this.__wbg_ptr;
|
| 6 |
+
this.__wbg_ptr = 0;
|
| 7 |
+
UsdLoaderFinalization.unregister(this);
|
| 8 |
+
return ptr;
|
| 9 |
+
}
|
| 10 |
+
free() {
|
| 11 |
+
const ptr = this.__destroy_into_raw();
|
| 12 |
+
wasm.__wbg_usdloader_free(ptr, 0);
|
| 13 |
+
}
|
| 14 |
+
/**
|
| 15 |
+
* Stores a layer and returns the layers it names outside unselected
|
| 16 |
+
* variants (see [`Loader::add_layer`]).
|
| 17 |
+
* @param {string} path
|
| 18 |
+
* @param {Uint8Array} bytes
|
| 19 |
+
* @returns {string[]}
|
| 20 |
+
*/
|
| 21 |
+
addLayer(path, bytes) {
|
| 22 |
+
try {
|
| 23 |
+
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
| 24 |
+
const ptr0 = passStringToWasm0(path, wasm.__wbindgen_export, wasm.__wbindgen_export2);
|
| 25 |
+
const len0 = WASM_VECTOR_LEN;
|
| 26 |
+
const ptr1 = passArray8ToWasm0(bytes, wasm.__wbindgen_export);
|
| 27 |
+
const len1 = WASM_VECTOR_LEN;
|
| 28 |
+
wasm.usdloader_addLayer(retptr, this.__wbg_ptr, ptr0, len0, ptr1, len1);
|
| 29 |
+
var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
|
| 30 |
+
var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
|
| 31 |
+
var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
|
| 32 |
+
var r3 = getDataViewMemory0().getInt32(retptr + 4 * 3, true);
|
| 33 |
+
if (r3) {
|
| 34 |
+
throw takeObject(r2);
|
| 35 |
+
}
|
| 36 |
+
var v3 = getArrayJsValueFromWasm0(r0, r1);
|
| 37 |
+
wasm.__wbindgen_export3(r0, r1 * 4, 4);
|
| 38 |
+
return v3;
|
| 39 |
+
} finally {
|
| 40 |
+
wasm.__wbindgen_add_to_stack_pointer(16);
|
| 41 |
+
}
|
| 42 |
+
}
|
| 43 |
+
/**
|
| 44 |
+
* Composes the stage at `root`. Returns the layers still missing; when
|
| 45 |
+
* that is empty the scene is ready for [`take_scene`](Self::take_scene).
|
| 46 |
+
* The scene draws at most `max_instances` mesh instances.
|
| 47 |
+
* @param {string} root
|
| 48 |
+
* @param {number} max_instances
|
| 49 |
+
* @returns {string[]}
|
| 50 |
+
*/
|
| 51 |
+
compose(root, max_instances) {
|
| 52 |
+
try {
|
| 53 |
+
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
| 54 |
+
const ptr0 = passStringToWasm0(root, wasm.__wbindgen_export, wasm.__wbindgen_export2);
|
| 55 |
+
const len0 = WASM_VECTOR_LEN;
|
| 56 |
+
wasm.usdloader_compose(retptr, this.__wbg_ptr, ptr0, len0, max_instances);
|
| 57 |
+
var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
|
| 58 |
+
var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
|
| 59 |
+
var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
|
| 60 |
+
var r3 = getDataViewMemory0().getInt32(retptr + 4 * 3, true);
|
| 61 |
+
if (r3) {
|
| 62 |
+
throw takeObject(r2);
|
| 63 |
+
}
|
| 64 |
+
var v2 = getArrayJsValueFromWasm0(r0, r1);
|
| 65 |
+
wasm.__wbindgen_export3(r0, r1 * 4, 4);
|
| 66 |
+
return v2;
|
| 67 |
+
} finally {
|
| 68 |
+
wasm.__wbindgen_add_to_stack_pointer(16);
|
| 69 |
+
}
|
| 70 |
+
}
|
| 71 |
+
/**
|
| 72 |
+
* @param {string} path
|
| 73 |
+
* @returns {boolean}
|
| 74 |
+
*/
|
| 75 |
+
has(path) {
|
| 76 |
+
const ptr0 = passStringToWasm0(path, wasm.__wbindgen_export, wasm.__wbindgen_export2);
|
| 77 |
+
const len0 = WASM_VECTOR_LEN;
|
| 78 |
+
const ret = wasm.usdloader_has(this.__wbg_ptr, ptr0, len0);
|
| 79 |
+
return ret !== 0;
|
| 80 |
+
}
|
| 81 |
+
/**
|
| 82 |
+
* @param {string} path
|
| 83 |
+
*/
|
| 84 |
+
markUnavailable(path) {
|
| 85 |
+
const ptr0 = passStringToWasm0(path, wasm.__wbindgen_export, wasm.__wbindgen_export2);
|
| 86 |
+
const len0 = WASM_VECTOR_LEN;
|
| 87 |
+
wasm.usdloader_markUnavailable(this.__wbg_ptr, ptr0, len0);
|
| 88 |
+
}
|
| 89 |
+
constructor() {
|
| 90 |
+
const ret = wasm.usdloader_new();
|
| 91 |
+
this.__wbg_ptr = ret;
|
| 92 |
+
UsdLoaderFinalization.register(this, this.__wbg_ptr, this);
|
| 93 |
+
return this;
|
| 94 |
+
}
|
| 95 |
+
/**
|
| 96 |
+
* Also reads the stage's physics when composing (see
|
| 97 |
+
* [`Loader::set_physics`]); `namespaces` are the host's own attribute
|
| 98 |
+
* namespaces (`["simready"]`). The scene's meta then carries `physics`,
|
| 99 |
+
* and [`UsdScene::read_collider`] reads its colliders.
|
| 100 |
+
* @param {string[]} namespaces
|
| 101 |
+
*/
|
| 102 |
+
setPhysics(namespaces) {
|
| 103 |
+
const ptr0 = passArrayJsValueToWasm0(namespaces, wasm.__wbindgen_export);
|
| 104 |
+
const len0 = WASM_VECTOR_LEN;
|
| 105 |
+
wasm.usdloader_setPhysics(this.__wbg_ptr, ptr0, len0);
|
| 106 |
+
}
|
| 107 |
+
/**
|
| 108 |
+
* Hands over the extracted scene and drops every stored layer.
|
| 109 |
+
* @returns {UsdScene}
|
| 110 |
+
*/
|
| 111 |
+
takeScene() {
|
| 112 |
+
try {
|
| 113 |
+
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
| 114 |
+
wasm.usdloader_takeScene(retptr, this.__wbg_ptr);
|
| 115 |
+
var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
|
| 116 |
+
var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
|
| 117 |
+
var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
|
| 118 |
+
if (r2) {
|
| 119 |
+
throw takeObject(r1);
|
| 120 |
+
}
|
| 121 |
+
return UsdScene.__wrap(r0);
|
| 122 |
+
} finally {
|
| 123 |
+
wasm.__wbindgen_add_to_stack_pointer(16);
|
| 124 |
+
}
|
| 125 |
+
}
|
| 126 |
+
}
|
| 127 |
+
if (Symbol.dispose) UsdLoader.prototype[Symbol.dispose] = UsdLoader.prototype.free;
|
| 128 |
+
|
| 129 |
+
/**
|
| 130 |
+
* A composed scene whose meshes are read one at a time: `read(i)` makes
|
| 131 |
+
* geometry `i` current, and the array getters move its data out (each once).
|
| 132 |
+
* Only the current mesh's arrays live in WASM memory at any time.
|
| 133 |
+
*/
|
| 134 |
+
export class UsdScene {
|
| 135 |
+
static __wrap(ptr) {
|
| 136 |
+
const obj = Object.create(UsdScene.prototype);
|
| 137 |
+
obj.__wbg_ptr = ptr;
|
| 138 |
+
UsdSceneFinalization.register(obj, obj.__wbg_ptr, obj);
|
| 139 |
+
return obj;
|
| 140 |
+
}
|
| 141 |
+
__destroy_into_raw() {
|
| 142 |
+
const ptr = this.__wbg_ptr;
|
| 143 |
+
this.__wbg_ptr = 0;
|
| 144 |
+
UsdSceneFinalization.unregister(this);
|
| 145 |
+
return ptr;
|
| 146 |
+
}
|
| 147 |
+
free() {
|
| 148 |
+
const ptr = this.__destroy_into_raw();
|
| 149 |
+
wasm.__wbg_usdscene_free(ptr, 0);
|
| 150 |
+
}
|
| 151 |
+
/**
|
| 152 |
+
* How many colliders the scene's physics holds (0 when it was not read).
|
| 153 |
+
* @returns {number}
|
| 154 |
+
*/
|
| 155 |
+
colliderCount() {
|
| 156 |
+
const ret = wasm.usdscene_colliderCount(this.__wbg_ptr);
|
| 157 |
+
return ret >>> 0;
|
| 158 |
+
}
|
| 159 |
+
/**
|
| 160 |
+
* @returns {Float32Array}
|
| 161 |
+
*/
|
| 162 |
+
colors() {
|
| 163 |
+
try {
|
| 164 |
+
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
| 165 |
+
wasm.usdscene_colors(retptr, this.__wbg_ptr);
|
| 166 |
+
var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
|
| 167 |
+
var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
|
| 168 |
+
var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
|
| 169 |
+
var r3 = getDataViewMemory0().getInt32(retptr + 4 * 3, true);
|
| 170 |
+
if (r3) {
|
| 171 |
+
throw takeObject(r2);
|
| 172 |
+
}
|
| 173 |
+
var v1 = getArrayF32FromWasm0(r0, r1).slice();
|
| 174 |
+
wasm.__wbindgen_export3(r0, r1 * 4, 4);
|
| 175 |
+
return v1;
|
| 176 |
+
} finally {
|
| 177 |
+
wasm.__wbindgen_add_to_stack_pointer(16);
|
| 178 |
+
}
|
| 179 |
+
}
|
| 180 |
+
/**
|
| 181 |
+
* Releases the stage once every geometry has been read.
|
| 182 |
+
*/
|
| 183 |
+
finish() {
|
| 184 |
+
wasm.usdscene_finish(this.__wbg_ptr);
|
| 185 |
+
}
|
| 186 |
+
/**
|
| 187 |
+
* Indices as 16-bit, for geometries with fewer than 65536 vertices.
|
| 188 |
+
* @returns {Uint16Array}
|
| 189 |
+
*/
|
| 190 |
+
indices16() {
|
| 191 |
+
try {
|
| 192 |
+
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
| 193 |
+
wasm.usdscene_indices16(retptr, this.__wbg_ptr);
|
| 194 |
+
var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
|
| 195 |
+
var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
|
| 196 |
+
var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
|
| 197 |
+
var r3 = getDataViewMemory0().getInt32(retptr + 4 * 3, true);
|
| 198 |
+
if (r3) {
|
| 199 |
+
throw takeObject(r2);
|
| 200 |
+
}
|
| 201 |
+
var v1 = getArrayU16FromWasm0(r0, r1).slice();
|
| 202 |
+
wasm.__wbindgen_export3(r0, r1 * 2, 2);
|
| 203 |
+
return v1;
|
| 204 |
+
} finally {
|
| 205 |
+
wasm.__wbindgen_add_to_stack_pointer(16);
|
| 206 |
+
}
|
| 207 |
+
}
|
| 208 |
+
/**
|
| 209 |
+
* @returns {Uint32Array}
|
| 210 |
+
*/
|
| 211 |
+
indices() {
|
| 212 |
+
try {
|
| 213 |
+
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
| 214 |
+
wasm.usdscene_indices(retptr, this.__wbg_ptr);
|
| 215 |
+
var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
|
| 216 |
+
var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
|
| 217 |
+
var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
|
| 218 |
+
var r3 = getDataViewMemory0().getInt32(retptr + 4 * 3, true);
|
| 219 |
+
if (r3) {
|
| 220 |
+
throw takeObject(r2);
|
| 221 |
+
}
|
| 222 |
+
var v1 = getArrayU32FromWasm0(r0, r1).slice();
|
| 223 |
+
wasm.__wbindgen_export3(r0, r1 * 4, 4);
|
| 224 |
+
return v1;
|
| 225 |
+
} finally {
|
| 226 |
+
wasm.__wbindgen_add_to_stack_pointer(16);
|
| 227 |
+
}
|
| 228 |
+
}
|
| 229 |
+
/**
|
| 230 |
+
* Everything but the triangle data, as JSON.
|
| 231 |
+
* @returns {string}
|
| 232 |
+
*/
|
| 233 |
+
meta() {
|
| 234 |
+
let deferred1_0;
|
| 235 |
+
let deferred1_1;
|
| 236 |
+
try {
|
| 237 |
+
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
| 238 |
+
wasm.usdscene_meta(retptr, this.__wbg_ptr);
|
| 239 |
+
var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
|
| 240 |
+
var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
|
| 241 |
+
deferred1_0 = r0;
|
| 242 |
+
deferred1_1 = r1;
|
| 243 |
+
return getStringFromWasm0(r0, r1);
|
| 244 |
+
} finally {
|
| 245 |
+
wasm.__wbindgen_add_to_stack_pointer(16);
|
| 246 |
+
wasm.__wbindgen_export3(deferred1_0, deferred1_1, 1);
|
| 247 |
+
}
|
| 248 |
+
}
|
| 249 |
+
/**
|
| 250 |
+
* @returns {Float32Array}
|
| 251 |
+
*/
|
| 252 |
+
normals() {
|
| 253 |
+
try {
|
| 254 |
+
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
| 255 |
+
wasm.usdscene_normals(retptr, this.__wbg_ptr);
|
| 256 |
+
var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
|
| 257 |
+
var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
|
| 258 |
+
var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
|
| 259 |
+
var r3 = getDataViewMemory0().getInt32(retptr + 4 * 3, true);
|
| 260 |
+
if (r3) {
|
| 261 |
+
throw takeObject(r2);
|
| 262 |
+
}
|
| 263 |
+
var v1 = getArrayF32FromWasm0(r0, r1).slice();
|
| 264 |
+
wasm.__wbindgen_export3(r0, r1 * 4, 4);
|
| 265 |
+
return v1;
|
| 266 |
+
} finally {
|
| 267 |
+
wasm.__wbindgen_add_to_stack_pointer(16);
|
| 268 |
+
}
|
| 269 |
+
}
|
| 270 |
+
/**
|
| 271 |
+
* A texture that lives inside a USDZ package, if `path` names one there.
|
| 272 |
+
* Fails rather than expand it past `limit` bytes.
|
| 273 |
+
* @param {string} path
|
| 274 |
+
* @param {number} limit
|
| 275 |
+
* @returns {Uint8Array | undefined}
|
| 276 |
+
*/
|
| 277 |
+
packagedFile(path, limit) {
|
| 278 |
+
try {
|
| 279 |
+
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
| 280 |
+
const ptr0 = passStringToWasm0(path, wasm.__wbindgen_export, wasm.__wbindgen_export2);
|
| 281 |
+
const len0 = WASM_VECTOR_LEN;
|
| 282 |
+
wasm.usdscene_packagedFile(retptr, this.__wbg_ptr, ptr0, len0, limit);
|
| 283 |
+
var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
|
| 284 |
+
var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
|
| 285 |
+
var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
|
| 286 |
+
var r3 = getDataViewMemory0().getInt32(retptr + 4 * 3, true);
|
| 287 |
+
if (r3) {
|
| 288 |
+
throw takeObject(r2);
|
| 289 |
+
}
|
| 290 |
+
let v2;
|
| 291 |
+
if (r0 !== 0) {
|
| 292 |
+
v2 = getArrayU8FromWasm0(r0, r1).slice();
|
| 293 |
+
wasm.__wbindgen_export3(r0, r1 * 1, 1);
|
| 294 |
+
}
|
| 295 |
+
return v2;
|
| 296 |
+
} finally {
|
| 297 |
+
wasm.__wbindgen_add_to_stack_pointer(16);
|
| 298 |
+
}
|
| 299 |
+
}
|
| 300 |
+
/**
|
| 301 |
+
* @returns {Float32Array}
|
| 302 |
+
*/
|
| 303 |
+
positions() {
|
| 304 |
+
try {
|
| 305 |
+
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
| 306 |
+
wasm.usdscene_positions(retptr, this.__wbg_ptr);
|
| 307 |
+
var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
|
| 308 |
+
var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
|
| 309 |
+
var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
|
| 310 |
+
var r3 = getDataViewMemory0().getInt32(retptr + 4 * 3, true);
|
| 311 |
+
if (r3) {
|
| 312 |
+
throw takeObject(r2);
|
| 313 |
+
}
|
| 314 |
+
var v1 = getArrayF32FromWasm0(r0, r1).slice();
|
| 315 |
+
wasm.__wbindgen_export3(r0, r1 * 4, 4);
|
| 316 |
+
return v1;
|
| 317 |
+
} finally {
|
| 318 |
+
wasm.__wbindgen_add_to_stack_pointer(16);
|
| 319 |
+
}
|
| 320 |
+
}
|
| 321 |
+
/**
|
| 322 |
+
* Reads collider `index`: returns its metadata as JSON (`path`, `body`,
|
| 323 |
+
* `approximation`, `enabled`, `purpose`, `vertices`, `triangles`) and makes
|
| 324 |
+
* its points and triangle indices current for [`positions`](Self::positions)
|
| 325 |
+
* and [`indices`](Self::indices) (each once).
|
| 326 |
+
* @param {number} index
|
| 327 |
+
* @returns {string}
|
| 328 |
+
*/
|
| 329 |
+
readCollider(index) {
|
| 330 |
+
let deferred2_0;
|
| 331 |
+
let deferred2_1;
|
| 332 |
+
try {
|
| 333 |
+
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
| 334 |
+
wasm.usdscene_readCollider(retptr, this.__wbg_ptr, index);
|
| 335 |
+
var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
|
| 336 |
+
var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
|
| 337 |
+
var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
|
| 338 |
+
var r3 = getDataViewMemory0().getInt32(retptr + 4 * 3, true);
|
| 339 |
+
var ptr1 = r0;
|
| 340 |
+
var len1 = r1;
|
| 341 |
+
if (r3) {
|
| 342 |
+
ptr1 = 0; len1 = 0;
|
| 343 |
+
throw takeObject(r2);
|
| 344 |
+
}
|
| 345 |
+
deferred2_0 = ptr1;
|
| 346 |
+
deferred2_1 = len1;
|
| 347 |
+
return getStringFromWasm0(ptr1, len1);
|
| 348 |
+
} finally {
|
| 349 |
+
wasm.__wbindgen_add_to_stack_pointer(16);
|
| 350 |
+
wasm.__wbindgen_export3(deferred2_0, deferred2_1, 1);
|
| 351 |
+
}
|
| 352 |
+
}
|
| 353 |
+
/**
|
| 354 |
+
* Reads geometry `index` and returns its metadata as JSON, or `None` when
|
| 355 |
+
* the mesh has nothing drawable. A mesh with more than `max_triangles` is
|
| 356 |
+
* left unread: `{"overBudget": triangles, "path": prim path}`.
|
| 357 |
+
* @param {number} index
|
| 358 |
+
* @param {number} max_triangles
|
| 359 |
+
* @returns {string | undefined}
|
| 360 |
+
*/
|
| 361 |
+
read(index, max_triangles) {
|
| 362 |
+
try {
|
| 363 |
+
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
| 364 |
+
wasm.usdscene_read(retptr, this.__wbg_ptr, index, max_triangles);
|
| 365 |
+
var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
|
| 366 |
+
var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
|
| 367 |
+
var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
|
| 368 |
+
var r3 = getDataViewMemory0().getInt32(retptr + 4 * 3, true);
|
| 369 |
+
if (r3) {
|
| 370 |
+
throw takeObject(r2);
|
| 371 |
+
}
|
| 372 |
+
let v1;
|
| 373 |
+
if (r0 !== 0) {
|
| 374 |
+
v1 = getStringFromWasm0(r0, r1);
|
| 375 |
+
wasm.__wbindgen_export3(r0, r1 * 1, 1);
|
| 376 |
+
}
|
| 377 |
+
return v1;
|
| 378 |
+
} finally {
|
| 379 |
+
wasm.__wbindgen_add_to_stack_pointer(16);
|
| 380 |
+
}
|
| 381 |
+
}
|
| 382 |
+
/**
|
| 383 |
+
* UV set `set` (in the order of the geometry's `uvSets`).
|
| 384 |
+
* @param {number} set
|
| 385 |
+
* @returns {Float32Array}
|
| 386 |
+
*/
|
| 387 |
+
uvs(set) {
|
| 388 |
+
try {
|
| 389 |
+
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
| 390 |
+
wasm.usdscene_uvs(retptr, this.__wbg_ptr, set);
|
| 391 |
+
var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
|
| 392 |
+
var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
|
| 393 |
+
var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
|
| 394 |
+
var r3 = getDataViewMemory0().getInt32(retptr + 4 * 3, true);
|
| 395 |
+
if (r3) {
|
| 396 |
+
throw takeObject(r2);
|
| 397 |
+
}
|
| 398 |
+
var v1 = getArrayF32FromWasm0(r0, r1).slice();
|
| 399 |
+
wasm.__wbindgen_export3(r0, r1 * 4, 4);
|
| 400 |
+
return v1;
|
| 401 |
+
} finally {
|
| 402 |
+
wasm.__wbindgen_add_to_stack_pointer(16);
|
| 403 |
+
}
|
| 404 |
+
}
|
| 405 |
+
}
|
| 406 |
+
if (Symbol.dispose) UsdScene.prototype[Symbol.dispose] = UsdScene.prototype.free;
|
| 407 |
+
|
| 408 |
+
/**
|
| 409 |
+
* Takes the message of the last panic, if any.
|
| 410 |
+
* @returns {string | undefined}
|
| 411 |
+
*/
|
| 412 |
+
export function lastPanic() {
|
| 413 |
+
try {
|
| 414 |
+
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
| 415 |
+
wasm.lastPanic(retptr);
|
| 416 |
+
var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
|
| 417 |
+
var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
|
| 418 |
+
let v1;
|
| 419 |
+
if (r0 !== 0) {
|
| 420 |
+
v1 = getStringFromWasm0(r0, r1);
|
| 421 |
+
wasm.__wbindgen_export3(r0, r1 * 1, 1);
|
| 422 |
+
}
|
| 423 |
+
return v1;
|
| 424 |
+
} finally {
|
| 425 |
+
wasm.__wbindgen_add_to_stack_pointer(16);
|
| 426 |
+
}
|
| 427 |
+
}
|
| 428 |
+
|
| 429 |
+
export function start() {
|
| 430 |
+
wasm.start();
|
| 431 |
+
}
|
| 432 |
+
function __wbg_get_imports() {
|
| 433 |
+
const import0 = {
|
| 434 |
+
__proto__: null,
|
| 435 |
+
__wbg_Error_30c8987f7c2ed4e2: function(arg0, arg1) {
|
| 436 |
+
const ret = Error(getStringFromWasm0(arg0, arg1));
|
| 437 |
+
return addHeapObject(ret);
|
| 438 |
+
},
|
| 439 |
+
__wbg___wbindgen_string_get_0380ccaa2f57f0d9: function(arg0, arg1) {
|
| 440 |
+
const obj = getObject(arg1);
|
| 441 |
+
const ret = typeof(obj) === 'string' ? obj : undefined;
|
| 442 |
+
var ptr1 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_export, wasm.__wbindgen_export2);
|
| 443 |
+
var len1 = WASM_VECTOR_LEN;
|
| 444 |
+
getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
|
| 445 |
+
getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
|
| 446 |
+
},
|
| 447 |
+
__wbg___wbindgen_throw_41e9ee4f547fc59a: function(arg0, arg1) {
|
| 448 |
+
throw new Error(getStringFromWasm0(arg0, arg1));
|
| 449 |
+
},
|
| 450 |
+
__wbindgen_generic_0000000000000001: function(arg0, arg1) {
|
| 451 |
+
// Cast intrinsic for `Ref(String) -> Externref`.
|
| 452 |
+
const ret = getStringFromWasm0(arg0, arg1);
|
| 453 |
+
return addHeapObject(ret);
|
| 454 |
+
},
|
| 455 |
+
__wbindgen_object_drop_ref: function(arg0) {
|
| 456 |
+
takeObject(arg0);
|
| 457 |
+
},
|
| 458 |
+
};
|
| 459 |
+
return {
|
| 460 |
+
__proto__: null,
|
| 461 |
+
"./usd_wasm_bg.js": import0,
|
| 462 |
+
};
|
| 463 |
+
}
|
| 464 |
+
|
| 465 |
+
const UsdLoaderFinalization = (typeof FinalizationRegistry === 'undefined')
|
| 466 |
+
? { register: () => {}, unregister: () => {} }
|
| 467 |
+
: new FinalizationRegistry(ptr => wasm.__wbg_usdloader_free(ptr, 1));
|
| 468 |
+
const UsdSceneFinalization = (typeof FinalizationRegistry === 'undefined')
|
| 469 |
+
? { register: () => {}, unregister: () => {} }
|
| 470 |
+
: new FinalizationRegistry(ptr => wasm.__wbg_usdscene_free(ptr, 1));
|
| 471 |
+
|
| 472 |
+
function addHeapObject(obj) {
|
| 473 |
+
if (heap_next === heap.length) heap.push(heap.length + 1);
|
| 474 |
+
const idx = heap_next;
|
| 475 |
+
heap_next = heap[idx];
|
| 476 |
+
|
| 477 |
+
heap[idx] = obj;
|
| 478 |
+
return idx;
|
| 479 |
+
}
|
| 480 |
+
|
| 481 |
+
function dropObject(idx) {
|
| 482 |
+
if (idx < 1028) return;
|
| 483 |
+
heap[idx] = heap_next;
|
| 484 |
+
heap_next = idx;
|
| 485 |
+
}
|
| 486 |
+
|
| 487 |
+
function getArrayF32FromWasm0(ptr, len) {
|
| 488 |
+
ptr = ptr >>> 0;
|
| 489 |
+
return getFloat32ArrayMemory0().subarray(ptr / 4, ptr / 4 + len);
|
| 490 |
+
}
|
| 491 |
+
|
| 492 |
+
function getArrayJsValueFromWasm0(ptr, len) {
|
| 493 |
+
ptr = ptr >>> 0;
|
| 494 |
+
const mem = getDataViewMemory0();
|
| 495 |
+
const result = [];
|
| 496 |
+
for (let i = ptr; i < ptr + 4 * len; i += 4) {
|
| 497 |
+
result.push(takeObject(mem.getUint32(i, true)));
|
| 498 |
+
}
|
| 499 |
+
return result;
|
| 500 |
+
}
|
| 501 |
+
|
| 502 |
+
function getArrayU16FromWasm0(ptr, len) {
|
| 503 |
+
ptr = ptr >>> 0;
|
| 504 |
+
return getUint16ArrayMemory0().subarray(ptr / 2, ptr / 2 + len);
|
| 505 |
+
}
|
| 506 |
+
|
| 507 |
+
function getArrayU32FromWasm0(ptr, len) {
|
| 508 |
+
ptr = ptr >>> 0;
|
| 509 |
+
return getUint32ArrayMemory0().subarray(ptr / 4, ptr / 4 + len);
|
| 510 |
+
}
|
| 511 |
+
|
| 512 |
+
function getArrayU8FromWasm0(ptr, len) {
|
| 513 |
+
ptr = ptr >>> 0;
|
| 514 |
+
return getUint8ArrayMemory0().subarray(ptr / 1, ptr / 1 + len);
|
| 515 |
+
}
|
| 516 |
+
|
| 517 |
+
let cachedDataViewMemory0 = null;
|
| 518 |
+
function getDataViewMemory0() {
|
| 519 |
+
if (cachedDataViewMemory0 === null || cachedDataViewMemory0.buffer.detached === true || (cachedDataViewMemory0.buffer.detached === undefined && cachedDataViewMemory0.buffer !== wasm.memory.buffer)) {
|
| 520 |
+
cachedDataViewMemory0 = new DataView(wasm.memory.buffer);
|
| 521 |
+
}
|
| 522 |
+
return cachedDataViewMemory0;
|
| 523 |
+
}
|
| 524 |
+
|
| 525 |
+
let cachedFloat32ArrayMemory0 = null;
|
| 526 |
+
function getFloat32ArrayMemory0() {
|
| 527 |
+
if (cachedFloat32ArrayMemory0 === null || cachedFloat32ArrayMemory0.byteLength === 0) {
|
| 528 |
+
cachedFloat32ArrayMemory0 = new Float32Array(wasm.memory.buffer);
|
| 529 |
+
}
|
| 530 |
+
return cachedFloat32ArrayMemory0;
|
| 531 |
+
}
|
| 532 |
+
|
| 533 |
+
function getStringFromWasm0(ptr, len) {
|
| 534 |
+
return decodeText(ptr >>> 0, len);
|
| 535 |
+
}
|
| 536 |
+
|
| 537 |
+
let cachedUint16ArrayMemory0 = null;
|
| 538 |
+
function getUint16ArrayMemory0() {
|
| 539 |
+
if (cachedUint16ArrayMemory0 === null || cachedUint16ArrayMemory0.byteLength === 0) {
|
| 540 |
+
cachedUint16ArrayMemory0 = new Uint16Array(wasm.memory.buffer);
|
| 541 |
+
}
|
| 542 |
+
return cachedUint16ArrayMemory0;
|
| 543 |
+
}
|
| 544 |
+
|
| 545 |
+
let cachedUint32ArrayMemory0 = null;
|
| 546 |
+
function getUint32ArrayMemory0() {
|
| 547 |
+
if (cachedUint32ArrayMemory0 === null || cachedUint32ArrayMemory0.byteLength === 0) {
|
| 548 |
+
cachedUint32ArrayMemory0 = new Uint32Array(wasm.memory.buffer);
|
| 549 |
+
}
|
| 550 |
+
return cachedUint32ArrayMemory0;
|
| 551 |
+
}
|
| 552 |
+
|
| 553 |
+
let cachedUint8ArrayMemory0 = null;
|
| 554 |
+
function getUint8ArrayMemory0() {
|
| 555 |
+
if (cachedUint8ArrayMemory0 === null || cachedUint8ArrayMemory0.byteLength === 0) {
|
| 556 |
+
cachedUint8ArrayMemory0 = new Uint8Array(wasm.memory.buffer);
|
| 557 |
+
}
|
| 558 |
+
return cachedUint8ArrayMemory0;
|
| 559 |
+
}
|
| 560 |
+
|
| 561 |
+
function getObject(idx) { return heap[idx]; }
|
| 562 |
+
|
| 563 |
+
let heap = new Array(1024).fill(undefined);
|
| 564 |
+
heap.push(undefined, null, true, false);
|
| 565 |
+
|
| 566 |
+
let heap_next = heap.length;
|
| 567 |
+
|
| 568 |
+
function isLikeNone(x) {
|
| 569 |
+
return x === undefined || x === null;
|
| 570 |
+
}
|
| 571 |
+
|
| 572 |
+
function passArray8ToWasm0(arg, malloc) {
|
| 573 |
+
const ptr = malloc(arg.length * 1, 1) >>> 0;
|
| 574 |
+
getUint8ArrayMemory0().set(arg, ptr / 1);
|
| 575 |
+
WASM_VECTOR_LEN = arg.length;
|
| 576 |
+
return ptr;
|
| 577 |
+
}
|
| 578 |
+
|
| 579 |
+
function passArrayJsValueToWasm0(array, malloc) {
|
| 580 |
+
const ptr = malloc(array.length * 4, 4) >>> 0;
|
| 581 |
+
const mem = getDataViewMemory0();
|
| 582 |
+
for (let i = 0; i < array.length; i++) {
|
| 583 |
+
mem.setUint32(ptr + 4 * i, addHeapObject(array[i]), true);
|
| 584 |
+
}
|
| 585 |
+
WASM_VECTOR_LEN = array.length;
|
| 586 |
+
return ptr;
|
| 587 |
+
}
|
| 588 |
+
|
| 589 |
+
function passStringToWasm0(arg, malloc, realloc) {
|
| 590 |
+
if (realloc === undefined) {
|
| 591 |
+
const buf = cachedTextEncoder.encode(arg);
|
| 592 |
+
const ptr = malloc(buf.length, 1) >>> 0;
|
| 593 |
+
getUint8ArrayMemory0().subarray(ptr, ptr + buf.length).set(buf);
|
| 594 |
+
WASM_VECTOR_LEN = buf.length;
|
| 595 |
+
return ptr;
|
| 596 |
+
}
|
| 597 |
+
|
| 598 |
+
let len = arg.length;
|
| 599 |
+
let ptr = malloc(len, 1) >>> 0;
|
| 600 |
+
|
| 601 |
+
const mem = getUint8ArrayMemory0();
|
| 602 |
+
|
| 603 |
+
let offset = 0;
|
| 604 |
+
|
| 605 |
+
for (; offset < len; offset++) {
|
| 606 |
+
const code = arg.charCodeAt(offset);
|
| 607 |
+
if (code > 0x7F) break;
|
| 608 |
+
mem[ptr + offset] = code;
|
| 609 |
+
}
|
| 610 |
+
if (offset !== len) {
|
| 611 |
+
if (offset !== 0) {
|
| 612 |
+
arg = arg.slice(offset);
|
| 613 |
+
}
|
| 614 |
+
ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0;
|
| 615 |
+
const view = getUint8ArrayMemory0().subarray(ptr + offset, ptr + len);
|
| 616 |
+
const ret = cachedTextEncoder.encodeInto(arg, view);
|
| 617 |
+
|
| 618 |
+
offset += ret.written;
|
| 619 |
+
ptr = realloc(ptr, len, offset, 1) >>> 0;
|
| 620 |
+
}
|
| 621 |
+
|
| 622 |
+
WASM_VECTOR_LEN = offset;
|
| 623 |
+
return ptr;
|
| 624 |
+
}
|
| 625 |
+
|
| 626 |
+
function takeObject(idx) {
|
| 627 |
+
const ret = getObject(idx);
|
| 628 |
+
dropObject(idx);
|
| 629 |
+
return ret;
|
| 630 |
+
}
|
| 631 |
+
|
| 632 |
+
let cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });
|
| 633 |
+
cachedTextDecoder.decode();
|
| 634 |
+
const MAX_SAFARI_DECODE_BYTES = 2146435072;
|
| 635 |
+
let numBytesDecoded = 0;
|
| 636 |
+
function decodeText(ptr, len) {
|
| 637 |
+
numBytesDecoded += len;
|
| 638 |
+
if (numBytesDecoded >= MAX_SAFARI_DECODE_BYTES) {
|
| 639 |
+
cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });
|
| 640 |
+
cachedTextDecoder.decode();
|
| 641 |
+
numBytesDecoded = len;
|
| 642 |
+
}
|
| 643 |
+
return cachedTextDecoder.decode(getUint8ArrayMemory0().subarray(ptr, ptr + len));
|
| 644 |
+
}
|
| 645 |
+
|
| 646 |
+
const cachedTextEncoder = new TextEncoder();
|
| 647 |
+
|
| 648 |
+
if (!('encodeInto' in cachedTextEncoder)) {
|
| 649 |
+
cachedTextEncoder.encodeInto = function (arg, view) {
|
| 650 |
+
const buf = cachedTextEncoder.encode(arg);
|
| 651 |
+
view.set(buf);
|
| 652 |
+
return {
|
| 653 |
+
read: arg.length,
|
| 654 |
+
written: buf.length
|
| 655 |
+
};
|
| 656 |
+
};
|
| 657 |
+
}
|
| 658 |
+
|
| 659 |
+
let WASM_VECTOR_LEN = 0;
|
| 660 |
+
|
| 661 |
+
let wasmModule, wasmInstance, wasm;
|
| 662 |
+
function __wbg_finalize_init(instance, module) {
|
| 663 |
+
wasmInstance = instance;
|
| 664 |
+
wasm = instance.exports;
|
| 665 |
+
wasmModule = module;
|
| 666 |
+
cachedDataViewMemory0 = null;
|
| 667 |
+
cachedFloat32ArrayMemory0 = null;
|
| 668 |
+
cachedUint16ArrayMemory0 = null;
|
| 669 |
+
cachedUint32ArrayMemory0 = null;
|
| 670 |
+
cachedUint8ArrayMemory0 = null;
|
| 671 |
+
wasm.__wbindgen_start();
|
| 672 |
+
return wasm;
|
| 673 |
+
}
|
| 674 |
+
|
| 675 |
+
async function __wbg_load(module, imports) {
|
| 676 |
+
if (typeof Response === 'function' && module instanceof Response) {
|
| 677 |
+
if (!module.ok) {
|
| 678 |
+
throw new Error(`failed to fetch Wasm: ${module.status} ${module.statusText} fetching '${module.url}'`);
|
| 679 |
+
}
|
| 680 |
+
|
| 681 |
+
if (typeof WebAssembly.instantiateStreaming === 'function') {
|
| 682 |
+
try {
|
| 683 |
+
return await WebAssembly.instantiateStreaming(module, imports);
|
| 684 |
+
} catch (e) {
|
| 685 |
+
const validResponse = expectedResponseType(module.type);
|
| 686 |
+
|
| 687 |
+
if (validResponse && module.headers.get('Content-Type') !== 'application/wasm') {
|
| 688 |
+
console.warn("`WebAssembly.instantiateStreaming` failed because your server does not serve Wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n", e);
|
| 689 |
+
|
| 690 |
+
} else { throw e; }
|
| 691 |
+
}
|
| 692 |
+
}
|
| 693 |
+
|
| 694 |
+
const bytes = await module.arrayBuffer();
|
| 695 |
+
return await WebAssembly.instantiate(bytes, imports);
|
| 696 |
+
} else {
|
| 697 |
+
const instance = await WebAssembly.instantiate(module, imports);
|
| 698 |
+
|
| 699 |
+
if (instance instanceof WebAssembly.Instance) {
|
| 700 |
+
return { instance, module };
|
| 701 |
+
} else {
|
| 702 |
+
return instance;
|
| 703 |
+
}
|
| 704 |
+
}
|
| 705 |
+
|
| 706 |
+
function expectedResponseType(type) {
|
| 707 |
+
switch (type) {
|
| 708 |
+
case 'basic': case 'cors': case 'default': return true;
|
| 709 |
+
}
|
| 710 |
+
return false;
|
| 711 |
+
}
|
| 712 |
+
}
|
| 713 |
+
|
| 714 |
+
function initSync(module) {
|
| 715 |
+
if (wasm !== undefined) return wasm;
|
| 716 |
+
|
| 717 |
+
|
| 718 |
+
if (module !== undefined) {
|
| 719 |
+
if (Object.getPrototypeOf(module) === Object.prototype) {
|
| 720 |
+
({module} = module)
|
| 721 |
+
} else {
|
| 722 |
+
console.warn('using deprecated parameters for `initSync()`; pass a single object instead')
|
| 723 |
+
}
|
| 724 |
+
}
|
| 725 |
+
|
| 726 |
+
const imports = __wbg_get_imports();
|
| 727 |
+
if (!(module instanceof WebAssembly.Module)) {
|
| 728 |
+
module = new WebAssembly.Module(module);
|
| 729 |
+
}
|
| 730 |
+
const instance = new WebAssembly.Instance(module, imports);
|
| 731 |
+
return __wbg_finalize_init(instance, module);
|
| 732 |
+
}
|
| 733 |
+
|
| 734 |
+
async function __wbg_init(module_or_path) {
|
| 735 |
+
if (wasm !== undefined) return wasm;
|
| 736 |
+
|
| 737 |
+
|
| 738 |
+
if (module_or_path !== undefined) {
|
| 739 |
+
if (Object.getPrototypeOf(module_or_path) === Object.prototype) {
|
| 740 |
+
({module_or_path} = module_or_path)
|
| 741 |
+
} else {
|
| 742 |
+
console.warn('using deprecated parameters for the initialization function; pass a single object instead')
|
| 743 |
+
}
|
| 744 |
+
}
|
| 745 |
+
|
| 746 |
+
if (module_or_path === undefined) {
|
| 747 |
+
module_or_path = new URL('usd_wasm_bg.wasm', import.meta.url);
|
| 748 |
+
}
|
| 749 |
+
const imports = __wbg_get_imports();
|
| 750 |
+
|
| 751 |
+
if (typeof module_or_path === 'string' || (typeof Request === 'function' && module_or_path instanceof Request) || (typeof URL === 'function' && module_or_path instanceof URL)) {
|
| 752 |
+
module_or_path = fetch(module_or_path);
|
| 753 |
+
}
|
| 754 |
+
|
| 755 |
+
const { instance, module } = await __wbg_load(await module_or_path, imports);
|
| 756 |
+
|
| 757 |
+
return __wbg_finalize_init(instance, module);
|
| 758 |
+
}
|
| 759 |
+
|
| 760 |
+
export { initSync, __wbg_init as default };
|
services/explorer/dist/static/usd-reader/81290bc/wasm/usd_wasm_bg.wasm
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:d746ca57ac800465e447c67d1790b6c19da772e02501083a25a189bcd9aaa74b
|
| 3 |
+
size 2356773
|
services/explorer/dist/third-party-notices.txt
CHANGED
|
@@ -1,4 +1,4 @@
|
|
| 1 |
-
Third-party notices — SimReady Central Explorer slim-ui-
|
| 2 |
|
| 3 |
The software in this web application's browser bundle includes the packages below, each under its own
|
| 4 |
license. Each entry gives the package, its version, its license and the license / notice text it ships.
|
|
|
|
| 1 |
+
Third-party notices — SimReady Central Explorer slim-ui-9d95b298
|
| 2 |
|
| 3 |
The software in this web application's browser bundle includes the packages below, each under its own
|
| 4 |
license. Each entry gives the package, its version, its license and the license / notice text it ships.
|