@openfn/language-kobotoolbox 3.0.5 → 4.0.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/ast.json CHANGED
@@ -43,16 +43,21 @@
43
43
  "options"
44
44
  ],
45
45
  "docs": {
46
- "description": "Get submissions for a specific form. Calls `/api/v2/assets/<formId>/data/`.",
46
+ "description": "Get submissions for a specific form. Calls `/api/v2/assets/<formId>/data/`",
47
47
  "tags": [
48
48
  {
49
49
  "title": "example",
50
- "description": "getSubmissions('aXecHjmbATuF6iGFmvBLBX');",
50
+ "description": "getSubmissions('aXecHjmbATuF6iGFmvBLBX');.",
51
+ "caption": "Get submissions for a specific form"
52
+ },
53
+ {
54
+ "title": "example",
55
+ "description": "getSubmissions('aXecHjmbATuF6iGFmvBLBX', { limit: Infinity });",
51
56
  "caption": "Get all submissions for a specific form"
52
57
  },
53
58
  {
54
59
  "title": "example",
55
- "description": "getSubmissions('aXecHjmbATuF6iGFmvBLBX', { query: { _submission_time:{ $gte: \"2022-06-12T21:54:20\" } } });",
60
+ "description": "getSubmissions('aXecHjmbATuF6iGFmvBLBX', { query: { _submission_time:{ $gte: \"2025-03-12T21:54:20\" } } });",
56
61
  "caption": "Get form submissions with a query"
57
62
  },
58
63
  {
@@ -76,7 +81,7 @@
76
81
  },
77
82
  {
78
83
  "title": "param",
79
- "description": "Optional query params for the request",
84
+ "description": "Options to control the request",
80
85
  "type": {
81
86
  "type": "OptionalType",
82
87
  "expression": {
@@ -87,6 +92,44 @@
87
92
  "name": "options",
88
93
  "default": "{}"
89
94
  },
95
+ {
96
+ "title": "param",
97
+ "description": "Query options to filter the submissions. See query operators {@link http://docs.mongodb.org/manual/reference/operator/query/.}",
98
+ "type": {
99
+ "type": "OptionalType",
100
+ "expression": {
101
+ "type": "NameExpression",
102
+ "name": "object"
103
+ }
104
+ },
105
+ "name": "options.query"
106
+ },
107
+ {
108
+ "title": "param",
109
+ "description": "Maximum number of submissions to fetch. Pass Infinity to disable the limit and download all submissions",
110
+ "type": {
111
+ "type": "OptionalType",
112
+ "expression": {
113
+ "type": "NameExpression",
114
+ "name": "number"
115
+ }
116
+ },
117
+ "name": "options.limit",
118
+ "default": "30000"
119
+ },
120
+ {
121
+ "title": "param",
122
+ "description": "Limits the size of each page of submissions. Maximum value is 30000.",
123
+ "type": {
124
+ "type": "OptionalType",
125
+ "expression": {
126
+ "type": "NameExpression",
127
+ "name": "number"
128
+ }
129
+ },
130
+ "name": "options.pageSize",
131
+ "default": "10000"
132
+ },
90
133
  {
91
134
  "title": "state",
92
135
  "description": "data - an array of submission objects"
@@ -101,7 +144,7 @@
101
144
  }
102
145
  ]
103
146
  },
104
- "valid": true
147
+ "valid": false
105
148
  },
106
149
  {
107
150
  "name": "getDeploymentInfo",
package/dist/index.cjs CHANGED
@@ -58,7 +58,6 @@ __export(Adaptor_exports, {
58
58
  getForms: () => getForms,
59
59
  getSubmissions: () => getSubmissions,
60
60
  group: () => import_language_common3.group,
61
- http: () => import_language_common3.http,
62
61
  lastReferenceValue: () => import_language_common3.lastReferenceValue,
63
62
  merge: () => import_language_common3.merge,
64
63
  sourceValue: () => import_language_common3.sourceValue
@@ -66,36 +65,29 @@ __export(Adaptor_exports, {
66
65
  var import_language_common2 = require("@openfn/language-common");
67
66
  var import_util2 = require("@openfn/language-common/util");
68
67
 
69
- // src/Utils.js
68
+ // src/util.js
70
69
  var import_language_common = require("@openfn/language-common");
71
70
  var import_util = require("@openfn/language-common/util");
72
- var prepareNextState = (state, response) => {
71
+ var DEFAULT_LIMIT = 3e4;
72
+ var DEFAULT_PAGE_SIZE = 1e4;
73
+ function prepareNextState(state, response) {
73
74
  const { body, ...responseWithoutBody } = response;
74
75
  return {
75
- ...(0, import_language_common.composeNextState)(state, response.body),
76
+ ...(0, import_language_common.composeNextState)(state, body),
76
77
  response: responseWithoutBody
77
78
  };
78
- };
79
- async function request(state, method, path, opts) {
80
- const { baseURL, apiVersion, username, password } = state.configuration;
81
- let baseUrl;
82
- if (!state.configuration.baseUrl && baseURL) {
83
- baseUrl = baseURL;
84
- console.warn(
85
- "No baseUrl found in state.configuration. baseURL will be used instead, but this will be deprecated in the future."
86
- );
87
- } else {
88
- baseUrl = state.configuration.baseUrl;
89
- }
79
+ }
80
+ async function request(state, method, path, opts = {}) {
81
+ const { baseUrl, apiVersion, username, password } = state.configuration;
90
82
  const {
91
83
  data = {},
92
84
  query = {},
93
85
  headers = {},
94
86
  parseAs = "json",
95
- paginate = false
87
+ maxRedirections
96
88
  } = opts;
89
+ const requestPath = `/api/${apiVersion}/${path}/`;
97
90
  const authHeaders = (0, import_util.makeBasicAuthHeader)(username, password);
98
- let start, limit;
99
91
  const options = {
100
92
  body: data,
101
93
  headers: {
@@ -107,34 +99,57 @@ async function request(state, method, path, opts) {
107
99
  format: "json",
108
100
  ...query
109
101
  },
102
+ maxRedirections,
110
103
  parseAs,
111
- baseUrl: `${baseUrl}/api/${apiVersion}`
104
+ baseUrl
112
105
  };
113
- if (paginate) {
114
- const results = [];
115
- do {
116
- const response = await (0, import_util.request)(method, path, options).then(
117
- import_util.logResponse
106
+ return (0, import_util.request)(method, requestPath, options).then(import_util.logResponse);
107
+ }
108
+ async function requestWithPagination(state, path, options = {}) {
109
+ var _a, _b, _c, _d;
110
+ const results = [];
111
+ let { pageSize = DEFAULT_PAGE_SIZE, start, limit, ...otherOptions } = options;
112
+ const maxResults = limit ?? DEFAULT_LIMIT;
113
+ let isFirstRequest = true;
114
+ let requestOptions = { query: { start, limit: pageSize }, ...otherOptions };
115
+ let shouldFetchMoreContent = false;
116
+ const didUserPassLimit = Boolean(limit);
117
+ do {
118
+ requestOptions.query ?? (requestOptions.query = {});
119
+ if (start) {
120
+ requestOptions.query.start = start;
121
+ }
122
+ if (didUserPassLimit || !isFirstRequest) {
123
+ requestOptions.query.limit = Math.min(
124
+ pageSize || maxResults,
125
+ maxResults - results.length
118
126
  );
127
+ } else if (!isNaN(pageSize)) {
128
+ requestOptions.query.limit = pageSize;
129
+ }
130
+ const response = await request(state, "GET", path, requestOptions);
131
+ if ((_a = response.body) == null ? void 0 : _a.results) {
119
132
  results.push(...response.body.results);
120
- if (response.body.next) {
121
- const nextUrl = new URL(response.body.next);
122
- const startDigit = nextUrl.searchParams.get("start") !== null ? nextUrl.searchParams.get("start") : 0;
123
- start = Number(startDigit);
124
- limit = nextUrl.searchParams.get("limit");
125
- options.query = {
126
- ...options.query,
127
- start,
128
- limit
129
- };
130
- } else {
131
- break;
133
+ if ((_b = response == null ? void 0 : response.body) == null ? void 0 : _b.next) {
134
+ const nextUrl = new URL((_c = response == null ? void 0 : response.body) == null ? void 0 : _c.next);
135
+ start = nextUrl.searchParams.get("start");
132
136
  }
133
- } while (true);
134
- return { results };
135
- } else {
136
- return (0, import_util.request)(method, path, options).then(import_util.logResponse);
137
- }
137
+ } else {
138
+ results.push(response.body);
139
+ }
140
+ if (isFirstRequest && !pageSize) {
141
+ pageSize = results.length;
142
+ }
143
+ isFirstRequest = false;
144
+ const hasMoreContent = (_d = response.body.next) == null ? void 0 : _d.includes("start=");
145
+ if (hasMoreContent && didUserPassLimit && results.length === maxResults) {
146
+ console.warn(
147
+ `Warning: The default maximum number of items has been reached (${maxResults}), but more items are available on the server. To download all available items, make another request with start=${maxResults + 1} or set max to Infinity`
148
+ );
149
+ }
150
+ shouldFetchMoreContent = results.length < maxResults && hasMoreContent;
151
+ } while (shouldFetchMoreContent);
152
+ return results;
138
153
  }
139
154
 
140
155
  // src/Adaptor.js
@@ -153,34 +168,43 @@ function execute(...operations) {
153
168
  }
154
169
  function getForms() {
155
170
  return async (state) => {
156
- const url = `/assets/?asset_type=survey`;
157
- const response = await request(state, "GET", url, {});
158
- console.log("\u2713", response.body.results.length, "forms fetched.");
171
+ var _a;
172
+ const response = await request(state, "GET", "assets", {
173
+ query: { asset_type: "survey" }
174
+ });
175
+ console.log("\u2713", (_a = response.body.results) == null ? void 0 : _a.length, "forms fetched.");
159
176
  return prepareNextState(state, response);
160
177
  };
161
178
  }
162
- function getSubmissions(formId, options = {}) {
179
+ function getSubmissions(formId, options) {
163
180
  return async (state) => {
164
- const [resolvedFormId, resolvedOptions] = (0, import_util2.expandReferences)(
181
+ const [resolvedFormId, resolvedOptions = {}] = (0, import_util2.expandReferences)(
165
182
  state,
166
183
  formId,
167
184
  options
168
185
  );
169
- const url = `/assets/${resolvedFormId}/data/`;
170
- const query = {};
171
- if (resolvedOptions.query) {
172
- if (typeof resolvedOptions.query == "string") {
173
- query.query = resolvedOptions.query;
186
+ const { query, limit, pageSize } = resolvedOptions;
187
+ const path = `/assets/${resolvedFormId}/data/`;
188
+ const qs = {};
189
+ if (query) {
190
+ if (typeof query === "string") {
191
+ qs.query = query;
174
192
  } else {
175
- query.query = JSON.stringify(resolvedOptions.query);
193
+ qs.query = JSON.stringify(query);
176
194
  }
177
195
  }
178
- const { results } = await request(state, "GET", url, {
179
- paginate: true,
180
- query
181
- });
182
- console.log("\u2713", results.length, "submissions fetched.");
183
- return (0, import_language_common2.composeNextState)(state, results);
196
+ const requestOptions = {
197
+ query: { ...qs },
198
+ limit,
199
+ pageSize
200
+ };
201
+ const result = await requestWithPagination(
202
+ state,
203
+ path,
204
+ requestOptions
205
+ );
206
+ console.log("\u2713", result == null ? void 0 : result.length, "submissions fetched.");
207
+ return (0, import_language_common2.composeNextState)(state, result);
184
208
  };
185
209
  }
186
210
  function getDeploymentInfo(formId) {
@@ -198,12 +222,25 @@ var http_exports = {};
198
222
  __export(http_exports, {
199
223
  get: () => get,
200
224
  post: () => post,
201
- put: () => put
225
+ put: () => put,
226
+ request: () => request2
202
227
  });
203
228
  var import_util3 = require("@openfn/language-common/util");
204
- function get(path, options = {}) {
229
+ function request2(method, path, options = {}) {
230
+ return async (state) => {
231
+ const [resolvedMethod, resolvedPath, resolvedOptions = {}] = (0, import_util3.expandReferences)(state, method, path, options);
232
+ const response = await request(
233
+ state,
234
+ resolvedMethod,
235
+ resolvedPath,
236
+ resolvedOptions
237
+ );
238
+ return prepareNextState(state, response);
239
+ };
240
+ }
241
+ function get(path, options) {
205
242
  return async (state) => {
206
- const [resolvedPath, resolvedOptions] = (0, import_util3.expandReferences)(
243
+ const [resolvedPath, resolvedOptions = {}] = (0, import_util3.expandReferences)(
207
244
  state,
208
245
  path,
209
246
  options
@@ -217,9 +254,9 @@ function get(path, options = {}) {
217
254
  return prepareNextState(state, response);
218
255
  };
219
256
  }
220
- function post(path, data, options = {}) {
257
+ function post(path, data, options) {
221
258
  return async (state) => {
222
- const [resolvedPath, resolvedData, resolvedOptions] = (0, import_util3.expandReferences)(
259
+ const [resolvedPath, resolvedData, resolvedOptions = {}] = (0, import_util3.expandReferences)(
223
260
  state,
224
261
  path,
225
262
  data,
@@ -238,9 +275,9 @@ function post(path, data, options = {}) {
238
275
  return prepareNextState(state, response);
239
276
  };
240
277
  }
241
- function put(path, data, options = {}) {
278
+ function put(path, data, options) {
242
279
  return async (state) => {
243
- const [resolvedPath, resolvedData, resolvedOptions] = (0, import_util3.expandReferences)(
280
+ const [resolvedPath, resolvedData, resolvedOptions = {}] = (0, import_util3.expandReferences)(
244
281
  state,
245
282
  path,
246
283
  data,
package/dist/index.js CHANGED
@@ -21,7 +21,6 @@ __export(Adaptor_exports, {
21
21
  getForms: () => getForms,
22
22
  getSubmissions: () => getSubmissions,
23
23
  group: () => group,
24
- http: () => http,
25
24
  lastReferenceValue: () => lastReferenceValue,
26
25
  merge: () => merge,
27
26
  sourceValue: () => sourceValue
@@ -32,40 +31,33 @@ import {
32
31
  } from "@openfn/language-common";
33
32
  import { expandReferences } from "@openfn/language-common/util";
34
33
 
35
- // src/Utils.js
34
+ // src/util.js
36
35
  import { composeNextState } from "@openfn/language-common";
37
36
  import {
38
37
  request as commonRequest,
39
38
  makeBasicAuthHeader,
40
39
  logResponse
41
40
  } from "@openfn/language-common/util";
42
- var prepareNextState = (state, response) => {
41
+ var DEFAULT_LIMIT = 3e4;
42
+ var DEFAULT_PAGE_SIZE = 1e4;
43
+ function prepareNextState(state, response) {
43
44
  const { body, ...responseWithoutBody } = response;
44
45
  return {
45
- ...composeNextState(state, response.body),
46
+ ...composeNextState(state, body),
46
47
  response: responseWithoutBody
47
48
  };
48
- };
49
- async function request(state, method, path, opts) {
50
- const { baseURL, apiVersion, username, password } = state.configuration;
51
- let baseUrl;
52
- if (!state.configuration.baseUrl && baseURL) {
53
- baseUrl = baseURL;
54
- console.warn(
55
- "No baseUrl found in state.configuration. baseURL will be used instead, but this will be deprecated in the future."
56
- );
57
- } else {
58
- baseUrl = state.configuration.baseUrl;
59
- }
49
+ }
50
+ async function request(state, method, path, opts = {}) {
51
+ const { baseUrl, apiVersion, username, password } = state.configuration;
60
52
  const {
61
53
  data = {},
62
54
  query = {},
63
55
  headers = {},
64
56
  parseAs = "json",
65
- paginate = false
57
+ maxRedirections
66
58
  } = opts;
59
+ const requestPath = `/api/${apiVersion}/${path}/`;
67
60
  const authHeaders = makeBasicAuthHeader(username, password);
68
- let start, limit;
69
61
  const options = {
70
62
  body: data,
71
63
  headers: {
@@ -77,34 +69,57 @@ async function request(state, method, path, opts) {
77
69
  format: "json",
78
70
  ...query
79
71
  },
72
+ maxRedirections,
80
73
  parseAs,
81
- baseUrl: `${baseUrl}/api/${apiVersion}`
74
+ baseUrl
82
75
  };
83
- if (paginate) {
84
- const results = [];
85
- do {
86
- const response = await commonRequest(method, path, options).then(
87
- logResponse
76
+ return commonRequest(method, requestPath, options).then(logResponse);
77
+ }
78
+ async function requestWithPagination(state, path, options = {}) {
79
+ var _a, _b, _c, _d;
80
+ const results = [];
81
+ let { pageSize = DEFAULT_PAGE_SIZE, start, limit, ...otherOptions } = options;
82
+ const maxResults = limit ?? DEFAULT_LIMIT;
83
+ let isFirstRequest = true;
84
+ let requestOptions = { query: { start, limit: pageSize }, ...otherOptions };
85
+ let shouldFetchMoreContent = false;
86
+ const didUserPassLimit = Boolean(limit);
87
+ do {
88
+ requestOptions.query ?? (requestOptions.query = {});
89
+ if (start) {
90
+ requestOptions.query.start = start;
91
+ }
92
+ if (didUserPassLimit || !isFirstRequest) {
93
+ requestOptions.query.limit = Math.min(
94
+ pageSize || maxResults,
95
+ maxResults - results.length
88
96
  );
97
+ } else if (!isNaN(pageSize)) {
98
+ requestOptions.query.limit = pageSize;
99
+ }
100
+ const response = await request(state, "GET", path, requestOptions);
101
+ if ((_a = response.body) == null ? void 0 : _a.results) {
89
102
  results.push(...response.body.results);
90
- if (response.body.next) {
91
- const nextUrl = new URL(response.body.next);
92
- const startDigit = nextUrl.searchParams.get("start") !== null ? nextUrl.searchParams.get("start") : 0;
93
- start = Number(startDigit);
94
- limit = nextUrl.searchParams.get("limit");
95
- options.query = {
96
- ...options.query,
97
- start,
98
- limit
99
- };
100
- } else {
101
- break;
103
+ if ((_b = response == null ? void 0 : response.body) == null ? void 0 : _b.next) {
104
+ const nextUrl = new URL((_c = response == null ? void 0 : response.body) == null ? void 0 : _c.next);
105
+ start = nextUrl.searchParams.get("start");
102
106
  }
103
- } while (true);
104
- return { results };
105
- } else {
106
- return commonRequest(method, path, options).then(logResponse);
107
- }
107
+ } else {
108
+ results.push(response.body);
109
+ }
110
+ if (isFirstRequest && !pageSize) {
111
+ pageSize = results.length;
112
+ }
113
+ isFirstRequest = false;
114
+ const hasMoreContent = (_d = response.body.next) == null ? void 0 : _d.includes("start=");
115
+ if (hasMoreContent && didUserPassLimit && results.length === maxResults) {
116
+ console.warn(
117
+ `Warning: The default maximum number of items has been reached (${maxResults}), but more items are available on the server. To download all available items, make another request with start=${maxResults + 1} or set max to Infinity`
118
+ );
119
+ }
120
+ shouldFetchMoreContent = results.length < maxResults && hasMoreContent;
121
+ } while (shouldFetchMoreContent);
122
+ return results;
108
123
  }
109
124
 
110
125
  // src/Adaptor.js
@@ -118,7 +133,6 @@ import {
118
133
  fields,
119
134
  fn,
120
135
  fnIf,
121
- http,
122
136
  group,
123
137
  lastReferenceValue,
124
138
  merge,
@@ -138,34 +152,43 @@ function execute(...operations) {
138
152
  }
139
153
  function getForms() {
140
154
  return async (state) => {
141
- const url = `/assets/?asset_type=survey`;
142
- const response = await request(state, "GET", url, {});
143
- console.log("\u2713", response.body.results.length, "forms fetched.");
155
+ var _a;
156
+ const response = await request(state, "GET", "assets", {
157
+ query: { asset_type: "survey" }
158
+ });
159
+ console.log("\u2713", (_a = response.body.results) == null ? void 0 : _a.length, "forms fetched.");
144
160
  return prepareNextState(state, response);
145
161
  };
146
162
  }
147
- function getSubmissions(formId, options = {}) {
163
+ function getSubmissions(formId, options) {
148
164
  return async (state) => {
149
- const [resolvedFormId, resolvedOptions] = expandReferences(
165
+ const [resolvedFormId, resolvedOptions = {}] = expandReferences(
150
166
  state,
151
167
  formId,
152
168
  options
153
169
  );
154
- const url = `/assets/${resolvedFormId}/data/`;
155
- const query = {};
156
- if (resolvedOptions.query) {
157
- if (typeof resolvedOptions.query == "string") {
158
- query.query = resolvedOptions.query;
170
+ const { query, limit, pageSize } = resolvedOptions;
171
+ const path = `/assets/${resolvedFormId}/data/`;
172
+ const qs = {};
173
+ if (query) {
174
+ if (typeof query === "string") {
175
+ qs.query = query;
159
176
  } else {
160
- query.query = JSON.stringify(resolvedOptions.query);
177
+ qs.query = JSON.stringify(query);
161
178
  }
162
179
  }
163
- const { results } = await request(state, "GET", url, {
164
- paginate: true,
165
- query
166
- });
167
- console.log("\u2713", results.length, "submissions fetched.");
168
- return composeNextState2(state, results);
180
+ const requestOptions = {
181
+ query: { ...qs },
182
+ limit,
183
+ pageSize
184
+ };
185
+ const result = await requestWithPagination(
186
+ state,
187
+ path,
188
+ requestOptions
189
+ );
190
+ console.log("\u2713", result == null ? void 0 : result.length, "submissions fetched.");
191
+ return composeNextState2(state, result);
169
192
  };
170
193
  }
171
194
  function getDeploymentInfo(formId) {
@@ -183,12 +206,25 @@ var http_exports = {};
183
206
  __export(http_exports, {
184
207
  get: () => get,
185
208
  post: () => post,
186
- put: () => put
209
+ put: () => put,
210
+ request: () => request2
187
211
  });
188
212
  import { expandReferences as expandReferences2 } from "@openfn/language-common/util";
189
- function get(path, options = {}) {
213
+ function request2(method, path, options = {}) {
214
+ return async (state) => {
215
+ const [resolvedMethod, resolvedPath, resolvedOptions = {}] = expandReferences2(state, method, path, options);
216
+ const response = await request(
217
+ state,
218
+ resolvedMethod,
219
+ resolvedPath,
220
+ resolvedOptions
221
+ );
222
+ return prepareNextState(state, response);
223
+ };
224
+ }
225
+ function get(path, options) {
190
226
  return async (state) => {
191
- const [resolvedPath, resolvedOptions] = expandReferences2(
227
+ const [resolvedPath, resolvedOptions = {}] = expandReferences2(
192
228
  state,
193
229
  path,
194
230
  options
@@ -202,9 +238,9 @@ function get(path, options = {}) {
202
238
  return prepareNextState(state, response);
203
239
  };
204
240
  }
205
- function post(path, data, options = {}) {
241
+ function post(path, data, options) {
206
242
  return async (state) => {
207
- const [resolvedPath, resolvedData, resolvedOptions] = expandReferences2(
243
+ const [resolvedPath, resolvedData, resolvedOptions = {}] = expandReferences2(
208
244
  state,
209
245
  path,
210
246
  data,
@@ -223,9 +259,9 @@ function post(path, data, options = {}) {
223
259
  return prepareNextState(state, response);
224
260
  };
225
261
  }
226
- function put(path, data, options = {}) {
262
+ function put(path, data, options) {
227
263
  return async (state) => {
228
- const [resolvedPath, resolvedData, resolvedOptions] = expandReferences2(
264
+ const [resolvedPath, resolvedData, resolvedOptions = {}] = expandReferences2(
229
265
  state,
230
266
  path,
231
267
  data,
package/package.json CHANGED
@@ -1,7 +1,8 @@
1
1
  {
2
2
  "name": "@openfn/language-kobotoolbox",
3
- "version": "3.0.5",
4
- "description": "A Kobo Toolbox Language Pack for OpenFn",
3
+ "label": "KoboToolbox",
4
+ "version": "4.0.0",
5
+ "description": "A KoboToolbox Language Pack for OpenFn",
5
6
  "homepage": "https://docs.openfn.org",
6
7
  "repository": {
7
8
  "type": "git",
@@ -21,9 +22,8 @@
21
22
  },
22
23
  "devDependencies": {
23
24
  "assertion-error": "^1.0.1",
24
- "chai": "^3.4.0",
25
+ "chai": "^5.2.0",
25
26
  "deep-eql": "^0.1.3",
26
- "esno": "^0.16.3",
27
27
  "rimraf": "^3.0.2"
28
28
  },
29
29
  "type": "module",
@@ -38,8 +38,9 @@
38
38
  },
39
39
  "scripts": {
40
40
  "build": "pnpm clean && build-adaptor kobotoolbox",
41
- "test": "mocha --experimental-specifier-resolution=node --no-warnings",
42
- "test:watch": "mocha -w --experimental-specifier-resolution=node --no-warnings",
41
+ "test": "mocha --experimental-specifier-resolution=node --no-warnings --exclude test/integration.js --recursive",
42
+ "test:watch": "mocha -w --experimental-specifier-resolution=node --no-warnings --exclude test/integration.js --recursive",
43
+ "test:integration": "mocha --experimental-specifier-resolution=node --no-warnings test/integration.js",
43
44
  "clean": "rimraf dist types docs",
44
45
  "pack": "pnpm pack --pack-destination ../../dist",
45
46
  "lint": "eslint src"
@@ -1,10 +1,3 @@
1
- /**
2
- * Options object
3
- * @typedef {Object} RequestOptions
4
- * @property {object} query - An object of query parameters to be encoded into the URL
5
- * @property {object} headers - An object of all request headers
6
- * @property {string} [parseAs='json'] - The response format to parse (e.g., 'json', 'text', or 'stream')
7
- */
8
1
  /**
9
2
  * Execute a sequence of operations.
10
3
  * Wraps `language-common/execute`, and prepends initial state for http.
@@ -29,19 +22,28 @@ export function execute(...operations: Operations): Operation;
29
22
  */
30
23
  export function getForms(): Operation;
31
24
  /**
32
- * Get submissions for a specific form. Calls `/api/v2/assets/<formId>/data/`.
25
+ * Get submissions for a specific form. Calls `/api/v2/assets/<formId>/data/`
26
+ * @example <caption>Get submissions for a specific form</caption>
27
+ * getSubmissions('aXecHjmbATuF6iGFmvBLBX');.
33
28
  * @example <caption>Get all submissions for a specific form</caption>
34
- * getSubmissions('aXecHjmbATuF6iGFmvBLBX');
29
+ * getSubmissions('aXecHjmbATuF6iGFmvBLBX', { limit: Infinity });
35
30
  * @example <caption>Get form submissions with a query</caption>
36
- * getSubmissions('aXecHjmbATuF6iGFmvBLBX', { query: { _submission_time:{ $gte: "2022-06-12T21:54:20" } } });
31
+ * getSubmissions('aXecHjmbATuF6iGFmvBLBX', { query: { _submission_time:{ $gte: "2025-03-12T21:54:20" } } });
37
32
  * @function
38
33
  * @public
39
34
  * @param {string} formId - Form Id to get the specific submissions
40
- * @param {object} [options={}] - Optional query params for the request
35
+ * @param {object} [options={}] - Options to control the request
36
+ * @param {object} [options.query] - Query options to filter the submissions. See query operators {@link http://docs.mongodb.org/manual/reference/operator/query/.}
37
+ * @param {number} [options.limit=30000] - Maximum number of submissions to fetch. Pass Infinity to disable the limit and download all submissions
38
+ * @param {number} [options.pageSize=10000] - Limits the size of each page of submissions. Maximum value is 30000.
41
39
  * @state data - an array of submission objects
42
40
  * @returns {Operation}
43
41
  */
44
- export function getSubmissions(formId: string, options?: object): Operation;
42
+ export function getSubmissions(formId: string, options?: {
43
+ query?: object;
44
+ limit?: number;
45
+ pageSize?: number;
46
+ }): Operation;
45
47
  /**
46
48
  * Get deployment information for a specific form. Calls `/api/v2/assets/<id>/deployment/`.
47
49
  * @example
@@ -53,21 +55,4 @@ export function getSubmissions(formId: string, options?: object): Operation;
53
55
  * @returns {Operation}
54
56
  */
55
57
  export function getDeploymentInfo(formId: string): Operation;
56
- /**
57
- * Options object
58
- */
59
- export type RequestOptions = {
60
- /**
61
- * - An object of query parameters to be encoded into the URL
62
- */
63
- query: object;
64
- /**
65
- * - An object of all request headers
66
- */
67
- headers: object;
68
- /**
69
- * - The response format to parse (e.g., 'json', 'text', or 'stream')
70
- */
71
- parseAs?: string;
72
- };
73
- export { alterState, cursor, dataPath, dataValue, each, field, fields, fn, fnIf, http, group, lastReferenceValue, merge, sourceValue } from "@openfn/language-common";
58
+ export { alterState, cursor, dataPath, dataValue, each, field, fields, fn, fnIf, group, lastReferenceValue, merge, sourceValue } from "@openfn/language-common";
package/types/http.d.ts CHANGED
@@ -1,31 +1,52 @@
1
1
  /**
2
2
  * State object
3
- * @typedef {Object} KoboToolboxHttpState
3
+ * @typedef {Object} HttpState
4
+ * @private
4
5
  * @property data - The response body (as JSON)
5
- * @property response - The HTTP response from the KoboToolbox server (excluding the body). Responses will be returned in JSON format
6
- * @property references - An array of all previous data objects used in the Job
6
+ * @property response - The HTTP response from the KoboToolbox server (excluding the body)
7
+ * @property references - An array containing all previous data objects
7
8
  */
8
9
  /**
9
10
  * Options object
10
- * @typedef {Object} RequestOptions
11
+ * @typedef {Object} HTTPRequestOptions
11
12
  * @property {object} query - An object of query parameters to be encoded into the URL
12
13
  * @property {object} headers - An object of all request headers
14
+ * @property {object} body - The request body (as JSON)
15
+ * @property {number} maxRedirections - The maximum number of redirects to follow
13
16
  * @property {string} [parseAs='json'] - The response format to parse (e.g., 'json', 'text', or 'stream')
14
17
  */
18
+ /**
19
+ * Make a HTTP request to any KoboToolbox endpoint
20
+ * @example <caption>Bulk updating of submissions</caption>
21
+ * http.request("PATCH", `assets/${$.form_uid}/data/bulk/`, {
22
+ * body: {
23
+ * submission_ids: [$.data.submission_id],
24
+ * data: {
25
+ * Transaction_status: "success",
26
+ * },
27
+ * },
28
+ * });
29
+ * @function
30
+ * @public
31
+ * @param {string} method - HTTP method to use
32
+ * @param {string} path - Path to resource
33
+ * @param {HTTPRequestOptions} [options={}] - An object containing query, headers, and body for the request
34
+ * @state {HttpState}
35
+ * @returns {Operation}
36
+ */
37
+ export function request(method: string, path: string, options?: HTTPRequestOptions): Operation;
15
38
  /**
16
39
  * Make a GET request to any KoboToolbox endpoint.
17
40
  * @public
18
41
  * @function
19
42
  * @example <caption>GET assets resource</caption>
20
- * http.get(
21
- * "/assets/",
22
- * )
43
+ * http.get('assets')
23
44
  * @param {string} path - path to resource
24
- * @param {RequestOptions} [options={}] - An object containing query params and headers for the request
25
- * @state {KoboToolboxHttpState}
45
+ * @param {HTTPRequestOptions} [options={}] - An object containing query params and headers for the request
46
+ * @state {HttpState}
26
47
  * @returns {operation}
27
48
  */
28
- export function get(path: string, options?: RequestOptions): operation;
49
+ export function get(path: string, options?: HTTPRequestOptions): operation;
29
50
  /**
30
51
  * Make a POST request to a KoboToolbox endpoint
31
52
  * @public
@@ -40,11 +61,11 @@ export function get(path: string, options?: RequestOptions): operation;
40
61
  * );
41
62
  * @param {string} path - path to resource
42
63
  * @param {any} data - the body data in JSON format
43
- * @param {RequestOptions} [options={}] - An object containing query params and headers for the request
44
- * @state {KoboToolboxHttpState}
64
+ * @param {HTTPRequestOptions} [options={}] - An object containing query params and headers for the request
65
+ * @state {HttpState}
45
66
  * @returns {operation}
46
67
  */
47
- export function post(path: string, data: any, options?: RequestOptions): operation;
68
+ export function post(path: string, data: any, options?: HTTPRequestOptions): operation;
48
69
  /**
49
70
  * Make a PUT request to a KoboToolbox endpoint
50
71
  * @public
@@ -59,32 +80,19 @@ export function post(path: string, data: any, options?: RequestOptions): operati
59
80
  * );
60
81
  * @param {string} path - path to resource
61
82
  * @param {any} data - the body data in JSON format
62
- * @param {RequestOptions} [options={}] - An object containing query params and headers for the request
63
- * @state {KoboToolboxHttpState}
83
+ * @param {HTTPRequestOptions} [options={}] - An object containing query params and headers for the request
84
+ * @state {HttpState}
64
85
  * @returns {operation}
65
86
  */
66
- export function put(path: string, data: any, options?: RequestOptions): operation;
87
+ export function put(path: string, data: any, options?: HTTPRequestOptions): operation;
67
88
  /**
68
89
  * State object
69
90
  */
70
- export type KoboToolboxHttpState = {
71
- /**
72
- * - The response body (as JSON)
73
- */
74
- data: any;
75
- /**
76
- * - The HTTP response from the KoboToolbox server (excluding the body). Responses will be returned in JSON format
77
- */
78
- response: any;
79
- /**
80
- * - An array of all previous data objects used in the Job
81
- */
82
- references: any;
83
- };
91
+ export type HttpState = any;
84
92
  /**
85
93
  * Options object
86
94
  */
87
- export type RequestOptions = {
95
+ export type HTTPRequestOptions = {
88
96
  /**
89
97
  * - An object of query parameters to be encoded into the URL
90
98
  */
@@ -93,6 +101,14 @@ export type RequestOptions = {
93
101
  * - An object of all request headers
94
102
  */
95
103
  headers: object;
104
+ /**
105
+ * - The request body (as JSON)
106
+ */
107
+ body: object;
108
+ /**
109
+ * - The maximum number of redirects to follow
110
+ */
111
+ maxRedirections: number;
96
112
  /**
97
113
  * - The response format to parse (e.g., 'json', 'text', or 'stream')
98
114
  */
@@ -0,0 +1,5 @@
1
+ export function prepareNextState(state: any, response: any): any;
2
+ export function request(state: any, method: any, path: any, opts?: {}): Promise<any>;
3
+ export function requestWithPagination(state: any, path: any, options?: {}): Promise<any[]>;
4
+ export const DEFAULT_LIMIT: 30000;
5
+ export const DEFAULT_PAGE_SIZE: 10000;
package/types/Utils.d.ts DELETED
@@ -1,2 +0,0 @@
1
- export function request(state: any, method: any, path: any, opts: any): Promise<any>;
2
- export function prepareNextState(state: any, response: any): any;