@doist/twist-sdk 0.1.0-alpha.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/LICENSE +21 -0
- package/README.md +222 -0
- package/dist/authentication.d.ts +79 -0
- package/dist/authentication.d.ts.map +1 -0
- package/dist/authentication.js +115 -0
- package/dist/authentication.test.d.ts.map +1 -0
- package/dist/batch-builder.d.ts +27 -0
- package/dist/batch-builder.d.ts.map +1 -0
- package/dist/batch-builder.js +191 -0
- package/dist/batch-builder.test.d.ts.map +1 -0
- package/dist/clients/channels-client.d.ts +215 -0
- package/dist/clients/channels-client.d.ts.map +1 -0
- package/dist/clients/channels-client.js +140 -0
- package/dist/clients/channels-client.test.d.ts.map +1 -0
- package/dist/clients/comments-client.d.ts +125 -0
- package/dist/clients/comments-client.d.ts.map +1 -0
- package/dist/clients/comments-client.js +86 -0
- package/dist/clients/comments-client.test.d.ts.map +1 -0
- package/dist/clients/conversation-messages-client.d.ts +141 -0
- package/dist/clients/conversation-messages-client.d.ts.map +1 -0
- package/dist/clients/conversation-messages-client.js +92 -0
- package/dist/clients/conversation-messages-client.test.d.ts.map +1 -0
- package/dist/clients/conversations-client.d.ts +263 -0
- package/dist/clients/conversations-client.d.ts.map +1 -0
- package/dist/clients/conversations-client.js +174 -0
- package/dist/clients/conversations-client.test.d.ts.map +1 -0
- package/dist/clients/groups-client.d.ts +175 -0
- package/dist/clients/groups-client.d.ts.map +1 -0
- package/dist/clients/groups-client.js +104 -0
- package/dist/clients/groups-client.test.d.ts.map +1 -0
- package/dist/clients/inbox-client.d.ts +146 -0
- package/dist/clients/inbox-client.d.ts.map +1 -0
- package/dist/clients/inbox-client.js +92 -0
- package/dist/clients/reactions-client.d.ts +98 -0
- package/dist/clients/reactions-client.d.ts.map +1 -0
- package/dist/clients/reactions-client.js +86 -0
- package/dist/clients/reactions-client.test.d.ts.map +1 -0
- package/dist/clients/search-client.d.ts +128 -0
- package/dist/clients/search-client.d.ts.map +1 -0
- package/dist/clients/search-client.js +89 -0
- package/dist/clients/threads-client.d.ts +321 -0
- package/dist/clients/threads-client.d.ts.map +1 -0
- package/dist/clients/threads-client.js +212 -0
- package/dist/clients/threads-client.test.d.ts.map +1 -0
- package/dist/clients/users-client.d.ts +254 -0
- package/dist/clients/users-client.d.ts.map +1 -0
- package/dist/clients/users-client.js +155 -0
- package/dist/clients/users-client.test.d.ts.map +1 -0
- package/dist/clients/workspace-users-client.d.ts +220 -0
- package/dist/clients/workspace-users-client.d.ts.map +1 -0
- package/dist/clients/workspace-users-client.js +132 -0
- package/dist/clients/workspace-users-client.test.d.ts.map +1 -0
- package/dist/clients/workspaces-client.d.ts +143 -0
- package/dist/clients/workspaces-client.d.ts.map +1 -0
- package/dist/clients/workspaces-client.js +89 -0
- package/dist/clients/workspaces-client.test.d.ts.map +1 -0
- package/dist/consts/endpoints.d.ts +16 -0
- package/dist/consts/endpoints.d.ts.map +1 -0
- package/dist/consts/endpoints.js +23 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +32 -0
- package/dist/rest-client.d.ts +5 -0
- package/dist/rest-client.d.ts.map +1 -0
- package/dist/rest-client.js +201 -0
- package/dist/rest-client.test.d.ts.map +1 -0
- package/dist/testUtils/msw-handlers.d.ts +29 -0
- package/dist/testUtils/msw-handlers.d.ts.map +1 -0
- package/dist/testUtils/msw-handlers.js +52 -0
- package/dist/testUtils/msw-setup.d.ts +2 -0
- package/dist/testUtils/msw-setup.d.ts.map +1 -0
- package/dist/testUtils/msw-setup.js +21 -0
- package/dist/testUtils/test-defaults.d.ts +11 -0
- package/dist/testUtils/test-defaults.d.ts.map +1 -0
- package/dist/testUtils/test-defaults.js +96 -0
- package/dist/twist-api.d.ts +64 -0
- package/dist/twist-api.d.ts.map +1 -0
- package/dist/twist-api.js +76 -0
- package/dist/twist-api.test.d.ts.map +1 -0
- package/dist/types/batch.d.ts +36 -0
- package/dist/types/batch.d.ts.map +1 -0
- package/dist/types/batch.js +2 -0
- package/dist/types/entities.d.ts +367 -0
- package/dist/types/entities.d.ts.map +1 -0
- package/dist/types/entities.js +358 -0
- package/dist/types/enums.d.ts +22 -0
- package/dist/types/enums.d.ts.map +1 -0
- package/dist/types/enums.js +7 -0
- package/dist/types/errors.d.ts +7 -0
- package/dist/types/errors.d.ts.map +1 -0
- package/dist/types/errors.js +30 -0
- package/dist/types/http.d.ts +12 -0
- package/dist/types/http.d.ts.map +1 -0
- package/dist/types/http.js +2 -0
- package/dist/types/index.d.ts +7 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +22 -0
- package/dist/types/requests.d.ts +97 -0
- package/dist/types/requests.d.ts.map +1 -0
- package/dist/types/requests.js +92 -0
- package/dist/utils/case-conversion.d.ts +9 -0
- package/dist/utils/case-conversion.d.ts.map +1 -0
- package/dist/utils/case-conversion.js +56 -0
- package/dist/utils/case-conversion.test.d.ts.map +1 -0
- package/dist/utils/index.d.ts +3 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +18 -0
- package/dist/utils/timestamp-conversion.d.ts +14 -0
- package/dist/utils/timestamp-conversion.d.ts.map +1 -0
- package/dist/utils/timestamp-conversion.js +47 -0
- package/dist/utils/url-helpers.d.ts +154 -0
- package/dist/utils/url-helpers.d.ts.map +1 -0
- package/dist/utils/url-helpers.js +223 -0
- package/dist/utils/url-helpers.test.d.ts.map +1 -0
- package/package.json +70 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Doist
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
# Twist SDK TypeScript
|
|
2
|
+
|
|
3
|
+
<p align="center">
|
|
4
|
+
<img src="./website/static/img/twist-logo.png" alt="Twist Logo" width="100" />
|
|
5
|
+
</p>
|
|
6
|
+
|
|
7
|
+
This is the official TypeScript SDK for the Twist REST API.
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install @doist/twist-sdk
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Usage
|
|
16
|
+
|
|
17
|
+
An example of initializing the API client and fetching a user's information:
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
import { TwistApi } from '@doist/twist-sdk'
|
|
21
|
+
|
|
22
|
+
const api = new TwistApi('YOUR_API_TOKEN')
|
|
23
|
+
|
|
24
|
+
api.users.getSessionUser()
|
|
25
|
+
.then((user) => console.log(user))
|
|
26
|
+
.catch((error) => console.log(error))
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### OAuth 2.0 Authentication
|
|
30
|
+
|
|
31
|
+
For applications that need to access user data, use OAuth 2.0:
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
import { getAuthorizationUrl, getAuthToken, TwistApi } from '@doist/twist-sdk'
|
|
35
|
+
|
|
36
|
+
// Step 1: Generate authorization URL
|
|
37
|
+
const authUrl = getAuthorizationUrl(
|
|
38
|
+
'your-client-id',
|
|
39
|
+
['user:read', 'channels:read'],
|
|
40
|
+
'state-parameter',
|
|
41
|
+
'https://yourapp.com/callback'
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
// Step 2: Exchange authorization code for access token
|
|
45
|
+
const tokenResponse = await getAuthToken({
|
|
46
|
+
clientId: 'your-client-id',
|
|
47
|
+
clientSecret: 'your-client-secret',
|
|
48
|
+
code: 'authorization-code',
|
|
49
|
+
redirectUri: 'https://yourapp.com/callback'
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
// Step 3: Use the access token
|
|
53
|
+
const api = new TwistApi(tokenResponse.accessToken)
|
|
54
|
+
const user = await api.users.getSessionUser()
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Batch Requests
|
|
58
|
+
|
|
59
|
+
The SDK supports making multiple API calls in a single HTTP request using the `/batch` endpoint. This can significantly improve performance when you need to fetch or update multiple resources.
|
|
60
|
+
|
|
61
|
+
**Note:** Batch requests are completely optional. If you only need to make a single API call, simply call the method normally without the `{ batch: true }` option.
|
|
62
|
+
|
|
63
|
+
#### How It Works
|
|
64
|
+
|
|
65
|
+
To use batch requests:
|
|
66
|
+
|
|
67
|
+
1. Pass `{ batch: true }` as the last parameter to any API method
|
|
68
|
+
2. This returns a `BatchRequestDescriptor` instead of executing the request immediately
|
|
69
|
+
3. Pass multiple descriptors to `api.batch()` to execute them together
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
// Single requests (normal usage)
|
|
73
|
+
const user1 = await api.workspaceUsers.getUserById(123, 456)
|
|
74
|
+
const user2 = await api.workspaceUsers.getUserById(123, 789)
|
|
75
|
+
|
|
76
|
+
// Batch requests - executes in a single HTTP call
|
|
77
|
+
const results = await api.batch(
|
|
78
|
+
api.workspaceUsers.getUserById(123, 456, { batch: true }),
|
|
79
|
+
api.workspaceUsers.getUserById(123, 789, { batch: true })
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
console.log(results[0].data.name) // First user
|
|
83
|
+
console.log(results[1].data.name) // Second user
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
#### Response Structure
|
|
87
|
+
|
|
88
|
+
Each item in the batch response includes:
|
|
89
|
+
|
|
90
|
+
- `code` - HTTP status code for that specific request (e.g., 200, 404)
|
|
91
|
+
- `headers` - Response headers as a key-value object
|
|
92
|
+
- `data` - The parsed and validated response data
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
const results = await api.batch(
|
|
96
|
+
api.channels.getChannel(123, { batch: true }),
|
|
97
|
+
api.channels.getChannel(456, { batch: true })
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
results.forEach((result) => {
|
|
101
|
+
if (result.code === 200) {
|
|
102
|
+
console.log('Success:', result.data.name)
|
|
103
|
+
} else {
|
|
104
|
+
console.error('Error:', result.code)
|
|
105
|
+
}
|
|
106
|
+
})
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
#### Performance Optimization
|
|
110
|
+
|
|
111
|
+
When all requests in a batch are GET requests, they are executed in parallel on the server for optimal performance. Mixed GET and POST requests are executed sequentially.
|
|
112
|
+
|
|
113
|
+
```typescript
|
|
114
|
+
// These GET requests execute in parallel
|
|
115
|
+
const results = await api.batch(
|
|
116
|
+
api.workspaceUsers.getUserById(123, 456, { batch: true }),
|
|
117
|
+
api.channels.getChannel(789, { batch: true }),
|
|
118
|
+
api.threads.getThread(101112, { batch: true })
|
|
119
|
+
)
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
#### Mixing Different API Calls
|
|
123
|
+
|
|
124
|
+
You can batch requests across different resource types:
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
const results = await api.batch(
|
|
128
|
+
api.workspaceUsers.getUserById(123, 456, { batch: true }),
|
|
129
|
+
api.channels.getChannels({ workspaceId: 123 }, { batch: true }),
|
|
130
|
+
api.conversations.getConversations({ workspaceId: 123 }, { batch: true })
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
const [user, channels, conversations] = results
|
|
134
|
+
// TypeScript maintains proper types for each result
|
|
135
|
+
console.log(user.data.name)
|
|
136
|
+
console.log(channels.data.length)
|
|
137
|
+
console.log(conversations.data.length)
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
#### Error Handling
|
|
141
|
+
|
|
142
|
+
Individual requests in a batch can fail independently. Always check the status code of each result:
|
|
143
|
+
|
|
144
|
+
```typescript
|
|
145
|
+
const results = await api.batch(
|
|
146
|
+
api.channels.getChannel(123, { batch: true }),
|
|
147
|
+
api.channels.getChannel(999999, { batch: true }) // Non-existent channel
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
results.forEach((result, index) => {
|
|
151
|
+
if (result.code >= 200 && result.code < 300) {
|
|
152
|
+
console.log(`Request ${index} succeeded:`, result.data)
|
|
153
|
+
} else {
|
|
154
|
+
console.error(`Request ${index} failed with status ${result.code}`)
|
|
155
|
+
}
|
|
156
|
+
})
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## Documentation
|
|
160
|
+
|
|
161
|
+
For detailed documentation, visit the [Twist SDK Documentation](https://doist.github.io/twist-sdk-typescript/).
|
|
162
|
+
|
|
163
|
+
For information about the Twist REST API, see the [Twist API Documentation](https://developer.twist.com/v3/).
|
|
164
|
+
|
|
165
|
+
## Development and Testing
|
|
166
|
+
|
|
167
|
+
This project uses [ts-node](https://github.com/TypeStrong/ts-node) for local development and testing.
|
|
168
|
+
|
|
169
|
+
- `npm install`
|
|
170
|
+
- Add a file named `scratch.ts` in the `src` folder
|
|
171
|
+
- Configure your IDE to run the scratch file with `ts-node` (instructions for [VSCode](https://medium.com/@dupski/debug-typescript-in-vs-code-without-compiling-using-ts-node-9d1f4f9a94a), [WebStorm](https://www.jetbrains.com/help/webstorm/running-and-debugging-typescript.html#ws_ts_run_debug_server_side_ts_node)), or run it directly: `npx ts-node ./src/scratch.ts`
|
|
172
|
+
|
|
173
|
+
Example scratch.ts file:
|
|
174
|
+
|
|
175
|
+
```typescript
|
|
176
|
+
import { TwistApi } from './twist-api'
|
|
177
|
+
|
|
178
|
+
const token = 'YOUR_API_TOKEN'
|
|
179
|
+
const api = new TwistApi(token)
|
|
180
|
+
|
|
181
|
+
api.workspaces.getWorkspaces()
|
|
182
|
+
.then((workspaces) => {
|
|
183
|
+
console.log(workspaces)
|
|
184
|
+
})
|
|
185
|
+
.catch((error) => console.error(error))
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
## Scripts
|
|
189
|
+
|
|
190
|
+
- `npm test` - Run tests
|
|
191
|
+
- `npm run test:watch` - Run tests in watch mode
|
|
192
|
+
- `npm run test:coverage` - Run tests with coverage
|
|
193
|
+
- `npm run build` - Build the package
|
|
194
|
+
- `npm run type-check` - Type check without building
|
|
195
|
+
- `npm run lint:check` - Check code style
|
|
196
|
+
- `npm run format:check` - Check formatting
|
|
197
|
+
|
|
198
|
+
## Releases
|
|
199
|
+
|
|
200
|
+
This package follows semantic versioning. Currently in alpha release (0.1.0-alpha.x).
|
|
201
|
+
|
|
202
|
+
A new version is published to the NPM Registry whenever a new release on GitHub is created. The workflow automatically detects prerelease versions (alpha, beta, rc) and publishes them with the appropriate tag.
|
|
203
|
+
|
|
204
|
+
To prepare a new release:
|
|
205
|
+
|
|
206
|
+
```bash
|
|
207
|
+
# For alpha releases
|
|
208
|
+
npm version prerelease --preid=alpha --no-git-tag-version
|
|
209
|
+
|
|
210
|
+
# For stable releases
|
|
211
|
+
npm version <major|minor|patch> --no-git-tag-version
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
Once the version in `package.json` is updated, push the changes and create a GitHub release. The workflow will automatically publish to npm with the correct tag.
|
|
215
|
+
|
|
216
|
+
## Feedback
|
|
217
|
+
|
|
218
|
+
Any feedback, such as bugs, questions, comments, etc. can be reported as _Issues_ in this repository, and will be handled by the Doist team.
|
|
219
|
+
|
|
220
|
+
## Contributions
|
|
221
|
+
|
|
222
|
+
We welcome contributions in the form of _Pull requests_ in this repository.
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OAuth scopes for the Twist API.
|
|
3
|
+
*
|
|
4
|
+
* @remarks
|
|
5
|
+
* Request only the scopes your application needs:
|
|
6
|
+
*
|
|
7
|
+
* **User Scopes:**
|
|
8
|
+
* - `user:read` - Access user's personal settings
|
|
9
|
+
* - `user:write` - Access and update user's personal settings
|
|
10
|
+
*
|
|
11
|
+
* **Workspace Scopes:**
|
|
12
|
+
* - `workspaces:read` - Access teams the user is part of
|
|
13
|
+
* - `workspaces:write` - Access and update teams the user is part of
|
|
14
|
+
*
|
|
15
|
+
* **Channel Scopes:**
|
|
16
|
+
* - `channels:read` - Access channels
|
|
17
|
+
* - `channels:write` - Access and update channels
|
|
18
|
+
* - `channels:remove` - Access, update, and delete channels
|
|
19
|
+
*
|
|
20
|
+
* **Thread Scopes:**
|
|
21
|
+
* - `threads:read` - Access threads
|
|
22
|
+
* - `threads:write` - Access and update threads
|
|
23
|
+
* - `threads:remove` - Access, update, and delete threads
|
|
24
|
+
*
|
|
25
|
+
* **Comment Scopes:**
|
|
26
|
+
* - `comments:read` - Access comments
|
|
27
|
+
* - `comments:write` - Access and update comments
|
|
28
|
+
* - `comments:remove` - Access, update, and delete comments
|
|
29
|
+
*
|
|
30
|
+
* **Group Scopes:**
|
|
31
|
+
* - `groups:read` - Access groups
|
|
32
|
+
* - `groups:write` - Access and update groups
|
|
33
|
+
* - `groups:remove` - Access, update, and delete groups
|
|
34
|
+
*
|
|
35
|
+
* **Message Scopes:**
|
|
36
|
+
* - `messages:read` - Access messages
|
|
37
|
+
* - `messages:write` - Access and update messages
|
|
38
|
+
* - `messages:remove` - Access, update, and delete messages
|
|
39
|
+
*
|
|
40
|
+
* **Reaction Scopes:**
|
|
41
|
+
* - `reactions:read` - Access reactions
|
|
42
|
+
* - `reactions:write` - Access and update reactions
|
|
43
|
+
* - `reactions:remove` - Access, update, and delete reactions
|
|
44
|
+
*
|
|
45
|
+
* **Search Scopes:**
|
|
46
|
+
* - `search:read` - Search
|
|
47
|
+
*
|
|
48
|
+
* **Attachment Scopes:**
|
|
49
|
+
* - `attachments:read` - Access attachments
|
|
50
|
+
* - `attachments:write` - Access and update attachments
|
|
51
|
+
*
|
|
52
|
+
* **Notification Scopes:**
|
|
53
|
+
* - `notifications:read` - Read user's notifications settings
|
|
54
|
+
* - `notifications:write` - Read and update user's notifications settings
|
|
55
|
+
*/
|
|
56
|
+
export type TwistScope = 'user:read' | 'user:write' | 'workspaces:read' | 'workspaces:write' | 'channels:read' | 'channels:write' | 'channels:remove' | 'threads:read' | 'threads:write' | 'threads:remove' | 'comments:read' | 'comments:write' | 'comments:remove' | 'groups:read' | 'groups:write' | 'groups:remove' | 'messages:read' | 'messages:write' | 'messages:remove' | 'reactions:read' | 'reactions:write' | 'reactions:remove' | 'search:read' | 'attachments:read' | 'attachments:write' | 'notifications:read' | 'notifications:write';
|
|
57
|
+
export type AuthTokenRequestArgs = {
|
|
58
|
+
clientId: string;
|
|
59
|
+
clientSecret: string;
|
|
60
|
+
code: string;
|
|
61
|
+
redirectUri?: string;
|
|
62
|
+
};
|
|
63
|
+
export type AuthTokenResponse = {
|
|
64
|
+
accessToken: string;
|
|
65
|
+
tokenType: string;
|
|
66
|
+
refreshToken?: string;
|
|
67
|
+
expiresIn?: number;
|
|
68
|
+
scope?: string;
|
|
69
|
+
};
|
|
70
|
+
export type RevokeAuthTokenRequestArgs = {
|
|
71
|
+
clientId: string;
|
|
72
|
+
clientSecret: string;
|
|
73
|
+
accessToken: string;
|
|
74
|
+
};
|
|
75
|
+
export declare function getAuthStateParameter(): string;
|
|
76
|
+
export declare function getAuthorizationUrl(clientId: string, scopes: TwistScope[], state: string, redirectUri?: string, baseUrl?: string): string;
|
|
77
|
+
export declare function getAuthToken(args: AuthTokenRequestArgs, baseUrl?: string): Promise<AuthTokenResponse>;
|
|
78
|
+
export declare function revokeAuthToken(args: RevokeAuthTokenRequestArgs, baseUrl?: string): Promise<boolean>;
|
|
79
|
+
//# sourceMappingURL=authentication.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"authentication.d.ts","sourceRoot":"","sources":["../src/authentication.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsDG;AACH,MAAM,MAAM,UAAU,GAChB,WAAW,GACX,YAAY,GACZ,iBAAiB,GACjB,kBAAkB,GAClB,eAAe,GACf,gBAAgB,GAChB,iBAAiB,GACjB,cAAc,GACd,eAAe,GACf,gBAAgB,GAChB,eAAe,GACf,gBAAgB,GAChB,iBAAiB,GACjB,aAAa,GACb,cAAc,GACd,eAAe,GACf,eAAe,GACf,gBAAgB,GAChB,iBAAiB,GACjB,gBAAgB,GAChB,iBAAiB,GACjB,kBAAkB,GAClB,aAAa,GACb,kBAAkB,GAClB,mBAAmB,GACnB,oBAAoB,GACpB,qBAAqB,CAAA;AAE3B,MAAM,MAAM,oBAAoB,GAAG;IAC/B,QAAQ,EAAE,MAAM,CAAA;IAChB,YAAY,EAAE,MAAM,CAAA;IACpB,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,CAAC,EAAE,MAAM,CAAA;CACvB,CAAA;AAED,MAAM,MAAM,iBAAiB,GAAG;IAC5B,WAAW,EAAE,MAAM,CAAA;IACnB,SAAS,EAAE,MAAM,CAAA;IACjB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,KAAK,CAAC,EAAE,MAAM,CAAA;CACjB,CAAA;AAED,MAAM,MAAM,0BAA0B,GAAG;IACrC,QAAQ,EAAE,MAAM,CAAA;IAChB,YAAY,EAAE,MAAM,CAAA;IACpB,WAAW,EAAE,MAAM,CAAA;CACtB,CAAA;AAED,wBAAgB,qBAAqB,IAAI,MAAM,CAE9C;AAED,wBAAgB,mBAAmB,CAC/B,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,UAAU,EAAE,EACpB,KAAK,EAAE,MAAM,EACb,WAAW,CAAC,EAAE,MAAM,EACpB,OAAO,CAAC,EAAE,MAAM,GACjB,MAAM,CAmBR;AAED,wBAAsB,YAAY,CAC9B,IAAI,EAAE,oBAAoB,EAC1B,OAAO,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,iBAAiB,CAAC,CAsB5B;AAED,wBAAsB,eAAe,CACjC,IAAI,EAAE,0BAA0B,EAChC,OAAO,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,OAAO,CAAC,CAUlB"}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __assign = (this && this.__assign) || function () {
|
|
3
|
+
__assign = Object.assign || function(t) {
|
|
4
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
5
|
+
s = arguments[i];
|
|
6
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
7
|
+
t[p] = s[p];
|
|
8
|
+
}
|
|
9
|
+
return t;
|
|
10
|
+
};
|
|
11
|
+
return __assign.apply(this, arguments);
|
|
12
|
+
};
|
|
13
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
14
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
15
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
16
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
17
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
18
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
19
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
20
|
+
});
|
|
21
|
+
};
|
|
22
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
23
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
|
|
24
|
+
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
25
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
26
|
+
function step(op) {
|
|
27
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
28
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
29
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
30
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
31
|
+
switch (op[0]) {
|
|
32
|
+
case 0: case 1: t = op; break;
|
|
33
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
34
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
35
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
36
|
+
default:
|
|
37
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
38
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
39
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
40
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
41
|
+
if (t[2]) _.ops.pop();
|
|
42
|
+
_.trys.pop(); continue;
|
|
43
|
+
}
|
|
44
|
+
op = body.call(thisArg, _);
|
|
45
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
46
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
50
|
+
exports.getAuthStateParameter = getAuthStateParameter;
|
|
51
|
+
exports.getAuthorizationUrl = getAuthorizationUrl;
|
|
52
|
+
exports.getAuthToken = getAuthToken;
|
|
53
|
+
exports.revokeAuthToken = revokeAuthToken;
|
|
54
|
+
var uuid_1 = require("uuid");
|
|
55
|
+
var rest_client_1 = require("./rest-client");
|
|
56
|
+
var errors_1 = require("./types/errors");
|
|
57
|
+
function getAuthStateParameter() {
|
|
58
|
+
return (0, uuid_1.v4)();
|
|
59
|
+
}
|
|
60
|
+
function getAuthorizationUrl(clientId, scopes, state, redirectUri, baseUrl) {
|
|
61
|
+
if (!(scopes === null || scopes === void 0 ? void 0 : scopes.length)) {
|
|
62
|
+
throw new Error('At least one scope value is required.');
|
|
63
|
+
}
|
|
64
|
+
var authBaseUrl = baseUrl ? "".concat(baseUrl, "/oauth") : 'https://twist.com/oauth';
|
|
65
|
+
var scope = scopes.join(' ');
|
|
66
|
+
var params = new URLSearchParams({
|
|
67
|
+
client_id: clientId,
|
|
68
|
+
response_type: 'code',
|
|
69
|
+
scope: scope,
|
|
70
|
+
state: state,
|
|
71
|
+
});
|
|
72
|
+
if (redirectUri) {
|
|
73
|
+
params.append('redirect_uri', redirectUri);
|
|
74
|
+
}
|
|
75
|
+
return "".concat(authBaseUrl, "/authorize?").concat(params.toString());
|
|
76
|
+
}
|
|
77
|
+
function getAuthToken(args, baseUrl) {
|
|
78
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
79
|
+
var tokenUrl, payload, response;
|
|
80
|
+
var _a;
|
|
81
|
+
return __generator(this, function (_b) {
|
|
82
|
+
switch (_b.label) {
|
|
83
|
+
case 0:
|
|
84
|
+
tokenUrl = baseUrl ? "".concat(baseUrl, "/oauth/token") : 'https://twist.com/oauth/token';
|
|
85
|
+
payload = __assign({ clientId: args.clientId, clientSecret: args.clientSecret, code: args.code, grantType: 'authorization_code' }, (args.redirectUri && { redirectUri: args.redirectUri }));
|
|
86
|
+
return [4 /*yield*/, (0, rest_client_1.request)('POST', tokenUrl, '', undefined, payload)];
|
|
87
|
+
case 1:
|
|
88
|
+
response = _b.sent();
|
|
89
|
+
if (!(0, rest_client_1.isSuccess)(response) || !((_a = response.data) === null || _a === void 0 ? void 0 : _a.accessToken)) {
|
|
90
|
+
throw new errors_1.TwistRequestError('Authentication token exchange failed.', response.status, response.data);
|
|
91
|
+
}
|
|
92
|
+
return [2 /*return*/, response.data];
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
function revokeAuthToken(args, baseUrl) {
|
|
98
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
99
|
+
var revokeUrl, response;
|
|
100
|
+
return __generator(this, function (_a) {
|
|
101
|
+
switch (_a.label) {
|
|
102
|
+
case 0:
|
|
103
|
+
revokeUrl = baseUrl ? "".concat(baseUrl, "/oauth/revoke") : 'https://twist.com/oauth/revoke';
|
|
104
|
+
return [4 /*yield*/, (0, rest_client_1.request)('POST', revokeUrl, '', undefined, {
|
|
105
|
+
clientId: args.clientId,
|
|
106
|
+
clientSecret: args.clientSecret,
|
|
107
|
+
token: args.accessToken,
|
|
108
|
+
})];
|
|
109
|
+
case 1:
|
|
110
|
+
response = _a.sent();
|
|
111
|
+
return [2 /*return*/, (0, rest_client_1.isSuccess)(response)];
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"authentication.test.d.ts","sourceRoot":"","sources":["../src/authentication.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { BatchRequestDescriptor, BatchResponseArray } from './types/batch';
|
|
2
|
+
/**
|
|
3
|
+
* Executes multiple API requests in a single HTTP call.
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* ```typescript
|
|
7
|
+
* const results = await api.batch(
|
|
8
|
+
* api.workspaceUsers.getUserById(123, 456, { batch: true }),
|
|
9
|
+
* api.workspaceUsers.getUserById(123, 789, { batch: true })
|
|
10
|
+
* )
|
|
11
|
+
* ```
|
|
12
|
+
*/
|
|
13
|
+
export declare class BatchBuilder {
|
|
14
|
+
private apiToken;
|
|
15
|
+
private baseUrl?;
|
|
16
|
+
constructor(apiToken: string, baseUrl?: string | undefined);
|
|
17
|
+
private getBaseUri;
|
|
18
|
+
/**
|
|
19
|
+
* Executes an array of batch request descriptors in a single API call.
|
|
20
|
+
*
|
|
21
|
+
* @param requests - Array of batch request descriptors
|
|
22
|
+
* @returns Array of BatchResponse objects with processed data
|
|
23
|
+
* @throws {TwistRequestError} If the batch request fails
|
|
24
|
+
*/
|
|
25
|
+
execute<T extends readonly BatchRequestDescriptor<unknown>[]>(requests: T): Promise<BatchResponseArray<T>>;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=batch-builder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"batch-builder.d.ts","sourceRoot":"","sources":["../src/batch-builder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAoB,sBAAsB,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAA;AAKjG;;;;;;;;;;GAUG;AACH,qBAAa,YAAY;IAEjB,OAAO,CAAC,QAAQ;IAChB,OAAO,CAAC,OAAO,CAAC;gBADR,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,MAAM,YAAA;IAG5B,OAAO,CAAC,UAAU;IAIlB;;;;;;OAMG;IACG,OAAO,CAAC,CAAC,SAAS,SAAS,sBAAsB,CAAC,OAAO,CAAC,EAAE,EAC9D,QAAQ,EAAE,CAAC,GACZ,OAAO,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC;CAyHpC"}
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
12
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
|
|
13
|
+
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
14
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
15
|
+
function step(op) {
|
|
16
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
17
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
18
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
19
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
20
|
+
switch (op[0]) {
|
|
21
|
+
case 0: case 1: t = op; break;
|
|
22
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
23
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
24
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
25
|
+
default:
|
|
26
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
27
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
28
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
29
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
30
|
+
if (t[2]) _.ops.pop();
|
|
31
|
+
_.trys.pop(); continue;
|
|
32
|
+
}
|
|
33
|
+
op = body.call(thisArg, _);
|
|
34
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
35
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.BatchBuilder = void 0;
|
|
40
|
+
var errors_1 = require("./types/errors");
|
|
41
|
+
var case_conversion_1 = require("./utils/case-conversion");
|
|
42
|
+
var timestamp_conversion_1 = require("./utils/timestamp-conversion");
|
|
43
|
+
/**
|
|
44
|
+
* Executes multiple API requests in a single HTTP call.
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```typescript
|
|
48
|
+
* const results = await api.batch(
|
|
49
|
+
* api.workspaceUsers.getUserById(123, 456, { batch: true }),
|
|
50
|
+
* api.workspaceUsers.getUserById(123, 789, { batch: true })
|
|
51
|
+
* )
|
|
52
|
+
* ```
|
|
53
|
+
*/
|
|
54
|
+
var BatchBuilder = /** @class */ (function () {
|
|
55
|
+
function BatchBuilder(apiToken, baseUrl) {
|
|
56
|
+
this.apiToken = apiToken;
|
|
57
|
+
this.baseUrl = baseUrl;
|
|
58
|
+
}
|
|
59
|
+
BatchBuilder.prototype.getBaseUri = function () {
|
|
60
|
+
return this.baseUrl ? "".concat(this.baseUrl, "/api/v3") : 'https://api.twist.com/api/v3/';
|
|
61
|
+
};
|
|
62
|
+
/**
|
|
63
|
+
* Executes an array of batch request descriptors in a single API call.
|
|
64
|
+
*
|
|
65
|
+
* @param requests - Array of batch request descriptors
|
|
66
|
+
* @returns Array of BatchResponse objects with processed data
|
|
67
|
+
* @throws {TwistRequestError} If the batch request fails
|
|
68
|
+
*/
|
|
69
|
+
BatchBuilder.prototype.execute = function (requests) {
|
|
70
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
71
|
+
var batchRequests, allGets, formData, response, errorText, batchApiResponses;
|
|
72
|
+
var _this = this;
|
|
73
|
+
return __generator(this, function (_a) {
|
|
74
|
+
switch (_a.label) {
|
|
75
|
+
case 0:
|
|
76
|
+
if (requests.length === 0) {
|
|
77
|
+
return [2 /*return*/, []];
|
|
78
|
+
}
|
|
79
|
+
batchRequests = requests.map(function (descriptor) {
|
|
80
|
+
// Convert params to snake_case
|
|
81
|
+
var snakeCaseParams = descriptor.params
|
|
82
|
+
? (0, case_conversion_1.snakeCaseKeys)(descriptor.params)
|
|
83
|
+
: undefined;
|
|
84
|
+
// Build the full URL with query params for GET requests
|
|
85
|
+
var url = "".concat(_this.getBaseUri()).concat(descriptor.url);
|
|
86
|
+
if (descriptor.method === 'GET' && snakeCaseParams) {
|
|
87
|
+
var searchParams_1 = new URLSearchParams();
|
|
88
|
+
Object.entries(snakeCaseParams).forEach(function (_a) {
|
|
89
|
+
var key = _a[0], value = _a[1];
|
|
90
|
+
if (value != null) {
|
|
91
|
+
if (Array.isArray(value)) {
|
|
92
|
+
searchParams_1.append(key, value.join(','));
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
searchParams_1.append(key, String(value));
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
var queryString = searchParams_1.toString();
|
|
100
|
+
if (queryString) {
|
|
101
|
+
url += "?".concat(queryString);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return {
|
|
105
|
+
method: descriptor.method,
|
|
106
|
+
url: url,
|
|
107
|
+
};
|
|
108
|
+
});
|
|
109
|
+
allGets = batchRequests.every(function (req) { return req.method === 'GET'; });
|
|
110
|
+
formData = new URLSearchParams();
|
|
111
|
+
formData.append('requests', JSON.stringify(batchRequests));
|
|
112
|
+
if (allGets) {
|
|
113
|
+
formData.append('parallel', 'true');
|
|
114
|
+
}
|
|
115
|
+
return [4 /*yield*/, fetch("".concat(this.getBaseUri(), "batch"), {
|
|
116
|
+
method: 'POST',
|
|
117
|
+
headers: {
|
|
118
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
119
|
+
Authorization: "Bearer ".concat(this.apiToken),
|
|
120
|
+
},
|
|
121
|
+
body: formData.toString(),
|
|
122
|
+
})];
|
|
123
|
+
case 1:
|
|
124
|
+
response = _a.sent();
|
|
125
|
+
if (!!response.ok) return [3 /*break*/, 3];
|
|
126
|
+
return [4 /*yield*/, response.text()];
|
|
127
|
+
case 2:
|
|
128
|
+
errorText = _a.sent();
|
|
129
|
+
throw new errors_1.TwistRequestError("Batch request failed with status ".concat(response.status), response.status, errorText);
|
|
130
|
+
case 3: return [4 /*yield*/, response.json()
|
|
131
|
+
// Process each response
|
|
132
|
+
];
|
|
133
|
+
case 4:
|
|
134
|
+
batchApiResponses = _a.sent();
|
|
135
|
+
// Process each response
|
|
136
|
+
return [2 /*return*/, batchApiResponses.map(function (apiResponse, index) {
|
|
137
|
+
var descriptor = requests[index];
|
|
138
|
+
// Parse the body JSON
|
|
139
|
+
var parsedBody;
|
|
140
|
+
try {
|
|
141
|
+
parsedBody = apiResponse.body ? JSON.parse(apiResponse.body) : undefined;
|
|
142
|
+
}
|
|
143
|
+
catch (_error) {
|
|
144
|
+
parsedBody = apiResponse.body;
|
|
145
|
+
}
|
|
146
|
+
// Apply transformations: camelCase -> timestamps
|
|
147
|
+
var camelCased = (0, case_conversion_1.camelCaseKeys)(parsedBody);
|
|
148
|
+
var transformed = (0, timestamp_conversion_1.transformTimestamps)(camelCased);
|
|
149
|
+
// Validate with schema if provided
|
|
150
|
+
var finalData = transformed;
|
|
151
|
+
if (descriptor.schema && apiResponse.code >= 200 && apiResponse.code < 300) {
|
|
152
|
+
try {
|
|
153
|
+
finalData = descriptor.schema.parse(transformed);
|
|
154
|
+
}
|
|
155
|
+
catch (error) {
|
|
156
|
+
// If validation fails, include the error in the response
|
|
157
|
+
console.error('Batch response validation failed:', error);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
// Parse headers string into object
|
|
161
|
+
var headers = {};
|
|
162
|
+
if (apiResponse.headers && typeof apiResponse.headers === 'string') {
|
|
163
|
+
try {
|
|
164
|
+
var headerLines = apiResponse.headers.split('\n');
|
|
165
|
+
headerLines.forEach(function (line) {
|
|
166
|
+
var separatorIndex = line.indexOf(':');
|
|
167
|
+
if (separatorIndex > 0) {
|
|
168
|
+
var key = line.substring(0, separatorIndex).trim();
|
|
169
|
+
var value = line.substring(separatorIndex + 1).trim();
|
|
170
|
+
headers[key] = value;
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
catch (error) {
|
|
175
|
+
// If header parsing fails, just leave headers empty
|
|
176
|
+
console.error('Failed to parse batch response headers:', error);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
return {
|
|
180
|
+
code: apiResponse.code,
|
|
181
|
+
headers: headers,
|
|
182
|
+
data: finalData,
|
|
183
|
+
};
|
|
184
|
+
})];
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
};
|
|
189
|
+
return BatchBuilder;
|
|
190
|
+
}());
|
|
191
|
+
exports.BatchBuilder = BatchBuilder;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"batch-builder.test.d.ts","sourceRoot":"","sources":["../src/batch-builder.test.ts"],"names":[],"mappings":""}
|