@b-jones-rfd/qualtrics-api-tasks 0.1.0 → 0.2.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/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @b-jones-rfd/qualtrics-api-tasks
2
2
 
3
+ ## 0.2.0
4
+
5
+ ### Minor Changes
6
+
7
+ - a5028bb: Support file export multiple formats
8
+
9
+ ## 0.1.1
10
+
11
+ ### Patch Changes
12
+
13
+ - 2f8dbdf: Added JSDoc action method descriptions
14
+
3
15
  ## 0.1.0
4
16
 
5
17
  ### Minor 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: 20000, // optional timeout in milliseconds, default is 30 seconds
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 | Required |
127
- | ------ | ------------- | ------------------------- | --------------------- | -------- |
128
- | number | 30000 | Qualtrics request timeout | sharepoint.domain.com | N |
126
+ | Type | Default value | Description | Example | Required |
127
+ | ------ | ------------- | ------------------------- | ------- | -------- |
128
+ | number | 30000 | Qualtrics request timeout | 1000 | N |
129
129
 
130
130
  ### Actions
131
131
 
package/dist/index.d.mts CHANGED
@@ -22,6 +22,11 @@ type Connection = {
22
22
  clientSecret: string;
23
23
  scope: string;
24
24
  }, string>;
25
+ getResponseExportFile: Action<{
26
+ surveyId: string;
27
+ fileId: string;
28
+ bearerToken?: string;
29
+ }, Buffer>;
25
30
  getResponseExportProgress: Action<{
26
31
  exportProgressId: string;
27
32
  surveyId: string;
@@ -33,7 +38,7 @@ type Connection = {
33
38
  status: string;
34
39
  continuationToken?: string;
35
40
  }>;
36
- testConnection: (bearerToken?: string) => Promise<Result<void>>;
41
+ testConnection: (bearerToken?: string) => Promise<Result<string>>;
37
42
  };
38
43
  type ConnectionFactory = (options: ConnectionOptions) => Connection;
