@form-engine-ts/core 4.7.0 → 5.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/dist/index.js CHANGED
@@ -1,8 +1,24 @@
1
+ // src/locale.ts
2
+ var normalizeLocale = (rawLocale) => {
3
+ if (!rawLocale || typeof rawLocale !== "string") return null;
4
+ const trimmed = rawLocale.trim().replace(/_/gu, "-");
5
+ if (trimmed.length === 0) return null;
6
+ try {
7
+ return Intl.getCanonicalLocales(trimmed)[0] ?? null;
8
+ } catch {
9
+ return null;
10
+ }
11
+ };
12
+ function canonicalLocaleOrRaw(rawLocale) {
13
+ return normalizeLocale(rawLocale) ?? rawLocale;
14
+ }
15
+
1
16
  // src/policy.ts
2
17
  function collectRecordKeys(value, path, pathsByLocale) {
3
- for (const locale of Object.keys(value ?? {})) {
18
+ for (const rawLocale of Object.keys(value ?? {})) {
19
+ const locale = canonicalLocaleOrRaw(rawLocale);
4
20
  const paths = pathsByLocale.get(locale) ?? [];
5
- paths.push(`${path}.${locale}`);
21
+ paths.push(`${path}.${rawLocale}`);
6
22
  pathsByLocale.set(locale, paths);
7
23
  }
8
24
  }
@@ -33,13 +49,15 @@ function collectSchemaLocales(schema) {
33
49
  });
34
50
  const translationLocales = new Set(pathsByLocale.keys());
35
51
  const allUniqueLocales = /* @__PURE__ */ new Set([
36
- ...schema.defaultLocale === void 0 ? [] : [schema.defaultLocale],
37
- ...schema.supportedLocales ?? [],
52
+ ...schema.defaultLocale === void 0 ? [] : [canonicalLocaleOrRaw(schema.defaultLocale)],
53
+ ...(schema.supportedLocales ?? []).map(canonicalLocaleOrRaw),
38
54
  ...translationLocales
39
55
  ]);
