@multisetai/vps 1.0.6 → 1.0.7-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +84 -10
- package/dist/core/index.d.ts +34 -3
- package/dist/core/index.js +46 -11
- package/dist/core/index.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +224 -76
- package/dist/index.js.map +1 -1
- package/dist/webxr/index.d.ts +13 -0
- package/dist/webxr/index.js +179 -66
- package/dist/webxr/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -24,11 +24,13 @@ npm install @multisetai/vps three
|
|
|
24
24
|
|
|
25
25
|
### Runtime Requirements
|
|
26
26
|
|
|
27
|
-
- **HTTPS**: WebXR requires a secure context. Use HTTPS in production or `
|
|
28
|
-
- **WebXR-capable device**: Android device with ARCore
|
|
29
|
-
- **Modern browser**: Chrome
|
|
27
|
+
- **HTTPS**: WebXR requires a secure context. Use HTTPS in production or `http://localhost` for local development.
|
|
28
|
+
- **WebXR-capable device**: Android device with ARCore
|
|
29
|
+
- **Modern browser**: Chrome or Edge on Android
|
|
30
30
|
- **Three.js**: Version 0.176.0 or higher (peer dependency)
|
|
31
31
|
|
|
32
|
+
> **iOS is not supported.** This SDK requires the `camera-access` WebXR feature to capture frames for localization. Safari on iOS does not implement `camera-access`, so the AR session will fail to start on any iOS browser.
|
|
33
|
+
|
|
32
34
|
### Development Requirements
|
|
33
35
|
|
|
34
36
|
- Node.js 16+ and npm
|
|
@@ -55,7 +57,7 @@ Since this SDK makes direct API calls to MultiSet servers from browser-based app
|
|
|
55
57
|
Add entries for both your local development and production environments:
|
|
56
58
|
|
|
57
59
|
**Local Development:**
|
|
58
|
-
- **Format:** `
|
|
60
|
+
- **Format:** `https://localhost:PORT` (e.g., `https://localhost:3000`, `https://localhost:5173`)
|
|
59
61
|
- **Note:** Use the exact port your development server runs on
|
|
60
62
|
|
|
61
63
|
**Production:**
|
|
@@ -81,7 +83,7 @@ import { WebxrController } from '@multisetai/vps/webxr';
|
|
|
81
83
|
const client = new MultisetClient({
|
|
82
84
|
clientId: 'CLIENT_ID',
|
|
83
85
|
clientSecret: 'CLIENT_SECRET',
|
|
84
|
-
code: '
|
|
86
|
+
code: 'MAP_OR_MAPSET_CODE',
|
|
85
87
|
mapType: 'map', // or 'map-set'
|
|
86
88
|
endpoints: DEFAULT_ENDPOINTS,
|
|
87
89
|
onAuthorize: (token) => console.log('Authorized:', token),
|
|
@@ -131,11 +133,42 @@ new MultisetClient(config: IMultisetSdkConfig)
|
|
|
131
133
|
|
|
132
134
|
```typescript
|
|
133
135
|
interface IMultisetSdkConfig {
|
|
136
|
+
// Core
|
|
134
137
|
clientId: string; // Your MultiSet client ID
|
|
135
138
|
clientSecret: string; // Your MultiSet client secret
|
|
136
|
-
code: string; // Map code (e.g., 'MAP_XXXXX')
|
|
139
|
+
code: string; // Map or map-set code (e.g., 'MAP_XXXXX')
|
|
137
140
|
mapType: 'map' | 'map-set'; // Type of map to use
|
|
138
141
|
endpoints?: Partial<IMultisetSdkEndpoints>; // Optional custom endpoints
|
|
142
|
+
mapId?: string; // Optional map ID (overrides code-based lookup)
|
|
143
|
+
mapSetId?: string; // Optional map-set ID (overrides code-based lookup)
|
|
144
|
+
|
|
145
|
+
// Localization behavior
|
|
146
|
+
/** If true, automatically start a localization run when the AR session starts. */
|
|
147
|
+
autoLocalize?: boolean;
|
|
148
|
+
/** If true, automatically re-localize when tracking is lost and then recovered. */
|
|
149
|
+
relocalization?: boolean;
|
|
150
|
+
/** When enabled, only accept a localization result if confidence >= confidenceThreshold. */
|
|
151
|
+
confidenceCheck?: boolean;
|
|
152
|
+
/** Minimum confidence (0.2–0.8) required when confidenceCheck is enabled. */
|
|
153
|
+
confidenceThreshold?: number;
|
|
154
|
+
/** Total single-frame attempts per localization run (1–5). */
|
|
155
|
+
requestAttempts?: number;
|
|
156
|
+
/** Time in seconds between attempts in a localization run (1–5). */
|
|
157
|
+
localizationInterval?: number;
|
|
158
|
+
/** Include device geo pose as a hint in localization requests. */
|
|
159
|
+
passGeoPose?: boolean;
|
|
160
|
+
/** Request geo coordinates in the localization response (if supported by backend). */
|
|
161
|
+
geoCoordinatesInResponse?: boolean;
|
|
162
|
+
|
|
163
|
+
// Localization lifecycle callbacks
|
|
164
|
+
/** Invoked at the start of a localization run. */
|
|
165
|
+
onLocalizationInit?: () => void;
|
|
166
|
+
/** Invoked after a successful localization that meets confidence criteria (if enabled). */
|
|
167
|
+
onLocalizationSuccess?: (result: ILocalizeAndMapDetails) => void;
|
|
168
|
+
/** Invoked when all attempts fail or the best result is below the confidence threshold. */
|
|
169
|
+
onLocalizationFailure?: (reason?: string) => void;
|
|
170
|
+
|
|
171
|
+
// Core callbacks
|
|
139
172
|
onAuthorize?: (token: string) => void;
|
|
140
173
|
onFrameCaptured?: (payload: IFrameCaptureEvent) => void;
|
|
141
174
|
onCameraIntrinsics?: (intrinsics: ICameraIntrinsicsEvent) => void;
|
|
@@ -156,15 +189,28 @@ const token = await client.authorize();
|
|
|
156
189
|
|
|
157
190
|
**Returns**: The access token as a string.
|
|
158
191
|
|
|
159
|
-
#### Events
|
|
192
|
+
#### Events and callbacks
|
|
160
193
|
|
|
161
|
-
The client
|
|
194
|
+
The client and controller emit events through callback functions:
|
|
162
195
|
|
|
163
196
|
- **`onAuthorize`**: Called when authorization succeeds with the access token
|
|
164
197
|
- **`onFrameCaptured`**: Called when a camera frame is captured for localization
|
|
165
198
|
- **`onCameraIntrinsics`**: Called with camera intrinsic parameters
|
|
166
199
|
- **`onPoseResult`**: Called with localization results (pose found/not found)
|
|
167
|
-
- **`
|
|
200
|
+
- **`onLocalizationInit`**: Called at the start of a localization run
|
|
201
|
+
- **`onLocalizationSuccess`**: Called when a localization run succeeds (optionally after confidence checks)
|
|
202
|
+
- **`onLocalizationFailure`**: Called when a localization run fails or the best result is below the confidence threshold
|
|
203
|
+
- **`onError`**: Called when any error occurs during authorization or localization
|
|
204
|
+
|
|
205
|
+
### Advanced localization behavior
|
|
206
|
+
|
|
207
|
+
`MultisetClient` together with `WebxrController` supports a higher-level localization flow similar to the Unity SingleFrameLocalizationManager:
|
|
208
|
+
|
|
209
|
+
- **Multiple attempts per run**: `requestAttempts` and `localizationInterval` control how many single-frame attempts are made and how long to wait between them.
|
|
210
|
+
- **Confidence-based acceptance**: When `confidenceCheck` is `true`, only results with `confidence >= confidenceThreshold` (0.2–0.8) are treated as successful.
|
|
211
|
+
- **Auto-localize**: When `autoLocalize` is `true`, a localization run is started automatically when the AR session starts.
|
|
212
|
+
- **Re-localize on tracking loss**: When `relocalization` is `true`, the controller automatically tries to re-localize after tracking has been lost for a short period.
|
|
213
|
+
- **Geo hint**: When `passGeoPose` is `true`, the SDK uses the browser Geolocation API to compute a `geoHint` string `"lat,lon,alt"` and sends it with the localization request. When `geoCoordinatesInResponse` is `true`, the backend may include geo coordinates in the response (if supported).
|
|
168
214
|
|
|
169
215
|
## WebXR Controller API
|
|
170
216
|
|
|
@@ -216,7 +262,26 @@ if (result?.localizeData?.poseFound) {
|
|
|
216
262
|
}
|
|
217
263
|
```
|
|
218
264
|
|
|
219
|
-
**Returns**: Object with `localizeData` and optional `mapDetails`, or `null` if capture fails.
|
|
265
|
+
**Returns**: Object with `localizeData` and optional `mapDetails`, or `null` if no pose is found or capture fails.
|
|
266
|
+
|
|
267
|
+
##### `localizeFrame(): Promise<ILocalizeAndMapDetails | null>`
|
|
268
|
+
|
|
269
|
+
Runs a full localization cycle using the configured `requestAttempts`, `localizationInterval`,
|
|
270
|
+
`confidenceCheck`, and `confidenceThreshold`:
|
|
271
|
+
|
|
272
|
+
```typescript
|
|
273
|
+
const result = await controller.localizeFrame();
|
|
274
|
+
if (result?.localizeData?.poseFound) {
|
|
275
|
+
console.log('Localized at:', result.localizeData.position);
|
|
276
|
+
}
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
This method:
|
|
280
|
+
|
|
281
|
+
- Fires `onLocalizationInit` at the start of the run
|
|
282
|
+
- Performs multiple attempts and picks the best result by confidence
|
|
283
|
+
- Applies the confidence threshold when `confidenceCheck` is enabled
|
|
284
|
+
- Calls `onLocalizationSuccess` or `onLocalizationFailure` accordingly
|
|
220
285
|
|
|
221
286
|
##### `getScene(): THREE.Scene`
|
|
222
287
|
|
|
@@ -308,6 +373,15 @@ const client = new MultisetClient({
|
|
|
308
373
|
code: 'MAP_OR_MAPSET_CODE',
|
|
309
374
|
mapType: 'map',
|
|
310
375
|
endpoints: DEFAULT_ENDPOINTS,
|
|
376
|
+
// Optional advanced behavior
|
|
377
|
+
autoLocalize: true,
|
|
378
|
+
relocalization: true,
|
|
379
|
+
confidenceCheck: true,
|
|
380
|
+
confidenceThreshold: 0.5,
|
|
381
|
+
requestAttempts: 3,
|
|
382
|
+
localizationInterval: 2,
|
|
383
|
+
passGeoPose: true,
|
|
384
|
+
geoCoordinatesInResponse: true,
|
|
311
385
|
onAuthorize: (token) => console.log('Authorized:', token),
|
|
312
386
|
onError: (error) => console.error('Error:', error),
|
|
313
387
|
});
|
package/dist/core/index.d.ts
CHANGED
|
@@ -128,15 +128,46 @@ interface ILocalizeAndMapDetails {
|
|
|
128
128
|
}
|
|
129
129
|
|
|
130
130
|
interface IMultisetSdkConfig {
|
|
131
|
+
mapId?: string;
|
|
132
|
+
mapSetId?: string;
|
|
131
133
|
clientId: string;
|
|
132
134
|
clientSecret: string;
|
|
135
|
+
/** Map or map-set code used for localization. */
|
|
133
136
|
code: string;
|
|
137
|
+
/** Map or map-set type ('map' or 'map-set'). */
|
|
134
138
|
mapType: MapType;
|
|
135
139
|
endpoints?: Partial<IMultisetSdkEndpoints>;
|
|
140
|
+
/** If true, automatically start a localization run when the AR session starts. */
|
|
141
|
+
autoLocalize?: boolean;
|
|
142
|
+
/** If true, automatically re-localize when tracking is lost and then recovered. */
|
|
143
|
+
relocalization?: boolean;
|
|
144
|
+
/** When enabled, only accept a localization result if confidence >= confidenceThreshold. */
|
|
145
|
+
confidenceCheck?: boolean;
|
|
146
|
+
/** Minimum confidence (0.2–0.8) required when confidenceCheck is enabled. */
|
|
147
|
+
confidenceThreshold?: number;
|
|
148
|
+
/** Total single-frame attempts per localization run (1–5). */
|
|
149
|
+
requestAttempts?: number;
|
|
150
|
+
/** Time in seconds between attempts in a localization run (1–5). */
|
|
151
|
+
localizationInterval?: number;
|
|
152
|
+
/** Include device geo pose as a hint in localization requests. */
|
|
153
|
+
passGeoPose?: boolean;
|
|
154
|
+
/** Request geo coordinates in the localization response (if supported by backend). */
|
|
155
|
+
geoCoordinatesInResponse?: boolean;
|
|
156
|
+
/** Invoked at the start of a localization run. */
|
|
157
|
+
onLocalizationInit?: () => void;
|
|
158
|
+
/** Invoked after a successful localization that meets confidence criteria (if enabled). */
|
|
159
|
+
onLocalizationSuccess?: (result: ILocalizeAndMapDetails) => void;
|
|
160
|
+
/** Invoked when all attempts fail or the best result is below the confidence threshold. */
|
|
161
|
+
onLocalizationFailure?: (reason?: string) => void;
|
|
162
|
+
/** Called after a successful authorization with the access token. */
|
|
136
163
|
onAuthorize?: (token: string) => void;
|
|
164
|
+
/** Called whenever a camera frame is captured and sent for localization. */
|
|
137
165
|
onFrameCaptured?: (payload: IFrameCaptureEvent) => void;
|
|
166
|
+
/** Called with the camera intrinsics used for a localization request. */
|
|
138
167
|
onCameraIntrinsics?: (intrinsics: ICameraIntrinsicsEvent) => void;
|
|
168
|
+
/** Called with the raw pose/localization result returned by the backend. */
|
|
139
169
|
onPoseResult?: (payload: IPoseResultEvent) => void;
|
|
170
|
+
/** Called when any error occurs during authorization or localization. */
|
|
140
171
|
onError?: (error: unknown) => void;
|
|
141
172
|
}
|
|
142
173
|
interface IMultisetSdkEndpoints {
|
|
@@ -181,18 +212,18 @@ interface ILocalizeResultEvent {
|
|
|
181
212
|
response: ILocalizeAndMapDetails | null;
|
|
182
213
|
}
|
|
183
214
|
declare const DEFAULT_ENDPOINTS: IMultisetSdkEndpoints;
|
|
184
|
-
|
|
185
|
-
* Placeholder class to be implemented by porting logic from multiset-webxr-sdk.
|
|
186
|
-
*/
|
|
215
|
+
|
|
187
216
|
declare class MultisetClient {
|
|
188
217
|
private readonly config;
|
|
189
218
|
private readonly endpoints;
|
|
190
219
|
private accessToken;
|
|
191
220
|
constructor(config: IMultisetSdkConfig);
|
|
192
221
|
get token(): string | null;
|
|
222
|
+
getConfig(): IMultisetSdkConfig;
|
|
193
223
|
authorize(): Promise<string>;
|
|
194
224
|
private handleError;
|
|
195
225
|
localizeWithFrame(frame: IFrameCaptureEvent, intrinsics: ICameraIntrinsicsEvent): Promise<ILocalizeAndMapDetails | null>;
|
|
226
|
+
private getGeoPoseComponents;
|
|
196
227
|
private queryLocalization;
|
|
197
228
|
private fetchMapDetails;
|
|
198
229
|
private fetchMapSetDetails;
|
package/dist/core/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import axios from 'axios';
|
|
2
2
|
|
|
3
|
-
// src/lib/core/
|
|
3
|
+
// src/lib/core/config.ts
|
|
4
4
|
var DEFAULT_ENDPOINTS = {
|
|
5
5
|
authUrl: "https://api.multiset.ai/v1/m2m/token",
|
|
6
6
|
queryUrl: "https://api.multiset.ai/v1/vps/map/query-form",
|
|
@@ -21,6 +21,9 @@ var MultisetClient = class {
|
|
|
21
21
|
get token() {
|
|
22
22
|
return this.accessToken;
|
|
23
23
|
}
|
|
24
|
+
getConfig() {
|
|
25
|
+
return this.config;
|
|
26
|
+
}
|
|
24
27
|
async authorize() {
|
|
25
28
|
var _a, _b, _c, _d, _e;
|
|
26
29
|
try {
|
|
@@ -68,22 +71,54 @@ var MultisetClient = class {
|
|
|
68
71
|
}
|
|
69
72
|
return queryResult;
|
|
70
73
|
}
|
|
74
|
+
async getGeoPoseComponents() {
|
|
75
|
+
if (typeof navigator === "undefined" || !("geolocation" in navigator) || !navigator.geolocation) {
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
try {
|
|
79
|
+
const position = await new Promise((resolve, reject) => {
|
|
80
|
+
navigator.geolocation.getCurrentPosition(resolve, reject, {
|
|
81
|
+
enableHighAccuracy: true,
|
|
82
|
+
timeout: 1e4,
|
|
83
|
+
maximumAge: 0
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
const { latitude, longitude, altitude } = position.coords;
|
|
87
|
+
const safeAltitude = typeof altitude === "number" && !Number.isNaN(altitude) ? altitude : 0;
|
|
88
|
+
return [latitude, longitude, safeAltitude];
|
|
89
|
+
} catch {
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
71
93
|
async queryLocalization(frame, intrinsics) {
|
|
72
|
-
var _a;
|
|
94
|
+
var _a, _b, _c;
|
|
73
95
|
const formData = new FormData();
|
|
74
|
-
formData.append("
|
|
75
|
-
formData.append("
|
|
76
|
-
formData.append("height", `${frame.height}`);
|
|
77
|
-
formData.append("px", `${intrinsics.px}`);
|
|
78
|
-
formData.append("py", `${intrinsics.py}`);
|
|
79
|
-
formData.append("fx", `${intrinsics.fx}`);
|
|
80
|
-
formData.append("fy", `${intrinsics.fy}`);
|
|
81
|
-
formData.append("queryImage", frame.blob);
|
|
96
|
+
formData.append("mapId", (_a = this.config.mapId) != null ? _a : "");
|
|
97
|
+
formData.append("mapSetId", (_b = this.config.mapSetId) != null ? _b : "");
|
|
82
98
|
if (this.config.mapType === "map") {
|
|
83
99
|
formData.append("mapCode", this.config.code);
|
|
84
100
|
} else {
|
|
85
101
|
formData.append("mapSetCode", this.config.code);
|
|
86
102
|
}
|
|
103
|
+
formData.append("isRightHanded", "true");
|
|
104
|
+
formData.append("fx", `${intrinsics.fx}`);
|
|
105
|
+
formData.append("fy", `${intrinsics.fy}`);
|
|
106
|
+
formData.append("px", `${intrinsics.px}`);
|
|
107
|
+
formData.append("py", `${intrinsics.py}`);
|
|
108
|
+
formData.append("width", `${frame.width}`);
|
|
109
|
+
formData.append("height", `${frame.height}`);
|
|
110
|
+
formData.append("queryImage", frame.blob);
|
|
111
|
+
if (this.config.geoCoordinatesInResponse) {
|
|
112
|
+
formData.append("geoCoordinatesInResponse", "true");
|
|
113
|
+
}
|
|
114
|
+
if (this.config.passGeoPose) {
|
|
115
|
+
const components = await this.getGeoPoseComponents();
|
|
116
|
+
if (components) {
|
|
117
|
+
const [latitude, longitude, altitude] = components;
|
|
118
|
+
const geoHint = `${latitude},${longitude},${altitude}`;
|
|
119
|
+
formData.append("geoHint", geoHint);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
87
122
|
try {
|
|
88
123
|
const response = await axios.post(
|
|
89
124
|
this.endpoints.queryUrl,
|
|
@@ -101,7 +136,7 @@ var MultisetClient = class {
|
|
|
101
136
|
const result = {
|
|
102
137
|
localizeData: data
|
|
103
138
|
};
|
|
104
|
-
if ((
|
|
139
|
+
if ((_c = data.mapIds) == null ? void 0 : _c.length) {
|
|
105
140
|
const mapDetails = await this.fetchMapDetails(data.mapIds[0]);
|
|
106
141
|
if (mapDetails) {
|
|
107
142
|
result.mapDetails = mapDetails;
|
package/dist/core/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/lib/core/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import axios, { AxiosError } from 'axios';\nimport type {\n ILocalizeAndMapDetails,\n ILocalizeResponse,\n MapType,\n IGetMapsDetailsResponse,\n IMapSetMapsResponse,\n} from './types';\n\nexport interface IMultisetSdkConfig {\n clientId: string;\n clientSecret: string;\n code: string;\n mapType: MapType;\n endpoints?: Partial<IMultisetSdkEndpoints>;\n onAuthorize?: (token: string) => void;\n onFrameCaptured?: (payload: IFrameCaptureEvent) => void;\n onCameraIntrinsics?: (intrinsics: ICameraIntrinsicsEvent) => void;\n onPoseResult?: (payload: IPoseResultEvent) => void;\n onError?: (error: unknown) => void;\n}\n\nexport interface IMultisetSdkEndpoints {\n authUrl: string;\n queryUrl: string;\n mapDetailsUrl: string;\n fileDownloadUrl: string;\n mapSetDetailsUrl: string;\n}\n\nexport interface IFrameCaptureEvent {\n blob: Blob;\n width: number;\n height: number;\n}\n\nexport interface ICameraIntrinsicsEvent {\n fx: number;\n fy: number;\n px: number;\n py: number;\n width: number;\n height: number;\n}\n\nexport interface IPoseResultEvent {\n poseFound: boolean;\n position: {\n x: number;\n y: number;\n z: number;\n };\n rotation: {\n x: number;\n y: number;\n z: number;\n w: number;\n };\n mapIds: string[];\n confidence?: number;\n}\n\nexport interface ILocalizeResultEvent {\n frame: IFrameCaptureEvent;\n intrinsics: ICameraIntrinsicsEvent;\n response: ILocalizeAndMapDetails | null;\n}\n\nexport const DEFAULT_ENDPOINTS: IMultisetSdkEndpoints = {\n authUrl: 'https://api.multiset.ai/v1/m2m/token',\n queryUrl: 'https://api.multiset.ai/v1/vps/map/query-form',\n mapDetailsUrl: 'https://api.multiset.ai/v1/vps/map/',\n mapSetDetailsUrl: 'https://api.multiset.ai/v1/vps/map-set/',\n fileDownloadUrl: 'https://api.multiset.ai/v1/file',\n};\n\n/**\n * Placeholder class to be implemented by porting logic from multiset-webxr-sdk.\n */\nexport class MultisetClient {\n private readonly endpoints: IMultisetSdkEndpoints;\n private accessToken: string | null = null;\n\n constructor(private readonly config: IMultisetSdkConfig) {\n this.config = config;\n this.endpoints = {\n ...DEFAULT_ENDPOINTS,\n ...config.endpoints,\n };\n }\n\n get token(): string | null {\n return this.accessToken;\n }\n\n async authorize(): Promise<string> {\n try {\n const response = await axios.post(\n this.endpoints.authUrl,\n {},\n {\n auth: {\n username: this.config.clientId,\n password: this.config.clientSecret,\n },\n }\n );\n\n const token: string | undefined =\n response.data?.token ?? response.data?.access_token;\n\n if (!token) {\n throw new Error('Authorization succeeded but no token was returned.');\n }\n\n this.accessToken = token;\n this.config.onAuthorize?.(token);\n return token;\n } catch (error) {\n this.handleError(error);\n throw error;\n }\n }\n\n private handleError(error: unknown): void {\n if (axios.isAxiosError(error)) {\n const axiosError = error as AxiosError;\n this.config.onError?.(axiosError);\n } else {\n this.config.onError?.(error);\n }\n }\n\n async localizeWithFrame(\n frame: IFrameCaptureEvent,\n intrinsics: ICameraIntrinsicsEvent\n ): Promise<ILocalizeAndMapDetails | null> {\n if (!this.accessToken) {\n throw new Error('Access token is missing. Call authorize() first.');\n }\n\n this.config.onFrameCaptured?.(frame);\n this.config.onCameraIntrinsics?.(intrinsics);\n\n const queryResult = await this.queryLocalization(frame, intrinsics);\n\n if (queryResult?.localizeData?.poseFound) {\n this.config.onPoseResult?.(queryResult.localizeData);\n }\n\n return queryResult;\n }\n\n private async queryLocalization(\n frame: IFrameCaptureEvent,\n intrinsics: ICameraIntrinsicsEvent\n ): Promise<ILocalizeAndMapDetails | null> {\n const formData = new FormData();\n formData.append('isRightHanded', 'true');\n formData.append('width', `${frame.width}`);\n formData.append('height', `${frame.height}`);\n formData.append('px', `${intrinsics.px}`);\n formData.append('py', `${intrinsics.py}`);\n formData.append('fx', `${intrinsics.fx}`);\n formData.append('fy', `${intrinsics.fy}`);\n formData.append('queryImage', frame.blob);\n\n if (this.config.mapType === 'map') {\n formData.append('mapCode', this.config.code);\n } else {\n formData.append('mapSetCode', this.config.code);\n }\n\n try {\n const response = await axios.post<ILocalizeResponse>(\n this.endpoints.queryUrl,\n formData,\n {\n headers: {\n Authorization: `Bearer ${this.accessToken}`,\n },\n }\n );\n\n const data = response.data;\n if (!data.poseFound) {\n return null;\n }\n\n const result: ILocalizeAndMapDetails = {\n localizeData: data,\n };\n\n if (data.mapIds?.length) {\n const mapDetails = await this.fetchMapDetails(data.mapIds[0]);\n if (mapDetails) {\n result.mapDetails = mapDetails;\n }\n }\n\n return result;\n } catch (error) {\n this.handleError(error);\n return null;\n }\n }\n\n private async fetchMapDetails(mapId: string): Promise<IGetMapsDetailsResponse | null> {\n try {\n const response = await axios.get<IGetMapsDetailsResponse>(\n `${this.endpoints.mapDetailsUrl}${mapId}`,\n {\n headers: {\n Authorization: `Bearer ${this.accessToken}`,\n },\n }\n );\n return response.data;\n } catch (error) {\n this.handleError(error);\n return null;\n }\n }\n\n private async fetchMapSetDetails(mapSetId: string): Promise<IMapSetMapsResponse | null> {\n try {\n const response = await axios.get<IMapSetMapsResponse>(\n `${this.endpoints.mapSetDetailsUrl}${mapSetId}`,\n {\n headers: {\n Authorization: `Bearer ${this.accessToken}`,\n },\n }\n );\n return response.data;\n } catch (error) {\n this.handleError(error);\n return null;\n }\n }\n}\n\nexport type { IMultisetSdkConfig as IMultisetClientOptions };\nexport type {\n MapType,\n ILocalizeResponse,\n ILocalizeAndMapDetails,\n IGetMapsDetailsResponse,\n IMapSetMapsResponse,\n} from './types';\n\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/lib/core/config.ts","../../src/lib/core/client.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import type { ILocalizeAndMapDetails, MapType } from './types';\n\nexport interface IMultisetSdkConfig {\n mapId?: string;\n mapSetId?: string;\n clientId: string;\n clientSecret: string;\n /** Map or map-set code used for localization. */\n code: string;\n /** Map or map-set type ('map' or 'map-set'). */\n mapType: MapType;\n endpoints?: Partial<IMultisetSdkEndpoints>;\n\n /** If true, automatically start a localization run when the AR session starts. */\n autoLocalize?: boolean;\n /** If true, automatically re-localize when tracking is lost and then recovered. */\n relocalization?: boolean;\n /** When enabled, only accept a localization result if confidence >= confidenceThreshold. */\n confidenceCheck?: boolean;\n /** Minimum confidence (0.2–0.8) required when confidenceCheck is enabled. */\n confidenceThreshold?: number;\n /** Total single-frame attempts per localization run (1–5). */\n requestAttempts?: number;\n /** Time in seconds between attempts in a localization run (1–5). */\n localizationInterval?: number;\n /** Include device geo pose as a hint in localization requests. */\n passGeoPose?: boolean;\n /** Request geo coordinates in the localization response (if supported by backend). */\n geoCoordinatesInResponse?: boolean;\n\n /** Invoked at the start of a localization run. */\n onLocalizationInit?: () => void;\n /** Invoked after a successful localization that meets confidence criteria (if enabled). */\n onLocalizationSuccess?: (result: ILocalizeAndMapDetails) => void;\n /** Invoked when all attempts fail or the best result is below the confidence threshold. */\n onLocalizationFailure?: (reason?: string) => void;\n\n /** Called after a successful authorization with the access token. */\n onAuthorize?: (token: string) => void;\n /** Called whenever a camera frame is captured and sent for localization. */\n onFrameCaptured?: (payload: IFrameCaptureEvent) => void;\n /** Called with the camera intrinsics used for a localization request. */\n onCameraIntrinsics?: (intrinsics: ICameraIntrinsicsEvent) => void;\n /** Called with the raw pose/localization result returned by the backend. */\n onPoseResult?: (payload: IPoseResultEvent) => void;\n /** Called when any error occurs during authorization or localization. */\n onError?: (error: unknown) => void;\n}\n\nexport interface IMultisetSdkEndpoints {\n authUrl: string;\n queryUrl: string;\n mapDetailsUrl: string;\n fileDownloadUrl: string;\n mapSetDetailsUrl: string;\n}\n\nexport interface IFrameCaptureEvent {\n blob: Blob;\n width: number;\n height: number;\n}\n\nexport interface ICameraIntrinsicsEvent {\n fx: number;\n fy: number;\n px: number;\n py: number;\n width: number;\n height: number;\n}\n\nexport interface IPoseResultEvent {\n poseFound: boolean;\n position: {\n x: number;\n y: number;\n z: number;\n };\n rotation: {\n x: number;\n y: number;\n z: number;\n w: number;\n };\n mapIds: string[];\n confidence?: number;\n}\n\nexport interface ILocalizeResultEvent {\n frame: IFrameCaptureEvent;\n intrinsics: ICameraIntrinsicsEvent;\n response: ILocalizeAndMapDetails | null;\n}\n\nexport const DEFAULT_ENDPOINTS: IMultisetSdkEndpoints = {\n authUrl: 'https://api.multiset.ai/v1/m2m/token',\n queryUrl: 'https://api.multiset.ai/v1/vps/map/query-form',\n mapDetailsUrl: 'https://api.multiset.ai/v1/vps/map/',\n mapSetDetailsUrl: 'https://api.multiset.ai/v1/vps/map-set/',\n fileDownloadUrl: 'https://api.multiset.ai/v1/file',\n};\n","import axios, { AxiosError } from 'axios';\nimport type {\n IMultisetSdkConfig,\n IMultisetSdkEndpoints,\n IFrameCaptureEvent,\n ICameraIntrinsicsEvent,\n} from './config';\nimport { DEFAULT_ENDPOINTS } from './config';\nimport type {\n ILocalizeAndMapDetails,\n ILocalizeResponse,\n IGetMapsDetailsResponse,\n IMapSetMapsResponse,\n} from './types';\n\nexport class MultisetClient {\n private readonly endpoints: IMultisetSdkEndpoints;\n private accessToken: string | null = null;\n\n constructor(private readonly config: IMultisetSdkConfig) {\n this.config = config;\n this.endpoints = {\n ...DEFAULT_ENDPOINTS,\n ...config.endpoints,\n };\n }\n\n get token(): string | null {\n return this.accessToken;\n }\n\n getConfig(): IMultisetSdkConfig {\n return this.config;\n }\n\n async authorize(): Promise<string> {\n try {\n const response = await axios.post(\n this.endpoints.authUrl,\n {},\n {\n auth: {\n username: this.config.clientId,\n password: this.config.clientSecret,\n },\n }\n );\n\n const token: string | undefined =\n response.data?.token ?? response.data?.access_token;\n\n if (!token) {\n throw new Error('Authorization succeeded but no token was returned.');\n }\n\n this.accessToken = token;\n this.config.onAuthorize?.(token);\n return token;\n } catch (error) {\n this.handleError(error);\n throw error;\n }\n }\n\n private handleError(error: unknown): void {\n if (axios.isAxiosError(error)) {\n const axiosError = error as AxiosError;\n this.config.onError?.(axiosError);\n } else {\n this.config.onError?.(error);\n }\n }\n\n async localizeWithFrame(\n frame: IFrameCaptureEvent,\n intrinsics: ICameraIntrinsicsEvent\n ): Promise<ILocalizeAndMapDetails | null> {\n if (!this.accessToken) {\n throw new Error('Access token is missing. Call authorize() first.');\n }\n\n this.config.onFrameCaptured?.(frame);\n this.config.onCameraIntrinsics?.(intrinsics);\n\n const queryResult = await this.queryLocalization(frame, intrinsics);\n\n if (queryResult?.localizeData?.poseFound) {\n this.config.onPoseResult?.(queryResult.localizeData);\n }\n\n return queryResult;\n }\n\n private async getGeoPoseComponents(): Promise<\n [latitude: number, longitude: number, altitude: number] | null\n > {\n if (\n typeof navigator === 'undefined' ||\n !('geolocation' in navigator) ||\n !navigator.geolocation\n ) {\n return null;\n }\n\n try {\n const position = await new Promise<GeolocationPosition>((resolve, reject) => {\n navigator.geolocation.getCurrentPosition(resolve, reject, {\n enableHighAccuracy: true,\n timeout: 10000,\n maximumAge: 0,\n });\n });\n\n const { latitude, longitude, altitude } = position.coords;\n const safeAltitude =\n typeof altitude === 'number' && !Number.isNaN(altitude) ? altitude : 0.0;\n\n return [latitude, longitude, safeAltitude];\n } catch {\n return null;\n }\n }\n\n private async queryLocalization(\n frame: IFrameCaptureEvent,\n intrinsics: ICameraIntrinsicsEvent\n ): Promise<ILocalizeAndMapDetails | null> {\n const formData = new FormData();\n\n formData.append('mapId', this.config.mapId ?? '');\n formData.append('mapSetId', this.config.mapSetId ?? '');\n if (this.config.mapType === 'map') {\n formData.append('mapCode', this.config.code);\n } else {\n formData.append('mapSetCode', this.config.code);\n }\n formData.append('isRightHanded', 'true');\n formData.append('fx', `${intrinsics.fx}`);\n formData.append('fy', `${intrinsics.fy}`);\n formData.append('px', `${intrinsics.px}`);\n formData.append('py', `${intrinsics.py}`);\n formData.append('width', `${frame.width}`);\n formData.append('height', `${frame.height}`);\n formData.append('queryImage', frame.blob);\n if (this.config.geoCoordinatesInResponse) {\n formData.append('geoCoordinatesInResponse', 'true');\n }\n if (this.config.passGeoPose) {\n const components = await this.getGeoPoseComponents();\n if (components) {\n const [latitude, longitude, altitude] = components;\n const geoHint = `${latitude},${longitude},${altitude}`;\n formData.append('geoHint', geoHint);\n }\n }\n\n try {\n const response = await axios.post<ILocalizeResponse>(\n this.endpoints.queryUrl,\n formData,\n {\n headers: {\n Authorization: `Bearer ${this.accessToken}`,\n },\n }\n );\n\n const data = response.data;\n if (!data.poseFound) {\n return null;\n }\n\n const result: ILocalizeAndMapDetails = {\n localizeData: data,\n };\n\n if (data.mapIds?.length) {\n const mapDetails = await this.fetchMapDetails(data.mapIds[0]);\n if (mapDetails) {\n result.mapDetails = mapDetails;\n }\n }\n\n return result;\n } catch (error) {\n this.handleError(error);\n return null;\n }\n }\n\n private async fetchMapDetails(mapId: string): Promise<IGetMapsDetailsResponse | null> {\n try {\n const response = await axios.get<IGetMapsDetailsResponse>(\n `${this.endpoints.mapDetailsUrl}${mapId}`,\n {\n headers: {\n Authorization: `Bearer ${this.accessToken}`,\n },\n }\n );\n return response.data;\n } catch (error) {\n this.handleError(error);\n return null;\n }\n }\n\n private async fetchMapSetDetails(mapSetId: string): Promise<IMapSetMapsResponse | null> {\n try {\n const response = await axios.get<IMapSetMapsResponse>(\n `${this.endpoints.mapSetDetailsUrl}${mapSetId}`,\n {\n headers: {\n Authorization: `Bearer ${this.accessToken}`,\n },\n }\n );\n return response.data;\n } catch (error) {\n this.handleError(error);\n return null;\n }\n }\n}\n"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { DEFAULT_ENDPOINTS, ICameraIntrinsicsEvent, IFrameCaptureEvent, IGetMapsDetailsResponse, ILocalizeAndMapDetails, ILocalizeResponse, ILocalizeResultEvent, IMapSetMapsResponse, IMultisetClientOptions,
|
|
1
|
+
export { DEFAULT_ENDPOINTS, ICameraIntrinsicsEvent, IFrameCaptureEvent, IGetMapsDetailsResponse, ILocalizeAndMapDetails, ILocalizeResponse, ILocalizeResultEvent, IMapSetMapsResponse, IMultisetSdkConfig as IMultisetClientOptions, IMultisetSdkConfig, IMultisetSdkEndpoints, IPoseResultEvent, MapType, MultisetClient } from './core/index.js';
|
|
2
2
|
export { IWebxrControllerOptions, WebxrController } from './webxr/index.js';
|
|
3
3
|
import 'three';
|