@honua/app-platform 0.1.11-beta.0 → 0.1.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (236) hide show
  1. package/columnar/apache-arrow.d.ts +17 -0
  2. package/columnar/apache-arrow.d.ts.map +1 -0
  3. package/columnar/apache-arrow.js +1036 -0
  4. package/columnar/batch-cache-conformance.d.ts +66 -0
  5. package/columnar/batch-cache-conformance.d.ts.map +1 -0
  6. package/columnar/batch-cache-conformance.js +317 -0
  7. package/columnar/batch-cache-indexeddb.d.ts +31 -0
  8. package/columnar/batch-cache-indexeddb.d.ts.map +1 -0
  9. package/columnar/batch-cache-indexeddb.js +148 -0
  10. package/columnar/batch-cache.d.ts +298 -0
  11. package/columnar/batch-cache.d.ts.map +1 -0
  12. package/columnar/batch-cache.js +757 -0
  13. package/columnar/geoarrow-aggregate.d.ts +178 -0
  14. package/columnar/geoarrow-aggregate.d.ts.map +1 -0
  15. package/columnar/geoarrow-aggregate.js +976 -0
  16. package/columnar/geoarrow-patch.d.ts +382 -0
  17. package/columnar/geoarrow-patch.d.ts.map +1 -0
  18. package/columnar/geoarrow-patch.js +1656 -0
  19. package/columnar/geoarrow-reproject.d.ts +22 -0
  20. package/columnar/geoarrow-reproject.d.ts.map +1 -0
  21. package/columnar/geoarrow-reproject.js +119 -0
  22. package/columnar/geoarrow-serialization.d.ts +68 -0
  23. package/columnar/geoarrow-serialization.d.ts.map +1 -0
  24. package/columnar/geoarrow-serialization.js +331 -0
  25. package/columnar/geoarrow-types.d.ts +271 -0
  26. package/columnar/geoarrow-types.d.ts.map +1 -0
  27. package/columnar/geoarrow-types.js +15 -0
  28. package/columnar/geoarrow.d.ts +52 -0
  29. package/columnar/geoarrow.d.ts.map +1 -0
  30. package/columnar/geoarrow.js +1469 -0
  31. package/columnar/index.d.ts +43 -0
  32. package/columnar/index.d.ts.map +1 -0
  33. package/columnar/index.js +29 -0
  34. package/columnar/operators.d.ts +70 -0
  35. package/columnar/operators.d.ts.map +1 -0
  36. package/columnar/operators.js +307 -0
  37. package/columnar/result.d.ts +369 -0
  38. package/columnar/result.d.ts.map +1 -0
  39. package/columnar/result.js +815 -0
  40. package/columnar/telemetry.d.ts +152 -0
  41. package/columnar/telemetry.d.ts.map +1 -0
  42. package/columnar/telemetry.js +265 -0
  43. package/columnar/transfer.d.ts +28 -0
  44. package/columnar/transfer.d.ts.map +1 -0
  45. package/columnar/transfer.js +669 -0
  46. package/columnar/types.d.ts +175 -0
  47. package/columnar/types.d.ts.map +1 -0
  48. package/columnar/types.js +22 -0
  49. package/columnar/worker.d.ts +157 -0
  50. package/columnar/worker.d.ts.map +1 -0
  51. package/columnar/worker.js +1059 -0
  52. package/contract/pmtiles.d.ts +6 -5
  53. package/contract/pmtiles.d.ts.map +1 -1
  54. package/contract/pmtiles.js +30 -5
  55. package/control-plane/generated/admin-operations.d.ts +3 -3
  56. package/control-plane/generated/admin-operations.d.ts.map +1 -1
  57. package/control-plane/generated/admin-operations.js +3 -3
  58. package/controls/catalog.d.ts.map +1 -1
  59. package/controls/catalog.js +110 -0
  60. package/controls/index.d.ts +1 -1
  61. package/controls/index.js +1 -1
  62. package/controls/types.d.ts +1 -1
  63. package/controls/types.js +1 -1
  64. package/core/client.d.ts.map +1 -1
  65. package/core/client.js +87 -19
  66. package/core/deprecation-notice.d.ts +28 -0
  67. package/core/deprecation-notice.d.ts.map +1 -0
  68. package/core/deprecation-notice.js +22 -0
  69. package/core/esri-geojson.d.ts.map +1 -1
  70. package/core/esri-geojson.js +10 -6
  71. package/core/optional-grpc-peer.d.ts +15 -0
  72. package/core/optional-grpc-peer.d.ts.map +1 -0
  73. package/core/optional-grpc-peer.js +60 -0
  74. package/esri-compat/basemap-gallery.d.ts +2 -0
  75. package/esri-compat/basemap-gallery.d.ts.map +1 -1
  76. package/esri-compat/basemap-gallery.js +12 -0
  77. package/esri-compat/basemap.d.ts +4 -0
  78. package/esri-compat/basemap.d.ts.map +1 -1
  79. package/esri-compat/basemap.js +70 -0
  80. package/esri-compat/bookmarks.d.ts +2 -0
  81. package/esri-compat/bookmarks.d.ts.map +1 -1
  82. package/esri-compat/bookmarks.js +12 -0
  83. package/esri-compat/controls.d.ts +18 -0
  84. package/esri-compat/controls.d.ts.map +1 -1
  85. package/esri-compat/controls.js +120 -57
  86. package/esri-compat/directions.d.ts +4 -0
  87. package/esri-compat/directions.d.ts.map +1 -1
  88. package/esri-compat/directions.js +30 -20
  89. package/esri-compat/editor.d.ts +4 -0
  90. package/esri-compat/editor.d.ts.map +1 -1
  91. package/esri-compat/editor.js +16 -0
  92. package/esri-compat/esri-config.d.ts +2 -1
  93. package/esri-compat/esri-config.d.ts.map +1 -1
  94. package/esri-compat/feature-effect.d.ts +23 -0
  95. package/esri-compat/feature-effect.d.ts.map +1 -0
  96. package/esri-compat/feature-effect.js +12 -0
  97. package/esri-compat/feature-form.d.ts +6 -0
  98. package/esri-compat/feature-form.d.ts.map +1 -1
  99. package/esri-compat/feature-form.js +63 -0
  100. package/esri-compat/feature-layer.d.ts +21 -2
  101. package/esri-compat/feature-layer.d.ts.map +1 -1
  102. package/esri-compat/feature-layer.js +172 -1
  103. package/esri-compat/feature-table.d.ts +5 -0
  104. package/esri-compat/feature-table.d.ts.map +1 -1
  105. package/esri-compat/feature-table.js +23 -0
  106. package/esri-compat/identity-manager.d.ts +1 -1
  107. package/esri-compat/identity-manager.js +1 -1
  108. package/esri-compat/legend.d.ts +2 -0
  109. package/esri-compat/legend.d.ts.map +1 -1
  110. package/esri-compat/legend.js +98 -0
  111. package/esri-compat/locator.d.ts +1 -1
  112. package/esri-compat/locator.js +1 -1
  113. package/esri-compat/map-view-mount.d.ts +1 -0
  114. package/esri-compat/map-view-mount.d.ts.map +1 -1
  115. package/esri-compat/map-view-mount.js +46 -25
  116. package/esri-compat/map-view.d.ts +13 -0
  117. package/esri-compat/map-view.d.ts.map +1 -1
  118. package/esri-compat/map-view.js +94 -8
  119. package/esri-compat/map.d.ts +5 -1
  120. package/esri-compat/map.d.ts.map +1 -1
  121. package/esri-compat/map.js +10 -0
  122. package/esri-compat/measurement.d.ts +2 -0
  123. package/esri-compat/measurement.d.ts.map +1 -1
  124. package/esri-compat/measurement.js +14 -0
  125. package/esri-compat/point.d.ts +7 -0
  126. package/esri-compat/point.d.ts.map +1 -1
  127. package/esri-compat/point.js +33 -3
  128. package/esri-compat/popup.d.ts +2 -0
  129. package/esri-compat/popup.d.ts.map +1 -1
  130. package/esri-compat/popup.js +12 -0
  131. package/esri-compat/portal.d.ts +1 -1
  132. package/esri-compat/portal.js +1 -1
  133. package/esri-compat/print.d.ts +3 -0
  134. package/esri-compat/print.d.ts.map +1 -1
  135. package/esri-compat/print.js +15 -0
  136. package/esri-compat/search.d.ts +4 -0
  137. package/esri-compat/search.d.ts.map +1 -1
  138. package/esri-compat/search.js +25 -28
  139. package/esri-compat/sketch.d.ts +2 -0
  140. package/esri-compat/sketch.d.ts.map +1 -1
  141. package/esri-compat/sketch.js +12 -0
  142. package/esri-compat/widget-host.d.ts +46 -17
  143. package/esri-compat/widget-host.d.ts.map +1 -1
  144. package/esri-compat/widget-host.js +84 -20
  145. package/esri-compat/widget-shell-hosts.d.ts +61 -0
  146. package/esri-compat/widget-shell-hosts.d.ts.map +1 -0
  147. package/esri-compat/widget-shell-hosts.js +76 -0
  148. package/kernel/renderer.d.ts +82 -0
  149. package/kernel/renderer.js +1 -0
  150. package/offline/conflict-resolution.d.ts +183 -0
  151. package/offline/conflict-resolution.d.ts.map +1 -0
  152. package/offline/conflict-resolution.js +286 -0
  153. package/offline/credential-screen.d.ts +34 -0
  154. package/offline/credential-screen.d.ts.map +1 -0
  155. package/offline/credential-screen.js +78 -0
  156. package/offline/digest.d.ts +15 -0
  157. package/offline/digest.d.ts.map +1 -0
  158. package/offline/digest.js +58 -0
  159. package/offline/edit-queue.d.ts +403 -0
  160. package/offline/edit-queue.d.ts.map +1 -0
  161. package/offline/edit-queue.js +1807 -0
  162. package/offline/edit-replay.d.ts +116 -0
  163. package/offline/edit-replay.d.ts.map +1 -0
  164. package/offline/edit-replay.js +392 -0
  165. package/offline/fetch-handler.d.ts +12 -0
  166. package/offline/fetch-handler.d.ts.map +1 -0
  167. package/offline/fetch-handler.js +65 -0
  168. package/offline/index.d.ts +52 -0
  169. package/offline/index.d.ts.map +1 -0
  170. package/offline/index.js +34 -0
  171. package/offline/indexeddb.d.ts +135 -0
  172. package/offline/indexeddb.d.ts.map +1 -0
  173. package/offline/indexeddb.js +888 -0
  174. package/offline/memory-store.d.ts +17 -0
  175. package/offline/memory-store.d.ts.map +1 -0
  176. package/offline/memory-store.js +183 -0
  177. package/offline/quota.d.ts +161 -0
  178. package/offline/quota.d.ts.map +1 -0
  179. package/offline/quota.js +370 -0
  180. package/offline/read-gate.d.ts +175 -0
  181. package/offline/read-gate.d.ts.map +1 -0
  182. package/offline/read-gate.js +252 -0
  183. package/offline/read-resource.d.ts +99 -0
  184. package/offline/read-resource.d.ts.map +1 -0
  185. package/offline/read-resource.js +156 -0
  186. package/offline/read.d.ts +50 -0
  187. package/offline/read.d.ts.map +1 -0
  188. package/offline/read.js +65 -0
  189. package/offline/region.d.ts +29 -0
  190. package/offline/region.d.ts.map +1 -0
  191. package/offline/region.js +1007 -0
  192. package/offline/replay-conflict.d.ts +183 -0
  193. package/offline/replay-conflict.d.ts.map +1 -0
  194. package/offline/replay-conflict.js +482 -0
  195. package/offline/selection.d.ts +140 -0
  196. package/offline/selection.d.ts.map +1 -0
  197. package/offline/selection.js +391 -0
  198. package/offline/snapshot.d.ts +132 -0
  199. package/offline/snapshot.d.ts.map +1 -0
  200. package/offline/snapshot.js +312 -0
  201. package/offline/status.d.ts +136 -0
  202. package/offline/status.d.ts.map +1 -0
  203. package/offline/status.js +479 -0
  204. package/offline/store-conformance.d.ts +48 -0
  205. package/offline/store-conformance.d.ts.map +1 -0
  206. package/offline/store-conformance.js +233 -0
  207. package/offline/tile-protocol.d.ts +81 -0
  208. package/offline/tile-protocol.d.ts.map +1 -0
  209. package/offline/tile-protocol.js +119 -0
  210. package/offline/types.d.ts +349 -0
  211. package/offline/types.d.ts.map +1 -0
  212. package/offline/types.js +75 -0
  213. package/package.json +14 -2
  214. package/scene-workspace/index.d.ts +2 -2
  215. package/scene-workspace/index.d.ts.map +1 -1
  216. package/scene-workspace/index.js +1 -1
  217. package/scene-workspace/scene-discovery.d.ts +111 -91
  218. package/scene-workspace/scene-discovery.d.ts.map +1 -1
  219. package/scene-workspace/scene-discovery.js +340 -92
  220. package/scene-workspace/scene-view.d.ts +6 -6
  221. package/scene-workspace/scene-view.d.ts.map +1 -1
  222. package/scene-workspace/scene-view.js +32 -6
  223. package/web-components/elements.d.ts +34 -0
  224. package/web-components/elements.d.ts.map +1 -1
  225. package/web-components/elements.js +82 -8
  226. package/web-components/index.d.ts +2 -0
  227. package/web-components/index.d.ts.map +1 -1
  228. package/web-components/index.js +3 -1
  229. package/web-components/map-chrome.d.ts +103 -0
  230. package/web-components/map-chrome.d.ts.map +1 -0
  231. package/web-components/map-chrome.js +325 -0
  232. package/web-components/widget-shell.d.ts +68 -0
  233. package/web-components/widget-shell.d.ts.map +1 -0
  234. package/web-components/widget-shell.js +224 -0
  235. package/widget-capabilities.d.ts +67 -0
  236. package/widget-capabilities.js +152 -0
