@matech/thebigpos-sdk 3.5.2 → 3.6.0-stag-2655

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.
@@ -1,209 +1,56 @@
1
- /*
2
- Post-generation fixup for the generated TypeScript SDK.
1
+ /*
2
+ This script is meant to run after the SDK has been generated.
3
3
 
4
- swagger-typescript-api does not propagate the `application/json-patch+json`
5
- request content type into the generated code, so PATCH methods that use JSON
6
- Patch would otherwise go out with the wrong Content-Type. This script restores
7
- it by reading the OpenAPI spec the SDK was generated from and, for every
8
- generated PATCH method, setting:
4
+ - It updates the generated code to ensure that all PATCH methods use ContentType.JsonPatch.
5
+ - It also ensures that the ContentType enum includes JsonPatch and modifies the Operation interface
6
+ to allow any value for the `value` property instead of just object or null.
9
7
 
10
- - ContentType.JsonPatch -> when the spec's requestBody for that path
11
- advertises application/json-patch+json
12
- - ContentType.Json -> for every other PATCH method
13
- (e.g. updateLoan, which the backend declares as
14
- [Consumes("application/json")])
15
-
16
- The decision is taken entirely from the spec — there is no hard-coded list of
17
- endpoints to keep in sync. It also ensures the ContentType enum includes
18
- JsonPatch and relaxes the Operation interface `value` to accept any value.
19
-
20
- It additionally teaches `createFormData` to recognise React Native files. The
21
- generator assumes a browser and detects file parts with `instanceof Blob ||
22
- instanceof File`; in React Native a file is a plain `{ uri, name, type }`
23
- object, so without the extra branch every mobile upload is serialised as the
24
- string "[object Object]". This used to live as a patch-package patch in
25
- pos-mobile-v2, which had to be re-created on every SDK bump.
26
-
27
- Usage (pass the SAME spec given to `swagger-typescript-api -p`):
28
- node scripts/apply-json-patch-content-type.js https://api.thebigpos.dev/swagger/<version>/swagger.json
29
- node scripts/apply-json-patch-content-type.js ./swagger.json
30
- SWAGGER_SPEC=<url-or-file> node scripts/apply-json-patch-content-type.js
31
-
32
- Design notes:
33
- - The rewrite is scoped to a single generated method block at a time
34
- (anchored on that method's own `...params,`), so it can never bleed across
35
- method boundaries.
36
- - It sets each method's content type to its target value rather than doing a
37
- conditional replace, so it is idempotent and self-healing (it also repairs
38
- a previously-seen ContentType.JsonPatchPatch double-application).
39
- - If no spec is provided (e.g. a plain commit-hook run), the content-type
40
- rewrite is skipped instead of guessing, so it can never silently corrupt
41
- the generated output.
8
+ This is necessary because the SDK generation does not currently handle these cases correctly.
42
9
  */
43
10
 
44
11
  const fs = require('fs')
45
- const nodePath = require('path')
46
12
 
47
- const SRC = nodePath.resolve(__dirname, '../src/index.ts')
13
+ const path = require('path').resolve(__dirname, '../src/index.ts')
48
14
 
49
- async function loadSpec(source) {
50
- if (!source) return null
51
- if (/^https?:\/\//i.test(source)) {
52
- const res = await fetch(source)
53
- if (!res.ok) throw new Error(`Failed to fetch spec from "${source}": HTTP ${res.status}`)
54
- return res.json()
55
- }
56
- return JSON.parse(fs.readFileSync(nodePath.resolve(source), 'utf8'))
57
- }
58
-
59
- // Collapse spec ("{id}") and generated ("${id}") path params to a common token
60
- // so generated paths can be matched against spec paths regardless of param names.
61
- function normalizePath(p) {
62
- return p.replace(/\$\{[^}]+\}/g, '{}').replace(/\{[^}]+\}/g, '{}')
15
+ if (!fs.existsSync(path)) {
16
+ console.error(`Error: File not found at path "${path}". Please ensure the SDK has been generated.`)
17
+ process.exit(1)
63
18
  }
