Class: FormSubmissionService
Defined in: server/forms/form-submission-service.ts:48
Extends
Constructors
Constructor
new FormSubmissionService(deps: FormFeatureDeps): FormSubmissionService;Defined in: server/forms/base-form-service.ts:5
Parameters
| Parameter | Type |
|---|---|
deps | FormFeatureDeps |
Returns
FormSubmissionService
Inherited from
Properties
deps
protected readonly deps: FormFeatureDeps;Defined in: server/forms/base-form-service.ts:5
Inherited from
Accessors
actorId
Get Signature
get protected actorId(): string | null;Defined in: server/forms/base-form-service.ts:7
Returns
string | null
Inherited from
Methods
advanceStep()
advanceStep(submissionId: string, input: {
extensions?: FormDataRecord;
fromStepKey: string;
stepData: FormDataRecord;
user?: {
email?: string;
id: string;
organizationId?: string;
roles?: string[];
};
}): Promise<{
nextStepIsTerminal: boolean;
nextStepKey: string;
submission: FormSubmissionWithVersion;
}>;Defined in: server/forms/form-submission-service.ts:479
Wizard navigation: validate the current step's fields, merge them
into data, evaluate the step's outgoing transitions against the
pinned rule versions, and advance the draft in place.
Same-row update: the draft FormSubmissionVersions row's data,
visitedStepKeys, currentStepKey, and lastActivityAt are
mutated; no new version row is created. This keeps in-flight drafts
cheap and avoids polluting the version history with intermediate
states.
Fires the afterStepAdvance hook on success.
Parameters
| Parameter | Type |
|---|---|
submissionId | string |
input | { extensions?: FormDataRecord; fromStepKey: string; stepData: FormDataRecord; user?: { email?: string; id: string; organizationId?: string; roles?: string[]; }; } |
input.extensions? | FormDataRecord |
input.fromStepKey | string |
input.stepData | FormDataRecord |
input.user? | { email?: string; id: string; organizationId?: string; roles?: string[]; } |
input.user.email? | string |
input.user.id | string |
input.user.organizationId? | string |
input.user.roles? | string[] |
Returns
Promise<{
nextStepIsTerminal: boolean;
nextStepKey: string;
submission: FormSubmissionWithVersion;
}>
assertVersionUnpublished()
protected assertVersionUnpublished(versionId: string): Promise<void>;Defined in: server/forms/base-form-service.ts:28
Guard that rejects mutations against a published FormSchemaVersion.
Once a version is published the DAG (steps, transitions, entry-step
key) is frozen — editors must spawn a fresh draft version with
FormSchemaService.createDraftVersion to make further changes.
Centralised here so step / transition / future services share one invariant and one error message.
Parameters
| Parameter | Type |
|---|---|
versionId | string |
Returns
Promise<void>
Inherited from
BaseFormService.assertVersionUnpublished
create()
create(userId: string, input: {
data: Record<string, unknown>;
formSchemaVersionId: string;
}): Promise<FormSubmissionWithVersion>;Defined in: server/forms/form-submission-service.ts:165
Parameters
| Parameter | Type |
|---|---|
userId | string |
input | { data: Record<string, unknown>; formSchemaVersionId: string; } |
input.data | Record<string, unknown> |
input.formSchemaVersionId | string |
Returns
Promise<FormSubmissionWithVersion>
createDraft()
createDraft(userId: string, formSchemaId: string): Promise<FormSubmissionWithVersion>;Defined in: server/forms/form-submission-service.ts:392
Create — or resume — a draft submission for a multi-step (or single-page) form.
Pinned-version contract: the draft's formSchemaVersionId is set
once, at creation time, from the schema's current published version.
Subsequent schema edits create new versions but do not affect this
draft.
Resume semantics: at most one active draft per (user, schema). If the user already has an in-flight draft, it's returned as-is. If they have only a completed submission, a new draft version is appended to the same submission row, prefilled from the latest completed version (cross-version shape-migrated when the pins differ).
Fires the afterDraftCreated hook on success.
Parameters
| Parameter | Type |
|---|---|
userId | string |
formSchemaId | string |
Returns
Promise<FormSubmissionWithVersion>
finalizeSinglePage()
finalizeSinglePage(submissionId: string, input: {
data: FormDataRecord;
visitedStepKeys: string[];
}): Promise<FormSubmissionWithVersion>;Defined in: server/forms/form-submission-service.ts:808
Single-page-mode finalization: commit the whole form in one call,
skipping per-step advanceStep. Server-side validation is
authoritative; the client's check is a nicety.
Used when the schema's renderMode is single-page — the form is
still authored as steps + transitions so we can reuse the publish
validator and DAG checks, but at runtime the user fills every field
at once and the renderer never advances through them.
Parameters
| Parameter | Type |
|---|---|
submissionId | string |
input | { data: FormDataRecord; visitedStepKeys: string[]; } |
input.data | FormDataRecord |
input.visitedStepKeys | string[] |
Returns
Promise<FormSubmissionWithVersion>
getActiveDraftForUser()
getActiveDraftForUser(userId: string, formSchemaId: string): Promise<FormSubmissionWithVersion | null>;Defined in: server/forms/form-submission-service.ts:92
Returns the user's in-flight draft for formSchemaId, or null if
none. Pairs with createDraft for callers that want to
distinguish "user has a draft to resume" from "fresh start" before
mutating — createDraft would also transparently resume an
existing draft, but the explicit lookup lets UIs surface the
resume state up front instead of silently picking one.
Composed from FormSubmissionRepository.findLatestForUser and FormSubmissionVersionRepository.findActiveDraft; null is returned both when the user has never submitted and when their latest submission has no active draft (already completed, no edit-in-progress).
Parameters
| Parameter | Type |
|---|---|
userId | string |
formSchemaId | string |
Returns
Promise<FormSubmissionWithVersion | null>
getByFormSchemaId()
getByFormSchemaId(formSchemaId: string): Promise<FormSubmission[]>;Defined in: server/forms/form-submission-service.ts:72
Parameters
| Parameter | Type |
|---|---|
formSchemaId | string |
Returns
Promise<FormSubmission[]>
getById()
getById(id: string): Promise<FormSubmission>;Defined in: server/forms/form-submission-service.ts:49
Parameters
| Parameter | Type |
|---|---|
id | string |
Returns
Promise<FormSubmission>
getByIdWithCurrentVersion()
getByIdWithCurrentVersion(id: string): Promise<FormSubmissionWithVersion>;Defined in: server/forms/form-submission-service.ts:54
Parameters
| Parameter | Type |
|---|---|
id | string |
Returns
Promise<FormSubmissionWithVersion>
getByUserId()
getByUserId(userId: string): Promise<FormSubmission[]>;Defined in: server/forms/form-submission-service.ts:67
Parameters
| Parameter | Type |
|---|---|
userId | string |
Returns
Promise<FormSubmission[]>
getDraftForRender()
getDraftForRender(submissionId: string): Promise<{
conditionsTable: ConditionsTable;
entryStepKey: string | null;
renderMode: "wizard" | "single-page";
steps: {
description: string | null;
fields: {
additionalInfo?: {
body?: string;
title?: string;
};
adoptionStatement?: string;
allowedFonts?: string[];
asset?: {
alt?: string;
fileId?: string;
filename?: string;
mimeType?: string;
url?: string;
};
dataSource?: string;
defaultValue?: | string
| {
from: string;
to: string | null;
};
description?: string;
fields?: {
additionalInfo?: {
body?: ...;
title?: ...;
};
adoptionStatement?: string;
allowedFonts?: ...[];
asset?: {
alt?: ...;
fileId?: ...;
filename?: ...;
mimeType?: ...;
url?: ...;
};
dataSource?: string;
defaultValue?: | string
| {
from: ...;
to: ...;
};
description?: string;
format?: string;
label: string;
maxDate?: string;
maxFiles?: number;
maxLength?: number;
minDate?: string;
name: string;
options?: ...[];
placeholder?: string;
prefillFrom?: string;
required: boolean;
showRange?: boolean;
showTime?: boolean;
signatureMode?: "typed" | "drawn";
timezone?: string;
type: | "number"
| "date"
| "file"
| "email"
| "url"
| "select"
| "text"
| "checkbox"
| "textarea"
| "phone"
| "radio-group"
| "multiselect"
| "field-array"
| "image"
| "file-download"
| "section-header"
| "section-unset"
| "signature"
| "signature-adopted";
}[];
format?: string;
label: string;
maxDate?: string;
maxFiles?: number;
maxLength?: number;
maxRows?: number;
minDate?: string;
minRows?: number;
name: string;
options?: (
| string
| {
description?: ... | ...;
value: string;
})[];
placeholder?: string;
prefillFrom?: string;
required: boolean;
showRange?: boolean;
showTime?: boolean;
signatureMode?: "typed" | "drawn";
timezone?: string;
type: | "number"
| "date"
| "file"
| "email"
| "url"
| "select"
| "text"
| "checkbox"
| "textarea"
| "phone"
| "radio-group"
| "multiselect"
| "field-array"
| "image"
| "file-download"
| "section-header"
| "section-unset"
| "signature"
| "signature-adopted";
}[];
formSchemaVersionId: string;
id: string;
key: string;
label: string | null;
}[];
submission: FormSubmissionWithVersion;
transitions: FormStepTransitionWithKey[];
}>;Defined in: server/forms/form-submission-service.ts:885
Single-call convenience for the renderer: returns the active draft
with the steps, transitions (pre-joined with fromKey/toKey plus
resolved conditionLogic from the pinned rule version), the
conditions lookup table referenced by those transitions, and the
schema's render mode.
Throws FormNotFoundError("ActiveDraft", id) if there's no
in-flight draft on the submission.
Parameters
| Parameter | Type |
|---|---|
submissionId | string |
Returns
Promise<{
conditionsTable: ConditionsTable;
entryStepKey: string | null;
renderMode: "wizard" | "single-page";
steps: {
description: string | null;
fields: {
additionalInfo?: {
body?: string;
title?: string;
};
adoptionStatement?: string;
allowedFonts?: string[];
asset?: {
alt?: string;
fileId?: string;
filename?: string;
mimeType?: string;
url?: string;
};
dataSource?: string;
defaultValue?: | string
| {
from: string;
to: string | null;
};
description?: string;
fields?: {
additionalInfo?: {
body?: ...;
title?: ...;
};
adoptionStatement?: string;
allowedFonts?: ...[];
asset?: {
alt?: ...;
fileId?: ...;
filename?: ...;
mimeType?: ...;
url?: ...;
};
dataSource?: string;
defaultValue?: | string
| {
from: ...;
to: ...;
};
description?: string;
format?: string;
label: string;
maxDate?: string;
maxFiles?: number;
maxLength?: number;
minDate?: string;
name: string;
options?: ...[];
placeholder?: string;
prefillFrom?: string;
required: boolean;
showRange?: boolean;
showTime?: boolean;
signatureMode?: "typed" | "drawn";
timezone?: string;
type: | "number"
| "date"
| "file"
| "email"
| "url"
| "select"
| "text"
| "checkbox"
| "textarea"
| "phone"
| "radio-group"
| "multiselect"
| "field-array"
| "image"
| "file-download"
| "section-header"
| "section-unset"
| "signature"
| "signature-adopted";
}[];
format?: string;
label: string;
maxDate?: string;
maxFiles?: number;
maxLength?: number;
maxRows?: number;
minDate?: string;
minRows?: number;
name: string;
options?: (
| string
| {
description?: ... | ...;
value: string;
})[];
placeholder?: string;
prefillFrom?: string;
required: boolean;
showRange?: boolean;
showTime?: boolean;
signatureMode?: "typed" | "drawn";
timezone?: string;
type: | "number"
| "date"
| "file"
| "email"
| "url"
| "select"
| "text"
| "checkbox"
| "textarea"
| "phone"
| "radio-group"
| "multiselect"
| "field-array"
| "image"
| "file-download"
| "section-header"
| "section-unset"
| "signature"
| "signature-adopted";
}[];
formSchemaVersionId: string;
id: string;
key: string;
label: string | null;
}[];
submission: FormSubmissionWithVersion;
transitions: FormStepTransitionWithKey[];
}>
getSubmissionPrefill()
getSubmissionPrefill(userId: string, formSchemaId: string): Promise<
| CrossVersionPrefillResult
| null>;Defined in: server/forms/form-submission-service.ts:116
Prefill values for a user's next submission of a form schema. Locates the user's most recent submission, and either passes the data through (same schema version) or runs cross-version prefill against the current schema (different version).
Returns null if the user has no previous submission for this schema.
Parameters
| Parameter | Type |
|---|---|
userId | string |
formSchemaId | string |
Returns
Promise<
| CrossVersionPrefillResult
| null>
goToPreviousStep()
goToPreviousStep(submissionId: string): Promise<FormSubmissionWithVersion>;Defined in: server/forms/form-submission-service.ts:632
Wizard back-navigation: pop the current step off visitedStepKeys
and re-pin currentStepKey to the new tail. Field data on the
popped step is left on data so a forward re-walk along the same
path re-hydrates the inputs; if the user re-routes across a
branching transition, submitDraft / finalizeSinglePage's
visited-path filter strips the orphaned answers from the validated
payload.
Refuses to navigate back from the entry step (only key in the
visited stack). Throws FormNotFoundError("ActiveDraft", id) if
there's no in-flight draft, and FormValidationError if already
at the first step.
Parameters
| Parameter | Type |
|---|---|
submissionId | string |
Returns
Promise<FormSubmissionWithVersion>
setUserEditing()
setUserEditing(id: string, allowed: boolean): Promise<FormSubmission>;Defined in: server/forms/form-submission-service.ts:367
Override whether this specific submission allows user editing. Takes
precedence over the schema's allowUserEditing default. Callers that
expose editing UIs should gate on FormSubmission.allowUserEditingOverride.
Parameters
| Parameter | Type |
|---|---|
id | string |
allowed | boolean |
Returns
Promise<FormSubmission>
softDelete()
softDelete(id: string): Promise<FormSubmission>;Defined in: server/forms/form-submission-service.ts:357
Parameters
| Parameter | Type |
|---|---|
id | string |
Returns
Promise<FormSubmission>
submitDraft()
submitDraft(submissionId: string, input?: {
stepData?: FormDataRecord;
}): Promise<FormSubmissionWithVersion>;Defined in: server/forms/form-submission-service.ts:701
Submit a multi-step draft.
Terminal-step data: advanceStep refuses to walk past a terminal
step (no outgoing transitions), so the terminal step's field values
never reach the draft via the wizard's normal merge path. Pass them
here as stepData and they're validated against the terminal
step's schema, merged into the draft data, and persisted before
whole-form revalidation runs. Omit stepData only when the
terminal step has no fields (e.g. a pure confirmation page).
Whole-form revalidation runs against the visited path (only the
fields the user actually saw). Orphaned answers — answers belonging
to fields on non-visited steps, e.g. when the user backtracked
across a branching decision — are preserved on data for audit but
stripped from the validated payload.
Refuses to submit from a non-terminal step (one with outgoing
transitions). Fires afterSubmissionCreated on success.
Parameters
| Parameter | Type |
|---|---|
submissionId | string |
input? | { stepData?: FormDataRecord; } |
input.stepData? | FormDataRecord |
Returns
Promise<FormSubmissionWithVersion>
transaction()
protected transaction<T>(fn: (deps: FormFeatureDeps) => Promise<T>): Promise<T>;Defined in: server/forms/base-form-service.ts:11
Type Parameters
| Type Parameter |
|---|
T |
Parameters
| Parameter | Type |
|---|---|
fn | (deps: FormFeatureDeps) => Promise<T> |
Returns
Promise<T>
Inherited from
update()
update(id: string, input: {
changeReason?: string;
data: Record<string, unknown>;
formSchemaVersionId: string;
}): Promise<FormSubmissionWithVersion>;Defined in: server/forms/form-submission-service.ts:259
Parameters
| Parameter | Type |
|---|---|
id | string |
input | { changeReason?: string; data: Record<string, unknown>; formSchemaVersionId: string; } |
input.changeReason? | string |
input.data | Record<string, unknown> |
input.formSchemaVersionId | string |
Returns
Promise<FormSubmissionWithVersion>