@form-engine-ts/core 2.5.0 → 2.6.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/README.md +14 -4
- package/dist/index.cjs +228 -25
- package/dist/index.d.cts +135 -66
- package/dist/index.d.ts +135 -66
- package/dist/index.js +225 -25
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1043,17 +1043,38 @@ function aggregateResponses(schema, submissions) {
|
|
|
1043
1043
|
};
|
|
1044
1044
|
}
|
|
1045
1045
|
function responseValues(submission) {
|
|
1046
|
-
|
|
1046
|
+
if (typeof submission !== "object" || submission === null) return void 0;
|
|
1047
|
+
if ("values" in submission) return submission.values;
|
|
1048
|
+
return "answers" in submission ? submission.answers : void 0;
|
|
1047
1049
|
}
|
|
1048
1050
|
function responseIdentifier(submission) {
|
|
1049
|
-
|
|
1051
|
+
if (typeof submission !== "object" || submission === null) return "<unknown>";
|
|
1052
|
+
if ("id" in submission && typeof submission.id === "string" && submission.id.length > 0) return submission.id;
|
|
1053
|
+
if ("responseId" in submission && typeof submission.responseId === "string" && submission.responseId.length > 0) {
|
|
1054
|
+
return submission.responseId;
|
|
1055
|
+
}
|
|
1056
|
+
return "<unknown>";
|
|
1057
|
+
}
|
|
1058
|
+
function isAnswerRecord(value) {
|
|
1059
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1050
1060
|
}
|
|
1051
|
-
function
|
|
1061
|
+
function responseProblem(schema, submission) {
|
|
1062
|
+
if (typeof submission !== "object" || submission === null) {
|
|
1063
|
+
return { reason: "invalid_structure", error: "Submission structure is invalid." };
|
|
1064
|
+
}
|
|
1065
|
+
const identifier = responseIdentifier(submission);
|
|
1066
|
+
const values = responseValues(submission);
|
|
1067
|
+
if (typeof identifier !== "string" || identifier.length === 0 || typeof submission.formId !== "string" || typeof submission.submittedAt !== "string" || !isAnswerRecord(values)) {
|
|
1068
|
+
return { reason: "invalid_structure", error: `Submission ${String(identifier)} structure is invalid.` };
|
|
1069
|
+
}
|
|
1052
1070
|
if (submission.formId !== schema.id) {
|
|
1053
|
-
return `Submission ${
|
|
1071
|
+
return { reason: "form_id_mismatch", error: `Submission ${identifier} does not match form ${schema.id}.` };
|
|
1054
1072
|
}
|
|
1055
|
-
if ("formVersion" in submission && submission.formVersion !== schema.version) {
|
|
1056
|
-
return
|
|
1073
|
+
if ("formVersion" in submission && submission.formVersion !== void 0 && submission.formVersion !== schema.version) {
|
|
1074
|
+
return {
|
|
1075
|
+
reason: "version_mismatch",
|
|
1076
|
+
error: `Submission ${identifier} does not match ${schema.id}@${schema.version}.`
|
|
1077
|
+
};
|
|
1057
1078
|
}
|
|
1058
1079
|
return void 0;
|
|
1059
1080
|
}
|
|
@@ -1061,6 +1082,7 @@ var IncrementalResponseAccumulator = class _IncrementalResponseAccumulator {
|
|
|
1061
1082
|
#schema;
|
|
1062
1083
|
#mode;
|
|
1063
1084
|
#fields;
|
|
1085
|
+
#skipReasons = [];
|
|
1064
1086
|
#submissionCount = 0;
|
|
1065
1087
|
constructor(schema, options) {
|
|
1066
1088
|
assertValidFormSchema(schema);
|
|
@@ -1082,9 +1104,14 @@ var IncrementalResponseAccumulator = class _IncrementalResponseAccumulator {
|
|
|
1082
1104
|
);
|
|
1083
1105
|
}
|
|
1084
1106
|
add(submission) {
|
|
1085
|
-
const
|
|
1086
|
-
if (
|
|
1107
|
+
const problem = responseProblem(this.#schema, submission);
|
|
1108
|
+
if (problem !== void 0) {
|
|
1109
|
+
if (this.#mode === "strict") return { success: false, error: problem.error };
|
|
1110
|
+
this.#skipReasons.push({ responseId: responseIdentifier(submission), reason: problem.reason });
|
|
1111
|
+
return { success: true, skipped: true };
|
|
1112
|
+
}
|
|
1087
1113
|
const values = responseValues(submission);
|
|
1114
|
+
if (!isAnswerRecord(values)) throw new Error("Validated response answers are unavailable.");
|
|
1088
1115
|
const visibility = calculateFieldVisibility(this.#schema, values);
|
|
1089
1116
|
for (const field of this.#schema.fields) {
|
|
1090
1117
|
const accumulator = this.#fields.get(field.id);
|
|
@@ -1114,6 +1141,7 @@ var IncrementalResponseAccumulator = class _IncrementalResponseAccumulator {
|
|
|
1114
1141
|
const result = this.add(submission);
|
|
1115
1142
|
if (!result.success) throw new TypeError(result.error ?? "Submission could not be accumulated.");
|
|
1116
1143
|
}
|
|
1144
|
+
return this.getReport();
|
|
1117
1145
|
}
|
|
1118
1146
|
merge(other) {
|
|
1119
1147
|
if (!(other instanceof _IncrementalResponseAccumulator)) {
|
|
@@ -1123,6 +1151,7 @@ var IncrementalResponseAccumulator = class _IncrementalResponseAccumulator {
|
|
|
1123
1151
|
throw new TypeError("Response accumulators must use the same schema.");
|
|
1124
1152
|
}
|
|
1125
1153
|
this.#submissionCount += other.#submissionCount;
|
|
1154
|
+
this.#skipReasons.push(...other.#skipReasons);
|
|
1126
1155
|
for (const [fieldId, source] of other.#fields) {
|
|
1127
1156
|
const target = this.#fields.get(fieldId);
|
|
1128
1157
|
if (target === void 0) throw new Error(`Accumulator for ${fieldId} is unavailable.`);
|
|
@@ -1138,6 +1167,13 @@ var IncrementalResponseAccumulator = class _IncrementalResponseAccumulator {
|
|
|
1138
1167
|
}
|
|
1139
1168
|
return this;
|
|
1140
1169
|
}
|
|
1170
|
+
getReport() {
|
|
1171
|
+
return {
|
|
1172
|
+
processedCount: this.#submissionCount,
|
|
1173
|
+
skippedCount: this.#skipReasons.length,
|
|
1174
|
+
skipReasons: this.#skipReasons.map((reason) => ({ ...reason }))
|
|
1175
|
+
};
|
|
1176
|
+
}
|
|
1141
1177
|
finalize() {
|
|
1142
1178
|
return {
|
|
1143
1179
|
formId: this.#schema.id,
|
|
@@ -1209,6 +1245,7 @@ function asFormResponse(submission) {
|
|
|
1209
1245
|
responseId: submission.id,
|
|
1210
1246
|
formId: submission.formId,
|
|
1211
1247
|
sourceLocale: submission.locale,
|
|
1248
|
+
formVersion: submission.formVersion,
|
|
1212
1249
|
answers: submission.values,
|
|
1213
1250
|
submittedAt: submission.submittedAt,
|
|
1214
1251
|
...submission.metadata === void 0 ? {} : { metadata: submission.metadata },
|
|
@@ -1232,8 +1269,8 @@ async function* exportResponsesToCsvStream(schema, submissions, options = {}) {
|
|
|
1232
1269
|
const header = headers.map((value) => escapeCsvCell(value, neutralizeFormulas)).join(",");
|
|
1233
1270
|
yield `${options.withBom ?? true ? "\uFEFF" : ""}${header}`;
|
|
1234
1271
|
for await (const submission of submissions) {
|
|
1235
|
-
const
|
|
1236
|
-
if (
|
|
1272
|
+
const problem = responseProblem(schema, submission);
|
|
1273
|
+
if (problem !== void 0) throw new TypeError(problem.error);
|
|
1237
1274
|
const response = asFormResponse(submission);
|
|
1238
1275
|
const answers = response.answers;
|
|
1239
1276
|
const visible = selectVisibleAnswers(schema, answers);
|
|
@@ -1243,11 +1280,64 @@ async function* exportResponsesToCsvStream(schema, submissions, options = {}) {
|
|
|
1243
1280
|
response.sourceLocale ?? "",
|
|
1244
1281
|
...schema.fields.map((field) => serializeUnknown(visible[field.id]))
|
|
1245
1282
|
] : [];
|
|
1246
|
-
const
|
|
1283
|
+
const context = {
|
|
1284
|
+
...response,
|
|
1285
|
+
submission: response,
|
|
1286
|
+
formVersion: response.formVersion ?? schema.version,
|
|
1287
|
+
schema
|
|
1288
|
+
};
|
|
1289
|
+
const customCells = await Promise.all(customColumns.map((column) => column.getValue(context)));
|
|
1247
1290
|
yield `\r
|
|
1248
1291
|
${[...defaultCells, ...customCells].map((value) => escapeCsvCell(value, neutralizeFormulas)).join(",")}`;
|
|
1249
1292
|
}
|
|
1250
1293
|
}
|
|
1294
|
+
function isWebWritableStream(writable) {
|
|
1295
|
+
return "getWriter" in writable && typeof writable.getWriter === "function";
|
|
1296
|
+
}
|
|
1297
|
+
async function writeNodeChunk(writable, chunk, streamError) {
|
|
1298
|
+
if (writable.write(chunk)) return;
|
|
1299
|
+
let onDrain;
|
|
1300
|
+
const drain = new Promise((resolve) => {
|
|
1301
|
+
onDrain = resolve;
|
|
1302
|
+
writable.once("drain", resolve);
|
|
1303
|
+
});
|
|
1304
|
+
try {
|
|
1305
|
+
await Promise.race([drain, streamError]);
|
|
1306
|
+
} finally {
|
|
1307
|
+
if (onDrain !== void 0) writable.removeListener("drain", onDrain);
|
|
1308
|
+
}
|
|
1309
|
+
}
|
|
1310
|
+
async function pipeResponsesToCsvStream(schema, submissions, writable, options = {}) {
|
|
1311
|
+
const encoder = new TextEncoder();
|
|
1312
|
+
if (isWebWritableStream(writable)) {
|
|
1313
|
+
const writer = writable.getWriter();
|
|
1314
|
+
try {
|
|
1315
|
+
for await (const chunk of exportResponsesToCsvStream(schema, submissions, options)) {
|
|
1316
|
+
await writer.write(encoder.encode(chunk));
|
|
1317
|
+
}
|
|
1318
|
+
await writer.close();
|
|
1319
|
+
} catch (cause) {
|
|
1320
|
+
await writer.abort(cause);
|
|
1321
|
+
throw cause;
|
|
1322
|
+
} finally {
|
|
1323
|
+
writer.releaseLock();
|
|
1324
|
+
}
|
|
1325
|
+
return;
|
|
1326
|
+
}
|
|
1327
|
+
let onStreamError;
|
|
1328
|
+
const streamError = new Promise((_resolve, reject) => {
|
|
1329
|
+
onStreamError = reject;
|
|
1330
|
+
writable.once("error", reject);
|
|
1331
|
+
});
|
|
1332
|
+
try {
|
|
1333
|
+
for await (const chunk of exportResponsesToCsvStream(schema, submissions, options)) {
|
|
1334
|
+
await writeNodeChunk(writable, encoder.encode(chunk), streamError);
|
|
1335
|
+
}
|
|
1336
|
+
await Promise.race([new Promise((resolve) => writable.end(resolve)), streamError]);
|
|
1337
|
+
} finally {
|
|
1338
|
+
if (onStreamError !== void 0) writable.removeListener("error", onStreamError);
|
|
1339
|
+
}
|
|
1340
|
+
}
|
|
1251
1341
|
function exportResponsesToCsv(schema, responses, options = {}) {
|
|
1252
1342
|
assertValidFormSchema(schema);
|
|
1253
1343
|
for (const response of responses) {
|
|
@@ -1419,6 +1509,32 @@ function normalizeSubmissionPageSize(pageSize, fallback = 100) {
|
|
|
1419
1509
|
if (!Number.isSafeInteger(value) || value < 1) throw new TypeError("pageSize must be a positive safe integer.");
|
|
1420
1510
|
return value;
|
|
1421
1511
|
}
|
|
1512
|
+
function isJsonArray(value) {
|
|
1513
|
+
return Array.isArray(value);
|
|
1514
|
+
}
|
|
1515
|
+
function isJsonObject(value) {
|
|
1516
|
+
return typeof value === "object" && value !== null && !isJsonArray(value);
|
|
1517
|
+
}
|
|
1518
|
+
function jsonValuesEqual(left, right) {
|
|
1519
|
+
if (left === right) return true;
|
|
1520
|
+
if (left === void 0 || left === null || right === void 0 || right === null || typeof left !== typeof right) {
|
|
1521
|
+
return false;
|
|
1522
|
+
}
|
|
1523
|
+
if (isJsonArray(left) || isJsonArray(right)) {
|
|
1524
|
+
return isJsonArray(left) && isJsonArray(right) && left.length === right.length && left.every((value, index) => jsonValuesEqual(value, right[index]));
|
|
1525
|
+
}
|
|
1526
|
+
if (!isJsonObject(left) || !isJsonObject(right)) return false;
|
|
1527
|
+
const leftKeys = Object.keys(left);
|
|
1528
|
+
const rightKeys = Object.keys(right);
|
|
1529
|
+
return leftKeys.length === rightKeys.length && leftKeys.every((key) => Object.hasOwn(right, key) && jsonValuesEqual(left[key], right[key]));
|
|
1530
|
+
}
|
|
1531
|
+
function matchesSubmissionPageFilters(submission, options) {
|
|
1532
|
+
if (options.filter !== void 0 && !options.filter(submission)) return false;
|
|
1533
|
+
if (options.metadataFilters === void 0) return true;
|
|
1534
|
+
return Object.entries(options.metadataFilters).every(
|
|
1535
|
+
([key, value]) => jsonValuesEqual(submission.metadata?.[key], value)
|
|
1536
|
+
);
|
|
1537
|
+
}
|
|
1422
1538
|
|
|
1423
1539
|
// src/validation.ts
|
|
1424
1540
|
var DEFAULT_MESSAGES = {
|
|
@@ -1857,6 +1973,12 @@ async function resolveFormTranslation(schema, adapter, targetLocale, sourceLocal
|
|
|
1857
1973
|
}
|
|
1858
1974
|
|
|
1859
1975
|
// src/versioning.ts
|
|
1976
|
+
function revisionConflict(state, expectedRevision) {
|
|
1977
|
+
return expectedRevision === void 0 || expectedRevision === state.revision ? void 0 : {
|
|
1978
|
+
success: false,
|
|
1979
|
+
error: { type: "revision_conflict", expectedRevision, actualRevision: state.revision }
|
|
1980
|
+
};
|
|
1981
|
+
}
|
|
1860
1982
|
function validateState(state) {
|
|
1861
1983
|
if (state.formId.trim().length === 0) throw new TypeError("formId must not be empty.");
|
|
1862
1984
|
if (!Number.isSafeInteger(state.nextVersion) || state.nextVersion < 1) {
|
|
@@ -1869,9 +1991,25 @@ function validateState(state) {
|
|
|
1869
1991
|
function cloneVersionToDraft(state, sourceSchema, options = {}) {
|
|
1870
1992
|
validateState(state);
|
|
1871
1993
|
if (sourceSchema.id !== state.formId) throw new TypeError("sourceSchema.id must match state.formId.");
|
|
1994
|
+
const conflict = revisionConflict(state, options.expectedRevision);
|
|
1995
|
+
if (conflict !== void 0) return conflict;
|
|
1872
1996
|
if (state.draftVersion !== void 0) {
|
|
1873
1997
|
return { success: false, error: { type: "draft_already_exists", currentDraftVersion: state.draftVersion } };
|
|
1874
1998
|
}
|
|
1999
|
+
const allowedSourceVersions = /* @__PURE__ */ new Set([
|
|
2000
|
+
...state.publishedVersion === void 0 ? [] : [state.publishedVersion],
|
|
2001
|
+
...options.allowedSourceVersions ?? []
|
|
2002
|
+
]);
|
|
2003
|
+
if (!allowedSourceVersions.has(sourceSchema.version)) {
|
|
2004
|
+
return {
|
|
2005
|
+
success: false,
|
|
2006
|
+
error: {
|
|
2007
|
+
type: "invalid_source_version",
|
|
2008
|
+
requestedVersion: sourceSchema.version,
|
|
2009
|
+
...state.publishedVersion === void 0 ? {} : { publishedVersion: state.publishedVersion }
|
|
2010
|
+
}
|
|
2011
|
+
};
|
|
2012
|
+
}
|
|
1875
2013
|
const maxVersions = options.maxVersions ?? Number.MAX_SAFE_INTEGER;
|
|
1876
2014
|
if (!Number.isSafeInteger(maxVersions) || maxVersions < 1) {
|
|
1877
2015
|
throw new TypeError("maxVersions must be a positive safe integer.");
|
|
@@ -1893,25 +2031,42 @@ function cloneVersionToDraft(state, sourceSchema, options = {}) {
|
|
|
1893
2031
|
}
|
|
1894
2032
|
};
|
|
1895
2033
|
}
|
|
1896
|
-
function
|
|
2034
|
+
function validatePublishedRecord(state, record) {
|
|
2035
|
+
if (record === void 0) return;
|
|
2036
|
+
if (record.formId !== state.formId || record.version !== state.publishedVersion || record.status !== "published" || record.schema.id !== record.formId || record.schema.version !== record.version) {
|
|
2037
|
+
throw new TypeError("currentPublishedRecord must match the state's published version.");
|
|
2038
|
+
}
|
|
2039
|
+
}
|
|
2040
|
+
function transitionTimestamp(options) {
|
|
2041
|
+
const timestamp = options.publishedAt ?? options.timestamp ?? "1970-01-01T00:00:00.000Z";
|
|
2042
|
+
if (!Number.isFinite(Date.parse(timestamp))) throw new TypeError("publishedAt must be a valid date string.");
|
|
2043
|
+
return timestamp;
|
|
2044
|
+
}
|
|
2045
|
+
async function publishDraft(state, draftSchema, options = {}) {
|
|
1897
2046
|
validateState(state);
|
|
1898
|
-
|
|
2047
|
+
const conflict = revisionConflict(state, options.expectedRevision);
|
|
2048
|
+
if (conflict !== void 0) return conflict;
|
|
2049
|
+
if (state.draftVersion === void 0 || draftSchema.id !== state.formId || draftSchema.version !== state.draftVersion) {
|
|
2050
|
+
return { success: false, error: { type: "draft_not_found" } };
|
|
2051
|
+
}
|
|
2052
|
+
validatePublishedRecord(state, options.currentPublishedRecord);
|
|
2053
|
+
const validation = await options.validate?.(draftSchema);
|
|
2054
|
+
if (validation === false || Array.isArray(validation) && validation.length > 0) {
|
|
1899
2055
|
return {
|
|
1900
2056
|
success: false,
|
|
1901
|
-
error: {
|
|
1902
|
-
type: "revision_conflict",
|
|
1903
|
-
expectedRevision: options.expectedRevision,
|
|
1904
|
-
actualRevision: state.revision
|
|
1905
|
-
}
|
|
2057
|
+
error: { type: "validation_failed", issues: Array.isArray(validation) ? validation : [] }
|
|
1906
2058
|
};
|
|
1907
2059
|
}
|
|
1908
|
-
|
|
1909
|
-
return { success: false, error: { type: "draft_not_found" } };
|
|
1910
|
-
}
|
|
1911
|
-
if (options.validate?.(draftSchema) === false) throw new TypeError("Draft schema validation failed.");
|
|
1912
|
-
const timestamp = options.timestamp ?? "1970-01-01T00:00:00.000Z";
|
|
1913
|
-
if (!Number.isFinite(Date.parse(timestamp))) throw new TypeError("timestamp must be a valid date string.");
|
|
2060
|
+
const timestamp = transitionTimestamp(options);
|
|
1914
2061
|
const archivedVersion = state.publishedVersion;
|
|
2062
|
+
const archivedRecords = options.currentPublishedRecord === void 0 ? [] : [
|
|
2063
|
+
{
|
|
2064
|
+
...options.currentPublishedRecord,
|
|
2065
|
+
status: "archived",
|
|
2066
|
+
revision: options.currentPublishedRecord.revision + 1,
|
|
2067
|
+
archivedAt: timestamp
|
|
2068
|
+
}
|
|
2069
|
+
];
|
|
1915
2070
|
const { draftVersion: _draftVersion, ...stateWithoutDraft } = state;
|
|
1916
2071
|
return {
|
|
1917
2072
|
success: true,
|
|
@@ -1926,15 +2081,57 @@ function publishDraft(state, draftSchema, options = {}) {
|
|
|
1926
2081
|
version: draftSchema.version,
|
|
1927
2082
|
status: "published",
|
|
1928
2083
|
schema: draftSchema,
|
|
2084
|
+
revision: 1,
|
|
2085
|
+
...archivedVersion === void 0 ? {} : { createdFromVersion: archivedVersion },
|
|
1929
2086
|
createdAt: timestamp,
|
|
1930
2087
|
publishedAt: timestamp
|
|
1931
2088
|
},
|
|
2089
|
+
archivedRecords,
|
|
1932
2090
|
...archivedVersion === void 0 ? {} : { archivedVersion }
|
|
1933
2091
|
}
|
|
1934
2092
|
};
|
|
1935
2093
|
}
|
|
1936
|
-
function
|
|
2094
|
+
async function createPublishTransitionPlan(state, draftRecord, options = {}) {
|
|
2095
|
+
if (draftRecord.formId !== state.formId || draftRecord.version !== state.draftVersion || draftRecord.schema.id !== draftRecord.formId || draftRecord.schema.version !== draftRecord.version) {
|
|
2096
|
+
return { success: false, error: { type: "draft_not_found" } };
|
|
2097
|
+
}
|
|
2098
|
+
if (draftRecord.status !== "draft") {
|
|
2099
|
+
return { success: false, error: { type: "version_immutable", status: draftRecord.status } };
|
|
2100
|
+
}
|
|
2101
|
+
const expectedRevision = options.expectedRevision ?? state.revision;
|
|
2102
|
+
const timestamp = transitionTimestamp(options);
|
|
2103
|
+
const result = await publishDraft(state, draftRecord.schema, {
|
|
2104
|
+
...options,
|
|
2105
|
+
expectedRevision,
|
|
2106
|
+
publishedAt: timestamp
|
|
2107
|
+
});
|
|
2108
|
+
if (!result.success) return result;
|
|
2109
|
+
const publishedRecordToSave = {
|
|
2110
|
+
...draftRecord,
|
|
2111
|
+
status: "published",
|
|
2112
|
+
revision: draftRecord.revision + 1,
|
|
2113
|
+
publishedAt: timestamp
|
|
2114
|
+
};
|
|
2115
|
+
return {
|
|
2116
|
+
success: true,
|
|
2117
|
+
value: {
|
|
2118
|
+
nextState: result.value.nextState,
|
|
2119
|
+
plan: {
|
|
2120
|
+
formId: state.formId,
|
|
2121
|
+
expectedRevision,
|
|
2122
|
+
nextRevision: result.value.nextState.revision,
|
|
2123
|
+
draftToDeleteVersion: draftRecord.version,
|
|
2124
|
+
publishedRecordToSave,
|
|
2125
|
+
archivedRecordsToSave: result.value.archivedRecords,
|
|
2126
|
+
timestamp
|
|
2127
|
+
}
|
|
2128
|
+
}
|
|
2129
|
+
};
|
|
2130
|
+
}
|
|
2131
|
+
function deleteDraft(state, options = {}) {
|
|
1937
2132
|
validateState(state);
|
|
2133
|
+
const conflict = revisionConflict(state, options.expectedRevision);
|
|
2134
|
+
if (conflict !== void 0) return conflict;
|
|
1938
2135
|
if (state.draftVersion === void 0) return { success: false, error: { type: "draft_not_found" } };
|
|
1939
2136
|
const { draftVersion: _draftVersion, ...stateWithoutDraft } = state;
|
|
1940
2137
|
return {
|
|
@@ -1959,6 +2156,7 @@ export {
|
|
|
1959
2156
|
calculatePageVisibility,
|
|
1960
2157
|
cloneVersionToDraft,
|
|
1961
2158
|
collectSchemaLocales,
|
|
2159
|
+
createPublishTransitionPlan,
|
|
1962
2160
|
createResponseAccumulator,
|
|
1963
2161
|
createSubmission,
|
|
1964
2162
|
decodeSubmissionCursor,
|
|
@@ -1970,7 +2168,9 @@ export {
|
|
|
1970
2168
|
exportResponsesToCsvStream,
|
|
1971
2169
|
isDisplayConditionSatisfied,
|
|
1972
2170
|
isQuestionVisible,
|
|
2171
|
+
matchesSubmissionPageFilters,
|
|
1973
2172
|
normalizeSubmissionPageSize,
|
|
2173
|
+
pipeResponsesToCsvStream,
|
|
1974
2174
|
populateSchemaTranslations,
|
|
1975
2175
|
publishDraft,
|
|
1976
2176
|
resolveFormTranslation,
|