64
-
65
- function jsonPatchPaths(spec) {
66
- const set = new Set()
67
- for (const [route, ops] of Object.entries(spec.paths || {})) {
68
- const content = ops && ops.patch && ops.patch.requestBody && ops.patch.requestBody.content
69
- if (content && Object.prototype.hasOwnProperty.call(content, 'application/json-patch+json')) {
70
- set.add(normalizePath(route))
71
- }
72
- }
73
- return set
19
+ let content
20
+ try {
21
+ content = fs.readFileSync(path, 'utf8')
22
+ } catch (err) {
23
+ console.error(`Error: Unable to read file at path "${path}". Details: ${err.message}`)
24
+ process.exit(1)
74
25
  }
75
26
 
76
- function setContentType(block, member) {
77
- const target = `type: ContentType.${member}`
78
- if (/type:\s*ContentType\.\w+/.test(block)) return block.replace(/type:\s*ContentType\.\w+/, target)
79
- if (/type:\s*"[^"]*"/.test(block)) return block.replace(/type:\s*"[^"]*"/, target)
80
- if (/\n(\s*)format:/.test(block)) return block.replace(/\n(\s*)format:/, `\n$1${target},\n$1format:`)
81
- return block.replace(/\n(\s*)\.\.\.params,/, `\n$1${target},\n$1...params,`)
82
- }
27
+ // Update PATCH methods to use ContentType.JsonPatch
28
+ content = content.replace(
29
+ /(method:\s*"PATCH"[\s\S]+?)type:\s*ContentType\.Json/g,
30
+ (match) => match.replace('ContentType.Json', 'ContentType.JsonPatch')
31
+ )
83
32
 
84
- function ensureJsonPatchEnum(content) {
85
- return content.replace(/export enum ContentType\s*{([\s\S]*?)}/, (match, enumBody) => {
33
+ // Ensure JsonPatch is included in the ContentType enum
34
+ content = content.replace(
35
+ /export enum ContentType\s*{([\s\S]*?)}/,
36
+ (match, enumBody) => {
86
37
  if (enumBody.includes('JsonPatch')) return match
87
- return `export enum ContentType {\n JsonPatch = "application/json-patch+json",\n ${enumBody.trim()}\n}`
88
- })
89
- }
38
+ const insertion = ` JsonPatch = "application/json-patch+json",\n `
39
+ return `export enum ContentType {\n${insertion}${enumBody.trim()}\n}`
40
+ }
41
+ )
90
42
 
91
- function relaxOperationValue(content) {
92
- return content.replace(/export interface Operation\s*{([\s\S]*?)}/, (match, body) => {
43
+ // Fix the Operation interface to allow any value
44
+ content = content.replace(
45
+ /export interface Operation\s*{([\s\S]*?)}/,
46
+ (match, body) => {
93
47
  const updated = body.replace(
94
48
  /value\?:\s*object\s*\|?\s*null?;/,
95
49
  'value?: string | number | boolean | null | object;'
96
50
  )
97
51
  return `export interface Operation {\n ${updated.trim()}\n}`
98
- })
99
- }
100
-
101
- const RN_FILE_MARKER = 'isReactNativeFile'
102
-
103
- // swagger-typescript-api assumes a browser: it detects multipart file parts with
104
- // `instanceof Blob || instanceof File`. React Native has neither in a usable form —
105
- // a file there is a plain `{ uri, name, type }` object. Without this branch those
106
- // objects fall through to `stringifyFormItem` and every upload from the mobile app
107
- // goes out as the string "[object Object]".
108
- //
109
- // The React Native check runs first so the `instanceof` operands are never even
110
- // evaluated on that path.
111
- //
112
- // The pattern is deliberately whitespace-tolerant instead of matching one exact
113
- // line. As generated today that statement is exactly 80 characters wide, which is
114
- // Prettier's default printWidth — so the moment the generator nests it one level
115
- // deeper, or renames `formItem`, Prettier reflows it across two lines. Anchoring
116
- // on the single-line form would then quietly stop matching.
117
- const GENERATED_FILE_CHECK =
118
- /^([ \t]*)const isFileType\s*=\s*formItem instanceof Blob\s*\|\|\s*formItem instanceof File;/m
119
-
120
- function applyReactNativeFileSupport(content) {
121
- if (content.includes(RN_FILE_MARKER)) return content
122
-
123
- // Never fail open. A silent no-op here ships an SDK where every React Native
124
- // upload is serialised as "[object Object]", with nothing in the build to
125
- // suggest anything went wrong.
126
- if (!GENERATED_FILE_CHECK.test(content)) {
127
- throw new Error(
128
- 'applyReactNativeFileSupport: could not find the generated `isFileType` check in ' +
129
- 'createFormData.\n' +
130
- 'swagger-typescript-api has most likely changed its output. Update ' +
131
- 'GENERATED_FILE_CHECK in this script — do not skip this step, or React Native ' +
132
- 'file uploads will break with no visible error.'
133
- )
134
- }
135
-
136
- return content.replace(
137
- GENERATED_FILE_CHECK,
138
- (match, indent) =>
139
- [
140
- `${indent}// React Native files are plain { uri, name, type } objects, not Blob/File.`,
141
- `${indent}const ${RN_FILE_MARKER} =`,
142
- `${indent} !!formItem &&`,
143
- `${indent} typeof formItem === "object" &&`,
144
- `${indent} "uri" in formItem &&`,
145
- `${indent} "name" in formItem &&`,
146
- `${indent} "type" in formItem;`,
147
- `${indent}const isFileType =`,
148
- `${indent} ${RN_FILE_MARKER} || formItem instanceof Blob || formItem instanceof File;`,
149
- ].join('\n')
150
- )
151
- }
152
-
153
- function applyContentTypes(content, patchPaths) {
154
- // Heal any earlier double-application (ContentType.JsonPatchPatch...).
155
- content = content.replace(/ContentType\.JsonPatch(?:Patch)+\b/g, 'ContentType.JsonPatch')
156
-
157
- const METHOD_BLOCK = /[a-zA-Z0-9_]+:\s*\([\s\S]*?\)\s*=>\s*this\.request<[^>]*>\(\{[\s\S]*?\.\.\.params,/g
158
- return content.replace(METHOD_BLOCK, (block) => {
159
- if (!/method:\s*"PATCH"/.test(block)) {
160
- // Non-PATCH methods must never be JSON Patch.
161
- return /type:\s*ContentType\.JsonPatch\b/.test(block)
162
- ? block.replace(/type:\s*ContentType\.JsonPatch\b/, 'type: ContentType.Json')
163
- : block
164
- }
165
- const routeMatch = block.match(/path:\s*`([^`]*)`/)
166
- const route = routeMatch ? normalizePath(routeMatch[1]) : ''
167
- return setContentType(block, patchPaths.has(route) ? 'JsonPatch' : 'Json')
168
- })
169
- }
170
-
171
- ;(async () => {
172
- if (!fs.existsSync(SRC)) {
173
- console.error(`Error: File not found at "${SRC}". Generate the SDK first.`)
174
- process.exit(1)
175
52
  }
53
+ )
176
54
 
177
- const source = process.argv[2] || process.env.SWAGGER_SPEC || process.env.SWAGGER_URL
178
- let spec
179
- try {
180
- spec = await loadSpec(source)
181
- } catch (err) {
182
- console.error(`Error loading OpenAPI spec: ${err.message}`)
183
- process.exit(1)
184
- }
185
-
186
- let content = fs.readFileSync(SRC, 'utf8')
187
- content = ensureJsonPatchEnum(content)
188
- content = relaxOperationValue(content)
189
- content = applyReactNativeFileSupport(content)
190
-
191
- if (!spec) {
192
- console.warn(
193
- 'No OpenAPI spec provided (argument / SWAGGER_SPEC / SWAGGER_URL) — skipping PATCH content-type rewrite.\n' +
194
- 'Re-run with the spec used for generation to apply it, e.g.:\n' +
195
- ' node scripts/apply-json-patch-content-type.js https://api.thebigpos.dev/swagger/<version>/swagger.json'
196
- )
197
- fs.writeFileSync(SRC, content)
198
- return
199
- }
200
-
201
- const patchPaths = jsonPatchPaths(spec)
202
- content = applyContentTypes(content, patchPaths)
203
-
204
- fs.writeFileSync(SRC, content)
205
- console.log(`SDK patch complete: PATCH content types set from the OpenAPI spec (${patchPaths.size} json-patch endpoint(s)).`)
206
- })().catch((err) => {
207
- console.error(err)
208
- process.exit(1)
209
- })
55
+ fs.writeFileSync(path, content)
56
+ console.log('SDK patch complete: All PATCH methods now use ContentType.JsonPatch.')
package/src/index.ts CHANGED
@@ -402,6 +402,8 @@ export type LoanDocumentType =
402
402
  | "AiGeneratedDocument"
403
403
  | "Unidentified";
404
404
 
405
+ export type LoanDocumentFolderScope = "Any" | "Assigned" | "Unassigned";
406
+
405
407
  export type LoanDocumentFolderPermissionLevel =
406
408
  | "None"
407
409
  | "Read"
@@ -537,7 +539,7 @@ export type CompanyDocumentIndexStatus =
537
539
 
538
540
  export type ClassificationSource = "Textract" | "Llm" | "Manual";
539
541
 
540
- export type BulkLoanTaskOperationType = "SetStatus" | "Delete";
542
+ export type BulkLoanTaskOperationType = "SetStatus" | "Delete" | "SetDueDate";
541
543
 
542
544
  export type BranchType = "Mortgage" | "RealEstate";
543
545
 
@@ -1705,6 +1707,8 @@ export interface BulkLoanTaskOperationRequest {
1705
1707
  operation?: BulkLoanTaskOperationType | null;
1706
1708
  status?: TaskStatus | null;
1707
1709
  comment?: string | null;
1710
+ /** @format date */
1711
+ dueDate?: string | null;
1708
1712
  }
1709
1713
 
1710
1714
  export interface BusinessRule {
@@ -3139,6 +3143,13 @@ export interface GuidPatchOperation {
3139
3143
  from?: string | null;
3140
3144
  }
3141
3145
 
3146
+ export interface HttpError {
3147
+ logId?: string | null;
3148
+ message?: string | null;
3149
+ errorCode?: string | null;
3150
+ errors?: string[] | null;
3151
+ }
3152
+
3142
3153
  export interface IPAddress {
3143
3154
  addressFamily: IpAddressAddressFamilyEnum;
3144
3155
  /** @format int64 */
@@ -3762,6 +3773,8 @@ export interface LoanBorrowerEmploymentCurrentGrossIncome {
3762
3773
  /** @format double */
3763
3774
  hourlyRate?: number | null;
3764
3775
  /** @format double */
3776
+ annualBasePay?: number | null;
3777
+ /** @format double */
3765
3778
  other?: number | null;
3766
3779
  /** @format double */
3767
3780
  bonus?: number | null;
@@ -4361,6 +4374,8 @@ export interface LoanDocument {
4361
4374
  losStatus: string;
4362
4375
  contents?: string | null;
4363
4376
  failoverDocumentPath?: string | null;
4377
+ /** @format int64 */
4378
+ fileSizeBytes?: number | null;
4364
4379
  /** @format date-time */
4365
4380
  sensitiveDataPurgedOn?: string | null;
4366
4381
  observedDocumentType?: LoanDocumentType | null;
@@ -4437,6 +4452,7 @@ export interface LoanDocumentFolderWithCount {
4437
4452
  isActive: boolean;
4438
4453
  /** @format int32 */
4439
4454
  documentCount: number;
4455
+ isUnassigned: boolean;
4440
4456
  }
4441
4457
 
4442
4458
  export interface LoanDocumentPreviewsRequest {
@@ -4477,6 +4493,7 @@ export interface LoanDocumentSearchCriteria {
4477
4493
  bucket?: string | null;
4478
4494
  /** @format uuid */
4479
4495
  folderID?: string | null;
4496
+ folderScope?: LoanDocumentFolderScope | null;
4480
4497
  /** @format uuid */
4481
4498
  userID?: string | null;
4482
4499
  documentIDs?: string[] | null;
@@ -6756,6 +6773,7 @@ export interface Task {
6756
6773
  description?: string | null;
6757
6774
  type: string;
6758
6775
  losTarget?: string | null;
6776
+ loanDocumentFolder?: LoanDocumentFolderSummary | null;
6759
6777
  targetUserRole?: string | null;
6760
6778
  /** @format int32 */
6761
6779
  daysDueFromApplication?: number | null;
@@ -6808,6 +6826,8 @@ export interface TaskRequest {
6808
6826
  name: string;
6809
6827
  description?: string | null;
6810
6828
  losTarget?: string | null;
6829
+ /** @format uuid */
6830
+ loanDocumentFolderID?: string | null;
6811
6831
  type: string;
6812
6832
  targetUserRole?: string | null;
6813
6833
  /** @format int32 */
@@ -6832,6 +6852,8 @@ export interface TaskUpdateRequest {
6832
6852
  name: string;
6833
6853
  description?: string | null;
6834
6854
  losTarget?: string | null;
6855
+ /** @format uuid */
6856
+ loanDocumentFolderID?: string | null;
6835
6857
  type: string;
6836
6858
  targetUserRole?: string | null;
6837
6859
  /** @format int32 */
@@ -8580,15 +8602,7 @@ export class HttpClient<SecurityDataType = unknown> {
8580
8602
  property instanceof Array ? property : [property];
8581
8603
 
8582
8604
  for (const formItem of propertyContent) {
8583
- // React Native files are plain { uri, name, type } objects, not Blob/File.
8584
- const isReactNativeFile =
8585
- !!formItem &&
8586
- typeof formItem === "object" &&
8587
- "uri" in formItem &&
8588
- "name" in formItem &&
8589
- "type" in formItem;
8590
- const isFileType =
8591
- isReactNativeFile || formItem instanceof Blob || formItem instanceof File;
8605
+ const isFileType = formItem instanceof Blob || formItem instanceof File;
8592
8606
  formData.append(
8593
8607
  key,
8594
8608
  isFileType ? formItem : this.stringifyFormItem(formItem),
@@ -8650,7 +8664,7 @@ export class HttpClient<SecurityDataType = unknown> {
8650
8664
 
8651
8665
  /**
8652
8666
  * @title The Big POS API
8653
- * @version v3.5.2
8667
+ * @version v3.6.0
8654
8668
  * @termsOfService https://www.thebigpos.com/terms-of-use/
8655
8669
  * @contact Mortgage Automation Technologies <support@thebigpos.com> (https://www.thebigpos.com/terms-of-use/)
8656
8670
  */
@@ -14396,10 +14410,11 @@ export class Api<
14396
14410
  * @request POST:/api/listings
14397
14411
  * @secure
14398
14412
  * @response `201` `Listing` Created
14399
- * @response `403` `ProblemDetails` Forbidden
14413
+ * @response `401` `HttpError` Unauthorized
14414
+ * @response `403` `HttpError` Forbidden
14400
14415
  */
14401
14416
  createListing: (data: ListingRequest, params: RequestParams = {}) =>
14402
- this.request<Listing, ProblemDetails>({
14417
+ this.request<Listing, HttpError>({
14403
14418
  path: `/api/listings`,
14404
14419
  method: "POST",
14405
14420
  body: data,
@@ -14456,14 +14471,15 @@ export class Api<
14456
14471
  * @request PUT:/api/listings/{id}
14457
14472
  * @secure
14458
14473
  * @response `200` `Listing` OK
14459
- * @response `403` `ProblemDetails` Forbidden
14474
+ * @response `401` `HttpError` Unauthorized
14475
+ * @response `403` `HttpError` Forbidden
14460
14476
  */
14461
14477
  replaceListing: (
14462
14478
  id: string,
14463
14479
  data: ListingRequest,
14464
14480
  params: RequestParams = {},
14465
14481
  ) =>
14466
- this.request<Listing, ProblemDetails>({
14482
+ this.request<Listing, HttpError>({
14467
14483
  path: `/api/listings/${id}`,
14468
14484
  method: "PUT",
14469
14485
  body: data,
@@ -15054,7 +15070,7 @@ export class Api<
15054
15070
  }),
15055
15071
 
15056
15072
  /**
15057
- * @description Returns each folder that holds at least one document the caller can read, with the document count per folder. Documents that are not assigned to a folder are returned as a synthetic 'Unassigned' folder (ID = empty GUID).
15073
+ * @description Returns each folder that holds at least one document the caller can read, with the document count per folder. Documents that are not assigned to a folder are returned as a synthetic 'Unassigned' folder (ID = empty GUID, isUnassigned = true); filter to its documents with searchLoanDocuments folderScope 'Unassigned' rather than by echoing that ID.
15058
15074
  *
15059
15075
  * @tags LoanDocumentFoldersForSingleLoan
15060
15076
  * @name ListLoanDocumentFolders
@@ -15159,7 +15175,7 @@ export class Api<
15159
15175
  }),
15160
15176
 
15161
15177
  /**
15162
- * No description
15178
+ * @description Filters the loan's readable documents. Pass folderID to filter to one folder, or folderScope 'Unassigned' for the documents that have no folder (the synthetic folder listLoanDocumentFolders reports with isUnassigned true); the two cannot be combined.
15163
15179
  *
15164
15180
  * @tags LoanDocuments
15165
15181
  * @name SearchLoanDocuments
@@ -15167,6 +15183,7 @@ export class Api<
15167
15183
  * @request POST:/api/loans/{loanId}/documents/search
15168
15184
  * @secure
15169
15185
  * @response `200` `LoanDocumentSearchPaginated` OK
15186
+ * @response `422` `UnprocessableEntity` Unprocessable Content
15170
15187
  */
15171
15188
  searchLoanDocuments: (
15172
15189
  loanId: string,
@@ -15181,7 +15198,7 @@ export class Api<
15181
15198
  },
15182
15199
  params: RequestParams = {},
15183
15200
  ) =>
15184
- this.request<LoanDocumentSearchPaginated, any>({
15201
+ this.request<LoanDocumentSearchPaginated, UnprocessableEntity>({
15185
15202
  path: `/api/loans/${loanId}/documents/search`,
15186
15203
  method: "POST",
15187
15204
  query: query,
@@ -16470,6 +16487,7 @@ export class Api<
16470
16487
  * @secure
16471
16488
  * @response `201` `TaskComment` Created
16472
16489
  * @response `404` `ProblemDetails` Not Found
16490
+ * @response `422` `UnprocessableEntity` Unprocessable Content
16473
16491
  */
16474
16492
  createLoanTaskComment: (
16475
16493
  loanId: string,
@@ -16477,7 +16495,7 @@ export class Api<
16477
16495
  data: TaskCommentRequest,
16478
16496
  params: RequestParams = {},
16479
16497
  ) =>
16480
- this.request<TaskComment, ProblemDetails>({
16498
+ this.request<TaskComment, ProblemDetails | UnprocessableEntity>({
16481
16499
  path: `/api/loans/${loanId}/tasks/${userLoanTaskId}/comments`,
16482
16500
  method: "POST",
16483
16501
  body: data,
@@ -16497,6 +16515,7 @@ export class Api<
16497
16515
  * @secure
16498
16516
  * @response `200` `TaskComment` OK
16499
16517
  * @response `404` `ProblemDetails` Not Found
16518
+ * @response `422` `UnprocessableEntity` Unprocessable Content
16500
16519
  */
16501
16520
  replaceLoanTaskComment: (
16502
16521
  loanId: string,
@@ -16505,7 +16524,7 @@ export class Api<
16505
16524
  data: TaskCommentRequest,
16506
16525
  params: RequestParams = {},
16507
16526
  ) =>
16508
- this.request<TaskComment, ProblemDetails>({
16527
+ this.request<TaskComment, ProblemDetails | UnprocessableEntity>({
16509
16528
  path: `/api/loans/${loanId}/tasks/${userLoanTaskId}/comments/${commentId}`,
16510
16529
  method: "PUT",
16511
16530
  body: data,
@@ -1,149 +0,0 @@
1
- # Publishing the POS Typescript SDK
2
-
3
- ## Prerequisites
4
-
5
- 1. Clone the repository (if you haven't already):
6
-
7
- ```bash
8
- git clone https://github.com/MortgageAutomationTechnologies/thebigpos-sdk-typescript
9
- cd thebigpos-sdk-typescript
10
- ```
11
-
12
- 2. Install swagger-typescript-api globally:
13
-
14
- ```bash
15
- npm i -g swagger-typescript-api
16
- ```
17
-
18
- 3. Connect to the MAT VPN
19
-
20
- ## Step 1: Create a release branch
21
-
22
- Create a new branch for the version you're releasing:
23
-
24
- ```bash
25
- git checkout develop
26
- git pull origin develop
27
- git checkout -b release/X.Y.Z
28
- ```
29
-
30
- ## Step 2: Generate the SDK
31
-
32
- Replace `{version}` with the target API version (e.g., `v2.31.0`):
33
-
34
- ```bash
35
- npx swagger-typescript-api generate -p https://api.thebigpos.dev/swagger/{version}/swagger.json -o ./src -n index.ts -r true --axios --enum-names-as-values --generate-union-enums
36
- ```
37
-
38
- > **Note:** If generating locally, use `http://localhost:5212/swagger/{version}/swagger.json` due to self-signed cert issues with https.
39
-
40
- ## Step 3: Apply post-generation fixes
41
-
42
- Run the script to fix PATCH methods content type and Operation interface:
43
-
44
- ```bash
45
- node scripts/apply-json-patch-content-type.js
46
- ```
47
-
48
- This script:
49
- - Sets all PATCH methods to use `ContentType.JsonPatch`
50
- - Adds `JsonPatch` to the `ContentType` enum
51
- - Fixes the `Operation` interface to allow any value type
52
-
53
- ## Step 4: Update the version
54
-
55
- Use npm's version command to update the version in `package.json`:
56
-
57
- ```bash
58
- npm version X.Y.Z
59
- ```
60
-
61
- **Version conventions:**
62
-
63
- - Match the SDK version to the API version being released
64
- - For release candidates (pre-release), use: `npm version X.Y.Z-rc.N --preid=rc`
65
- - For patch increments: `npm version patch`
66
- - For minor increments: `npm version minor`
67
-
68
- ## Step 5: Build the SDK
69
-
70
- ```bash
71
- npm run build
72
- ```
73
-
74
- Ensure there are no TypeScript compilation errors.
75
-
76
- ## Step 6: Merge develop (if needed)
77
-
78
- If there are changes in develop that need to be included:
79
-
80
- ```bash
81
- git fetch origin develop
82
- git merge origin/develop
83
- ```
84
-
85
- If there are conflicts in `src/index.ts` or `dist/*`, regenerate the SDK (Step 2), apply fixes (Step 3), and rebuild (Step 5) to resolve them.
86
-
87
- ## Step 7: Commit and push
88
-
89
- ```bash
90
- git add .
91
- git commit -m "X.Y.Z"
92
- git push -u origin release/X.Y.Z
93
- ```
94
-
95
- ## Step 8: Publish to NPM
96
-
97
- ### Authentication
98
-
99
- NPM requires a granular access token with publish permissions and 2FA bypass enabled.
100
-
101
- 1. Go to [npmjs.com](https://www.npmjs.com) > Access Tokens > Generate New Token
102
- 2. Select "Granular Access Token"
103
- 3. Enable "Bypass 2FA for automation"
104
- 4. Set permissions to publish to `@matech/thebigpos-sdk`
105
-
106
- Configure the token:
107
-
108
- ```bash
109
- npm config set //registry.npmjs.org/:_authToken YOUR_TOKEN
110
- ```
111
-
112
- ### Publish
113
-
114
- **To latest (stable release):**
115
-
116
- ```bash
117
- npm publish --access public
118
- ```
119
-
120
- **To next (pre-release):**
121
-
122
- ```bash
123
- npm publish --tag next
124
- ```
125
-
126
- **To a feature tag (for testing):**
127
-
128
- ```bash
129
- npm publish --tag feature-name
130
- ```
131
-
132
- ### Installing the SDK
133
-
134
- ```bash
135
- # Latest stable
136
- yarn add @matech/thebigpos-sdk
137
-
138
- # Next pre-release
139
- yarn add @matech/thebigpos-sdk@next
140
-
141
- # Specific version
142
- yarn add @matech/thebigpos-sdk@X.Y.Z
143
- ```
144
-
145
- ## Step 9: Clean up
146
-
147
- 1. **Revoke the NPM token** after publishing for security
148
- 2. **Create a Pull Request** from `release/X.Y.Z` to `develop` and `main`
149
- 3. **Create a GitHub Release** with release notes