@serviceai/api-spec 1.6.1 → 1.6.3

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.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  openapi: 3.1.0
2
2
  info:
3
3
  title: ServiceAi API
4
- version: 1.6.1
4
+ version: 1.6.3
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
@@ -103,7 +103,7 @@ components:
103
103
  properties:
104
104
  apiVersion:
105
105
  type: string
106
- example: 1.6.1
106
+ example: 1.6.3
107
107
  minClientVersion:
108
108
  type: string
109
109
  example: 1.0.0
@@ -3496,6 +3496,60 @@ components:
3496
3496
  - action
3497
3497
  - token
3498
3498
  additionalProperties: false
3499
+ - type: object
3500
+ properties:
3501
+ action:
3502
+ type: string
3503
+ enum:
3504
+ - separate
3505
+ rooms:
3506
+ type: array
3507
+ items:
3508
+ type: object
3509
+ properties:
3510
+ id:
3511
+ type: integer
3512
+ exclusiveMinimum: 0
3513
+ revision:
3514
+ type: string
3515
+ pattern: ^[a-f0-9]{64}$
3516
+ required:
3517
+ - id
3518
+ - revision
3519
+ additionalProperties: false
3520
+ required:
3521
+ - action
3522
+ - rooms
3523
+ additionalProperties: false
3524
+ - type: object
3525
+ properties:
3526
+ action:
3527
+ type: string
3528
+ enum:
3529
+ - disconnect
3530
+ connectionId:
3531
+ type: integer
3532
+ exclusiveMinimum: 0
3533
+ rooms:
3534
+ type: array
3535
+ items:
3536
+ type: object
3537
+ properties:
3538
+ id:
3539
+ type: integer
3540
+ exclusiveMinimum: 0
3541
+ revision:
3542
+ type: string
3543
+ pattern: ^[a-f0-9]{64}$
3544
+ required:
3545
+ - id
3546
+ - revision
3547
+ additionalProperties: false
3548
+ required:
3549
+ - action
3550
+ - connectionId
3551
+ - rooms
3552
+ additionalProperties: false
3499
3553
  - type: object
3500
3554
  properties:
3501
3555
  action:
@@ -4514,6 +4568,226 @@ components:
4514
4568
  - unsortedPhotos
4515
4569
  - created
4516
4570
  description: '`data` of a successful `draft_checklist_from_job_photos` call (`success: true`).'
