@form-engine-ts/core 2.7.0 → 2.9.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 +9 -0
- package/dist/index.cjs +70 -3
- package/dist/index.d.cts +22 -2
- package/dist/index.d.ts +22 -2
- package/dist/index.js +69 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -79,6 +79,9 @@ Results are ordered by `submittedAt`, then submission ID. Both boundaries are in
|
|
|
79
79
|
`cloneVersionToDraft`, asynchronous `publishDraft`, and `deleteDraft` implement revision-checked version transitions as
|
|
80
80
|
pure functions. `createCloneTransitionPlan`, `createPublishTransitionPlan`, and `createDeleteDraftTransitionPlan` produce
|
|
81
81
|
complete persistence plans with the next state, affected records, and immutable audit events.
|
|
82
|
+
Publishing when state already identifies a Published version requires its matching `currentPublishedRecord`; omission or
|
|
83
|
+
a version mismatch returns the typed `missing_published_record` error. The resulting archive preserves the original
|
|
84
|
+
schema, creation timestamp, and metadata.
|
|
82
85
|
Clone/delete operations accept `expectedRevision`; cloning rejects non-published sources, publish validation failures are
|
|
83
86
|
returned as typed `validation_failed` issues, and successful publishing archives only a supplied actual published record,
|
|
84
87
|
preserving its schema and metadata. `createPublishTransitionPlan` returns complete records plus expected/next revisions for
|
|
@@ -99,5 +102,11 @@ cursor combines `submittedAt` and response ID, so equal timestamps do not produc
|
|
|
99
102
|
and `filter` are applied before page sizing. `filter` accepts a composable `eq`/`in`/`range`/`exists` and/or AST; adapters
|
|
100
103
|
may push supported nodes to their native query language while preserving identical client-side semantics. Adapters that
|
|
101
104
|
implement `listTextAnswerPage` expose stable cursor pagination over individual text answers.
|
|
105
|
+
`TextAnswerPageQueryOptions.fieldIds` can select multiple free-text fields for item-level paging.
|
|
106
|
+
|
|
107
|
+
`iterateSubmissionPages(adapter, formId, query, options)` safely traverses every page as an async generator. It supports
|
|
108
|
+
`pageSize`, `maxItems`, and `AbortSignal`, continues through empty pages with a next cursor, and rejects missing or cyclic
|
|
109
|
+
cursors instead of looping indefinitely. Publish transition validation also rejects mismatched form IDs, non-Published
|
|
110
|
+
records, and an unexpected current record with typed errors.
|
|
102
111
|
|
|
103
112
|
See the [project documentation](https://github.com/nitta-a/form-engine-ts#readme) for the complete schema and API guide.
|
package/dist/index.cjs
CHANGED
|
@@ -46,6 +46,7 @@ __export(index_exports, {
|
|
|
46
46
|
exportResponsesToCsvStream: () => exportResponsesToCsvStream,
|
|
47
47
|
isDisplayConditionSatisfied: () => isDisplayConditionSatisfied,
|
|
48
48
|
isQuestionVisible: () => isQuestionVisible,
|
|
49
|
+
iterateSubmissionPages: () => iterateSubmissionPages,
|
|
49
50
|
jsonValuesEqual: () => jsonValuesEqual,
|
|
50
51
|
matchesSubmissionFilter: () => matchesSubmissionFilter,
|
|
51
52
|
matchesSubmissionPageFilters: () => matchesSubmissionPageFilters,
|
|
@@ -1523,6 +1524,54 @@ function transformFieldType(field, nextType) {
|
|
|
1523
1524
|
}
|
|
1524
1525
|
|
|
1525
1526
|
// src/pagination.ts
|
|
1527
|
+
function asFormResponse2(submission) {
|
|
1528
|
+
return {
|
|
1529
|
+
responseId: submission.id,
|
|
1530
|
+
formId: submission.formId,
|
|
1531
|
+
formVersion: submission.formVersion,
|
|
1532
|
+
sourceLocale: submission.locale,
|
|
1533
|
+
answers: submission.values,
|
|
1534
|
+
submittedAt: submission.submittedAt,
|
|
1535
|
+
...submission.metadata === void 0 ? {} : { metadata: submission.metadata }
|
|
1536
|
+
};
|
|
1537
|
+
}
|
|
1538
|
+
async function* iterateSubmissionPages(adapter, formId, queryOptions = {}, options = {}) {
|
|
1539
|
+
const pageSize = normalizeSubmissionPageSize(options.pageSize ?? queryOptions.pageSize);
|
|
1540
|
+
const maxItems = options.maxItems ?? Number.POSITIVE_INFINITY;
|
|
1541
|
+
if (maxItems !== Number.POSITIVE_INFINITY && (!Number.isSafeInteger(maxItems) || maxItems < 0)) {
|
|
1542
|
+
throw new TypeError("maxItems must be a non-negative safe integer.");
|
|
1543
|
+
}
|
|
1544
|
+
if (maxItems === 0) return;
|
|
1545
|
+
const seenCursors = /* @__PURE__ */ new Set();
|
|
1546
|
+
let cursor = queryOptions.cursor;
|
|
1547
|
+
const { cursor: _initialCursor, pageSize: _initialPageSize, ...baseQueryOptions } = queryOptions;
|
|
1548
|
+
if (cursor !== void 0) seenCursors.add(cursor);
|
|
1549
|
+
let emitted = 0;
|
|
1550
|
+
while (emitted < maxItems) {
|
|
1551
|
+
options.signal?.throwIfAborted();
|
|
1552
|
+
const remaining = maxItems - emitted;
|
|
1553
|
+
const requestedPageSize = Number.isFinite(remaining) ? Math.min(pageSize, remaining) : pageSize;
|
|
1554
|
+
const page = await adapter.listSubmissionPage(formId, {
|
|
1555
|
+
...baseQueryOptions,
|
|
1556
|
+
pageSize: requestedPageSize,
|
|
1557
|
+
...cursor === void 0 ? {} : { cursor }
|
|
1558
|
+
});
|
|
1559
|
+
options.signal?.throwIfAborted();
|
|
1560
|
+
const available = Number.isFinite(remaining) ? page.items.slice(0, remaining) : page.items;
|
|
1561
|
+
if (available.length > 0) {
|
|
1562
|
+
emitted += available.length;
|
|
1563
|
+
yield available.map(asFormResponse2);
|
|
1564
|
+
}
|
|
1565
|
+
if (!page.hasMore || emitted >= maxItems) return;
|
|
1566
|
+
const nextCursor = page.nextCursor;
|
|
1567
|
+
if (nextCursor === void 0 || nextCursor.length === 0) {
|
|
1568
|
+
throw new Error("Submission pagination returned hasMore without a next cursor.");
|
|
1569
|
+
}
|
|
1570
|
+
if (seenCursors.has(nextCursor)) throw new Error(`Submission pagination cursor cycle detected: ${nextCursor}`);
|
|
1571
|
+
seenCursors.add(nextCursor);
|
|
1572
|
+
cursor = nextCursor;
|
|
1573
|
+
}
|
|
1574
|
+
}
|
|
1526
1575
|
var BASE64_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
1527
1576
|
function encodeBase64(bytes) {
|
|
1528
1577
|
let result = "";
|
|
@@ -2203,10 +2252,26 @@ function createCloneTransitionPlan(state, sourceRecord, options = {}) {
|
|
|
2203
2252
|
};
|
|
2204
2253
|
}
|
|
2205
2254
|
function validatePublishedRecord(state, record) {
|
|
2206
|
-
if (
|
|
2207
|
-
|
|
2255
|
+
if (state.publishedVersion === void 0) {
|
|
2256
|
+
return record === void 0 ? void 0 : { success: false, error: { type: "unexpected_published_record" } };
|
|
2257
|
+
}
|
|
2258
|
+
if (record !== void 0 && record.formId !== state.formId) {
|
|
2259
|
+
return { success: false, error: { type: "form_id_mismatch" } };
|
|
2260
|
+
}
|
|
2261
|
+
if (record !== void 0 && record.status !== "published") {
|
|
2262
|
+
return { success: false, error: { type: "invalid_published_status" } };
|
|
2263
|
+
}
|
|
2264
|
+
if (record?.version !== state.publishedVersion) {
|
|
2265
|
+
return {
|
|
2266
|
+
success: false,
|
|
2267
|
+
error: { type: "missing_published_record", expectedVersion: state.publishedVersion }
|
|
2268
|
+
};
|
|
2269
|
+
}
|
|
2270
|
+
if (record === void 0) return void 0;
|
|
2271
|
+
if (record.schema.id !== record.formId || record.schema.version !== record.version) {
|
|
2208
2272
|
throw new TypeError("currentPublishedRecord must match the state's published version.");
|
|
2209
2273
|
}
|
|
2274
|
+
return void 0;
|
|
2210
2275
|
}
|
|
2211
2276
|
function transitionTimestamp(options) {
|
|
2212
2277
|
return requireTimestamp(options.publishedAt ?? options.timestamp, "publishedAt");
|
|
@@ -2218,7 +2283,8 @@ async function publishDraft(state, draftSchema, options = {}) {
|
|
|
2218
2283
|
if (state.draftVersion === void 0 || draftSchema.id !== state.formId || draftSchema.version !== state.draftVersion) {
|
|
2219
2284
|
return { success: false, error: { type: "draft_not_found" } };
|
|
2220
2285
|
}
|
|
2221
|
-
validatePublishedRecord(state, options.currentPublishedRecord);
|
|
2286
|
+
const publishedRecordError = validatePublishedRecord(state, options.currentPublishedRecord);
|
|
2287
|
+
if (publishedRecordError !== void 0) return publishedRecordError;
|
|
2222
2288
|
const validation = await options.validate?.(draftSchema);
|
|
2223
2289
|
if (validation === false || Array.isArray(validation) && validation.length > 0) {
|
|
2224
2290
|
return {
|
|
@@ -2378,6 +2444,7 @@ function assertVersionMutable(status) {
|
|
|
2378
2444
|
exportResponsesToCsvStream,
|
|
2379
2445
|
isDisplayConditionSatisfied,
|
|
2380
2446
|
isQuestionVisible,
|
|
2447
|
+
iterateSubmissionPages,
|
|
2381
2448
|
jsonValuesEqual,
|
|
2382
2449
|
matchesSubmissionFilter,
|
|
2383
2450
|
matchesSubmissionPageFilters,
|
package/dist/index.d.cts
CHANGED
|
@@ -37,6 +37,15 @@ type VersionTransitionError = {
|
|
|
37
37
|
readonly currentDraftVersion: number;
|
|
38
38
|
} | {
|
|
39
39
|
readonly type: "draft_not_found";
|
|
40
|
+
} | {
|
|
41
|
+
readonly type: "missing_published_record";
|
|
42
|
+
readonly expectedVersion: number;
|
|
43
|
+
} | {
|
|
44
|
+
readonly type: "form_id_mismatch";
|
|
45
|
+
} | {
|
|
46
|
+
readonly type: "invalid_published_status";
|
|
47
|
+
} | {
|
|
48
|
+
readonly type: "unexpected_published_record";
|
|
40
49
|
} | {
|
|
41
50
|
readonly type: "revision_conflict";
|
|
42
51
|
readonly expectedRevision: number;
|
|
@@ -280,6 +289,9 @@ interface SubmissionPageQueryOptions {
|
|
|
280
289
|
/** @deprecated Prefer the generic filter AST. */
|
|
281
290
|
readonly metadataFilters?: Readonly<Record<string, JsonValue>>;
|
|
282
291
|
}
|
|
292
|
+
interface TextAnswerPageQueryOptions extends SubmissionPageQueryOptions {
|
|
293
|
+
readonly fieldIds?: readonly string[];
|
|
294
|
+
}
|
|
283
295
|
type SubmissionFilter = {
|
|
284
296
|
readonly op: "eq";
|
|
285
297
|
readonly path: string;
|
|
@@ -311,7 +323,7 @@ interface SubmissionPage {
|
|
|
311
323
|
}
|
|
312
324
|
interface PagedSubmissionStorageAdapter extends FormStorageAdapter {
|
|
313
325
|
listSubmissionPage(formId: string, options?: SubmissionPageQueryOptions): Promise<SubmissionPage>;
|
|
314
|
-
listTextAnswerPage?(formId: string,
|
|
326
|
+
listTextAnswerPage?(formId: string, fieldIdOrOptions?: string | TextAnswerPageQueryOptions, options?: TextAnswerPageQueryOptions): Promise<TextAnswerPage>;
|
|
315
327
|
}
|
|
316
328
|
interface TextAnswerItem {
|
|
317
329
|
readonly responseId: string;
|
|
@@ -348,6 +360,8 @@ type StorageCommitError = {
|
|
|
348
360
|
} | {
|
|
349
361
|
readonly type: "draft_already_exists";
|
|
350
362
|
readonly currentDraftVersion: number;
|
|
363
|
+
} | {
|
|
364
|
+
readonly type: "transaction_unsupported";
|
|
351
365
|
} | {
|
|
352
366
|
readonly type: "invalid_transition";
|
|
353
367
|
readonly message: string;
|
|
@@ -517,6 +531,12 @@ declare function dispatchWebhook<T>(event: FormEvent<T>, config: WebhookConfig,
|
|
|
517
531
|
*/
|
|
518
532
|
declare function transformFieldType(field: FormField, nextType: QuestionType): FormField;
|
|
519
533
|
|
|
534
|
+
interface PaginationIteratorOptions {
|
|
535
|
+
readonly pageSize?: number;
|
|
536
|
+
readonly maxItems?: number;
|
|
537
|
+
readonly signal?: AbortSignal;
|
|
538
|
+
}
|
|
539
|
+
declare function iterateSubmissionPages(adapter: PagedSubmissionStorageAdapter, formId: string, queryOptions?: SubmissionPageQueryOptions, options?: PaginationIteratorOptions): AsyncIterable<readonly FormResponse[]>;
|
|
520
540
|
interface SubmissionCursorValue {
|
|
521
541
|
readonly submittedAt: string;
|
|
522
542
|
readonly responseId: string;
|
|
@@ -607,4 +627,4 @@ declare function calculatePageVisibility(schema: FormSchema, currentAnswers: Rea
|
|
|
607
627
|
declare function calculateFieldVisibility(schema: FormSchema, currentAnswers: Readonly<Record<string, unknown>>): Readonly<Record<string, boolean>>;
|
|
608
628
|
declare function selectVisibleAnswers(schema: FormSchema, currentAnswers: FormValues): FormValues;
|
|
609
629
|
|
|
610
|
-
export { type AccumulatorReport, type AccumulatorResponse, type AccumulatorSkipReason, type AnswerValidationResult, type AsyncTranslationAdapter, type BaseField, type CheckboxField, type CheckboxQuestionAggregate, type ChoiceDistributionEntry, type ChoiceOption, type ChoiceQuestionAggregate, type CloneVersionOptions, type CollectedLocales, type ConditionOperator, type ConditionValue, type CreateSubmissionOptions, type CrossTabulationResult, type CsvColumnContext, type CsvColumnDef, type CsvExportOptions, type DeleteDraftOptions, type DisplayCondition, type ExtensibleNode, type FieldOption, type FieldType, type FormAnalytics, type FormEvent, type FormEventType, type FormField, type FormPage, type FormPolicy, type FormResponse, type FormSchema, type FormStorageAdapter, type FormSubmission, type FormValue, type FormValues, type FormVersionRecord, type FormVersionState, type FormVersionStatus, type JsonValue, type LocalizedText, type MultiSelectField, type NodeWritableStream, type NumberField, type NumberQuestionAggregate, type NumericSummary, type OptionAggregate, type PagedSubmissionStorageAdapter, type PopulateTranslationOptions, type PublishDraftOptions, type PublishDraftResult, type Question, type QuestionAggregate, type QuestionType, type RatingField, type ResponseAccumulator, type ResponseAccumulatorOptions, type Result, type SchemaIssue, type SchemaStructureIssue, type SchemaStructureIssueType, type SchemaTranslations, type SchemaValidationResult, type SelectField, type StorageAdapter, type StorageCommitError, type StreamCsvOptions, type SubmissionCursorValue, type SubmissionFilter, type SubmissionPage, type SubmissionPageQueryOptions, type SubmissionQueryOptions, type TextAnswerCursorValue, type TextAnswerItem, type TextAnswerPage, type TextField, type TextQuestionAggregate, type TranslationAdapter, type TranslationReport, type TranslationSlot, type ValidateFormSchemaOptions, type ValidationCode, type ValidationError, type ValidationIssue, type VersionTransitionError, type VersionTransitionEvent, type VersionTransitionPlan, type VersionedFormStorageAdapter, type WebhookConfig, type WebhookDispatchResult, aggregateResponses, assertValidFormSchema, assertVersionMutable, calculateChoiceDistribution, calculateCrossTabulation, calculateFieldVisibility, calculateNumericSummary, calculatePageVisibility, cloneVersionToDraft, collectSchemaLocales, createCloneTransitionPlan, createDeleteDraftTransitionPlan, createPublishTransitionPlan, createResponseAccumulator, createSubmission, decodeSubmissionCursor, decodeTextAnswerCursor, deleteDraft, dispatchWebhook, encodeSubmissionCursor, encodeTextAnswerCursor, escapeCsvCell, exportResponsesToCsv, exportResponsesToCsvStream, isDisplayConditionSatisfied, isQuestionVisible, jsonValuesEqual, matchesSubmissionFilter, matchesSubmissionPageFilters, normalizeSubmissionPageSize, pipeResponsesToCsvStream, populateSchemaTranslations, publishDraft, resolveFormTranslation, resolveLocalizedSchema, sanitizeSchema, selectVisibleAnswers, transformFieldType, validateAnswers, validateFormSchema, validatePageAnswers, validateSchemaStructure };
|
|
630
|
+
export { type AccumulatorReport, type AccumulatorResponse, type AccumulatorSkipReason, type AnswerValidationResult, type AsyncTranslationAdapter, type BaseField, type CheckboxField, type CheckboxQuestionAggregate, type ChoiceDistributionEntry, type ChoiceOption, type ChoiceQuestionAggregate, type CloneVersionOptions, type CollectedLocales, type ConditionOperator, type ConditionValue, type CreateSubmissionOptions, type CrossTabulationResult, type CsvColumnContext, type CsvColumnDef, type CsvExportOptions, type DeleteDraftOptions, type DisplayCondition, type ExtensibleNode, type FieldOption, type FieldType, type FormAnalytics, type FormEvent, type FormEventType, type FormField, type FormPage, type FormPolicy, type FormResponse, type FormSchema, type FormStorageAdapter, type FormSubmission, type FormValue, type FormValues, type FormVersionRecord, type FormVersionState, type FormVersionStatus, type JsonValue, type LocalizedText, type MultiSelectField, type NodeWritableStream, type NumberField, type NumberQuestionAggregate, type NumericSummary, type OptionAggregate, type PagedSubmissionStorageAdapter, type PaginationIteratorOptions, type PopulateTranslationOptions, type PublishDraftOptions, type PublishDraftResult, type Question, type QuestionAggregate, type QuestionType, type RatingField, type ResponseAccumulator, type ResponseAccumulatorOptions, type Result, type SchemaIssue, type SchemaStructureIssue, type SchemaStructureIssueType, type SchemaTranslations, type SchemaValidationResult, type SelectField, type StorageAdapter, type StorageCommitError, type StreamCsvOptions, type SubmissionCursorValue, type SubmissionFilter, type SubmissionPage, type SubmissionPageQueryOptions, type SubmissionQueryOptions, type TextAnswerCursorValue, type TextAnswerItem, type TextAnswerPage, type TextAnswerPageQueryOptions, type TextField, type TextQuestionAggregate, type TranslationAdapter, type TranslationReport, type TranslationSlot, type ValidateFormSchemaOptions, type ValidationCode, type ValidationError, type ValidationIssue, type VersionTransitionError, type VersionTransitionEvent, type VersionTransitionPlan, type VersionedFormStorageAdapter, type WebhookConfig, type WebhookDispatchResult, aggregateResponses, assertValidFormSchema, assertVersionMutable, calculateChoiceDistribution, calculateCrossTabulation, calculateFieldVisibility, calculateNumericSummary, calculatePageVisibility, cloneVersionToDraft, collectSchemaLocales, createCloneTransitionPlan, createDeleteDraftTransitionPlan, createPublishTransitionPlan, createResponseAccumulator, createSubmission, decodeSubmissionCursor, decodeTextAnswerCursor, deleteDraft, dispatchWebhook, encodeSubmissionCursor, encodeTextAnswerCursor, escapeCsvCell, exportResponsesToCsv, exportResponsesToCsvStream, isDisplayConditionSatisfied, isQuestionVisible, iterateSubmissionPages, jsonValuesEqual, matchesSubmissionFilter, matchesSubmissionPageFilters, normalizeSubmissionPageSize, pipeResponsesToCsvStream, populateSchemaTranslations, publishDraft, resolveFormTranslation, resolveLocalizedSchema, sanitizeSchema, selectVisibleAnswers, transformFieldType, validateAnswers, validateFormSchema, validatePageAnswers, validateSchemaStructure };
|
package/dist/index.d.ts
CHANGED
|
@@ -37,6 +37,15 @@ type VersionTransitionError = {
|
|
|
37
37
|
readonly currentDraftVersion: number;
|
|
38
38
|
} | {
|
|
39
39
|
readonly type: "draft_not_found";
|
|
40
|
+
} | {
|
|
41
|
+
readonly type: "missing_published_record";
|
|
42
|
+
readonly expectedVersion: number;
|
|
43
|
+
} | {
|
|
44
|
+
readonly type: "form_id_mismatch";
|
|
45
|
+
} | {
|
|
46
|
+
readonly type: "invalid_published_status";
|
|
47
|
+
} | {
|
|
48
|
+
readonly type: "unexpected_published_record";
|
|
40
49
|
} | {
|
|
41
50
|
readonly type: "revision_conflict";
|
|
42
51
|
readonly expectedRevision: number;
|
|
@@ -280,6 +289,9 @@ interface SubmissionPageQueryOptions {
|
|
|
280
289
|
/** @deprecated Prefer the generic filter AST. */
|
|
281
290
|
readonly metadataFilters?: Readonly<Record<string, JsonValue>>;
|
|
282
291
|
}
|
|
292
|
+
interface TextAnswerPageQueryOptions extends SubmissionPageQueryOptions {
|
|
293
|
+
readonly fieldIds?: readonly string[];
|
|
294
|
+
}
|
|
283
295
|
type SubmissionFilter = {
|
|
284
296
|
readonly op: "eq";
|
|
285
297
|
readonly path: string;
|
|
@@ -311,7 +323,7 @@ interface SubmissionPage {
|
|
|
311
323
|
}
|
|
312
324
|
interface PagedSubmissionStorageAdapter extends FormStorageAdapter {
|
|
313
325
|
listSubmissionPage(formId: string, options?: SubmissionPageQueryOptions): Promise<SubmissionPage>;
|
|
314
|
-
listTextAnswerPage?(formId: string,
|
|
326
|
+
listTextAnswerPage?(formId: string, fieldIdOrOptions?: string | TextAnswerPageQueryOptions, options?: TextAnswerPageQueryOptions): Promise<TextAnswerPage>;
|
|
315
327
|
}
|
|
316
328
|
interface TextAnswerItem {
|
|
317
329
|
readonly responseId: string;
|
|
@@ -348,6 +360,8 @@ type StorageCommitError = {
|
|
|
348
360
|
} | {
|
|
349
361
|
readonly type: "draft_already_exists";
|
|
350
362
|
readonly currentDraftVersion: number;
|
|
363
|
+
} | {
|
|
364
|
+
readonly type: "transaction_unsupported";
|
|
351
365
|
} | {
|
|
352
366
|
readonly type: "invalid_transition";
|
|
353
367
|
readonly message: string;
|
|
@@ -517,6 +531,12 @@ declare function dispatchWebhook<T>(event: FormEvent<T>, config: WebhookConfig,
|
|
|
517
531
|
*/
|
|
518
532
|
declare function transformFieldType(field: FormField, nextType: QuestionType): FormField;
|
|
519
533
|
|
|
534
|
+
interface PaginationIteratorOptions {
|
|
535
|
+
readonly pageSize?: number;
|
|
536
|
+
readonly maxItems?: number;
|
|
537
|
+
readonly signal?: AbortSignal;
|
|
538
|
+
}
|
|
539
|
+
declare function iterateSubmissionPages(adapter: PagedSubmissionStorageAdapter, formId: string, queryOptions?: SubmissionPageQueryOptions, options?: PaginationIteratorOptions): AsyncIterable<readonly FormResponse[]>;
|
|
520
540
|
interface SubmissionCursorValue {
|
|
521
541
|
readonly submittedAt: string;
|
|
522
542
|
readonly responseId: string;
|
|
@@ -607,4 +627,4 @@ declare function calculatePageVisibility(schema: FormSchema, currentAnswers: Rea
|
|
|
607
627
|
declare function calculateFieldVisibility(schema: FormSchema, currentAnswers: Readonly<Record<string, unknown>>): Readonly<Record<string, boolean>>;
|
|
608
628
|
declare function selectVisibleAnswers(schema: FormSchema, currentAnswers: FormValues): FormValues;
|
|
609
629
|
|
|
610
|
-
export { type AccumulatorReport, type AccumulatorResponse, type AccumulatorSkipReason, type AnswerValidationResult, type AsyncTranslationAdapter, type BaseField, type CheckboxField, type CheckboxQuestionAggregate, type ChoiceDistributionEntry, type ChoiceOption, type ChoiceQuestionAggregate, type CloneVersionOptions, type CollectedLocales, type ConditionOperator, type ConditionValue, type CreateSubmissionOptions, type CrossTabulationResult, type CsvColumnContext, type CsvColumnDef, type CsvExportOptions, type DeleteDraftOptions, type DisplayCondition, type ExtensibleNode, type FieldOption, type FieldType, type FormAnalytics, type FormEvent, type FormEventType, type FormField, type FormPage, type FormPolicy, type FormResponse, type FormSchema, type FormStorageAdapter, type FormSubmission, type FormValue, type FormValues, type FormVersionRecord, type FormVersionState, type FormVersionStatus, type JsonValue, type LocalizedText, type MultiSelectField, type NodeWritableStream, type NumberField, type NumberQuestionAggregate, type NumericSummary, type OptionAggregate, type PagedSubmissionStorageAdapter, type PopulateTranslationOptions, type PublishDraftOptions, type PublishDraftResult, type Question, type QuestionAggregate, type QuestionType, type RatingField, type ResponseAccumulator, type ResponseAccumulatorOptions, type Result, type SchemaIssue, type SchemaStructureIssue, type SchemaStructureIssueType, type SchemaTranslations, type SchemaValidationResult, type SelectField, type StorageAdapter, type StorageCommitError, type StreamCsvOptions, type SubmissionCursorValue, type SubmissionFilter, type SubmissionPage, type SubmissionPageQueryOptions, type SubmissionQueryOptions, type TextAnswerCursorValue, type TextAnswerItem, type TextAnswerPage, type TextField, type TextQuestionAggregate, type TranslationAdapter, type TranslationReport, type TranslationSlot, type ValidateFormSchemaOptions, type ValidationCode, type ValidationError, type ValidationIssue, type VersionTransitionError, type VersionTransitionEvent, type VersionTransitionPlan, type VersionedFormStorageAdapter, type WebhookConfig, type WebhookDispatchResult, aggregateResponses, assertValidFormSchema, assertVersionMutable, calculateChoiceDistribution, calculateCrossTabulation, calculateFieldVisibility, calculateNumericSummary, calculatePageVisibility, cloneVersionToDraft, collectSchemaLocales, createCloneTransitionPlan, createDeleteDraftTransitionPlan, createPublishTransitionPlan, createResponseAccumulator, createSubmission, decodeSubmissionCursor, decodeTextAnswerCursor, deleteDraft, dispatchWebhook, encodeSubmissionCursor, encodeTextAnswerCursor, escapeCsvCell, exportResponsesToCsv, exportResponsesToCsvStream, isDisplayConditionSatisfied, isQuestionVisible, jsonValuesEqual, matchesSubmissionFilter, matchesSubmissionPageFilters, normalizeSubmissionPageSize, pipeResponsesToCsvStream, populateSchemaTranslations, publishDraft, resolveFormTranslation, resolveLocalizedSchema, sanitizeSchema, selectVisibleAnswers, transformFieldType, validateAnswers, validateFormSchema, validatePageAnswers, validateSchemaStructure };
|
|
630
|
+
export { type AccumulatorReport, type AccumulatorResponse, type AccumulatorSkipReason, type AnswerValidationResult, type AsyncTranslationAdapter, type BaseField, type CheckboxField, type CheckboxQuestionAggregate, type ChoiceDistributionEntry, type ChoiceOption, type ChoiceQuestionAggregate, type CloneVersionOptions, type CollectedLocales, type ConditionOperator, type ConditionValue, type CreateSubmissionOptions, type CrossTabulationResult, type CsvColumnContext, type CsvColumnDef, type CsvExportOptions, type DeleteDraftOptions, type DisplayCondition, type ExtensibleNode, type FieldOption, type FieldType, type FormAnalytics, type FormEvent, type FormEventType, type FormField, type FormPage, type FormPolicy, type FormResponse, type FormSchema, type FormStorageAdapter, type FormSubmission, type FormValue, type FormValues, type FormVersionRecord, type FormVersionState, type FormVersionStatus, type JsonValue, type LocalizedText, type MultiSelectField, type NodeWritableStream, type NumberField, type NumberQuestionAggregate, type NumericSummary, type OptionAggregate, type PagedSubmissionStorageAdapter, type PaginationIteratorOptions, type PopulateTranslationOptions, type PublishDraftOptions, type PublishDraftResult, type Question, type QuestionAggregate, type QuestionType, type RatingField, type ResponseAccumulator, type ResponseAccumulatorOptions, type Result, type SchemaIssue, type SchemaStructureIssue, type SchemaStructureIssueType, type SchemaTranslations, type SchemaValidationResult, type SelectField, type StorageAdapter, type StorageCommitError, type StreamCsvOptions, type SubmissionCursorValue, type SubmissionFilter, type SubmissionPage, type SubmissionPageQueryOptions, type SubmissionQueryOptions, type TextAnswerCursorValue, type TextAnswerItem, type TextAnswerPage, type TextAnswerPageQueryOptions, type TextField, type TextQuestionAggregate, type TranslationAdapter, type TranslationReport, type TranslationSlot, type ValidateFormSchemaOptions, type ValidationCode, type ValidationError, type ValidationIssue, type VersionTransitionError, type VersionTransitionEvent, type VersionTransitionPlan, type VersionedFormStorageAdapter, type WebhookConfig, type WebhookDispatchResult, aggregateResponses, assertValidFormSchema, assertVersionMutable, calculateChoiceDistribution, calculateCrossTabulation, calculateFieldVisibility, calculateNumericSummary, calculatePageVisibility, cloneVersionToDraft, collectSchemaLocales, createCloneTransitionPlan, createDeleteDraftTransitionPlan, createPublishTransitionPlan, createResponseAccumulator, createSubmission, decodeSubmissionCursor, decodeTextAnswerCursor, deleteDraft, dispatchWebhook, encodeSubmissionCursor, encodeTextAnswerCursor, escapeCsvCell, exportResponsesToCsv, exportResponsesToCsvStream, isDisplayConditionSatisfied, isQuestionVisible, iterateSubmissionPages, jsonValuesEqual, matchesSubmissionFilter, matchesSubmissionPageFilters, normalizeSubmissionPageSize, pipeResponsesToCsvStream, populateSchemaTranslations, publishDraft, resolveFormTranslation, resolveLocalizedSchema, sanitizeSchema, selectVisibleAnswers, transformFieldType, validateAnswers, validateFormSchema, validatePageAnswers, validateSchemaStructure };
|
package/dist/index.js
CHANGED
|
@@ -1456,6 +1456,54 @@ function transformFieldType(field, nextType) {
|
|
|
1456
1456
|
}
|
|
1457
1457
|
|
|
1458
1458
|
// src/pagination.ts
|
|
1459
|
+
function asFormResponse2(submission) {
|
|
1460
|
+
return {
|
|
1461
|
+
responseId: submission.id,
|
|
1462
|
+
formId: submission.formId,
|
|
1463
|
+
formVersion: submission.formVersion,
|
|
1464
|
+
sourceLocale: submission.locale,
|
|
1465
|
+
answers: submission.values,
|
|
1466
|
+
submittedAt: submission.submittedAt,
|
|
1467
|
+
...submission.metadata === void 0 ? {} : { metadata: submission.metadata }
|
|
1468
|
+
};
|
|
1469
|
+
}
|
|
1470
|
+
async function* iterateSubmissionPages(adapter, formId, queryOptions = {}, options = {}) {
|
|
1471
|
+
const pageSize = normalizeSubmissionPageSize(options.pageSize ?? queryOptions.pageSize);
|
|
1472
|
+
const maxItems = options.maxItems ?? Number.POSITIVE_INFINITY;
|
|
1473
|
+
if (maxItems !== Number.POSITIVE_INFINITY && (!Number.isSafeInteger(maxItems) || maxItems < 0)) {
|
|
1474
|
+
throw new TypeError("maxItems must be a non-negative safe integer.");
|
|
1475
|
+
}
|
|
1476
|
+
if (maxItems === 0) return;
|
|
1477
|
+
const seenCursors = /* @__PURE__ */ new Set();
|
|
1478
|
+
let cursor = queryOptions.cursor;
|
|
1479
|
+
const { cursor: _initialCursor, pageSize: _initialPageSize, ...baseQueryOptions } = queryOptions;
|
|
1480
|
+
if (cursor !== void 0) seenCursors.add(cursor);
|
|
1481
|
+
let emitted = 0;
|
|
1482
|
+
while (emitted < maxItems) {
|
|
1483
|
+
options.signal?.throwIfAborted();
|
|
1484
|
+
const remaining = maxItems - emitted;
|
|
1485
|
+
const requestedPageSize = Number.isFinite(remaining) ? Math.min(pageSize, remaining) : pageSize;
|
|
1486
|
+
const page = await adapter.listSubmissionPage(formId, {
|
|
1487
|
+
...baseQueryOptions,
|
|
1488
|
+
pageSize: requestedPageSize,
|
|
1489
|
+
...cursor === void 0 ? {} : { cursor }
|
|
1490
|
+
});
|
|
1491
|
+
options.signal?.throwIfAborted();
|
|
1492
|
+
const available = Number.isFinite(remaining) ? page.items.slice(0, remaining) : page.items;
|
|
1493
|
+
if (available.length > 0) {
|
|
1494
|
+
emitted += available.length;
|
|
1495
|
+
yield available.map(asFormResponse2);
|
|
1496
|
+
}
|
|
1497
|
+
if (!page.hasMore || emitted >= maxItems) return;
|
|
1498
|
+
const nextCursor = page.nextCursor;
|
|
1499
|
+
if (nextCursor === void 0 || nextCursor.length === 0) {
|
|
1500
|
+
throw new Error("Submission pagination returned hasMore without a next cursor.");
|
|
1501
|
+
}
|
|
1502
|
+
if (seenCursors.has(nextCursor)) throw new Error(`Submission pagination cursor cycle detected: ${nextCursor}`);
|
|
1503
|
+
seenCursors.add(nextCursor);
|
|
1504
|
+
cursor = nextCursor;
|
|
1505
|
+
}
|
|
1506
|
+
}
|
|
1459
1507
|
var BASE64_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
1460
1508
|
function encodeBase64(bytes) {
|
|
1461
1509
|
let result = "";
|
|
@@ -2136,10 +2184,26 @@ function createCloneTransitionPlan(state, sourceRecord, options = {}) {
|
|
|
2136
2184
|
};
|
|
2137
2185
|
}
|
|
2138
2186
|
function validatePublishedRecord(state, record) {
|
|
2139
|
-
if (
|
|
2140
|
-
|
|
2187
|
+
if (state.publishedVersion === void 0) {
|
|
2188
|
+
return record === void 0 ? void 0 : { success: false, error: { type: "unexpected_published_record" } };
|
|
2189
|
+
}
|
|
2190
|
+
if (record !== void 0 && record.formId !== state.formId) {
|
|
2191
|
+
return { success: false, error: { type: "form_id_mismatch" } };
|
|
2192
|
+
}
|
|
2193
|
+
if (record !== void 0 && record.status !== "published") {
|
|
2194
|
+
return { success: false, error: { type: "invalid_published_status" } };
|
|
2195
|
+
}
|
|
2196
|
+
if (record?.version !== state.publishedVersion) {
|
|
2197
|
+
return {
|
|
2198
|
+
success: false,
|
|
2199
|
+
error: { type: "missing_published_record", expectedVersion: state.publishedVersion }
|
|
2200
|
+
};
|
|
2201
|
+
}
|
|
2202
|
+
if (record === void 0) return void 0;
|
|
2203
|
+
if (record.schema.id !== record.formId || record.schema.version !== record.version) {
|
|
2141
2204
|
throw new TypeError("currentPublishedRecord must match the state's published version.");
|
|
2142
2205
|
}
|
|
2206
|
+
return void 0;
|
|
2143
2207
|
}
|
|
2144
2208
|
function transitionTimestamp(options) {
|
|
2145
2209
|
return requireTimestamp(options.publishedAt ?? options.timestamp, "publishedAt");
|
|
@@ -2151,7 +2215,8 @@ async function publishDraft(state, draftSchema, options = {}) {
|
|
|
2151
2215
|
if (state.draftVersion === void 0 || draftSchema.id !== state.formId || draftSchema.version !== state.draftVersion) {
|
|
2152
2216
|
return { success: false, error: { type: "draft_not_found" } };
|
|
2153
2217
|
}
|
|
2154
|
-
validatePublishedRecord(state, options.currentPublishedRecord);
|
|
2218
|
+
const publishedRecordError = validatePublishedRecord(state, options.currentPublishedRecord);
|
|
2219
|
+
if (publishedRecordError !== void 0) return publishedRecordError;
|
|
2155
2220
|
const validation = await options.validate?.(draftSchema);
|
|
2156
2221
|
if (validation === false || Array.isArray(validation) && validation.length > 0) {
|
|
2157
2222
|
return {
|
|
@@ -2310,6 +2375,7 @@ export {
|
|
|
2310
2375
|
exportResponsesToCsvStream,
|
|
2311
2376
|
isDisplayConditionSatisfied,
|
|
2312
2377
|
isQuestionVisible,
|
|
2378
|
+
iterateSubmissionPages,
|
|
2313
2379
|
jsonValuesEqual,
|
|
2314
2380
|
matchesSubmissionFilter,
|
|
2315
2381
|
matchesSubmissionPageFilters,
|