@@ -1,24 +1,32 @@
1
1
  /**
2
2
  * HTTP scene discovery for the 3D scene workspace.
3
3
  *
4
- * Honua publishes 3D scenes over the `geospatial.v1` `SceneService`
5
- * (`ListScenes` / `GetScene`) and mirrors that catalog over plain HTTP scene
6
- * discovery (`GET /api/scenes`, `GET /api/scenes/{id}`) alongside the static
7
- * 3D-Tiles entry point (`GET /scenes/{id}/tileset.json`). This module gives the
8
- * SDK a typed read model over that discovery surface and maps a discovered
9
- * {@link HonuaScene} onto the renderer-neutral {@link SceneRuntimePrimitive}s the
10
- * Cesium adapter renders.
4
+ * Honua Server publishes three public JSON contracts, and this module
5
+ * normalizes those rather than the proto `sceneId` / `title` / `extent` shape:
6
+ *
7
+ * - `GET /api/scenes` — list items use `id`, `name`, `tilesetUrl`, `bounds`, `auth`
8
+ * - `GET /api/scenes/{sceneId}` — metadata uses `id`, `name`, `tileset`, `center`, `bounds`, `auth`
9
+ * - `GET /api/scenes/{sceneId}/resolve` — resolution uses `sceneId`, `endpoints`, `auth`
10
+ *
11
+ * `bounds` is `{west,south,east,north}` and is remapped onto {@link SceneExtent3D}.
12
+ * `center` is `{latitude,longitude,height}` and becomes the initial camera.
13
+ * A nested metadata `tileset` object supplies the tileset URL. The flat proto
14
+ * names (`sceneId`, `scene_id`, `title`, `tileset_url`, `extent`) are still
15
+ * accepted so older payloads do not throw; callers that need the server
16
+ * contract should pass the three routes above.
17
+ *
18
+ * The runtime tileset URL comes from {@link resolveScene}. Nothing in this
19
+ * module synthesizes `/scenes/{id}/tileset.json`. An empty id fails closed
20
+ * before a request is sent, and a tileset URL whose path contains `/scenes//`
21
+ * is rejected so a missing id cannot be requested.
22
+ *
23
+ * Auth requirements are retained on the normalized scene. This module does not
24
+ * refresh protected-asset credentials; that is a separate ticket.
11
25
  *
12
26
  * Discovery calls go through a caller-supplied {@link SceneDiscoveryRequestExecutor}
13
27
  * — typically `(...args) => client.pipelineRequestJson(...args)` against a
14
28
  * `HonuaClient` — so they reuse the SDK's shared auth / retry / timeout /
15
- * interceptor pipeline rather than issuing ad-hoc `fetch` calls. Modelling the
16
- * transport as a function keeps this module free of a hard `core/client` import
17
- * (and equally usable from a Node backend, a worker, or a unit test with a mock).
18
- *
19
- * The mapping helpers ({@link sceneToRuntimePrimitives},
20
- * {@link sceneCameraPrimitive}, {@link sceneViewpointBookmarks}) are pure (no
21
- * Cesium, no transport) and unit-testable on their own.
29
+ * interceptor pipeline rather than issuing ad-hoc `fetch` calls.
22
30
  *
23
31
  * @experimental Held back from the beta `@honua/app-platform/scene-workspace`
24
32
  * tier: Honua Server scene discovery is server-attached, so it sits outside
@@ -27,107 +35,347 @@
27
35
  * are beta.
28
36
  * @module
29
37
  */