4571
+ AssetInitUploadRequest:
4572
+ type: object
4573
+ properties:
4574
+ filename:
4575
+ anyOf:
4576
+ - type: string
4577
+ maxLength: 10000
4578
+ - type: number
4579
+ - type: 'null'
4580
+ byteSize:
4581
+ anyOf:
4582
+ - type: number
4583
+ - type: string
4584
+ maxLength: 10000
4585
+ - type: 'null'
4586
+ clientQueueId:
4587
+ anyOf:
4588
+ - type: string
4589
+ maxLength: 10000
4590
+ - type: number
4591
+ - type: 'null'
4592
+ pendingMetadata:
4593
+ type:
4594
+ - object
4595
+ - 'null'
4596
+ additionalProperties: {}
4597
+ mimeType:
4598
+ anyOf:
4599
+ - type: string
4600
+ maxLength: 10000
4601
+ - type: number
4602
+ - type: 'null'
4603
+ contentType:
4604
+ anyOf:
4605
+ - type: string
4606
+ maxLength: 10000
4607
+ - type: number
4608
+ - type: 'null'
4609
+ poster:
4610
+ type:
4611
+ - object
4612
+ - 'null'
4613
+ properties:
4614
+ contentType:
4615
+ type: string
4616
+ enum:
4617
+ - image/jpeg
4618
+ byteSize:
4619
+ type: integer
4620
+ exclusiveMinimum: 0
4621
+ maximum: 2097152
4622
+ required:
4623
+ - contentType
4624
+ - byteSize
4625
+ description: >-
4626
+ POST /api/assets/init-upload body. `filename` and `mimeType` (alias `contentType`) are required by the handler.
4627
+ `poster` is accepted only when the upload's content type is `video/*`: a JPEG frame of at most 2 MiB the client
4628
+ renders locally and PUTs to `posterUploadUrl`; on any other content type the response is 400
4629
+ `poster_requires_video`.
4630
+ AssetInitUploadResponse:
4631
+ type: object
4632
+ properties:
4633
+ assetId:
4634
+ type: string
4635
+ key:
4636
+ type: string
4637
+ description: Storage key of the original (`org/<orgId>/assets/<assetId>/original`).
4638
+ putUrl:
4639
+ type: string
4640
+ description: Presigned PUT for the original. Absent when `alreadyCompleted` is true.
4641
+ headersToSend:
4642
+ type: object
4643
+ additionalProperties:
4644
+ type: string
4645
+ putUrlExpiresAt:
4646
+ type: string
4647
+ description: ISO instant; also the expiry of `posterUploadUrl`.
4648
+ reused:
4649
+ type: boolean
4650
+ alreadyCompleted:
4651
+ type: boolean
4652
+ posterUploadUrl:
4653
+ type: string
4654
+ description: 'Presigned PUT (Content-Type: image/jpeg) for the poster frame. Present only when `poster` was sent.'
4655
+ posterKey:
4656
+ type: string
4657
+ description: 'The poster''s storage key: the asset prefix with `/original` replaced by `/thumb_320`.'
4658
+ required:
4659
+ - assetId
4660
+ - key
4661
+ AssetCompleteUploadRequest:
4662
+ type: object
4663
+ properties:
4664
+ assetId:
4665
+ anyOf:
4666
+ - type: string
4667
+ maxLength: 10000
4668
+ - type: number
4669
+ - type: 'null'
4670
+ clientQueueId:
4671
+ anyOf:
4672
+ - type: string
4673
+ maxLength: 10000
4674
+ - type: number
4675
+ - type: 'null'
4676
+ gpsLatitude:
4677
+ anyOf:
4678
+ - type: number
4679
+ - type: string
4680
+ maxLength: 10000
4681
+ - type: 'null'
4682
+ gpsLongitude:
4683
+ anyOf:
4684
+ - type: number
4685
+ - type: string
4686
+ maxLength: 10000
4687
+ - type: 'null'
4688
+ gpsAddress:
4689
+ anyOf:
4690
+ - type: string
4691
+ maxLength: 10000
4692
+ - type: number
4693
+ - type: 'null'
4694
+ captureTimestamp:
4695
+ anyOf:
4696
+ - type: string
4697
+ - type: number
4698
+ - type: string
4699
+ format: date-time
4700
+ - type: 'null'
4701
+ deviceInfo:
4702
+ anyOf:
4703
+ - type: string
4704
+ maxLength: 10000
4705
+ - type: number
4706
+ - type: 'null'
4707
+ overlayApplied:
4708
+ anyOf:
4709
+ - type: boolean
4710
+ - type: string
4711
+ - type: number
4712
+ - type: 'null'
4713
+ hasMarkup:
4714
+ anyOf:
4715
+ - type: boolean
4716
+ - type: string
4717
+ - type: number
4718
+ - type: 'null'
4719
+ tags:
4720
+ type:
4721
+ - array
4722
+ - 'null'
4723
+ items: {}
4724
+ projectId:
4725
+ anyOf:
4726
+ - type: number
4727
+ - type: string
4728
+ maxLength: 10000
4729
+ - type: 'null'
4730
+ contactId:
4731
+ anyOf:
4732
+ - type: number
4733
+ - type: string
4734
+ maxLength: 10000
4735
+ - type: 'null'
4736
+ folderId:
4737
+ anyOf:
4738
+ - type: string
4739
+ maxLength: 10000
4740
+ - type: number
4741
+ - type: 'null'
4742
+ description:
4743
+ anyOf:
4744
+ - type: string
4745
+ maxLength: 200000
4746
+ - type: number
4747
+ - type: 'null'
4748
+ serverOverlay:
4749
+ type:
4750
+ - object
4751
+ - 'null'
4752
+ additionalProperties: {}
4753
+ capturePose:
4754
+ type:
4755
+ - object
4756
+ - 'null'
4757
+ additionalProperties: {}
4758
+ posterUploaded:
4759
+ anyOf:
4760
+ - type: boolean
4761
+ - type: string
4762
+ - type: number
4763
+ - type: 'null'
4764
+ description: >-
4765
+ POST /api/assets/complete-upload body. `assetId` or `clientQueueId` is required. `posterUploaded: true` (video
4766
+ uploads only) asks the server to verify the poster frame PUT to `posterUploadUrl` and use it as the thumbnail at
4767
+ once; a missing, oversized or non-JPEG poster never fails the upload — it completes without it.
4768
+ AssetCompleteUploadResponse:
4769
+ type: object
4770
+ properties:
4771
+ ok:
4772
+ type: boolean
4773
+ enum:
4774
+ - true
4775
+ assetId:
4776
+ type: string
4777
+ alreadyCompleted:
4778
+ type: boolean
4779
+ actions:
4780
+ type: array
4781
+ items:
4782
+ type: string
4783
+ description: >-
4784
+ Human-readable log of what finalize did (status change, links, pipeline dispatch, `thumbnail: client poster
4785
+ accepted (thumb_320)`).
4786
+ required:
4787
+ - ok
4788
+ - assetId
4789
+ - alreadyCompleted
4790
+ - actions
4517
4791
  parameters: {}
