@faclon-labs/app-sdk 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (183) hide show
  1. package/README.md +39 -1
  2. package/dist/IOSenseApp.js +26 -6
  3. package/dist/SignIn.js +2 -2
  4. package/dist/auth.d.ts +7 -0
  5. package/dist/auth.js +35 -1
  6. package/dist/config.d.ts +5 -0
  7. package/dist/config.js +1 -0
  8. package/dist/index.d.ts +1 -1
  9. package/dist/index.js +1 -1
  10. package/dist/map/globe.d.ts +5 -0
  11. package/dist/map/globe.js +5 -0
  12. package/dist/map/index.d.ts +21 -0
  13. package/dist/map/index.js +21 -0
  14. package/dist/map/source.d.ts +48 -0
  15. package/dist/map/source.js +73 -0
  16. package/dist/map/testing.d.ts +5 -0
  17. package/dist/map/testing.js +5 -0
  18. package/dist/session.d.ts +1 -1
  19. package/dist/session.js +1 -1
  20. package/package.json +55 -5
  21. package/vendor/SOURCE.txt +1 -0
  22. package/vendor/map-engine/cesium/camera.d.ts +10 -0
  23. package/vendor/map-engine/cesium/camera.js +25 -0
  24. package/vendor/map-engine/cesium/index.d.ts +2 -0
  25. package/vendor/map-engine/cesium/index.js +2 -0
  26. package/vendor/map-engine/cesium/renderer.d.ts +149 -0
  27. package/vendor/map-engine/cesium/renderer.js +837 -0
  28. package/vendor/map-engine/commands/index.d.ts +2 -0
  29. package/vendor/map-engine/commands/index.js +2 -0
  30. package/vendor/map-engine/commands/post-message.d.ts +32 -0
  31. package/vendor/map-engine/commands/post-message.js +77 -0
  32. package/vendor/map-engine/commands/webmcp.d.ts +17 -0
  33. package/vendor/map-engine/commands/webmcp.js +59 -0
  34. package/vendor/map-engine/core/commands.d.ts +82 -0
  35. package/vendor/map-engine/core/commands.js +46 -0
  36. package/vendor/map-engine/core/emitter.d.ts +9 -0
  37. package/vendor/map-engine/core/emitter.js +38 -0
  38. package/vendor/map-engine/core/equal.d.ts +2 -0
  39. package/vendor/map-engine/core/equal.js +28 -0
  40. package/vendor/map-engine/core/errors.d.ts +20 -0
  41. package/vendor/map-engine/core/errors.js +34 -0
  42. package/vendor/map-engine/core/geometry-family.d.ts +3 -0
  43. package/vendor/map-engine/core/geometry-family.js +13 -0
  44. package/vendor/map-engine/core/index.d.ts +4 -0
  45. package/vendor/map-engine/core/index.js +3 -0
  46. package/vendor/map-engine/core/types.d.ts +709 -0
  47. package/vendor/map-engine/core/types.js +7 -0
  48. package/vendor/map-engine/data/annotations.d.ts +3 -0
  49. package/vendor/map-engine/data/annotations.js +63 -0
  50. package/vendor/map-engine/data/contracts.d.ts +172 -0
  51. package/vendor/map-engine/data/contracts.js +12 -0
  52. package/vendor/map-engine/data/index.d.ts +4 -0
  53. package/vendor/map-engine/data/index.js +3 -0
  54. package/vendor/map-engine/data/schema.d.ts +7 -0
  55. package/vendor/map-engine/data/schema.js +40 -0
  56. package/vendor/map-engine/geofence/evaluator.d.ts +35 -0
  57. package/vendor/map-engine/geofence/evaluator.js +172 -0
  58. package/vendor/map-engine/geofence/history.d.ts +9 -0
  59. package/vendor/map-engine/geofence/history.js +19 -0
  60. package/vendor/map-engine/geofence/index.d.ts +2 -0
  61. package/vendor/map-engine/geofence/index.js +2 -0
  62. package/vendor/map-engine/index.d.ts +27 -0
  63. package/vendor/map-engine/index.js +14 -0
  64. package/vendor/map-engine/layers/index.d.ts +1 -0
  65. package/vendor/map-engine/layers/index.js +1 -0
  66. package/vendor/map-engine/layers/layers.d.ts +49 -0
  67. package/vendor/map-engine/layers/layers.js +316 -0
  68. package/vendor/map-engine/maplibre/deck-host.d.ts +105 -0
  69. package/vendor/map-engine/maplibre/deck-host.js +401 -0
  70. package/vendor/map-engine/maplibre/icons.d.ts +17 -0
  71. package/vendor/map-engine/maplibre/icons.js +65 -0
  72. package/vendor/map-engine/maplibre/index.d.ts +3 -0
  73. package/vendor/map-engine/maplibre/index.js +2 -0
  74. package/vendor/map-engine/maplibre/map-like.d.ts +56 -0
  75. package/vendor/map-engine/maplibre/map-like.js +1 -0
  76. package/vendor/map-engine/maplibre/renderer.d.ts +173 -0
  77. package/vendor/map-engine/maplibre/renderer.js +889 -0
  78. package/vendor/map-engine/maplibre/style.d.ts +84 -0
  79. package/vendor/map-engine/maplibre/style.js +493 -0
  80. package/vendor/map-engine/present/decorations.d.ts +25 -0
  81. package/vendor/map-engine/present/decorations.js +115 -0
  82. package/vendor/map-engine/present/index.d.ts +2 -0
  83. package/vendor/map-engine/present/index.js +2 -0
  84. package/vendor/map-engine/present/present.d.ts +47 -0
  85. package/vendor/map-engine/present/present.js +149 -0
  86. package/vendor/map-engine/query/index.d.ts +1 -0
  87. package/vendor/map-engine/query/index.js +1 -0
  88. package/vendor/map-engine/query/planner.d.ts +26 -0
  89. package/vendor/map-engine/query/planner.js +47 -0
  90. package/vendor/map-engine/react/MapView.d.ts +87 -0
  91. package/vendor/map-engine/react/MapView.js +270 -0
  92. package/vendor/map-engine/react/context.d.ts +39 -0
  93. package/vendor/map-engine/react/context.js +94 -0
  94. package/vendor/map-engine/react/index.d.ts +2 -0
  95. package/vendor/map-engine/react/index.js +2 -0
  96. package/vendor/map-engine/react/store.d.ts +19 -0
  97. package/vendor/map-engine/react/store.js +18 -0
  98. package/vendor/map-engine/realtime/apply.d.ts +74 -0
  99. package/vendor/map-engine/realtime/apply.js +155 -0
  100. package/vendor/map-engine/realtime/index.d.ts +1 -0
  101. package/vendor/map-engine/realtime/index.js +1 -0
  102. package/vendor/map-engine/render/index.d.ts +1 -0
  103. package/vendor/map-engine/render/index.js +1 -0
  104. package/vendor/map-engine/render/offline.d.ts +8 -0
  105. package/vendor/map-engine/render/offline.js +47 -0
  106. package/vendor/map-engine/render/renderer.d.ts +74 -0
  107. package/vendor/map-engine/render/renderer.js +1 -0
  108. package/vendor/map-engine/render/terrarium.d.ts +48 -0
  109. package/vendor/map-engine/render/terrarium.js +110 -0
  110. package/vendor/map-engine/runtime/drawing.d.ts +28 -0
  111. package/vendor/map-engine/runtime/drawing.js +58 -0
  112. package/vendor/map-engine/runtime/index.d.ts +5 -0
  113. package/vendor/map-engine/runtime/index.js +2 -0
  114. package/vendor/map-engine/runtime/offline.d.ts +24 -0
  115. package/vendor/map-engine/runtime/offline.js +37 -0
  116. package/vendor/map-engine/runtime/overlays.d.ts +25 -0
  117. package/vendor/map-engine/runtime/overlays.js +65 -0
  118. package/vendor/map-engine/runtime/runtime.d.ts +4 -0
  119. package/vendor/map-engine/runtime/runtime.js +2105 -0
  120. package/vendor/map-engine/runtime/types.d.ts +407 -0
  121. package/vendor/map-engine/runtime/types.js +1 -0
  122. package/vendor/map-engine/scene/index.d.ts +1 -0
  123. package/vendor/map-engine/scene/index.js +1 -0
  124. package/vendor/map-engine/scene/scene.d.ts +31 -0
  125. package/vendor/map-engine/scene/scene.js +216 -0
  126. package/vendor/map-engine/selection/index.d.ts +1 -0
  127. package/vendor/map-engine/selection/index.js +1 -0
  128. package/vendor/map-engine/selection/selection.d.ts +12 -0
  129. package/vendor/map-engine/selection/selection.js +28 -0
  130. package/vendor/map-engine/spatial/geojson.d.ts +15 -0
  131. package/vendor/map-engine/spatial/geojson.js +83 -0
  132. package/vendor/map-engine/spatial/geometry.d.ts +13 -0
  133. package/vendor/map-engine/spatial/geometry.js +206 -0
  134. package/vendor/map-engine/spatial/import.d.ts +27 -0
  135. package/vendor/map-engine/spatial/import.js +96 -0
  136. package/vendor/map-engine/spatial/index.d.ts +38 -0
  137. package/vendor/map-engine/spatial/index.js +37 -0
  138. package/vendor/map-engine/spatial/line-of-sight.d.ts +35 -0
  139. package/vendor/map-engine/spatial/line-of-sight.js +43 -0
  140. package/vendor/map-engine/spatial/measure.d.ts +28 -0
  141. package/vendor/map-engine/spatial/measure.js +90 -0
  142. package/vendor/map-engine/spatial/operations.d.ts +21 -0
  143. package/vendor/map-engine/spatial/operations.js +171 -0
  144. package/vendor/map-engine/spatial/query.d.ts +17 -0
  145. package/vendor/map-engine/spatial/query.js +88 -0
  146. package/vendor/map-engine/spatial/spatial-index.d.ts +24 -0
  147. package/vendor/map-engine/spatial/spatial-index.js +36 -0
  148. package/vendor/map-engine/spatial/volume-mesh.d.ts +19 -0
  149. package/vendor/map-engine/spatial/volume-mesh.js +56 -0
  150. package/vendor/map-engine/temporal/index.d.ts +3 -0
  151. package/vendor/map-engine/temporal/index.js +3 -0
  152. package/vendor/map-engine/temporal/journal.d.ts +20 -0
  153. package/vendor/map-engine/temporal/journal.js +34 -0
  154. package/vendor/map-engine/temporal/playback.d.ts +41 -0
  155. package/vendor/map-engine/temporal/playback.js +80 -0
  156. package/vendor/map-engine/temporal/tracks.d.ts +33 -0
  157. package/vendor/map-engine/temporal/tracks.js +119 -0
  158. package/vendor/map-engine/testing/annotation-store.d.ts +24 -0
  159. package/vendor/map-engine/testing/annotation-store.js +43 -0
  160. package/vendor/map-engine/testing/contracts.d.ts +41 -0
  161. package/vendor/map-engine/testing/contracts.js +328 -0
  162. package/vendor/map-engine/testing/fixtures-monitoring.d.ts +22 -0
  163. package/vendor/map-engine/testing/fixtures-monitoring.js +103 -0
  164. package/vendor/map-engine/testing/fixtures.d.ts +18 -0
  165. package/vendor/map-engine/testing/fixtures.js +28 -0
  166. package/vendor/map-engine/testing/index.d.ts +7 -0
  167. package/vendor/map-engine/testing/index.js +7 -0
  168. package/vendor/map-engine/testing/mock-ontology.d.ts +13 -0
  169. package/vendor/map-engine/testing/mock-ontology.js +24 -0
  170. package/vendor/map-engine/testing/mock-provider.d.ts +97 -0
  171. package/vendor/map-engine/testing/mock-provider.js +369 -0
  172. package/vendor/map-engine/testing/test-renderer.d.ts +72 -0
  173. package/vendor/map-engine/testing/test-renderer.js +153 -0
  174. package/vendor/map-engine/viewport/index.d.ts +1 -0
  175. package/vendor/map-engine/viewport/index.js +1 -0
  176. package/vendor/map-engine/viewport/viewport.d.ts +19 -0
  177. package/vendor/map-engine/viewport/viewport.js +102 -0
  178. package/vendor/map-provider-uns/client.d.ts +75 -0
  179. package/vendor/map-provider-uns/client.js +111 -0
  180. package/vendor/map-provider-uns/index.d.ts +2 -0
  181. package/vendor/map-provider-uns/index.js +2 -0
  182. package/vendor/map-provider-uns/provider.d.ts +131 -0
  183. package/vendor/map-provider-uns/provider.js +561 -0