30
- import { trimTrailingSlashes } from "../core/path-utils.js";
31
38
  const SCENES_BASE_PATH = "/api/scenes";
32
- function normalizeCamera(raw) {
33
- if (!raw || raw.longitude === undefined || raw.latitude === undefined)
39
+ const EMPTY_TILESET_PATH = "/scenes//";
40
+ function asRecord(raw, message) {
41
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
42
+ throw new Error(message);
43
+ }
44
+ return raw;
45
+ }
46
+ function readText(value) {
47
+ return typeof value === "string" && value !== "" ? value : undefined;
48
+ }
49
+ function readId(value) {
50
+ if (typeof value !== "string")
34
51
  return undefined;
52
+ const trimmed = value.trim();
53
+ return trimmed === "" ? undefined : trimmed;
54
+ }
55
+ function requireSceneId(record, message) {
56
+ // `id` is the list/metadata contract. `sceneId` / `scene_id` remain only so
57
+ // proto-shaped payloads still normalize; an empty value is never substituted.
58
+ const sceneId = readId(record.id) ?? readId(record.sceneId) ?? readId(record.scene_id);
59
+ if (!sceneId)
60
+ throw new Error(message);
61
+ return sceneId;
62
+ }
63
+ function readFinite(value) {
64
+ return typeof value === "number" && Number.isFinite(value) ? value : undefined;
65
+ }
66
+ /** Reject a blank URL and the empty-id `/scenes//` path. */
67
+ function isUsableSceneResourceUrl(url) {
68
+ if (!url)
69
+ return false;
70
+ const trimmed = url.trim();
71
+ return trimmed !== "" && !trimmed.includes(EMPTY_TILESET_PATH);
72
+ }
73
+ function readStringList(value) {
74
+ if (!Array.isArray(value))
75
+ return undefined;
76
+ return value.filter((item) => typeof item === "string");
77
+ }
78
+ function readAuth(value) {
79
+ if (!value || typeof value !== "object" || Array.isArray(value))
80
+ return undefined;
81
+ const record = value;
82
+ const schemes = readStringList(record.schemes) ?? [];
83
+ const policy = readText(record.policy);
35
84
  return {
36
- longitude: raw.longitude,
37
- latitude: raw.latitude,
38
- height: raw.height ?? 0,
39
- ...(raw.heading !== undefined ? { heading: raw.heading } : {}),
40
- ...(raw.pitch !== undefined ? { pitch: raw.pitch } : {}),
41
- ...(raw.roll !== undefined ? { roll: raw.roll } : {}),
85
+ requiresAuthentication: record.requiresAuthentication === true,
86
+ schemes,
87
+ ...(policy !== undefined ? { policy } : {}),
42
88
  };
43
89
  }