39
44
  type ExportResponsesOptions = {
@@ -71,26 +76,56 @@ type FileProgressResponse = {
71
76
 
72
77
  declare const createConnection: ConnectionFactory;
73
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
+ */
74
85
  declare const exportResponses: ActionFactory<ExportResponsesOptions, Buffer>;
75
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
+ */
76
93
  declare const getBearerToken: ActionFactory<{
77
94
  clientId: string;
78
95
  clientSecret: string;
79
96
  scope: string;
80
97
  }, string>;
81
98
 
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
+ */
82
105
  declare const getResponseExportProgress: ActionFactory<{
83
106
  exportProgressId: string;
84
107
  surveyId: string;
85
108
  bearerToken?: string;
86
109
  }, FileProgressResponse>;
87
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
+ */
88
117
  declare const getResponseExportFile: ActionFactory<{
89
118
  surveyId: string;
90
119
  fileId: string;
91
120
  bearerToken?: string;
92
121
  }, Buffer>;
93
122
 
123
+ /**
124
+ * Start Response Export
125
+ *
126
+ * Implements Start Response File Export
127
+ * @see https://api.qualtrics.com/6b00592b9c013-start-response-export
128
+ */
94
129
  declare const startResponseExport: ActionFactory<ExportResponsesOptions, {
95
130
  progressId: string;
96
131
  percentComplete: number;
@@ -98,6 +133,9 @@ declare const startResponseExport: ActionFactory<ExportResponsesOptions, {
98
133
  continuationToken?: string;
99
134
  }>;
100
135
 
101
- declare const testConnection: (connectionOptions: ConnectionOptions) => (bearerToken?: string) => Promise<Result<void>>;
136
+ /**
137
+ * Test connection to Qualtrics API
138
+ */
139
+ declare const testConnection: (connectionOptions: ConnectionOptions) => (bearerToken?: string) => Promise<Result<string>>;
102
140
 
103
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
@@ -22,6 +22,11 @@ type Connection = {
22
22
  clientSecret: string;
23
23
  scope: string;
24
24
  }, string>;
25
+ getResponseExportFile: Action<{
26
+ surveyId: string;
27
+ fileId: string;
28
+ bearerToken?: string;
29
+ }, Buffer>;
25
30
  getResponseExportProgress: Action<{
26
31
  exportProgressId: string;
27
32
  surveyId: string;
@@ -33,7 +38,7 @@ type Connection = {
33
38
  status: string;
34
39
  continuationToken?: string;
35
40
  }>;
36
- testConnection: (bearerToken?: string) => Promise<Result<void>>;
41
+ testConnection: (bearerToken?: string) => Promise<Result<string>>;
37
42
  };
38
43
  type ConnectionFactory = (options: ConnectionOptions) => Connection;
39
44
  type ExportResponsesOptions = {
@@ -71,26 +76,56 @@ type FileProgressResponse = {
71
76
 
72
77
  declare const createConnection: ConnectionFactory;
73
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
+ */
74
85
  declare const exportResponses: ActionFactory<ExportResponsesOptions, Buffer>;
75
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
+ */
76
93
  declare const getBearerToken: ActionFactory<{
77
94
  clientId: string;
78
95
  clientSecret: string;
79
96
  scope: string;
80
97
  }, string>;
81
98
 
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
+ */
82
105
  declare const getResponseExportProgress: ActionFactory<{
83
106
  exportProgressId: string;
84
107
  surveyId: string;
85
108
  bearerToken?: string;
86
109
  }, FileProgressResponse>;
87
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
+ */
88
117
  declare const getResponseExportFile: ActionFactory<{
89
118
  surveyId: string;
90
119
  fileId: string;
91
120
  bearerToken?: string;
92
121
  }, Buffer>;
93
122
 
123
+ /**
124
+ * Start Response Export
125
+ *
126
+ * Implements Start Response File Export
127
+ * @see https://api.qualtrics.com/6b00592b9c013-start-response-export
128
+ */
94
129
  declare const startResponseExport: ActionFactory<ExportResponsesOptions, {
95
130
  progressId: string;
96
131
  percentComplete: number;
@@ -98,6 +133,9 @@ declare const startResponseExport: ActionFactory<ExportResponsesOptions, {
98
133
  continuationToken?: string;
99
134
  }>;
100
135
 
101
- declare const testConnection: (connectionOptions: ConnectionOptions) => (bearerToken?: string) => Promise<Result<void>>;
136
+ /**
137
+ * Test connection to Qualtrics API
138
+ */
139
+ declare const testConnection: (connectionOptions: ConnectionOptions) => (bearerToken?: string) => Promise<Result<string>>;
102
140
 
103
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
@@ -125,7 +125,7 @@ function safeParseBearerToken(response) {
125
125
  return response?.access_token && typeof response.access_token === "string" ? success(response.access_token) : failure("Incorrect token format");
126
126
  }
127
127
  function safeParseTestResponse(response) {
128
- return response?.result?.userId ? success(void 0) : failure("Incorrect test response format");
128
+ return response?.result?.userId ? success("Connection successful") : failure("Incorrect test response format");
129
129
  }
130
130
  function safeParseStartFileExportResponse(response) {
131
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`);
@@ -133,9 +133,6 @@ function safeParseStartFileExportResponse(response) {
133
133
  function safeParseFileProgressResponse(response) {
134
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
135
  }
136
- function safeParseFileResponse(response) {
137
- return Buffer.isBuffer(response) ? success(response) : failure("Incorrect file response format");
138
- }
139
136
 
140
137
  // src/qualtrics/index.ts
141
138
  async function execute(config) {
@@ -149,8 +146,9 @@ async function execute(config) {
149
146
  signal: controller.signal
150
147
  };
151
148
  if (body) {
152
- if (typeof body === "string")
149
+ if (typeof body === "string") {
153
150
  headers.append("Content-Type", "application/json");
151
+ }
154
152
  options.method = "POST";
155
153
  options.headers = headers;
156
154
  options.body = body;
@@ -159,10 +157,19 @@ async function execute(config) {
159
157
  const response = await fetch(resource, options);
160
158
  clearTimeout(timer);
161
159
  if (response.ok) {
162
- const data = await response.json();
163
- return Promise.resolve(data);
160
+ const contentType = response.headers.get("content-type");
161
+ switch (contentType) {
162
+ case "application/json":
163
+ return Promise.resolve(await response.json());
164
+ case "application/csv":
165
+ case "application/tsv":
166
+ case "application/xml":
167
+ return Promise.resolve(await response.text());
168
+ default:
169
+ return Promise.resolve(response.body);
170
+ }
164
171
  } else {
165
- const message = await response.text();
172
+ const message = await response.json();
166
173
  return Promise.reject(`${response.status}: ${message}`);
167
174
  }
168
175
  }
@@ -195,7 +202,7 @@ var getBearerToken = (connectionOptions) => async ({ clientId, clientSecret, sco
195
202
 
196
203
  // src/methods/getResponseExportProgress.ts
197
204
  var getResponseExportProgress = (connectionOptions) => async ({ exportProgressId, surveyId, bearerToken }) => {
198
- const route = `/surveys/${surveyId}/export-responses/${exportProgressId}`;
205
+ const route = `/API/v3/surveys/${surveyId}/export-responses/${exportProgressId}`;
199
206
  try {
200
207
  const headers = getAuthHeaders(connectionOptions.apiToken, bearerToken);
201
208
  const config = {
@@ -215,7 +222,7 @@ var getResponseExportProgress = (connectionOptions) => async ({ exportProgressId
215
222
 
216
223
  // src/methods/getResponseExportFile.ts
217
224
  var getResponseExportFile = (connectionOptions) => async ({ surveyId, fileId, bearerToken }) => {
218
- const route = `/surveys/${surveyId}/export-responses/${fileId}/file`;
225
+ const route = `/API/v3/surveys/${surveyId}/export-responses/${fileId}/file`;
219
226
  try {
220
227
  const headers = getAuthHeaders(connectionOptions.apiToken, bearerToken);
221
228
  const config = {
@@ -225,8 +232,7 @@ var getResponseExportFile = (connectionOptions) => async ({ surveyId, fileId, be
225
232
  timeout: connectionOptions.timeout
226
233
  };
227
234
  const response = await execute(config);
228
- const result = safeParseFileResponse(response);
229
- return result;
235
+ return response;
230
236
  } catch (error) {
231
237
  const message = getErrorMessage(error);
232
238
  return failure(message);
@@ -242,12 +248,14 @@ var startResponseExport = (connectionOptions) => async ({
242
248
  bearerToken = void 0,
243
249
  ...rest
244
250
  }) => {
245
- const route = `/surveys/${surveyId}/export-responses`;
251
+ const route = `/API/v3/surveys/${surveyId}/export-responses`;
246
252
  try {
247
253
  const headers = getAuthHeaders(connectionOptions.apiToken, bearerToken);
248
254
  const body = JSON.stringify({
249
- startDate: startDate.toISOString(),
250
- endDate: endDate.toDateString(),
255
+ startDate: "2024-03-01T06:00:00Z",
256
+ //startDate.toISOString(),
257
+ endDate: "2024-03-05T06:00:00Z",
258
+ //endDate.toISOString(),
251
259
  format,
252
260
  ...rest
253
261
  });
@@ -291,6 +299,7 @@ var testConnection = (connectionOptions) => async (bearerToken) => {
291
299
  var createConnection = (options) => ({
292
300
  exportResponses: exportResponses(options),
293
301
  getBearerToken: getBearerToken(options),
302
+ getResponseExportFile: getResponseExportFile(options),
294
303
  getResponseExportProgress: getResponseExportProgress(options),
295
304
  startResponseExport: startResponseExport(options),
296
305
  testConnection: testConnection(options)
package/dist/index.mjs CHANGED
@@ -93,7 +93,7 @@ function safeParseBearerToken(response) {
93
93
  return response?.access_token && typeof response.access_token === "string" ? success(response.access_token) : failure("Incorrect token format");
94
94
  }
95
95
  function safeParseTestResponse(response) {
96
- return response?.result?.userId ? success(void 0) : failure("Incorrect test response format");
96
+ return response?.result?.userId ? success("Connection successful") : failure("Incorrect test response format");
97
97
  }
98
98
  function safeParseStartFileExportResponse(response) {
99
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`);
@@ -101,9 +101,6 @@ function safeParseStartFileExportResponse(response) {
101
101
  function safeParseFileProgressResponse(response) {
102
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
103
  }
104
- function safeParseFileResponse(response) {
105
- return Buffer.isBuffer(response) ? success(response) : failure("Incorrect file response format");
106
- }
107
104
 
108
105
  // src/qualtrics/index.ts
109
106
  async function execute(config) {
@@ -117,8 +114,9 @@ async function execute(config) {
117
114
  signal: controller.signal
118
115
  };
119
116
  if (body) {
120
- if (typeof body === "string")
117
+ if (typeof body === "string") {
121
118
  headers.append("Content-Type", "application/json");
119
+ }
122
120
  options.method = "POST";
123
121
  options.headers = headers;
124
122
  options.body = body;
@@ -127,10 +125,19 @@ async function execute(config) {
127
125
  const response = await fetch(resource, options);
128
126
  clearTimeout(timer);
129
127
  if (response.ok) {
130
- const data = await response.json();
131
- return Promise.resolve(data);
128
+ const contentType = response.headers.get("content-type");
129
+ switch (contentType) {
130
+ case "application/json":
131
+ return Promise.resolve(await response.json());
132
+ case "application/csv":
133
+ case "application/tsv":
134
+ case "application/xml":
135
+ return Promise.resolve(await response.text());
136
+ default:
137
+ return Promise.resolve(response.body);
138
+ }
132
139
  } else {
133
- const message = await response.text();
140
+ const message = await response.json();
134
141
  return Promise.reject(`${response.status}: ${message}`);
135
142
  }
136
143
  }
@@ -163,7 +170,7 @@ var getBearerToken = (connectionOptions) => async ({ clientId, clientSecret, sco
163
170
 
164
171
  // src/methods/getResponseExportProgress.ts
165
172
  var getResponseExportProgress = (connectionOptions) => async ({ exportProgressId, surveyId, bearerToken }) => {
166
- const route = `/surveys/${surveyId}/export-responses/${exportProgressId}`;
173
+ const route = `/API/v3/surveys/${surveyId}/export-responses/${exportProgressId}`;
167
174
  try {
168
175
  const headers = getAuthHeaders(connectionOptions.apiToken, bearerToken);
169
176
  const config = {
@@ -183,7 +190,7 @@ var getResponseExportProgress = (connectionOptions) => async ({ exportProgressId
183
190
 
184
191
  // src/methods/getResponseExportFile.ts
185
192
  var getResponseExportFile = (connectionOptions) => async ({ surveyId, fileId, bearerToken }) => {
186
- const route = `/surveys/${surveyId}/export-responses/${fileId}/file`;
193
+ const route = `/API/v3/surveys/${surveyId}/export-responses/${fileId}/file`;
187
194
  try {
188
195
  const headers = getAuthHeaders(connectionOptions.apiToken, bearerToken);
189
196
  const config = {
@@ -193,8 +200,7 @@ var getResponseExportFile = (connectionOptions) => async ({ surveyId, fileId, be
193
200
  timeout: connectionOptions.timeout
194
201
  };
195
202
  const response = await execute(config);
196
- const result = safeParseFileResponse(response);
197
- return result;
203
+ return response;
198
204
  } catch (error) {
199
205
  const message = getErrorMessage(error);
200
206
  return failure(message);
@@ -210,12 +216,14 @@ var startResponseExport = (connectionOptions) => async ({
210
216
  bearerToken = void 0,
211
217
  ...rest
212
218
  }) => {
213
- const route = `/surveys/${surveyId}/export-responses`;
219
+ const route = `/API/v3/surveys/${surveyId}/export-responses`;
214
220
  try {
215
221
  const headers = getAuthHeaders(connectionOptions.apiToken, bearerToken);
216
222
  const body = JSON.stringify({
217
- startDate: startDate.toISOString(),
218
- endDate: endDate.toDateString(),
223
+ startDate: "2024-03-01T06:00:00Z",
224
+ //startDate.toISOString(),
225
+ endDate: "2024-03-05T06:00:00Z",
226
+ //endDate.toISOString(),
219
227
  format,
220
228
  ...rest
221
229
  });
@@ -259,6 +267,7 @@ var testConnection = (connectionOptions) => async (bearerToken) => {
259
267
  var createConnection = (options) => ({
260
268
  exportResponses: exportResponses(options),
261
269
  getBearerToken: getBearerToken(options),
270
+ getResponseExportFile: getResponseExportFile(options),
262
271
  getResponseExportProgress: getResponseExportProgress(options),
263
272
  startResponseExport: startResponseExport(options),
264
273
  testConnection: testConnection(options)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@b-jones-rfd/qualtrics-api-tasks",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Perform common tasks using the Qualtrics API",
5
5
  "private": false,
6
6
  "main": "./dist/index.js",
@@ -5,7 +5,6 @@ import {
5
5
  safeParseTestResponse,
6
6
  safeParseStartFileExportResponse,
7
7
  safeParseFileProgressResponse,
8
- safeParseFileResponse,
9
8
  } from '../src/utils/parsers'
10
9
 
11
10
  describe('safeParseBearerToken', () => {
@@ -126,7 +125,7 @@ describe('safeParseTestResponse', () => {
126
125
 
127
126
  it('should pass with correct data', () => {
128
127
  const res = fixture
129
- const expected = success(undefined)
128
+ const expected = success('Connection successful')
130
129
  const parsed = safeParseTestResponse(res)
131
130
  expect(parsed).toStrictEqual(expected)
132
131
  })
@@ -140,21 +139,3 @@ describe('safeParseTestResponse', () => {
140
139
  expect(parsed).toStrictEqual(expected)
141
140
  })
142
141
  })
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
- })