4518
4792
  paths:
4519
4793
  /api/version:
@@ -8700,4 +8974,66 @@ paths:
8700
8974
  application/json:
8701
8975
  schema:
8702
8976
  $ref: '#/components/schemas/ErrorEnvelope'
8977
+ /api/assets/init-upload:
8978
+ post:
8979
+ summary: 'Open a direct-to-S3 upload: presigned PUT for the original, and for a video''s optional poster frame.'
8980
+ tags:
8981
+ - photos
8982
+ parameters:
8983
+ - *ref_0
8984
+ requestBody:
8985
+ required: true
8986
+ content:
8987
+ application/json:
8988
+ schema:
8989
+ $ref: '#/components/schemas/AssetInitUploadRequest'
8990
+ responses:
8991
+ '200':
8992
+ description: Presigned URL(s) and the asset id to pass to complete-upload.
8993
+ content:
8994
+ application/json:
8995
+ schema:
8996
+ $ref: '#/components/schemas/AssetInitUploadResponse'
8997
+ '400':
8998
+ description: Missing filename/mimeType, or a `poster` on a non-video upload (`poster_requires_video`).
8999
+ content:
9000
+ application/json:
9001
+ schema:
9002
+ $ref: '#/components/schemas/ErrorEnvelope'
9003
+ '401':
9004
+ description: Authentication required.
9005
+ '413':
9006
+ description: File larger than the single-PUT limit.
9007
+ /api/assets/complete-upload:
9008
+ post:
9009
+ summary: Mark a direct upload complete (idempotent); link it to a job/contact; dispatch processing.
9010
+ tags:
9011
+ - photos
9012
+ parameters:
9013
+ - *ref_0
9014
+ requestBody:
9015
+ required: true
9016
+ content:
9017
+ application/json:
9018
+ schema:
9019
+ $ref: '#/components/schemas/AssetCompleteUploadRequest'
9020
+ responses:
9021
+ '200':
9022
+ description: Finalized (or already was).
9023
+ content:
9024
+ application/json:
9025
+ schema:
9026
+ $ref: '#/components/schemas/AssetCompleteUploadResponse'
9027
+ '400':
9028
+ description: Neither assetId nor clientQueueId.
9029
+ content:
9030
+ application/json:
9031
+ schema:
9032
+ $ref: '#/components/schemas/ErrorEnvelope'
9033
+ '401':
9034
+ description: Authentication required.
9035
+ '403':
9036
+ description: Attaching to a job/contact without the Upload Files permission.
9037
+ '404':
9038
+ description: Asset, job or contact not found in the organization.
8703
9039
  webhooks: {}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@serviceai/api-spec",
3
- "version": "1.6.1",
3
+ "version": "1.6.3",
4
4
  "description": "ServiceAi OpenAPI 3.1 contract + generated TS types. Auto-published from the desktop repo.",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
package/types.d.ts CHANGED
@@ -4237,6 +4237,145 @@ export interface paths {
4237
4237
  patch?: never;
4238
4238
  trace?: never;
4239
4239
  };