@@ -0,0 +1,2 @@
1
+ export { createPostMessageBridge, connectToMap, type PostMessageBridgeOptions } from './post-message.js';
2
+ export { mapWebMcpTools, type WebMcpTool } from './webmcp.js';
@@ -0,0 +1,2 @@
1
+ export { createPostMessageBridge, connectToMap } from './post-message.js';
2
+ export { mapWebMcpTools } from './webmcp.js';
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Map commands over `postMessage` (doc 28 G6): a page that shows a map lets its host (an assistant panel, an
3
+ * iframe parent) drive it, and tells the host what happens on the map. Only listed origins are heard; every run
4
+ * is the runtime's `execute`, so it is checked whole and audited with its origin.
5
+ *
6
+ * host → map { kind: 'map-engine/command', id, version: 1, commands, origin? }
7
+ * map → host { kind: 'map-engine/result', id, result }
8
+ * map → host { kind: 'map-engine/event', event, payload } (the events the bridge forwards)
9
+ */
10
+ import { type CommandResult, type MapCommand } from '../core/commands.js';
11
+ import type { MapRuntime, MapRuntimeEvents } from '../runtime/types.js';
12
+ export interface PostMessageBridgeOptions {
13
+ /** Origins allowed to send commands and to receive events. Required: there is no "any origin". */
14
+ allowedOrigins: string[];
15
+ /** Where to listen. Default: `window`. */
16
+ listenOn?: Pick<Window, 'addEventListener' | 'removeEventListener'>;
17
+ /** Runtime events forwarded to the allowed host(s). Default: selection, proposal, annotation, command. */
18
+ forward?: Array<keyof MapRuntimeEvents>;
19
+ /** Where forwarded events go (e.g. `window.parent`). Default: the window that last sent a command. */
20
+ host?: Pick<Window, 'postMessage'>;
21
+ }
22
+ /** Starts the bridge; returns a function that stops it. */
23
+ export declare function createPostMessageBridge(runtime: MapRuntime, options: PostMessageBridgeOptions): () => void;
24
+ /** The host side: send commands to a map in another window or frame and wait for the answer. */
25
+ export declare function connectToMap(mapWindow: Pick<Window, 'postMessage'>, mapOrigin: string, options?: {
26
+ listenOn?: Pick<Window, 'addEventListener' | 'removeEventListener'>;
27
+ origin?: string;
28
+ timeoutMs?: number;
29
+ }): {
30
+ execute(commands: MapCommand | MapCommand[]): Promise<CommandResult>;
31
+ close(): void;
32
+ };
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Map commands over `postMessage` (doc 28 G6): a page that shows a map lets its host (an assistant panel, an
3
+ * iframe parent) drive it, and tells the host what happens on the map. Only listed origins are heard; every run
4
+ * is the runtime's `execute`, so it is checked whole and audited with its origin.
5
+ *
6
+ * host → map { kind: 'map-engine/command', id, version: 1, commands, origin? }
7
+ * map → host { kind: 'map-engine/result', id, result }
8
+ * map → host { kind: 'map-engine/event', event, payload } (the events the bridge forwards)
9
+ */
10
+ import { COMMAND_VERSION } from '../core/commands.js';
11
+ const isCommandMessage = (d) => typeof d === 'object' && d !== null && d.kind === 'map-engine/command';
12
+ /** Starts the bridge; returns a function that stops it. */
13
+ export function createPostMessageBridge(runtime, options) {
14
+ if (!options.allowedOrigins?.length || options.allowedOrigins.includes('*'))
15
+ throw new Error('createPostMessageBridge: list the allowed origins (no "*")');
16
+ const allowed = new Set(options.allowedOrigins);
17
+ const listener = options.listenOn ?? window;
18
+ let host = options.host ? { win: options.host, origin: options.allowedOrigins[0] } : null;
19
+ const onMessage = (event) => {
20
+ if (!allowed.has(event.origin) || !isCommandMessage(event.data))
21
+ return;
22
+ const msg = event.data;
23
+ const reply = event.source;
24
+ if (reply && !options.host)
25
+ host = { win: reply, origin: event.origin };
26
+ const answer = (result) => reply?.postMessage({ kind: 'map-engine/result', id: msg.id, result }, event.origin);
27
+ if (msg.version !== undefined && msg.version !== COMMAND_VERSION) {
28
+ answer({ ok: false, applied: 0, error: { index: -1, reason: `command version ${msg.version} is not supported (this map speaks ${COMMAND_VERSION})` } });
29
+ return;
30
+ }
31
+ const origin = `${typeof msg.origin === 'string' && msg.origin ? msg.origin : 'host'}@${event.origin}`;
32
+ runtime.execute(msg.commands, { origin }).then(answer, (e) => answer({ ok: false, applied: 0, error: { index: -1, reason: e instanceof Error ? e.message : String(e) } }));
33
+ };
34
+ listener.addEventListener('message', onMessage);
35
+ const offs = (options.forward ?? ['selection', 'proposal', 'annotation', 'command']).map((event) => runtime.on(event, (payload) => {
36
+ if (host)
37
+ host.win.postMessage({ kind: 'map-engine/event', event, payload: JSON.parse(JSON.stringify(payload ?? null)) }, host.origin);
38
+ }));
39
+ return () => {
40
+ listener.removeEventListener('message', onMessage);
41
+ for (const off of offs)
42
+ off();
43
+ };
44
+ }
45
+ /** The host side: send commands to a map in another window or frame and wait for the answer. */
46
+ export function connectToMap(mapWindow, mapOrigin, options = {}) {
47
+ const listenOn = options.listenOn ?? window;
48
+ let next = 1;
49
+ const waiting = new Map();
50
+ const onMessage = (event) => {
51
+ const d = event.data;
52
+ if (event.origin !== mapOrigin || d?.kind !== 'map-engine/result' || d.id === undefined)
53
+ return;
54
+ waiting.get(d.id)?.(d.result);
55
+ waiting.delete(d.id);
56
+ };
57
+ listenOn.addEventListener('message', onMessage);
58
+ return {
59
+ execute(commands) {
60
+ const id = next++;
61
+ return new Promise((resolve) => {
62
+ waiting.set(id, resolve);
63
+ mapWindow.postMessage({ kind: 'map-engine/command', id, version: COMMAND_VERSION, commands, ...(options.origin ? { origin: options.origin } : {}) }, mapOrigin);
64
+ setTimeout(() => {
65
+ if (!waiting.has(id))
66
+ return;
67
+ waiting.delete(id);
68
+ resolve({ ok: false, applied: 0, error: { index: -1, reason: 'the map did not answer' } });
69
+ }, options.timeoutMs ?? 10_000);
70
+ });
71
+ },
72
+ close() {
73
+ listenOn.removeEventListener('message', onMessage);
74
+ waiting.clear();
75
+ },
76
+ };
77
+ }
@@ -0,0 +1,17 @@
1
+ import type { MapRuntime } from '../runtime/types.js';
2
+ export interface WebMcpTool {
3
+ name: string;
4
+ description: string;
5
+ inputSchema: Record<string, unknown>;
6
+ execute: (input: Record<string, unknown>) => Promise<{
7
+ content: Array<{
8
+ type: 'text';
9
+ text: string;
10
+ }>;
11
+ }>;
12
+ }
13
+ /** The map's tools for an agent: read the map, find objects on it, run commands. */
14
+ export declare function mapWebMcpTools(runtime: MapRuntime, options?: {
15
+ origin?: string;
16
+ prefix?: string;
17
+ }): WebMcpTool[];
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Map commands as WebMCP tools (doc 28 G6): an agent in the browser reads the map and drives it with the same
3
+ * command set, through `execute` — checked whole and audited with its origin. The application registers them
4
+ * (`document.modelContext.registerTool(tool)`); the engine only builds them.
5
+ */
6
+ import { COMMAND_TYPES } from '../core/commands.js';
7
+ const text = (value) => ({ content: [{ type: 'text', text: JSON.stringify(value) }] });
8
+ const label = (p, id) => String(p?.label ?? p?.name ?? id);
9
+ /** The map's tools for an agent: read the map, find objects on it, run commands. */
10
+ export function mapWebMcpTools(runtime, options = {}) {
11
+ const origin = options.origin ?? 'agent:webmcp';
12
+ const n = (name) => `${options.prefix ?? 'map_'}${name}`;
13
+ return [
14
+ {
15
+ name: n('read'),
16
+ description: 'Read the map: camera, layers (id, kind, visible, status), selection, time (live or replay), highlight and open proposals. Call this first.',
17
+ inputSchema: { type: 'object', properties: {} },
18
+ async execute() {
19
+ const v = runtime.getViewport();
20
+ return text({
21
+ viewport: { center: v.center, zoom: v.zoom, bounds: v.bounds },
22
+ layers: runtime.getLayers().map((l) => ({ id: l.id, kind: l.visualization.type, visible: l.visible, type: l.source.ontologyType, status: runtime.getLayerStatus(l.id) })),
23
+ selection: runtime.getSelection().objectIds,
24
+ time: runtime.getTime(),
25
+ highlight: runtime.getHighlight(),
26
+ proposals: runtime.getProposals().map((p) => ({ id: p.id, label: p.label, origin: p.origin })),
27
+ });
28
+ },
29
+ },
30
+ {
31
+ name: n('find'),
32
+ description: 'Find objects loaded on the map, by type and/or property conditions (op: eq, neq, gt, gte, lt, lte, between, in, exists). Returns ids, labels and positions (at most 50).',
33
+ inputSchema: {
34
+ type: 'object',
35
+ properties: {
36
+ ontologyType: { type: 'string' },
37
+ where: { type: 'array', items: { type: 'object', properties: { property: { type: 'string' }, op: { type: 'string' }, value: {} }, required: ['property', 'op'] } },
38
+ },
39
+ },
40
+ async execute(input) {
41
+ const where = Array.isArray(input.where) ? input.where : undefined;
42
+ const found = runtime.queryLoaded({ ...(typeof input.ontologyType === 'string' ? { ontologyType: input.ontologyType } : {}), ...(where ? { where } : {}) });
43
+ return text(found.slice(0, 50).map((o) => ({ id: o.objectId, label: label(o.properties, o.objectId), geometry: o.geometry.type === 'Point' ? o.geometry.coordinates : o.geometry.type })));
44
+ },
45
+ },
46
+ {
47
+ name: n('command'),
48
+ description: `Run map commands as one unit: all are checked first, then applied in order, or none. Types: ${COMMAND_TYPES.join(', ')}. Example: [{"type":"flyTo","objectId":"x"},{"type":"highlight","objectIds":["x"],"durationMs":8000}]. drawProposal suggests a geometry a person must accept.`,
49
+ inputSchema: {
50
+ type: 'object',
51
+ properties: { commands: { type: 'array', items: { type: 'object', properties: { type: { type: 'string', enum: [...COMMAND_TYPES] } }, required: ['type'] } } },
52
+ required: ['commands'],
53
+ },
54
+ async execute(input) {
55
+ return text(await runtime.execute((input.commands ?? []), { origin }));
56
+ },
57
+ },
58
+ ];
59
+ }
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Map commands (doc 28 G6): one versioned, declarative set that an agent, an iframe host or any part of an app can
3
+ * send. Each command maps onto a runtime method — the command set adds no behaviour of its own. A list of commands is
4
+ * checked as a whole before anything runs: an unknown or invalid command refuses the whole list, never half of it.
5
+ */
6
+ import type { BoundingBox, Geometry, Position, PropertyCondition } from './types.js';
7
+ export declare const COMMAND_VERSION = 1;
8
+ export type MapCommand = {
9
+ type: 'showLayer';
10
+ layerId: string;
11
+ } | {
12
+ type: 'hideLayer';
13
+ layerId: string;
14
+ }
15
+ /** Narrows what a layer loads; `where: []` clears the filter. */
16
+ | {
17
+ type: 'setFilter';
18
+ layerId: string;
19
+ where: PropertyCondition[];
20
+ } | {
21
+ type: 'flyTo';
22
+ objectId?: string;
23
+ position?: Position;
24
+ zoom?: number;
25
+ } | {
26
+ type: 'fitTo';
27
+ bounds?: BoundingBox;
28
+ objectIds?: string[];
29
+ } | {
30
+ type: 'select';
31
+ objectIds: string[];
32
+ } | {
33
+ type: 'clearSelection';
34
+ } | {
35
+ type: 'highlight';
36
+ objectIds: string[];
37
+ durationMs?: number;
38
+ color?: string;
39
+ } | {
40
+ type: 'clearHighlight';
41
+ }
42
+ /** Asks the application to open its details view for an object (the engine has no inspector of its own). */
43
+ | {
44
+ type: 'openInspector';
45
+ objectId: string;
46
+ }
47
+ /** `at` ISO 8601, or 'live'. */
48
+ | {
49
+ type: 'setTime';
50
+ at: string;
51
+ }
52
+ /** Asks the application's timeline to play or pause (the application owns time, ADR-010). */
53
+ | {
54
+ type: 'play';
55
+ speed?: number;
56
+ } | {
57
+ type: 'pause';
58
+ } | {
59
+ type: 'drawProposal';
60
+ geometry: Geometry;
61
+ label?: string;
62
+ note?: string;
63
+ id?: string;
64
+ } | {
65
+ type: 'clearProposals';
66
+ };
67
+ export type MapCommandType = MapCommand['type'];
68
+ export interface CommandResult {
69
+ ok: boolean;
70
+ /** How many commands ran (all of them, or none). */
71
+ applied: number;
72
+ /** Why the list was refused: the index and reason of the first bad command. */
73
+ error?: {
74
+ index: number;
75
+ reason: string;
76
+ };
77
+ /** Values some commands return (e.g. the id of a drawn proposal), by index. */
78
+ results?: Record<number, unknown>;
79
+ }
80
+ export declare const COMMAND_TYPES: readonly ("showLayer" | "hideLayer" | "setFilter" | "flyTo" | "fitTo" | "select" | "clearSelection" | "highlight" | "clearHighlight" | "openInspector" | "setTime" | "play" | "pause" | "drawProposal" | "clearProposals")[];
81
+ /** Shape checks of one command (references to layers and objects are checked by the runtime). Null when fine. */
82
+ export declare function commandProblem(c: unknown): string | null;
@@ -0,0 +1,46 @@
1
+ export const COMMAND_VERSION = 1;
2
+ const TYPES = ['showLayer', 'hideLayer', 'setFilter', 'flyTo', 'fitTo', 'select', 'clearSelection', 'highlight', 'clearHighlight', 'openInspector', 'setTime', 'play', 'pause', 'drawProposal', 'clearProposals'];
3
+ export const COMMAND_TYPES = TYPES;
4
+ const str = (v) => typeof v === 'string' && v !== '';
5
+ const ids = (v) => Array.isArray(v) && v.length > 0 && v.every(str);
6
+ const isPos = (p) => {
7
+ const q = p;
8
+ return !!q && typeof q.latitude === 'number' && typeof q.longitude === 'number' && Math.abs(q.latitude) <= 90 && Math.abs(q.longitude) <= 180;
9
+ };
10
+ /** Shape checks of one command (references to layers and objects are checked by the runtime). Null when fine. */
11
+ export function commandProblem(c) {
12
+ if (typeof c !== 'object' || c === null)
13
+ return 'a command must be an object';
14
+ const cmd = c;
15
+ if (!TYPES.includes(cmd.type))
16
+ return `unknown command type "${String(cmd.type)}" (known: ${TYPES.join(', ')})`;
17
+ switch (cmd.type) {
18
+ case 'showLayer':
19
+ case 'hideLayer':
20
+ return str(cmd.layerId) ? null : 'layerId is required';
21
+ case 'setFilter':
22
+ return !str(cmd.layerId) ? 'layerId is required' : Array.isArray(cmd.where) ? null : 'where must be an array of conditions';
23
+ case 'flyTo':
24
+ if (!str(cmd.objectId) && !isPos(cmd.position))
25
+ return 'flyTo needs an objectId or a position';
26
+ return cmd.zoom === undefined || (typeof cmd.zoom === 'number' && cmd.zoom >= 0 && cmd.zoom <= 24) ? null : 'zoom must be within [0, 24]';
27
+ case 'fitTo':
28
+ return ids(cmd.objectIds) || (typeof cmd.bounds === 'object' && cmd.bounds !== null) ? null : 'fitTo needs bounds or objectIds';
29
+ case 'select':
30
+ return Array.isArray(cmd.objectIds) && cmd.objectIds.every(str) ? null : 'objectIds must be an array of ids';
31
+ case 'highlight':
32
+ if (!ids(cmd.objectIds))
33
+ return 'objectIds must be a non-empty array of ids';
34
+ return cmd.durationMs === undefined || (typeof cmd.durationMs === 'number' && cmd.durationMs > 0) ? null : 'durationMs must be > 0';
35
+ case 'openInspector':
36
+ return str(cmd.objectId) ? null : 'objectId is required';
37
+ case 'setTime':
38
+ return cmd.at === 'live' || (str(cmd.at) && Number.isFinite(Date.parse(String(cmd.at)))) ? null : 'at must be an ISO 8601 time or "live"';
39
+ case 'play':
40
+ return cmd.speed === undefined || (typeof cmd.speed === 'number' && cmd.speed > 0) ? null : 'speed must be > 0';
41
+ case 'drawProposal':
42
+ return typeof cmd.geometry === 'object' && cmd.geometry !== null ? null : 'geometry is required';
43
+ default:
44
+ return null;
45
+ }
46
+ }
@@ -0,0 +1,9 @@
1
+ import type { Unsubscribe } from './types.js';
2
+ /** A small typed event emitter. One listener throwing does not stop the others. */
3
+ export declare class Emitter<Events extends Record<string, unknown>> {
4
+ private readonly listeners;
5
+ on<K extends keyof Events>(event: K, listener: (payload: Events[K]) => void): Unsubscribe;
6
+ emit<K extends keyof Events>(event: K, payload: Events[K]): void;
7
+ clear(): void;
8
+ listenerCount(event: keyof Events): number;
9
+ }
@@ -0,0 +1,38 @@
1
+ /** A small typed event emitter. One listener throwing does not stop the others. */
2
+ export class Emitter {
3
+ listeners = new Map();
4
+ on(event, listener) {
5
+ let set = this.listeners.get(event);
6
+ if (!set) {
7
+ set = new Set();
8
+ this.listeners.set(event, set);
9
+ }
10
+ const fn = listener;
11
+ set.add(fn);
12
+ return () => {
13
+ set.delete(fn);
14
+ };
15
+ }
16
+ emit(event, payload) {
17
+ const set = this.listeners.get(event);
18
+ if (!set)
19
+ return;
20
+ for (const fn of [...set]) {
21
+ try {
22
+ fn(payload);
23
+ }
24
+ catch (error) {
25
+ // A faulty listener must not break the runtime or other listeners.
26
+ queueMicrotask(() => {
27
+ throw error;
28
+ });
29
+ }
30
+ }
31
+ }
32
+ clear() {
33
+ this.listeners.clear();
34
+ }
35
+ listenerCount(event) {
36
+ return this.listeners.get(event)?.size ?? 0;
37
+ }
38
+ }
@@ -0,0 +1,2 @@
1
+ /** Structural equality for plain data (objects, arrays, primitives). Used to keep scene patches minimal. */
2
+ export declare function deepEqual(a: unknown, b: unknown): boolean;
@@ -0,0 +1,28 @@
1
+ /** Structural equality for plain data (objects, arrays, primitives). Used to keep scene patches minimal. */
2
+ export function deepEqual(a, b) {
3
+ if (Object.is(a, b))
4
+ return true;
5
+ if (typeof a !== 'object' || typeof b !== 'object' || a === null || b === null)
6
+ return false;
7
+ if (Array.isArray(a)) {
8
+ if (!Array.isArray(b) || a.length !== b.length)
9
+ return false;
10
+ for (let i = 0; i < a.length; i++)
11
+ if (!deepEqual(a[i], b[i]))
12
+ return false;
13
+ return true;
14
+ }
15
+ if (Array.isArray(b))
16
+ return false;
17
+ const ka = Object.keys(a);
18
+ const kb = Object.keys(b);
19
+ if (ka.length !== kb.length)
20
+ return false;
21
+ for (const k of ka) {
22
+ if (!Object.prototype.hasOwnProperty.call(b, k))
23
+ return false;
24
+ if (!deepEqual(a[k], b[k]))
25
+ return false;
26
+ }
27
+ return true;
28
+ }
@@ -0,0 +1,20 @@
1
+ export type MapEngineErrorCode = 'INVALID_GEOMETRY' | 'INVALID_VIEWPORT' | 'INVALID_LAYER' | 'INVALID_GEOFENCE' | 'DUPLICATE_LAYER' | 'UNKNOWN_LAYER' | 'PROVIDER_ERROR' | 'RENDERER_ERROR' | 'MISSING_CAPABILITY'
2
+ /** A source stamped data ahead of this clock (doc 14 freshness): it is shown, but its time is not trusted for ordering. */
3
+ | 'CLOCK_SKEW'
4
+ /** The provider refused data for this user (doc 28 G13): shown as a "no access" state, not as a failure. */
5
+ | 'ACCESS_DENIED'
6
+ /** A URL that leaves the site in an offline profile (doc 28 G14). */
7
+ | 'OFFLINE_VIOLATION'
8
+ /** A map command was refused (unknown, invalid or not allowed); nothing of it was applied (doc 28 G6). */
9
+ | 'INVALID_COMMAND' | 'NOT_MOUNTED' | 'ALREADY_MOUNTED' | 'DESTROYED';
10
+ /** Which part of the system an error comes from (doc §63): data, configuration, geometry, renderer, lifecycle. */
11
+ export type MapEngineErrorSource = 'geometry' | 'config' | 'provider' | 'data' | 'renderer' | 'lifecycle';
12
+ export declare class MapEngineError extends Error {
13
+ readonly code: MapEngineErrorCode;
14
+ readonly source: MapEngineErrorSource;
15
+ readonly details?: Record<string, unknown>;
16
+ constructor(code: MapEngineErrorCode, message: string, details?: Record<string, unknown>, options?: {
17
+ cause?: unknown;
18
+ });
19
+ }
20
+ export declare function isAbortError(error: unknown): boolean;
@@ -0,0 +1,34 @@
1
+ const SOURCE = {
2
+ INVALID_GEOMETRY: 'geometry',
3
+ INVALID_VIEWPORT: 'config',
4
+ INVALID_LAYER: 'config',
5
+ INVALID_GEOFENCE: 'config',
6
+ DUPLICATE_LAYER: 'config',
7
+ UNKNOWN_LAYER: 'config',
8
+ PROVIDER_ERROR: 'provider',
9
+ MISSING_CAPABILITY: 'data',
10
+ CLOCK_SKEW: 'data',
11
+ ACCESS_DENIED: 'provider',
12
+ OFFLINE_VIOLATION: 'config',
13
+ INVALID_COMMAND: 'config',
14
+ RENDERER_ERROR: 'renderer',
15
+ NOT_MOUNTED: 'lifecycle',
16
+ ALREADY_MOUNTED: 'lifecycle',
17
+ DESTROYED: 'lifecycle',
18
+ };
19
+ export class MapEngineError extends Error {
20
+ code;
21
+ source;
22
+ details;
23
+ constructor(code, message, details, options) {
24
+ super(message, options);
25
+ this.name = 'MapEngineError';
26
+ this.code = code;
27
+ this.source = SOURCE[code];
28
+ if (details)
29
+ this.details = details;
30
+ }
31
+ }
32
+ export function isAbortError(error) {
33
+ return typeof error === 'object' && error !== null && error.name === 'AbortError';
34
+ }
@@ -0,0 +1,3 @@
1
+ import type { GeometryFamily, GeometryType } from './types.js';
2
+ /** Point, line or area: what a layer of that kind can draw. A MultiPoint is drawn by a marker layer, and so on. */
3
+ export declare function geometryFamily(type: GeometryType): GeometryFamily;
@@ -0,0 +1,13 @@
1
+ const FAMILY = {
2
+ Point: 'point',
3
+ MultiPoint: 'point',
4
+ LineString: 'line',
5
+ MultiLineString: 'line',
6
+ Polygon: 'area',
7
+ MultiPolygon: 'area',
8
+ Circle: 'area',
9
+ };
10
+ /** Point, line or area: what a layer of that kind can draw. A MultiPoint is drawn by a marker layer, and so on. */
11
+ export function geometryFamily(type) {
12
+ return FAMILY[type];
13
+ }
@@ -0,0 +1,4 @@
1
+ export type * from './types.js';
2
+ export { MapEngineError, isAbortError, type MapEngineErrorCode } from './errors.js';
3
+ export { Emitter } from './emitter.js';
4
+ export { deepEqual } from './equal.js';
@@ -0,0 +1,3 @@
1
+ export { MapEngineError, isAbortError } from './errors.js';
2
+ export { Emitter } from './emitter.js';
3
+ export { deepEqual } from './equal.js';