@saastro/forms 0.1.3 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +86 -3
- package/dist/index.js +162 -0
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
package/dist/index.d.ts
CHANGED
|
@@ -96,7 +96,7 @@ type ConditionGroup = {
|
|
|
96
96
|
* Cada acción puede tener su propio trigger (cuándo se ejecuta).
|
|
97
97
|
*/
|
|
98
98
|
|
|
99
|
-
type SubmitActionType = 'http' | 'webhook' | 'email' | 'custom';
|
|
99
|
+
type SubmitActionType = 'http' | 'webhook' | 'email' | 'custom' | 'integration';
|
|
100
100
|
interface HttpEndpointConfig {
|
|
101
101
|
url: string;
|
|
102
102
|
method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
|
|
@@ -184,7 +184,26 @@ interface CustomSubmitAction {
|
|
|
184
184
|
/** Función que se ejecuta con los valores del formulario */
|
|
185
185
|
handler: (values: Record<string, unknown>) => Promise<unknown>;
|
|
186
186
|
}
|
|
187
|
-
|
|
187
|
+
/**
|
|
188
|
+
* References a `site_integrations` row in Saastro Hub. The form runtime
|
|
189
|
+
* itself doesn't execute integrations (Hub does, server-side, after
|
|
190
|
+
* receiving the submission); this action exists so the form schema can
|
|
191
|
+
* declare which integrations Hub should dispatch on submit.
|
|
192
|
+
*
|
|
193
|
+
* `integrationRef` is the UUID Hub assigned to the integration when
|
|
194
|
+
* the user configured it in `/w/{ws}/s/{site}/settings/integrations`.
|
|
195
|
+
*
|
|
196
|
+
* Optional `fieldMapping` lets the user rename form field keys to
|
|
197
|
+
* different names in the destination (e.g. form field "name" →
|
|
198
|
+
* Sheets column "Full Name"). Default: pass-through.
|
|
199
|
+
*/
|
|
200
|
+
interface IntegrationSubmitAction {
|
|
201
|
+
type: 'integration';
|
|
202
|
+
name: string;
|
|
203
|
+
integrationRef: string;
|
|
204
|
+
fieldMapping?: Record<string, string>;
|
|
205
|
+
}
|
|
206
|
+
type SubmitAction = HttpSubmitAction | WebhookSubmitAction | EmailSubmitAction | CustomSubmitAction | IntegrationSubmitAction;
|
|
188
207
|
type SubmitTriggerType = 'onSubmit' | 'onStepEnter' | 'onStepExit' | 'onFieldChange' | 'onFieldBlur' | 'onDelay' | 'manual';
|
|
189
208
|
interface SubmitTrigger {
|
|
190
209
|
type: SubmitTriggerType;
|
|
@@ -3697,6 +3716,70 @@ declare function executeSubmitActions(actions: SubmitActionNode[], values: Recor
|
|
|
3697
3716
|
*/
|
|
3698
3717
|
declare function executeSubmitActionsByTrigger(config: FormConfig, triggerType: SubmitTriggerType, values: Record<string, unknown>, triggerValue?: string): Promise<SubmitActionsResult>;
|
|
3699
3718
|
|
|
3719
|
+
/**
|
|
3720
|
+
* Build a `CustomSubmitConfig` that routes form submissions to a
|
|
3721
|
+
* Saastro Hub site. Used by Astro / React sites whose forms are
|
|
3722
|
+
* authored in Hub (`builder.saastro.io` embed mode) and stored there.
|
|
3723
|
+
*
|
|
3724
|
+
* The flow is:
|
|
3725
|
+
*
|
|
3726
|
+
* 1. Walk the field values and split into `payload` (scalar/JSON-safe)
|
|
3727
|
+
* and `files` (instances of File). Hub keeps text fields together;
|
|
3728
|
+
* files take a separate path.
|
|
3729
|
+
* 2. For each file, POST `/api/public/forms/:siteId/:slug/upload-url`
|
|
3730
|
+
* to get a presigned R2 PUT URL, then PUT the binary directly to
|
|
3731
|
+
* that URL. Hub never touches the file body — R2 receives it.
|
|
3732
|
+
* 3. POST `/api/public/forms/:siteId/:slug/submit` with the textual
|
|
3733
|
+
* payload + an `attachments` array describing the uploaded R2
|
|
3734
|
+
* keys. Hub inserts the submission row and dispatches integrations
|
|
3735
|
+
* (Sheets / Resend / etc.) per the form's schema.
|
|
3736
|
+
*
|
|
3737
|
+
* Turnstile: if the form schema declares `meta.requireCaptcha=true`,
|
|
3738
|
+
* the host app must render the Turnstile widget and pass the token
|
|
3739
|
+
* via the special `_turnstile` field in the form values. The helper
|
|
3740
|
+
* extracts it before sending.
|
|
3741
|
+
*
|
|
3742
|
+
* Honeypot: pass via `_hp` (or whatever `meta.honeypotField` says).
|
|
3743
|
+
* The Hub will silently 200 the request and not store anything if
|
|
3744
|
+
* the honeypot is non-empty.
|
|
3745
|
+
*/
|
|
3746
|
+
|
|
3747
|
+
interface CreateHubFormSubmitOptions {
|
|
3748
|
+
/** Hub origin, e.g. `https://hub.saastro.io`. No trailing slash. */
|
|
3749
|
+
hubUrl: string;
|
|
3750
|
+
siteId: string;
|
|
3751
|
+
formSlug: string;
|
|
3752
|
+
}
|
|
3753
|
+
/**
|
|
3754
|
+
* Build a `CustomSubmitConfig` to plug into `<Form config={{...,
|
|
3755
|
+
* submit: createHubFormSubmit({...})}} />`.
|
|
3756
|
+
*
|
|
3757
|
+
* On submit:
|
|
3758
|
+
* - Files are uploaded to R2 first (presigned URLs).
|
|
3759
|
+
* - Then the payload + attachments are POSTed to Hub's submit endpoint.
|
|
3760
|
+
* - Throws on any non-2xx so the caller's `<Form>` shows the error.
|
|
3761
|
+
*/
|
|
3762
|
+
declare function createHubFormSubmit(opts: CreateHubFormSubmitOptions): CustomSubmitConfig;
|
|
3763
|
+
|
|
3764
|
+
interface HubFormProps {
|
|
3765
|
+
/** Origin of the Hub API. e.g. `https://hub.saastro.io`. No trailing slash. */
|
|
3766
|
+
hubUrl: string;
|
|
3767
|
+
siteId: string;
|
|
3768
|
+
formSlug: string;
|
|
3769
|
+
/** Custom UI while the schema is being fetched. Defaults to a skeleton. */
|
|
3770
|
+
loadingFallback?: ReactNode;
|
|
3771
|
+
/**
|
|
3772
|
+
* Custom UI when the schema fetch fails. Receives the error message
|
|
3773
|
+
* as a string. Defaults to a minimal red banner.
|
|
3774
|
+
*/
|
|
3775
|
+
errorFallback?: (error: string) => ReactNode;
|
|
3776
|
+
/**
|
|
3777
|
+
* Forwarded to `<Form>` — every prop except `config` (which we own).
|
|
3778
|
+
*/
|
|
3779
|
+
formProps?: Omit<FormProps, 'config'>;
|
|
3780
|
+
}
|
|
3781
|
+
declare function HubForm({ hubUrl, siteId, formSlug, loadingFallback, errorFallback, formProps, }: HubFormProps): string | number | bigint | boolean | Iterable<ReactNode> | Promise<string | number | bigint | boolean | React$1.ReactPortal | React$1.ReactElement<unknown, string | React$1.JSXElementConstructor<any>> | Iterable<ReactNode> | null | undefined> | react_jsx_runtime.JSX.Element;
|
|
3782
|
+
|
|
3700
3783
|
/**
|
|
3701
3784
|
* Test Data Generator — generates realistic field values for form testing.
|
|
3702
3785
|
*
|
|
@@ -3751,4 +3834,4 @@ declare function getFieldClass(formLayout?: {
|
|
|
3751
3834
|
*/
|
|
3752
3835
|
declare function getHiddenClasses(hidden?: Partial<Record<Breakpoint, 'visible' | 'hidden'>>): string;
|
|
3753
3836
|
|
|
3754
|
-
export { type AccordionContentProps, type AccordionItemProps, type AccordionProps, type AccordionTriggerProps, BUILD_METHODS, BUILTIN_RESOLVERS, type BaseFieldProps, type Breakpoint$1 as Breakpoint, type BuiltinTransform, type ButtonCardFieldProps, type ButtonCardOption, type ButtonCheckboxFieldProps, type ButtonConfig, type ButtonProps, type ButtonRadioFieldProps, COMMON_CLASSES, COMMON_METHODS, COMMON_STRINGS, type CalendarProps, type CheckboxFieldProps, type CheckboxGroupFieldProps, type CheckboxProps, type ColumnsValue, type ComboboxFieldProps, type CommandEmptyProps, type CommandFieldProps, type CommandGroupProps, type CommandInputProps, type CommandItemProps, type CommandListProps, type CommandProps, type ComponentName, type ComponentOverrides, ComponentProvider, type ComponentProviderProps, type ComponentRegistry, type ComponentRegistryInput, ComponentResolver, type ComponentResolverConfig, type Condition, type ConditionGroup, type ConditionOperator, type CurrencyFieldProps, type CustomSubmitAction, type CustomSubmitConfig, type DatabowlConfig, type DateFieldProps, type DateRangeFieldProps, type DefaultSubmitConfig, type DefinePlugin, type DialogContentProps, type DialogDescriptionProps, type DialogHeaderProps, type DialogProps, type DialogTitleProps, type DialogTriggerProps, type EmailProvider, type EmailSubmitAction, type EndpointConfig, FIELD_DEFAULTS, FieldBuilder, type FieldConfig, type FieldDescriptionProps, type FieldErrorProps, type FieldLabelProps, type FieldLayoutConfig, type FieldMapEntry, type FieldMapping, type FieldMappingConfig, type FieldProps, FieldRenderer, type FieldResolver, type FieldTransformFn, type Fields, type FileFieldProps, Form, FormBuilder, type FormButtonProps, type FormButtons, FormComponentsProvider, type FormComponentsProviderProps, type FormConfig, type FormControlProps, type FormFieldProps, type FormLayout, type FormPlugin, type FormProps, type FormRef, type FormStepsInfo, type GapValue, type GlobModules, type HiddenFieldProps, type HtmlFieldProps, type HttpAuthConfig, type HttpBodyConfig, type HttpEndpointConfig, type HttpRetryConfig, type HttpSubmitAction, type InputGroupFieldProps, type InputOTPGroupProps, type InputOTPProps, type InputOTPSlotProps, type InputProps, type InputSize, InternalComponentProvider, type InternalComponentProviderProps, type LabelProps, MissingComponentFallback, type MissingComponentFallbackProps, type NativeSelectFieldProps, type NativeSelectProps, OPTION_BASED_TYPES, type Option, type OtpFieldProps, type PartialComponentRegistry, PluginManager, type PopoverContentProps, type PopoverProps, type PopoverTriggerProps, type PropertyMapping, type RadioFieldProps, type RadioGroupItemProps, type RadioGroupProps, type RangeFieldProps, type RecaptchaConfig, type RecaptchaPluginConfig, type RepeaterFieldProps, type ResolvedComponents, SUSPENSE_CONFIG, type SchemaType, type SelectContentProps, type SelectFieldProps, type SelectItemProps, type SelectProps, type SelectTriggerProps, type SelectValueProps, type SeparatorProps, type SerializableFieldResolver, type SerializationHint, type SliderFieldProps, type SliderProps, type Step, type StepCondition, type StepInfo, type StepStatus, type Steps, StepsAccordion, StepsNavigation, StepsProgress, type SubmitAction, type SubmitActionCondition, type SubmitActionNode, type SubmitActionResult, type SubmitActionType, type SubmitActionsResult, type SubmitConfig, type SubmitConfirmationConfig, type SubmitExecutionConfig, type SubmitTrigger, type SubmitTriggerType, type SubmitType, type SwitchFieldProps, type SwitchGroupFieldProps, type SwitchProps, TYPE_SPECIFIC_PROPERTIES, type TestDataLocale, type TestDataOptions, type TextFieldProps, type TextareaFieldProps, type TextareaProps, type TooltipContentProps, type TooltipProps, type TooltipProviderProps, type TooltipTriggerProps, type UseSubmitConfirmationReturn, VALIDATION_METHODS, type ValidateComponentRegistry, type ValidationContext, type ValidationPresetMeta, type ValidationRules, type WebhookSubmitAction, analyticsPlugin, applyBuiltinTransform, applyFieldMapping, applyFieldMappingSync, applyFieldTransforms, applyTransform, autosavePlugin, compileValidationRules, configureComponents, coreComponents, createComponentRegistry, createMissingComponentPlaceholder, createShadcnRegistry, databowlAction, databowlPlugin, defaultSubmit, definePlugin, detectLocale, executeCustomAction, executeEmailAction, executeHttpAction, executeSubmitAction, executeSubmitActions, executeSubmitActionsByTrigger, executeWebhookAction, fieldTypeComponents, generateFieldValue, generateTestData, getActionsByTrigger, getAllKnownMethods, getAvailablePresets, getComponentResolver, getFieldClass, getFormGridClass, getHiddenClasses, getInstallCommand, getMinDelayMs, getMissingComponents, getRequiredComponents, globalPluginManager, groupMissingByPackage, iconVariants, iconVariantsConfig, inputVariants, inputVariantsConfig, isAdvancedMapping, isValidationRules, isZodSchema, localStoragePlugin, mergeComponentRegistries, parseGlobModules, pxToRem, recaptchaPlugin, registerPreset, resolvePreset, resolveValue, resolveValueSync, textareaVariants, textareaVariantsConfig, useComponentMode, useComponents, useComputedFields, useFormLayout, useFormState, useFormStepsInfo, useHasComponentProvider, useHiddenFieldResolvers, usePartialComponents, useRecaptcha, useSubmitActionTriggers, useSubmitConfirmation, withComponents };
|
|
3837
|
+
export { type AccordionContentProps, type AccordionItemProps, type AccordionProps, type AccordionTriggerProps, BUILD_METHODS, BUILTIN_RESOLVERS, type BaseFieldProps, type Breakpoint$1 as Breakpoint, type BuiltinTransform, type ButtonCardFieldProps, type ButtonCardOption, type ButtonCheckboxFieldProps, type ButtonConfig, type ButtonProps, type ButtonRadioFieldProps, COMMON_CLASSES, COMMON_METHODS, COMMON_STRINGS, type CalendarProps, type CheckboxFieldProps, type CheckboxGroupFieldProps, type CheckboxProps, type ColumnsValue, type ComboboxFieldProps, type CommandEmptyProps, type CommandFieldProps, type CommandGroupProps, type CommandInputProps, type CommandItemProps, type CommandListProps, type CommandProps, type ComponentName, type ComponentOverrides, ComponentProvider, type ComponentProviderProps, type ComponentRegistry, type ComponentRegistryInput, ComponentResolver, type ComponentResolverConfig, type Condition, type ConditionGroup, type ConditionOperator, type CreateHubFormSubmitOptions, type CurrencyFieldProps, type CustomSubmitAction, type CustomSubmitConfig, type DatabowlConfig, type DateFieldProps, type DateRangeFieldProps, type DefaultSubmitConfig, type DefinePlugin, type DialogContentProps, type DialogDescriptionProps, type DialogHeaderProps, type DialogProps, type DialogTitleProps, type DialogTriggerProps, type EmailProvider, type EmailSubmitAction, type EndpointConfig, FIELD_DEFAULTS, FieldBuilder, type FieldConfig, type FieldDescriptionProps, type FieldErrorProps, type FieldLabelProps, type FieldLayoutConfig, type FieldMapEntry, type FieldMapping, type FieldMappingConfig, type FieldProps, FieldRenderer, type FieldResolver, type FieldTransformFn, type Fields, type FileFieldProps, Form, FormBuilder, type FormButtonProps, type FormButtons, FormComponentsProvider, type FormComponentsProviderProps, type FormConfig, type FormControlProps, type FormFieldProps, type FormLayout, type FormPlugin, type FormProps, type FormRef, type FormStepsInfo, type GapValue, type GlobModules, type HiddenFieldProps, type HtmlFieldProps, type HttpAuthConfig, type HttpBodyConfig, type HttpEndpointConfig, type HttpRetryConfig, type HttpSubmitAction, HubForm, type HubFormProps, type InputGroupFieldProps, type InputOTPGroupProps, type InputOTPProps, type InputOTPSlotProps, type InputProps, type InputSize, type IntegrationSubmitAction, InternalComponentProvider, type InternalComponentProviderProps, type LabelProps, MissingComponentFallback, type MissingComponentFallbackProps, type NativeSelectFieldProps, type NativeSelectProps, OPTION_BASED_TYPES, type Option, type OtpFieldProps, type PartialComponentRegistry, PluginManager, type PopoverContentProps, type PopoverProps, type PopoverTriggerProps, type PropertyMapping, type RadioFieldProps, type RadioGroupItemProps, type RadioGroupProps, type RangeFieldProps, type RecaptchaConfig, type RecaptchaPluginConfig, type RepeaterFieldProps, type ResolvedComponents, SUSPENSE_CONFIG, type SchemaType, type SelectContentProps, type SelectFieldProps, type SelectItemProps, type SelectProps, type SelectTriggerProps, type SelectValueProps, type SeparatorProps, type SerializableFieldResolver, type SerializationHint, type SliderFieldProps, type SliderProps, type Step, type StepCondition, type StepInfo, type StepStatus, type Steps, StepsAccordion, StepsNavigation, StepsProgress, type SubmitAction, type SubmitActionCondition, type SubmitActionNode, type SubmitActionResult, type SubmitActionType, type SubmitActionsResult, type SubmitConfig, type SubmitConfirmationConfig, type SubmitExecutionConfig, type SubmitTrigger, type SubmitTriggerType, type SubmitType, type SwitchFieldProps, type SwitchGroupFieldProps, type SwitchProps, TYPE_SPECIFIC_PROPERTIES, type TestDataLocale, type TestDataOptions, type TextFieldProps, type TextareaFieldProps, type TextareaProps, type TooltipContentProps, type TooltipProps, type TooltipProviderProps, type TooltipTriggerProps, type UseSubmitConfirmationReturn, VALIDATION_METHODS, type ValidateComponentRegistry, type ValidationContext, type ValidationPresetMeta, type ValidationRules, type WebhookSubmitAction, analyticsPlugin, applyBuiltinTransform, applyFieldMapping, applyFieldMappingSync, applyFieldTransforms, applyTransform, autosavePlugin, compileValidationRules, configureComponents, coreComponents, createComponentRegistry, createHubFormSubmit, createMissingComponentPlaceholder, createShadcnRegistry, databowlAction, databowlPlugin, defaultSubmit, definePlugin, detectLocale, executeCustomAction, executeEmailAction, executeHttpAction, executeSubmitAction, executeSubmitActions, executeSubmitActionsByTrigger, executeWebhookAction, fieldTypeComponents, generateFieldValue, generateTestData, getActionsByTrigger, getAllKnownMethods, getAvailablePresets, getComponentResolver, getFieldClass, getFormGridClass, getHiddenClasses, getInstallCommand, getMinDelayMs, getMissingComponents, getRequiredComponents, globalPluginManager, groupMissingByPackage, iconVariants, iconVariantsConfig, inputVariants, inputVariantsConfig, isAdvancedMapping, isValidationRules, isZodSchema, localStoragePlugin, mergeComponentRegistries, parseGlobModules, pxToRem, recaptchaPlugin, registerPreset, resolvePreset, resolveValue, resolveValueSync, textareaVariants, textareaVariantsConfig, useComponentMode, useComponents, useComputedFields, useFormLayout, useFormState, useFormStepsInfo, useHasComponentProvider, useHiddenFieldResolvers, usePartialComponents, useRecaptcha, useSubmitActionTriggers, useSubmitConfirmation, withComponents };
|
package/dist/index.js
CHANGED
|
@@ -6799,6 +6799,166 @@ var BUILTIN_RESOLVERS = [
|
|
|
6799
6799
|
{ id: "urlParam", label: "URL Parameter", description: "Value from a URL query parameter" }
|
|
6800
6800
|
];
|
|
6801
6801
|
|
|
6802
|
+
// src/lib/createHubFormSubmit.ts
|
|
6803
|
+
function publicBase({ hubUrl, siteId, formSlug }) {
|
|
6804
|
+
const cleanHub = hubUrl.replace(/\/+$/, "");
|
|
6805
|
+
return `${cleanHub}/api/public/forms/${encodeURIComponent(siteId)}/${encodeURIComponent(formSlug)}`;
|
|
6806
|
+
}
|
|
6807
|
+
async function presignAndUpload(base, file) {
|
|
6808
|
+
const presignRes = await fetch(`${base}/upload-url`, {
|
|
6809
|
+
method: "POST",
|
|
6810
|
+
headers: { "content-type": "application/json" },
|
|
6811
|
+
body: JSON.stringify({
|
|
6812
|
+
filename: file.name,
|
|
6813
|
+
size: file.size,
|
|
6814
|
+
mime: file.type || "application/octet-stream"
|
|
6815
|
+
})
|
|
6816
|
+
});
|
|
6817
|
+
const presignBody = await presignRes.json().catch(() => ({}));
|
|
6818
|
+
if (!presignRes.ok || !presignBody.ok || !presignBody.uploadUrl || !presignBody.key) {
|
|
6819
|
+
const detail = presignBody.detail ?? presignBody.error ?? presignRes.statusText;
|
|
6820
|
+
throw new Error(`upload-url failed: ${detail}`);
|
|
6821
|
+
}
|
|
6822
|
+
const putRes = await fetch(presignBody.uploadUrl, {
|
|
6823
|
+
method: "PUT",
|
|
6824
|
+
headers: { "content-type": file.type || "application/octet-stream" },
|
|
6825
|
+
body: file
|
|
6826
|
+
});
|
|
6827
|
+
if (!putRes.ok) {
|
|
6828
|
+
throw new Error(`upload PUT to R2 failed: ${putRes.status} ${putRes.statusText}`);
|
|
6829
|
+
}
|
|
6830
|
+
return {
|
|
6831
|
+
key: presignBody.key,
|
|
6832
|
+
filename: file.name,
|
|
6833
|
+
size: file.size,
|
|
6834
|
+
mime: file.type || "application/octet-stream"
|
|
6835
|
+
};
|
|
6836
|
+
}
|
|
6837
|
+
function partitionValues(values) {
|
|
6838
|
+
const payload = {};
|
|
6839
|
+
const files = [];
|
|
6840
|
+
let turnstileToken = null;
|
|
6841
|
+
const honeypotEntries = [];
|
|
6842
|
+
for (const [key, value] of Object.entries(values)) {
|
|
6843
|
+
if (key === "_turnstile") {
|
|
6844
|
+
if (typeof value === "string") turnstileToken = value;
|
|
6845
|
+
continue;
|
|
6846
|
+
}
|
|
6847
|
+
if (key.startsWith("_hp") || key === "_hp") {
|
|
6848
|
+
if (typeof value === "string") {
|
|
6849
|
+
honeypotEntries.push({ field: key, value });
|
|
6850
|
+
}
|
|
6851
|
+
continue;
|
|
6852
|
+
}
|
|
6853
|
+
if (typeof File !== "undefined" && value instanceof File) {
|
|
6854
|
+
files.push({ field: key, file: value });
|
|
6855
|
+
continue;
|
|
6856
|
+
}
|
|
6857
|
+
if (Array.isArray(value)) {
|
|
6858
|
+
const onlyFiles = value.every((v) => typeof File !== "undefined" && v instanceof File);
|
|
6859
|
+
if (onlyFiles && value.length > 0) {
|
|
6860
|
+
for (const f of value) files.push({ field: key, file: f });
|
|
6861
|
+
continue;
|
|
6862
|
+
}
|
|
6863
|
+
}
|
|
6864
|
+
payload[key] = value;
|
|
6865
|
+
}
|
|
6866
|
+
return { payload, files, turnstileToken, honeypotEntries };
|
|
6867
|
+
}
|
|
6868
|
+
function createHubFormSubmit(opts) {
|
|
6869
|
+
const base = publicBase(opts);
|
|
6870
|
+
return {
|
|
6871
|
+
type: "custom",
|
|
6872
|
+
async onSubmit(values) {
|
|
6873
|
+
const { payload, files, turnstileToken, honeypotEntries } = partitionValues(values);
|
|
6874
|
+
const attachments = files.length ? await Promise.all(files.map(({ file }) => presignAndUpload(base, file))) : void 0;
|
|
6875
|
+
const honeypotEntry = {};
|
|
6876
|
+
for (const { field, value } of honeypotEntries) honeypotEntry[field] = value;
|
|
6877
|
+
const submitRes = await fetch(`${base}/submit`, {
|
|
6878
|
+
method: "POST",
|
|
6879
|
+
headers: { "content-type": "application/json" },
|
|
6880
|
+
body: JSON.stringify({
|
|
6881
|
+
payload,
|
|
6882
|
+
attachments,
|
|
6883
|
+
turnstile: turnstileToken ?? void 0,
|
|
6884
|
+
...honeypotEntry
|
|
6885
|
+
})
|
|
6886
|
+
});
|
|
6887
|
+
const body = await submitRes.json().catch(() => ({}));
|
|
6888
|
+
if (!submitRes.ok || !body.ok) {
|
|
6889
|
+
const detail = body.detail ?? body.error ?? submitRes.statusText;
|
|
6890
|
+
throw new Error(`submit failed: ${detail}`);
|
|
6891
|
+
}
|
|
6892
|
+
}
|
|
6893
|
+
};
|
|
6894
|
+
}
|
|
6895
|
+
|
|
6896
|
+
// src/components/HubForm.tsx
|
|
6897
|
+
import { useEffect as useEffect8, useState as useState5 } from "react";
|
|
6898
|
+
import { Fragment as Fragment3, jsx as jsx14, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
6899
|
+
function HubForm({
|
|
6900
|
+
hubUrl,
|
|
6901
|
+
siteId,
|
|
6902
|
+
formSlug,
|
|
6903
|
+
loadingFallback,
|
|
6904
|
+
errorFallback,
|
|
6905
|
+
formProps
|
|
6906
|
+
}) {
|
|
6907
|
+
const [state, setState] = useState5({ status: "loading" });
|
|
6908
|
+
useEffect8(() => {
|
|
6909
|
+
let cancelled = false;
|
|
6910
|
+
const cleanHub = hubUrl.replace(/\/+$/, "");
|
|
6911
|
+
const url = `${cleanHub}/api/public/forms/${encodeURIComponent(siteId)}/${encodeURIComponent(formSlug)}.json`;
|
|
6912
|
+
fetch(url, { headers: { accept: "application/json" } }).then(async (res) => {
|
|
6913
|
+
if (!res.ok) throw new Error(`schema fetch failed: ${res.status} ${res.statusText}`);
|
|
6914
|
+
return res.json();
|
|
6915
|
+
}).then((schema) => {
|
|
6916
|
+
if (!cancelled) setState({ status: "ready", schema });
|
|
6917
|
+
}).catch((err) => {
|
|
6918
|
+
if (!cancelled) {
|
|
6919
|
+
setState({
|
|
6920
|
+
status: "error",
|
|
6921
|
+
error: err instanceof Error ? err.message : String(err)
|
|
6922
|
+
});
|
|
6923
|
+
}
|
|
6924
|
+
});
|
|
6925
|
+
return () => {
|
|
6926
|
+
cancelled = true;
|
|
6927
|
+
};
|
|
6928
|
+
}, [hubUrl, siteId, formSlug]);
|
|
6929
|
+
if (state.status === "loading") {
|
|
6930
|
+
return loadingFallback ?? /* @__PURE__ */ jsx14("div", { "data-saastro-hubform-loading": true, style: loadingStyle, children: "Loading\u2026" });
|
|
6931
|
+
}
|
|
6932
|
+
if (state.status === "error") {
|
|
6933
|
+
if (errorFallback) return /* @__PURE__ */ jsx14(Fragment3, { children: errorFallback(state.error) });
|
|
6934
|
+
return /* @__PURE__ */ jsxs11("div", { role: "alert", style: errorStyle, children: [
|
|
6935
|
+
"Could not load form: ",
|
|
6936
|
+
state.error
|
|
6937
|
+
] });
|
|
6938
|
+
}
|
|
6939
|
+
const config = {
|
|
6940
|
+
...state.schema,
|
|
6941
|
+
submit: createHubFormSubmit({ hubUrl, siteId, formSlug })
|
|
6942
|
+
};
|
|
6943
|
+
return /* @__PURE__ */ jsx14(Form, { ...formProps, config });
|
|
6944
|
+
}
|
|
6945
|
+
var loadingStyle = {
|
|
6946
|
+
padding: "2rem 1rem",
|
|
6947
|
+
textAlign: "center",
|
|
6948
|
+
color: "#888",
|
|
6949
|
+
fontFamily: "system-ui, -apple-system, sans-serif",
|
|
6950
|
+
fontSize: "0.9rem"
|
|
6951
|
+
};
|
|
6952
|
+
var errorStyle = {
|
|
6953
|
+
padding: "1rem",
|
|
6954
|
+
background: "#fef2f2",
|
|
6955
|
+
color: "#991b1b",
|
|
6956
|
+
border: "1px solid #fecaca",
|
|
6957
|
+
borderRadius: "0.375rem",
|
|
6958
|
+
fontFamily: "system-ui, -apple-system, sans-serif",
|
|
6959
|
+
fontSize: "0.875rem"
|
|
6960
|
+
};
|
|
6961
|
+
|
|
6802
6962
|
// src/utils/testDataGenerator.ts
|
|
6803
6963
|
var SPANISH_PATTERNS = [
|
|
6804
6964
|
"nombre",
|
|
@@ -7029,6 +7189,7 @@ export {
|
|
|
7029
7189
|
Form,
|
|
7030
7190
|
FormBuilder,
|
|
7031
7191
|
FormComponentsProvider,
|
|
7192
|
+
HubForm,
|
|
7032
7193
|
InternalComponentProvider,
|
|
7033
7194
|
MissingComponentFallback,
|
|
7034
7195
|
OPTION_BASED_TYPES,
|
|
@@ -7050,6 +7211,7 @@ export {
|
|
|
7050
7211
|
configureComponents,
|
|
7051
7212
|
coreComponents,
|
|
7052
7213
|
createComponentRegistry,
|
|
7214
|
+
createHubFormSubmit,
|
|
7053
7215
|
createMissingComponentPlaceholder,
|
|
7054
7216
|
createShadcnRegistry,
|
|
7055
7217
|
databowlAction,
|