4240
+ "/api/assets/init-upload": {
4241
+ parameters: {
4242
+ query?: never;
4243
+ header?: never;
4244
+ path?: never;
4245
+ cookie?: never;
4246
+ };
4247
+ get?: never;
4248
+ put?: never;
4249
+ /** Open a direct-to-S3 upload: presigned PUT for the original, and for a video's optional poster frame. */
4250
+ post: {
4251
+ parameters: {
4252
+ query?: never;
4253
+ header?: {
4254
+ /** @description Semver of the calling app build. Drives the 426 / soft-upgrade handshake. */
4255
+ "X-Client-Version"?: string;
4256
+ };
4257
+ path?: never;
4258
+ cookie?: never;
4259
+ };
4260
+ requestBody: {
4261
+ content: {
4262
+ "application/json": components["schemas"]["AssetInitUploadRequest"];
4263
+ };
4264
+ };
4265
+ responses: {
4266
+ /** @description Presigned URL(s) and the asset id to pass to complete-upload. */
4267
+ 200: {
4268
+ headers: {
4269
+ [name: string]: unknown;
4270
+ };
4271
+ content: {
4272
+ "application/json": components["schemas"]["AssetInitUploadResponse"];
4273
+ };
4274
+ };
4275
+ /** @description Missing filename/mimeType, or a `poster` on a non-video upload (`poster_requires_video`). */
4276
+ 400: {
4277
+ headers: {
4278
+ [name: string]: unknown;
4279
+ };
4280
+ content: {
4281
+ "application/json": components["schemas"]["ErrorEnvelope"];
4282
+ };
4283
+ };
4284
+ /** @description Authentication required. */
4285
+ 401: {
4286
+ headers: {
4287
+ [name: string]: unknown;
4288
+ };
4289
+ content?: never;
4290
+ };
4291
+ /** @description File larger than the single-PUT limit. */
4292
+ 413: {
4293
+ headers: {
4294
+ [name: string]: unknown;
4295
+ };
4296
+ content?: never;
4297
+ };
4298
+ };
4299
+ };
4300
+ delete?: never;
4301
+ options?: never;
4302
+ head?: never;
4303
+ patch?: never;
4304
+ trace?: never;
4305
+ };
4306
+ "/api/assets/complete-upload": {
4307
+ parameters: {
4308
+ query?: never;
4309
+ header?: never;
4310
+ path?: never;
4311
+ cookie?: never;
4312
+ };
4313
+ get?: never;
4314
+ put?: never;
4315
+ /** Mark a direct upload complete (idempotent); link it to a job/contact; dispatch processing. */
4316
+ post: {
4317
+ parameters: {
4318
+ query?: never;
4319
+ header?: {
4320
+ /** @description Semver of the calling app build. Drives the 426 / soft-upgrade handshake. */
4321
+ "X-Client-Version"?: string;
4322
+ };
4323
+ path?: never;
4324
+ cookie?: never;
4325
+ };
4326
+ requestBody: {
4327
+ content: {
4328
+ "application/json": components["schemas"]["AssetCompleteUploadRequest"];
4329
+ };
4330
+ };
4331
+ responses: {
4332
+ /** @description Finalized (or already was). */
4333
+ 200: {
4334
+ headers: {
4335
+ [name: string]: unknown;
4336
+ };
4337
+ content: {
4338
+ "application/json": components["schemas"]["AssetCompleteUploadResponse"];
4339
+ };
4340
+ };
4341
+ /** @description Neither assetId nor clientQueueId. */
4342
+ 400: {
4343
+ headers: {
4344
+ [name: string]: unknown;
4345
+ };
4346
+ content: {
4347
+ "application/json": components["schemas"]["ErrorEnvelope"];
4348
+ };
4349
+ };
4350
+ /** @description Authentication required. */
4351
+ 401: {
4352
+ headers: {
4353
+ [name: string]: unknown;
4354
+ };
4355
+ content?: never;
4356
+ };
4357
+ /** @description Attaching to a job/contact without the Upload Files permission. */
4358
+ 403: {
4359
+ headers: {
4360
+ [name: string]: unknown;
4361
+ };
4362
+ content?: never;
4363
+ };
4364
+ /** @description Asset, job or contact not found in the organization. */
4365
+ 404: {
4366
+ headers: {
4367
+ [name: string]: unknown;
4368
+ };
4369
+ content?: never;
4370
+ };
4371
+ };
4372
+ };
4373
+ delete?: never;
4374
+ options?: never;
4375
+ head?: never;
4376
+ patch?: never;
4377
+ trace?: never;
4378
+ };
4240
4379
  }
4241
4380
  export type webhooks = Record<string, never>;