44
- function normalizeExtent(raw) {
45
- if (!raw)
90
+ function readEndpoint(value) {
91
+ if (!value || typeof value !== "object" || Array.isArray(value))
92
+ return undefined;
93
+ const record = value;
94
+ const url = readText(record.url) ?? readText(record.href);
95
+ const kind = readText(record.kind) ?? readText(record.type) ?? readText(record.format);
96
+ if (!isUsableSceneResourceUrl(url) || !kind)
46
97
  return undefined;
47
- const envelope = raw.extent ?? raw;
48
- if (envelope.xmin === undefined ||
49
- envelope.ymin === undefined ||
50
- envelope.xmax === undefined ||
51
- envelope.ymax === undefined) {
98
+ const mediaType = readText(record.mediaType);
99
+ const format = readText(record.format);
100
+ return {
101
+ kind,
102
+ url: url.trim(),
103
+ ...(mediaType !== undefined ? { mediaType } : {}),
104
+ ...(format !== undefined ? { format } : {}),
105
+ requiresAuthentication: record.requiresAuthentication === true,
106
+ };
107
+ }
108
+ function readEndpoints(value) {
109
+ if (!Array.isArray(value))
110
+ return [];
111
+ return value.flatMap((item) => {
112
+ const endpoint = readEndpoint(item);
113
+ return endpoint ? [endpoint] : [];
114
+ });
115
+ }
116
+ function readLinks(value) {
117
+ if (!Array.isArray(value))
52
118
  return undefined;
119
+ const links = [];
120
+ for (const item of value) {
121
+ if (!item || typeof item !== "object" || Array.isArray(item))
122
+ continue;
123
+ const record = item;
124
+ const rel = readText(record.rel);
125
+ const href = readText(record.href);
126
+ if (!rel || !href)
127
+ continue;
128
+ const type = readText(record.type);
129
+ const title = readText(record.title);
130
+ links.push({
131
+ rel,
132
+ href,
133
+ ...(type !== undefined ? { type } : {}),
134
+ ...(title !== undefined ? { title } : {}),
135
+ });
53
136
  }
54
- const minHeight = raw.minHeight ?? raw.min_height;
55
- const maxHeight = raw.maxHeight ?? raw.max_height;
137
+ return links;
138
+ }
139
+ function readTilesetUrl(record) {
140
+ const flat = readText(record.tilesetUrl) ?? readText(record.tileset_url);
141
+ if (isUsableSceneResourceUrl(flat))
142
+ return flat.trim();
143
+ const tileset = record.tileset;
144
+ if (!tileset || typeof tileset !== "object" || Array.isArray(tileset))
145
+ return undefined;
146
+ const nested = tileset;
147
+ const url = readText(nested.url) ?? readText(nested.href);
148
+ return isUsableSceneResourceUrl(url) ? url.trim() : undefined;
149
+ }
150
+ function normalizeCamera(raw) {
151
+ if (!raw || typeof raw !== "object" || Array.isArray(raw))
152
+ return undefined;
153
+ const camera = raw;
154
+ const longitude = readFinite(camera.longitude);
155
+ const latitude = readFinite(camera.latitude);
156
+ if (longitude === undefined || latitude === undefined)
157
+ return undefined;
158
+ const height = readFinite(camera.height) ?? 0;
159
+ const heading = readFinite(camera.heading);
160
+ const pitch = readFinite(camera.pitch);
161
+ const roll = readFinite(camera.roll);
162
+ return {
163
+ longitude,
164
+ latitude,
165
+ height,
166
+ ...(heading !== undefined ? { heading } : {}),
167
+ ...(pitch !== undefined ? { pitch } : {}),
168
+ ...(roll !== undefined ? { roll } : {}),
169
+ };
170
+ }
171
+ /** Server `bounds` (`west`/`south`/`east`/`north`) onto the SDK extent axes. */
172
+ function readBounds(raw) {
173
+ if (!raw || typeof raw !== "object" || Array.isArray(raw))
174
+ return undefined;
175
+ const bounds = raw;
176
+ const xmin = readFinite(bounds.west);
177
+ const ymin = readFinite(bounds.south);
178
+ const xmax = readFinite(bounds.east);
179
+ const ymax = readFinite(bounds.north);
180
+ if (xmin === undefined || ymin === undefined || xmax === undefined || ymax === undefined)
181
+ return undefined;
182
+ return { xmin, ymin, xmax, ymax };
183
+ }
184
+ /** Proto `extent` tolerance: a flat or nested `{xmin,ymin,xmax,ymax}` envelope. */
185
+ function readProtoExtent(raw) {
186
+ if (!raw || typeof raw !== "object" || Array.isArray(raw))
187
+ return undefined;
188
+ const record = raw;
189
+ const nested = record.extent;
190
+ const envelope = nested && typeof nested === "object" && !Array.isArray(nested) ? nested : record;
191
+ const xmin = readFinite(envelope.xmin);
192
+ const ymin = readFinite(envelope.ymin);
193
+ const xmax = readFinite(envelope.xmax);
194
+ const ymax = readFinite(envelope.ymax);
195
+ if (xmin === undefined || ymin === undefined || xmax === undefined || ymax === undefined)
196
+ return undefined;
197
+ const minHeight = readFinite(record.minHeight) ?? readFinite(record.min_height);
198
+ const maxHeight = readFinite(record.maxHeight) ?? readFinite(record.max_height);
199
+ const spatialReference = readFinite(envelope.spatialReference);
56
200
  return {
57
- xmin: envelope.xmin,
58
- ymin: envelope.ymin,
59
- xmax: envelope.xmax,
60
- ymax: envelope.ymax,
201
+ xmin,
202
+ ymin,
203
+ xmax,
204
+ ymax,
61
205
  ...(minHeight !== undefined ? { minHeight } : {}),
62
206
  ...(maxHeight !== undefined ? { maxHeight } : {}),
63
- ...(envelope.spatialReference !== undefined ? { spatialReference: envelope.spatialReference } : {}),
207
+ ...(spatialReference !== undefined ? { spatialReference } : {}),
208
+ };
209
+ }
210
+ function readExtent(record) {
211
+ return readBounds(record.bounds) ?? readProtoExtent(record.extent);
212
+ }
213
+ function readInitialCamera(record) {
214
+ const explicit = normalizeCamera(record.initialCamera) ?? normalizeCamera(record.initial_camera);
215
+ if (explicit)
216
+ return explicit;
217
+ return normalizeCamera(record.center);
218
+ }
219
+ function readViewpoints(value) {
220
+ if (!Array.isArray(value))
221
+ return [];
222
+ const viewpoints = [];
223
+ for (const item of value) {
224
+ if (!item || typeof item !== "object" || Array.isArray(item))
225
+ continue;
226
+ const record = item;
227
+ const id = readId(record.id);
228
+ const camera = normalizeCamera(record.camera);
229
+ if (!id || !camera)
230
+ continue;
231
+ const title = readText(record.title) ?? id;
232
+ viewpoints.push({ id, title, camera });
233
+ }
234
+ return viewpoints;
235
+ }
236
+ function readStyleExpression(record) {
237
+ const direct = readText(record.styleExpression);
238
+ if (direct)
239
+ return direct;
240
+ const style = record.style;
241
+ if (!style || typeof style !== "object" || Array.isArray(style))
242
+ return undefined;
243
+ return readText(style.expression);
244
+ }
245
+ function readScene(record, missingIdMessage) {
246
+ const sceneId = requireSceneId(record, missingIdMessage);
247
+ const name = readText(record.name);
248
+ const title = name ?? readText(record.title);
249
+ const description = readText(record.description);
250
+ const tilesetUrl = readTilesetUrl(record);
251
+ const terrainUrl = readText(record.terrainUrl) ?? readText(record.terrain_url);
252
+ const extent = readExtent(record);
253
+ const initialCamera = readInitialCamera(record);
254
+ const styleExpression = readStyleExpression(record);
255
+ const edition = readText(record.edition);
256
+ const auth = readAuth(record.auth);
257
+ const attribution = readStringList(record.attribution);
258
+ const updatedAt = readText(record.updatedAt);
259
+ const links = readLinks(record.links);
260
+ const usableTerrain = isUsableSceneResourceUrl(terrainUrl) ? terrainUrl.trim() : undefined;
261
+ return {
262
+ sceneId,
263
+ ...(name !== undefined ? { name } : {}),
264
+ ...(title !== undefined ? { title } : {}),
265
+ ...(description !== undefined ? { description } : {}),
266
+ ...(tilesetUrl !== undefined ? { tilesetUrl } : {}),
267
+ ...(usableTerrain !== undefined ? { terrainUrl: usableTerrain } : {}),
268
+ ...(extent ? { extent } : {}),
269
+ ...(initialCamera ? { initialCamera } : {}),
270
+ viewpoints: readViewpoints(record.viewpoints),
271
+ ...(styleExpression !== undefined ? { styleExpression } : {}),
272
+ ...(edition !== undefined ? { edition } : {}),
273
+ capabilities: readStringList(record.capabilities) ?? [],
274
+ ...(auth ? { auth } : {}),
275
+ ...(attribution ? { attribution } : {}),
276
+ ...(updatedAt !== undefined ? { updatedAt } : {}),
277
+ ...(links ? { links } : {}),
64
278
  };
65
279
  }
280
+ function unwrapSceneEnvelope(raw) {
281
+ const record = asRecord(raw, "Scene response must be a JSON object.");
282
+ const nested = record.scene;
283
+ const hasOwnId = readId(record.id) ?? readId(record.sceneId) ?? readId(record.scene_id);
284
+ if (!hasOwnId && nested && typeof nested === "object" && !Array.isArray(nested)) {
285
+ return nested;
286
+ }
287
+ return record;
288
+ }
289
+ /**
290
+ * Normalize one list item from `GET /api/scenes`.
291
+ * Reads `id`, `name`, `tilesetUrl`, `bounds`, and `auth`.
292
+ */
293
+ export function normalizeSceneSummary(raw) {
294
+ return readScene(asRecord(raw, "Scene list item must be a JSON object."), "Scene list item is missing an id.");
295
+ }
66
296
  /**
67
- * Normalize a raw scene payload (camelCase or proto3-JSON snake_case) into a
68
- * {@link HonuaScene}. Exported so the normalization is unit-testable against
69
- * either wire shape without a transport.
297
+ * Normalize `GET /api/scenes/{sceneId}`.
298
+ * Reads `id`, `name`, `tileset`, `center`, `bounds`, and `auth`.
299
+ * A `{ scene }` envelope is accepted only when the root has no id of its own
300
+ * (proto-shaped responses). The server returns the metadata object itself.
301
+ */
302
+ export function normalizeSceneMetadata(raw) {
303
+ return readScene(unwrapSceneEnvelope(raw), "Scene metadata is missing an id.");
304
+ }
305
+ /**
306
+ * Normalize a scene payload. Prefer {@link normalizeSceneSummary} or
307
+ * {@link normalizeSceneMetadata} at the route boundary. This entry point
308
+ * accepts either of those contracts and the documented proto field names.
70
309
  */
71
310
  export function normalizeScene(raw) {
72
- const sceneId = raw.sceneId ?? raw.scene_id ?? "";
73
- const tilesetUrl = raw.tilesetUrl ?? raw.tileset_url;
74
- const terrainUrl = raw.terrainUrl ?? raw.terrain_url;
75
- const initialCamera = normalizeCamera(raw.initialCamera ?? raw.initial_camera);
76
- const viewpoints = (raw.viewpoints ?? [])
77
- .map((viewpoint) => {
78
- const camera = normalizeCamera(viewpoint.camera);
79
- if (!camera || !viewpoint.id)
80
- return undefined;
81
- return { id: viewpoint.id, title: viewpoint.title ?? viewpoint.id, camera };
82
- })
83
- .filter((viewpoint) => viewpoint !== undefined);
84
- const styleExpression = raw.styleExpression ?? raw.style?.expression;
311
+ return readScene(unwrapSceneEnvelope(raw), "Scene response is missing an id.");
312
+ }
313
+ function tilesetEndpointUrl(endpoints) {
314
+ const match = endpoints.find((endpoint) => endpoint.kind === "3d-tiles" || endpoint.format === "3d-tiles");
315
+ return match && isUsableSceneResourceUrl(match.url) ? match.url.trim() : undefined;
316
+ }
317
+ /**
318
+ * Normalize `GET /api/scenes/{sceneId}/resolve`.
319
+ * Reads `sceneId`, `endpoints`, and `auth`. The runtime tileset URL is the
320
+ * response `tilesetUrl` when usable, otherwise the `3d-tiles` endpoint.
321
+ */
322
+ export function normalizeSceneResolution(raw) {
323
+ const record = asRecord(raw, "Scene resolution must be a JSON object.");
324
+ const sceneId = requireSceneId(record, "Scene resolution is missing a sceneId.");
325
+ const endpoints = readEndpoints(record.endpoints);
326
+ const flat = readText(record.tilesetUrl) ?? readText(record.tileset_url);
327
+ const tilesetUrl = (isUsableSceneResourceUrl(flat) ? flat.trim() : undefined) ?? tilesetEndpointUrl(endpoints);
328
+ const auth = readAuth(record.auth) ?? { requiresAuthentication: false, schemes: [] };
85
329
  return {
86
330
  sceneId,
87
- ...(raw.title !== undefined ? { title: raw.title } : {}),
88
- ...(raw.description !== undefined ? { description: raw.description } : {}),
89
331
  ...(tilesetUrl !== undefined ? { tilesetUrl } : {}),
90
- ...(terrainUrl !== undefined ? { terrainUrl } : {}),
91
- ...(normalizeExtent(raw.extent) ? { extent: normalizeExtent(raw.extent) } : {}),
92
- ...(initialCamera ? { initialCamera } : {}),
93
- viewpoints,
94
- ...(styleExpression !== undefined ? { styleExpression } : {}),
95
- ...(raw.edition !== undefined ? { edition: raw.edition } : {}),
96
- capabilities: raw.capabilities ?? [],
332
+ endpoints,
333
+ capabilities: readStringList(record.capabilities) ?? [],
334
+ auth,
97
335
  };
98
336
  }
99
337
  /**
100
- * List the catalog of available 3D scenes from `GET /api/scenes`
101
- * (`SceneService.ListScenes`). Returns the normalized {@link HonuaScene}s.
338
+ * List the catalog of available 3D scenes from `GET /api/scenes`.
339
+ * Returns the normalized {@link HonuaScene}s. A list item with no id throws;
340
+ * it is not returned with an empty id.
102
341
  */
103
342
  export async function listScenes(execute, signal) {
104
343
  const raw = await execute("GET", SCENES_BASE_PATH, undefined, signal);
105
- return (raw.scenes ?? []).map(normalizeScene);
344
+ const record = asRecord(raw, "Scene list response must be a JSON object.");
345
+ if (!Array.isArray(record.scenes)) {
346
+ throw new Error("Scene list response must contain a scenes array.");
347
+ }
348
+ return record.scenes.map((item) => normalizeSceneSummary(item));
106
349
  }
107
350
  /**
108
- * Fetch a single scene's metadata from `GET /api/scenes/{sceneId}`
109
- * (`SceneService.GetScene`). The response is tolerated as either the bare scene
110
- * object or a `{ scene }` envelope.
351
+ * Fetch a single scene's metadata from `GET /api/scenes/{sceneId}`.
352
+ * Fails closed before the request when `sceneId` is empty.
111
353
  */
112
354
  export async function getScene(execute, sceneId, signal) {
113
- if (!sceneId)
355
+ if (typeof sceneId !== "string" || sceneId.trim() === "") {
114
356
  throw new Error("getScene requires a non-empty sceneId.");
115
- const raw = await execute("GET", `${SCENES_BASE_PATH}/${encodeURIComponent(sceneId)}`, undefined, signal);
116
- return normalizeScene(raw.scene ?? raw);
357
+ }
358
+ const raw = await execute("GET", `${SCENES_BASE_PATH}/${encodeURIComponent(sceneId.trim())}`, undefined, signal);
359
+ return normalizeSceneMetadata(raw);
117
360
  }
118
361
  /**
119
- * Resolve the static 3D-Tiles entry-point URL for a scene
120
- * (`/scenes/{sceneId}/tileset.json`). Prefers the scene's advertised
121
- * `tilesetUrl`; falls back to the conventional discovery path under `baseUrl`
122
- * when the scene omits one. Returns `undefined` when neither is available.
362
+ * Resolve a scene's runtime endpoints from `GET /api/scenes/{sceneId}/resolve`.
363
+ * Fails closed before the request when `sceneId` is empty. The returned
364
+ * `tilesetUrl` is taken from the server payload only.
123
365
  */
124
- export function resolveSceneTilesetUrl(scene, baseUrl) {
125
- if (scene.tilesetUrl && scene.tilesetUrl.trim() !== "")
126
- return scene.tilesetUrl;
127
- if (!baseUrl)
128
- return undefined;
129
- const trimmed = trimTrailingSlashes(baseUrl);
130
- return `${trimmed}/scenes/${encodeURIComponent(scene.sceneId)}/tileset.json`;
366
+ export async function resolveScene(execute, sceneId, signal) {
367
+ if (typeof sceneId !== "string" || sceneId.trim() === "") {
368
+ throw new Error("resolveScene requires a non-empty sceneId.");
369
+ }
370
+ const raw = await execute("GET", `${SCENES_BASE_PATH}/${encodeURIComponent(sceneId.trim())}/resolve`, undefined, signal);
371
+ return normalizeSceneResolution(raw);
372
+ }
373
+ /**
374
+ * The scene's advertised 3D-Tiles entry-point URL, or `undefined` when the
375
+ * scene has none. Does not synthesize a `/scenes/{id}/tileset.json` path.
376
+ */
377
+ export function resolveSceneTilesetUrl(scene) {
378
+ return isUsableSceneResourceUrl(scene.tilesetUrl) ? scene.tilesetUrl.trim() : undefined;
131
379
  }
132
380
  /**
133
381
  * Build the camera primitive for a scene's suggested initial view, or
@@ -147,8 +395,8 @@ export function sceneCameraPrimitive(scene) {
147
395
  * Build the 3D-Tiles model-layer primitive for a scene's root tileset, or
148
396
  * `undefined` when the scene has no resolvable tileset URL. Pure.
149
397
  */
150
- export function sceneTilesetPrimitive(scene, baseUrl) {
151
- const uri = resolveSceneTilesetUrl(scene, baseUrl);
398
+ export function sceneTilesetPrimitive(scene) {
399
+ const uri = resolveSceneTilesetUrl(scene);
152
400
  if (!uri)
153
401
  return undefined;
154
402
  return {
@@ -165,23 +413,23 @@ export function sceneTilesetPrimitive(scene, baseUrl) {
165
413
  * treated as a quantized-mesh endpoint (Cesium's `CesiumTerrainProvider`).
166
414
  */
167
415
  export function sceneTerrainPrimitive(scene) {
168
- if (!scene.terrainUrl || scene.terrainUrl.trim() === "")
416
+ if (!isUsableSceneResourceUrl(scene.terrainUrl))
169
417
  return undefined;
170
418
  return {
171
419
  kind: "elevation-source",
172
420
  id: `${scene.sceneId}:terrain`,
173
421
  sourceId: `${scene.sceneId}:terrain`,
174
422
  protocol: "quantized-mesh",
175
- url: scene.terrainUrl,
423
+ url: scene.terrainUrl.trim(),
176
424
  };
177
425
  }
178
426
  /**
179
427
  * Map a discovered scene onto the renderer-neutral primitives the Cesium
180
428
  * adapter renders: an initial-camera primitive, the terrain elevation source
181
- * (when present), and the 3D-Tiles tileset (when resolvable). Pure; the result
182
- * feeds straight into `applyCesiumScenePrimitives` / a `SceneView`.
429
+ * (when present), and the 3D-Tiles tileset (when the scene advertises a URL).
430
+ * Pure; the result feeds straight into `applyCesiumScenePrimitives` / a `SceneView`.
183
431
  */
184
- export function sceneToRuntimePrimitives(scene, baseUrl) {
432
+ export function sceneToRuntimePrimitives(scene) {
185
433
  const primitives = [];
186
434
  const camera = sceneCameraPrimitive(scene);
187
435
  if (camera)
@@ -189,7 +437,7 @@ export function sceneToRuntimePrimitives(scene, baseUrl) {
189
437
  const terrain = sceneTerrainPrimitive(scene);
190
438
  if (terrain)
191
439
  primitives.push(terrain);
192
- const tileset = sceneTilesetPrimitive(scene, baseUrl);
440
+ const tileset = sceneTilesetPrimitive(scene);
193
441
  if (tileset)
194
442
  primitives.push(tileset);
195
443
  return primitives;
@@ -199,9 +447,9 @@ export function sceneToRuntimePrimitives(scene, baseUrl) {
199
447
  * primitive), so a {@link module:scene-workspace/workspace.SceneWorkspace} can
200
448
  * seed its layer list from the scene. Pure.
201
449
  */
202
- export function sceneLayerStates(scene, baseUrl) {
450
+ export function sceneLayerStates(scene) {
203
451
  const layers = [];
204
- if (sceneTilesetPrimitive(scene, baseUrl)) {
452
+ if (sceneTilesetPrimitive(scene)) {
205
453
  layers.push({
206
454
  id: `${scene.sceneId}:tileset`,
207
455
  title: scene.title ?? scene.sceneId,
@@ -43,7 +43,7 @@ import type { QueryMethod } from "../core/types.js";
43
43
  import { type CesiumEntityCollectionLike, type ElevationProfileRequest, type ElevationProfileResult, type LineOfSightRequest, type LineOfSightResult, type SceneAnalysisCesiumModule, type SceneAnalysisOverlay, type SceneAnalysisPosition, type SceneMeasurement, type ViewshedRequest, type ViewshedResult } from "./analysis-widgets.js";
44
44
  import { type CesiumSceneRuntimeTarget } from "./cesium-adapter.js";
45
45
  import type { ScenePrimitiveDiagnostic } from "./primitives.js";
46
- import { type HonuaScene } from "./scene-discovery.js";
46
+ import { type HonuaScene, type HonuaSceneResolution } from "./scene-discovery.js";
47
47
  import type { SceneBookmark, SceneCameraState, SceneLayerState } from "./types.js";
48
48
  /**
49
49
  * The request transport a {@link SceneView} uses for scene discovery and
@@ -71,11 +71,6 @@ export interface SceneViewOptions {
71
71
  * rendering). Omit to load + diagnose scenes headlessly without rendering.
72
72
  */
73
73
  readonly target?: CesiumSceneRuntimeTarget;
74
- /**
75
- * Base URL used to resolve a scene's static `tileset.json` entry point when
76
- * the scene omits an explicit `tilesetUrl`. Defaults to `client.serverBaseUrl`.
77
- */
78
- readonly baseUrl?: string;
79
74
  }
80
75
  /** Events emitted by a {@link SceneView}. */
81
76
  export type SceneViewEvent = {
@@ -115,6 +110,11 @@ export declare class SceneView {
115
110
  listScenes(signal?: AbortSignal): Promise<HonuaScene[]>;
116
111
  /** Fetch a single scene's metadata without loading it (`GET /api/scenes/{id}`). */
117
112
  getScene(sceneId: string, signal?: AbortSignal): Promise<HonuaScene>;
113
+ /**
114
+ * Resolve a scene's runtime endpoints (`GET /api/scenes/{id}/resolve`).
115
+ * The tileset URL in the result is the server's. This view does not invent one.
116
+ */
117
+ resolveScene(sceneId: string, signal?: AbortSignal): Promise<HonuaSceneResolution>;
118
118
  /**
119
119
  * Load a scene by id (or a pre-fetched {@link HonuaScene}) and render it onto
120
120
  * the live target: the initial camera, terrain provider, and 3D-Tiles
@@ -1 +1 @@
1
- {"version":3,"file":"scene-view.d.ts","sourceRoot":"","sources":["../../../src/scene-workspace/scene-view.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"scene-view.d.ts","sourceRoot":"","sources":["../../../src/scene-workspace/scene-view.ts"],"names":[],"mappings":"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"}
@@ -40,7 +40,7 @@
40
40
  */
41
41
  import { measureScenePositions, renderElevationProfilePolyline, renderLineOfSight, renderMeasurement, renderViewshed, requestElevationProfile, requestLineOfSight, requestViewshed, } from "./analysis-widgets.js";
42
42
  import { applyCesiumScenePrimitives, cesiumCameraToSceneState, } from "./cesium-adapter.js";
43
- import { getScene, listScenes, sceneLayerStates, sceneToRuntimePrimitives, sceneViewpointBookmarks, } from "./scene-discovery.js";
43
+ import { getScene, listScenes, resolveScene as requestSceneResolution, sceneLayerStates, sceneToRuntimePrimitives, sceneViewpointBookmarks, } from "./scene-discovery.js";
44
44
  /**
45
45
  * First-class 3D scene container. Loads a Honua scene, renders it through the
46
46
  * Cesium adapter, and exposes the analysis/measurement widgets.
@@ -48,7 +48,6 @@ import { getScene, listScenes, sceneLayerStates, sceneToRuntimePrimitives, scene
48
48
  export class SceneView {
49
49
  #execute;
50
50
  #target;
51
- #baseUrl;
52
51
  #listeners = new Set();
53
52
  #layerHandles = new Map();
54
53
  #scene;
@@ -62,7 +61,6 @@ export class SceneView {
62
61
  }
63
62
  this.#execute = execute;
64
63
  this.#target = options.target;
65
- this.#baseUrl = options.baseUrl ?? options.client?.serverBaseUrl;
66
64
  }
67
65
  // ── Discovery ───────────────────────────────────────────────
68
66
  /** List the catalog of available 3D scenes (`GET /api/scenes`). */
@@ -73,6 +71,13 @@ export class SceneView {
73
71
  getScene(sceneId, signal) {
74
72
  return getScene(this.#discoveryExecutor(), sceneId, signal);
75
73
  }
74
+ /**
75
+ * Resolve a scene's runtime endpoints (`GET /api/scenes/{id}/resolve`).
76
+ * The tileset URL in the result is the server's. This view does not invent one.
77
+ */
78
+ resolveScene(sceneId, signal) {
79
+ return requestSceneResolution(this.#discoveryExecutor(), sceneId, signal);
80
+ }
76
81
  // ── Loading / rendering ─────────────────────────────────────
77
82
  /**
78
83
  * Load a scene by id (or a pre-fetched {@link HonuaScene}) and render it onto
@@ -82,13 +87,23 @@ export class SceneView {
82
87
  * rendered.
83
88
  */
84
89
  async loadScene(scene, signal) {
85
- const resolved = typeof scene === "string" ? await this.getScene(scene, signal) : scene;
90
+ const requestedId = typeof scene === "string" ? scene : scene.sceneId;
91
+ if (typeof requestedId !== "string" || requestedId.trim() === "") {
92
+ throw new Error("loadScene requires a non-empty sceneId.");
93
+ }
94
+ const sceneId = requestedId.trim();
95
+ const execute = this.#discoveryExecutor();
96
+ const metadata = typeof scene === "string" ? await getScene(execute, sceneId, signal) : scene;
97
+ // Resolve is the only source of the runtime tileset URL. Do not synthesize
98
+ // `/scenes/{id}/tileset.json` from the client origin when the payload omits one.
99
+ const resolution = await requestSceneResolution(execute, sceneId, signal);
100
+ const resolved = sceneWithResolvedRuntime(metadata, resolution);
86
101
  this.#teardownLayers();
87
102
  this.#scene = resolved;
88
103
  this.#bookmarks = sceneViewpointBookmarks(resolved);
89
- this.#layers = sceneLayerStates(resolved, this.#baseUrl);
104
+ this.#layers = sceneLayerStates(resolved);
90
105
  if (this.#target) {
91
- const primitives = sceneToRuntimePrimitives(resolved, this.#baseUrl);
106
+ const primitives = sceneToRuntimePrimitives(resolved);
92
107
  const result = await applyCesiumScenePrimitives(this.#target, primitives);
93
108
  this.#diagnostics = result.diagnostics;
94
109
  for (const [id, handle] of result.layers)
@@ -268,3 +283,14 @@ function bindClientExecutor(client) {
268
283
  return undefined;
269
284
  return (method, path, init, signal) => client.pipelineRequestJson(method, path, init, signal);
270
285
  }
286
+ /** Keep metadata for display, but take the runtime tileset URL only from resolve. */
287
+ function sceneWithResolvedRuntime(scene, resolution) {
288
+ const { tilesetUrl: _metadataTilesetUrl, ...rest } = scene;
289
+ return {
290
+ ...rest,
291
+ sceneId: resolution.sceneId,
292
+ capabilities: resolution.capabilities,
293
+ auth: resolution.auth,
294
+ ...(resolution.tilesetUrl ? { tilesetUrl: resolution.tilesetUrl } : {}),
295
+ };
296
+ }