@b-jones-rfd/qualtrics-api-tasks 0.0.5 → 0.1.1
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/CHANGELOG.md +12 -0
- package/README.md +100 -11
- package/dist/index.d.mts +109 -3
- package/dist/index.d.ts +109 -3
- package/dist/index.js +174 -14
- package/dist/index.mjs +170 -14
- package/package.json +1 -1
- package/tests/utils.test.ts +110 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @b-jones-rfd/qualtrics-api-tasks
|
|
2
2
|
|
|
3
|
+
## 0.1.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 2f8dbdf: Added JSDoc action method descriptions
|
|
8
|
+
|
|
9
|
+
## 0.1.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- efa27c7: Implemented survey file response methods
|
|
14
|
+
|
|
3
15
|
## 0.0.5
|
|
4
16
|
|
|
5
17
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -76,7 +76,7 @@ import { createConnection } from '@b-jones-rfd/qualtrics-api-tasks'
|
|
|
76
76
|
const connectionOptions = {
|
|
77
77
|
datacenterId: 'az1',
|
|
78
78
|
apiToken: 'my API Token', // optional
|
|
79
|
-
timeout:
|
|
79
|
+
timeout: 20 * 1000, // optional timeout in milliseconds, default is 30 seconds
|
|
80
80
|
}
|
|
81
81
|
|
|
82
82
|
const connection: SiteConnection = createConnection(connectionOptions)
|
|
@@ -123,9 +123,9 @@ async function testMyQualtricsConnection(listName: string) {
|
|
|
123
123
|
|
|
124
124
|
`timeout`
|
|
125
125
|
|
|
126
|
-
| Type | Default value | Description | Example
|
|
127
|
-
| ------ | ------------- | ------------------------- |
|
|
128
|
-
| number | 30000 | Qualtrics request timeout |
|
|
126
|
+
| Type | Default value | Description | Example | Required |
|
|
127
|
+
| ------ | ------------- | ------------------------- | ------- | -------- |
|
|
128
|
+
| number | 30000 | Qualtrics request timeout | 1000 | N |
|
|
129
129
|
|
|
130
130
|
### Actions
|
|
131
131
|
|
|
@@ -139,23 +139,112 @@ export type Action<TConfig, TResponse> = (
|
|
|
139
139
|
|
|
140
140
|
If using the actions directly call the factory method with a ConnectionOptions object to return an action that can be used to execute a Qualtrics action.
|
|
141
141
|
|
|
142
|
-
####
|
|
142
|
+
#### exportResponses(options)
|
|
143
|
+
|
|
144
|
+
Implements [Survey Response File Export](https://api.qualtrics.com/u9e5lh4172v0v-survey-response-export-guide) multistep process.
|
|
145
|
+
|
|
146
|
+
`options`
|
|
147
|
+
|
|
148
|
+
| Property | Type | Description | Required | Default |
|
|
149
|
+
| ------------------------------- | -------- | ------------------------------------------- | -------- | ------- |
|
|
150
|
+
| surveyId | string | Quatrics Survey ID | Y | |
|
|
151
|
+
| startDate | Date | Export start date and time | Y | |
|
|
152
|
+
| endDate | Date | Export end date and time | Y | |
|
|
153
|
+
| format | Enum | File format | N | 'csv' |
|
|
154
|
+
| breakoutSets | boolean | Split multi-value fields into columns | N | true |
|
|
155
|
+
| compress | boolean | Compress final export | N | true |
|
|
156
|
+
| exportResponsesInProgress | boolean | Only export not complete | N | false |
|
|
157
|
+
| filterId | string | Return responses matching id | N | |
|
|
158
|
+
| formatDecimalAsComma | boolean | Use comma as decimal separator | N | false |
|
|
159
|
+
| includeDisplayOrder | boolean | Include display order in export | N | false |
|
|
160
|
+
| limit | number | Max responses to export | N | |
|
|
161
|
+
| multiselectSeenUnansweredRecode | number | Recode seen, but unanswered for multiselect | N | |
|
|
162
|
+
| newlineReplacement | string | Replace newline character with this | N | |
|
|
163
|
+
| seenUnansweredRecode | number | Recode seen, but unanswered with this | N | |
|
|
164
|
+
| timeZone | string | Timezone used to determine response date | N | 'UTC" |
|
|
165
|
+
| useLabels | boolean | Export text of answer choice | N | false |
|
|
166
|
+
| embeddedDataIds | string[] | Only export these embedded data fields | N | |
|
|
167
|
+
| questionIds | string[] | Only export these question IDs | N | |
|
|
168
|
+
| surveyMetadataIds | string[] | Only export these metadata fields | N | |
|
|
169
|
+
| continuationToken | string | Previous export continuation token | N | |
|
|
170
|
+
| allowContinuation | boolean | Request continuation token | N | false |
|
|
171
|
+
| includeLabelColumns | boolean | Export two columns, recode and labels | N | false |
|
|
172
|
+
| sortByLastModifiedDate | boolean | Sort responses by modified date | N | false |
|
|
173
|
+
| bearerToken | string | Valid Bearer Token | N | |
|
|
174
|
+
|
|
175
|
+
#### getBearerToken(options)
|
|
143
176
|
|
|
144
177
|
Implements [OAuth Authentication (Client Credentials)](https://api.qualtrics.com/9398592961ced-o-auth-authentication-client-credentials)
|
|
145
178
|
|
|
146
179
|
`options`
|
|
147
180
|
|
|
148
|
-
| Property | Type | Description
|
|
149
|
-
| ------------ | ------ |
|
|
150
|
-
| clientId | string | Quatrics Client ID
|
|
151
|
-
| clientSecret | string | Qualtrics Client Password
|
|
181
|
+
| Property | Type | Description | Required |
|
|
182
|
+
| ------------ | ------ | --------------------------------- | -------- |
|
|
183
|
+
| clientId | string | Quatrics Client ID | Y |
|
|
184
|
+
| clientSecret | string | Qualtrics Client Password | Y |
|
|
185
|
+
| scope | string | Qualtrics Client requested scopes | Y |
|
|
186
|
+
|
|
187
|
+
#### getResponseExportFile(options)
|
|
152
188
|
|
|
153
|
-
|
|
189
|
+
Implements [Get Response Export File](https://api.qualtrics.com/41296b6f2e828-get-response-export-file)
|
|
154
190
|
|
|
155
191
|
`options`
|
|
156
192
|
|
|
157
193
|
| Property | Type | Description | Required |
|
|
158
194
|
| ----------- | ------ | ------------------ | -------- |
|
|
195
|
+
| surveyId | string | Quatrics Survey ID | Y |
|
|
196
|
+
| fileId | string | File ID | Y |
|
|
197
|
+
| bearerToken | string | Valid Bearer Token | N |
|
|
198
|
+
|
|
199
|
+
#### getResponseExportProgress(options)
|
|
200
|
+
|
|
201
|
+
Implements [Get Response Export Progress](https://api.qualtrics.com/37e6a66f74ab4-get-response-export-progress)
|
|
202
|
+
|
|
203
|
+
`options`
|
|
204
|
+
|
|
205
|
+
| Property | Type | Description | Required |
|
|
206
|
+
| ---------------- | ------ | ------------------ | -------- |
|
|
207
|
+
| surveyId | string | Quatrics Survey ID | Y |
|
|
208
|
+
| exportProgressId | string | Progress ID | Y |
|
|
209
|
+
| bearerToken | string | Valid Bearer Token | N |
|
|
210
|
+
|
|
211
|
+
#### startResponseExports(options)
|
|
212
|
+
|
|
213
|
+
Implements [Start Response Exports](https://api.qualtrics.com/6b00592b9c013-start-response-export)
|
|
214
|
+
|
|
215
|
+
`options`
|
|
216
|
+
|
|
217
|
+
| Property | Type | Description | Required | Default |
|
|
218
|
+
| ------------------------------- | -------- | ------------------------------------------- | -------- | ------- |
|
|
219
|
+
| surveyId | string | Quatrics Survey ID | Y | |
|
|
220
|
+
| startDate | Date | Export start date and time | Y | |
|
|
221
|
+
| endDate | Date | Export end date and time | Y | |
|
|
222
|
+
| format | Enum | File format | N | 'csv' |
|
|
223
|
+
| breakoutSets | boolean | Split multi-value fields into columns | N | true |
|
|
224
|
+
| compress | boolean | Compress final export | N | true |
|
|
225
|
+
| exportResponsesInProgress | boolean | Only export not complete | N | false |
|
|
226
|
+
| filterId | string | Return responses matching id | N | |
|
|
227
|
+
| formatDecimalAsComma | boolean | Use comma as decimal separator | N | false |
|
|
228
|
+
| includeDisplayOrder | boolean | Include display order in export | N | false |
|
|
229
|
+
| limit | number | Max responses to export | N | |
|
|
230
|
+
| multiselectSeenUnansweredRecode | number | Recode seen, but unanswered for multiselect | N | |
|
|
231
|
+
| newlineReplacement | string | Replace newline character with this | N | |
|
|
232
|
+
| seenUnansweredRecode | number | Recode seen, but unanswered with this | N | |
|
|
233
|
+
| timeZone | string | Timezone used to determine response date | N | 'UTC" |
|
|
234
|
+
| useLabels | boolean | Export text of answer choice | N | false |
|
|
235
|
+
| embeddedDataIds | string[] | Only export these embedded data fields | N | |
|
|
236
|
+
| questionIds | string[] | Only export these question IDs | N | |
|
|
237
|
+
| surveyMetadataIds | string[] | Only export these metadata fields | N | |
|
|
238
|
+
| continuationToken | string | Previous export continuation token | N | |
|
|
239
|
+
| allowContinuation | boolean | Request continuation token | N | false |
|
|
240
|
+
| includeLabelColumns | boolean | Export two columns, recode and labels | N | false |
|
|
241
|
+
| sortByLastModifiedDate | boolean | Sort responses by modified date | N | false |
|
|
242
|
+
| bearerToken | string | Valid Bearer Token | N | |
|
|
243
|
+
|
|
244
|
+
#### testConnection(bearerToken)
|
|
245
|
+
|
|
246
|
+
| Parameter | Type | Description | Required |
|
|
247
|
+
| ----------- | ------ | ------------------ | -------- |
|
|
159
248
|
| bearerToken | string | Valid Bearer Token | N |
|
|
160
249
|
|
|
161
250
|
## Responses
|
|
@@ -196,4 +285,4 @@ We use [SemVer](http://semver.org/) for versioning. For the versions available,
|
|
|
196
285
|
|
|
197
286
|
## License
|
|
198
287
|
|
|
199
|
-
[MIT License](https://github.com/B-Jones-RFD/
|
|
288
|
+
[MIT License](https://github.com/B-Jones-RFD/qualtrics-api-tasks/blob/main/LICENSE)
|
package/dist/index.d.mts
CHANGED
|
@@ -7,6 +7,7 @@ type Failure = {
|
|
|
7
7
|
error: string;
|
|
8
8
|
};
|
|
9
9
|
type Result<T> = Success<T> | Failure;
|
|
10
|
+
type ResponseFormat = 'csv' | 'json' | 'ndjson' | 'spss' | 'tsv' | 'xml';
|
|
10
11
|
type Action<TConfig, TResponse> = (options: TConfig) => Promise<Result<TResponse>>;
|
|
11
12
|
type ConnectionOptions = {
|
|
12
13
|
datacenterId: string;
|
|
@@ -15,21 +16,126 @@ type ConnectionOptions = {
|
|
|
15
16
|
};
|
|
16
17
|
type ActionFactory<TParams, TResponse> = (options: ConnectionOptions) => Action<TParams, TResponse>;
|
|
17
18
|
type Connection = {
|
|
18
|
-
|
|
19
|
+
exportResponses: Action<ExportResponsesOptions, Buffer>;
|
|
19
20
|
getBearerToken: Action<{
|
|
20
21
|
clientId: string;
|
|
21
22
|
clientSecret: string;
|
|
23
|
+
scope: string;
|
|
22
24
|
}, string>;
|
|
25
|
+
getResponseExportFile: Action<{
|
|
26
|
+
surveyId: string;
|
|
27
|
+
fileId: string;
|
|
28
|
+
bearerToken?: string;
|
|
29
|
+
}, Buffer>;
|
|
30
|
+
getResponseExportProgress: Action<{
|
|
31
|
+
exportProgressId: string;
|
|
32
|
+
surveyId: string;
|
|
33
|
+
bearerToken?: string;
|
|
34
|
+
}, FileProgressResponse>;
|
|
35
|
+
startResponseExport: Action<ExportResponsesOptions, {
|
|
36
|
+
progressId: string;
|
|
37
|
+
percentComplete: number;
|
|
38
|
+
status: string;
|
|
39
|
+
continuationToken?: string;
|
|
40
|
+
}>;
|
|
41
|
+
testConnection: (bearerToken?: string) => Promise<Result<string>>;
|
|
23
42
|
};
|
|
24
43
|
type ConnectionFactory = (options: ConnectionOptions) => Connection;
|
|
44
|
+
type ExportResponsesOptions = {
|
|
45
|
+
surveyId: string;
|
|
46
|
+
startDate: Date;
|
|
47
|
+
endDate: Date;
|
|
48
|
+
format?: ResponseFormat;
|
|
49
|
+
breakoutSets?: boolean;
|
|
50
|
+
compress?: boolean;
|
|
51
|
+
exportResponsesInProgress?: boolean;
|
|
52
|
+
filterId?: string;
|
|
53
|
+
formatDecimalAsComma?: boolean;
|
|
54
|
+
includeDisplayOrder?: boolean;
|
|
55
|
+
limit?: number;
|
|
56
|
+
multiselectSeenUnansweredRecode?: number;
|
|
57
|
+
newlineReplacement?: string;
|
|
58
|
+
seenUnansweredRecode?: number;
|
|
59
|
+
timeZone?: string;
|
|
60
|
+
useLabels?: boolean;
|
|
61
|
+
embeddedDataIds?: string[];
|
|
62
|
+
questionIds?: string[];
|
|
63
|
+
surveyMetadataIds?: string[];
|
|
64
|
+
continuationToken?: string;
|
|
65
|
+
allowContinuation?: boolean;
|
|
66
|
+
includeLabelColumns?: boolean;
|
|
67
|
+
sortByLastModifiedDate?: boolean;
|
|
68
|
+
bearerToken?: string;
|
|
69
|
+
};
|
|
70
|
+
type FileProgressResponse = {
|
|
71
|
+
fileId: string;
|
|
72
|
+
percentComplete: number;
|
|
73
|
+
status: string;
|
|
74
|
+
continuationToken?: string;
|
|
75
|
+
};
|
|
25
76
|
|
|
26
77
|
declare const createConnection: ConnectionFactory;
|
|
27
78
|
|
|
79
|
+
/**
|
|
80
|
+
* Export Survey Response File
|
|
81
|
+
*
|
|
82
|
+
* Implements Survey Response File Export end to end
|
|
83
|
+
* @see https://api.qualtrics.com/u9e5lh4172v0v-survey-response-export-guide
|
|
84
|
+
*/
|
|
85
|
+
declare const exportResponses: ActionFactory<ExportResponsesOptions, Buffer>;
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Get Bearer Token
|
|
89
|
+
*
|
|
90
|
+
* Implements OAuth Authentication (Client Credentials
|
|
91
|
+
* @see https://api.qualtrics.com/9398592961ced-o-auth-authentication-client-credentials
|
|
92
|
+
*/
|
|
28
93
|
declare const getBearerToken: ActionFactory<{
|
|
29
94
|
clientId: string;
|
|
30
95
|
clientSecret: string;
|
|
96
|
+
scope: string;
|
|
31
97
|
}, string>;
|
|
32
98
|
|
|
33
|
-
|
|
99
|
+
/**
|
|
100
|
+
* Get Response Export File
|
|
101
|
+
*
|
|
102
|
+
* Implements Get Response Export Progress. This is step 2 in the survey response file export process.
|
|
103
|
+
* @see https://api.qualtrics.com/37e6a66f74ab4-get-response-export-progress
|
|
104
|
+
*/
|
|
105
|
+
declare const getResponseExportProgress: ActionFactory<{
|
|
106
|
+
exportProgressId: string;
|
|
107
|
+
surveyId: string;
|
|
108
|
+
bearerToken?: string;
|
|
109
|
+
}, FileProgressResponse>;
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Get Response Export File
|
|
113
|
+
*
|
|
114
|
+
* Implements Get Response Export File. This is step 3 in the survey response file export process.
|
|
115
|
+
* @see https://api.qualtrics.com/41296b6f2e828-get-response-export-file
|
|
116
|
+
*/
|
|
117
|
+
declare const getResponseExportFile: ActionFactory<{
|
|
118
|
+
surveyId: string;
|
|
119
|
+
fileId: string;
|
|
120
|
+
bearerToken?: string;
|
|
121
|
+
}, Buffer>;
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Start Response Export
|
|
125
|
+
*
|
|
126
|
+
* Implements Start Response File Export
|
|
127
|
+
* @see https://api.qualtrics.com/6b00592b9c013-start-response-export
|
|
128
|
+
*/
|
|
129
|
+
declare const startResponseExport: ActionFactory<ExportResponsesOptions, {
|
|
130
|
+
progressId: string;
|
|
131
|
+
percentComplete: number;
|
|
132
|
+
status: string;
|
|
133
|
+
continuationToken?: string;
|
|
134
|
+
}>;
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Test connection to Qualtrics API
|
|
138
|
+
*/
|
|
139
|
+
declare const testConnection: (connectionOptions: ConnectionOptions) => (bearerToken?: string) => Promise<Result<string>>;
|
|
34
140
|
|
|
35
|
-
export { type Action, type ActionFactory, type Connection, type ConnectionFactory, type ConnectionOptions, type Failure, type Result, type Success, createConnection, getBearerToken, testConnection };
|
|
141
|
+
export { type Action, type ActionFactory, type Connection, type ConnectionFactory, type ConnectionOptions, type ExportResponsesOptions, type Failure, type FileProgressResponse, type ResponseFormat, type Result, type Success, createConnection, exportResponses, getBearerToken, getResponseExportFile, getResponseExportProgress, startResponseExport, testConnection };
|
package/dist/index.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ type Failure = {
|
|
|
7
7
|
error: string;
|
|
8
8
|
};
|
|
9
9
|
type Result<T> = Success<T> | Failure;
|
|
10
|
+
type ResponseFormat = 'csv' | 'json' | 'ndjson' | 'spss' | 'tsv' | 'xml';
|
|
10
11
|
type Action<TConfig, TResponse> = (options: TConfig) => Promise<Result<TResponse>>;
|
|
11
12
|
type ConnectionOptions = {
|
|
12
13
|
datacenterId: string;
|
|
@@ -15,21 +16,126 @@ type ConnectionOptions = {
|
|
|
15
16
|
};
|
|
16
17
|
type ActionFactory<TParams, TResponse> = (options: ConnectionOptions) => Action<TParams, TResponse>;
|
|
17
18
|
type Connection = {
|
|
18
|
-
|
|
19
|
+
exportResponses: Action<ExportResponsesOptions, Buffer>;
|
|
19
20
|
getBearerToken: Action<{
|
|
20
21
|
clientId: string;
|
|
21
22
|
clientSecret: string;
|
|
23
|
+
scope: string;
|
|
22
24
|
}, string>;
|
|
25
|
+
getResponseExportFile: Action<{
|
|
26
|
+
surveyId: string;
|
|
27
|
+
fileId: string;
|
|
28
|
+
bearerToken?: string;
|
|
29
|
+
}, Buffer>;
|
|
30
|
+
getResponseExportProgress: Action<{
|
|
31
|
+
exportProgressId: string;
|
|
32
|
+
surveyId: string;
|
|
33
|
+
bearerToken?: string;
|
|
34
|
+
}, FileProgressResponse>;
|
|
35
|
+
startResponseExport: Action<ExportResponsesOptions, {
|
|
36
|
+
progressId: string;
|
|
37
|
+
percentComplete: number;
|
|
38
|
+
status: string;
|
|
39
|
+
continuationToken?: string;
|
|
40
|
+
}>;
|
|
41
|
+
testConnection: (bearerToken?: string) => Promise<Result<string>>;
|
|
23
42
|
};
|
|
24
43
|
type ConnectionFactory = (options: ConnectionOptions) => Connection;
|
|
44
|
+
type ExportResponsesOptions = {
|
|
45
|
+
surveyId: string;
|
|
46
|
+
startDate: Date;
|
|
47
|
+
endDate: Date;
|
|
48
|
+
format?: ResponseFormat;
|
|
49
|
+
breakoutSets?: boolean;
|
|
50
|
+
compress?: boolean;
|
|
51
|
+
exportResponsesInProgress?: boolean;
|
|
52
|
+
filterId?: string;
|
|
53
|
+
formatDecimalAsComma?: boolean;
|
|
54
|
+
includeDisplayOrder?: boolean;
|
|
55
|
+
limit?: number;
|
|
56
|
+
multiselectSeenUnansweredRecode?: number;
|
|
57
|
+
newlineReplacement?: string;
|
|
58
|
+
seenUnansweredRecode?: number;
|
|
59
|
+
timeZone?: string;
|
|
60
|
+
useLabels?: boolean;
|
|
61
|
+
embeddedDataIds?: string[];
|
|
62
|
+
questionIds?: string[];
|
|
63
|
+
surveyMetadataIds?: string[];
|
|
64
|
+
continuationToken?: string;
|
|
65
|
+
allowContinuation?: boolean;
|
|
66
|
+
includeLabelColumns?: boolean;
|
|
67
|
+
sortByLastModifiedDate?: boolean;
|
|
68
|
+
bearerToken?: string;
|
|
69
|
+
};
|
|
70
|
+
type FileProgressResponse = {
|
|
71
|
+
fileId: string;
|
|
72
|
+
percentComplete: number;
|
|
73
|
+
status: string;
|
|
74
|
+
continuationToken?: string;
|
|
75
|
+
};
|
|
25
76
|
|
|
26
77
|
declare const createConnection: ConnectionFactory;
|
|
27
78
|
|
|
79
|
+
/**
|
|
80
|
+
* Export Survey Response File
|
|
81
|
+
*
|
|
82
|
+
* Implements Survey Response File Export end to end
|
|
83
|
+
* @see https://api.qualtrics.com/u9e5lh4172v0v-survey-response-export-guide
|
|
84
|
+
*/
|
|
85
|
+
declare const exportResponses: ActionFactory<ExportResponsesOptions, Buffer>;
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Get Bearer Token
|
|
89
|
+
*
|
|
90
|
+
* Implements OAuth Authentication (Client Credentials
|
|
91
|
+
* @see https://api.qualtrics.com/9398592961ced-o-auth-authentication-client-credentials
|
|
92
|
+
*/
|
|
28
93
|
declare const getBearerToken: ActionFactory<{
|
|
29
94
|
clientId: string;
|
|
30
95
|
clientSecret: string;
|
|
96
|
+
scope: string;
|
|
31
97
|
}, string>;
|
|
32
98
|
|
|
33
|
-
|
|
99
|
+
/**
|
|
100
|
+
* Get Response Export File
|
|
101
|
+
*
|
|
102
|
+
* Implements Get Response Export Progress. This is step 2 in the survey response file export process.
|
|
103
|
+
* @see https://api.qualtrics.com/37e6a66f74ab4-get-response-export-progress
|
|
104
|
+
*/
|
|
105
|
+
declare const getResponseExportProgress: ActionFactory<{
|
|
106
|
+
exportProgressId: string;
|
|
107
|
+
surveyId: string;
|
|
108
|
+
bearerToken?: string;
|
|
109
|
+
}, FileProgressResponse>;
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Get Response Export File
|
|
113
|
+
*
|
|
114
|
+
* Implements Get Response Export File. This is step 3 in the survey response file export process.
|
|
115
|
+
* @see https://api.qualtrics.com/41296b6f2e828-get-response-export-file
|
|
116
|
+
*/
|
|
117
|
+
declare const getResponseExportFile: ActionFactory<{
|
|
118
|
+
surveyId: string;
|
|
119
|
+
fileId: string;
|
|
120
|
+
bearerToken?: string;
|
|
121
|
+
}, Buffer>;
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Start Response Export
|
|
125
|
+
*
|
|
126
|
+
* Implements Start Response File Export
|
|
127
|
+
* @see https://api.qualtrics.com/6b00592b9c013-start-response-export
|
|
128
|
+
*/
|
|
129
|
+
declare const startResponseExport: ActionFactory<ExportResponsesOptions, {
|
|
130
|
+
progressId: string;
|
|
131
|
+
percentComplete: number;
|
|
132
|
+
status: string;
|
|
133
|
+
continuationToken?: string;
|
|
134
|
+
}>;
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Test connection to Qualtrics API
|
|
138
|
+
*/
|
|
139
|
+
declare const testConnection: (connectionOptions: ConnectionOptions) => (bearerToken?: string) => Promise<Result<string>>;
|
|
34
140
|
|
|
35
|
-
export { type Action, type ActionFactory, type Connection, type ConnectionFactory, type ConnectionOptions, type Failure, type Result, type Success, createConnection, getBearerToken, testConnection };
|
|
141
|
+
export { type Action, type ActionFactory, type Connection, type ConnectionFactory, type ConnectionOptions, type ExportResponsesOptions, type Failure, type FileProgressResponse, type ResponseFormat, type Result, type Success, createConnection, exportResponses, getBearerToken, getResponseExportFile, getResponseExportProgress, startResponseExport, testConnection };
|
package/dist/index.js
CHANGED
|
@@ -21,12 +21,16 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
21
21
|
var src_exports = {};
|
|
22
22
|
__export(src_exports, {
|
|
23
23
|
createConnection: () => createConnection,
|
|
24
|
+
exportResponses: () => exportResponses,
|
|
24
25
|
getBearerToken: () => getBearerToken,
|
|
26
|
+
getResponseExportFile: () => getResponseExportFile,
|
|
27
|
+
getResponseExportProgress: () => getResponseExportProgress,
|
|
28
|
+
startResponseExport: () => startResponseExport,
|
|
25
29
|
testConnection: () => testConnection
|
|
26
30
|
});
|
|
27
31
|
module.exports = __toCommonJS(src_exports);
|
|
28
32
|
|
|
29
|
-
// src/utils.ts
|
|
33
|
+
// src/utils/index.ts
|
|
30
34
|
function success(data) {
|
|
31
35
|
return {
|
|
32
36
|
success: true,
|
|
@@ -42,12 +46,6 @@ function failure(error) {
|
|
|
42
46
|
function getErrorMessage(error) {
|
|
43
47
|
return error ? typeof error === "object" && "message" in error && typeof error.message === "string" ? error.message : error.toString() : "An error occured";
|
|
44
48
|
}
|
|
45
|
-
function safeParseBearerToken(response) {
|
|
46
|
-
return response?.access_token && typeof response.access_token === "string" ? success(response.access_token) : failure("Incorrect token format");
|
|
47
|
-
}
|
|
48
|
-
function safeParseTestResponse(response) {
|
|
49
|
-
return response?.result?.userId ? success(void 0) : failure("Incorrect test response format");
|
|
50
|
-
}
|
|
51
49
|
function getAuthHeaders(apiToken, bearerToken) {
|
|
52
50
|
if (apiToken)
|
|
53
51
|
return new Headers({
|
|
@@ -55,7 +53,7 @@ function getAuthHeaders(apiToken, bearerToken) {
|
|
|
55
53
|
});
|
|
56
54
|
if (bearerToken) {
|
|
57
55
|
return new Headers({
|
|
58
|
-
Authorization: bearerToken
|
|
56
|
+
Authorization: `Bearer ${bearerToken}`
|
|
59
57
|
});
|
|
60
58
|
}
|
|
61
59
|
throw new Error(
|
|
@@ -63,6 +61,82 @@ function getAuthHeaders(apiToken, bearerToken) {
|
|
|
63
61
|
);
|
|
64
62
|
}
|
|
65
63
|
|
|
64
|
+
// src/utils/poll.ts
|
|
65
|
+
async function poll({
|
|
66
|
+
fn,
|
|
67
|
+
validate,
|
|
68
|
+
interval,
|
|
69
|
+
maxAttempts
|
|
70
|
+
}) {
|
|
71
|
+
let attempts = 0;
|
|
72
|
+
const executePoll = async (resolve, reject) => {
|
|
73
|
+
try {
|
|
74
|
+
const result = await fn();
|
|
75
|
+
attempts++;
|
|
76
|
+
if (validate(result)) {
|
|
77
|
+
return resolve(result);
|
|
78
|
+
} else if (maxAttempts && attempts === maxAttempts) {
|
|
79
|
+
return reject(new Error("Exceeded max attempts"));
|
|
80
|
+
} else {
|
|
81
|
+
setTimeout(executePoll, interval, resolve, reject);
|
|
82
|
+
}
|
|
83
|
+
} catch (error) {
|
|
84
|
+
reject(new Error(`Poll function execution failed: ${error}`));
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
return new Promise(executePoll);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// src/methods/exportResponses.ts
|
|
91
|
+
var exportResponses = (connectionOptions) => async (responseOptions) => {
|
|
92
|
+
try {
|
|
93
|
+
const startResponseAction = startResponseExport(connectionOptions);
|
|
94
|
+
const startResponse = await startResponseAction(responseOptions);
|
|
95
|
+
if (!startResponse.success)
|
|
96
|
+
return failure(startResponse.error);
|
|
97
|
+
const exportProgressAction = getResponseExportProgress(connectionOptions);
|
|
98
|
+
const progressResponse = await poll({
|
|
99
|
+
fn: async () => await exportProgressAction({
|
|
100
|
+
exportProgressId: startResponse.data.progressId,
|
|
101
|
+
surveyId: responseOptions.surveyId,
|
|
102
|
+
bearerToken: responseOptions.bearerToken
|
|
103
|
+
}),
|
|
104
|
+
validate: (res) => res.success && res.data.percentComplete === 100,
|
|
105
|
+
interval: 1,
|
|
106
|
+
maxAttempts: 60
|
|
107
|
+
});
|
|
108
|
+
if (!progressResponse.success)
|
|
109
|
+
return failure(progressResponse.error);
|
|
110
|
+
const getFileResponseAction = getResponseExportFile(connectionOptions);
|
|
111
|
+
const fileResponse = await getFileResponseAction({
|
|
112
|
+
surveyId: responseOptions.surveyId,
|
|
113
|
+
fileId: progressResponse.data.fileId,
|
|
114
|
+
bearerToken: responseOptions.bearerToken
|
|
115
|
+
});
|
|
116
|
+
return fileResponse;
|
|
117
|
+
} catch (error) {
|
|
118
|
+
const message = getErrorMessage(error);
|
|
119
|
+
return failure(message);
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
// src/utils/parsers.ts
|
|
124
|
+
function safeParseBearerToken(response) {
|
|
125
|
+
return response?.access_token && typeof response.access_token === "string" ? success(response.access_token) : failure("Incorrect token format");
|
|
126
|
+
}
|
|
127
|
+
function safeParseTestResponse(response) {
|
|
128
|
+
return response?.result?.userId ? success("Connection successful") : failure("Incorrect test response format");
|
|
129
|
+
}
|
|
130
|
+
function safeParseStartFileExportResponse(response) {
|
|
131
|
+
return "result" in response ? "progressId" in response.result && "percentComplete" in response.result && "status" in response.result ? success(response.result) : failure("Start Export Response invalid format") : "error" in response ? failure(`${response.error.errorCode}: ${response.error.errorMessage}`) : failure(`Unable to parse Start Export Response`);
|
|
132
|
+
}
|
|
133
|
+
function safeParseFileProgressResponse(response) {
|
|
134
|
+
return "result" in response ? "fileId" in response.result && "percentComplete" in response.result && "status" in response.result ? success(response.result) : failure("File Progress Response invalid format") : "error" in response ? failure(`${response.error.errorCode}: ${response.error.errorMessage}`) : failure(`Unable to parse File Progress Response`);
|
|
135
|
+
}
|
|
136
|
+
function safeParseFileResponse(response) {
|
|
137
|
+
return Buffer.isBuffer(response) ? success(response) : failure("Incorrect file response format");
|
|
138
|
+
}
|
|
139
|
+
|
|
66
140
|
// src/qualtrics/index.ts
|
|
67
141
|
async function execute(config) {
|
|
68
142
|
const { datacenterId, route, headers, timeout, body } = config;
|
|
@@ -75,8 +149,10 @@ async function execute(config) {
|
|
|
75
149
|
signal: controller.signal
|
|
76
150
|
};
|
|
77
151
|
if (body) {
|
|
78
|
-
if (typeof body === "string")
|
|
152
|
+
if (typeof body === "string") {
|
|
79
153
|
headers.append("Content-Type", "application/json");
|
|
154
|
+
headers.append("Accept", "application/json");
|
|
155
|
+
}
|
|
80
156
|
options.method = "POST";
|
|
81
157
|
options.headers = headers;
|
|
82
158
|
options.body = body;
|
|
@@ -88,13 +164,13 @@ async function execute(config) {
|
|
|
88
164
|
const data = await response.json();
|
|
89
165
|
return Promise.resolve(data);
|
|
90
166
|
} else {
|
|
91
|
-
const message = await response.
|
|
167
|
+
const message = await response.json();
|
|
92
168
|
return Promise.reject(`${response.status}: ${message}`);
|
|
93
169
|
}
|
|
94
170
|
}
|
|
95
171
|
|
|
96
172
|
// src/methods/getBearerToken.ts
|
|
97
|
-
var getBearerToken = (connectionOptions) => async ({ clientId, clientSecret }) => {
|
|
173
|
+
var getBearerToken = (connectionOptions) => async ({ clientId, clientSecret, scope }) => {
|
|
98
174
|
const route = `/oauth2/token`;
|
|
99
175
|
try {
|
|
100
176
|
const { datacenterId, timeout } = connectionOptions;
|
|
@@ -103,7 +179,7 @@ var getBearerToken = (connectionOptions) => async ({ clientId, clientSecret }) =
|
|
|
103
179
|
});
|
|
104
180
|
const body = new FormData();
|
|
105
181
|
body.append("grant_type", "client_credentials");
|
|
106
|
-
body.append("scope",
|
|
182
|
+
body.append("scope", scope);
|
|
107
183
|
const response = await execute({
|
|
108
184
|
datacenterId,
|
|
109
185
|
route,
|
|
@@ -119,6 +195,82 @@ var getBearerToken = (connectionOptions) => async ({ clientId, clientSecret }) =
|
|
|
119
195
|
}
|
|
120
196
|
};
|
|
121
197
|
|
|
198
|
+
// src/methods/getResponseExportProgress.ts
|
|
199
|
+
var getResponseExportProgress = (connectionOptions) => async ({ exportProgressId, surveyId, bearerToken }) => {
|
|
200
|
+
const route = `/surveys/${surveyId}/export-responses/${exportProgressId}`;
|
|
201
|
+
try {
|
|
202
|
+
const headers = getAuthHeaders(connectionOptions.apiToken, bearerToken);
|
|
203
|
+
const config = {
|
|
204
|
+
datacenterId: connectionOptions.datacenterId,
|
|
205
|
+
route,
|
|
206
|
+
headers,
|
|
207
|
+
timeout: connectionOptions.timeout
|
|
208
|
+
};
|
|
209
|
+
const response = await execute(config);
|
|
210
|
+
const result = safeParseFileProgressResponse(response);
|
|
211
|
+
return result;
|
|
212
|
+
} catch (error) {
|
|
213
|
+
const message = getErrorMessage(error);
|
|
214
|
+
return failure(message);
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
// src/methods/getResponseExportFile.ts
|
|
219
|
+
var getResponseExportFile = (connectionOptions) => async ({ surveyId, fileId, bearerToken }) => {
|
|
220
|
+
const route = `/surveys/${surveyId}/export-responses/${fileId}/file`;
|
|
221
|
+
try {
|
|
222
|
+
const headers = getAuthHeaders(connectionOptions.apiToken, bearerToken);
|
|
223
|
+
const config = {
|
|
224
|
+
datacenterId: connectionOptions.datacenterId,
|
|
225
|
+
route,
|
|
226
|
+
headers,
|
|
227
|
+
timeout: connectionOptions.timeout
|
|
228
|
+
};
|
|
229
|
+
const response = await execute(config);
|
|
230
|
+
const result = safeParseFileResponse(response);
|
|
231
|
+
return result;
|
|
232
|
+
} catch (error) {
|
|
233
|
+
const message = getErrorMessage(error);
|
|
234
|
+
return failure(message);
|
|
235
|
+
}
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
// src/methods/startResponseExport.ts
|
|
239
|
+
var startResponseExport = (connectionOptions) => async ({
|
|
240
|
+
surveyId,
|
|
241
|
+
startDate,
|
|
242
|
+
endDate,
|
|
243
|
+
format = "csv",
|
|
244
|
+
bearerToken = void 0,
|
|
245
|
+
...rest
|
|
246
|
+
}) => {
|
|
247
|
+
const route = `/surveys/${surveyId}/export-responses`;
|
|
248
|
+
try {
|
|
249
|
+
const headers = getAuthHeaders(connectionOptions.apiToken, bearerToken);
|
|
250
|
+
const body = JSON.stringify({
|
|
251
|
+
startDate: "2024-03-01T06:00:00Z",
|
|
252
|
+
//startDate.toISOString(),
|
|
253
|
+
endDate: "2024-03-05T06:00:00Z",
|
|
254
|
+
//endDate.toISOString(),
|
|
255
|
+
format,
|
|
256
|
+
...rest
|
|
257
|
+
});
|
|
258
|
+
const config = {
|
|
259
|
+
datacenterId: connectionOptions.datacenterId,
|
|
260
|
+
route,
|
|
261
|
+
headers,
|
|
262
|
+
body,
|
|
263
|
+
timeout: connectionOptions.timeout
|
|
264
|
+
};
|
|
265
|
+
const response = await execute(config);
|
|
266
|
+
const result = safeParseStartFileExportResponse(response);
|
|
267
|
+
return result;
|
|
268
|
+
} catch (error) {
|
|
269
|
+
const message = getErrorMessage(error);
|
|
270
|
+
return failure(message);
|
|
271
|
+
}
|
|
272
|
+
};
|
|
273
|
+
|
|
122
274
|
// src/methods/testConnection.ts
|
|
123
275
|
var testConnection = (connectionOptions) => async (bearerToken) => {
|
|
124
276
|
const route = "/API/v3/whoami";
|
|
@@ -141,12 +293,20 @@ var testConnection = (connectionOptions) => async (bearerToken) => {
|
|
|
141
293
|
|
|
142
294
|
// src/createConnection.ts
|
|
143
295
|
var createConnection = (options) => ({
|
|
144
|
-
|
|
145
|
-
getBearerToken: getBearerToken(options)
|
|
296
|
+
exportResponses: exportResponses(options),
|
|
297
|
+
getBearerToken: getBearerToken(options),
|
|
298
|
+
getResponseExportFile: getResponseExportFile(options),
|
|
299
|
+
getResponseExportProgress: getResponseExportProgress(options),
|
|
300
|
+
startResponseExport: startResponseExport(options),
|
|
301
|
+
testConnection: testConnection(options)
|
|
146
302
|
});
|
|
147
303
|
// Annotate the CommonJS export names for ESM import in node:
|
|
148
304
|
0 && (module.exports = {
|
|
149
305
|
createConnection,
|
|
306
|
+
exportResponses,
|
|
150
307
|
getBearerToken,
|
|
308
|
+
getResponseExportFile,
|
|
309
|
+
getResponseExportProgress,
|
|
310
|
+
startResponseExport,
|
|
151
311
|
testConnection
|
|
152
312
|
});
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// src/utils.ts
|
|
1
|
+
// src/utils/index.ts
|
|
2
2
|
function success(data) {
|
|
3
3
|
return {
|
|
4
4
|
success: true,
|
|
@@ -14,12 +14,6 @@ function failure(error) {
|
|
|
14
14
|
function getErrorMessage(error) {
|
|
15
15
|
return error ? typeof error === "object" && "message" in error && typeof error.message === "string" ? error.message : error.toString() : "An error occured";
|
|
16
16
|
}
|
|
17
|
-
function safeParseBearerToken(response) {
|
|
18
|
-
return response?.access_token && typeof response.access_token === "string" ? success(response.access_token) : failure("Incorrect token format");
|
|
19
|
-
}
|
|
20
|
-
function safeParseTestResponse(response) {
|
|
21
|
-
return response?.result?.userId ? success(void 0) : failure("Incorrect test response format");
|
|
22
|
-
}
|
|
23
17
|
function getAuthHeaders(apiToken, bearerToken) {
|
|
24
18
|
if (apiToken)
|
|
25
19
|
return new Headers({
|
|
@@ -27,7 +21,7 @@ function getAuthHeaders(apiToken, bearerToken) {
|
|
|
27
21
|
});
|
|
28
22
|
if (bearerToken) {
|
|
29
23
|
return new Headers({
|
|
30
|
-
Authorization: bearerToken
|
|
24
|
+
Authorization: `Bearer ${bearerToken}`
|
|
31
25
|
});
|
|
32
26
|
}
|
|
33
27
|
throw new Error(
|
|
@@ -35,6 +29,82 @@ function getAuthHeaders(apiToken, bearerToken) {
|
|
|
35
29
|
);
|
|
36
30
|
}
|
|
37
31
|
|
|
32
|
+
// src/utils/poll.ts
|
|
33
|
+
async function poll({
|
|
34
|
+
fn,
|
|
35
|
+
validate,
|
|
36
|
+
interval,
|
|
37
|
+
maxAttempts
|
|
38
|
+
}) {
|
|
39
|
+
let attempts = 0;
|
|
40
|
+
const executePoll = async (resolve, reject) => {
|
|
41
|
+
try {
|
|
42
|
+
const result = await fn();
|
|
43
|
+
attempts++;
|
|
44
|
+
if (validate(result)) {
|
|
45
|
+
return resolve(result);
|
|
46
|
+
} else if (maxAttempts && attempts === maxAttempts) {
|
|
47
|
+
return reject(new Error("Exceeded max attempts"));
|
|
48
|
+
} else {
|
|
49
|
+
setTimeout(executePoll, interval, resolve, reject);
|
|
50
|
+
}
|
|
51
|
+
} catch (error) {
|
|
52
|
+
reject(new Error(`Poll function execution failed: ${error}`));
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
return new Promise(executePoll);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// src/methods/exportResponses.ts
|
|
59
|
+
var exportResponses = (connectionOptions) => async (responseOptions) => {
|
|
60
|
+
try {
|
|
61
|
+
const startResponseAction = startResponseExport(connectionOptions);
|
|
62
|
+
const startResponse = await startResponseAction(responseOptions);
|
|
63
|
+
if (!startResponse.success)
|
|
64
|
+
return failure(startResponse.error);
|
|
65
|
+
const exportProgressAction = getResponseExportProgress(connectionOptions);
|
|
66
|
+
const progressResponse = await poll({
|
|
67
|
+
fn: async () => await exportProgressAction({
|
|
68
|
+
exportProgressId: startResponse.data.progressId,
|
|
69
|
+
surveyId: responseOptions.surveyId,
|
|
70
|
+
bearerToken: responseOptions.bearerToken
|
|
71
|
+
}),
|
|
72
|
+
validate: (res) => res.success && res.data.percentComplete === 100,
|
|
73
|
+
interval: 1,
|
|
74
|
+
maxAttempts: 60
|
|
75
|
+
});
|
|
76
|
+
if (!progressResponse.success)
|
|
77
|
+
return failure(progressResponse.error);
|
|
78
|
+
const getFileResponseAction = getResponseExportFile(connectionOptions);
|
|
79
|
+
const fileResponse = await getFileResponseAction({
|
|
80
|
+
surveyId: responseOptions.surveyId,
|
|
81
|
+
fileId: progressResponse.data.fileId,
|
|
82
|
+
bearerToken: responseOptions.bearerToken
|
|
83
|
+
});
|
|
84
|
+
return fileResponse;
|
|
85
|
+
} catch (error) {
|
|
86
|
+
const message = getErrorMessage(error);
|
|
87
|
+
return failure(message);
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
// src/utils/parsers.ts
|
|
92
|
+
function safeParseBearerToken(response) {
|
|
93
|
+
return response?.access_token && typeof response.access_token === "string" ? success(response.access_token) : failure("Incorrect token format");
|
|
94
|
+
}
|
|
95
|
+
function safeParseTestResponse(response) {
|
|
96
|
+
return response?.result?.userId ? success("Connection successful") : failure("Incorrect test response format");
|
|
97
|
+
}
|
|
98
|
+
function safeParseStartFileExportResponse(response) {
|
|
99
|
+
return "result" in response ? "progressId" in response.result && "percentComplete" in response.result && "status" in response.result ? success(response.result) : failure("Start Export Response invalid format") : "error" in response ? failure(`${response.error.errorCode}: ${response.error.errorMessage}`) : failure(`Unable to parse Start Export Response`);
|
|
100
|
+
}
|
|
101
|
+
function safeParseFileProgressResponse(response) {
|
|
102
|
+
return "result" in response ? "fileId" in response.result && "percentComplete" in response.result && "status" in response.result ? success(response.result) : failure("File Progress Response invalid format") : "error" in response ? failure(`${response.error.errorCode}: ${response.error.errorMessage}`) : failure(`Unable to parse File Progress Response`);
|
|
103
|
+
}
|
|
104
|
+
function safeParseFileResponse(response) {
|
|
105
|
+
return Buffer.isBuffer(response) ? success(response) : failure("Incorrect file response format");
|
|
106
|
+
}
|
|
107
|
+
|
|
38
108
|
// src/qualtrics/index.ts
|
|
39
109
|
async function execute(config) {
|
|
40
110
|
const { datacenterId, route, headers, timeout, body } = config;
|
|
@@ -47,8 +117,10 @@ async function execute(config) {
|
|
|
47
117
|
signal: controller.signal
|
|
48
118
|
};
|
|
49
119
|
if (body) {
|
|
50
|
-
if (typeof body === "string")
|
|
120
|
+
if (typeof body === "string") {
|
|
51
121
|
headers.append("Content-Type", "application/json");
|
|
122
|
+
headers.append("Accept", "application/json");
|
|
123
|
+
}
|
|
52
124
|
options.method = "POST";
|
|
53
125
|
options.headers = headers;
|
|
54
126
|
options.body = body;
|
|
@@ -60,13 +132,13 @@ async function execute(config) {
|
|
|
60
132
|
const data = await response.json();
|
|
61
133
|
return Promise.resolve(data);
|
|
62
134
|
} else {
|
|
63
|
-
const message = await response.
|
|
135
|
+
const message = await response.json();
|
|
64
136
|
return Promise.reject(`${response.status}: ${message}`);
|
|
65
137
|
}
|
|
66
138
|
}
|
|
67
139
|
|
|
68
140
|
// src/methods/getBearerToken.ts
|
|
69
|
-
var getBearerToken = (connectionOptions) => async ({ clientId, clientSecret }) => {
|
|
141
|
+
var getBearerToken = (connectionOptions) => async ({ clientId, clientSecret, scope }) => {
|
|
70
142
|
const route = `/oauth2/token`;
|
|
71
143
|
try {
|
|
72
144
|
const { datacenterId, timeout } = connectionOptions;
|
|
@@ -75,7 +147,7 @@ var getBearerToken = (connectionOptions) => async ({ clientId, clientSecret }) =
|
|
|
75
147
|
});
|
|
76
148
|
const body = new FormData();
|
|
77
149
|
body.append("grant_type", "client_credentials");
|
|
78
|
-
body.append("scope",
|
|
150
|
+
body.append("scope", scope);
|
|
79
151
|
const response = await execute({
|
|
80
152
|
datacenterId,
|
|
81
153
|
route,
|
|
@@ -91,6 +163,82 @@ var getBearerToken = (connectionOptions) => async ({ clientId, clientSecret }) =
|
|
|
91
163
|
}
|
|
92
164
|
};
|
|
93
165
|
|
|
166
|
+
// src/methods/getResponseExportProgress.ts
|
|
167
|
+
var getResponseExportProgress = (connectionOptions) => async ({ exportProgressId, surveyId, bearerToken }) => {
|
|
168
|
+
const route = `/surveys/${surveyId}/export-responses/${exportProgressId}`;
|
|
169
|
+
try {
|
|
170
|
+
const headers = getAuthHeaders(connectionOptions.apiToken, bearerToken);
|
|
171
|
+
const config = {
|
|
172
|
+
datacenterId: connectionOptions.datacenterId,
|
|
173
|
+
route,
|
|
174
|
+
headers,
|
|
175
|
+
timeout: connectionOptions.timeout
|
|
176
|
+
};
|
|
177
|
+
const response = await execute(config);
|
|
178
|
+
const result = safeParseFileProgressResponse(response);
|
|
179
|
+
return result;
|
|
180
|
+
} catch (error) {
|
|
181
|
+
const message = getErrorMessage(error);
|
|
182
|
+
return failure(message);
|
|
183
|
+
}
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
// src/methods/getResponseExportFile.ts
|
|
187
|
+
var getResponseExportFile = (connectionOptions) => async ({ surveyId, fileId, bearerToken }) => {
|
|
188
|
+
const route = `/surveys/${surveyId}/export-responses/${fileId}/file`;
|
|
189
|
+
try {
|
|
190
|
+
const headers = getAuthHeaders(connectionOptions.apiToken, bearerToken);
|
|
191
|
+
const config = {
|
|
192
|
+
datacenterId: connectionOptions.datacenterId,
|
|
193
|
+
route,
|
|
194
|
+
headers,
|
|
195
|
+
timeout: connectionOptions.timeout
|
|
196
|
+
};
|
|
197
|
+
const response = await execute(config);
|
|
198
|
+
const result = safeParseFileResponse(response);
|
|
199
|
+
return result;
|
|
200
|
+
} catch (error) {
|
|
201
|
+
const message = getErrorMessage(error);
|
|
202
|
+
return failure(message);
|
|
203
|
+
}
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
// src/methods/startResponseExport.ts
|
|
207
|
+
var startResponseExport = (connectionOptions) => async ({
|
|
208
|
+
surveyId,
|
|
209
|
+
startDate,
|
|
210
|
+
endDate,
|
|
211
|
+
format = "csv",
|
|
212
|
+
bearerToken = void 0,
|
|
213
|
+
...rest
|
|
214
|
+
}) => {
|
|
215
|
+
const route = `/surveys/${surveyId}/export-responses`;
|
|
216
|
+
try {
|
|
217
|
+
const headers = getAuthHeaders(connectionOptions.apiToken, bearerToken);
|
|
218
|
+
const body = JSON.stringify({
|
|
219
|
+
startDate: "2024-03-01T06:00:00Z",
|
|
220
|
+
//startDate.toISOString(),
|
|
221
|
+
endDate: "2024-03-05T06:00:00Z",
|
|
222
|
+
//endDate.toISOString(),
|
|
223
|
+
format,
|
|
224
|
+
...rest
|
|
225
|
+
});
|
|
226
|
+
const config = {
|
|
227
|
+
datacenterId: connectionOptions.datacenterId,
|
|
228
|
+
route,
|
|
229
|
+
headers,
|
|
230
|
+
body,
|
|
231
|
+
timeout: connectionOptions.timeout
|
|
232
|
+
};
|
|
233
|
+
const response = await execute(config);
|
|
234
|
+
const result = safeParseStartFileExportResponse(response);
|
|
235
|
+
return result;
|
|
236
|
+
} catch (error) {
|
|
237
|
+
const message = getErrorMessage(error);
|
|
238
|
+
return failure(message);
|
|
239
|
+
}
|
|
240
|
+
};
|
|
241
|
+
|
|
94
242
|
// src/methods/testConnection.ts
|
|
95
243
|
var testConnection = (connectionOptions) => async (bearerToken) => {
|
|
96
244
|
const route = "/API/v3/whoami";
|
|
@@ -113,11 +261,19 @@ var testConnection = (connectionOptions) => async (bearerToken) => {
|
|
|
113
261
|
|
|
114
262
|
// src/createConnection.ts
|
|
115
263
|
var createConnection = (options) => ({
|
|
116
|
-
|
|
117
|
-
getBearerToken: getBearerToken(options)
|
|
264
|
+
exportResponses: exportResponses(options),
|
|
265
|
+
getBearerToken: getBearerToken(options),
|
|
266
|
+
getResponseExportFile: getResponseExportFile(options),
|
|
267
|
+
getResponseExportProgress: getResponseExportProgress(options),
|
|
268
|
+
startResponseExport: startResponseExport(options),
|
|
269
|
+
testConnection: testConnection(options)
|
|
118
270
|
});
|
|
119
271
|
export {
|
|
120
272
|
createConnection,
|
|
273
|
+
exportResponses,
|
|
121
274
|
getBearerToken,
|
|
275
|
+
getResponseExportFile,
|
|
276
|
+
getResponseExportProgress,
|
|
277
|
+
startResponseExport,
|
|
122
278
|
testConnection
|
|
123
279
|
};
|
package/package.json
CHANGED
package/tests/utils.test.ts
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { describe, it, expect } from 'vitest'
|
|
2
|
+
import { success, failure } from '../src/utils'
|
|
2
3
|
import {
|
|
3
|
-
success,
|
|
4
|
-
failure,
|
|
5
4
|
safeParseBearerToken,
|
|
6
5
|
safeParseTestResponse,
|
|
7
|
-
|
|
6
|
+
safeParseStartFileExportResponse,
|
|
7
|
+
safeParseFileProgressResponse,
|
|
8
|
+
safeParseFileResponse,
|
|
9
|
+
} from '../src/utils/parsers'
|
|
8
10
|
|
|
9
11
|
describe('safeParseBearerToken', () => {
|
|
10
12
|
const fixture = {
|
|
@@ -29,6 +31,92 @@ describe('safeParseBearerToken', () => {
|
|
|
29
31
|
})
|
|
30
32
|
})
|
|
31
33
|
|
|
34
|
+
describe('safeParseFileProgressResponse', () => {
|
|
35
|
+
const fixture = {
|
|
36
|
+
result: {
|
|
37
|
+
fileId: 'sometoken',
|
|
38
|
+
percentComplete: 0,
|
|
39
|
+
status: 'inProgress',
|
|
40
|
+
},
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
it('should pass with correct data', () => {
|
|
44
|
+
const res = fixture
|
|
45
|
+
const expected = success(fixture.result)
|
|
46
|
+
const parsed = safeParseFileProgressResponse(res)
|
|
47
|
+
expect(parsed).toStrictEqual(expected)
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
it('should fail when error response', () => {
|
|
51
|
+
const res = {
|
|
52
|
+
error: {
|
|
53
|
+
errorCode: '401',
|
|
54
|
+
errorMessage: 'Some error',
|
|
55
|
+
},
|
|
56
|
+
}
|
|
57
|
+
const expected = failure(
|
|
58
|
+
`${res.error.errorCode}: ${res.error.errorMessage}`
|
|
59
|
+
)
|
|
60
|
+
const parsed = safeParseFileProgressResponse(res)
|
|
61
|
+
expect(parsed).toStrictEqual(expected)
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
it('should fail with missing props', () => {
|
|
65
|
+
const res = {
|
|
66
|
+
result: {
|
|
67
|
+
percentComplete: 0,
|
|
68
|
+
status: 'inProgress',
|
|
69
|
+
},
|
|
70
|
+
}
|
|
71
|
+
const expected = failure('File Progress Response invalid format')
|
|
72
|
+
const parsed = safeParseFileProgressResponse(res)
|
|
73
|
+
expect(parsed).toStrictEqual(expected)
|
|
74
|
+
})
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
describe('safeParseStartFileExportResponse', () => {
|
|
78
|
+
const fixture = {
|
|
79
|
+
result: {
|
|
80
|
+
progressId: 'sometoken',
|
|
81
|
+
percentComplete: 0,
|
|
82
|
+
status: 'inProgress',
|
|
83
|
+
},
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
it('should pass with correct data', () => {
|
|
87
|
+
const res = fixture
|
|
88
|
+
const expected = success(fixture.result)
|
|
89
|
+
const parsed = safeParseStartFileExportResponse(res)
|
|
90
|
+
expect(parsed).toStrictEqual(expected)
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
it('should fail when error response', () => {
|
|
94
|
+
const res = {
|
|
95
|
+
error: {
|
|
96
|
+
errorCode: '401',
|
|
97
|
+
errorMessage: 'Some error',
|
|
98
|
+
},
|
|
99
|
+
}
|
|
100
|
+
const expected = failure(
|
|
101
|
+
`${res.error.errorCode}: ${res.error.errorMessage}`
|
|
102
|
+
)
|
|
103
|
+
const parsed = safeParseStartFileExportResponse(res)
|
|
104
|
+
expect(parsed).toStrictEqual(expected)
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
it('should fail with missing props', () => {
|
|
108
|
+
const res = {
|
|
109
|
+
result: {
|
|
110
|
+
percentComplete: 0,
|
|
111
|
+
status: 'inProgress',
|
|
112
|
+
},
|
|
113
|
+
}
|
|
114
|
+
const expected = failure('Start Export Response invalid format')
|
|
115
|
+
const parsed = safeParseStartFileExportResponse(res)
|
|
116
|
+
expect(parsed).toStrictEqual(expected)
|
|
117
|
+
})
|
|
118
|
+
})
|
|
119
|
+
|
|
32
120
|
describe('safeParseTestResponse', () => {
|
|
33
121
|
const fixture = {
|
|
34
122
|
result: {
|
|
@@ -38,7 +126,7 @@ describe('safeParseTestResponse', () => {
|
|
|
38
126
|
|
|
39
127
|
it('should pass with correct data', () => {
|
|
40
128
|
const res = fixture
|
|
41
|
-
const expected = success(
|
|
129
|
+
const expected = success('Connection successful')
|
|
42
130
|
const parsed = safeParseTestResponse(res)
|
|
43
131
|
expect(parsed).toStrictEqual(expected)
|
|
44
132
|
})
|
|
@@ -52,3 +140,21 @@ describe('safeParseTestResponse', () => {
|
|
|
52
140
|
expect(parsed).toStrictEqual(expected)
|
|
53
141
|
})
|
|
54
142
|
})
|
|
143
|
+
|
|
144
|
+
describe('safeParseFileResponse', () => {
|
|
145
|
+
const fixture = Buffer.from('file content')
|
|
146
|
+
|
|
147
|
+
it('should pass with correct data', () => {
|
|
148
|
+
const res = fixture
|
|
149
|
+
const expected = success(fixture)
|
|
150
|
+
const parsed = safeParseFileResponse(res)
|
|
151
|
+
expect(parsed).toStrictEqual(expected)
|
|
152
|
+
})
|
|
153
|
+
|
|
154
|
+
it('should fail with invalid response type', () => {
|
|
155
|
+
const res = { fixture }
|
|
156
|
+
const expected = failure('Incorrect file response format')
|
|
157
|
+
const parsed = safeParseFileResponse(res)
|
|
158
|
+
expect(parsed).toStrictEqual(expected)
|
|
159
|
+
})
|
|
160
|
+
})
|