@serviceai/api-spec 1.1.24 → 1.2.2
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/openapi.json +246 -52
- package/openapi.yaml +178 -34
- package/package.json +1 -1
- package/types.d.ts +63 -13
package/openapi.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"openapi": "3.1.0",
|
|
3
3
|
"info": {
|
|
4
4
|
"title": "ServiceAi API",
|
|
5
|
-
"version": "1.
|
|
5
|
+
"version": "1.2.2",
|
|
6
6
|
"description": "Source-of-truth API contract for ServiceAi. Generated from `shared/schema.ts` Zod schemas by `scripts/build-api-spec.ts`. Versioning policy: see `docs/api-versioning.md`. The hand-written docs/ios-contract.md and docs/lidar-mobile-upload-contract.md are human-readable design notes only — this spec is the canonical wire contract.",
|
|
7
7
|
"license": {
|
|
8
8
|
"name": "Proprietary",
|
|
@@ -114,7 +114,7 @@
|
|
|
114
114
|
"properties": {
|
|
115
115
|
"apiVersion": {
|
|
116
116
|
"type": "string",
|
|
117
|
-
"example": "1.
|
|
117
|
+
"example": "1.2.2"
|
|
118
118
|
},
|
|
119
119
|
"minClientVersion": {
|
|
120
120
|
"type": "string",
|
|
@@ -1942,9 +1942,70 @@
|
|
|
1942
1942
|
"category": {
|
|
1943
1943
|
"type": "string"
|
|
1944
1944
|
},
|
|
1945
|
+
"roomLocalId": {
|
|
1946
|
+
"type": "string",
|
|
1947
|
+
"maxLength": 128
|
|
1948
|
+
},
|
|
1945
1949
|
"walls": {
|
|
1946
1950
|
"type": "array",
|
|
1947
|
-
"items": {
|
|
1951
|
+
"items": {
|
|
1952
|
+
"type": "object",
|
|
1953
|
+
"properties": {
|
|
1954
|
+
"start": {
|
|
1955
|
+
"type": "object",
|
|
1956
|
+
"properties": {
|
|
1957
|
+
"x": {
|
|
1958
|
+
"type": "number"
|
|
1959
|
+
},
|
|
1960
|
+
"y": {
|
|
1961
|
+
"type": "number"
|
|
1962
|
+
}
|
|
1963
|
+
},
|
|
1964
|
+
"required": [
|
|
1965
|
+
"x",
|
|
1966
|
+
"y"
|
|
1967
|
+
]
|
|
1968
|
+
},
|
|
1969
|
+
"end": {
|
|
1970
|
+
"type": "object",
|
|
1971
|
+
"properties": {
|
|
1972
|
+
"x": {
|
|
1973
|
+
"type": "number"
|
|
1974
|
+
},
|
|
1975
|
+
"y": {
|
|
1976
|
+
"type": "number"
|
|
1977
|
+
}
|
|
1978
|
+
},
|
|
1979
|
+
"required": [
|
|
1980
|
+
"x",
|
|
1981
|
+
"y"
|
|
1982
|
+
]
|
|
1983
|
+
},
|
|
1984
|
+
"length": {
|
|
1985
|
+
"type": "number"
|
|
1986
|
+
},
|
|
1987
|
+
"height": {
|
|
1988
|
+
"type": "number"
|
|
1989
|
+
},
|
|
1990
|
+
"captureMetadata": {
|
|
1991
|
+
"type": "object",
|
|
1992
|
+
"properties": {
|
|
1993
|
+
"identifier": {
|
|
1994
|
+
"type": "string"
|
|
1995
|
+
},
|
|
1996
|
+
"isDoor": {
|
|
1997
|
+
"type": "boolean"
|
|
1998
|
+
},
|
|
1999
|
+
"isOpening": {
|
|
2000
|
+
"type": "boolean"
|
|
2001
|
+
}
|
|
2002
|
+
}
|
|
2003
|
+
},
|
|
2004
|
+
"captureMethod": {
|
|
2005
|
+
"type": "string"
|
|
2006
|
+
}
|
|
2007
|
+
}
|
|
2008
|
+
}
|
|
1948
2009
|
},
|
|
1949
2010
|
"doors": {
|
|
1950
2011
|
"type": "array",
|
|
@@ -1959,15 +2020,11 @@
|
|
|
1959
2020
|
},
|
|
1960
2021
|
"y": {
|
|
1961
2022
|
"type": "number"
|
|
1962
|
-
},
|
|
1963
|
-
"z": {
|
|
1964
|
-
"type": "number"
|
|
1965
2023
|
}
|
|
1966
2024
|
},
|
|
1967
2025
|
"required": [
|
|
1968
2026
|
"x",
|
|
1969
|
-
"y"
|
|
1970
|
-
"z"
|
|
2027
|
+
"y"
|
|
1971
2028
|
]
|
|
1972
2029
|
},
|
|
1973
2030
|
"width": {
|
|
@@ -2025,15 +2082,11 @@
|
|
|
2025
2082
|
},
|
|
2026
2083
|
"y": {
|
|
2027
2084
|
"type": "number"
|
|
2028
|
-
},
|
|
2029
|
-
"z": {
|
|
2030
|
-
"type": "number"
|
|
2031
2085
|
}
|
|
2032
2086
|
},
|
|
2033
2087
|
"required": [
|
|
2034
2088
|
"x",
|
|
2035
|
-
"y"
|
|
2036
|
-
"z"
|
|
2089
|
+
"y"
|
|
2037
2090
|
]
|
|
2038
2091
|
},
|
|
2039
2092
|
"width": {
|
|
@@ -2091,15 +2144,11 @@
|
|
|
2091
2144
|
},
|
|
2092
2145
|
"y": {
|
|
2093
2146
|
"type": "number"
|
|
2094
|
-
},
|
|
2095
|
-
"z": {
|
|
2096
|
-
"type": "number"
|
|
2097
2147
|
}
|
|
2098
2148
|
},
|
|
2099
2149
|
"required": [
|
|
2100
2150
|
"x",
|
|
2101
|
-
"y"
|
|
2102
|
-
"z"
|
|
2151
|
+
"y"
|
|
2103
2152
|
]
|
|
2104
2153
|
},
|
|
2105
2154
|
"width": {
|
|
@@ -2143,6 +2192,119 @@
|
|
|
2143
2192
|
"height"
|
|
2144
2193
|
]
|
|
2145
2194
|
}
|
|
2195
|
+
},
|
|
2196
|
+
"pins": {
|
|
2197
|
+
"type": "array",
|
|
2198
|
+
"items": {
|
|
2199
|
+
"type": "object",
|
|
2200
|
+
"properties": {
|
|
2201
|
+
"id": {
|
|
2202
|
+
"type": "string",
|
|
2203
|
+
"minLength": 1,
|
|
2204
|
+
"maxLength": 128
|
|
2205
|
+
},
|
|
2206
|
+
"position": {
|
|
2207
|
+
"type": "object",
|
|
2208
|
+
"properties": {
|
|
2209
|
+
"x": {
|
|
2210
|
+
"type": "number"
|
|
2211
|
+
},
|
|
2212
|
+
"y": {
|
|
2213
|
+
"type": "number"
|
|
2214
|
+
}
|
|
2215
|
+
},
|
|
2216
|
+
"required": [
|
|
2217
|
+
"x",
|
|
2218
|
+
"y"
|
|
2219
|
+
]
|
|
2220
|
+
},
|
|
2221
|
+
"label": {
|
|
2222
|
+
"type": "string",
|
|
2223
|
+
"maxLength": 256
|
|
2224
|
+
},
|
|
2225
|
+
"roomLocalId": {
|
|
2226
|
+
"type": "string",
|
|
2227
|
+
"maxLength": 128
|
|
2228
|
+
},
|
|
2229
|
+
"kind": {
|
|
2230
|
+
"type": "string",
|
|
2231
|
+
"maxLength": 64
|
|
2232
|
+
},
|
|
2233
|
+
"note": {
|
|
2234
|
+
"type": "string",
|
|
2235
|
+
"maxLength": 1024
|
|
2236
|
+
}
|
|
2237
|
+
},
|
|
2238
|
+
"required": [
|
|
2239
|
+
"id",
|
|
2240
|
+
"position"
|
|
2241
|
+
]
|
|
2242
|
+
}
|
|
2243
|
+
},
|
|
2244
|
+
"objects": {
|
|
2245
|
+
"type": "array",
|
|
2246
|
+
"items": {
|
|
2247
|
+
"type": "object",
|
|
2248
|
+
"properties": {
|
|
2249
|
+
"category": {
|
|
2250
|
+
"type": "string"
|
|
2251
|
+
},
|
|
2252
|
+
"position": {
|
|
2253
|
+
"type": "object",
|
|
2254
|
+
"properties": {
|
|
2255
|
+
"x": {
|
|
2256
|
+
"type": "number"
|
|
2257
|
+
},
|
|
2258
|
+
"y": {
|
|
2259
|
+
"type": "number"
|
|
2260
|
+
}
|
|
2261
|
+
},
|
|
2262
|
+
"required": [
|
|
2263
|
+
"x",
|
|
2264
|
+
"y"
|
|
2265
|
+
]
|
|
2266
|
+
},
|
|
2267
|
+
"dimensions": {
|
|
2268
|
+
"type": "object",
|
|
2269
|
+
"properties": {
|
|
2270
|
+
"width": {
|
|
2271
|
+
"type": "number"
|
|
2272
|
+
},
|
|
2273
|
+
"height": {
|
|
2274
|
+
"type": "number"
|
|
2275
|
+
},
|
|
2276
|
+
"depth": {
|
|
2277
|
+
"type": "number"
|
|
2278
|
+
}
|
|
2279
|
+
}
|
|
2280
|
+
}
|
|
2281
|
+
}
|
|
2282
|
+
}
|
|
2283
|
+
},
|
|
2284
|
+
"boundaryPolygon": {
|
|
2285
|
+
"type": "array",
|
|
2286
|
+
"items": {
|
|
2287
|
+
"type": "object",
|
|
2288
|
+
"properties": {
|
|
2289
|
+
"x": {
|
|
2290
|
+
"type": "number"
|
|
2291
|
+
},
|
|
2292
|
+
"y": {
|
|
2293
|
+
"type": "number"
|
|
2294
|
+
}
|
|
2295
|
+
},
|
|
2296
|
+
"required": [
|
|
2297
|
+
"x",
|
|
2298
|
+
"y"
|
|
2299
|
+
]
|
|
2300
|
+
}
|
|
2301
|
+
},
|
|
2302
|
+
"roomNote": {
|
|
2303
|
+
"type": "string",
|
|
2304
|
+
"maxLength": 4096
|
|
2305
|
+
},
|
|
2306
|
+
"entryDoorwayId": {
|
|
2307
|
+
"type": "string"
|
|
2146
2308
|
}
|
|
2147
2309
|
},
|
|
2148
2310
|
"description": "Mobile-upload scan room. `doors`, `windows`, and `openings` are three distinct non-overlapping arrays — array membership IS the discriminator (there is no `kind` / `type` field on the item itself). Append-room `entryDoorwayId` of the form `scan-<scanId>-room-<roomLocalId>-(door|opening)-<idx>` resolves kind-specifically against the parent scan's matching array only: a `door` segment indexes `doors[]`, an `opening` segment indexes `openings[]`. Windows are not traversable and never appear as an `entryDoorwayId` target."
|
|
@@ -2151,7 +2313,8 @@
|
|
|
2151
2313
|
},
|
|
2152
2314
|
"required": [
|
|
2153
2315
|
"rooms"
|
|
2154
|
-
]
|
|
2316
|
+
],
|
|
2317
|
+
"description": "RoomPlan JSON envelope. `rooms[]` carries the per-room geometry (walls/doors/windows/openings/pins/objects/boundaryPolygon). iOS continues to upload positions in the RoomPlan-native frame; the server applies the view-alignment intake transform once at `/scans/mobile-upload` (see docs/lidar-contract-v4.md)."
|
|
2155
2318
|
},
|
|
2156
2319
|
"name": {
|
|
2157
2320
|
"type": "string",
|
|
@@ -2173,8 +2336,36 @@
|
|
|
2173
2336
|
"type": "string"
|
|
2174
2337
|
},
|
|
2175
2338
|
"wallConfidences": {
|
|
2176
|
-
"
|
|
2177
|
-
|
|
2339
|
+
"anyOf": [
|
|
2340
|
+
{
|
|
2341
|
+
"type": "array",
|
|
2342
|
+
"items": {
|
|
2343
|
+
"type": [
|
|
2344
|
+
"array",
|
|
2345
|
+
"null"
|
|
2346
|
+
],
|
|
2347
|
+
"items": {
|
|
2348
|
+
"type": "number"
|
|
2349
|
+
}
|
|
2350
|
+
}
|
|
2351
|
+
},
|
|
2352
|
+
{
|
|
2353
|
+
"type": "array",
|
|
2354
|
+
"items": {
|
|
2355
|
+
"type": "number"
|
|
2356
|
+
}
|
|
2357
|
+
},
|
|
2358
|
+
{
|
|
2359
|
+
"type": "object",
|
|
2360
|
+
"additionalProperties": {
|
|
2361
|
+
"type": "array",
|
|
2362
|
+
"items": {
|
|
2363
|
+
"type": "number"
|
|
2364
|
+
}
|
|
2365
|
+
}
|
|
2366
|
+
}
|
|
2367
|
+
],
|
|
2368
|
+
"description": "Per-room per-wall capture confidences. Canonical shape: nested `(number[] | null)[]` parallel to `roomPlanJSON.rooms[]`. Two legacy shapes are still accepted for backwards compatibility but should not be emitted by new clients: a flat `number[]` (treated as room[0] confidences) and an object keyed by `roomLocalId` (or numeric index as string). See `normalizeWallConfidences` in `server/routes/lidar.ts`."
|
|
2178
2369
|
},
|
|
2179
2370
|
"deviceTrack": {},
|
|
2180
2371
|
"referencePhotos": {
|
|
@@ -2286,13 +2477,40 @@
|
|
|
2286
2477
|
},
|
|
2287
2478
|
"clientMirrorApplied": {
|
|
2288
2479
|
"type": "boolean"
|
|
2480
|
+
},
|
|
2481
|
+
"parentScanId": {
|
|
2482
|
+
"type": "integer",
|
|
2483
|
+
"exclusiveMinimum": 0
|
|
2484
|
+
},
|
|
2485
|
+
"entryDoorwayId": {
|
|
2486
|
+
"type": "string",
|
|
2487
|
+
"description": "Append-room doorway link to a target room on the parent composite. Format: `scan-<scanId>-room-<roomLocalId>-(door|opening)-<idx>`. The trailing segment selects kind-specifically — `door` indexes the target room's `doors[]`, `opening` indexes `openings[]`; the two are never folded. `<scanId>` and `<roomLocalId>` must reference a scan + room on the parent composite the iOS client is appending to."
|
|
2488
|
+
},
|
|
2489
|
+
"entryDoorwayWallIndex": {
|
|
2490
|
+
"type": "integer",
|
|
2491
|
+
"minimum": 0
|
|
2492
|
+
},
|
|
2493
|
+
"entryDoorwayPosition": {
|
|
2494
|
+
"type": "object",
|
|
2495
|
+
"properties": {
|
|
2496
|
+
"x": {
|
|
2497
|
+
"type": "number"
|
|
2498
|
+
},
|
|
2499
|
+
"y": {
|
|
2500
|
+
"type": "number"
|
|
2501
|
+
}
|
|
2502
|
+
},
|
|
2503
|
+
"required": [
|
|
2504
|
+
"x",
|
|
2505
|
+
"y"
|
|
2506
|
+
]
|
|
2289
2507
|
}
|
|
2290
2508
|
},
|
|
2291
2509
|
"required": [
|
|
2292
2510
|
"roomPlanJSON",
|
|
2293
2511
|
"name"
|
|
2294
2512
|
],
|
|
2295
|
-
"description": "POST /api/jobs/:jobId/scans/mobile-upload body. Required: `roomPlanJSON` (object with nested `rooms` array) + `name`. All
|
|
2513
|
+
"description": "POST /api/jobs/:jobId/scans/mobile-upload body. v5 of the LiDAR contract (Task #879) — additive over v3/v4. Required: `roomPlanJSON` (object with nested `rooms` array) + `name`. All v3 and v4 payloads remain accepted byte-for-byte. New first-class fields: per-room `roomLocalId`, `pins[]`, `objects[]`, `boundaryPolygon[]`, per-wall `captureMetadata`; append-room `parentScanId`, `entryDoorwayId`, `entryDoorwayWallIndex`, `entryDoorwayPosition`; opening `position` is 2D `{x, y}` (an additional `z` is tolerated for backwards compatibility but ignored by the server). `wallConfidences` advertises the canonical nested `(number[] | null)[]` shape; the two legacy shapes (flat `number[]` and `Record<roomLocalIdOrIndex, number[]>`) are still parsed by `normalizeWallConfidences` in `server/routes/lidar.ts`."
|
|
2296
2514
|
},
|
|
2297
2515
|
"MobileUploadResponse": {
|
|
2298
2516
|
"type": "object",
|
|
@@ -4759,15 +4977,11 @@
|
|
|
4759
4977
|
},
|
|
4760
4978
|
"y": {
|
|
4761
4979
|
"type": "number"
|
|
4762
|
-
},
|
|
4763
|
-
"z": {
|
|
4764
|
-
"type": "number"
|
|
4765
4980
|
}
|
|
4766
4981
|
},
|
|
4767
4982
|
"required": [
|
|
4768
4983
|
"x",
|
|
4769
|
-
"y"
|
|
4770
|
-
"z"
|
|
4984
|
+
"y"
|
|
4771
4985
|
]
|
|
4772
4986
|
},
|
|
4773
4987
|
"width": {
|
|
@@ -4826,15 +5040,11 @@
|
|
|
4826
5040
|
},
|
|
4827
5041
|
"y": {
|
|
4828
5042
|
"type": "number"
|
|
4829
|
-
},
|
|
4830
|
-
"z": {
|
|
4831
|
-
"type": "number"
|
|
4832
5043
|
}
|
|
4833
5044
|
},
|
|
4834
5045
|
"required": [
|
|
4835
5046
|
"x",
|
|
4836
|
-
"y"
|
|
4837
|
-
"z"
|
|
5047
|
+
"y"
|
|
4838
5048
|
]
|
|
4839
5049
|
},
|
|
4840
5050
|
"width": {
|
|
@@ -4893,15 +5103,11 @@
|
|
|
4893
5103
|
},
|
|
4894
5104
|
"y": {
|
|
4895
5105
|
"type": "number"
|
|
4896
|
-
},
|
|
4897
|
-
"z": {
|
|
4898
|
-
"type": "number"
|
|
4899
5106
|
}
|
|
4900
5107
|
},
|
|
4901
5108
|
"required": [
|
|
4902
5109
|
"x",
|
|
4903
|
-
"y"
|
|
4904
|
-
"z"
|
|
5110
|
+
"y"
|
|
4905
5111
|
]
|
|
4906
5112
|
},
|
|
4907
5113
|
"width": {
|
|
@@ -5141,15 +5347,11 @@
|
|
|
5141
5347
|
},
|
|
5142
5348
|
"y": {
|
|
5143
5349
|
"type": "number"
|
|
5144
|
-
},
|
|
5145
|
-
"z": {
|
|
5146
|
-
"type": "number"
|
|
5147
5350
|
}
|
|
5148
5351
|
},
|
|
5149
5352
|
"required": [
|
|
5150
5353
|
"x",
|
|
5151
|
-
"y"
|
|
5152
|
-
"z"
|
|
5354
|
+
"y"
|
|
5153
5355
|
]
|
|
5154
5356
|
},
|
|
5155
5357
|
"width": {
|
|
@@ -5208,15 +5410,11 @@
|
|
|
5208
5410
|
},
|
|
5209
5411
|
"y": {
|
|
5210
5412
|
"type": "number"
|
|
5211
|
-
},
|
|
5212
|
-
"z": {
|
|
5213
|
-
"type": "number"
|
|
5214
5413
|
}
|
|
5215
5414
|
},
|
|
5216
5415
|
"required": [
|
|
5217
5416
|
"x",
|
|
5218
|
-
"y"
|
|
5219
|
-
"z"
|
|
5417
|
+
"y"
|
|
5220
5418
|
]
|
|
5221
5419
|
},
|
|
5222
5420
|
"width": {
|
|
@@ -5275,15 +5473,11 @@
|
|
|
5275
5473
|
},
|
|
5276
5474
|
"y": {
|
|
5277
5475
|
"type": "number"
|
|
5278
|
-
},
|
|
5279
|
-
"z": {
|
|
5280
|
-
"type": "number"
|
|
5281
5476
|
}
|
|
5282
5477
|
},
|
|
5283
5478
|
"required": [
|
|
5284
5479
|
"x",
|
|
5285
|
-
"y"
|
|
5286
|
-
"z"
|
|
5480
|
+
"y"
|
|
5287
5481
|
]
|
|
5288
5482
|
},
|
|
5289
5483
|
"width": {
|
package/openapi.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
openapi: 3.1.0
|
|
2
2
|
info:
|
|
3
3
|
title: ServiceAi API
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.2.2
|
|
5
5
|
description: >-
|
|
6
6
|
Source-of-truth API contract for ServiceAi. Generated from `shared/schema.ts` Zod schemas by
|
|
7
7
|
`scripts/build-api-spec.ts`. Versioning policy: see `docs/api-versioning.md`. The hand-written docs/ios-contract.md
|
|
@@ -78,7 +78,7 @@ components:
|
|
|
78
78
|
properties:
|
|
79
79
|
apiVersion:
|
|
80
80
|
type: string
|
|
81
|
-
example: 1.
|
|
81
|
+
example: 1.2.2
|
|
82
82
|
minClientVersion:
|
|
83
83
|
type: string
|
|
84
84
|
example: 1.0.0
|
|
@@ -1234,9 +1234,49 @@ components:
|
|
|
1234
1234
|
type: string
|
|
1235
1235
|
category:
|
|
1236
1236
|
type: string
|
|
1237
|
+
roomLocalId:
|
|
1238
|
+
type: string
|
|
1239
|
+
maxLength: 128
|
|
1237
1240
|
walls:
|
|
1238
1241
|
type: array
|
|
1239
|
-
items:
|
|
1242
|
+
items:
|
|
1243
|
+
type: object
|
|
1244
|
+
properties:
|
|
1245
|
+
start:
|
|
1246
|
+
type: object
|
|
1247
|
+
properties:
|
|
1248
|
+
x:
|
|
1249
|
+
type: number
|
|
1250
|
+
'y':
|
|
1251
|
+
type: number
|
|
1252
|
+
required:
|
|
1253
|
+
- x
|
|
1254
|
+
- 'y'
|
|
1255
|
+
end:
|
|
1256
|
+
type: object
|
|
1257
|
+
properties:
|
|
1258
|
+
x:
|
|
1259
|
+
type: number
|
|
1260
|
+
'y':
|
|
1261
|
+
type: number
|
|
1262
|
+
required:
|
|
1263
|
+
- x
|
|
1264
|
+
- 'y'
|
|
1265
|
+
length:
|
|
1266
|
+
type: number
|
|
1267
|
+
height:
|
|
1268
|
+
type: number
|
|
1269
|
+
captureMetadata:
|
|
1270
|
+
type: object
|
|
1271
|
+
properties:
|
|
1272
|
+
identifier:
|
|
1273
|
+
type: string
|
|
1274
|
+
isDoor:
|
|
1275
|
+
type: boolean
|
|
1276
|
+
isOpening:
|
|
1277
|
+
type: boolean
|
|
1278
|
+
captureMethod:
|
|
1279
|
+
type: string
|
|
1240
1280
|
doors:
|
|
1241
1281
|
type: array
|
|
1242
1282
|
items:
|
|
@@ -1249,12 +1289,9 @@ components:
|
|
|
1249
1289
|
type: number
|
|
1250
1290
|
'y':
|
|
1251
1291
|
type: number
|
|
1252
|
-
z:
|
|
1253
|
-
type: number
|
|
1254
1292
|
required:
|
|
1255
1293
|
- x
|
|
1256
1294
|
- 'y'
|
|
1257
|
-
- z
|
|
1258
1295
|
width:
|
|
1259
1296
|
type: number
|
|
1260
1297
|
exclusiveMinimum: 0
|
|
@@ -1296,12 +1333,9 @@ components:
|
|
|
1296
1333
|
type: number
|
|
1297
1334
|
'y':
|
|
1298
1335
|
type: number
|
|
1299
|
-
z:
|
|
1300
|
-
type: number
|
|
1301
1336
|
required:
|
|
1302
1337
|
- x
|
|
1303
1338
|
- 'y'
|
|
1304
|
-
- z
|
|
1305
1339
|
width:
|
|
1306
1340
|
type: number
|
|
1307
1341
|
exclusiveMinimum: 0
|
|
@@ -1338,12 +1372,9 @@ components:
|
|
|
1338
1372
|
type: number
|
|
1339
1373
|
'y':
|
|
1340
1374
|
type: number
|
|
1341
|
-
z:
|
|
1342
|
-
type: number
|
|
1343
1375
|
required:
|
|
1344
1376
|
- x
|
|
1345
1377
|
- 'y'
|
|
1346
|
-
- z
|
|
1347
1378
|
width:
|
|
1348
1379
|
type: number
|
|
1349
1380
|
exclusiveMinimum: 0
|
|
@@ -1368,6 +1399,83 @@ components:
|
|
|
1368
1399
|
- position
|
|
1369
1400
|
- width
|
|
1370
1401
|
- height
|
|
1402
|
+
pins:
|
|
1403
|
+
type: array
|
|
1404
|
+
items:
|
|
1405
|
+
type: object
|
|
1406
|
+
properties:
|
|
1407
|
+
id:
|
|
1408
|
+
type: string
|
|
1409
|
+
minLength: 1
|
|
1410
|
+
maxLength: 128
|
|
1411
|
+
position:
|
|
1412
|
+
type: object
|
|
1413
|
+
properties:
|
|
1414
|
+
x:
|
|
1415
|
+
type: number
|
|
1416
|
+
'y':
|
|
1417
|
+
type: number
|
|
1418
|
+
required:
|
|
1419
|
+
- x
|
|
1420
|
+
- 'y'
|
|
1421
|
+
label:
|
|
1422
|
+
type: string
|
|
1423
|
+
maxLength: 256
|
|
1424
|
+
roomLocalId:
|
|
1425
|
+
type: string
|
|
1426
|
+
maxLength: 128
|
|
1427
|
+
kind:
|
|
1428
|
+
type: string
|
|
1429
|
+
maxLength: 64
|
|
1430
|
+
note:
|
|
1431
|
+
type: string
|
|
1432
|
+
maxLength: 1024
|
|
1433
|
+
required:
|
|
1434
|
+
- id
|
|
1435
|
+
- position
|
|
1436
|
+
objects:
|
|
1437
|
+
type: array
|
|
1438
|
+
items:
|
|
1439
|
+
type: object
|
|
1440
|
+
properties:
|
|
1441
|
+
category:
|
|
1442
|
+
type: string
|
|
1443
|
+
position:
|
|
1444
|
+
type: object
|
|
1445
|
+
properties:
|
|
1446
|
+
x:
|
|
1447
|
+
type: number
|
|
1448
|
+
'y':
|
|
1449
|
+
type: number
|
|
1450
|
+
required:
|
|
1451
|
+
- x
|
|
1452
|
+
- 'y'
|
|
1453
|
+
dimensions:
|
|
1454
|
+
type: object
|
|
1455
|
+
properties:
|
|
1456
|
+
width:
|
|
1457
|
+
type: number
|
|
1458
|
+
height:
|
|
1459
|
+
type: number
|
|
1460
|
+
depth:
|
|
1461
|
+
type: number
|
|
1462
|
+
boundaryPolygon:
|
|
1463
|
+
type: array
|
|
1464
|
+
items:
|
|
1465
|
+
type: object
|
|
1466
|
+
properties:
|
|
1467
|
+
x:
|
|
1468
|
+
type: number
|
|
1469
|
+
'y':
|
|
1470
|
+
type: number
|
|
1471
|
+
required:
|
|
1472
|
+
- x
|
|
1473
|
+
- 'y'
|
|
1474
|
+
roomNote:
|
|
1475
|
+
type: string
|
|
1476
|
+
maxLength: 4096
|
|
1477
|
+
entryDoorwayId:
|
|
1478
|
+
type: string
|
|
1371
1479
|
description: >-
|
|
1372
1480
|
Mobile-upload scan room. `doors`, `windows`, and `openings` are three distinct non-overlapping arrays
|
|
1373
1481
|
— array membership IS the discriminator (there is no `kind` / `type` field on the item itself).
|
|
@@ -1377,6 +1485,11 @@ components:
|
|
|
1377
1485
|
an `entryDoorwayId` target.
|
|
1378
1486
|
required:
|
|
1379
1487
|
- rooms
|
|
1488
|
+
description: >-
|
|
1489
|
+
RoomPlan JSON envelope. `rooms[]` carries the per-room geometry
|
|
1490
|
+
(walls/doors/windows/openings/pins/objects/boundaryPolygon). iOS continues to upload positions in the
|
|
1491
|
+
RoomPlan-native frame; the server applies the view-alignment intake transform once at `/scans/mobile-upload`
|
|
1492
|
+
(see docs/lidar-contract-v4.md).
|
|
1380
1493
|
name:
|
|
1381
1494
|
type: string
|
|
1382
1495
|
minLength: 1
|
|
@@ -1391,8 +1504,27 @@ components:
|
|
|
1391
1504
|
userOrientationHint:
|
|
1392
1505
|
type: string
|
|
1393
1506
|
wallConfidences:
|
|
1394
|
-
|
|
1395
|
-
|
|
1507
|
+
anyOf:
|
|
1508
|
+
- type: array
|
|
1509
|
+
items:
|
|
1510
|
+
type:
|
|
1511
|
+
- array
|
|
1512
|
+
- 'null'
|
|
1513
|
+
items:
|
|
1514
|
+
type: number
|
|
1515
|
+
- type: array
|
|
1516
|
+
items:
|
|
1517
|
+
type: number
|
|
1518
|
+
- type: object
|
|
1519
|
+
additionalProperties:
|
|
1520
|
+
type: array
|
|
1521
|
+
items:
|
|
1522
|
+
type: number
|
|
1523
|
+
description: >-
|
|
1524
|
+
Per-room per-wall capture confidences. Canonical shape: nested `(number[] | null)[]` parallel to
|
|
1525
|
+
`roomPlanJSON.rooms[]`. Two legacy shapes are still accepted for backwards compatibility but should not be
|
|
1526
|
+
emitted by new clients: a flat `number[]` (treated as room[0] confidences) and an object keyed by
|
|
1527
|
+
`roomLocalId` (or numeric index as string). See `normalizeWallConfidences` in `server/routes/lidar.ts`.
|
|
1396
1528
|
deviceTrack: {}
|
|
1397
1529
|
referencePhotos:
|
|
1398
1530
|
type: array
|
|
@@ -1473,12 +1605,42 @@ components:
|
|
|
1473
1605
|
type: string
|
|
1474
1606
|
clientMirrorApplied:
|
|
1475
1607
|
type: boolean
|
|
1608
|
+
parentScanId:
|
|
1609
|
+
type: integer
|
|
1610
|
+
exclusiveMinimum: 0
|
|
1611
|
+
entryDoorwayId:
|
|
1612
|
+
type: string
|
|
1613
|
+
description: >-
|
|
1614
|
+
Append-room doorway link to a target room on the parent composite. Format:
|
|
1615
|
+
`scan-<scanId>-room-<roomLocalId>-(door|opening)-<idx>`. The trailing segment selects kind-specifically —
|
|
1616
|
+
`door` indexes the target room's `doors[]`, `opening` indexes `openings[]`; the two are never folded.
|
|
1617
|
+
`<scanId>` and `<roomLocalId>` must reference a scan + room on the parent composite the iOS client is
|
|
1618
|
+
appending to.
|
|
1619
|
+
entryDoorwayWallIndex:
|
|
1620
|
+
type: integer
|
|
1621
|
+
minimum: 0
|
|
1622
|
+
entryDoorwayPosition:
|
|
1623
|
+
type: object
|
|
1624
|
+
properties:
|
|
1625
|
+
x:
|
|
1626
|
+
type: number
|
|
1627
|
+
'y':
|
|
1628
|
+
type: number
|
|
1629
|
+
required:
|
|
1630
|
+
- x
|
|
1631
|
+
- 'y'
|
|
1476
1632
|
required:
|
|
1477
1633
|
- roomPlanJSON
|
|
1478
1634
|
- name
|
|
1479
1635
|
description: >-
|
|
1480
|
-
POST /api/jobs/:jobId/scans/mobile-upload body.
|
|
1481
|
-
`
|
|
1636
|
+
POST /api/jobs/:jobId/scans/mobile-upload body. v5 of the LiDAR contract (Task #879) — additive over v3/v4.
|
|
1637
|
+
Required: `roomPlanJSON` (object with nested `rooms` array) + `name`. All v3 and v4 payloads remain accepted
|
|
1638
|
+
byte-for-byte. New first-class fields: per-room `roomLocalId`, `pins[]`, `objects[]`, `boundaryPolygon[]`,
|
|
1639
|
+
per-wall `captureMetadata`; append-room `parentScanId`, `entryDoorwayId`, `entryDoorwayWallIndex`,
|
|
1640
|
+
`entryDoorwayPosition`; opening `position` is 2D `{x, y}` (an additional `z` is tolerated for backwards
|
|
1641
|
+
compatibility but ignored by the server). `wallConfidences` advertises the canonical nested `(number[] |
|
|
1642
|
+
null)[]` shape; the two legacy shapes (flat `number[]` and `Record<roomLocalIdOrIndex, number[]>`) are still
|
|
1643
|
+
parsed by `normalizeWallConfidences` in `server/routes/lidar.ts`.
|
|
1482
1644
|
MobileUploadResponse:
|
|
1483
1645
|
type: object
|
|
1484
1646
|
properties:
|
|
@@ -2994,12 +3156,9 @@ paths:
|
|
|
2994
3156
|
type: number
|
|
2995
3157
|
'y':
|
|
2996
3158
|
type: number
|
|
2997
|
-
z:
|
|
2998
|
-
type: number
|
|
2999
3159
|
required:
|
|
3000
3160
|
- x
|
|
3001
3161
|
- 'y'
|
|
3002
|
-
- z
|
|
3003
3162
|
width:
|
|
3004
3163
|
type: number
|
|
3005
3164
|
exclusiveMinimum: 0
|
|
@@ -3039,12 +3198,9 @@ paths:
|
|
|
3039
3198
|
type: number
|
|
3040
3199
|
'y':
|
|
3041
3200
|
type: number
|
|
3042
|
-
z:
|
|
3043
|
-
type: number
|
|
3044
3201
|
required:
|
|
3045
3202
|
- x
|
|
3046
3203
|
- 'y'
|
|
3047
|
-
- z
|
|
3048
3204
|
width:
|
|
3049
3205
|
type: number
|
|
3050
3206
|
exclusiveMinimum: 0
|
|
@@ -3084,12 +3240,9 @@ paths:
|
|
|
3084
3240
|
type: number
|
|
3085
3241
|
'y':
|
|
3086
3242
|
type: number
|
|
3087
|
-
z:
|
|
3088
|
-
type: number
|
|
3089
3243
|
required:
|
|
3090
3244
|
- x
|
|
3091
3245
|
- 'y'
|
|
3092
|
-
- z
|
|
3093
3246
|
width:
|
|
3094
3247
|
type: number
|
|
3095
3248
|
exclusiveMinimum: 0
|
|
@@ -3244,12 +3397,9 @@ paths:
|
|
|
3244
3397
|
type: number
|
|
3245
3398
|
'y':
|
|
3246
3399
|
type: number
|
|
3247
|
-
z:
|
|
3248
|
-
type: number
|
|
3249
3400
|
required:
|
|
3250
3401
|
- x
|
|
3251
3402
|
- 'y'
|
|
3252
|
-
- z
|
|
3253
3403
|
width:
|
|
3254
3404
|
type: number
|
|
3255
3405
|
exclusiveMinimum: 0
|
|
@@ -3289,12 +3439,9 @@ paths:
|
|
|
3289
3439
|
type: number
|
|
3290
3440
|
'y':
|
|
3291
3441
|
type: number
|
|
3292
|
-
z:
|
|
3293
|
-
type: number
|
|
3294
3442
|
required:
|
|
3295
3443
|
- x
|
|
3296
3444
|
- 'y'
|
|
3297
|
-
- z
|
|
3298
3445
|
width:
|
|
3299
3446
|
type: number
|
|
3300
3447
|
exclusiveMinimum: 0
|
|
@@ -3334,12 +3481,9 @@ paths:
|
|
|
3334
3481
|
type: number
|
|
3335
3482
|
'y':
|
|
3336
3483
|
type: number
|
|
3337
|
-
z:
|
|
3338
|
-
type: number
|
|
3339
3484
|
required:
|
|
3340
3485
|
- x
|
|
3341
3486
|
- 'y'
|
|
3342
|
-
- z
|
|
3343
3487
|
width:
|
|
3344
3488
|
type: number
|
|
3345
3489
|
exclusiveMinimum: 0
|
package/package.json
CHANGED
package/types.d.ts
CHANGED
|
@@ -1064,7 +1064,6 @@ export interface paths {
|
|
|
1064
1064
|
position: {
|
|
1065
1065
|
x: number;
|
|
1066
1066
|
y: number;
|
|
1067
|
-
z: number;
|
|
1068
1067
|
};
|
|
1069
1068
|
width: number;
|
|
1070
1069
|
height: number;
|
|
@@ -1080,7 +1079,6 @@ export interface paths {
|
|
|
1080
1079
|
position: {
|
|
1081
1080
|
x: number;
|
|
1082
1081
|
y: number;
|
|
1083
|
-
z: number;
|
|
1084
1082
|
};
|
|
1085
1083
|
width: number;
|
|
1086
1084
|
height: number;
|
|
@@ -1096,7 +1094,6 @@ export interface paths {
|
|
|
1096
1094
|
position: {
|
|
1097
1095
|
x: number;
|
|
1098
1096
|
y: number;
|
|
1099
|
-
z: number;
|
|
1100
1097
|
};
|
|
1101
1098
|
width: number;
|
|
1102
1099
|
height: number;
|
|
@@ -1198,7 +1195,6 @@ export interface paths {
|
|
|
1198
1195
|
position: {
|
|
1199
1196
|
x: number;
|
|
1200
1197
|
y: number;
|
|
1201
|
-
z: number;
|
|
1202
1198
|
};
|
|
1203
1199
|
width: number;
|
|
1204
1200
|
height: number;
|
|
@@ -1214,7 +1210,6 @@ export interface paths {
|
|
|
1214
1210
|
position: {
|
|
1215
1211
|
x: number;
|
|
1216
1212
|
y: number;
|
|
1217
|
-
z: number;
|
|
1218
1213
|
};
|
|
1219
1214
|
width: number;
|
|
1220
1215
|
height: number;
|
|
@@ -1230,7 +1225,6 @@ export interface paths {
|
|
|
1230
1225
|
position: {
|
|
1231
1226
|
x: number;
|
|
1232
1227
|
y: number;
|
|
1233
|
-
z: number;
|
|
1234
1228
|
};
|
|
1235
1229
|
width: number;
|
|
1236
1230
|
height: number;
|
|
@@ -1848,7 +1842,7 @@ export interface components {
|
|
|
1848
1842
|
};
|
|
1849
1843
|
/** @description Cross-platform version handshake manifest. See docs/api-versioning.md. */
|
|
1850
1844
|
VersionManifest: {
|
|
1851
|
-
/** @example 1.
|
|
1845
|
+
/** @example 1.2.2 */
|
|
1852
1846
|
apiVersion: string;
|
|
1853
1847
|
/** @example 1.0.0 */
|
|
1854
1848
|
minClientVersion: string;
|
|
@@ -2140,19 +2134,37 @@ export interface components {
|
|
|
2140
2134
|
orgId: number;
|
|
2141
2135
|
role: string;
|
|
2142
2136
|
};
|
|
2143
|
-
/** @description POST /api/jobs/:jobId/scans/mobile-upload body. Required: `roomPlanJSON` (object with nested `rooms` array) + `name`. All
|
|
2137
|
+
/** @description POST /api/jobs/:jobId/scans/mobile-upload body. v5 of the LiDAR contract (Task #879) — additive over v3/v4. Required: `roomPlanJSON` (object with nested `rooms` array) + `name`. All v3 and v4 payloads remain accepted byte-for-byte. New first-class fields: per-room `roomLocalId`, `pins[]`, `objects[]`, `boundaryPolygon[]`, per-wall `captureMetadata`; append-room `parentScanId`, `entryDoorwayId`, `entryDoorwayWallIndex`, `entryDoorwayPosition`; opening `position` is 2D `{x, y}` (an additional `z` is tolerated for backwards compatibility but ignored by the server). `wallConfidences` advertises the canonical nested `(number[] | null)[]` shape; the two legacy shapes (flat `number[]` and `Record<roomLocalIdOrIndex, number[]>`) are still parsed by `normalizeWallConfidences` in `server/routes/lidar.ts`. */
|
|
2144
2138
|
MobileUploadRequest: {
|
|
2139
|
+
/** @description RoomPlan JSON envelope. `rooms[]` carries the per-room geometry (walls/doors/windows/openings/pins/objects/boundaryPolygon). iOS continues to upload positions in the RoomPlan-native frame; the server applies the view-alignment intake transform once at `/scans/mobile-upload` (see docs/lidar-contract-v4.md). */
|
|
2145
2140
|
roomPlanJSON: {
|
|
2146
2141
|
rooms: {
|
|
2147
2142
|
label?: string;
|
|
2148
2143
|
name?: string;
|
|
2149
2144
|
category?: string;
|
|
2150
|
-
|
|
2145
|
+
roomLocalId?: string;
|
|
2146
|
+
walls?: {
|
|
2147
|
+
start?: {
|
|
2148
|
+
x: number;
|
|
2149
|
+
y: number;
|
|
2150
|
+
};
|
|
2151
|
+
end?: {
|
|
2152
|
+
x: number;
|
|
2153
|
+
y: number;
|
|
2154
|
+
};
|
|
2155
|
+
length?: number;
|
|
2156
|
+
height?: number;
|
|
2157
|
+
captureMetadata?: {
|
|
2158
|
+
identifier?: string;
|
|
2159
|
+
isDoor?: boolean;
|
|
2160
|
+
isOpening?: boolean;
|
|
2161
|
+
};
|
|
2162
|
+
captureMethod?: string;
|
|
2163
|
+
}[];
|
|
2151
2164
|
doors?: {
|
|
2152
2165
|
position: {
|
|
2153
2166
|
x: number;
|
|
2154
2167
|
y: number;
|
|
2155
|
-
z: number;
|
|
2156
2168
|
};
|
|
2157
2169
|
width: number;
|
|
2158
2170
|
height: number;
|
|
@@ -2167,7 +2179,6 @@ export interface components {
|
|
|
2167
2179
|
position: {
|
|
2168
2180
|
x: number;
|
|
2169
2181
|
y: number;
|
|
2170
|
-
z: number;
|
|
2171
2182
|
};
|
|
2172
2183
|
width: number;
|
|
2173
2184
|
height: number;
|
|
@@ -2182,7 +2193,6 @@ export interface components {
|
|
|
2182
2193
|
position: {
|
|
2183
2194
|
x: number;
|
|
2184
2195
|
y: number;
|
|
2185
|
-
z: number;
|
|
2186
2196
|
};
|
|
2187
2197
|
width: number;
|
|
2188
2198
|
height: number;
|
|
@@ -2193,6 +2203,35 @@ export interface components {
|
|
|
2193
2203
|
/** @enum {string} */
|
|
2194
2204
|
placementSource?: "auto" | "manual";
|
|
2195
2205
|
}[];
|
|
2206
|
+
pins?: {
|
|
2207
|
+
id: string;
|
|
2208
|
+
position: {
|
|
2209
|
+
x: number;
|
|
2210
|
+
y: number;
|
|
2211
|
+
};
|
|
2212
|
+
label?: string;
|
|
2213
|
+
roomLocalId?: string;
|
|
2214
|
+
kind?: string;
|
|
2215
|
+
note?: string;
|
|
2216
|
+
}[];
|
|
2217
|
+
objects?: {
|
|
2218
|
+
category?: string;
|
|
2219
|
+
position?: {
|
|
2220
|
+
x: number;
|
|
2221
|
+
y: number;
|
|
2222
|
+
};
|
|
2223
|
+
dimensions?: {
|
|
2224
|
+
width?: number;
|
|
2225
|
+
height?: number;
|
|
2226
|
+
depth?: number;
|
|
2227
|
+
};
|
|
2228
|
+
}[];
|
|
2229
|
+
boundaryPolygon?: {
|
|
2230
|
+
x: number;
|
|
2231
|
+
y: number;
|
|
2232
|
+
}[];
|
|
2233
|
+
roomNote?: string;
|
|
2234
|
+
entryDoorwayId?: string;
|
|
2196
2235
|
}[];
|
|
2197
2236
|
};
|
|
2198
2237
|
name: string;
|
|
@@ -2201,7 +2240,10 @@ export interface components {
|
|
|
2201
2240
|
autoMeasure?: boolean;
|
|
2202
2241
|
cleanupPipelineVersion?: string;
|
|
2203
2242
|
userOrientationHint?: string;
|
|
2204
|
-
|
|
2243
|
+
/** @description Per-room per-wall capture confidences. Canonical shape: nested `(number[] | null)[]` parallel to `roomPlanJSON.rooms[]`. Two legacy shapes are still accepted for backwards compatibility but should not be emitted by new clients: a flat `number[]` (treated as room[0] confidences) and an object keyed by `roomLocalId` (or numeric index as string). See `normalizeWallConfidences` in `server/routes/lidar.ts`. */
|
|
2244
|
+
wallConfidences?: (number[] | null)[] | number[] | {
|
|
2245
|
+
[key: string]: number[];
|
|
2246
|
+
};
|
|
2205
2247
|
deviceTrack?: unknown;
|
|
2206
2248
|
referencePhotos?: unknown[];
|
|
2207
2249
|
propertyId?: number;
|
|
@@ -2229,6 +2271,14 @@ export interface components {
|
|
|
2229
2271
|
sessionId?: string;
|
|
2230
2272
|
sessionCapturedAt?: string;
|
|
2231
2273
|
clientMirrorApplied?: boolean;
|
|
2274
|
+
parentScanId?: number;
|
|
2275
|
+
/** @description Append-room doorway link to a target room on the parent composite. Format: `scan-<scanId>-room-<roomLocalId>-(door|opening)-<idx>`. The trailing segment selects kind-specifically — `door` indexes the target room's `doors[]`, `opening` indexes `openings[]`; the two are never folded. `<scanId>` and `<roomLocalId>` must reference a scan + room on the parent composite the iOS client is appending to. */
|
|
2276
|
+
entryDoorwayId?: string;
|
|
2277
|
+
entryDoorwayWallIndex?: number;
|
|
2278
|
+
entryDoorwayPosition?: {
|
|
2279
|
+
x: number;
|
|
2280
|
+
y: number;
|
|
2281
|
+
};
|
|
2232
2282
|
};
|
|
2233
2283
|
MobileUploadResponse: {
|
|
2234
2284
|
scanId: number;
|