4242
4381
  export interface components {
@@ -4261,7 +4400,7 @@ export interface components {
4261
4400
  };
4262
4401
  /** @description Cross-platform version handshake manifest. See docs/api-versioning.md. */
4263
4402
  VersionManifest: {
4264
- /** @example 1.6.1 */
4403
+ /** @example 1.6.3 */
4265
4404
  apiVersion: string;
4266
4405
  /** @example 1.0.0 */
4267
4406
  minClientVersion: string;
@@ -5419,6 +5558,21 @@ export interface components {
5419
5558
  /** @enum {string} */
5420
5559
  action: "undo";
5421
5560
  token: string;
5561
+ } | {
5562
+ /** @enum {string} */
5563
+ action: "separate";
5564
+ rooms: {
5565
+ id: number;
5566
+ revision: string;
5567
+ }[];
5568
+ } | {
5569
+ /** @enum {string} */
5570
+ action: "disconnect";
5571
+ connectionId: number;
5572
+ rooms: {
5573
+ id: number;
5574
+ revision: string;
5575
+ }[];
5422
5576
  } | {
5423
5577
  /** @enum {string} */
5424
5578
  action: "connect";
@@ -5724,6 +5878,72 @@ export interface components {
5724
5878
  unsortedPhotos: number;
5725
5879
  created: boolean;
5726
5880
  };
5881
+ /** @description POST /api/assets/init-upload body. `filename` and `mimeType` (alias `contentType`) are required by the handler. `poster` is accepted only when the upload's content type is `video/*`: a JPEG frame of at most 2 MiB the client renders locally and PUTs to `posterUploadUrl`; on any other content type the response is 400 `poster_requires_video`. */
5882
+ AssetInitUploadRequest: {
5883
+ filename?: string | number | null;
5884
+ byteSize?: number | string | null;
5885
+ clientQueueId?: string | number | null;
5886
+ pendingMetadata?: {
5887
+ [key: string]: unknown;
5888
+ } | null;
5889
+ mimeType?: string | number | null;
5890
+ contentType?: string | number | null;
5891
+ poster?: {
5892
+ /** @enum {string} */
5893
+ contentType: "image/jpeg";
5894
+ byteSize: number;
5895
+ } | null;
5896
+ };
5897
+ AssetInitUploadResponse: {
5898
+ assetId: string;
5899
+ /** @description Storage key of the original (`org/<orgId>/assets/<assetId>/original`). */
5900
+ key: string;
5901
+ /** @description Presigned PUT for the original. Absent when `alreadyCompleted` is true. */
5902
+ putUrl?: string;
5903
+ headersToSend?: {
5904
+ [key: string]: string;
5905
+ };
5906
+ /** @description ISO instant; also the expiry of `posterUploadUrl`. */
5907
+ putUrlExpiresAt?: string;
5908
+ reused?: boolean;
5909
+ alreadyCompleted?: boolean;
5910
+ /** @description Presigned PUT (Content-Type: image/jpeg) for the poster frame. Present only when `poster` was sent. */
5911
+ posterUploadUrl?: string;
5912
+ /** @description The poster's storage key: the asset prefix with `/original` replaced by `/thumb_320`. */
5913
+ posterKey?: string;
5914
+ };
5915
+ /** @description POST /api/assets/complete-upload body. `assetId` or `clientQueueId` is required. `posterUploaded: true` (video uploads only) asks the server to verify the poster frame PUT to `posterUploadUrl` and use it as the thumbnail at once; a missing, oversized or non-JPEG poster never fails the upload — it completes without it. */
5916
+ AssetCompleteUploadRequest: {
5917
+ assetId?: string | number | null;
5918
+ clientQueueId?: string | number | null;
5919
+ gpsLatitude?: number | string | null;
5920
+ gpsLongitude?: number | string | null;
5921
+ gpsAddress?: string | number | null;
5922
+ captureTimestamp?: string | number | null;
5923
+ deviceInfo?: string | number | null;
5924
+ overlayApplied?: boolean | string | number | null;
5925
+ hasMarkup?: boolean | string | number | null;
5926
+ tags?: unknown[] | null;
5927
+ projectId?: number | string | null;
5928
+ contactId?: number | string | null;
5929
+ folderId?: string | number | null;
5930
+ description?: string | number | null;
5931
+ serverOverlay?: {
5932
+ [key: string]: unknown;
5933
+ } | null;
5934
+ capturePose?: {
5935
+ [key: string]: unknown;
5936
+ } | null;
5937
+ posterUploaded?: boolean | string | number | null;
5938
+ };
5939
+ AssetCompleteUploadResponse: {
5940
+ /** @enum {boolean} */
5941
+ ok: true;
5942
+ assetId: string;
5943
+ alreadyCompleted: boolean;
5944
+ /** @description Human-readable log of what finalize did (status change, links, pipeline dispatch, `thumbnail: client poster accepted (thumb_320)`). */
5945
+ actions: string[];
5946
+ };
5727
5947
  };
5728
5948
  responses: never;
5729
5949
  parameters: never;