@getrheo/flow-runtime 1.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/agentPrompt/index.d.ts +72 -0
- package/dist/agentPrompt/index.js +739 -0
- package/dist/agentPrompt/index.js.map +1 -0
- package/dist/aiFlowGenerationMerge.d.ts +32 -0
- package/dist/aiFlowGenerationMerge.js +120 -0
- package/dist/aiFlowGenerationMerge.js.map +1 -0
- package/dist/animations.d.ts +110 -0
- package/dist/animations.js +312 -0
- package/dist/animations.js.map +1 -0
- package/dist/assignment.d.ts +7 -0
- package/dist/assignment.js +25 -0
- package/dist/assignment.js.map +1 -0
- package/dist/brandGradient.d.ts +57 -0
- package/dist/brandGradient.js +137 -0
- package/dist/brandGradient.js.map +1 -0
- package/dist/brandGradientManifestIssues.d.ts +11 -0
- package/dist/brandGradientManifestIssues.js +302 -0
- package/dist/brandGradientManifestIssues.js.map +1 -0
- package/dist/buildFlowPreview.d.ts +7 -0
- package/dist/buildFlowPreview.js +81 -0
- package/dist/buildFlowPreview.js.map +1 -0
- package/dist/buttonVariantChrome.d.ts +26 -0
- package/dist/buttonVariantChrome.js +59 -0
- package/dist/buttonVariantChrome.js.map +1 -0
- package/dist/checkboxGlyphStyle.d.ts +31 -0
- package/dist/checkboxGlyphStyle.js +241 -0
- package/dist/checkboxGlyphStyle.js.map +1 -0
- package/dist/choiceOptionSelection.d.ts +11 -0
- package/dist/choiceOptionSelection.js +120 -0
- package/dist/choiceOptionSelection.js.map +1 -0
- package/dist/colorAlpha.d.ts +8 -0
- package/dist/colorAlpha.js +48 -0
- package/dist/colorAlpha.js.map +1 -0
- package/dist/counterLayer.d.ts +42 -0
- package/dist/counterLayer.js +95 -0
- package/dist/counterLayer.js.map +1 -0
- package/dist/decisionEval.d.ts +27 -0
- package/dist/decisionEval.js +197 -0
- package/dist/decisionEval.js.map +1 -0
- package/dist/dropShadow.d.ts +26 -0
- package/dist/dropShadow.js +76 -0
- package/dist/dropShadow.js.map +1 -0
- package/dist/emailPasswordAuthValidation.d.ts +16 -0
- package/dist/emailPasswordAuthValidation.js +25 -0
- package/dist/emailPasswordAuthValidation.js.map +1 -0
- package/dist/flowBuilderRules.d.ts +15 -0
- package/dist/flowBuilderRules.js +368 -0
- package/dist/flowBuilderRules.js.map +1 -0
- package/dist/flowGraph.d.ts +19 -0
- package/dist/flowGraph.js +373 -0
- package/dist/flowGraph.js.map +1 -0
- package/dist/hyperlinkLabel.d.ts +19 -0
- package/dist/hyperlinkLabel.js +232 -0
- package/dist/hyperlinkLabel.js.map +1 -0
- package/dist/index.d.ts +48 -0
- package/dist/index.js +4200 -0
- package/dist/index.js.map +1 -0
- package/dist/interpolateTemplate.d.ts +44 -0
- package/dist/interpolateTemplate.js +188 -0
- package/dist/interpolateTemplate.js.map +1 -0
- package/dist/layerRotate.d.ts +10 -0
- package/dist/layerRotate.js +9 -0
- package/dist/layerRotate.js.map +1 -0
- package/dist/layerTypography.d.ts +36 -0
- package/dist/layerTypography.js +68 -0
- package/dist/layerTypography.js.map +1 -0
- package/dist/layers.d.ts +69 -0
- package/dist/layers.js +257 -0
- package/dist/layers.js.map +1 -0
- package/dist/layout/index.d.ts +57 -0
- package/dist/layout/index.js +151 -0
- package/dist/layout/index.js.map +1 -0
- package/dist/manifestBillingSlice.d.ts +17 -0
- package/dist/manifestBillingSlice.js +102 -0
- package/dist/manifestBillingSlice.js.map +1 -0
- package/dist/prepareAiGeneratedScreen.d.ts +17 -0
- package/dist/prepareAiGeneratedScreen.js +99 -0
- package/dist/prepareAiGeneratedScreen.js.map +1 -0
- package/dist/publish-exports.json +166 -0
- package/dist/responsive/breakpoints.d.ts +34 -0
- package/dist/responsive/breakpoints.js +52 -0
- package/dist/responsive/breakpoints.js.map +1 -0
- package/dist/responsive/index.d.ts +8 -0
- package/dist/responsive/index.js +307 -0
- package/dist/responsive/index.js.map +1 -0
- package/dist/responsive/layerResolve.d.ts +43 -0
- package/dist/responsive/layerResolve.js +168 -0
- package/dist/responsive/layerResolve.js.map +1 -0
- package/dist/responsive/merge.d.ts +19 -0
- package/dist/responsive/merge.js +74 -0
- package/dist/responsive/merge.js.map +1 -0
- package/dist/responsive/previewSafeAreaInsets.d.ts +14 -0
- package/dist/responsive/previewSafeAreaInsets.js +24 -0
- package/dist/responsive/previewSafeAreaInsets.js.map +1 -0
- package/dist/responsive/screenContainerResolve.d.ts +11 -0
- package/dist/responsive/screenContainerResolve.js +122 -0
- package/dist/responsive/screenContainerResolve.js.map +1 -0
- package/dist/responsive/screenShellInsets.d.ts +11 -0
- package/dist/responsive/screenShellInsets.js +26 -0
- package/dist/responsive/screenShellInsets.js.map +1 -0
- package/dist/restingMotion.d.ts +167 -0
- package/dist/restingMotion.js +484 -0
- package/dist/restingMotion.js.map +1 -0
- package/dist/rheoAgentManifestMerge.d.ts +33 -0
- package/dist/rheoAgentManifestMerge.js +55 -0
- package/dist/rheoAgentManifestMerge.js.map +1 -0
- package/dist/scaleInputStyle.d.ts +35 -0
- package/dist/scaleInputStyle.js +77 -0
- package/dist/scaleInputStyle.js.map +1 -0
- package/dist/scaleValidation.d.ts +9 -0
- package/dist/scaleValidation.js +21 -0
- package/dist/scaleValidation.js.map +1 -0
- package/dist/stateMachine.d.ts +105 -0
- package/dist/stateMachine.js +674 -0
- package/dist/stateMachine.js.map +1 -0
- package/dist/stepResponse-BXgoZ7o-.d.ts +112 -0
- package/dist/textInputValidation.d.ts +14 -0
- package/dist/textInputValidation.js +46 -0
- package/dist/textInputValidation.js.map +1 -0
- package/dist/translationPlaceholders.d.ts +9 -0
- package/dist/translationPlaceholders.js +52 -0
- package/dist/translationPlaceholders.js.map +1 -0
- package/dist/validation.d.ts +31 -0
- package/dist/validation.js +233 -0
- package/dist/validation.js.map +1 -0
- package/package.json +242 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/stateMachine/stepResponse.ts","../src/stateMachine/flowSession.ts","../src/layers.ts","../src/decisionEval.ts","../src/stateMachine/graphLanding.ts","../src/stateMachine/flowAdvance.ts","../src/stateMachine/flowTerminal.ts"],"names":["nextResponses","landing","key","oauthLoginResponseKey","emailPasswordAuthResponseKey","nextRaw"],"mappings":"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","file":"stateMachine.js","sourcesContent":["\n\nimport type {\n AppReviewOutcome,\n EmailPasswordAuthMode,\n OsPermissionKey,\n OAuthLoginProvider,\n PermissionOutcome,\n} from '@getrheo/contracts/layers';\nimport type {\n NormalizedSurfaceOutcome,\n} from '@getrheo/contracts/externalSurfaces';\n\n/** Reserved-key patch the SDK can merge into the session when an external surface resolves. */\nexport type SurfaceSdkKeyPatch = Record<string, string | number | boolean>;\n\n/** Stable response key used to store an external surface outcome for analytics. */\nexport const externalSurfaceResponseKey = (nodeId: string): string => `surface_${nodeId}`;\n\n/** Input/capture payloads merged when Skip or End flow consumes the screen draft. */\nexport type ConsumedDraftPayload =\n | { kind: 'choice'; choiceId: string }\n | { kind: 'multiChoice'; choiceIds: string[] }\n | { kind: 'text'; value: string; classification: 'safe' | 'sensitive' }\n | { kind: 'scale'; value: number }\n | { kind: 'cta'; action: 'primary' | 'secondary' }\n | { kind: 'carousel' };\n\n/** Payloads issued when advancing a step (excludes {@link screen_commit}). */\nexport type StepResponseCore =\n | { kind: 'choice'; choiceId: string }\n | { kind: 'multiChoice'; choiceIds: string[] }\n | { kind: 'text'; value: string; classification: 'safe' | 'sensitive' }\n | { kind: 'scale'; value: number }\n | { kind: 'checkbox'; fieldKey: string; value: boolean }\n | { kind: 'cta'; action: 'primary' | 'secondary' }\n | { kind: 'carousel' }\n | { kind: 'skip'; consumedDraft?: ConsumedDraftPayload }\n | { kind: 'end_flow'; consumedDraft?: ConsumedDraftPayload }\n /** Recorded under the screen's `fieldKey` when Skip / Go to screen leaves a manual-submit input empty. */\n | { kind: 'bypass_input'; via: 'skip' | 'go_to_screen' }\n | { kind: 'go_to_screen'; screenId: string }\n | {\n kind: 'permission_outcome';\n layerId: string;\n permissionKey: OsPermissionKey;\n outcome: PermissionOutcome;\n }\n | {\n kind: 'app_review_outcome';\n layerId: string;\n outcome: AppReviewOutcome;\n }\n | {\n kind: 'oauth_login_resolve';\n layerId: string;\n provider: OAuthLoginProvider;\n success: boolean;\n customerExternalId?: string;\n error?: unknown;\n }\n | {\n kind: 'email_password_auth_resolve';\n layerId: string;\n fieldKey: string;\n mode: EmailPasswordAuthMode;\n email: string;\n password: string;\n confirmPassword?: string;\n success: boolean;\n error?: unknown;\n }\n | {\n /** Resolved when an external surface (e.g. RevenueCat paywall) finishes. */\n kind: 'external_surface_outcome';\n nodeId: string;\n outcome: NormalizedSurfaceOutcome;\n /** Reserved SDK keys merged into the session (e.g. `onb_rc_last_product_id`). */\n sdkKeyPatch?: SurfaceSdkKeyPatch;\n }\n | { kind: 'go_back'; fallbackScreenId?: string };\n\n/** Single user or SDK action on the flow (may bundle checkbox snapshots on Continue). */\nexport type StepResponse =\n | StepResponseCore\n | {\n kind: 'screen_commit';\n primary: StepResponseCore;\n checkboxValues: Record<string, boolean>;\n /** Input draft captured alongside a non-input primary (e.g. `app_review_outcome`). */\n capturedDraft?: ConsumedDraftPayload;\n };\n\nexport const isEligibleConsumedDraft = (r: StepResponse): r is ConsumedDraftPayload => {\n switch (r.kind) {\n case 'text':\n case 'choice':\n case 'multiChoice':\n case 'scale':\n case 'cta':\n case 'carousel':\n return true;\n default:\n return false;\n }\n};\n","import type { FlowManifest } from '@getrheo/contracts/manifest';\nimport type { Screen } from '@getrheo/contracts/screens';\n\n\n\n\nimport type {\n ExternalSurfaceNode,\n} from '@getrheo/contracts/externalSurfaces';\n\nimport type { DecisionEvaluationTelemetry } from '../decisionEval.js';\nimport type { StepResponse } from './stepResponse.js';\n\nexport type FlowSessionContext = {\n locale: string;\n platform: string;\n sdkAttributes: Record<string, unknown>;\n};\n\nexport type FlowState = {\n manifest: FlowManifest;\n currentScreenId: string | null;\n /**\n * Non-null while the flow is awaiting an outcome from an external surface\n * (e.g. RevenueCat paywall). `currentScreenId` is null in this state so the\n * native renderer doesn't try to paint a screen.\n */\n pendingExternalSurface: { nodeId: string } | null;\n history: string[];\n /** Responses keyed by `fieldKey` (or screen id for non-input responses like CTA/skip). */\n responses: Record<string, StepResponse>;\n session: FlowSessionContext;\n status: 'idle' | 'running' | 'completed' | 'abandoned';\n startedAt: string | null;\n completedAt: string | null;\n};\n\nexport type SubmitResponseOptions = {\n now?: string;\n onDecisionEvaluated?: (payload: DecisionEvaluationTelemetry) => void;\n};\n\n\nexport const findScreen = (manifest: FlowManifest, screenId: string): Screen | undefined =>\n manifest.screens.find((s) => s.id === screenId) as Screen | undefined;\n\nexport const findExternalSurface = (\n manifest: FlowManifest,\n nodeId: string,\n): ExternalSurfaceNode | undefined =>\n // Older / hand-constructed manifests may omit `externalSurfaceNodes` entirely;\n // treat that as \"no surfaces\" rather than crashing the state machine.\n (manifest.externalSurfaceNodes ?? []).find((n) => n.id === nodeId);\n\nexport const initFlowState = (\n manifest: FlowManifest,\n sessionPartial?: Partial<FlowSessionContext>,\n): FlowState => ({\n manifest,\n currentScreenId: null,\n pendingExternalSurface: null,\n history: [],\n responses: {},\n session: {\n locale: sessionPartial?.locale ?? manifest.defaultLocale,\n platform: sessionPartial?.platform ?? 'unknown',\n sdkAttributes: sessionPartial?.sdkAttributes ?? {},\n },\n status: 'idle',\n startedAt: null,\n completedAt: null,\n});\n","import type { Branding } from '@getrheo/contracts/dashboard';\nimport type { FlowManifest, Theme } from '@getrheo/contracts/manifest';\nimport type { Screen } from '@getrheo/contracts/screens';\nimport {\n brandGradientFromThemedColor,\n brandGradientNativeLinear,\n brandGradientSolidFallback,\n isStoredLinearGradientCss,\n nativeLinearFromAngleAndStops,\n parseLinearGradientCss,\n resolveBrandGradientToken,\n type BrandGradientNativeLinear,\n} from './brandGradient';\nimport type {\n InputLayer,\n Layer,\n MultipleChoiceLayer,\n ScaleInputLayer,\n SingleChoiceLayer,\n StackLayer,\n TextInputLayer,\n ThemedColor,\n} from '@getrheo/contracts/layers';\nimport type { LocalizedText } from '@getrheo/contracts/localized';\nimport { resolveLocalizedText } from '@getrheo/contracts/localized';\nimport { isInputLayer } from '@getrheo/contracts/layers';\n\n/** Walk a layer tree depth-first. */\nexport const walkLayers = (root: Layer, fn: (l: Layer, depth: number) => void): void => {\n const visit = (l: Layer, depth: number): void => {\n fn(l, depth);\n if (l.kind === 'stack') l.children.forEach((c) => visit(c, depth + 1));\n else if (l.kind === 'carousel') l.slides.forEach((c) => visit(c, depth + 1));\n else if (l.kind === 'button') l.children.forEach((c) => visit(c, depth + 1));\n else if (l.kind === 'back_button') l.children.forEach((c) => visit(c, depth + 1));\n else if (l.kind === 'hyperlink') l.children.forEach((c) => visit(c, depth + 1));\n else if (l.kind === 'single_choice' || l.kind === 'multiple_choice') {\n l.children.forEach((c) => visit(c, depth + 1));\n } else if (l.kind === 'text_input' || l.kind === 'scale_input') {\n l.children?.forEach((c) => visit(c, depth + 1));\n } else if (l.kind === 'oauth_login') {\n l.children.forEach((c) => visit(c, depth + 1));\n } else if (l.kind === 'oauth_provider' && l.variant === 'custom') {\n l.children.forEach((c) => visit(c, depth + 1));\n } else if (l.kind === 'email_password_auth') {\n l.children.forEach((c) => visit(c, depth + 1));\n } else if (l.kind === 'email_password_field') {\n l.children?.forEach((c) => visit(c, depth + 1));\n } else if (l.kind === 'email_password_submit') {\n l.children.forEach((c) => visit(c, depth + 1));\n }\n };\n visit(root, 0);\n};\n\n/** Walk every layer in a screen's regions (header → body → footer). */\nexport const walkScreen = (screen: Screen, fn: (l: Layer) => void): void => {\n if (screen.regions.header) walkLayers(screen.regions.header, fn);\n walkLayers(screen.regions.body, fn);\n if (screen.regions.footer) walkLayers(screen.regions.footer, fn);\n};\n\n/** Find the screen's lone input layer (if any). Schema enforces ≤1. */\nexport const findInputLayer = (screen: Screen): InputLayer | null => {\n let found: InputLayer | null = null;\n walkScreen(screen, (l) => {\n if (!found && isInputLayer(l)) found = l;\n });\n return found;\n};\n\n/** Input kinds that use a screen draft and require an explicit Continue to submit. */\nexport const findManualSubmitInputLayer = (\n screen: Screen,\n): MultipleChoiceLayer | TextInputLayer | ScaleInputLayer | null => {\n const input = findInputLayer(screen);\n if (!input) return null;\n if (input.kind === 'multiple_choice' || input.kind === 'text_input' || input.kind === 'scale_input') {\n return input;\n }\n return null;\n};\n\n/**\n * Whether the screen contains any Button layer that submits the screen\n * (i.e. `action.kind === 'continue'`). Used by input layers to decide\n * between auto-submit-on-tap (legacy behaviour for choice-only screens)\n * and writing into the screen-level draft for a Button to submit.\n */\nexport const screenHasContinueButton = (screen: Screen): boolean => {\n let found = false;\n walkScreen(screen, (l) => {\n if (l.kind === 'button' && l.action.kind === 'continue') found = true;\n });\n return found;\n};\n\n/**\n * Resolve a choice layer's option stack by stable optionId via its\n * binding. Returns null when the binding is missing or the bound child\n * was removed (manifest validation rejects that, but runtime stays safe).\n */\nexport const findOptionStackForChoice = (\n layer: SingleChoiceLayer | MultipleChoiceLayer,\n optionId: string,\n): StackLayer | null => {\n const binding = layer.optionBindings.find((b) => b.optionId === optionId);\n if (!binding) return null;\n const stack = layer.children.find((c) => c.id === binding.rootLayerId);\n return stack ?? null;\n};\n\n/**\n * Best-effort textual label for a choice option, used by interpolation\n * (e.g. `{{ goal }}` rendering the chosen option's label) and by editor\n * surfaces that show option rows. Walks the option's child subtree\n * depth-first and returns the first `text` layer's content; falls back\n * to the option's stable id when no text is present.\n */\nexport const choiceOptionLabel = (\n layer: SingleChoiceLayer | MultipleChoiceLayer,\n optionId: string,\n locale: string,\n): string => {\n const stack = findOptionStackForChoice(layer, optionId);\n if (!stack) return '';\n let foundText: LocalizedText | null = null;\n walkLayers(stack, (l) => {\n if (foundText) return;\n if (l.kind === 'text') foundText = l.text;\n });\n if (foundText) return resolveLocalizedText(foundText, locale);\n return optionId;\n};\n\n/** Find a layer in a screen by id, including nested children/slides. */\nexport const findLayerById = (screen: Screen, id: string): Layer | null => {\n let found: Layer | null = null;\n walkScreen(screen, (l) => {\n if (!found && l.id === id) found = l;\n });\n return found;\n};\n\n/** Collect all input fieldKeys across a manifest. */\nexport const collectFieldKeys = (manifest: FlowManifest): { fieldKey: string; screenId: string }[] => {\n const out: { fieldKey: string; screenId: string }[] = [];\n for (const screen of manifest.screens) {\n walkScreen(screen as unknown as Screen, (l) => {\n if (isInputLayer(l)) out.push({ fieldKey: l.fieldKey, screenId: screen.id });\n if (l.kind === 'checkbox') out.push({ fieldKey: l.fieldKey, screenId: screen.id });\n if (l.kind === 'email_password_auth') {\n out.push({ fieldKey: l.fieldKey, screenId: screen.id });\n }\n });\n }\n return out;\n};\n\n/**\n * Pick a snake_case field key starting from `base` that is not in `used`\n * (e.g. `text` → `text_2` → `text_3` when `text` is taken).\n */\nexport const nextUniqueFieldKey = (base: string, used: Iterable<string>): string => {\n const set = used instanceof Set ? used : new Set(used);\n if (!set.has(base)) return base;\n let n = 2;\n while (set.has(`${base}_${n}`)) n += 1;\n return `${base}_${n}`;\n};\n\n/**\n * Resolve a token reference like `$primary` to a literal value from `theme`.\n * Pass-through for non-token strings; returns undefined for `undefined`.\n */\nexport const resolveTokens = <T extends string | undefined>(\n theme: Theme | undefined,\n value: T,\n): T | string => {\n if (value === undefined) return value;\n if (typeof value !== 'string' || !value.startsWith('$')) return value;\n const key = value.slice(1) as keyof Theme;\n const literal = theme?.[key];\n if (typeof literal === 'string') return literal;\n return value;\n};\n\n/**\n * Resolve a layer color for the current appearance (`light` | `dark`).\n * Plain string uses `resolveTokens` for both modes (legacy). Object form\n * picks `light` / `dark` with fallback to the other key when one is omitted.\n */\nexport const resolveThemedColor = (\n theme: Theme | undefined,\n palette: 'light' | 'dark',\n value: ThemedColor | undefined,\n): string | undefined => {\n if (value === undefined) return undefined;\n if (typeof value === 'string') return resolveTokens(theme, value) as string;\n const raw = palette === 'dark' ? (value.dark ?? value.light) : (value.light ?? value.dark);\n if (raw === undefined) return undefined;\n return resolveTokens(theme, raw) as string;\n};\n\n/**\n * Resolve a themed value used for CSS `background` (or RN background fill).\n * Supports `$brandGradient:<uuid>` when branding presets are provided; other values match {@link resolveThemedColor}.\n */\nexport const resolveThemedBackground = (\n theme: Theme | undefined,\n branding: Branding | undefined,\n palette: 'light' | 'dark',\n value: ThemedColor | undefined,\n): string | undefined => {\n if (value === undefined) return undefined;\n if (typeof value === 'string') {\n if (value.startsWith('$brandGradient:')) {\n return resolveBrandGradientToken(branding, value);\n }\n return resolveTokens(theme, value) as string;\n }\n const raw = palette === 'dark' ? (value.dark ?? value.light) : (value.light ?? value.dark);\n if (raw === undefined) return undefined;\n if (raw.startsWith('$brandGradient:')) {\n return resolveBrandGradientToken(branding, raw);\n }\n return resolveTokens(theme, raw) as string;\n};\n\nexport const nativeBrandBackgroundFromThemedColor = (\n theme: Theme | undefined,\n branding: Branding | undefined,\n palette: 'light' | 'dark',\n value: ThemedColor | undefined,\n): { solid?: string; linear?: BrandGradientNativeLinear } => {\n const preset = brandGradientFromThemedColor(branding, palette, value);\n if (preset) {\n const lin = brandGradientNativeLinear(preset);\n if (lin) return { linear: lin };\n return { solid: brandGradientSolidFallback(preset) };\n }\n const bg = resolveThemedBackground(theme, branding, palette, value) as string | undefined;\n if (!bg) return {};\n const parsed = parseLinearGradientCss(bg);\n if (parsed) {\n return {\n linear: nativeLinearFromAngleAndStops(\n parsed.angleDeg,\n parsed.stops.map((s) => ({ color: s.color, offsetPct: s.offsetPct })),\n ),\n };\n }\n if (isStoredLinearGradientCss(bg)) {\n const first = bg.match(/#[0-9a-fA-F]{3,8}/);\n return { solid: first ? first[0] : '#808080' };\n }\n return { solid: bg };\n};\n","import type { FlowManifest } from '@getrheo/contracts/manifest';\nimport type { DecisionExpr, DecisionNode, FlowJumpTarget } from '@getrheo/contracts/decisions';\n\nexport type DecisionEvaluationTelemetry = {\n decisionNodeId: string;\n /** Matched segment id, or null when no case matched (else branch). */\n matchedCaseId: string | null;\n clauseDigest: string;\n};\n\nexport const findDecisionNode = (manifest: FlowManifest, id: string): DecisionNode | undefined =>\n (manifest.decisionNodes ?? []).find((d) => d.id === id);\n\nexport const decisionTargetIds = (manifest: FlowManifest): Set<string> =>\n new Set((manifest.decisionNodes ?? []).map((d) => d.id));\n\nconst stableSerialize = (value: unknown): string => {\n if (value === null || typeof value !== 'object') return JSON.stringify(value);\n if (Array.isArray(value)) return `[${value.map(stableSerialize).join(',')}]`;\n const keys = Object.keys(value as Record<string, unknown>).sort();\n const parts = keys.map((k) => `${JSON.stringify(k)}:${stableSerialize((value as Record<string, unknown>)[k])}`);\n return `{${parts.join(',')}}`;\n};\n\n/** Stable digest of the expression shape and literal predicate values (not runtime answers). */\nexport const digestDecisionExpression = (expr: DecisionExpr): string => {\n const s = stableSerialize(expr);\n let h = 5381;\n for (let i = 0; i < s.length; i += 1) {\n h = (h * 33) ^ s.charCodeAt(i)!;\n }\n return `d${(h >>> 0).toString(16)}`;\n};\n\ntype EvalCtx = {\n locale: string;\n platform: string;\n sdkAttributes: Record<string, unknown>;\n responses: Record<string, unknown>;\n};\n\nconst responseForField = (\n fieldKey: string,\n responses: Record<string, unknown>,\n): unknown => responses[fieldKey];\n\nconst normalizeResponseValue = (r: unknown): unknown => {\n if (!r || typeof r !== 'object') return undefined;\n const o = r as Record<string, unknown>;\n switch (o.kind) {\n case 'choice':\n return typeof o.choiceId === 'string' ? o.choiceId : undefined;\n case 'multiChoice':\n return Array.isArray(o.choiceIds) ? o.choiceIds : undefined;\n case 'text':\n return typeof o.value === 'string' ? o.value : undefined;\n case 'scale':\n return typeof o.value === 'number' ? o.value : undefined;\n case 'checkbox':\n return typeof o.value === 'boolean' ? o.value : undefined;\n default:\n return undefined;\n }\n};\nconst normalizeScalarForStringPred = (raw: unknown): string | undefined => {\n if (raw === undefined || raw === null) return undefined;\n if (typeof raw === 'string') return raw;\n if (typeof raw === 'number' && Number.isFinite(raw)) return String(raw);\n return undefined;\n};\n\nconst normalizeNumber = (raw: unknown): number | undefined => {\n if (typeof raw !== 'number' || !Number.isFinite(raw)) return undefined;\n return raw;\n};\n\nconst normalizeChoiceId = (raw: unknown): string | undefined =>\n typeof raw === 'string' && raw.length > 0 ? raw : undefined;\n\nconst normalizeChoiceIds = (raw: unknown): string[] | undefined => {\n if (!Array.isArray(raw)) return undefined;\n const ids = raw.filter((x): x is string => typeof x === 'string' && x.length > 0);\n return ids;\n};\n\nconst normalizeBoolean = (raw: unknown): boolean | undefined => {\n if (typeof raw === 'boolean') return raw;\n if (typeof raw === 'number' && Number.isFinite(raw)) return raw !== 0;\n if (typeof raw === 'string') {\n const s = raw.trim().toLowerCase();\n if (s === 'true' || s === '1' || s === 'yes') return true;\n if (s === 'false' || s === '0' || s === 'no') return false;\n }\n return undefined;\n};\n\ntype PredicateVariable = Extract<DecisionExpr, { kind: 'predicate' }>['variable'];\n\nconst resolveVariableValue = (variable: PredicateVariable, ctx: EvalCtx): unknown => {\n if (variable.kind === 'builtin') {\n if (variable.name === 'locale') return ctx.locale;\n return ctx.platform;\n }\n if (variable.kind === 'sdk') return ctx.sdkAttributes[variable.key];\n const r = responseForField(variable.fieldKey, ctx.responses);\n return normalizeResponseValue(r);\n};\n\nconst evalStringPred = (left: string, pred: { op: string; value: string }): boolean => {\n switch (pred.op) {\n case 'eq':\n return left === pred.value;\n case 'neq':\n return left !== pred.value;\n case 'contains':\n return left.includes(pred.value);\n default:\n return false;\n }\n};\n\nconst evalNumberPred = (left: number, pred: { op: string; value: number }): boolean => {\n switch (pred.op) {\n case 'eq':\n return left === pred.value;\n case 'neq':\n return left !== pred.value;\n case 'lt':\n return left < pred.value;\n case 'lte':\n return left <= pred.value;\n case 'gt':\n return left > pred.value;\n case 'gte':\n return left >= pred.value;\n default:\n return false;\n }\n};\n\nconst evalChoicePred = (\n choiceId: string,\n pred:\n | { op: 'eq'; optionId: string }\n | { op: 'one_of'; optionIds: string[] },\n): boolean => {\n if (pred.op === 'eq') return choiceId === pred.optionId;\n return pred.optionIds.includes(choiceId);\n};\n\nconst setIntersect = (a: string[], b: string[]): string[] => {\n const bs = new Set(b);\n return a.filter((x) => bs.has(x));\n};\n\nconst evalBooleanPred = (\n left: boolean,\n pred: { op: 'eq' | 'neq'; value: boolean },\n): boolean => {\n if (pred.op === 'eq') return left === pred.value;\n return left !== pred.value;\n};\n\nconst evalMultiPred = (\n selected: string[],\n pred:\n | { op: 'intersects'; optionIds: string[] }\n | { op: 'contains_all'; optionIds: string[] }\n | { op: 'subset_of'; optionIds: string[] },\n): boolean => {\n const required = pred.optionIds;\n switch (pred.op) {\n case 'intersects':\n return setIntersect(selected, required).length > 0;\n case 'contains_all': {\n const sel = new Set(selected);\n return required.every((id) => sel.has(id));\n }\n case 'subset_of': {\n const allow = new Set(required);\n return selected.every((id) => allow.has(id));\n }\n default:\n return false;\n }\n};\n\nexport const evaluateDecisionExpression = (expr: DecisionExpr, ctx: EvalCtx): boolean => {\n if (expr.kind === 'empty') return false;\n if (expr.kind === 'group') {\n if (expr.op === 'and') {\n for (const c of expr.children) {\n if (!evaluateDecisionExpression(c, ctx)) return false;\n }\n return true;\n }\n for (const c of expr.children) {\n if (evaluateDecisionExpression(c, ctx)) return true;\n }\n return false;\n }\n\n const raw = resolveVariableValue(expr.variable, ctx);\n const { predicate } = expr;\n\n switch (predicate.type) {\n case 'string': {\n const s = normalizeScalarForStringPred(raw);\n if (s === undefined) return false;\n return evalStringPred(s, predicate.pred);\n }\n case 'number': {\n const n = normalizeNumber(raw);\n if (n === undefined) return false;\n return evalNumberPred(n, predicate.pred);\n }\n case 'choice': {\n const id = normalizeChoiceId(raw);\n if (!id) return false;\n return evalChoicePred(id, predicate.pred);\n }\n case 'multi': {\n const ids = normalizeChoiceIds(raw);\n if (!ids) return false;\n return evalMultiPred(ids, predicate.pred);\n }\n case 'boolean': {\n const b = normalizeBoolean(raw);\n if (b === undefined) return false;\n return evalBooleanPred(b, predicate.pred);\n }\n default:\n return false;\n }\n};\n\nexport const evaluateDecisionNode = (\n node: DecisionNode,\n ctx: EvalCtx,\n): { matchedCaseId: string | null; next: FlowJumpTarget; clauseDigest: string } => {\n for (const c of node.cases) {\n if (evaluateDecisionExpression(c.expression, ctx)) {\n return {\n matchedCaseId: c.id,\n next: c.next,\n clauseDigest: digestDecisionExpression(c.expression),\n };\n }\n }\n return {\n matchedCaseId: null,\n next: node.elseNext,\n clauseDigest: 'else',\n };\n};\n","import type { FlowManifest } from '@getrheo/contracts/manifest';\nimport type { Screen } from '@getrheo/contracts/screens';\nimport {\n OS_PERMISSION_OUTCOME_CONTINUE,\n OS_PERMISSION_OUTCOME_END,\n appReviewCaptureFieldKey,\n emailPasswordAuthResponseKey,\n oauthLoginResponseKey,\n permissionCaptureFieldKey,\n} from '@getrheo/contracts/layers';\n\n\n\n\n\nimport { findInputLayer, findLayerById } from '../layers.js';\nimport { evaluateDecisionNode, findDecisionNode } from '../decisionEval.js';\nimport type { DecisionEvaluationTelemetry } from '../decisionEval.js';\nimport type { FlowSessionContext, FlowState } from './flowSession.js';\nimport { findExternalSurface } from './flowSession.js';\nimport type { StepResponse } from './stepResponse.js';\n\n/**\n * Result of walking the manifest from a cursor id past decision nodes:\n * either we landed on a screen (renderable), an external surface (await\n * outcome), or fell off the graph (flow complete).\n */\nexport type GraphLanding =\n | { kind: 'screen'; screenId: string }\n | { kind: 'surface'; nodeId: string }\n | { kind: 'end' };\n\nconst resolveOsPermissionDestination = (\n screen: Screen,\n response: Extract<StepResponse, { kind: 'permission_outcome' }>,\n): string | null => {\n const layer = findLayerById(screen, response.layerId);\n if (!layer || layer.kind !== 'button' || layer.action.kind !== 'request_os_permission')\n return null;\n if (layer.action.permissionKey !== response.permissionKey) return null;\n const target = layer.action.outcomes[response.outcome];\n if (target === OS_PERMISSION_OUTCOME_END) return null;\n if (target === OS_PERMISSION_OUTCOME_CONTINUE) return screen.next.default ?? null;\n return target;\n};\n\nexport const resolveNextScreenId = (screen: Screen, response: StepResponse): string | null => {\n if (response.kind === 'screen_commit') {\n return resolveNextScreenId(screen, response.primary);\n }\n if (response.kind === 'go_to_screen') return response.screenId;\n\n if (response.kind === 'permission_outcome') {\n const nextId = resolveOsPermissionDestination(screen, response);\n return nextId ?? screen.next.default ?? null;\n }\n\n if (response.kind === 'app_review_outcome') {\n const layer = findLayerById(screen, response.layerId);\n if (!layer || layer.kind !== 'button' || layer.action.kind !== 'request_app_review') {\n return screen.next.default ?? null;\n }\n return screen.next.default ?? null;\n }\n\n if (response.kind === 'oauth_login_resolve') {\n return screen.next.default ?? null;\n }\n\n if (response.kind === 'email_password_auth_resolve') {\n return screen.next.default ?? null;\n }\n\n const input = findInputLayer(screen);\n if (\n input &&\n (input.kind === 'single_choice' || input.kind === 'multiple_choice') &&\n input.branching.enabled\n ) {\n if (response.kind === 'choice') {\n const m = input.branching.conditions.find((c) => c.choiceId === response.choiceId);\n if (m) return m.goTo;\n } else if (response.kind === 'multiChoice') {\n const m = input.branching.conditions.find((c) => response.choiceIds.includes(c.choiceId));\n if (m) return m.goTo;\n }\n }\n return screen.next.default ?? null;\n};\n\nexport const resolveThroughGraph = (\n manifest: FlowManifest,\n cursor: string | null,\n responses: Record<string, StepResponse>,\n session: FlowSessionContext,\n onDecisionEvaluated?: (payload: DecisionEvaluationTelemetry) => void,\n): GraphLanding => {\n let cur = cursor;\n const evalCtx = {\n locale: session.locale,\n platform: session.platform,\n sdkAttributes: session.sdkAttributes,\n responses: responses as Record<string, unknown>,\n };\n while (cur) {\n const dn = findDecisionNode(manifest, cur);\n if (!dn) break;\n const evalResult = evaluateDecisionNode(dn, evalCtx);\n onDecisionEvaluated?.({\n decisionNodeId: dn.id,\n matchedCaseId: evalResult.matchedCaseId,\n clauseDigest: evalResult.clauseDigest,\n });\n cur = evalResult.next;\n if (cur == null) break;\n }\n if (cur == null) return { kind: 'end' };\n if (findExternalSurface(manifest, cur)) return { kind: 'surface', nodeId: cur };\n return { kind: 'screen', screenId: cur };\n};\n\n/** Determine the storage key for a response on a given screen. Input layers\n * use their `fieldKey`; others use the screen id (for analytics breadcrumbs). */\nexport const responseKeyFor = (screen: Screen, response: StepResponse): string => {\n if (\n response.kind === 'text' ||\n response.kind === 'choice' ||\n response.kind === 'multiChoice' ||\n response.kind === 'scale' ||\n response.kind === 'checkbox'\n ) {\n const input = findInputLayer(screen);\n if (input) return input.fieldKey;\n }\n if (response.kind === 'permission_outcome') return permissionCaptureFieldKey(response.permissionKey);\n if (response.kind === 'app_review_outcome') return appReviewCaptureFieldKey(response.layerId);\n if (response.kind === 'checkbox') return response.fieldKey;\n if (response.kind === 'oauth_login_resolve') return oauthLoginResponseKey(response.layerId);\n if (response.kind === 'email_password_auth_resolve') {\n return emailPasswordAuthResponseKey(response.layerId);\n }\n return screen.id;\n};\n\n/** Apply a surface landing to a state update (history + pending flag). */\nexport const applyGraphLanding = (\n base: FlowState,\n landing: GraphLanding,\n nextResponses: Record<string, StepResponse>,\n now: string,\n): FlowState => {\n if (landing.kind === 'end') {\n return {\n ...base,\n responses: nextResponses,\n currentScreenId: null,\n pendingExternalSurface: null,\n status: 'completed',\n completedAt: now,\n };\n }\n if (landing.kind === 'surface') {\n return {\n ...base,\n responses: nextResponses,\n currentScreenId: null,\n pendingExternalSurface: { nodeId: landing.nodeId },\n history: [...base.history, landing.nodeId],\n };\n }\n return {\n ...base,\n responses: nextResponses,\n currentScreenId: landing.screenId,\n pendingExternalSurface: null,\n history: [...base.history, landing.screenId],\n };\n};\n","import {\n emailPasswordAuthResponseKey,\n oauthLoginResponseKey,\n} from '@getrheo/contracts/layers';\n\n\n\n\n\nimport { EXTERNAL_SURFACE_NO_NEXT } from '@getrheo/contracts/decisions';\nimport { findManualSubmitInputLayer } from '../layers.js';\nimport type { DecisionEvaluationTelemetry } from '../decisionEval.js';\nimport type { FlowState, FlowSessionContext, SubmitResponseOptions } from './flowSession.js';\nimport { findExternalSurface, findScreen } from './flowSession.js';\nimport {\n applyGraphLanding,\n resolveNextScreenId,\n resolveThroughGraph,\n responseKeyFor,\n} from './graphLanding.js';\nimport type { StepResponse } from './stepResponse.js';\nimport { externalSurfaceResponseKey } from './stepResponse.js';\n\nexport type { DecisionEvaluationTelemetry } from '../decisionEval.js';\n\nexport type StartFlowOptions = {\n now?: string;\n onDecisionEvaluated?: (payload: DecisionEvaluationTelemetry) => void;\n};\n\nexport const startFlow = (\n state: FlowState,\n second?: string | StartFlowOptions,\n): FlowState => {\n const opts: StartFlowOptions = typeof second === 'string' ? { now: second } : second ?? {};\n const now = opts.now ?? new Date().toISOString();\n const entry = state.manifest.entryScreenId;\n if (entry == null) {\n return {\n ...state,\n status: 'idle',\n currentScreenId: null,\n pendingExternalSurface: null,\n history: [],\n startedAt: null,\n completedAt: null,\n };\n }\n\n // Walk decisions starting at entry so a flow can begin on a decision or surface.\n // With no responses yet, decision branches that depend on responses fall through\n // to their `false` branch — same behaviour as evaluating a missing field today.\n const landing = resolveThroughGraph(\n state.manifest,\n entry,\n {},\n {\n ...state.session,\n },\n opts.onDecisionEvaluated,\n );\n\n if (landing.kind === 'end') {\n return {\n ...state,\n status: 'completed',\n currentScreenId: null,\n pendingExternalSurface: null,\n history: [entry],\n startedAt: now,\n completedAt: now,\n };\n }\n if (landing.kind === 'surface') {\n return {\n ...state,\n status: 'running',\n currentScreenId: null,\n pendingExternalSurface: { nodeId: landing.nodeId },\n history: [landing.nodeId],\n startedAt: now,\n };\n }\n return {\n ...state,\n status: 'running',\n currentScreenId: landing.screenId,\n pendingExternalSurface: null,\n history: [landing.screenId],\n startedAt: now,\n };\n};\n\nexport const submitResponse = (\n state: FlowState,\n response: StepResponse,\n third?: string | SubmitResponseOptions,\n): FlowState => {\n const opts: SubmitResponseOptions = typeof third === 'string' ? { now: third } : third ?? {};\n const now = opts.now ?? new Date().toISOString();\n\n if (state.status !== 'running') return state;\n\n // Surface outcomes are the only response kind valid while pending on a surface.\n if (response.kind === 'external_surface_outcome') {\n const pending = state.pendingExternalSurface;\n if (!pending || pending.nodeId !== response.nodeId) return state;\n const surface = findExternalSurface(state.manifest, pending.nodeId);\n if (!surface) return state;\n\n const nextSession: FlowSessionContext = response.sdkKeyPatch\n ? {\n ...state.session,\n sdkAttributes: { ...state.session.sdkAttributes, ...response.sdkKeyPatch },\n }\n : state.session;\n\n const target = surface.outcomes[response.outcome] ?? surface.fallback;\n const nextResponses = {\n ...state.responses,\n [externalSurfaceResponseKey(pending.nodeId)]: response,\n };\n if (target === EXTERNAL_SURFACE_NO_NEXT) {\n return {\n ...state,\n session: nextSession,\n responses: nextResponses,\n pendingExternalSurface: null,\n currentScreenId: null,\n status: 'completed',\n completedAt: now,\n };\n }\n const landing = resolveThroughGraph(\n state.manifest,\n target,\n nextResponses,\n nextSession,\n opts.onDecisionEvaluated,\n );\n return applyGraphLanding(\n { ...state, session: nextSession },\n landing,\n nextResponses,\n now,\n );\n }\n\n if (!state.currentScreenId) return state;\n const screen = findScreen(state.manifest, state.currentScreenId);\n if (!screen) return state;\n\n if (response.kind === 'screen_commit') {\n const mergedResponses = { ...state.responses };\n for (const [fk, value] of Object.entries(response.checkboxValues)) {\n mergedResponses[fk] = { kind: 'checkbox', fieldKey: fk, value };\n }\n if (response.capturedDraft) {\n mergedResponses[responseKeyFor(screen, response.capturedDraft)] = response.capturedDraft;\n }\n return submitResponse({ ...state, responses: mergedResponses }, response.primary, opts);\n }\n\n if (response.kind === 'go_back') {\n const fallback = response.fallbackScreenId;\n if (state.history.length > 1) {\n const nextHistory = state.history.slice(0, -1);\n const prevId = nextHistory[nextHistory.length - 1];\n if (!prevId) return state;\n return {\n ...state,\n currentScreenId: prevId,\n history: nextHistory,\n };\n }\n if (fallback && findScreen(state.manifest, fallback)) {\n return {\n ...state,\n currentScreenId: fallback,\n history: [fallback],\n };\n }\n return state;\n }\n\n if (response.kind === 'oauth_login_resolve' && !response.success) {\n const key = oauthLoginResponseKey(response.layerId);\n return {\n ...state,\n responses: { ...state.responses, [key]: response },\n };\n }\n\n if (response.kind === 'email_password_auth_resolve' && !response.success) {\n const key = emailPasswordAuthResponseKey(response.layerId);\n return {\n ...state,\n responses: { ...state.responses, [key]: response },\n };\n }\n\n if (response.kind === 'end_flow') {\n const nextResponses = { ...state.responses };\n if (response.consumedDraft) {\n nextResponses[responseKeyFor(screen, response.consumedDraft)] = response.consumedDraft;\n }\n nextResponses[responseKeyFor(screen, { kind: 'end_flow' })] = { kind: 'end_flow' };\n return {\n ...state,\n responses: nextResponses,\n currentScreenId: null,\n status: 'completed',\n completedAt: now,\n };\n }\n\n if (response.kind === 'skip') {\n const nextResponses = { ...state.responses };\n const manualInput = findManualSubmitInputLayer(screen);\n if (manualInput) {\n nextResponses[manualInput.fieldKey] = { kind: 'bypass_input', via: 'skip' };\n }\n nextResponses[responseKeyFor(screen, { kind: 'skip' })] = { kind: 'skip' };\n const nextRaw = resolveNextScreenId(screen, { kind: 'skip' });\n const landing = resolveThroughGraph(\n state.manifest,\n nextRaw,\n nextResponses,\n state.session,\n opts.onDecisionEvaluated,\n );\n return applyGraphLanding(state, landing, nextResponses, now);\n }\n\n const key = responseKeyFor(screen, response);\n const nextResponses = { ...state.responses, [key]: response };\n if (response.kind === 'go_to_screen') {\n const manualInput = findManualSubmitInputLayer(screen);\n if (manualInput) {\n nextResponses[manualInput.fieldKey] = { kind: 'bypass_input', via: 'go_to_screen' };\n }\n }\n const nextRaw = resolveNextScreenId(screen, response);\n\n const landing = resolveThroughGraph(\n state.manifest,\n nextRaw,\n nextResponses,\n state.session,\n opts.onDecisionEvaluated,\n );\n return applyGraphLanding(state, landing, nextResponses, now);\n};\n","import type { EmailPasswordAuthMode, OAuthLoginProvider } from '@getrheo/contracts/layers';\nimport type { NormalizedSurfaceOutcome } from '@getrheo/contracts/externalSurfaces';\nimport type { FlowState } from './flowSession.js';\nimport type { StepResponse } from './stepResponse.js';\n\nconst TERMINAL_EXPORT_AUTH_RESPONSE_KEY_PREFIXES = ['oauth:', 'email_pw:'] as const;\n\n/** Response map keys produced by OAuth / email-password layers (see `oauthLoginResponseKey`, `emailPasswordAuthResponseKey`). */\nexport const isAuthTerminalExportResponseKey = (key: string): boolean =>\n TERMINAL_EXPORT_AUTH_RESPONSE_KEY_PREFIXES.some((prefix) => key.startsWith(prefix));\n\n/** Copy of `responses` without OAuth / email-password auth entries (hosts use auth provider callbacks for those). */\nexport const stripAuthResponsesForTerminalExport = (\n responses: Record<string, StepResponse>,\n): Record<string, StepResponse> => {\n const out: Record<string, StepResponse> = {};\n for (const [k, v] of Object.entries(responses)) {\n if (isAuthTerminalExportResponseKey(k)) continue;\n out[k] = v;\n }\n return out;\n};\n\n/** Values stored under each field key in {@link buildCompletionResponses} / terminal `answers`. */\nexport type FlowTerminalAnswerEntryValue =\n | string\n | string[]\n | number\n | { value: string; classification: string }\n | { success: boolean; customerExternalId?: string; provider: OAuthLoginProvider }\n | { success: boolean; mode: EmailPasswordAuthMode; email: string }\n | { bypassed: true; via: 'skip' | 'go_to_screen' }\n | { outcome: NormalizedSurfaceOutcome }\n | boolean\n | 'end_flow'\n | 'skip'\n | 'carousel'\n | { goToScreen: string };\n\n/**\n * Maps one stored {@link StepResponse} to a JSON-safe completion value.\n * `screen_commit` should not appear in `FlowState.responses` (it unwraps in `submitResponse`).\n */\nexport const stepResponseToCompletionValue = (\n r: StepResponse,\n): FlowTerminalAnswerEntryValue | undefined => {\n if (r.kind === 'screen_commit') return undefined;\n switch (r.kind) {\n case 'choice':\n return r.choiceId;\n case 'multiChoice':\n return r.choiceIds;\n case 'text':\n return { value: r.value, classification: r.classification };\n case 'scale':\n return r.value;\n case 'checkbox':\n return r.value;\n case 'cta':\n return r.action;\n case 'carousel':\n return 'carousel';\n case 'end_flow':\n return 'end_flow';\n case 'skip':\n return 'skip';\n case 'permission_outcome':\n return r.outcome;\n case 'app_review_outcome':\n return r.outcome;\n case 'oauth_login_resolve':\n return {\n success: r.success,\n customerExternalId: r.customerExternalId,\n provider: r.provider,\n };\n case 'email_password_auth_resolve':\n return {\n success: r.success,\n mode: r.mode,\n email: r.email,\n };\n case 'bypass_input':\n return { bypassed: true, via: r.via };\n case 'external_surface_outcome':\n return { outcome: r.outcome };\n case 'go_to_screen':\n return { goToScreen: r.screenId };\n case 'go_back':\n return undefined;\n default: {\n const _never: never = r;\n return _never;\n }\n }\n};\n\nexport const buildCompletionResponses = (\n state: FlowState,\n): Record<string, FlowTerminalAnswerEntryValue> => {\n const out: Record<string, FlowTerminalAnswerEntryValue> = {};\n for (const [key, r] of Object.entries(state.responses)) {\n const v = stepResponseToCompletionValue(r);\n if (v !== undefined) out[key] = v;\n }\n return out;\n};\n\n/** Normalized `answers` map in {@link FlowTerminalSnapshot} (from {@link buildCompletionResponses}). */\nexport type FlowTerminalAnswerMap = ReturnType<typeof buildCompletionResponses>;\n\nexport const abandonFlow = (\n state: FlowState,\n now: string = new Date().toISOString(),\n): FlowState => ({\n ...state,\n status: 'abandoned',\n completedAt: now,\n});\n"]}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { OsPermissionKey, PermissionOutcome, AppReviewOutcome, OAuthLoginProvider, EmailPasswordAuthMode } from '@getrheo/contracts/layers';
|
|
2
|
+
import { NormalizedSurfaceOutcome } from '@getrheo/contracts/externalSurfaces';
|
|
3
|
+
|
|
4
|
+
/** Reserved-key patch the SDK can merge into the session when an external surface resolves. */
|
|
5
|
+
type SurfaceSdkKeyPatch = Record<string, string | number | boolean>;
|
|
6
|
+
/** Stable response key used to store an external surface outcome for analytics. */
|
|
7
|
+
declare const externalSurfaceResponseKey: (nodeId: string) => string;
|
|
8
|
+
/** Input/capture payloads merged when Skip or End flow consumes the screen draft. */
|
|
9
|
+
type ConsumedDraftPayload = {
|
|
10
|
+
kind: 'choice';
|
|
11
|
+
choiceId: string;
|
|
12
|
+
} | {
|
|
13
|
+
kind: 'multiChoice';
|
|
14
|
+
choiceIds: string[];
|
|
15
|
+
} | {
|
|
16
|
+
kind: 'text';
|
|
17
|
+
value: string;
|
|
18
|
+
classification: 'safe' | 'sensitive';
|
|
19
|
+
} | {
|
|
20
|
+
kind: 'scale';
|
|
21
|
+
value: number;
|
|
22
|
+
} | {
|
|
23
|
+
kind: 'cta';
|
|
24
|
+
action: 'primary' | 'secondary';
|
|
25
|
+
} | {
|
|
26
|
+
kind: 'carousel';
|
|
27
|
+
};
|
|
28
|
+
/** Payloads issued when advancing a step (excludes {@link screen_commit}). */
|
|
29
|
+
type StepResponseCore = {
|
|
30
|
+
kind: 'choice';
|
|
31
|
+
choiceId: string;
|
|
32
|
+
} | {
|
|
33
|
+
kind: 'multiChoice';
|
|
34
|
+
choiceIds: string[];
|
|
35
|
+
} | {
|
|
36
|
+
kind: 'text';
|
|
37
|
+
value: string;
|
|
38
|
+
classification: 'safe' | 'sensitive';
|
|
39
|
+
} | {
|
|
40
|
+
kind: 'scale';
|
|
41
|
+
value: number;
|
|
42
|
+
} | {
|
|
43
|
+
kind: 'checkbox';
|
|
44
|
+
fieldKey: string;
|
|
45
|
+
value: boolean;
|
|
46
|
+
} | {
|
|
47
|
+
kind: 'cta';
|
|
48
|
+
action: 'primary' | 'secondary';
|
|
49
|
+
} | {
|
|
50
|
+
kind: 'carousel';
|
|
51
|
+
} | {
|
|
52
|
+
kind: 'skip';
|
|
53
|
+
consumedDraft?: ConsumedDraftPayload;
|
|
54
|
+
} | {
|
|
55
|
+
kind: 'end_flow';
|
|
56
|
+
consumedDraft?: ConsumedDraftPayload;
|
|
57
|
+
}
|
|
58
|
+
/** Recorded under the screen's `fieldKey` when Skip / Go to screen leaves a manual-submit input empty. */
|
|
59
|
+
| {
|
|
60
|
+
kind: 'bypass_input';
|
|
61
|
+
via: 'skip' | 'go_to_screen';
|
|
62
|
+
} | {
|
|
63
|
+
kind: 'go_to_screen';
|
|
64
|
+
screenId: string;
|
|
65
|
+
} | {
|
|
66
|
+
kind: 'permission_outcome';
|
|
67
|
+
layerId: string;
|
|
68
|
+
permissionKey: OsPermissionKey;
|
|
69
|
+
outcome: PermissionOutcome;
|
|
70
|
+
} | {
|
|
71
|
+
kind: 'app_review_outcome';
|
|
72
|
+
layerId: string;
|
|
73
|
+
outcome: AppReviewOutcome;
|
|
74
|
+
} | {
|
|
75
|
+
kind: 'oauth_login_resolve';
|
|
76
|
+
layerId: string;
|
|
77
|
+
provider: OAuthLoginProvider;
|
|
78
|
+
success: boolean;
|
|
79
|
+
customerExternalId?: string;
|
|
80
|
+
error?: unknown;
|
|
81
|
+
} | {
|
|
82
|
+
kind: 'email_password_auth_resolve';
|
|
83
|
+
layerId: string;
|
|
84
|
+
fieldKey: string;
|
|
85
|
+
mode: EmailPasswordAuthMode;
|
|
86
|
+
email: string;
|
|
87
|
+
password: string;
|
|
88
|
+
confirmPassword?: string;
|
|
89
|
+
success: boolean;
|
|
90
|
+
error?: unknown;
|
|
91
|
+
} | {
|
|
92
|
+
/** Resolved when an external surface (e.g. RevenueCat paywall) finishes. */
|
|
93
|
+
kind: 'external_surface_outcome';
|
|
94
|
+
nodeId: string;
|
|
95
|
+
outcome: NormalizedSurfaceOutcome;
|
|
96
|
+
/** Reserved SDK keys merged into the session (e.g. `onb_rc_last_product_id`). */
|
|
97
|
+
sdkKeyPatch?: SurfaceSdkKeyPatch;
|
|
98
|
+
} | {
|
|
99
|
+
kind: 'go_back';
|
|
100
|
+
fallbackScreenId?: string;
|
|
101
|
+
};
|
|
102
|
+
/** Single user or SDK action on the flow (may bundle checkbox snapshots on Continue). */
|
|
103
|
+
type StepResponse = StepResponseCore | {
|
|
104
|
+
kind: 'screen_commit';
|
|
105
|
+
primary: StepResponseCore;
|
|
106
|
+
checkboxValues: Record<string, boolean>;
|
|
107
|
+
/** Input draft captured alongside a non-input primary (e.g. `app_review_outcome`). */
|
|
108
|
+
capturedDraft?: ConsumedDraftPayload;
|
|
109
|
+
};
|
|
110
|
+
declare const isEligibleConsumedDraft: (r: StepResponse) => r is ConsumedDraftPayload;
|
|
111
|
+
|
|
112
|
+
export { type ConsumedDraftPayload as C, type StepResponse as S, type StepResponseCore as a, type SurfaceSdkKeyPatch as b, externalSurfaceResponseKey as e, isEligibleConsumedDraft as i };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { TextInputLayer } from '@getrheo/contracts/layers';
|
|
2
|
+
|
|
3
|
+
type TextInputValidateResult = {
|
|
4
|
+
ok: true;
|
|
5
|
+
} | {
|
|
6
|
+
ok: false;
|
|
7
|
+
reason: string;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* Validate trimmed text for a `text_input` layer (length, required, format by inputType).
|
|
11
|
+
*/
|
|
12
|
+
declare const validateTextInputValue: (layer: TextInputLayer, raw: string) => TextInputValidateResult;
|
|
13
|
+
|
|
14
|
+
export { type TextInputValidateResult, validateTextInputValue };
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
// src/textInputValidation.ts
|
|
2
|
+
var EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/u;
|
|
3
|
+
var PHONE_RE = /^[\d\s+().-]{3,32}$/u;
|
|
4
|
+
var isProbablyUrl = (s) => {
|
|
5
|
+
try {
|
|
6
|
+
const withProto = /^[a-z]+:/iu.test(s) ? s : `https://${s}`;
|
|
7
|
+
const u = new URL(withProto);
|
|
8
|
+
return u.hostname.length > 0;
|
|
9
|
+
} catch {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
var effectiveInputType = (layer) => layer.inputType ?? "plain";
|
|
14
|
+
var effectiveRequired = (layer) => layer.required !== false;
|
|
15
|
+
var validateTextInputValue = (layer, raw) => {
|
|
16
|
+
const trimmed = raw.trim();
|
|
17
|
+
const required = effectiveRequired(layer);
|
|
18
|
+
if (trimmed.length === 0) {
|
|
19
|
+
if (!required) return { ok: true };
|
|
20
|
+
return { ok: false, reason: "Text is empty" };
|
|
21
|
+
}
|
|
22
|
+
if (layer.minLength !== void 0 && trimmed.length < layer.minLength) {
|
|
23
|
+
return { ok: false, reason: `Enter at least ${layer.minLength} characters` };
|
|
24
|
+
}
|
|
25
|
+
if (layer.maxLength !== void 0 && trimmed.length > layer.maxLength) {
|
|
26
|
+
return { ok: false, reason: `Exceeds max length of ${layer.maxLength}` };
|
|
27
|
+
}
|
|
28
|
+
const mode = effectiveInputType(layer);
|
|
29
|
+
switch (mode) {
|
|
30
|
+
case "plain":
|
|
31
|
+
case "multiline":
|
|
32
|
+
return { ok: true };
|
|
33
|
+
case "email":
|
|
34
|
+
return EMAIL_RE.test(trimmed) ? { ok: true } : { ok: false, reason: "Enter a valid email address" };
|
|
35
|
+
case "phone":
|
|
36
|
+
return PHONE_RE.test(trimmed) ? { ok: true } : { ok: false, reason: "Enter a valid phone number (digits and common symbols only)" };
|
|
37
|
+
case "url":
|
|
38
|
+
return isProbablyUrl(trimmed) ? { ok: true } : { ok: false, reason: "Enter a valid URL" };
|
|
39
|
+
default:
|
|
40
|
+
return { ok: true };
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export { validateTextInputValue };
|
|
45
|
+
//# sourceMappingURL=textInputValidation.js.map
|
|
46
|
+
//# sourceMappingURL=textInputValidation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/textInputValidation.ts"],"names":[],"mappings":";AAEA,IAAM,QAAA,GACJ,6BAAA;AAGF,IAAM,QAAA,GAAW,sBAAA;AAEjB,IAAM,aAAA,GAAgB,CAAC,CAAA,KAAuB;AAC5C,EAAA,IAAI;AACF,IAAA,MAAM,YAAY,YAAA,CAAa,IAAA,CAAK,CAAC,CAAA,GAAI,CAAA,GAAI,WAAW,CAAC,CAAA,CAAA;AACzD,IAAA,MAAM,CAAA,GAAI,IAAI,GAAA,CAAI,SAAS,CAAA;AAC3B,IAAA,OAAO,CAAA,CAAE,SAAS,MAAA,GAAS,CAAA;AAAA,EAC7B,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,KAAA;AAAA,EACT;AACF,CAAA;AAIA,IAAM,kBAAA,GAAqB,CAAC,KAAA,KAA0B,KAAA,CAAM,SAAA,IAAa,OAAA;AAEzE,IAAM,iBAAA,GAAoB,CAAC,KAAA,KAAmC,KAAA,CAAM,QAAA,KAAa,KAAA;AAK1E,IAAM,sBAAA,GAAyB,CAAC,KAAA,EAAuB,GAAA,KAAyC;AACrG,EAAA,MAAM,OAAA,GAAU,IAAI,IAAA,EAAK;AACzB,EAAA,MAAM,QAAA,GAAW,kBAAkB,KAAK,CAAA;AAExC,EAAA,IAAI,OAAA,CAAQ,WAAW,CAAA,EAAG;AACxB,IAAA,IAAI,CAAC,QAAA,EAAU,OAAO,EAAE,IAAI,IAAA,EAAK;AACjC,IAAA,OAAO,EAAE,EAAA,EAAI,KAAA,EAAO,MAAA,EAAQ,eAAA,EAAgB;AAAA,EAC9C;AAEA,EAAA,IAAI,MAAM,SAAA,KAAc,MAAA,IAAa,OAAA,CAAQ,MAAA,GAAS,MAAM,SAAA,EAAW;AACrE,IAAA,OAAO,EAAE,EAAA,EAAI,KAAA,EAAO,QAAQ,CAAA,eAAA,EAAkB,KAAA,CAAM,SAAS,CAAA,WAAA,CAAA,EAAc;AAAA,EAC7E;AAEA,EAAA,IAAI,MAAM,SAAA,KAAc,MAAA,IAAa,OAAA,CAAQ,MAAA,GAAS,MAAM,SAAA,EAAW;AACrE,IAAA,OAAO,EAAE,EAAA,EAAI,KAAA,EAAO,QAAQ,CAAA,sBAAA,EAAyB,KAAA,CAAM,SAAS,CAAA,CAAA,EAAG;AAAA,EACzE;AAEA,EAAA,MAAM,IAAA,GAAO,mBAAmB,KAAK,CAAA;AACrC,EAAA,QAAQ,IAAA;AAAM,IACZ,KAAK,OAAA;AAAA,IACL,KAAK,WAAA;AACH,MAAA,OAAO,EAAE,IAAI,IAAA,EAAK;AAAA,IACpB,KAAK,OAAA;AACH,MAAA,OAAO,QAAA,CAAS,IAAA,CAAK,OAAO,CAAA,GACxB,EAAE,EAAA,EAAI,IAAA,EAAK,GACX,EAAE,EAAA,EAAI,KAAA,EAAO,MAAA,EAAQ,6BAAA,EAA8B;AAAA,IACzD,KAAK,OAAA;AACH,MAAA,OAAO,QAAA,CAAS,IAAA,CAAK,OAAO,CAAA,GACxB,EAAE,EAAA,EAAI,IAAA,EAAK,GACX,EAAE,EAAA,EAAI,KAAA,EAAO,MAAA,EAAQ,6DAAA,EAA8D;AAAA,IACzF,KAAK,KAAA;AACH,MAAA,OAAO,aAAA,CAAc,OAAO,CAAA,GAAI,EAAE,EAAA,EAAI,IAAA,EAAK,GAAI,EAAE,EAAA,EAAI,KAAA,EAAO,MAAA,EAAQ,mBAAA,EAAoB;AAAA,IAC1F;AACE,MAAA,OAAO,EAAE,IAAI,IAAA,EAAK;AAAA;AAExB","file":"textInputValidation.js","sourcesContent":["import type { TextInputLayer } from '@getrheo/contracts/layers';\n\nconst EMAIL_RE =\n /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/u;\n\n/** Phone: raw string as typed; allow common dial characters, length bounds. */\nconst PHONE_RE = /^[\\d\\s+().-]{3,32}$/u;\n\nconst isProbablyUrl = (s: string): boolean => {\n try {\n const withProto = /^[a-z]+:/iu.test(s) ? s : `https://${s}`;\n const u = new URL(withProto);\n return u.hostname.length > 0;\n } catch {\n return false;\n }\n};\n\nexport type TextInputValidateResult = { ok: true } | { ok: false; reason: string };\n\nconst effectiveInputType = (layer: TextInputLayer) => layer.inputType ?? 'plain';\n\nconst effectiveRequired = (layer: TextInputLayer): boolean => layer.required !== false;\n\n/**\n * Validate trimmed text for a `text_input` layer (length, required, format by inputType).\n */\nexport const validateTextInputValue = (layer: TextInputLayer, raw: string): TextInputValidateResult => {\n const trimmed = raw.trim();\n const required = effectiveRequired(layer);\n\n if (trimmed.length === 0) {\n if (!required) return { ok: true };\n return { ok: false, reason: 'Text is empty' };\n }\n\n if (layer.minLength !== undefined && trimmed.length < layer.minLength) {\n return { ok: false, reason: `Enter at least ${layer.minLength} characters` };\n }\n\n if (layer.maxLength !== undefined && trimmed.length > layer.maxLength) {\n return { ok: false, reason: `Exceeds max length of ${layer.maxLength}` };\n }\n\n const mode = effectiveInputType(layer);\n switch (mode) {\n case 'plain':\n case 'multiline':\n return { ok: true };\n case 'email':\n return EMAIL_RE.test(trimmed)\n ? { ok: true }\n : { ok: false, reason: 'Enter a valid email address' };\n case 'phone':\n return PHONE_RE.test(trimmed)\n ? { ok: true }\n : { ok: false, reason: 'Enter a valid phone number (digits and common symbols only)' };\n case 'url':\n return isProbablyUrl(trimmed) ? { ok: true } : { ok: false, reason: 'Enter a valid URL' };\n default:\n return { ok: true };\n }\n};\n"]}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tokens that must be preserved verbatim when translating (Liquid `{{ ... }}`
|
|
3
|
+
* tags and simple `{identifier}` placeholders). Used for server-side validation.
|
|
4
|
+
*/
|
|
5
|
+
declare const extractTranslationPlaceholders: (s: string) => string[];
|
|
6
|
+
/** True when both strings contain the same multiset of placeholder markers. */
|
|
7
|
+
declare const translationPlaceholdersMatch: (source: string, translated: string) => boolean;
|
|
8
|
+
|
|
9
|
+
export { extractTranslationPlaceholders, translationPlaceholdersMatch };
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { FIELD_KEY_RE } from '@getrheo/contracts/fields';
|
|
2
|
+
import '@getrheo/contracts/localized';
|
|
3
|
+
import '@getrheo/contracts/layers';
|
|
4
|
+
|
|
5
|
+
// src/interpolateTemplate.ts
|
|
6
|
+
|
|
7
|
+
// src/interpolateTemplate.ts
|
|
8
|
+
var extractLiquidTemplateBodies = (s) => {
|
|
9
|
+
const out = [];
|
|
10
|
+
let i = 0;
|
|
11
|
+
while (i < s.length) {
|
|
12
|
+
const open = s.indexOf("{{", i);
|
|
13
|
+
if (open === -1) break;
|
|
14
|
+
const close = s.indexOf("}}", open + 2);
|
|
15
|
+
if (close === -1) break;
|
|
16
|
+
out.push(s.slice(open + 2, close));
|
|
17
|
+
i = close + 2;
|
|
18
|
+
}
|
|
19
|
+
return out;
|
|
20
|
+
};
|
|
21
|
+
FIELD_KEY_RE.source.replace(/^\^|\$$/g, "");
|
|
22
|
+
|
|
23
|
+
// src/translationPlaceholders.ts
|
|
24
|
+
var sortedJson = (tokens) => JSON.stringify([...tokens].sort());
|
|
25
|
+
var stripLiquidRegions = (s) => {
|
|
26
|
+
let out = "";
|
|
27
|
+
let i = 0;
|
|
28
|
+
while (i < s.length) {
|
|
29
|
+
const open = s.indexOf("{{", i);
|
|
30
|
+
if (open === -1) return out + s.slice(i);
|
|
31
|
+
out += s.slice(i, open);
|
|
32
|
+
const close = s.indexOf("}}", open + 2);
|
|
33
|
+
if (close === -1) return out + s.slice(open);
|
|
34
|
+
i = close + 2;
|
|
35
|
+
}
|
|
36
|
+
return out;
|
|
37
|
+
};
|
|
38
|
+
var extractTranslationPlaceholders = (s) => {
|
|
39
|
+
const liquids = extractLiquidTemplateBodies(s).map((inner) => `{{${inner.trim()}}}`);
|
|
40
|
+
const stripped = stripLiquidRegions(s);
|
|
41
|
+
const singles = [];
|
|
42
|
+
const re = /\{([a-zA-Z_]\w*)\}/g;
|
|
43
|
+
for (const m of stripped.matchAll(re)) {
|
|
44
|
+
singles.push(`{${m[1]}}`);
|
|
45
|
+
}
|
|
46
|
+
return [...liquids, ...singles];
|
|
47
|
+
};
|
|
48
|
+
var translationPlaceholdersMatch = (source, translated) => sortedJson(extractTranslationPlaceholders(source)) === sortedJson(extractTranslationPlaceholders(translated));
|
|
49
|
+
|
|
50
|
+
export { extractTranslationPlaceholders, translationPlaceholdersMatch };
|
|
51
|
+
//# sourceMappingURL=translationPlaceholders.js.map
|
|
52
|
+
//# sourceMappingURL=translationPlaceholders.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/interpolateTemplate.ts","../src/translationPlaceholders.ts"],"names":[],"mappings":";;;;;;;AAwBO,IAAM,2BAAA,GAA8B,CAAC,CAAA,KAAwB;AAClE,EAAA,MAAM,MAAgB,EAAC;AACvB,EAAA,IAAI,CAAA,GAAI,CAAA;AACR,EAAA,OAAO,CAAA,GAAI,EAAE,MAAA,EAAQ;AACnB,IAAA,MAAM,IAAA,GAAO,CAAA,CAAE,OAAA,CAAQ,IAAA,EAAM,CAAC,CAAA;AAC9B,IAAA,IAAI,SAAS,EAAA,EAAI;AACjB,IAAA,MAAM,KAAA,GAAQ,CAAA,CAAE,OAAA,CAAQ,IAAA,EAAM,OAAO,CAAC,CAAA;AACtC,IAAA,IAAI,UAAU,EAAA,EAAI;AAClB,IAAA,GAAA,CAAI,KAAK,CAAA,CAAE,KAAA,CAAM,IAAA,GAAO,CAAA,EAAG,KAAK,CAAC,CAAA;AACjC,IAAA,CAAA,GAAI,KAAA,GAAQ,CAAA;AAAA,EACd;AACA,EAAA,OAAO,GAAA;AACT,CAAA;AAEyB,YAAA,CAAa,MAAA,CAAO,OAAA,CAAQ,YAAY,EAAE;;;ACjCnE,IAAM,UAAA,GAAa,CAAC,MAAA,KAA6B,IAAA,CAAK,SAAA,CAAU,CAAC,GAAG,MAAM,CAAA,CAAE,IAAA,EAAM,CAAA;AAMlF,IAAM,kBAAA,GAAqB,CAAC,CAAA,KAAsB;AAChD,EAAA,IAAI,GAAA,GAAM,EAAA;AACV,EAAA,IAAI,CAAA,GAAI,CAAA;AACR,EAAA,OAAO,CAAA,GAAI,EAAE,MAAA,EAAQ;AACnB,IAAA,MAAM,IAAA,GAAO,CAAA,CAAE,OAAA,CAAQ,IAAA,EAAM,CAAC,CAAA;AAC9B,IAAA,IAAI,SAAS,EAAA,EAAI,OAAO,GAAA,GAAM,CAAA,CAAE,MAAM,CAAC,CAAA;AACvC,IAAA,GAAA,IAAO,CAAA,CAAE,KAAA,CAAM,CAAA,EAAG,IAAI,CAAA;AACtB,IAAA,MAAM,KAAA,GAAQ,CAAA,CAAE,OAAA,CAAQ,IAAA,EAAM,OAAO,CAAC,CAAA;AACtC,IAAA,IAAI,UAAU,EAAA,EAAI,OAAO,GAAA,GAAM,CAAA,CAAE,MAAM,IAAI,CAAA;AAC3C,IAAA,CAAA,GAAI,KAAA,GAAQ,CAAA;AAAA,EACd;AACA,EAAA,OAAO,GAAA;AACT,CAAA;AAMO,IAAM,8BAAA,GAAiC,CAAC,CAAA,KAAwB;AACrE,EAAA,MAAM,OAAA,GAAU,2BAAA,CAA4B,CAAC,CAAA,CAAE,GAAA,CAAI,CAAC,KAAA,KAAU,CAAA,EAAA,EAAK,KAAA,CAAM,IAAA,EAAM,CAAA,EAAA,CAAI,CAAA;AACnF,EAAA,MAAM,QAAA,GAAW,mBAAmB,CAAC,CAAA;AACrC,EAAA,MAAM,UAAoB,EAAC;AAC3B,EAAA,MAAM,EAAA,GAAK,qBAAA;AACX,EAAA,KAAA,MAAW,CAAA,IAAK,QAAA,CAAS,QAAA,CAAS,EAAE,CAAA,EAAG;AACrC,IAAA,OAAA,CAAQ,IAAA,CAAK,CAAA,CAAA,EAAI,CAAA,CAAE,CAAC,CAAC,CAAA,CAAA,CAAG,CAAA;AAAA,EAC1B;AACA,EAAA,OAAO,CAAC,GAAG,OAAA,EAAS,GAAG,OAAO,CAAA;AAChC;AAGO,IAAM,4BAAA,GAA+B,CAAC,MAAA,EAAgB,UAAA,KAC3D,UAAA,CAAW,8BAAA,CAA+B,MAAM,CAAC,CAAA,KACjD,UAAA,CAAW,8BAAA,CAA+B,UAAU,CAAC","file":"translationPlaceholders.js","sourcesContent":["import { FIELD_KEY_RE } from '@getrheo/contracts/fields';\nimport type { FlowManifest } from '@getrheo/contracts/manifest';\nimport type { Screen } from '@getrheo/contracts/screens';\nimport type { LocalizedText } from '@getrheo/contracts/localized';\nimport { resolveLocalizedText } from '@getrheo/contracts/localized';\nimport { choiceOptionLabel, findInputLayer } from './layers';\nimport type { StepResponse } from './stateMachine';\n\n/** Runtime substitution for Text layer copy (after locale resolution). */\nexport type InterpolationRuntimeContext = {\n manifest: FlowManifest;\n locale: string;\n responses: Record<string, StepResponse>;\n customProperties?: Record<string, string>;\n};\n\n/** Props-sized slice passed into renderers. */\nexport type InterpolationContext = {\n responses: Record<string, StepResponse>;\n customProperties?: Record<string, string>;\n /** When true, the flow has a prior step so back navigation is available. */\n canGoBack?: boolean;\n};\n\nexport const extractLiquidTemplateBodies = (s: string): string[] => {\n const out: string[] = [];\n let i = 0;\n while (i < s.length) {\n const open = s.indexOf('{{', i);\n if (open === -1) break;\n const close = s.indexOf('}}', open + 2);\n if (close === -1) break;\n out.push(s.slice(open + 2, close));\n i = close + 2;\n }\n return out;\n};\n\nconst FIELD_KEY_SOURCE = FIELD_KEY_RE.source.replace(/^\\^|\\$$/g, '');\n\nconst parseDefaultFilter = (\n inner: string,\n): { exprPart: string; defaultValue?: string } => {\n const m = inner.match(/\\s*\\|\\s*default\\s*:/i);\n if (!m || m.index === undefined) return { exprPart: inner.trim() };\n\n const exprPart = inner.slice(0, m.index).trim();\n let tail = inner.slice(m.index + m[0].length).trim();\n if (tail.startsWith('\"')) {\n const end = tail.indexOf('\"', 1);\n if (end > 0) tail = tail.slice(1, end);\n else tail = tail.slice(1);\n }\n return { exprPart, defaultValue: tail };\n};\n\nconst parseExpression = (\n exprRaw: string,\n):\n | { kind: 'custom'; key: string }\n | { kind: 'field'; fieldKey: string; mode: 'label' | 'id' }\n | { kind: 'invalid' } => {\n const expr = exprRaw.trim();\n const customM = expr.match(new RegExp(`^custom\\\\.(${FIELD_KEY_SOURCE})$`));\n if (customM) return { kind: 'custom', key: customM[1]! };\n\n const idM = expr.match(new RegExp(`^(${FIELD_KEY_SOURCE})\\\\.id$`));\n if (idM) return { kind: 'field', fieldKey: idM[1]!, mode: 'id' };\n\n const plainM = expr.match(new RegExp(`^(${FIELD_KEY_SOURCE})$`));\n if (plainM) return { kind: 'field', fieldKey: plainM[1]!, mode: 'label' };\n\n return { kind: 'invalid' };\n};\n\nexport type InterpolationExprAnalysis =\n | { kind: 'custom'; key: string }\n | { kind: 'field'; fieldKey: string; mode: 'label' | 'id' }\n | { kind: 'invalid' };\n\n/** Parse one `{{ … }}` inner (after stripping delimiters) for diagnostics / validation. */\nexport const analyzeLiquidTemplateInner = (\n inner: string,\n): { expr: InterpolationExprAnalysis; defaultValue?: string } => {\n const { exprPart, defaultValue } = parseDefaultFilter(inner);\n const p = parseExpression(exprPart);\n if (p.kind === 'invalid') return { expr: { kind: 'invalid' }, defaultValue };\n if (p.kind === 'custom') return { expr: { kind: 'custom', key: p.key }, defaultValue };\n return { expr: { kind: 'field', fieldKey: p.fieldKey, mode: p.mode }, defaultValue };\n};\n\nconst findInputOwner = (\n manifest: FlowManifest,\n fieldKey: string,\n): { screen: Screen; input: NonNullable<ReturnType<typeof findInputLayer>> } | null => {\n for (const screen of manifest.screens) {\n const input = findInputLayer(screen as Screen);\n if (input && input.fieldKey === fieldKey) return { screen: screen as Screen, input };\n }\n return null;\n};\n\nconst choiceLabelFor = (\n manifest: FlowManifest,\n fieldKey: string,\n choiceId: string,\n locale: string,\n): string => {\n const owner = findInputOwner(manifest, fieldKey);\n if (!owner) return '';\n const { input } = owner;\n if (input.kind !== 'single_choice' && input.kind !== 'multiple_choice') return '';\n return choiceOptionLabel(input, choiceId, locale);\n};\n\nconst responseToDisplayString = (\n manifest: FlowManifest,\n fieldKey: string,\n response: StepResponse | undefined,\n mode: 'label' | 'id',\n locale: string,\n): string => {\n if (!response) return '';\n switch (response.kind) {\n case 'text':\n return mode === 'id' ? '' : response.value;\n case 'scale':\n return mode === 'id' ? '' : String(response.value);\n case 'choice':\n if (mode === 'id') return response.choiceId;\n return choiceLabelFor(manifest, fieldKey, response.choiceId, locale);\n case 'multiChoice':\n if (mode === 'id') return response.choiceIds.join(', ');\n return response.choiceIds\n .map((id) => choiceLabelFor(manifest, fieldKey, id, locale))\n .filter(Boolean)\n .join(', ');\n case 'checkbox':\n return mode === 'id' ? '' : response.value ? 'true' : 'false';\n case 'bypass_input':\n return '';\n default:\n return '';\n }\n};\n\nconst evalParsed = (\n parsed:\n | { kind: 'custom'; key: string }\n | { kind: 'field'; fieldKey: string; mode: 'label' | 'id' }\n | { kind: 'invalid' },\n ctx: InterpolationRuntimeContext,\n): string => {\n if (parsed.kind === 'invalid') return '';\n if (parsed.kind === 'custom') {\n const v = ctx.customProperties?.[parsed.key];\n return v === undefined || v === '' ? '' : String(v);\n }\n const owner = findInputOwner(ctx.manifest, parsed.fieldKey);\n const r = ctx.responses[parsed.fieldKey];\n if (parsed.mode === 'id' && owner && owner.input.kind !== 'single_choice' && owner.input.kind !== 'multiple_choice') {\n return '';\n }\n return responseToDisplayString(ctx.manifest, parsed.fieldKey, r, parsed.mode, ctx.locale);\n};\n\n/**\n * Interpolate `{{ … }}` segments in a plain string (already localized).\n * Supports `custom.key`, `field_key`, `field_key.id`, and `| default: …`.\n */\nexport const interpolateTemplateString = (\n template: string,\n ctx: InterpolationRuntimeContext,\n): string => {\n let i = 0;\n let out = '';\n while (i < template.length) {\n const open = template.indexOf('{{', i);\n if (open === -1) {\n out += template.slice(i);\n break;\n }\n out += template.slice(i, open);\n const close = template.indexOf('}}', open + 2);\n if (close === -1) {\n out += template.slice(open);\n break;\n }\n const inner = template.slice(open + 2, close);\n const { exprPart, defaultValue } = parseDefaultFilter(inner);\n const parsed = parseExpression(exprPart);\n let value = evalParsed(parsed, ctx);\n if ((value === '' || value === undefined) && defaultValue !== undefined) {\n value = defaultValue;\n }\n out += value;\n i = close + 2;\n }\n return out;\n};\n\nexport const resolveAndInterpolateLocalizedText = (\n text: LocalizedText,\n ctx: InterpolationRuntimeContext,\n): string => {\n const localized = resolveLocalizedText(text, ctx.locale);\n return interpolateTemplateString(localized, ctx);\n};\n","import { extractLiquidTemplateBodies } from './interpolateTemplate';\n\n/**\n * Serialized placeholder tokens for parity checks (sorted, JSON-stable).\n */\nconst sortedJson = (tokens: string[]): string => JSON.stringify([...tokens].sort());\n\n/**\n * Strips `{{ ... }}` Liquid regions from a string so lone `{foo}` patterns\n * aren't confused with Liquid delimiters.\n */\nconst stripLiquidRegions = (s: string): string => {\n let out = '';\n let i = 0;\n while (i < s.length) {\n const open = s.indexOf('{{', i);\n if (open === -1) return out + s.slice(i);\n out += s.slice(i, open);\n const close = s.indexOf('}}', open + 2);\n if (close === -1) return out + s.slice(open);\n i = close + 2;\n }\n return out;\n};\n\n/**\n * Tokens that must be preserved verbatim when translating (Liquid `{{ ... }}`\n * tags and simple `{identifier}` placeholders). Used for server-side validation.\n */\nexport const extractTranslationPlaceholders = (s: string): string[] => {\n const liquids = extractLiquidTemplateBodies(s).map((inner) => `{{${inner.trim()}}}`);\n const stripped = stripLiquidRegions(s);\n const singles: string[] = [];\n const re = /\\{([a-zA-Z_]\\w*)\\}/g;\n for (const m of stripped.matchAll(re)) {\n singles.push(`{${m[1]}}`);\n }\n return [...liquids, ...singles];\n};\n\n/** True when both strings contain the same multiset of placeholder markers. */\nexport const translationPlaceholdersMatch = (source: string, translated: string): boolean =>\n sortedJson(extractTranslationPlaceholders(source)) ===\n sortedJson(extractTranslationPlaceholders(translated));\n"]}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { FlowManifest } from '@getrheo/contracts';
|
|
2
|
+
|
|
3
|
+
type ManifestValidationIssue = {
|
|
4
|
+
/** Screen id when the issue is screen-scoped, null otherwise. Field name kept as `stepId` for back-compat with API/dashboard wire types. */
|
|
5
|
+
stepId?: string | null;
|
|
6
|
+
path: (string | number)[];
|
|
7
|
+
message: string;
|
|
8
|
+
code: string;
|
|
9
|
+
};
|
|
10
|
+
declare const validateManifest: (data: unknown) => {
|
|
11
|
+
ok: true;
|
|
12
|
+
manifest: FlowManifest;
|
|
13
|
+
} | {
|
|
14
|
+
ok: false;
|
|
15
|
+
issues: ManifestValidationIssue[];
|
|
16
|
+
};
|
|
17
|
+
type ValidatePublishableResult = {
|
|
18
|
+
/** False when there are blocking {@link issues} (empty flow or no completion path). */
|
|
19
|
+
ok: boolean;
|
|
20
|
+
/** Blocking publish issues. */
|
|
21
|
+
issues: ManifestValidationIssue[];
|
|
22
|
+
/**
|
|
23
|
+
* Non-blocking notices (e.g. screens not on any path from entry). The runtime
|
|
24
|
+
* only serves the reachable subgraph; orphans stay in the draft but are not shown.
|
|
25
|
+
*/
|
|
26
|
+
warnings: ManifestValidationIssue[];
|
|
27
|
+
};
|
|
28
|
+
/** Publish-time gate. Runs semantic checks beyond the schema. */
|
|
29
|
+
declare const validatePublishable: (manifest: FlowManifest) => ValidatePublishableResult;
|
|
30
|
+
|
|
31
|
+
export { type ManifestValidationIssue, type ValidatePublishableResult, validateManifest, validatePublishable };
|