56
+ const defaultLocale = schema.defaultLocale === void 0 ? void 0 : canonicalLocaleOrRaw(schema.defaultLocale);
57
+ const supportedLocales = (schema.supportedLocales ?? []).map(canonicalLocaleOrRaw);
40
58
  return {
41
- ...schema.defaultLocale === void 0 ? {} : { defaultLocale: schema.defaultLocale },
42
- supportedLocales: schema.supportedLocales ?? [],
59
+ ...defaultLocale === void 0 ? {} : { defaultLocale },
60
+ supportedLocales,
43
61
  translationLocales,
44
62
  allUniqueLocales,
45
63
  translationLocalePaths: pathsByLocale
@@ -62,7 +80,12 @@ function displayRuleSourceIds(field) {
62
80
  }
63
81
  function registeredEntries(value, registeredLocales) {
64
82
  if (value === void 0) return void 0;
65
- const entries = Object.entries(value).filter(([locale]) => registeredLocales.has(locale));
83
+ const entries = [];
84
+ for (const [rawLocale, entry] of Object.entries(value)) {
85
+ const locale = normalizeLocale(rawLocale);
86
+ if (locale === null || !registeredLocales.has(locale)) continue;
87
+ entries.push([locale, entry]);
88
+ }
66
89
  return entries.length === 0 ? void 0 : Object.fromEntries(entries);
67
90
  }
68
91
  function sanitizeNodeLocales(node, registeredLocales) {
@@ -100,6 +123,16 @@ function sanitizePageLocales(page, registeredLocales) {
100
123
  const translations = registeredEntries(page.translations, registeredLocales);
101
124
  return { ...base, ...translations === void 0 ? {} : { translations } };
102
125
  }
126
+ function normalizedLocaleList(locales) {
127
+ return [
128
+ ...new Set(
129
+ locales.flatMap((locale) => {
130
+ const normalized = normalizeLocale(locale);
131
+ return normalized === null ? [] : [normalized];
132
+ })
133
+ )
134
+ ];
135
+ }
103
136
  function sanitizeFieldConstraints(field, policy) {
104
137
  const constraint = policy?.fieldConstraints?.[field.type];
105
138
  if (constraint === void 0) return field;
@@ -214,10 +247,9 @@ function validateSchemaStructure(schema) {
214
247
  }
215
248
  function sanitizeSchema(schema, options = {}) {
216
249
  const existingQuestionIds = new Set(schema.fields.map((field) => field.id));
217
- const registeredLocales = /* @__PURE__ */ new Set([
218
- ...schema.defaultLocale === void 0 ? [] : [schema.defaultLocale],
219
- ...schema.supportedLocales ?? []
220
- ]);
250
+ const defaultLocale = schema.defaultLocale === void 0 ? null : normalizeLocale(schema.defaultLocale);
251
+ const supportedLocales = schema.supportedLocales === void 0 ? void 0 : normalizedLocaleList(schema.supportedLocales);
252
+ const registeredLocales = /* @__PURE__ */ new Set([...defaultLocale === null ? [] : [defaultLocale], ...supportedLocales ?? []]);
221
253
  const cyclic = cyclicQuestionIds(schema.fields);
222
254
  const sanitizedFields = schema.fields.map((sourceField) => {
223
255
  const field = sanitizeFieldConstraints(sanitizeFieldLocales(sourceField, registeredLocales), options.policy);
@@ -235,10 +267,17 @@ function sanitizeSchema(schema, options = {}) {
235
267
  return sanitized;
236
268
  });
237
269
  const localizedSchema = sanitizeNodeLocales(schema, registeredLocales);
238
- const { translations: _translations, ...schemaWithoutLocaleContent } = localizedSchema;
270
+ const {
271
+ defaultLocale: _defaultLocale,
272
+ supportedLocales: _supportedLocales,
273
+ translations: _translations,
274
+ ...schemaWithoutLocaleContent
275
+ } = localizedSchema;
239
276
  const translations = registeredEntries(schema.translations, registeredLocales);
240
277
  const base = {
241
278
  ...schemaWithoutLocaleContent,
279
+ ...defaultLocale === null ? {} : { defaultLocale },
280
+ ...supportedLocales === void 0 ? {} : { supportedLocales },
242
281
  ...translations === void 0 ? {} : { translations },
243
282
  fields: sanitizedFields
244
283
  };
@@ -291,6 +330,12 @@ function isRecord(value) {
291
330
  function isNonEmptyString(value) {
292
331
  return typeof value === "string" && value.trim().length > 0;
293
332
  }
333
+ function localeRecordEntry(record, locale) {
334
+ for (const [candidate, value] of Object.entries(record ?? {})) {
335
+ if (canonicalLocaleOrRaw(candidate) === locale) return value;
336
+ }
337
+ return void 0;
338
+ }
294
339
  function issue(issues, path, code, message) {
295
340
  issues.push({ path, code, message });
296
341
  }
@@ -653,51 +698,55 @@ function collectSchemaText(schema) {
653
698
  return entries;
654
699
  }
655
700
  function addRequiredTranslationIssues(schema, locale, issues) {
656
- if (!(schema.supportedLocales ?? []).includes(locale)) {
701
+ if (!(schema.supportedLocales ?? []).some((candidate) => canonicalLocaleOrRaw(candidate) === locale)) {
657
702
  issue(issues, "supportedLocales", "required_locale_missing", `Required locale ${locale} is missing.`);
658
703
  }
659
- if (locale === schema.defaultLocale) return;
704
+ if (schema.defaultLocale !== void 0 && canonicalLocaleOrRaw(schema.defaultLocale) === locale) return;
705
+ const formTranslation = localeRecordEntry(schema.translations, locale);
660
706
  const required = [
661
- { path: `translations.${locale}.title`, value: schema.translations?.[locale]?.title }
707
+ { path: `translations.${locale}.title`, value: formTranslation?.title }
662
708
  ];
663
709
  if (schema.description !== void 0)
664
- required.push({ path: `translations.${locale}.description`, value: schema.translations?.[locale]?.description });
710
+ required.push({ path: `translations.${locale}.description`, value: formTranslation?.description });
665
711
  if (schema.completionMessage !== void 0) {
666
712
  required.push({
667
713
  path: `translations.${locale}.completionMessage`,
668
- value: schema.translations?.[locale]?.completionMessage
714
+ value: formTranslation?.completionMessage
669
715
  });
670
716
  }
671
717
  schema.fields.forEach((field, fieldIndex) => {
718
+ const fieldTranslation = localeRecordEntry(field.translations, locale);
672
719
  required.push({
673
720
  path: `fields[${fieldIndex}].translations.${locale}.title`,
674
- value: field.translations?.[locale]?.title
721
+ value: fieldTranslation?.title
675
722
  });
676
723
  if (field.description !== void 0) {
677
724
  required.push({
678
725
  path: `fields[${fieldIndex}].translations.${locale}.description`,
679
- value: field.translations?.[locale]?.description
726
+ value: fieldTranslation?.description
680
727
  });
681
728
  }
682
729
  if (!("options" in field)) return;
683
730
  field.options.forEach((option, optionIndex) => {
731
+ const optionTranslation = localeRecordEntry(option.translations, locale);
684
732
  required.push({
685
733
  path: `fields[${fieldIndex}].options[${optionIndex}].translations.${locale}`,
686
- value: option.translations?.[locale]
734
+ value: optionTranslation
687
735
  });
688
736
  });
689
737
  });
690
738
  schema.pages?.forEach((page, pageIndex) => {
739
+ const pageTranslation = localeRecordEntry(page.translations, locale);
691
740
  if (page.title !== void 0) {
692
741
  required.push({
693
742
  path: `pages[${pageIndex}].translations.${locale}.title`,
694
- value: page.translations?.[locale]?.title
743
+ value: pageTranslation?.title
695
744
  });
696
745
  }
697
746
  if (page.description !== void 0) {
698
747
  required.push({
699
748
  path: `pages[${pageIndex}].translations.${locale}.description`,
700
- value: page.translations?.[locale]?.description
749
+ value: pageTranslation?.description
701
750
  });
702
751
  }
703
752
  });
@@ -830,8 +879,8 @@ function validatePolicy(schema, policy, issues) {
830
879
  }
831
880
  const collectedLocales = collectSchemaLocales(schema);
832
881
  const registeredLocales = /* @__PURE__ */ new Set([
833
- ...schema.defaultLocale === void 0 ? [] : [schema.defaultLocale],
834
- ...schema.supportedLocales ?? []
882
+ ...collectedLocales.defaultLocale === void 0 ? [] : [collectedLocales.defaultLocale],
883
+ ...collectedLocales.supportedLocales
835
884
  ]);
836
885
  for (const locale of collectedLocales.translationLocales) {
837
886
  if (registeredLocales.has(locale)) continue;
@@ -845,23 +894,27 @@ function validatePolicy(schema, policy, issues) {
845
894
  }
846
895
  }
847
896
  if (policy.allowedLocales !== void 0) {
897
+ const allowedLocales = new Set(policy.allowedLocales.map(canonicalLocaleOrRaw));
848
898
  const pathsByLocale = /* @__PURE__ */ new Map();
849
- if (schema.defaultLocale !== void 0) pathsByLocale.set(schema.defaultLocale, ["defaultLocale"]);
899
+ if (collectedLocales.defaultLocale !== void 0)
900
+ pathsByLocale.set(collectedLocales.defaultLocale, ["defaultLocale"]);
850
901
  schema.supportedLocales?.forEach((locale, index) => {
851
- pathsByLocale.set(locale, [...pathsByLocale.get(locale) ?? [], `supportedLocales[${index}]`]);
902
+ const canonical = canonicalLocaleOrRaw(locale);
903
+ pathsByLocale.set(canonical, [...pathsByLocale.get(canonical) ?? [], `supportedLocales[${index}]`]);
852
904
  });
853
905
  for (const [locale, paths] of collectedLocales.translationLocalePaths) {
854
906
  pathsByLocale.set(locale, [...pathsByLocale.get(locale) ?? [], ...paths]);
855
907
  }
856
908
  for (const [locale, paths] of pathsByLocale) {
857
- if (!policy.allowedLocales.includes(locale)) {
909
+ if (!allowedLocales.has(locale)) {
858
910
  for (const path of paths) {
859
911
  issue(issues, path, "disallowed_locale", `Locale ${locale} is not allowed by the form policy.`);
860
912
  }
861
913
  }
862
914
  }
863
- for (const locale of policy.requiredLocales ?? []) {
864
- if (!policy.allowedLocales.includes(locale)) {
915
+ for (const rawLocale of policy.requiredLocales ?? []) {
916
+ const locale = canonicalLocaleOrRaw(rawLocale);
917
+ if (!allowedLocales.has(locale)) {
865
918
  issue(
866
919
  issues,
867
920
  "policy.requiredLocales",
@@ -874,7 +927,8 @@ function validatePolicy(schema, policy, issues) {
874
927
  if (policy.maxLocales !== void 0 && collectedLocales.allUniqueLocales.size > policy.maxLocales) {
875
928
  issue(issues, "supportedLocales", "max_locales_exceeded", `At most ${policy.maxLocales} locales are allowed.`);
876
929
  }
877
- for (const locale of policy.requiredLocales ?? []) addRequiredTranslationIssues(schema, locale, issues);
930
+ for (const locale of policy.requiredLocales ?? [])
931
+ addRequiredTranslationIssues(schema, canonicalLocaleOrRaw(locale), issues);
878
932
  if (policy.maxSchemaBytes !== void 0) {
879
933
  try {
880
934
  const byteLength = new TextEncoder().encode(JSON.stringify(schema)).byteLength;
@@ -909,8 +963,12 @@ function validateFormSchema(input, options = {}) {
909
963
  );
910
964
  }
911
965
  }
912
- if (input.defaultLocale !== void 0 && !isNonEmptyString(input.defaultLocale)) {
913
- issue(issues, "defaultLocale", "invalid_locale", "Expected a non-empty default locale.");
966
+ if (input.defaultLocale !== void 0) {
967
+ if (!isNonEmptyString(input.defaultLocale)) {
968
+ issue(issues, "defaultLocale", "invalid_locale", "Expected a non-empty default locale.");
969
+ } else if (normalizeLocale(input.defaultLocale) === null) {
970
+ issue(issues, "defaultLocale", "invalid_locale", "Expected a valid BCP 47 locale.");
971
+ }
914
972
  }
915
973
  if (input.supportedLocales !== void 0) {
916
974
  if (!Array.isArray(input.supportedLocales) || input.supportedLocales.length === 0) {
@@ -920,10 +978,15 @@ function validateFormSchema(input, options = {}) {
920
978
  input.supportedLocales.forEach((locale, index) => {
921
979
  if (!isNonEmptyString(locale)) {
922
980
  issue(issues, `supportedLocales[${index}]`, "invalid_locale", "Expected a non-empty locale.");
923
- } else if (locales.has(locale)) {
924
- issue(issues, `supportedLocales[${index}]`, "duplicate_locale", "Locales must be unique.");
925
981
  } else {
926
- locales.add(locale);
982
+ const normalized = normalizeLocale(locale);
983
+ if (normalized === null) {
984
+ issue(issues, `supportedLocales[${index}]`, "invalid_locale", "Expected a valid BCP 47 locale.");
985
+ } else if (locales.has(normalized)) {
986
+ issue(issues, `supportedLocales[${index}]`, "duplicate_locale", "Locales must be unique.");
987
+ } else {
988
+ locales.add(normalized);
989
+ }
927
990
  }
928
991
  });
929
992
  }
@@ -1793,7 +1856,408 @@ var DEFAULT_FIELD_TYPE_DEFINITIONS = [
1793
1856
  }
1794
1857
  ];
1795
1858
 
1859
+ // src/i18n/catalogs/en.ts
1860
+ var EN_MESSAGES = Object.freeze({
1861
+ "builder.formTitle": "Form title",
1862
+ "builder.formDescription": "Form description",
1863
+ "builder.completionMessage": "Completion message",
1864
+ "builder.addQuestion": "Add question",
1865
+ "builder.actions.addField": "Add question",
1866
+ "builder.actions.deleteField": "Delete",
1867
+ "builder.actions.moveUp": "Move up",
1868
+ "builder.actions.moveDown": "Move down",
1869
+ "builder.actions.add": "Add",
1870
+ "builder.actions.delete": "Delete",
1871
+ "builder.actions.edit": "Edit",
1872
+ "builder.actions.settings": "Settings",
1873
+ "builder.actions.translate": "Translate",
1874
+ "builder.actions.close": "Close",
1875
+ "builder.actions.dragHandle": "Reorder",
1876
+ "builder.fields.selectType": "Select field type",
1877
+ "builder.fields.typeText": "Text",
1878
+ "builder.fields.typeTextarea": "Textarea",
1879
+ "builder.fields.typeNumber": "Number",
1880
+ "builder.fields.typeRadio": "Radio",
1881
+ "builder.fields.typeCheckbox": "Checkbox",
1882
+ "builder.fields.typeSelect": "Select",
1883
+ "builder.fields.typeRating": "Rating",
1884
+ "builder.fields.typeMultiSelect": "Multi-select",
1885
+ "builder.fieldType.text": "Text",
1886
+ "builder.fieldType.textarea": "Textarea",
1887
+ "builder.fieldType.number": "Number",
1888
+ "builder.fieldType.radio": "Radio",
1889
+ "builder.fieldType.checkbox": "Checkbox",
1890
+ "builder.fieldType.select": "Select",
1891
+ "builder.fieldType.rating": "Rating",
1892
+ "builder.fieldType.multi-select": "Multi-select",
1893
+ "builder.fieldTypeDescription.text": "A single-line text answer",
1894
+ "builder.fieldTypeDescription.textarea": "A long-form text answer",
1895
+ "builder.fieldTypeDescription.number": "A numeric answer",
1896
+ "builder.fieldTypeDescription.radio": "A single-choice answer",
1897
+ "builder.fieldTypeDescription.checkbox": "A yes/no answer",
1898
+ "builder.fieldTypeDescription.select": "A dropdown choice",
1899
+ "builder.fieldTypeDescription.rating": "A rating scale answer",
1900
+ "builder.fieldTypeDescription.multi-select": "Multiple choices",
1901
+ "builder.fieldCategory.text": "Text",
1902
+ "builder.fieldCategory.choice": "Choice",
1903
+ "builder.fieldCategory.number": "Number",
1904
+ "builder.fieldCategory.advanced": "Advanced",
1905
+ "builder.required": "Required",
1906
+ "builder.options": "Options",
1907
+ "builder.localization.title": "Localization",
1908
+ "builder.localization": "Localization",
1909
+ "builder.localization.addLocale": "Add locale",
1910
+ "builder.localization.selectLocaleToAdd": "Select a locale to add",
1911
+ "builder.localization.defaultLocale": "Default locale",
1912
+ "builder.localization.translateAll": "Translate all text",
1913
+ "builder.localization.noLocalesConfigured": "Translations not configured",
1914
+ "builder.localization.localesConfiguredSummary": "{{count}} locales configured",
1915
+ "builder.localization.allLocalesAdded": "All available locales have been added",
1916
+ "builder.localization.maxLocalesReached": "The maximum number of locales ({{max}}) has been reached",
1917
+ "builder.submissionSettings.title": "Submission settings",
1918
+ "builder.submissionSettings.showConfirmation": "Show confirmation before submit",
1919
+ "builder.submissionSettings.renderMode": "Confirmation display mode",
1920
+ "builder.formBuilder": "Form builder",
1921
+ "builder.basicSettings": "Basic settings",
1922
+ "builder.description": "Description",
1923
+ "builder.moveUp": "Move {{title}} up",
1924
+ "builder.moveDown": "Move {{title}} down",
1925
+ "builder.delete": "Delete {{title}}",
1926
+ "builder.deleteAction": "Delete",
1927
+ "builder.questionTitle": "Question title",
1928
+ "builder.questionTitlePlaceholder": "Example: Tell us what we could improve",
1929
+ "builder.newQuestionTitle": "New question",
1930
+ "builder.type": "Type",
1931
+ "builder.minimum": "Minimum",
1932
+ "builder.maximum": "Maximum",
1933
+ "builder.minimumLength": "Minimum length",
1934
+ "builder.maximumLength": "Maximum length",
1935
+ "builder.pattern": "Pattern",
1936
+ "builder.step": "Step",
1937
+ "builder.optionLabel": "Option label {{index}}",
1938
+ "builder.optionLabelPlaceholder": "Example: Very satisfied",
1939
+ "builder.newOptionLabel": "Option {{index}}",
1940
+ "builder.remove": "Remove",
1941
+ "builder.addOption": "Add option",
1942
+ "builder.displayCondition": "Display condition",
1943
+ "builder.alwaysVisible": "Always visible",
1944
+ "builder.conditionOperator": "Condition operator",
1945
+ "builder.conditionValue": "Condition value",
1946
+ "builder.conditionTrue": "true",
1947
+ "builder.conditionFalse": "false",
1948
+ "builder.pages": "Page manager",
1949
+ "builder.enablePages": "Enable multi-step pages",
1950
+ "builder.addPage": "Add page",
1951
+ "builder.newPage": "New page",
1952
+ "builder.pageTitle": "Page title",
1953
+ "builder.pageDescription": "Page description",
1954
+ "builder.pageQuestion": "Question to move to the new page",
1955
+ "builder.questionPage": "Page",
1956
+ "builder.pageCondition": "Page display condition",
1957
+ "builder.unassigned": "Unassigned",
1958
+ "builder.defaultLocale": "Default locale",
1959
+ "builder.supportedLocales": "Supported locales",
1960
+ "builder.addLocale": "Add locale",
1961
+ "builder.editLocale": "Edit locale",
1962
+ "builder.autoTranslate": "Translate all text",
1963
+ "builder.translating": "Translating\u2026",
1964
+ "builder.translationLocale": "Translation locale",
1965
+ "builder.selectLocale": "Select a locale to edit translations.",
1966
+ "builder.selectLocaleToAdd": "Select a locale to add",
1967
+ "builder.translation": "{{locale}} translation",
1968
+ "builder.translatedFormTitle": "Translated form title",
1969
+ "builder.translatedFormDescription": "Translated form description",
1970
+ "builder.translatedCompletionMessage": "Translated completion message",
1971
+ "builder.translatedQuestionTitle": "Translated question title",
1972
+ "builder.translatedDescription": "Translated description",
1973
+ "builder.translationUnavailable": "Provide an async translation adapter to enable automatic translation.",
1974
+ "builder.operator.equals": "equals",
1975
+ "builder.operator.not_equals": "does not equal",
1976
+ "builder.operator.contains": "contains",
1977
+ "builder.operator.not_empty": "is not empty",
1978
+ "builder.showConfirmationBeforeSubmit": "Show confirmation before submit",
1979
+ "builder.confirmationRenderMode": "Confirmation display mode",
1980
+ "renderer.submitButton": "Submit",
1981
+ "renderer.submittingButton": "Submitting...",
1982
+ "renderer.retryButton": "Retry",
1983
+ "renderer.requiredField": "This field is required.",
1984
+ "renderer.alreadySubmittedTitle": "Already Submitted",
1985
+ "renderer.alreadySubmittedMessage": "Already submitted.",
1986
+ "renderer.serverErrorSummary": "Submission failed. Please check your answers and try again.",
1987
+ "renderer.confirmSensitiveDataTitle": "Sensitive data may be included",
1988
+ "renderer.confirmSensitiveDataMessage": "The following answers may contain personal information. Continue submitting?",
1989
+ "renderer.confirmButton": "Proceed",
1990
+ "renderer.cancelButton": "Cancel",
1991
+ "form.submit": "Submit",
1992
+ "form.submitting": "Submitting...",
1993
+ "form.back": "Back",
1994
+ "form.next": "Next",
1995
+ "form.step": "{{current}} / {{total}}",
1996
+ "form.draftRestored": "Draft restored",
1997
+ "form.submissionBlocked": "Submission blocked because personal information was detected.",
1998
+ "form.confirmSensitiveData": "Sensitive data may be included. Please review before submitting.",
1999
+ "form.confirmSubmission": "Proceed",
2000
+ "form.cancelSubmission": "Cancel",
2001
+ "form.yes": "Yes",
2002
+ "form.no": "No",
2003
+ "form.alreadySubmitted": "Already submitted.",
2004
+ "form.submitAnother": "Submit another response",
2005
+ "validation.required": "This field is required.",
2006
+ "validation.invalidOption": "Select a valid option.",
2007
+ "validation.invalidType": "Enter a valid value.",
2008
+ "validation.max": "Value is too large.",
2009
+ "validation.maxLength": "Value is too long.",
2010
+ "validation.maxSelections": "Select fewer options.",
2011
+ "validation.min": "Value is too small.",
2012
+ "validation.minLength": "Value is too short.",
2013
+ "validation.minSelections": "Select more options.",
2014
+ "validation.pattern": "Value has an invalid format.",
2015
+ "validation.sensitiveData": "Sensitive data may be included.",
2016
+ "validation.step": "Enter a value with the correct step.",
2017
+ "validation.unknownField": "This field is not recognized.",
2018
+ "workspace.title": "Translation workspace",
2019
+ "workspace.status.missing": "Missing",
2020
+ "workspace.status.translated": "Translated",
2021
+ "workspace.status.stale": "Source changed",
2022
+ "workspace.status.manual": "Manual",
2023
+ "workspace.status.manualStale": "Manual / source changed",
2024
+ "workspace.errors.localeNotAllowed": "Locale {{locale}} is not allowed.",
2025
+ "workspace.errors.maxLocalesExceeded": "The maximum number of locales ({{max}}) has been reached.",
2026
+ "workspace.errors.readOnly": "This workspace is read-only.",
2027
+ "workspace.errors.adapterNotConfigured": "A translation adapter is not configured.",
2028
+ "workspace.errors.translationFailed": "Translation failed."
2029
+ });
2030
+
2031
+ // src/i18n/catalogs/ja.ts
2032
+ var JA_MESSAGES = Object.freeze({
2033
+ "builder.formTitle": "\u30D5\u30A9\u30FC\u30E0\u306E\u30BF\u30A4\u30C8\u30EB",
2034
+ "builder.formDescription": "\u30D5\u30A9\u30FC\u30E0\u306E\u8AAC\u660E",
2035
+ "builder.completionMessage": "\u9001\u4FE1\u5B8C\u4E86\u30E1\u30C3\u30BB\u30FC\u30B8",
2036
+ "builder.addQuestion": "\u8CEA\u554F\u3092\u8FFD\u52A0",
2037
+ "builder.actions.addField": "\u8CEA\u554F\u3092\u8FFD\u52A0",
2038
+ "builder.actions.deleteField": "\u524A\u9664",
2039
+ "builder.actions.moveUp": "\u4E0A\u3078\u79FB\u52D5",
2040
+ "builder.actions.moveDown": "\u4E0B\u3078\u79FB\u52D5",
2041
+ "builder.actions.add": "\u8FFD\u52A0",
2042
+ "builder.actions.delete": "\u524A\u9664",
2043
+ "builder.actions.edit": "\u7DE8\u96C6",
2044
+ "builder.actions.settings": "\u8A2D\u5B9A",
2045
+ "builder.actions.translate": "\u7FFB\u8A33",
2046
+ "builder.actions.close": "\u9589\u3058\u308B",
2047
+ "builder.actions.dragHandle": "\u4E26\u3079\u66FF\u3048",
2048
+ "builder.fields.selectType": "\u8CEA\u554F\u5F62\u5F0F\u3092\u9078\u629E",
2049
+ "builder.fields.typeText": "\u4E00\u884C\u30C6\u30AD\u30B9\u30C8",
2050
+ "builder.fields.typeTextarea": "\u9577\u6587\u30C6\u30AD\u30B9\u30C8",
2051
+ "builder.fields.typeNumber": "\u6570\u5024",
2052
+ "builder.fields.typeRadio": "\u5358\u4E00\u9078\u629E (\u30E9\u30B8\u30AA\u30DC\u30BF\u30F3)",
2053
+ "builder.fields.typeCheckbox": "\u30C1\u30A7\u30C3\u30AF\u30DC\u30C3\u30AF\u30B9",
2054
+ "builder.fields.typeSelect": "\u30C9\u30ED\u30C3\u30D7\u30C0\u30A6\u30F3",
2055
+ "builder.fields.typeRating": "\u8A55\u4FA1\u30B9\u30B1\u30FC\u30EB",
2056
+ "builder.fields.typeMultiSelect": "\u8907\u6570\u9078\u629E",
2057
+ "builder.fieldType.text": "\u4E00\u884C\u30C6\u30AD\u30B9\u30C8",
2058
+ "builder.fieldType.textarea": "\u9577\u6587\u30C6\u30AD\u30B9\u30C8",
2059
+ "builder.fieldType.number": "\u6570\u5024",
2060
+ "builder.fieldType.radio": "\u5358\u4E00\u9078\u629E",
2061
+ "builder.fieldType.checkbox": "\u30C1\u30A7\u30C3\u30AF\u30DC\u30C3\u30AF\u30B9",
2062
+ "builder.fieldType.select": "\u30C9\u30ED\u30C3\u30D7\u30C0\u30A6\u30F3",
2063
+ "builder.fieldType.rating": "\u8A55\u4FA1\u30B9\u30B1\u30FC\u30EB",
2064
+ "builder.fieldType.multi-select": "\u8907\u6570\u9078\u629E",
2065
+ "builder.fieldTypeDescription.text": "\u4E00\u884C\u306E\u56DE\u7B54",
2066
+ "builder.fieldTypeDescription.textarea": "\u9577\u6587\u306E\u56DE\u7B54",
2067
+ "builder.fieldTypeDescription.number": "\u6570\u5024\u306E\u56DE\u7B54",
2068
+ "builder.fieldTypeDescription.radio": "\u5358\u4E00\u9078\u629E\u306E\u56DE\u7B54",
2069
+ "builder.fieldTypeDescription.checkbox": "\u306F\u3044 / \u3044\u3044\u3048\u306E\u56DE\u7B54",
2070
+ "builder.fieldTypeDescription.select": "\u30C9\u30ED\u30C3\u30D7\u30C0\u30A6\u30F3\u5F62\u5F0F\u306E\u56DE\u7B54",
2071
+ "builder.fieldTypeDescription.rating": "\u8A55\u4FA1\u30B9\u30B1\u30FC\u30EB\u306E\u56DE\u7B54",
2072
+ "builder.fieldTypeDescription.multi-select": "\u8907\u6570\u9078\u629E\u306E\u56DE\u7B54",
2073
+ "builder.fieldCategory.text": "\u30C6\u30AD\u30B9\u30C8",
2074
+ "builder.fieldCategory.choice": "\u9078\u629E\u5F0F",
2075
+ "builder.fieldCategory.number": "\u6570\u5024",
2076
+ "builder.fieldCategory.advanced": "\u8A73\u7D30\u8A2D\u5B9A",
2077
+ "builder.required": "\u5FC5\u9808\u9805\u76EE\u306B\u3059\u308B",
2078
+ "builder.options": "\u9078\u629E\u80A2\u4E00\u89A7",
2079
+ "builder.localization.title": "\u591A\u8A00\u8A9E\u8A2D\u5B9A",
2080
+ "builder.localization": "\u591A\u8A00\u8A9E\u8A2D\u5B9A",
2081
+ "builder.localization.addLocale": "\u8A00\u8A9E\u3092\u8FFD\u52A0",
2082
+ "builder.localization.selectLocaleToAdd": "\u8FFD\u52A0\u3059\u308B\u8A00\u8A9E\u3092\u9078\u629E",
2083
+ "builder.localization.defaultLocale": "\u30C7\u30D5\u30A9\u30EB\u30C8\u8A00\u8A9E (\u5143\u8A00\u8A9E)",
2084
+ "builder.localization.translateAll": "\u4E00\u62EC\u81EA\u52D5\u7FFB\u8A33",
2085
+ "builder.localization.noLocalesConfigured": "\u7FFB\u8A33\u8A00\u8A9E\u306F\u307E\u3060\u8A2D\u5B9A\u3055\u308C\u3066\u3044\u307E\u305B\u3093\u3002",
2086
+ "builder.localization.localesConfiguredSummary": "{{count}}\u8A00\u8A9E\u306E\u7FFB\u8A33\u304C\u8A2D\u5B9A\u3055\u308C\u3066\u3044\u307E\u3059\u3002",
2087
+ "builder.localization.allLocalesAdded": "\u3059\u3079\u3066\u306E\u5019\u88DC\u8A00\u8A9E\u304C\u8FFD\u52A0\u6E08\u307F\u3067\u3059",
2088
+ "builder.localization.maxLocalesReached": "\u767B\u9332\u53EF\u80FD\u306A\u6700\u5927\u8A00\u8A9E\u6570 ({{max}}) \u306B\u9054\u3057\u307E\u3057\u305F",
2089
+ "builder.submissionSettings.title": "\u9001\u4FE1\u8A2D\u5B9A",
2090
+ "builder.submissionSettings.showConfirmation": "\u9001\u4FE1\u524D\u306B\u56DE\u7B54\u78BA\u8A8D\u753B\u9762\u3092\u8868\u793A\u3059\u308B",
2091
+ "builder.submissionSettings.renderMode": "\u78BA\u8A8D\u753B\u9762\u306E\u8868\u793A\u5F62\u5F0F",
2092
+ "builder.formBuilder": "\u30D5\u30A9\u30FC\u30E0\u30D3\u30EB\u30C0\u30FC",
2093
+ "builder.basicSettings": "\u57FA\u672C\u8A2D\u5B9A",
2094
+ "builder.description": "\u8AAC\u660E",
2095
+ "builder.moveUp": "{{title}}\u3092\u4E0A\u3078\u79FB\u52D5",
2096
+ "builder.moveDown": "{{title}}\u3092\u4E0B\u3078\u79FB\u52D5",
2097
+ "builder.delete": "{{title}}\u3092\u524A\u9664",
2098
+ "builder.deleteAction": "\u524A\u9664",
2099
+ "builder.questionTitle": "\u8CEA\u554F\u6587",
2100
+ "builder.questionTitlePlaceholder": "\u4F8B: \u6539\u5584\u3067\u304D\u308B\u70B9\u3092\u6559\u3048\u3066\u304F\u3060\u3055\u3044",
2101
+ "builder.newQuestionTitle": "\u65B0\u3057\u3044\u8CEA\u554F",
2102
+ "builder.type": "\u5F62\u5F0F",
2103
+ "builder.minimum": "\u6700\u5C0F\u5024",
2104
+ "builder.maximum": "\u6700\u5927\u5024",
2105
+ "builder.minimumLength": "\u6700\u5C0F\u6587\u5B57\u6570",
2106
+ "builder.maximumLength": "\u6700\u5927\u6587\u5B57\u6570",
2107
+ "builder.pattern": "\u5F62\u5F0F\u30D1\u30BF\u30FC\u30F3",
2108
+ "builder.step": "\u523B\u307F\u5E45",
2109
+ "builder.optionLabel": "\u9078\u629E\u80A2 {{index}}",
2110
+ "builder.optionLabelPlaceholder": "\u4F8B: \u3068\u3066\u3082\u6E80\u8DB3",
2111
+ "builder.newOptionLabel": "\u9078\u629E\u80A2 {{index}}",
2112
+ "builder.remove": "\u524A\u9664",
2113
+ "builder.addOption": "\u9078\u629E\u80A2\u3092\u8FFD\u52A0",
2114
+ "builder.displayCondition": "\u8868\u793A\u6761\u4EF6",
2115
+ "builder.alwaysVisible": "\u5E38\u306B\u8868\u793A",
2116
+ "builder.conditionOperator": "\u6761\u4EF6\u6F14\u7B97\u5B50",
2117
+ "builder.conditionValue": "\u6761\u4EF6\u5024",
2118
+ "builder.conditionTrue": "\u306F\u3044",
2119
+ "builder.conditionFalse": "\u3044\u3044\u3048",
2120
+ "builder.pages": "\u30DA\u30FC\u30B8\u7BA1\u7406",
2121
+ "builder.enablePages": "\u8907\u6570\u30DA\u30FC\u30B8\u3092\u6709\u52B9\u306B\u3059\u308B",
2122
+ "builder.addPage": "\u30DA\u30FC\u30B8\u3092\u8FFD\u52A0",
2123
+ "builder.newPage": "\u65B0\u3057\u3044\u30DA\u30FC\u30B8",
2124
+ "builder.pageTitle": "\u30DA\u30FC\u30B8\u30BF\u30A4\u30C8\u30EB",
2125
+ "builder.pageDescription": "\u30DA\u30FC\u30B8\u306E\u8AAC\u660E",
2126
+ "builder.pageQuestion": "\u65B0\u3057\u3044\u30DA\u30FC\u30B8\u3078\u79FB\u52D5\u3059\u308B\u8CEA\u554F",
2127
+ "builder.questionPage": "\u30DA\u30FC\u30B8",
2128
+ "builder.pageCondition": "\u30DA\u30FC\u30B8\u306E\u8868\u793A\u6761\u4EF6",
2129
+ "builder.unassigned": "\u672A\u5272\u308A\u5F53\u3066",
2130
+ "builder.defaultLocale": "\u30C7\u30D5\u30A9\u30EB\u30C8\u8A00\u8A9E",
2131
+ "builder.supportedLocales": "\u5BFE\u5FDC\u8A00\u8A9E",
2132
+ "builder.addLocale": "\u8A00\u8A9E\u3092\u8FFD\u52A0",
2133
+ "builder.editLocale": "\u8A00\u8A9E\u3092\u7DE8\u96C6",
2134
+ "builder.autoTranslate": "\u3059\u3079\u3066\u7FFB\u8A33",
2135
+ "builder.translating": "\u7FFB\u8A33\u4E2D\u2026",
2136
+ "builder.translationLocale": "\u7FFB\u8A33\u8A00\u8A9E",
2137
+ "builder.selectLocale": "\u7FFB\u8A33\u3092\u7DE8\u96C6\u3059\u308B\u8A00\u8A9E\u3092\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
2138
+ "builder.selectLocaleToAdd": "\u8FFD\u52A0\u3059\u308B\u8A00\u8A9E\u3092\u9078\u629E",
2139
+ "builder.translation": "{{locale}}\u7FFB\u8A33",
2140
+ "builder.translatedFormTitle": "\u7FFB\u8A33\u5F8C\u306E\u30D5\u30A9\u30FC\u30E0\u30BF\u30A4\u30C8\u30EB",
2141
+ "builder.translatedFormDescription": "\u7FFB\u8A33\u5F8C\u306E\u30D5\u30A9\u30FC\u30E0\u8AAC\u660E",
2142
+ "builder.translatedCompletionMessage": "\u7FFB\u8A33\u5F8C\u306E\u9001\u4FE1\u5B8C\u4E86\u30E1\u30C3\u30BB\u30FC\u30B8",
2143
+ "builder.translatedQuestionTitle": "\u7FFB\u8A33\u5F8C\u306E\u8CEA\u554F\u6587",
2144
+ "builder.translatedDescription": "\u7FFB\u8A33\u5F8C\u306E\u8AAC\u660E",
2145
+ "builder.translationUnavailable": "\u81EA\u52D5\u7FFB\u8A33\u306B\u306F\u975E\u540C\u671F\u7FFB\u8A33\u30A2\u30C0\u30D7\u30BF\u30FC\u3092\u8A2D\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
2146
+ "builder.operator.equals": "\u7B49\u3057\u3044",
2147
+ "builder.operator.not_equals": "\u7B49\u3057\u304F\u306A\u3044",
2148
+ "builder.operator.contains": "\u542B\u3080",
2149
+ "builder.operator.not_empty": "\u7A7A\u3067\u306F\u306A\u3044",
2150
+ "builder.showConfirmationBeforeSubmit": "\u9001\u4FE1\u524D\u306B\u78BA\u8A8D\u753B\u9762\u3092\u8868\u793A\u3059\u308B",
2151
+ "builder.confirmationRenderMode": "\u78BA\u8A8D\u753B\u9762\u306E\u8868\u793A\u5F62\u5F0F",
2152
+ "renderer.submitButton": "\u9001\u4FE1\u3059\u308B",
2153
+ "renderer.submittingButton": "\u9001\u4FE1\u4E2D...",
2154
+ "renderer.retryButton": "\u518D\u9001\u4FE1\u3059\u308B",
2155
+ "renderer.requiredField": "\u3053\u306E\u9805\u76EE\u306F\u5FC5\u9808\u3067\u3059\u3002",
2156
+ "renderer.alreadySubmittedTitle": "\u56DE\u7B54\u6E08\u307F\u3067\u3059",
2157
+ "renderer.alreadySubmittedMessage": "\u3053\u306E\u30A2\u30F3\u30B1\u30FC\u30C8\u306B\u306F\u3059\u3067\u306B\u56DE\u7B54\u3057\u3066\u3044\u307E\u3059\u3002",
2158
+ "renderer.serverErrorSummary": "\u9001\u4FE1\u306B\u5931\u6557\u3057\u307E\u3057\u305F\u3002\u5185\u5BB9\u3092\u3054\u78BA\u8A8D\u306E\u4E0A\u3001\u518D\u5EA6\u304A\u8A66\u3057\u304F\u3060\u3055\u3044\u3002",
2159
+ "renderer.confirmSensitiveDataTitle": "\u500B\u4EBA\u60C5\u5831\u304C\u542B\u307E\u308C\u3066\u3044\u308B\u53EF\u80FD\u6027\u304C\u3042\u308A\u307E\u3059",
2160
+ "renderer.confirmSensitiveDataMessage": "\u4EE5\u4E0B\u306E\u9805\u76EE\u306B\u500B\u4EBA\u60C5\u5831\u3068\u307F\u3089\u308C\u308B\u8A18\u8FF0\u304C\u3042\u308A\u307E\u3059\u3002\u3053\u306E\u307E\u307E\u9001\u4FE1\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B\uFF1F",
2161
+ "renderer.confirmButton": "\u3053\u306E\u307E\u307E\u9001\u4FE1",
2162
+ "renderer.cancelButton": "\u4FEE\u6B63\u3059\u308B",
2163
+ "form.submit": "\u9001\u4FE1\u3059\u308B",
2164
+ "form.submitting": "\u9001\u4FE1\u4E2D...",
2165
+ "form.back": "\u623B\u308B",
2166
+ "form.next": "\u6B21\u3078",
2167
+ "form.step": "{{current}} / {{total}}",
2168
+ "form.draftRestored": "\u4E0B\u66F8\u304D\u3092\u5FA9\u5143\u3057\u307E\u3057\u305F",
2169
+ "form.submissionBlocked": "\u500B\u4EBA\u60C5\u5831\u304C\u691C\u51FA\u3055\u308C\u305F\u305F\u3081\u9001\u4FE1\u3067\u304D\u307E\u305B\u3093\u3002",
2170
+ "form.confirmSensitiveData": "\u500B\u4EBA\u60C5\u5831\u304C\u542B\u307E\u308C\u3066\u3044\u308B\u53EF\u80FD\u6027\u304C\u3042\u308A\u307E\u3059\u3002\u9001\u4FE1\u524D\u306B\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
2171
+ "form.confirmSubmission": "\u3053\u306E\u307E\u307E\u9001\u4FE1",
2172
+ "form.cancelSubmission": "\u4FEE\u6B63\u3059\u308B",
2173
+ "form.yes": "\u306F\u3044",
2174
+ "form.no": "\u3044\u3044\u3048",
2175
+ "form.alreadySubmitted": "\u56DE\u7B54\u6E08\u307F\u3067\u3059",
2176
+ "form.submitAnother": "\u5225\u306E\u56DE\u7B54\u3092\u9001\u4FE1",
2177
+ "validation.required": "\u3053\u306E\u9805\u76EE\u306F\u5FC5\u9808\u3067\u3059\u3002",
2178
+ "validation.invalidOption": "\u6709\u52B9\u306A\u9078\u629E\u80A2\u3092\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
2179
+ "validation.invalidType": "\u6709\u52B9\u306A\u5024\u3092\u5165\u529B\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
2180
+ "validation.max": "\u5024\u304C\u5927\u304D\u3059\u304E\u307E\u3059\u3002",
2181
+ "validation.maxLength": "\u5165\u529B\u304C\u9577\u3059\u304E\u307E\u3059\u3002",
2182
+ "validation.maxSelections": "\u9078\u629E\u6570\u3092\u6E1B\u3089\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
2183
+ "validation.min": "\u5024\u304C\u5C0F\u3055\u3059\u304E\u307E\u3059\u3002",
2184
+ "validation.minLength": "\u5165\u529B\u304C\u77ED\u3059\u304E\u307E\u3059\u3002",
2185
+ "validation.minSelections": "\u3055\u3089\u306B\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
2186
+ "validation.pattern": "\u5165\u529B\u5F62\u5F0F\u304C\u6B63\u3057\u304F\u3042\u308A\u307E\u305B\u3093\u3002",
2187
+ "validation.sensitiveData": "\u500B\u4EBA\u60C5\u5831\u304C\u542B\u307E\u308C\u3066\u3044\u308B\u53EF\u80FD\u6027\u304C\u3042\u308A\u307E\u3059\u3002",
2188
+ "validation.step": "\u6B63\u3057\u3044\u523B\u307F\u5E45\u306E\u5024\u3092\u5165\u529B\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
2189
+ "validation.unknownField": "\u3053\u306E\u9805\u76EE\u306F\u8A8D\u8B58\u3055\u308C\u307E\u305B\u3093\u3002",
2190
+ "workspace.title": "\u591A\u8A00\u8A9E\u7FFB\u8A33\u30EF\u30FC\u30AF\u30B9\u30DA\u30FC\u30B9",
2191
+ "workspace.status.missing": "\u672A\u7FFB\u8A33",
2192
+ "workspace.status.translated": "\u7FFB\u8A33\u6E08\u307F",
2193
+ "workspace.status.stale": "\u539F\u6587\u66F4\u65B0\u3042\u308A",
2194
+ "workspace.status.manual": "\u624B\u52D5\u7DE8\u96C6\u6E08\u307F",
2195
+ "workspace.status.manualStale": "\u624B\u52D5\u7DE8\u96C6\u6E08\u307F (\u539F\u6587\u66F4\u65B0\u3042\u308A)",
2196
+ "workspace.errors.localeNotAllowed": "\u6307\u5B9A\u3055\u308C\u305F\u8A00\u8A9E\u300C{{locale}}\u300D\u306F\u8A2D\u5B9A\u3067\u304D\u307E\u305B\u3093\u3002",
2197
+ "workspace.errors.maxLocalesExceeded": "\u767B\u9332\u53EF\u80FD\u306A\u6700\u5927\u8A00\u8A9E\u6570 ({{max}}) \u306B\u9054\u3057\u307E\u3057\u305F\u3002",
2198
+ "workspace.errors.readOnly": "\u8AAD\u307F\u53D6\u308A\u5C02\u7528\u30E2\u30FC\u30C9\u306E\u305F\u3081\u5909\u66F4\u3067\u304D\u307E\u305B\u3093\u3002",
2199
+ "workspace.errors.adapterNotConfigured": "\u7FFB\u8A33\u30A2\u30C0\u30D7\u30BF\u30FC\u304C\u8A2D\u5B9A\u3055\u308C\u3066\u3044\u307E\u305B\u3093\u3002",
2200
+ "workspace.errors.translationFailed": "\u7FFB\u8A33\u51E6\u7406\u306B\u5931\u6557\u3057\u307E\u3057\u305F\u3002"
2201
+ });
2202
+
2203
+ // src/i18n/translator.ts
2204
+ function formatTemplate(template, params = {}) {
2205
+ return template.replace(
2206
+ /\{\{?(\w+)\}\}?/gu,
2207
+ (token, name) => Object.hasOwn(params, name) ? String(params[name]) : token
2208
+ );
2209
+ }
2210
+ function defaultCatalog(locale) {
2211
+ return locale.toLowerCase().startsWith("ja") ? JA_MESSAGES : EN_MESSAGES;
2212
+ }
2213
+ var createFormEngineTranslator = (options = {}) => {
2214
+ const { locale = "ja", fallbackLocale = "en", messages = {}, customCatalogs = {}, fallbackTextResolver } = options;
2215
+ const currentCatalog = { ...defaultCatalog(locale), ...customCatalogs[locale], ...messages };
2216
+ const fallbackCatalog = { ...defaultCatalog(fallbackLocale), ...customCatalogs[fallbackLocale] };
2217
+ return (rawKey, params = {}) => {
2218
+ const key = rawKey;
2219
+ const template = currentCatalog[key] ?? fallbackCatalog[key];
2220
+ if (template !== void 0 && template !== "") return formatTemplate(template, params);
2221
+ if (fallbackTextResolver !== void 0) return fallbackTextResolver(key, locale);
2222
+ return "";
2223
+ };
2224
+ };
2225
+
1796
2226
  // src/pagination.ts
2227
+ async function paginateWithFilter(params) {
2228
+ const { pageSize, cursor, maxScanPages = 5, fetchPage, filterPredicate, encodeCursor } = params;
2229
+ normalizeSubmissionPageSize(pageSize);
2230
+ if (!Number.isSafeInteger(maxScanPages) || maxScanPages < 1) {
2231
+ throw new TypeError("maxScanPages must be a positive safe integer.");
2232
+ }
2233
+ const collected = [];
2234
+ let currentRawCursor = cursor;
2235
+ let totalScannedCount = 0;
2236
+ let scanCount = 0;
2237
+ while (collected.length < pageSize && scanCount < maxScanPages) {
2238
+ scanCount += 1;
2239
+ const fetchLimit = pageSize - collected.length + 1;
2240
+ const { rawItems, rawNextCursor } = await fetchPage(currentRawCursor, fetchLimit);
2241
+ totalScannedCount += rawItems.length;
2242
+ for (const item of rawItems) {
2243
+ if (!filterPredicate(item)) continue;
2244
+ collected.push(item);
2245
+ if (collected.length === pageSize) {
2246
+ const lastItem = collected.at(-1);
2247
+ if (lastItem === void 0) break;
2248
+ return {
2249
+ items: collected,
2250
+ hasMore: rawNextCursor !== void 0,
2251
+ ...rawNextCursor === void 0 ? {} : { nextCursor: encodeCursor(lastItem) },
2252
+ totalScannedCount
2253
+ };
2254
+ }
2255
+ }
2256
+ if (rawItems.length === 0 || rawNextCursor === void 0) break;
2257
+ currentRawCursor = rawNextCursor;
2258
+ }
2259
+ return { items: collected, hasMore: false, totalScannedCount };
2260
+ }
1797
2261
  function asFormResponse2(submission) {
1798
2262
  return {
1799
2263
  responseId: submission.id,
@@ -1842,6 +2306,43 @@ async function* iterateSubmissionPages(adapter, formId, queryOptions = {}, optio
1842
2306
  cursor = nextCursor;
1843
2307
  }
1844
2308
  }
2309
+ function encodeStorageSubmissionCursor(value) {
2310
+ if (value.kind !== "submission" || value.formId.length === 0 || value.submittedAt.length === 0 || value.id.length === 0) {
2311
+ throw new TypeError("Submission cursor values are invalid.");
2312
+ }
2313
+ return encodeBase64Url(new TextEncoder().encode(JSON.stringify(value)));
2314
+ }
2315
+ function decodeStorageSubmissionCursor(cursor) {
2316
+ const parsed = decodeCursorPayload(cursor, "submission cursor payload is invalid.");
2317
+ if (parsed.kind !== "submission" || typeof parsed.formId !== "string" || parsed.formId.length === 0 || typeof parsed.submittedAt !== "string" || parsed.submittedAt.length === 0 || typeof parsed.id !== "string" || parsed.id.length === 0) {
2318
+ throw new TypeError("submission cursor payload is invalid.");
2319
+ }
2320
+ return {
2321
+ kind: "submission",
2322
+ formId: parsed.formId,
2323
+ submittedAt: parsed.submittedAt,
2324
+ id: parsed.id
2325
+ };
2326
+ }
2327
+ function encodeStorageTextAnswerCursor(value) {
2328
+ if (value.kind !== "text_answer" || value.formId.length === 0 || value.fieldId.length === 0 || value.submittedAt.length === 0 || value.submissionId.length === 0) {
2329
+ throw new TypeError("Text answer cursor values are invalid.");
2330
+ }
2331
+ return encodeBase64Url(new TextEncoder().encode(JSON.stringify(value)));
2332
+ }
2333
+ function decodeStorageTextAnswerCursor(cursor) {
2334
+ const parsed = decodeCursorPayload(cursor, "text answer cursor payload is invalid.");
2335
+ if (parsed.kind !== "text_answer" || typeof parsed.formId !== "string" || parsed.formId.length === 0 || typeof parsed.fieldId !== "string" || parsed.fieldId.length === 0 || typeof parsed.submittedAt !== "string" || parsed.submittedAt.length === 0 || typeof parsed.submissionId !== "string" || parsed.submissionId.length === 0) {
2336
+ throw new TypeError("text answer cursor payload is invalid.");
2337
+ }
2338
+ return {
2339
+ kind: "text_answer",
2340
+ formId: parsed.formId,
2341
+ fieldId: parsed.fieldId,
2342
+ submittedAt: parsed.submittedAt,
2343
+ submissionId: parsed.submissionId
2344
+ };
2345
+ }
1845
2346
  var BASE64_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
1846
2347
  function encodeBase64(bytes) {
1847
2348
  let result = "";
@@ -1872,6 +2373,20 @@ function decodeBase64(value) {
1872
2373
  }
1873
2374
  return new Uint8Array(bytes);
1874
2375
  }
2376
+ function encodeBase64Url(bytes) {
2377
+ return encodeBase64(bytes).replaceAll("+", "-").replaceAll("/", "_").replace(/=+$/u, "");
2378
+ }
2379
+ function decodeCursorPayload(cursor, invalidMessage) {
2380
+ try {
2381
+ const normalized = cursor.replaceAll("-", "+").replaceAll("_", "/").padEnd(Math.ceil(cursor.length / 4) * 4, "=");
2382
+ const parsed = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(decodeBase64(normalized)));
2383
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) throw new TypeError(invalidMessage);
2384
+ return parsed;
2385
+ } catch (cause) {
2386
+ if (cause instanceof TypeError && cause.message === invalidMessage) throw cause;
2387
+ throw new TypeError("cursor must be a valid Base64URL JSON token.", { cause });
2388
+ }
2389
+ }
1875
2390
  function encodeSubmissionCursor(value) {
1876
2391
  if (value.submittedAt.length === 0 || value.responseId.length === 0) {
1877
2392
  throw new TypeError("Cursor values must not be empty.");
@@ -2109,6 +2624,28 @@ function validatePageAnswers(schema, pageIndex, values) {
2109
2624
  }
2110
2625
  return issues.length === 0 ? { valid: true, issues: [] } : { valid: false, issues };
2111
2626
  }
2627
+ function validateSubmission(schema, submission, options) {
2628
+ const values = submission.values;
2629
+ const answerValidation = validateAnswers(schema, values);
2630
+ const fieldErrors = {};
2631
+ for (const issue2 of answerValidation.issues) {
2632
+ const existing = fieldErrors[issue2.fieldId];
2633
+ fieldErrors[issue2.fieldId] = existing === void 0 ? issue2.messageKey : `${existing}; ${issue2.messageKey}`;
2634
+ }
2635
+ const piiFindings = options?.privacyEngine?.detect(schema, { ...values });
2636
+ if (piiFindings !== void 0) {
2637
+ for (const finding of piiFindings) {
2638
+ const existing = fieldErrors[finding.fieldId];
2639
+ fieldErrors[finding.fieldId] = existing === void 0 ? "validation.sensitiveData" : `${existing}; validation.sensitiveData`;
2640
+ }
2641
+ }
2642
+ return {
2643
+ valid: Object.keys(fieldErrors).length === 0,
2644
+ fieldErrors,
2645
+ formErrors: [],
2646
+ ...piiFindings === void 0 ? {} : { piiFindings }
2647
+ };
2648
+ }
2112
2649
 
2113
2650
  // src/submission.ts
2114
2651
  function cloneValues(values) {
@@ -2116,7 +2653,46 @@ function cloneValues(values) {
2116
2653
  Object.entries(values).map(([key, value]) => [key, Array.isArray(value) ? Object.freeze([...value]) : value])
2117
2654
  );
2118
2655
  }
2119
- function createSubmission(schema, values, options) {
2656
+ function generatedSubmissionId() {
2657
+ return globalThis.crypto?.randomUUID?.() ?? `${Date.now()}-${Math.random().toString(36).slice(2)}`;
2658
+ }
2659
+ function toFormValues(answers) {
2660
+ const values = {};
2661
+ for (const [key, value] of Object.entries(answers)) {
2662
+ if (isFormValue(value)) values[key] = value;
2663
+ }
2664
+ return values;
2665
+ }
2666
+ function isFormValue(value) {
2667
+ return value === void 0 || typeof value === "string" || typeof value === "number" || typeof value === "boolean" || Array.isArray(value) && value.every((item) => typeof item === "string");
2668
+ }
2669
+ function createSubmission(schemaOrInput, values, options) {
2670
+ if ("answers" in schemaOrInput) {
2671
+ const input = schemaOrInput;
2672
+ const id = input.id ?? generatedSubmissionId();
2673
+ if (input.formId.trim().length === 0) throw new TypeError("formId must not be empty.");
2674
+ if (!Number.isSafeInteger(input.formVersion) || input.formVersion < 1) {
2675
+ throw new TypeError("formVersion must be a positive safe integer.");
2676
+ }
2677
+ const submittedAt = input.submittedAt ?? (/* @__PURE__ */ new Date()).toISOString();
2678
+ if (submittedAt.trim().length === 0 || !Number.isFinite(Date.parse(submittedAt))) {
2679
+ throw new TypeError("submittedAt must be a valid date string.");
2680
+ }
2681
+ const answers = Object.freeze({ ...input.answers });
2682
+ return Object.freeze({
2683
+ id,
2684
+ formId: input.formId,
2685
+ formVersion: input.formVersion,
2686
+ locale: "",
2687
+ values: Object.freeze(cloneValues(toFormValues(answers))),
2688
+ answers,
2689
+ metadata: input.metadata,
2690
+ submittedAt,
2691
+ ...input.schemaRevision === void 0 ? {} : { schemaRevision: input.schemaRevision }
2692
+ });
2693
+ }
2694
+ const schema = schemaOrInput;
2695
+ if (values === void 0 || options === void 0) throw new TypeError("values and options are required.");
2120
2696
  assertValidFormSchema(schema);
2121
2697
  if (options.id.trim().length === 0) throw new TypeError("Submission ID must not be empty.");
2122
2698
  if (options.locale.trim().length === 0) throw new TypeError("Submission locale must not be empty.");
@@ -2136,6 +2712,7 @@ function createSubmission(schema, values, options) {
2136
2712
  formVersion: schema.version,
2137
2713
  locale: options.locale,
2138
2714
  values: Object.freeze(cloneValues(visibleValues)),
2715
+ answers: Object.freeze({ ...visibleValues }),
2139
2716
  submittedAt: options.submittedAt,
2140
2717
  ...options.metadata === void 0 ? {} : { metadata: Object.freeze({ ...options.metadata }) },
2141
2718
  ...options.translationMetadata === void 0 ? {} : { translationMetadata: Object.freeze({ ...options.translationMetadata }) }
@@ -2192,8 +2769,15 @@ function withTranslationMetadata(node, locale, property, metadata) {
2192
2769
  }
2193
2770
  };
2194
2771
  }
2195
- function createSlot(kind, nodeId, property, locale, sourceText, existingText, nodeMetadata, existingTranslationMetadata, options = {}) {
2196
- const path = `${kind}.${nodeId}.${property}`;
2772
+ function localeRecordEntry2(record, locale) {
2773
+ const normalizedLocale = normalizeLocale(locale) ?? locale;
2774
+ for (const [candidate, value] of Object.entries(record ?? {})) {
2775
+ if ((normalizeLocale(candidate) ?? candidate) === normalizedLocale) return value;
2776
+ }
2777
+ return void 0;
2778
+ }
2779
+ function createSlot(kind, nodeId, property, locale, sourceText, existingText, nodeMetadata, existingTranslationMetadata, options = {}, parentId) {
2780
+ const path = kind === "form" ? `form.${property}` : kind === "option" ? `fields.${parentId ?? ""}.options.${nodeId}.${property}` : `${kind}s.${nodeId}.${property}`;
2197
2781
  const manual = options.isManualTranslation?.(existingTranslationMetadata, { path, locale }) ?? isManualTranslationMetadata(existingTranslationMetadata);
2198
2782
  const normalizedMetadata = existingTranslationMetadata === void 0 ? void 0 : options.normalizeMetadata === void 0 ? existingTranslationMetadata : { ...options.normalizeMetadata(existingTranslationMetadata, sourceText) };
2199
2783
  const status = getTranslationStatusWithManualOverride(sourceText, existingText, normalizedMetadata, manual);
@@ -2213,7 +2797,10 @@ function createSlot(kind, nodeId, property, locale, sourceText, existingText, no
2213
2797
  };
2214
2798
  }
2215
2799
  function translationSlots(schema, locale, options = {}) {
2800
+ locale = normalizeLocale(locale) ?? locale;
2216
2801
  const descriptors = [];
2802
+ const schemaTranslation = localeRecordEntry2(schema.translations, locale);
2803
+ const schemaTranslationMetadata = localeRecordEntry2(schema.translationMetadata, locale);
2217
2804
  const addFormSlot = (property, sourceText) => {
2218
2805
  const slot = createSlot(
2219
2806
  "form",
@@ -2221,17 +2808,17 @@ function translationSlots(schema, locale, options = {}) {
2221
2808
  property,
2222
2809
  locale,
2223
2810
  sourceText,
2224
- schema.translations?.[locale]?.[property],
2811
+ schemaTranslation?.[property],
2225
2812
  schema.metadata,
2226
- schema.translationMetadata?.[locale]?.[property],
2813
+ schemaTranslationMetadata?.[property],
2227
2814
  options
2228
2815
  );
2229
2816
  descriptors.push({
2230
2817
  slot,
2231
- manual: options.isManualTranslation?.(schema.translationMetadata?.[locale]?.[property], {
2818
+ manual: options.isManualTranslation?.(schemaTranslationMetadata?.[property], {
2232
2819
  path: slot.path ?? "",
2233
2820
  locale
2234
- }) ?? isManualTranslationMetadata(schema.translationMetadata?.[locale]?.[property]),
2821
+ }) ?? isManualTranslationMetadata(schemaTranslationMetadata?.[property]),
2235
2822
  apply: (current, value, metadata) => withTranslationMetadata(
2236
2823
  { ...current, translations: mergeLocalizedText(current.translations, locale, property, value) },
2237
2824
  locale,
@@ -2244,6 +2831,8 @@ function translationSlots(schema, locale, options = {}) {
2244
2831
  if (schema.description !== void 0) addFormSlot("description", schema.description);
2245
2832
  if (schema.completionMessage !== void 0) addFormSlot("completionMessage", schema.completionMessage);
2246
2833
  schema.fields.forEach((field, fieldIndex) => {
2834
+ const fieldTranslation = localeRecordEntry2(field.translations, locale);
2835
+ const fieldTranslationMetadata = localeRecordEntry2(field.translationMetadata, locale);
2247
2836
  const addFieldSlot = (property, sourceText) => {
2248
2837
  const slot = createSlot(
2249
2838
  "field",
@@ -2251,17 +2840,17 @@ function translationSlots(schema, locale, options = {}) {
2251
2840
  property,
2252
2841
  locale,
2253
2842
  sourceText,
2254
- field.translations?.[locale]?.[property],
2843
+ fieldTranslation?.[property],
2255
2844
  field.metadata,
2256
- field.translationMetadata?.[locale]?.[property],
2845
+ fieldTranslationMetadata?.[property],
2257
2846
  options
2258
2847
  );
2259
2848
  descriptors.push({
2260
2849
  slot,
2261
- manual: options.isManualTranslation?.(field.translationMetadata?.[locale]?.[property], {
2850
+ manual: options.isManualTranslation?.(fieldTranslationMetadata?.[property], {
2262
2851
  path: slot.path ?? "",
2263
2852
  locale
2264
- }) ?? isManualTranslationMetadata(field.translationMetadata?.[locale]?.[property]),
2853
+ }) ?? isManualTranslationMetadata(fieldTranslationMetadata?.[property]),
2265
2854
  apply: (current, value, metadata) => ({
2266
2855
  ...current,
2267
2856
  fields: current.fields.map(
@@ -2282,23 +2871,26 @@ function translationSlots(schema, locale, options = {}) {
2282
2871
  if (field.description !== void 0) addFieldSlot("description", field.description);
2283
2872
  if ("options" in field) {
2284
2873
  field.options.forEach((option, optionIndex) => {
2874
+ const optionTranslation = localeRecordEntry2(option.translations, locale);
2875
+ const optionTranslationMetadata = localeRecordEntry2(option.translationMetadata, locale);
2285
2876
  const slot = createSlot(
2286
2877
  "option",
2287
2878
  option.id,
2288
2879
  "label",
2289
2880
  locale,
2290
2881
  option.label,
2291
- option.translations?.[locale],
2882
+ optionTranslation,
2292
2883
  option.metadata,
2293
- option.translationMetadata?.[locale]?.label,
2294
- options
2884
+ optionTranslationMetadata?.label,
2885
+ options,
2886
+ field.id
2295
2887
  );
2296
2888
  descriptors.push({
2297
2889
  slot,
2298
- manual: options.isManualTranslation?.(option.translationMetadata?.[locale]?.label, {
2890
+ manual: options.isManualTranslation?.(optionTranslationMetadata?.label, {
2299
2891
  path: slot.path ?? "",
2300
2892
  locale
2301
- }) ?? isManualTranslationMetadata(option.translationMetadata?.[locale]?.label),
2893
+ }) ?? isManualTranslationMetadata(optionTranslationMetadata?.label),
2302
2894
  apply: (current, value, metadata) => ({
2303
2895
  ...current,
2304
2896
  fields: current.fields.map((candidate, candidateIndex) => {
@@ -2324,6 +2916,8 @@ function translationSlots(schema, locale, options = {}) {
2324
2916
  }
2325
2917
  });
2326
2918
  schema.pages?.forEach((page, pageIndex) => {
2919
+ const pageTranslation = localeRecordEntry2(page.translations, locale);
2920
+ const pageTranslationMetadata = localeRecordEntry2(page.translationMetadata, locale);
2327
2921
  const addPageSlot = (property, sourceText) => {
2328
2922
  const slot = createSlot(
2329
2923
  "page",
@@ -2331,17 +2925,17 @@ function translationSlots(schema, locale, options = {}) {
2331
2925
  property,
2332
2926
  locale,
2333
2927
  sourceText,
2334
- page.translations?.[locale]?.[property],
2928
+ pageTranslation?.[property],
2335
2929
  page.metadata,
2336
- page.translationMetadata?.[locale]?.[property],
2930
+ pageTranslationMetadata?.[property],
2337
2931
  options
2338
2932
  );
2339
2933
  descriptors.push({
2340
2934
  slot,
2341
- manual: options.isManualTranslation?.(page.translationMetadata?.[locale]?.[property], {
2935
+ manual: options.isManualTranslation?.(pageTranslationMetadata?.[property], {
2342
2936
  path: slot.path ?? "",
2343
2937
  locale
2344
- }) ?? isManualTranslationMetadata(page.translationMetadata?.[locale]?.[property]),
2938
+ }) ?? isManualTranslationMetadata(pageTranslationMetadata?.[property]),
2345
2939
  apply: (current, value, metadata) => ({
2346
2940
  ...current,
2347
2941
  ...current.pages === void 0 ? {} : {
@@ -2429,7 +3023,7 @@ var migrateSchemaTranslationMetadata = (schema, migratorOrOptions) => {
2429
3023
  (locale, property) => ({
2430
3024
  locale,
2431
3025
  defaultLocale,
2432
- path: property,
3026
+ path: `form.${property}`,
2433
3027
  property,
2434
3028
  nodeKind: "form"
2435
3029
  }),
@@ -2528,8 +3122,11 @@ function collectTranslationSlots(schema, locale) {
2528
3122
  return translationSlots(schema, locale).map((descriptor) => descriptor.slot);
2529
3123
  }
2530
3124
  function resolveLocalizedSchema(schema, targetLocale) {
2531
- if (targetLocale === void 0 || targetLocale.length === 0 || targetLocale === schema.defaultLocale) return schema;
2532
- const formTranslation = schema.translations?.[targetLocale];
3125
+ if (targetLocale === void 0 || targetLocale.length === 0) return schema;
3126
+ const normalizedTargetLocale = normalizeLocale(targetLocale) ?? targetLocale;
3127
+ const defaultLocale = schema.defaultLocale === void 0 ? void 0 : normalizeLocale(schema.defaultLocale);
3128
+ if (normalizedTargetLocale === defaultLocale || targetLocale === schema.defaultLocale) return schema;
3129
+ const formTranslation = localeRecordEntry2(schema.translations, normalizedTargetLocale);
2533
3130
  const completionMessage = formTranslation?.completionMessage ?? schema.completionMessage;
2534
3131
  return {
2535
3132
  ...schema,
@@ -2537,7 +3134,7 @@ function resolveLocalizedSchema(schema, targetLocale) {
2537
3134
  ...(formTranslation?.description ?? schema.description) === void 0 ? {} : { description: formTranslation?.description ?? schema.description },
2538
3135
  ...completionMessage === void 0 ? {} : { completionMessage },
2539
3136
  fields: schema.fields.map((field) => {
2540
- const translation = field.translations?.[targetLocale];
3137
+ const translation = localeRecordEntry2(field.translations, normalizedTargetLocale);
2541
3138
  const localized = {
2542
3139
  ...field,
2543
3140
  title: translation?.title ?? field.title,
@@ -2548,13 +3145,13 @@ function resolveLocalizedSchema(schema, targetLocale) {
2548
3145
  ...localized,
2549
3146
  options: field.options.map((option) => ({
2550
3147
  ...option,
2551
- label: option.translations?.[targetLocale] ?? option.label
3148
+ label: localeRecordEntry2(option.translations, normalizedTargetLocale) ?? option.label
2552
3149
  }))
2553
3150
  };
2554
3151
  }),
2555
3152
  ...schema.pages === void 0 ? {} : {
2556
3153
  pages: schema.pages.map((page) => {
2557
- const translation = page.translations?.[targetLocale];
3154
+ const translation = localeRecordEntry2(page.translations, normalizedTargetLocale);
2558
3155
  const title = translation?.title ?? page.title;
2559
3156
  const description = translation?.description ?? page.description;
2560
3157
  return {
@@ -2568,8 +3165,13 @@ function resolveLocalizedSchema(schema, targetLocale) {
2568
3165
  }
2569
3166
  async function populateSchemaTranslations(schema, targetLocales, adapter, options = {}) {
2570
3167
  assertValidFormSchema(schema);
2571
- const locales = [...new Set(targetLocales.filter((locale) => locale.length > 0 && locale !== schema.defaultLocale))];
2572
- const allowedLocales = options.policy?.allowedLocales;
3168
+ const defaultLocale = schema.defaultLocale === void 0 ? void 0 : normalizeLocale(schema.defaultLocale) ?? schema.defaultLocale;
3169
+ const locales = [
3170
+ ...new Set(
3171
+ targetLocales.map((locale) => normalizeLocale(locale) ?? locale.trim()).filter((locale) => locale.length > 0 && locale !== defaultLocale)
3172
+ )
3173
+ ];
3174
+ const allowedLocales = options.policy?.allowedLocales?.map((locale) => normalizeLocale(locale) ?? locale);
2573
3175
  const collectedLocales = collectSchemaLocales(schema);
2574
3176
  const disallowedLocale = [...collectedLocales.allUniqueLocales, ...locales].find(
2575
3177
  (locale) => allowedLocales !== void 0 && !allowedLocales.includes(locale)
@@ -2611,7 +3213,7 @@ async function populateSchemaTranslations(schema, targetLocales, adapter, option
2611
3213
  adapter,
2612
3214
  selected.map((descriptor) => descriptor.slot.sourceText),
2613
3215
  locale,
2614
- schema.defaultLocale
3216
+ defaultLocale
2615
3217
  );
2616
3218
  if (translated.length !== selected.length) {
2617
3219
  throw new Error(`Translation adapter returned ${translated.length} texts for ${selected.length} inputs.`);
@@ -2620,7 +3222,7 @@ async function populateSchemaTranslations(schema, targetLocales, adapter, option
2620
3222
  const translatedText = translated[index];
2621
3223
  if (translatedText === void 0) throw new Error("Translation adapter returned an unexpected result.");
2622
3224
  const metadata = options.createMetadata?.(descriptor.slot, translatedText) ?? {
2623
- sourceLocale: schema.defaultLocale ?? "",
3225
+ sourceLocale: defaultLocale ?? "",
2624
3226
  sourceTextHash: computeSourceTextHash(descriptor.slot.sourceText),
2625
3227
  translationSource: "automatic",
2626
3228
  translatedAt: (/* @__PURE__ */ new Date()).toISOString()
@@ -2631,8 +3233,8 @@ async function populateSchemaTranslations(schema, targetLocales, adapter, option
2631
3233
  }
2632
3234
  const supportedLocales = [
2633
3235
  .../* @__PURE__ */ new Set([
2634
- ...schema.defaultLocale === void 0 ? [] : [schema.defaultLocale],
2635
- ...schema.supportedLocales ?? [],
3236
+ ...defaultLocale === void 0 ? [] : [defaultLocale],
3237
+ ...(schema.supportedLocales ?? []).map((locale) => normalizeLocale(locale) ?? locale),
2636
3238
  ...locales
2637
3239
  ])
2638
3240
  ];
@@ -2929,9 +3531,49 @@ function assertVersionMutable(status) {
2929
3531
  throw new TypeError(`A ${status} form version is immutable.`, { cause: error });
2930
3532
  }
2931
3533
  }
3534
+ function applyTransitionPlan(plan) {
3535
+ if (plan.schema !== void 0) return plan.schema;
3536
+ if (plan.publishedRecordToSave !== void 0) return plan.publishedRecordToSave.schema;
3537
+ if (plan.draftToCreate !== void 0) return plan.draftToCreate.schema;
3538
+ const archivedSchema = plan.archivedRecordsToSave?.[0]?.schema;
3539
+ if (archivedSchema !== void 0) return archivedSchema;
3540
+ throw new TypeError("A version transition plan must include a target schema.");
3541
+ }
3542
+ async function commitVersionTransition(options) {
3543
+ const { context, beforeTransition, afterTransition, persistAdapter } = options;
3544
+ const { formId, toVersion, expectedRevision, plan } = context;
3545
+ let currentDomainData = context.domainData;
3546
+ try {
3547
+ if (beforeTransition !== void 0) {
3548
+ const hookResult = await beforeTransition(context);
3549
+ if (hookResult !== void 0) currentDomainData = hookResult;
3550
+ }
3551
+ const nextSchema = applyTransitionPlan(plan);
3552
+ const { nextRevision } = await persistAdapter({
3553
+ formId,
3554
+ targetVersion: toVersion,
3555
+ expectedRevision,
3556
+ schema: nextSchema,
3557
+ ...currentDomainData === void 0 ? {} : { domainData: currentDomainData }
3558
+ });
3559
+ if (afterTransition !== void 0) {
3560
+ await afterTransition({
3561
+ ...context,
3562
+ ...currentDomainData === void 0 ? {} : { domainData: currentDomainData },
3563
+ nextRevision
3564
+ });
3565
+ }
3566
+ return { success: true, nextRevision };
3567
+ } catch (cause) {
3568
+ return { success: false, nextRevision: expectedRevision, error: { type: "transition_failed", cause } };
3569
+ }
3570
+ }
2932
3571
  export {
2933
3572
  DEFAULT_FIELD_TYPE_DEFINITIONS,
3573
+ EN_MESSAGES,
3574
+ JA_MESSAGES,
2934
3575
  aggregateResponses,
3576
+ applyTransitionPlan,
2935
3577
  assertValidFormSchema,
2936
3578
  assertVersionMutable,
2937
3579
  calculateChoiceDistribution,
@@ -2942,16 +3584,22 @@ export {
2942
3584
  cloneVersionToDraft,
2943
3585
  collectSchemaLocales,
2944
3586
  collectTranslationSlots,
3587
+ commitVersionTransition,
2945
3588
  computeSourceTextHash,
2946
3589
  createCloneTransitionPlan,
2947
3590
  createDeleteDraftTransitionPlan,
3591
+ createFormEngineTranslator,
2948
3592
  createPublishTransitionPlan,
2949
3593
  createResponseAccumulator,
2950
3594
  createSubmission,
3595
+ decodeStorageSubmissionCursor,
3596
+ decodeStorageTextAnswerCursor,
2951
3597
  decodeSubmissionCursor,
2952
3598
  decodeTextAnswerCursor,
2953
3599
  deleteDraft,
2954
3600
  dispatchWebhook,
3601
+ encodeStorageSubmissionCursor,
3602
+ encodeStorageTextAnswerCursor,
2955
3603
  encodeSubmissionCursor,
2956
3604
  encodeTextAnswerCursor,
2957
3605
  escapeCsvCell,
@@ -2967,7 +3615,9 @@ export {
2967
3615
  matchesSubmissionFilter,
2968
3616
  matchesSubmissionPageFilters,
2969
3617
  migrateSchemaTranslationMetadata,
3618
+ normalizeLocale,
2970
3619
  normalizeSubmissionPageSize,
3620
+ paginateWithFilter,
2971
3621
  pipeResponsesToCsvStream,
2972
3622
  populateSchemaTranslations,
2973
3623
  publishDraft,
@@ -2980,5 +3630,6 @@ export {
2980
3630
  validateAnswers,
2981
3631
  validateFormSchema,
2982
3632
  validatePageAnswers,
2983
- validateSchemaStructure
3633
+ validateSchemaStructure,
3634
+ validateSubmission
2984
3635
  };