@onabl/js 0.3.0 → 0.3.2

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.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { PublicForm, ValidateCodeResponse, Quote, Invoice, PresignResponse, PublicFormField } from '@onabl/contracts/public-api';
2
- export { Invoice, PublicForm, PublicFormConfig, PublicFormField, Quote, ValidateCodeResponse } from '@onabl/contracts/public-api';
2
+ export { Invoice, InvoiceStatus, PublicForm, PublicFormConfig, PublicFormField, Quote, ValidateCodeResponse } from '@onabl/contracts/public-api';
3
3
  import { AnswerMap, DisplayGroup, FormStep } from '@onabl/types/config';
4
4
  import { LineItem } from '@onabl/types/engine';
5
5
 
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { PublicForm, ValidateCodeResponse, Quote, Invoice, PresignResponse, PublicFormField } from '@onabl/contracts/public-api';
2
- export { Invoice, PublicForm, PublicFormConfig, PublicFormField, Quote, ValidateCodeResponse } from '@onabl/contracts/public-api';
2
+ export { Invoice, InvoiceStatus, PublicForm, PublicFormConfig, PublicFormField, Quote, ValidateCodeResponse } from '@onabl/contracts/public-api';
3
3
  import { AnswerMap, DisplayGroup, FormStep } from '@onabl/types/config';
4
4
  import { LineItem } from '@onabl/types/engine';
5
5
 
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../../engine/dist/presentation.js","../../types/dist/config.js","../../engine/dist/expression.js","../../engine/dist/resolver.js","../../engine/dist/date-derival.js","../../engine/dist/variables.js","../../engine/dist/engine.js","../src/index.ts","../src/client.ts","../src/errors.ts","../src/presentation.ts","../src/form-state.ts"],"sourcesContent":["\"use strict\";\n/**\n * The one way a quote breakdown is turned into rows.\n *\n * There were four: the dashboard, the customer quote page, the quote PDF, and\n * the invoice PDF (which had none at all and rendered separately-quoted work as\n * ordinary billable lines). Two of them carried comments claiming to mirror the\n * others; all four had already drifted — one filtered zero-amount rows, another\n * did not; one enforced showOnQuote, another leaked internal lines to customers.\n *\n * Pure derivation over LineItem and DisplayGroup. No I/O, no framework, no\n * currency formatting — callers format, because locale is theirs to decide.\n */\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.shareOfGroup = shareOfGroup;\nexports.groupLineItems = groupLineItems;\nexports.presentQuote = presentQuote;\n/** The share of a line item that belongs to a display group. */\nfunction shareOfGroup(item, tag) {\n return item.groupAmounts?.[tag] ?? (item.tag === tag ? item.amount : 0);\n}\nfunction labelWithFactor(item) {\n if (item.factor === undefined || item.factor === 1)\n return item.label;\n const percent = Math.abs(Math.round((item.factor - 1) * 100));\n return item.factor > 1 ? `${item.label} (+${percent}%)` : `${item.label} (${percent}% off)`;\n}\n/**\n * Splits visible line items into payable rows and separately-quoted sections.\n *\n * `showOnQuote` is enforced here and only here. Zero-amount rows are dropped —\n * a customer should not read a line that costs nothing.\n */\nfunction groupLineItems(lineItems, displayGroups) {\n const visible = lineItems.filter((item) => item.showOnQuote);\n const groupTotals = {};\n if (!displayGroups || displayGroups.length === 0) {\n const main = visible\n .filter((item) => item.amount !== 0)\n .map((item) => ({ key: item.ruleId, label: labelWithFactor(item), amount: item.amount, isGroup: false, sourceItem: item }));\n return { main, separateSections: [], groupTotals };\n }\n const main = [];\n const separateSections = [];\n // How much of each item has already been accounted for — either rendered in a\n // shown group, or removed from the payable total by an excluded one.\n //\n // Accounting per share rather than per item matters: an item split across two\n // groups is only partly handled by either, so claiming the whole item as soon\n // as one group touched it silently dropped the rest of its value from the\n // breakdown while leaving it in the total.\n const accounted = new Map();\n const account = (item, amount) => accounted.set(item.ruleId, (accounted.get(item.ruleId) ?? 0) + amount);\n for (const group of displayGroups) {\n const matching = visible.filter((item) => (item.groupAmounts && group.tag in item.groupAmounts) || item.tag === group.tag);\n const total = matching.reduce((sum, item) => sum + shareOfGroup(item, group.tag), 0);\n groupTotals[group.tag] = total;\n // Hiding a group hides the *grouping*, not the money. Its share stays\n // unaccounted and reappears as an ungrouped row below, so the breakdown\n // still adds up to what the customer is charged. An excluded group is\n // different: its money genuinely leaves the payable total, so its share is\n // accounted for whether or not the section is shown.\n if (group.excludeFromTotal)\n matching.forEach((item) => account(item, shareOfGroup(item, group.tag)));\n if (!group.showOnQuote || matching.length === 0 || total === 0)\n continue;\n if (!group.excludeFromTotal)\n matching.forEach((item) => account(item, shareOfGroup(item, group.tag)));\n const active = matching.filter((item) => shareOfGroup(item, group.tag) !== 0);\n const rowFor = (item) => ({\n key: `${group.tag}:${item.ruleId}`,\n label: item.label,\n amount: shareOfGroup(item, group.tag),\n isGroup: false,\n sourceItem: item,\n groupTag: group.tag,\n });\n let rows;\n if (group.displayMode === \"individual\") {\n rows = active.map(rowFor);\n }\n else if (group.displayMode === \"both\" || group.displayMode === \"both_cashless\") {\n // \"both_cashless\" carries its children like \"both\"; customer-facing\n // renderers omit the per-child amounts. The subtotal is still shown.\n rows = [{ key: group.tag, label: group.label, amount: total, isGroup: true, displayMode: group.displayMode, children: active.map(rowFor), groupTag: group.tag }];\n }\n else {\n // \"grouped\" — a single subtotal row, named after its only item when there is one\n const label = active.length === 1 ? (active[0]?.label ?? group.label) : group.label;\n rows = [{ key: group.tag, label, amount: total, isGroup: true, displayMode: \"grouped\", groupTag: group.tag }];\n }\n if (group.excludeFromTotal)\n separateSections.push({ group, rows, amount: total });\n else\n main.push(...rows);\n }\n // Whatever no group rendered or removed still belongs on the quote.\n for (const item of visible) {\n const remaining = Math.round((item.amount - (accounted.get(item.ruleId) ?? 0)) * 100) / 100;\n if (remaining === 0)\n continue;\n main.push({ key: item.ruleId, label: labelWithFactor(item), amount: remaining, isGroup: false, sourceItem: item });\n }\n return { main, separateSections, groupTotals };\n}\n/**\n * Builds the complete display model for a quote or invoice.\n *\n * The discount is always the difference between the two stored totals, never\n * re-derived from a percentage and a base. Re-deriving is how the invoice PDF\n * came to print a discount computed off the already-discounted figure, and how\n * both PDFs could show two discount lines when only one had been applied.\n */\nfunction presentQuote(input) {\n const { main, separateSections } = groupLineItems(input.lineItems, input.displayGroups);\n const subtotal = input.finalTotal;\n const discountAmount = Math.round((input.finalTotal - input.totalAfterDiscount) * 100) / 100;\n return {\n rows: main,\n separateSections,\n subtotal,\n discount: discountAmount > 0 ? { label: input.discountLabel ?? \"Discount\", amount: discountAmount } : null,\n total: input.totalAfterDiscount,\n };\n}\n","\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.isAndCondition = isAndCondition;\nfunction isAndCondition(c) {\n return c.operator === \"and\";\n}\n","\"use strict\";\n/**\n * The expression language shared by the pricing engine and the wizard's formula\n * builder.\n *\n * Previously there were two implementations: a hand-written parser here and\n * mathjs in the dashboard preview. They could — and did — disagree, so a tenant\n * saw one number while building and the customer was quoted another.\n * Everything now parses and evaluates through this module.\n *\n * Grammar:\n * expr → term (('+' | '-') term)*\n * term → factor (('*' | '/') factor)*\n * factor → '-'? primary\n * primary → NUMBER | '$' name | 'field:' name | 'lookup:' ref | '(' expr ')'\n *\n * Parentheses are the reason this module exists. Without them a tenant cannot\n * express \"(20 + 3) x 3\" at all, and the flat left-to-right chip UI silently\n * produced the BODMAS reading instead.\n *\n * Pure — no I/O, never throws. Errors are returned, matching engine convention.\n */\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.parseExpression = parseExpression;\nexports.evaluateNode = evaluateNode;\nexports.evaluateExpression = evaluateExpression;\nexports.printExpression = printExpression;\nexports.collectFieldKeys = collectFieldKeys;\nconst IDENT = /[\\w]/;\nfunction tokenise(source) {\n const lexemes = [];\n const src = source.trim();\n let i = 0;\n const readIdent = (from) => {\n let out = \"\";\n let j = from;\n while (j < src.length && IDENT.test(src[j]))\n out += src[j++];\n return out;\n };\n while (i < src.length) {\n const ch = src[i];\n if (ch === \" \" || ch === \"\\t\" || ch === \"\\n\") {\n i++;\n continue;\n }\n if (ch === \"$\") {\n const key = readIdent(i + 1);\n lexemes.push({ type: \"TOKEN\", value: key, position: i });\n i += key.length + 1;\n continue;\n }\n if (src.startsWith(\"field:\", i)) {\n const key = readIdent(i + 6);\n lexemes.push({ type: \"FIELD\", value: key, position: i });\n i += key.length + 6;\n continue;\n }\n if (src.startsWith(\"lookup:\", i)) {\n const ref = readIdent(i + 7);\n lexemes.push({ type: \"LOOKUP\", value: ref, position: i });\n i += ref.length + 7;\n continue;\n }\n if (/[0-9]/.test(ch) || (ch === \".\" && /[0-9]/.test(src[i + 1] ?? \"\"))) {\n let num = \"\";\n while (i < src.length && /[0-9.]/.test(src[i]))\n num += src[i++];\n lexemes.push({ type: \"NUMBER\", value: num, position: i - num.length });\n continue;\n }\n if (ch === \"+\" || ch === \"-\" || ch === \"*\" || ch === \"/\") {\n lexemes.push({ type: \"OP\", value: ch, position: i });\n i++;\n continue;\n }\n if (ch === \"(\") {\n lexemes.push({ type: \"LPAREN\", value: ch, position: i });\n i++;\n continue;\n }\n if (ch === \")\") {\n lexemes.push({ type: \"RPAREN\", value: ch, position: i });\n i++;\n continue;\n }\n lexemes.push({ type: \"UNKNOWN\", value: ch, position: i });\n i++;\n }\n lexemes.push({ type: \"EOF\", value: \"\", position: src.length });\n return lexemes;\n}\nfunction parseExpression(source) {\n const errors = [];\n if (!source || source.trim().length === 0) {\n return { node: null, errors: [{ ruleId: null, message: \"Empty expression\" }] };\n }\n const lexemes = tokenise(source);\n let pos = 0;\n const peek = () => lexemes[pos] ?? { type: \"EOF\", value: \"\", position: 0 };\n const next = () => lexemes[pos++] ?? { type: \"EOF\", value: \"\", position: 0 };\n const fail = (message) => {\n errors.push({ ruleId: null, message });\n };\n function parsePrimary() {\n const lexeme = next();\n switch (lexeme.type) {\n case \"NUMBER\": {\n const value = parseFloat(lexeme.value);\n if (Number.isNaN(value)) {\n fail(`Invalid number \"${lexeme.value}\"`);\n return null;\n }\n return { kind: \"number\", value };\n }\n case \"TOKEN\":\n if (lexeme.value === \"\") {\n fail(\"Malformed token reference — nothing after '$'\");\n return null;\n }\n return { kind: \"token\", key: lexeme.value };\n case \"FIELD\":\n if (lexeme.value === \"\") {\n fail(\"Malformed field reference — nothing after 'field:'\");\n return null;\n }\n return { kind: \"field\", key: lexeme.value };\n case \"LOOKUP\":\n if (lexeme.value === \"\") {\n fail(\"Malformed lookup reference — nothing after 'lookup:'\");\n return null;\n }\n return { kind: \"lookup\", ref: lexeme.value };\n case \"LPAREN\": {\n const inner = parseExpr();\n if (peek().type === \"RPAREN\") {\n next();\n }\n else {\n fail(\"Unclosed '(' — every opening bracket needs a closing one\");\n }\n return inner;\n }\n case \"EOF\":\n fail(\"Expression ended unexpectedly\");\n return null;\n default:\n fail(`Unexpected \"${lexeme.value}\" in expression`);\n return null;\n }\n }\n function parseFactor() {\n if (peek().type === \"OP\" && peek().value === \"-\") {\n next();\n const operand = parseFactor();\n return operand === null ? null : { kind: \"negate\", operand };\n }\n return parsePrimary();\n }\n function parseTerm() {\n let left = parseFactor();\n while (peek().type === \"OP\" && (peek().value === \"*\" || peek().value === \"/\")) {\n const op = next().value;\n const right = parseFactor();\n if (left === null || right === null)\n return null;\n left = { kind: \"binary\", op, left, right };\n }\n return left;\n }\n function parseExpr() {\n let left = parseTerm();\n while (peek().type === \"OP\" && (peek().value === \"+\" || peek().value === \"-\")) {\n const op = next().value;\n const right = parseTerm();\n if (left === null || right === null)\n return null;\n left = { kind: \"binary\", op, left, right };\n }\n return left;\n }\n const node = parseExpr();\n if (peek().type !== \"EOF\") {\n fail(`Unexpected \"${peek().value}\" after the end of the expression`);\n }\n return { node: errors.length > 0 ? null : node, errors };\n}\nfunction evaluateNode(node, scope) {\n const errors = [];\n function walk(n) {\n switch (n.kind) {\n case \"number\":\n return n.value;\n case \"token\": {\n if (!(n.key in scope.tokens)) {\n errors.push({ ruleId: null, message: `Undefined token: \"$${n.key}\"` });\n return 0;\n }\n return scope.tokens[n.key];\n }\n case \"field\": {\n const fields = scope.fields ?? {};\n if (!(n.key in fields)) {\n errors.push({ ruleId: null, message: `Unanswered field referenced in a price: \"${n.key}\"` });\n return 0;\n }\n const value = fields[n.key];\n if (!Number.isFinite(value)) {\n errors.push({ ruleId: null, message: `Field \"${n.key}\" is not a number` });\n return 0;\n }\n return value;\n }\n case \"lookup\": {\n const lookups = scope.lookups ?? {};\n if (!(n.ref in lookups)) {\n errors.push({ ruleId: null, message: `Unresolved lookup reference: \"lookup:${n.ref}\"` });\n return 0;\n }\n return lookups[n.ref];\n }\n case \"negate\":\n return -walk(n.operand);\n case \"binary\": {\n const left = walk(n.left);\n const right = walk(n.right);\n switch (n.op) {\n case \"+\":\n return left + right;\n case \"-\":\n return left - right;\n case \"*\":\n return left * right;\n case \"/\":\n if (right === 0) {\n errors.push({ ruleId: null, message: \"Division by zero in expression\" });\n return 0;\n }\n return left / right;\n }\n }\n }\n }\n const value = walk(node);\n return { value: Number.isFinite(value) ? value : 0, errors };\n}\n/** Parses and evaluates in one step — the common case. */\nfunction evaluateExpression(source, scope) {\n const { node, errors } = parseExpression(source);\n if (node === null)\n return { value: 0, errors };\n return evaluateNode(node, scope);\n}\n// ── Printing ─────────────────────────────────────────────────────────────────\nconst PRECEDENCE = { \"+\": 1, \"-\": 1, \"*\": 2, \"/\": 2 };\n/**\n * Renders an AST back to source, adding brackets only where precedence or\n * associativity requires them. Round-trips: parse(print(node)) equals node.\n */\nfunction printExpression(node) {\n // `+` and `*` are associative, so `a + (b + c)` and `a * (b * c)` mean exactly\n // what they mean without the brackets. `-` and `/` are not: dropping them in\n // `a - (b - c)` or `a / (b / c)` changes the value.\n const ASSOCIATIVE = { \"+\": true, \"*\": true, \"-\": false, \"/\": false };\n function render(n, parentPrecedence = 0, isRightOperand = false, parentOp = null) {\n switch (n.kind) {\n case \"number\":\n return String(n.value);\n case \"token\":\n return `$${n.key}`;\n case \"field\":\n return `field:${n.key}`;\n case \"lookup\":\n return `lookup:${n.ref}`;\n case \"negate\":\n return `-${render(n.operand, 3)}`;\n case \"binary\": {\n const precedence = PRECEDENCE[n.op];\n const body = `${render(n.left, precedence, false, n.op)} ${n.op} ${render(n.right, precedence, true, n.op)}`;\n const parentKeepsOrder = parentOp !== null && !ASSOCIATIVE[parentOp];\n const needsBrackets = precedence < parentPrecedence || (precedence === parentPrecedence && isRightOperand && parentKeepsOrder);\n return needsBrackets ? `(${body})` : body;\n }\n }\n }\n return render(node);\n}\n/** Collects every `field:` key an expression depends on. */\nfunction collectFieldKeys(node) {\n const keys = new Set();\n (function walk(n) {\n if (n.kind === \"field\")\n keys.add(n.key);\n else if (n.kind === \"binary\") {\n walk(n.left);\n walk(n.right);\n }\n else if (n.kind === \"negate\")\n walk(n.operand);\n })(node);\n return [...keys];\n}\n","\"use strict\";\n/**\n * packages/engine/src/resolver.ts\n *\n * Expression resolver and condition evaluator for the onabl pricing engine.\n *\n * resolveExpression() — evaluates an expression string against tokens, lookup\n * values and (optionally) customer answers. Grammar, parsing and evaluation all\n * live in ./expression, which the dashboard formula builder shares — so a\n * preview and a live quote can never disagree.\n *\n * evaluateCondition() — evaluates a single Condition against an AnswerMap.\n * Handles all seven operators including `includes` for multicheck (string[]) fields.\n *\n * Both functions are pure — no side effects, no external dependencies.\n */\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.resolveExpression = resolveExpression;\nexports.evaluateCondition = evaluateCondition;\nconst config_1 = require(\"@onabl/types/config\");\nconst expression_1 = require(\"./expression\");\n// ─── Public: resolveExpression ────────────────────────────────────────────────\n/**\n * Resolves an expression string to a numeric value.\n *\n * @param expr - Expression string e.g. \"$base_rate * 1.5\", \"500\", \"lookup:r02\"\n * @param variables - Flat variable store from FormConfig.variables\n * @param lookupValues - Pre-resolved lookup table outputs (built during phase 1)\n * @returns { value, errors } — errors is empty on success\n */\nfunction resolveExpression(expr, variables, lookupValues, fields) {\n return (0, expression_1.evaluateExpression)(expr, { tokens: variables, lookups: lookupValues, fields });\n}\n// ─── Public: evaluateCondition ────────────────────────────────────────────────\n/**\n * Evaluates a Condition against the current AnswerMap.\n *\n * Returns true if the condition is satisfied, false otherwise.\n * Returns false (safe default = rule suppressed) if the field is missing from answers.\n *\n * The `includes` operator is the only operator that expects a string[] answer.\n * All other operators expect a scalar (string | number | boolean).\n */\nfunction evaluateCondition(condition, answers) {\n if ((0, config_1.isAndCondition)(condition)) {\n return condition.clauses.every((c) => evaluateCondition(c, answers));\n }\n const { field, operator, value: condValue } = condition;\n const answer = answers[field];\n // Missing field — treat as condition not met (safe default: suppress the rule)\n if (answer === undefined || answer === null) {\n return false;\n }\n // `includes` — answer is string[] (multicheck) or string (radio fallback for legacy configs)\n if (operator === \"includes\") {\n if (Array.isArray(answer))\n return answer.includes(String(condValue));\n return String(answer) === String(condValue);\n }\n // `includes_any` — answer must be string[], condValue must be string[]\n if (operator === \"includes_any\") {\n if (!Array.isArray(answer) || !Array.isArray(condValue)) {\n return false;\n }\n return condValue.some((v) => answer.includes(v));\n }\n // `in` — answer must be scalar, condValue must be string[]\n if (operator === \"in\") {\n if (Array.isArray(answer) || !Array.isArray(condValue)) {\n return false;\n }\n return condValue.includes(String(answer));\n }\n // All remaining operators work on scalars\n // Array answers are not valid for scalar operators\n if (Array.isArray(answer)) {\n return false;\n }\n const op = operator;\n switch (op) {\n case \"eq\":\n return answer === condValue;\n case \"neq\":\n return answer !== condValue;\n case \"gt\":\n case \"gte\":\n case \"lt\":\n case \"lte\": {\n const numAnswer = Number(answer);\n const numValue = Number(condValue);\n if (isNaN(numAnswer) || isNaN(numValue)) {\n return false;\n }\n if (op === \"gt\")\n return numAnswer > numValue;\n if (op === \"gte\")\n return numAnswer >= numValue;\n if (op === \"lt\")\n return numAnswer < numValue;\n if (op === \"lte\")\n return numAnswer <= numValue;\n return false;\n }\n default: {\n // Exhaustive check — TypeScript should catch unknown operators at compile time\n const _exhaustive = op;\n void _exhaustive;\n return false;\n }\n }\n}\n","\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.injectDateDerivals = injectDateDerivals;\n/**\n * Injects derived date fields into answers based on FormConfig.\n *\n * For each date field with derivedFields config, computes:\n * - isWeekend: `__is_weekend__<key>` = true if Sat/Sun\n * - isPeakSeason: `__is_peak_season__<key>` = true if month matches config\n * - daysUntil: `__days_until__<key>` = integer days from today (can be negative)\n *\n * Uses local date parsing (YYYY-MM-DD split + new Date(y, m-1, d)) to avoid UTC-offset bugs.\n *\n * `now` defaults to the current time but is an explicit parameter so this\n * function stays a pure function of its inputs — callers needing determinism\n * (e.g. tests) can pass a fixed date.\n */\nfunction injectDateDerivals(config, raw, now = new Date()) {\n const augmented = { ...raw };\n for (const field of config.fields) {\n if (field.type !== \"date\" || !field.derivedFields)\n continue;\n const value = raw[field.key];\n if (!value || typeof value !== \"string\")\n continue;\n const [year, month, day] = value.split(\"-\").map(Number);\n if (!year || !month || !day)\n continue;\n // Local date: new Date(y, m-1, d) avoids UTC-offset bugs\n // (new Date(\"2025-01-01\") is midnight UTC, which may be Dec 31 UTC-5)\n const date = new Date(year, month - 1, day);\n const { isWeekend, isPeakSeason, daysUntil } = field.derivedFields;\n if (isWeekend) {\n const d = date.getDay();\n augmented[`__is_weekend__${field.key}`] = d === 0 || d === 6;\n }\n if (isPeakSeason?.length) {\n augmented[`__is_peak_season__${field.key}`] = isPeakSeason.includes(date.getMonth() + 1);\n }\n if (daysUntil) {\n const today = new Date(now);\n today.setHours(0, 0, 0, 0);\n const diff = Math.round((date.getTime() - today.getTime()) / 86_400_000);\n augmented[`__days_until__${field.key}`] = diff;\n }\n }\n return augmented;\n}\n","\"use strict\";\n/**\n * packages/engine/src/variables.ts\n *\n * Resolves FormConfig.tokens — where a value may be a literal number or an\n * expression string referencing other tokens (e.g. \"$hourly_rate * 1.5\") —\n * down to a flat Record<string, number> that the rest of the engine consumes\n * exactly as it always has.\n *\n * Pure — no side effects. Never throws; a broken token (undefined ref,\n * circular ref) resolves to 0 and reports an EngineError instead.\n */\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.resolveTokens = resolveTokens;\nconst resolver_1 = require(\"./resolver\");\nfunction extractTokenRefs(expr) {\n const refs = new Set();\n for (const match of expr.matchAll(/\\$(\\w+)/g)) {\n refs.add(match[1]);\n }\n return Array.from(refs);\n}\n/**\n * Resolves raw tokens (literals + expressions) into a flat numeric map.\n *\n * Resolution order is dependency-driven (a token referencing another is\n * resolved after its dependency), not insertion order. Circular references\n * are detected and reported as an EngineError; the cyclic token resolves\n * to 0 rather than infinite-looping.\n */\nfunction resolveTokens(rawTokens) {\n const errors = [];\n const resolved = {};\n const resolving = new Set();\n const done = new Set();\n function resolveKey(key) {\n if (done.has(key))\n return resolved[key] ?? 0;\n const raw = rawTokens[key];\n if (raw === undefined)\n return 0; // referencing expression will surface \"Undefined variable\" itself\n if (typeof raw === \"number\") {\n resolved[key] = raw;\n done.add(key);\n return raw;\n }\n if (resolving.has(key)) {\n errors.push({ ruleId: null, message: `Circular reference detected in token \"$${key}\"` });\n resolved[key] = 0;\n done.add(key);\n return 0;\n }\n resolving.add(key);\n for (const dep of extractTokenRefs(raw)) {\n resolveKey(dep);\n }\n resolving.delete(key);\n const { value, errors: exprErrors } = (0, resolver_1.resolveExpression)(raw, resolved, {});\n errors.push(...exprErrors.map((e) => ({ ...e, message: `Token \"$${key}\": ${e.message}` })));\n resolved[key] = value;\n done.add(key);\n return value;\n }\n for (const key of Object.keys(rawTokens)) {\n resolveKey(key);\n }\n return { variables: resolved, errors };\n}\n","\"use strict\";\n/**\n * Core pricing engine for onabl.\n *\n * applyDefaults() — fills missing answers with field defaultValues from config.\n *\n * calculate() — runs the three-phase pricing calculation against a FormConfig\n * and a fully-populated AnswerMap. Returns an EngineResult.\n *\n * Both functions are pure — no side effects, no I/O, no external dependencies.\n * calculate() never throws — all errors are captured in EngineResult.errors.\n *\n * IMPORTANT: finalTotal is always pre-discount. Discount codes are applied at\n * the API layer after calculate() returns. The engine has no knowledge of discounts.\n */\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.resolveTokens = exports.injectDateDerivals = void 0;\nexports.applyDefaults = applyDefaults;\nexports.calculate = calculate;\nconst resolver_1 = require(\"./resolver\");\nconst date_derival_1 = require(\"./date-derival\");\nObject.defineProperty(exports, \"injectDateDerivals\", { enumerable: true, get: function () { return date_derival_1.injectDateDerivals; } });\nconst variables_1 = require(\"./variables\");\nObject.defineProperty(exports, \"resolveTokens\", { enumerable: true, get: function () { return variables_1.resolveTokens; } });\nconst presentation_1 = require(\"./presentation\");\n// ─── Group assignment helper ──────────────────────────────────────────────────\n/**\n * Computes groupAmounts for a rule's groupAssignments.\n * For each assignment:\n * - If expression is set, evaluate it to get the per-group amount\n * - Otherwise, use the baseAmount (the primary computed value for the rule)\n *\n * Returns a Record<tag, amount> mapping. Errors are pre-stamped with ruleId so\n * every call site doesn't have to repeat `.map(e => ({...e, ruleId}))`.\n */\nfunction computeGroupAmounts(groupAssignments, baseAmount, variables, lookupValues, ruleId) {\n if (!groupAssignments || groupAssignments.length === 0) {\n return { errors: [] };\n }\n const groupAmounts = {};\n const errors = [];\n for (const assignment of groupAssignments) {\n if (assignment.expression) {\n // Evaluate the custom expression for this group\n const { value, errors: exprErrors } = (0, resolver_1.resolveExpression)(assignment.expression, variables, lookupValues);\n errors.push(...exprErrors.map((e) => ({ ...e, ruleId })));\n groupAmounts[assignment.tag] = roundCents(value);\n }\n else {\n // Use the base amount (the rule's primary computed value)\n groupAmounts[assignment.tag] = baseAmount;\n }\n }\n return { groupAmounts: Object.keys(groupAmounts).length > 0 ? groupAmounts : undefined, errors };\n}\n// ─── Rounding helper ──────────────────────────────────────────────────────────\n/**\n * Rounds to 2 decimal places (cents) with IEEE 754 midpoint correction.\n * The Number.EPSILON addend nudges true 0.5 values above the representation\n * that would round incorrectly due to float imprecision.\n */\nfunction roundCents(n) {\n return Math.round((n + Number.EPSILON) * 100) / 100;\n}\n// ─── applyDefaults ────────────────────────────────────────────────────────────\n/**\n * Returns a new AnswerMap with any missing field keys filled in from\n * field.defaultValue. Fields with a null defaultValue are omitted if absent\n * (they remain missing — required field validation is the form renderer's job).\n *\n * Does not mutate the input answers object.\n *\n * Takes `Pick<FormConfig, \"fields\">` rather than the full FormConfig — this\n * only ever reads `.fields`, and requiring the whole config (with its\n * `rules`/`tokens`) made it uncallable against @onabl/contracts's public-safe\n * form shape, which deliberately excludes those. A full FormConfig still\n * satisfies this narrower type, so existing callers are unaffected.\n */\nfunction applyDefaults(config, answers) {\n const result = { ...answers };\n for (const field of config.fields) {\n if (result[field.key] === undefined || result[field.key] === null) {\n if (field.defaultValue !== null && field.defaultValue !== undefined) {\n result[field.key] = field.defaultValue;\n }\n else {\n // Safe type-based fallback when no explicit default is set\n if (field.type === \"number\")\n result[field.key] = 0;\n if (field.type === \"toggle\")\n result[field.key] = false;\n }\n }\n }\n return result;\n}\n// ─── Phase 1 helpers ─────────────────────────────────────────────────────────\nfunction processUnitRate(rule, answers, variables, lookupValues, fieldValues, quantityUnit) {\n const errors = [];\n const quantityRaw = answers[rule.quantityField];\n const quantity = Number(quantityRaw);\n if (quantityRaw === undefined || quantityRaw === null) {\n errors.push({\n ruleId: rule.id,\n message: `unit_rate rule \"${rule.id}\": field \"${rule.quantityField}\" not found in answers`,\n });\n return { lineItem: null, amount: 0, errors };\n }\n if (isNaN(quantity)) {\n errors.push({\n ruleId: rule.id,\n message: `unit_rate rule \"${rule.id}\": field \"${rule.quantityField}\" is not a number (got \"${quantityRaw}\")`,\n });\n return { lineItem: null, amount: 0, errors };\n }\n const { value: rate, errors: rateErrors } = (0, resolver_1.resolveExpression)(rule.rateExpr, variables, lookupValues, fieldValues);\n // Stamp ruleId onto resolver errors\n const stampedErrors = rateErrors.map((e) => ({ ...e, ruleId: rule.id }));\n errors.push(...stampedErrors);\n const amount = roundCents(quantity * rate);\n const { groupAmounts, errors: groupErrors } = computeGroupAmounts(rule.groupAssignments, amount, variables, lookupValues, rule.id);\n errors.push(...groupErrors);\n const lineItem = {\n ruleId: rule.id,\n label: rule.label,\n amount,\n type: \"unit_rate\",\n showOnQuote: rule.showOnQuote,\n ...(rule.tag !== undefined && { tag: rule.tag }),\n ...(groupAmounts !== undefined && { groupAmounts }),\n quantity,\n ...(quantityUnit !== undefined && { quantityUnit }),\n ratePerUnit: rate,\n };\n return { lineItem, amount, errors };\n}\nfunction processConditionalAddon(rule, variables, lookupValues, fieldValues) {\n const { value: rawAmount, errors: resolveErrors } = (0, resolver_1.resolveExpression)(rule.amountExpr, variables, lookupValues, fieldValues);\n const amount = roundCents(rawAmount);\n const errors = resolveErrors.map((e) => ({ ...e, ruleId: rule.id }));\n const { groupAmounts, errors: groupErrors } = computeGroupAmounts(rule.groupAssignments, amount, variables, lookupValues, rule.id);\n errors.push(...groupErrors);\n const lineItem = {\n ruleId: rule.id,\n label: rule.label,\n amount,\n type: \"conditional_addon\",\n showOnQuote: rule.showOnQuote,\n ...(rule.tag !== undefined && { tag: rule.tag }),\n ...(groupAmounts !== undefined && { groupAmounts }),\n };\n return { lineItem, amount, errors };\n}\nfunction processLookupTable(rule, answers, variables, lookupValues) {\n const errors = [];\n const rowAnswer = String(answers[rule.rowField] ?? \"\");\n const colAnswer = String(answers[rule.colField] ?? \"\");\n if (answers[rule.rowField] === undefined) {\n errors.push({\n ruleId: rule.id,\n message: `lookup_table rule \"${rule.id}\": row field \"${rule.rowField}\" not found in answers`,\n });\n }\n if (answers[rule.colField] === undefined) {\n errors.push({\n ruleId: rule.id,\n message: `lookup_table rule \"${rule.id}\": col field \"${rule.colField}\" not found in answers`,\n });\n }\n if (errors.length > 0) {\n return { lineItem: null, amount: 0, errors };\n }\n const row = rule.table[rowAnswer];\n if (row === undefined) {\n errors.push({\n ruleId: rule.id,\n message: `lookup_table rule \"${rule.id}\": no row for value \"${rowAnswer}\"`,\n });\n return { lineItem: null, amount: 0, errors };\n }\n const rawAmount = row[colAnswer];\n if (rawAmount === undefined) {\n errors.push({\n ruleId: rule.id,\n message: `lookup_table rule \"${rule.id}\": no column \"${colAnswer}\" in row \"${rowAnswer}\"`,\n });\n return { lineItem: null, amount: 0, errors };\n }\n const amount = roundCents(rawAmount);\n const { groupAmounts, errors: groupErrors } = computeGroupAmounts(rule.groupAssignments, amount, variables, lookupValues, rule.id);\n errors.push(...groupErrors);\n const lineItem = {\n ruleId: rule.id,\n label: rule.label,\n amount,\n type: \"lookup_table\",\n showOnQuote: rule.showOnQuote,\n ...(rule.tag !== undefined && { tag: rule.tag }),\n ...(groupAmounts !== undefined && { groupAmounts }),\n };\n return { lineItem, amount, errors };\n}\n// ─── Phase 2 helpers ──────────────────────────────────────────────────────────\nfunction processSelectionMultiplier(rule, answers, runningTotal, variables, lookupValues) {\n const errors = [];\n const selection = String(answers[rule.field] ?? \"\");\n if (answers[rule.field] === undefined) {\n // Field not answered yet — treat as neutral (1.0), same as an option with no multiplier entry\n return { lineItem: null, newTotal: runningTotal, errors };\n }\n const factor = rule.multipliers[selection];\n if (factor === undefined) {\n // Selection has no multiplier entry — treat as 1.0 (neutral), not an error.\n // Some options may intentionally not have a multiplier.\n return { lineItem: null, newTotal: runningTotal, errors };\n }\n const appliedTo = runningTotal;\n const newTotal = runningTotal * factor;\n const amount = roundCents(newTotal - appliedTo); // the delta — positive = markup, negative = discount\n const { groupAmounts, errors: groupErrors } = computeGroupAmounts(rule.groupAssignments, amount, variables, lookupValues, rule.id);\n errors.push(...groupErrors);\n const lineItem = {\n ruleId: rule.id,\n label: rule.label,\n amount,\n type: \"selection_multiplier\",\n showOnQuote: rule.showOnQuote,\n ...(rule.tag !== undefined && { tag: rule.tag }),\n ...(groupAmounts !== undefined && { groupAmounts }),\n factor,\n appliedTo,\n };\n return { lineItem, newTotal, errors };\n}\nfunction processConditionalMultiplier(rule, variables, lookupValues, fieldValues, runningTotal) {\n const { value: factor, errors: resolveErrors } = (0, resolver_1.resolveExpression)(rule.factorExpr, variables, lookupValues, fieldValues);\n const errors = resolveErrors.map((e) => ({ ...e, ruleId: rule.id }));\n const appliedTo = runningTotal;\n const newTotal = runningTotal * factor;\n const amount = roundCents(newTotal - appliedTo);\n const { groupAmounts, errors: groupErrors } = computeGroupAmounts(rule.groupAssignments, amount, variables, lookupValues, rule.id);\n errors.push(...groupErrors);\n const lineItem = {\n ruleId: rule.id,\n label: rule.label,\n amount,\n type: \"conditional_multiplier\",\n showOnQuote: rule.showOnQuote,\n ...(rule.tag !== undefined && { tag: rule.tag }),\n ...(groupAmounts !== undefined && { groupAmounts }),\n factor,\n appliedTo,\n };\n return { lineItem, newTotal, errors };\n}\n// ─── Phase 3 helper ───────────────────────────────────────────────────────────\nfunction processFloorMinimum(rule, variables, lookupValues, fieldValues, currentTotal) {\n const { value: minimum, errors: resolveErrors } = (0, resolver_1.resolveExpression)(rule.minimumExpr, variables, lookupValues, fieldValues);\n const errors = resolveErrors.map((e) => ({ ...e, ruleId: rule.id }));\n if (currentTotal < minimum) {\n const amount = roundCents(minimum - currentTotal); // the top-up amount\n const { groupAmounts, errors: groupErrors } = computeGroupAmounts(rule.groupAssignments, amount, variables, lookupValues, rule.id);\n errors.push(...groupErrors);\n const lineItem = {\n ruleId: rule.id,\n label: rule.label,\n amount,\n type: \"floor_minimum\",\n showOnQuote: rule.showOnQuote,\n ...(rule.tag !== undefined && { tag: rule.tag }),\n ...(groupAmounts !== undefined && { groupAmounts }),\n };\n return { lineItem, finalTotal: minimum, minimumApplied: true, minimumAmount: minimum, errors };\n }\n return { lineItem: null, finalTotal: currentTotal, minimumApplied: false, minimumAmount: minimum, errors };\n}\n// ─── Totals authority ─────────────────────────────────────────────────────────\n/**\n * Builds the reconciled QuoteTotals and checks that the parts add up.\n *\n * Two invariants, both enforced as errors rather than tolerances:\n *\n * 1. An item allocated across display groups must allocate its whole amount\n * and no more — sum(groupAmounts) === amount. Without this a breakdown can\n * silently double-count an item that belongs to two groups, or drop part of\n * one whose group expressions do not add up.\n *\n * 2. Visible line items must sum to gross. This is the check that would have\n * caught every reconciliation defect in the audit at authoring time.\n *\n * Amounts are compared in integer cents, so this is exact — no epsilon.\n */\nfunction buildTotals(lineItems, finalTotal, displayGroups, minimumApplied) {\n const errors = [];\n const cents = (n) => Math.round(n * 100);\n for (const item of lineItems) {\n if (!item.groupAmounts)\n continue;\n const allocated = Object.values(item.groupAmounts).reduce((a, b) => a + b, 0);\n if (cents(allocated) !== cents(item.amount)) {\n errors.push({\n ruleId: item.ruleId,\n message: `\"${item.label}\" is split across groups totalling ${allocated.toFixed(2)}, but the item is ${item.amount.toFixed(2)} — the split must account for the whole amount`,\n });\n }\n }\n // Grouped through the shared presenter, so the totals the engine states and\n // the rows every renderer draws come from one implementation.\n const { groupTotals: rawGroupTotals } = (0, presentation_1.groupLineItems)(lineItems, displayGroups);\n const groupTotals = {};\n let separatelyQuoted = 0;\n for (const group of displayGroups ?? []) {\n const total = rawGroupTotals[group.tag] ?? 0;\n groupTotals[group.tag] = roundCents(total);\n if (group.excludeFromTotal)\n separatelyQuoted += total;\n }\n // A floor minimum tops the total up to a fixed figure, so the line items\n // deliberately do not sum to it. Every other configuration must reconcile.\n if (!minimumApplied) {\n const visible = lineItems.filter((i) => i.showOnQuote).reduce((a, i) => a + i.amount, 0);\n const hidden = lineItems.filter((i) => !i.showOnQuote).reduce((a, i) => a + i.amount, 0);\n if (cents(visible + hidden) !== cents(finalTotal)) {\n errors.push({\n ruleId: null,\n message: `Line items sum to ${(visible + hidden).toFixed(2)} but the quote total is ${finalTotal.toFixed(2)} — the breakdown does not reconcile`,\n });\n }\n }\n return {\n totals: {\n gross: roundCents(finalTotal),\n separatelyQuoted: roundCents(separatelyQuoted),\n payable: roundCents(finalTotal - separatelyQuoted),\n groupTotals,\n },\n errors,\n };\n}\n// ─── calculate ────────────────────────────────────────────────────────────────\n/**\n * Runs the full three-phase pricing calculation.\n *\n * Phase 1 — ADD UP: unit_rate, conditional_addon, lookup_table\n * Phase 2 — SCALE: selection_multiplier, conditional_multiplier\n * Phase 3 — MINIMUM: floor_minimum\n *\n * Rules with a condition are skipped if the condition evaluates to false.\n * Skipped rule IDs are collected in EngineResult.suppressedRuleIds.\n *\n * Never throws. All errors are collected in EngineResult.errors.\n * Partial results with errors are returned — the caller decides how to handle them.\n *\n * finalTotal is always pre-discount. The API layer applies discount codes after\n * this function returns to produce Quote.totalAfterDiscount.\n */\nfunction calculate(config, answers) {\n const allErrors = [];\n const lineItems = [];\n const suppressedRuleIds = [];\n // lookupValues accumulates resolved lookup_table outputs during phase 1\n // so that downstream unit_rate rules can reference them via \"lookup:rXX\"\n const lookupValues = {};\n // config.tokens can be absent on a form whose stored config predates the\n // tokens feature (or was never migrated) — calculate() is documented to\n // never throw, so this can't be assumed present.\n const { variables, errors: variableErrors } = (0, variables_1.resolveTokens)(config.tokens ?? {});\n allErrors.push(...variableErrors);\n // Numeric view of the answers, so a rule expression can reference a customer\n // answer directly via `field:key` rather than only through unit_rate.\n const fieldValues = {};\n for (const [key, answer] of Object.entries(answers)) {\n const numeric = typeof answer === \"boolean\" ? (answer ? 1 : 0) : Number(answer);\n if (typeof answer !== \"object\" && Number.isFinite(numeric))\n fieldValues[key] = numeric;\n }\n // ── Phase 1 — ADD UP ───────────────────────────────────────────────────────\n let phase1Total = 0;\n function ruleConditionsMet(rule) {\n if (rule.condition !== undefined && !(0, resolver_1.evaluateCondition)(rule.condition, answers))\n return false;\n if (rule.scopeCondition !== undefined && !(0, resolver_1.evaluateCondition)(rule.scopeCondition, answers))\n return false;\n return true;\n }\n // Phase 1a: Process all Phase 1 rules EXCEPT conditional_addon with feeType === 'percent'\n for (const rule of config.rules.phase1) {\n // Skip percentage-based fixed fees — process them in phase 1b\n if (rule.type === \"conditional_addon\" && rule.feeType === \"percent\") {\n continue;\n }\n // Evaluate condition — skip rule if condition is present and not met\n if (!ruleConditionsMet(rule)) {\n suppressedRuleIds.push(rule.id);\n continue;\n }\n if (rule.type === \"unit_rate\") {\n const quantityUnit = config.meta.tokenLabels?.[rule.quantityField]?.unit;\n const { lineItem, amount, errors } = processUnitRate(rule, answers, variables, lookupValues, fieldValues, quantityUnit);\n allErrors.push(...errors);\n if (lineItem !== null) {\n lineItems.push(lineItem);\n phase1Total += amount;\n }\n continue;\n }\n if (rule.type === \"conditional_addon\") {\n const { lineItem, amount, errors } = processConditionalAddon(rule, variables, lookupValues, fieldValues);\n allErrors.push(...errors);\n if (lineItem !== null) {\n lineItems.push(lineItem);\n phase1Total += amount;\n }\n continue;\n }\n if (rule.type === \"lookup_table\") {\n const { lineItem, amount, errors } = processLookupTable(rule, answers, variables, lookupValues);\n allErrors.push(...errors);\n if (lineItem !== null) {\n // Register in lookupValues so downstream rules can reference \"lookup:<rule.id>\"\n lookupValues[rule.id] = amount;\n lineItems.push(lineItem);\n phase1Total += amount;\n }\n continue;\n }\n }\n // Phase 1b: Process percentage-based fixed fees using the phase1 subtotal\n const phase1SubTotal = phase1Total;\n for (const rule of config.rules.phase1) {\n // Only process conditional_addon rules with feeType === 'percent'\n if (!(rule.type === \"conditional_addon\" && rule.feeType === \"percent\")) {\n continue;\n }\n if (!ruleConditionsMet(rule)) {\n suppressedRuleIds.push(rule.id);\n continue;\n }\n // Resolve the percentage value from amountExpr\n const { value: percent, errors: resolveErrors } = (0, resolver_1.resolveExpression)(rule.amountExpr, variables, lookupValues, fieldValues);\n const errors = resolveErrors.map((e) => ({ ...e, ruleId: rule.id }));\n allErrors.push(...errors);\n // Calculate amount as percentage of phase1SubTotal\n const amount = roundCents(phase1SubTotal * (percent / 100));\n const { groupAmounts, errors: groupErrors } = computeGroupAmounts(rule.groupAssignments, amount, variables, lookupValues, rule.id);\n errors.push(...groupErrors);\n allErrors.push(...errors);\n const lineItem = {\n ruleId: rule.id,\n label: rule.label,\n amount,\n type: \"conditional_addon\",\n showOnQuote: rule.showOnQuote,\n ...(rule.tag !== undefined && { tag: rule.tag }),\n ...(groupAmounts !== undefined && { groupAmounts }),\n };\n lineItems.push(lineItem);\n phase1Total += amount;\n }\n // ── Phase 2 — SCALE ────────────────────────────────────────────────────────\n let runningTotal = phase1Total;\n for (const rule of config.rules.phase2) {\n if (!ruleConditionsMet(rule)) {\n suppressedRuleIds.push(rule.id);\n continue;\n }\n if (rule.type === \"selection_multiplier\") {\n const { lineItem, newTotal, errors } = processSelectionMultiplier(rule, answers, runningTotal, variables, lookupValues);\n allErrors.push(...errors);\n if (lineItem !== null) {\n lineItems.push(lineItem);\n }\n runningTotal = newTotal;\n continue;\n }\n if (rule.type === \"conditional_multiplier\") {\n const { lineItem, newTotal, errors } = processConditionalMultiplier(rule, variables, lookupValues, fieldValues, runningTotal);\n allErrors.push(...errors);\n if (lineItem !== null) {\n lineItems.push(lineItem);\n }\n runningTotal = newTotal;\n continue;\n }\n }\n const phase2Total = runningTotal;\n // ── Phase 3 — CHECK MINIMUM ────────────────────────────────────────────────\n let finalTotal = phase2Total;\n let minimumApplied = false;\n let minimumAmount = 0;\n for (const rule of config.rules.phase3) {\n if (!ruleConditionsMet(rule)) {\n suppressedRuleIds.push(rule.id);\n continue;\n }\n if (rule.type === \"floor_minimum\") {\n const result = processFloorMinimum(rule, variables, lookupValues, fieldValues, finalTotal);\n allErrors.push(...result.errors);\n if (result.lineItem !== null) {\n lineItems.push(result.lineItem);\n }\n // Last floor_minimum rule wins if multiple are present (rare but valid config)\n finalTotal = result.finalTotal;\n if (result.minimumApplied) {\n minimumApplied = true;\n minimumAmount = result.minimumAmount;\n }\n continue;\n }\n }\n const { totals, errors: totalsErrors } = buildTotals(lineItems, roundCents(finalTotal), config.meta.displayGroups, minimumApplied);\n allErrors.push(...totalsErrors);\n return {\n phase1Total: roundCents(phase1Total),\n phase2Total: roundCents(phase2Total),\n finalTotal: roundCents(finalTotal),\n minimumApplied,\n minimumAmount: roundCents(minimumAmount),\n lineItems,\n suppressedRuleIds,\n totals,\n errors: allErrors,\n };\n}\n","export {createOnablClient} from \"./client\";\nexport type {OnablClient, OnablClientConfig, CallOpts, TokenOpts} from \"./client\";\n\nexport {OnablError, OnablNotFound, OnablUnauthorized, OnablValidation, OnablNetwork} from \"./errors\";\n\nexport {presentQuote, groupLineItems} from \"./presentation\";\nexport type {PresentQuoteInput, QuotePresentation, QuoteRow, SeparateSection, GroupedItems} from \"./presentation\";\n\nexport {getVisibleSteps, getAllFields, getInitialAnswers, validateFields} from \"./form-state\";\nexport type {VisibleStep} from \"./form-state\";\n\nexport type {PublicForm, PublicFormConfig, PublicFormField, Quote, Invoice, ValidateCodeResponse} from \"@onabl/contracts/public-api\";\n","import {\n PublicFormSchema,\n ValidateCodeResponseSchema,\n SubmissionCreateResponseSchema,\n QuoteSchema,\n QuoteAcceptResponseSchema,\n QuoteDeclineResponseSchema,\n InvoiceSchema,\n PopUrlUpdateResponseSchema,\n PresignResponseSchema,\n type PublicForm,\n type ValidateCodeResponse,\n type Quote,\n type Invoice,\n type PresignResponse,\n} from \"@onabl/contracts/public-api\";\nimport type {AnswerMap} from \"@onabl/types/config\";\n\nimport {OnablError, OnablNetwork, OnablNotFound, OnablUnauthorized, OnablValidation} from \"./errors\";\n\n/**\n * Pinned to the API version this @onabl/js release was built against — see\n * docs/API-BASELINE-2026-09-01.md and PHASE-14 §14.2. Bump alongside a real\n * SDK release once a new dated API version needs adopting; the developer\n * never sets this themselves (SDK-DESIGN.md §4, \"The API version is sent\n * automatically\").\n */\nconst BUILT_AGAINST_API_VERSION = \"2026-09-01\";\n\n/**\n * Production default. Onabl has no dedicated api.onabl.com subdomain — the\n * API is path-routed under the main domain by the Caddy reverse proxy\n * (onabl.com/api/* -> the api container), same pattern as staging\n * (staging.onabl.com/api/*). There is no single default that covers staging\n * too, since it's a genuinely different host — callers targeting staging\n * (or any non-production environment) must always pass baseUrl explicitly.\n */\nconst DEFAULT_BASE_URL = \"https://onabl.com/api/v1\";\n\n/** Default quote-view path template on the integrator's own site, substituting `:uuid`. Overridable via config.quotePath. */\nconst DEFAULT_QUOTE_PATH = \"/quote/:uuid\";\n\nexport interface OnablClientConfig {\n handle: string;\n secretKey: string;\n baseUrl?: string;\n apiVersion?: string;\n /** Path template for the quote view page on the integrator's own site — see submissions.create()'s returned quoteUrl. */\n quotePath?: string;\n}\n\nexport interface CallOpts {\n /** Slug of a specific form, for tenants running more than one. Omitted, resolves to the tenant's dashboard-configured default. */\n slug?: string;\n}\n\n/**\n * Customer-token-scoped calls need a bearer token — @onabl/next supplies one\n * automatically from its managed cookie (SDK-DESIGN.md §3, \"Access cookie\").\n * Used directly (e.g. a Vite/plain-React app per SDK-DESIGN.md §4, \"Route\n * handler only\" decision), the caller supplies it explicitly.\n */\nexport interface TokenOpts {\n token: string;\n}\n\nexport interface OnablClient {\n forms: {\n get(opts?: CallOpts): Promise<PublicForm>;\n validateDiscountCode(code: string, opts?: CallOpts): Promise<ValidateCodeResponse>;\n };\n quotes: {\n get(uuid: string, opts: TokenOpts): Promise<Quote>;\n accept(uuid: string, opts: TokenOpts): Promise<void>;\n decline(uuid: string, reason: string, note: string | undefined, opts: TokenOpts): Promise<void>;\n };\n invoices: {\n get(uuid: string, opts: TokenOpts): Promise<Invoice>;\n /** milestone \"deposit\" saves the deposit POP; \"balance\"/\"full\" save the balance/full-payment POP. */\n savePopUrl(uuid: string, key: string, milestone: \"deposit\" | \"balance\" | \"full\", opts: TokenOpts): Promise<void>;\n };\n storage: {\n /** Presigns an upload for a customer-facing flow (currently only invoice POP uploads — pathPrefix is always \"pop\"). */\n presignPop(resourceId: string, filename: string, contentType: string, fileSize: number, opts: TokenOpts): Promise<PresignResponse>;\n };\n submissions: {\n /** isTenantSource marks a submission taken by the tenant on the customer's behalf (the on-site quote tool) rather than the customer directly — see docs/ROADMAP.md Phase 2.11. */\n create(\n answers: AnswerMap,\n opts?: CallOpts & {consentGiven?: boolean; discountCode?: string; isTenantSource?: boolean},\n ): Promise<{quoteId: string; quoteUrl: string; token: string}>;\n };\n}\n\nexport function createOnablClient(config: OnablClientConfig): OnablClient {\n const baseUrl = config.baseUrl ?? DEFAULT_BASE_URL;\n const apiVersion = config.apiVersion ?? BUILT_AGAINST_API_VERSION;\n const quotePath = config.quotePath ?? DEFAULT_QUOTE_PATH;\n\n async function request<T>(path: string, init: RequestInit & {auth: \"secret\" | TokenOpts}): Promise<T> {\n const headers = new Headers(init.headers);\n headers.set(\"Onabl-Version\", apiVersion);\n if (init.auth === \"secret\") {\n headers.set(\"x-api-key\", config.secretKey);\n } else {\n headers.set(\"Authorization\", `Bearer ${init.auth.token}`);\n }\n if (init.body) headers.set(\"Content-Type\", \"application/json\");\n\n let response: Response;\n try {\n response = await fetch(`${baseUrl}${path}`, {...init, headers});\n } catch (cause) {\n throw new OnablNetwork(\"Request to onabl failed\", cause);\n }\n\n if (response.ok) {\n if (response.status === 204) return undefined as T;\n try {\n return (await response.json()) as T;\n } catch (cause) {\n throw new OnablNetwork(\"Received an unparseable response from onabl\", cause);\n }\n }\n\n const body = await response.json().catch(() => undefined);\n if (response.status === 404) throw new OnablNotFound(body?.message ?? \"Not found\");\n if (response.status === 401) throw new OnablUnauthorized(body?.message ?? \"Unauthorized\");\n if (response.status === 400) throw new OnablValidation(body?.message ?? \"Validation failed\", body?.fieldErrors);\n throw new OnablError(body?.message ?? `Request failed with status ${response.status}`, response.status);\n }\n\n function formPath(opts?: CallOpts): string {\n return opts?.slug ? `/forms/q/${config.handle}/${opts.slug}` : `/forms/q/${config.handle}`;\n }\n\n function submissionPath(opts?: CallOpts): string {\n return opts?.slug ? `/submissions/q/${config.handle}/${opts.slug}` : `/submissions/q/${config.handle}`;\n }\n\n return {\n forms: {\n async get(opts) {\n const raw = await request(formPath(opts), {method: \"GET\", auth: \"secret\"});\n return PublicFormSchema.parse(raw);\n },\n async validateDiscountCode(code, opts) {\n const raw = await request(`${formPath(opts)}/validate-code?code=${encodeURIComponent(code)}`, {method: \"GET\", auth: \"secret\"});\n return ValidateCodeResponseSchema.parse(raw);\n },\n },\n quotes: {\n async get(uuid, opts) {\n const raw = await request(`/quotes/${uuid}`, {method: \"GET\", auth: opts});\n return QuoteSchema.parse(raw);\n },\n async accept(uuid, opts) {\n const raw = await request(`/quotes/${uuid}/accept`, {method: \"POST\", auth: opts});\n QuoteAcceptResponseSchema.parse(raw);\n },\n async decline(uuid, reason, note, opts) {\n const raw = await request(`/quotes/${uuid}/decline`, {method: \"POST\", auth: opts, body: JSON.stringify({declineReason: reason, declineNote: note})});\n QuoteDeclineResponseSchema.parse(raw);\n },\n },\n invoices: {\n async get(uuid, opts) {\n const raw = await request(`/invoices/${uuid}`, {method: \"GET\", auth: opts});\n return InvoiceSchema.parse(raw);\n },\n async savePopUrl(uuid, key, milestone, opts) {\n const path = milestone === \"deposit\" ? `/invoices/${uuid}/deposit-pop-url` : `/invoices/${uuid}/pop-url`;\n const raw = await request(path, {method: \"PATCH\", auth: opts, body: JSON.stringify({key})});\n PopUrlUpdateResponseSchema.parse(raw);\n },\n },\n storage: {\n async presignPop(resourceId, filename, contentType, fileSize, opts) {\n const raw = await request(\"/storage/presign/public\", {\n method: \"POST\",\n auth: opts,\n body: JSON.stringify({resourceId, filename, contentType, fileSize, pathPrefix: \"pop\"}),\n });\n return PresignResponseSchema.parse(raw);\n },\n },\n submissions: {\n async create(answers, opts) {\n const path = opts?.isTenantSource ? `${submissionPath(opts)}?source=tenant` : submissionPath(opts);\n const raw = await request<{uuid: string; reference: string; token: string}>(path, {\n method: \"POST\",\n auth: \"secret\",\n body: JSON.stringify({answers, consentGiven: opts?.consentGiven, discountCode: opts?.discountCode}),\n });\n const parsed = SubmissionCreateResponseSchema.parse(raw);\n return {quoteId: parsed.uuid, quoteUrl: quotePath.replace(\":uuid\", parsed.uuid), token: parsed.token};\n },\n },\n };\n}\n","/**\n * Typed error classes so a catch block can discriminate without matching on\n * HTTP status numbers or string messages. See docs/SDK-DESIGN.md §3.\n */\n\nexport class OnablError extends Error {\n constructor(\n message: string,\n public readonly status?: number,\n ) {\n super(message);\n this.name = \"OnablError\";\n }\n}\n\n/** 404, or a customer token that doesn't grant access to this resource. */\nexport class OnablNotFound extends OnablError {\n constructor(message = \"Not found\") {\n super(message, 404);\n this.name = \"OnablNotFound\";\n }\n}\n\n/** Missing or invalid secret key / customer token. */\nexport class OnablUnauthorized extends OnablError {\n constructor(message = \"Unauthorized\") {\n super(message, 401);\n this.name = \"OnablUnauthorized\";\n }\n}\n\n/** 400 — carries field-level detail from the API's Zod validation errors. */\nexport class OnablValidation extends OnablError {\n constructor(\n message: string,\n public readonly fieldErrors?: Record<string, string[]>,\n ) {\n super(message, 400);\n this.name = \"OnablValidation\";\n }\n}\n\n/** Transport failure — network error, timeout, or an unparseable response. */\nexport class OnablNetwork extends OnablError {\n constructor(message = \"Network error\", cause?: unknown) {\n super(message);\n this.name = \"OnablNetwork\";\n if (cause !== undefined) this.cause = cause;\n }\n}\n","/**\n * Re-exported from @onabl/engine (§14.5.2b) rather than left for every\n * integrator to reimplement — see tsup.config.ts for why this code is\n * bundled into @onabl/js's own output instead of left as an external\n * \"@onabl/engine\" import: @onabl/engine is never published on its own.\n *\n * This is what finally lets visualcreme delete quote-presentation.ts, a\n * 180-line verbatim hand-copy of this same file that carried a comment\n * instructing the reader to keep it manually in sync with the engine.\n *\n * The five interfaces below are declared locally rather than imported from\n * \"@onabl/engine/presentation\" — tsup's DTS bundler (rollup-plugin-dts)\n * preserves an external type import/re-export verbatim regardless of\n * `dts.resolve`, so the published .d.ts ended up pointing at\n * \"@onabl/engine/presentation\" itself, a module every external consumer's\n * tsc then fails to find (E2307) since @onabl/engine is never published.\n * Found and fixed 2026-08-24 when visualcreme adopted this package\n * (§14.5.6) — the 0.1.0 release shipped with this bug.\n *\n * Unlike the logic visualcreme used to hand-copy, this is just the display\n * *shape* — small and stable — and the `as` casts on presentQuote/\n * groupLineItems below mean any future drift between this shape and the\n * engine's real return type fails to compile right here, in this package,\n * rather than silently diverging at a caller three repos away.\n */\nimport {presentQuote as enginePresentQuote, groupLineItems as engineGroupLineItems} from \"@onabl/engine/presentation\";\nimport type {DisplayGroup} from \"@onabl/types/config\";\nimport type {LineItem} from \"@onabl/types/engine\";\n\nexport interface QuoteRow {\n key: string;\n label: string;\n amount: number;\n isGroup: boolean;\n displayMode?: DisplayGroup[\"displayMode\"];\n children?: QuoteRow[];\n sourceItem?: LineItem;\n groupTag?: string;\n}\n\nexport interface SeparateSection {\n group: DisplayGroup;\n rows: QuoteRow[];\n amount: number;\n}\n\nexport interface GroupedItems {\n main: QuoteRow[];\n separateSections: SeparateSection[];\n groupTotals: Record<string, number>;\n}\n\nexport interface PresentQuoteInput {\n lineItems: LineItem[];\n displayGroups?: DisplayGroup[];\n finalTotal: number;\n totalAfterDiscount: number;\n discountLabel?: string | null;\n}\n\nexport interface QuotePresentation {\n rows: QuoteRow[];\n separateSections: SeparateSection[];\n subtotal: number;\n discount: {label: string; amount: number} | null;\n total: number;\n}\n\nexport function groupLineItems(lineItems: LineItem[], displayGroups?: DisplayGroup[]): GroupedItems {\n return engineGroupLineItems(lineItems, displayGroups) as GroupedItems;\n}\n\nexport function presentQuote(input: PresentQuoteInput): QuotePresentation {\n return enginePresentQuote(input) as QuotePresentation;\n}\n","/**\n * The form state machine, extracted from apps/web/components/form/MultiStepForm.tsx\n * (§14.5.2, part 2). Pure functions only — no React, no framework of any kind —\n * so any UI layer (a React hook in @onabl/react, or something else entirely)\n * can drive the same tested logic. Renders nothing; every function here takes\n * a snapshot of state and returns a value, never mutates.\n *\n * Deliberately excludes three things apps/web's current implementation\n * handles that the documented useOnablForm surface (docs/SDK-DESIGN.md §3)\n * does not — decided 2026-08-24, see docs/INTEGRATION-LAYER-TODO.md:\n *\n * - Intro screen: not modeled as a step here at all. It's pure presentation\n * (config.meta.intro) with no fields to collect or validate — the\n * integrator reads it directly and renders it before ever touching this\n * module's step navigation.\n * - Auto-advance (single radio/toggle field steps skipping the Continue\n * click): not built in here. It's a UI/interaction choice, not form logic —\n * the render layer calls next() itself after setAnswer() when it wants\n * that behavior, using visibleFields to detect the single-field case.\n * - Discount code: folded in as ordinary state here (getDiscountCode-style\n * handling lives in @onabl/react's hook, not this module) rather than\n * modeled as a synthetic step the way apps/web's current buildSteps() does.\n * Where to render the discount input within the step flow (inline on the\n * last step, or as a separate screen before submit) is left to the\n * integrator — this module has no opinion on it.\n */\n\nimport type {PublicForm, PublicFormField} from \"@onabl/contracts/public-api\";\nimport {applyDefaults} from \"@onabl/engine/engine\";\nimport {evaluateCondition} from \"@onabl/engine/resolver\";\nimport type {AnswerMap, FormStep} from \"@onabl/types/config\";\n\n/** A step that currently has at least one visible field — steps a conditional field emptied out entirely are skipped. */\nexport interface VisibleStep extends FormStep {\n fields: PublicFormField[];\n}\n\nconst UNGROUPED_STEP_ID = \"__ungrouped\";\n\n/**\n * Every step the visitor can currently navigate to, in order, filtered to\n * only those with ≥1 visible field. Ungrouped fields (stepId: null) are\n * collected into a synthetic trailing step, matching apps/web's current\n * behavior — labeled \"Details\" there today; integrators using this directly\n * can relabel as they see fit since this is just a FormStep-shaped value.\n */\nexport function getVisibleSteps(form: PublicForm, answers: AnswerMap): VisibleStep[] {\n const config = form.config;\n const steps: VisibleStep[] = [];\n\n for (const step of config.steps) {\n const fields = fieldsForStep(config.fields, step.id, answers);\n if (fields.length > 0) steps.push({...step, fields});\n }\n\n const ungroupedFields = fieldsForStep(config.fields, null, answers);\n if (ungroupedFields.length > 0) {\n steps.push({id: UNGROUPED_STEP_ID, label: \"Details\", fields: ungroupedFields});\n }\n\n return steps;\n}\n\n/** Fields visible for one step id (or `null` for ungrouped fields), given the current answers. */\nfunction fieldsForStep(fields: PublicFormField[], stepId: string | null, answers: AnswerMap): PublicFormField[] {\n return fields.filter((f) => f.stepId === stepId && f.type !== \"hidden\" && conditionMet(f.condition, answers) && conditionMet(f.scopeCondition, answers));\n}\n\nfunction conditionMet(condition: PublicFormField[\"condition\"], answers: AnswerMap): boolean {\n if (!condition) return true;\n return evaluateCondition(condition, answers);\n}\n\n/** Every field on the form, regardless of visibility — for debugging a field that won't appear. */\nexport function getAllFields(form: PublicForm): PublicFormField[] {\n return form.config.fields;\n}\n\n/**\n * Seeds the initial AnswerMap from field defaults, using @onabl/engine's\n * canonical applyDefaults — including its type-based fallback (unset number\n * fields → 0, unset toggle → false). This is a deliberate choice for this\n * new implementation, not a port of apps/web's current (leaner) local\n * version — see docs/INTEGRATION-LAYER-TODO.md's Stage 3 pre-work note for\n * why apps/web wasn't swapped onto this same behavior directly. Verify this\n * during apps/web's own SDK migration (§14.5.5), since it is a real,\n * intentional behavior difference from what's live today.\n */\nexport function getInitialAnswers(form: PublicForm): AnswerMap {\n return applyDefaults(form.config, {});\n}\n\n/**\n * Validates one step's fields against the current answers. Same rules as\n * apps/web's current validateStep(), generalized to a plain field list\n * rather than coupled to a Step union type.\n */\nexport function validateFields(fields: PublicFormField[], answers: AnswerMap): Record<string, string> {\n const errors: Record<string, string> = {};\n\n for (const field of fields) {\n if (!field.required) continue;\n const value = answers[field.key];\n\n if (field.type === \"multicheck\") {\n if (!Array.isArray(value) || value.length === 0) {\n errors[field.key] = \"Please select at least one option.\";\n }\n continue;\n }\n\n if (field.type === \"toggle\") {\n if (value === undefined || value === null || value === \"\") {\n errors[field.key] = \"Please make a selection.\";\n }\n continue;\n }\n\n if (field.type === \"number\") {\n if (value === undefined || value === null || value === \"\") {\n errors[field.key] = \"Please enter a value.\";\n continue;\n }\n const num = Number(value);\n if (isNaN(num)) {\n errors[field.key] = \"Please enter a valid number.\";\n continue;\n }\n if (field.min !== undefined && num < field.min) {\n errors[field.key] = `Minimum value is ${field.min}.`;\n continue;\n }\n if (field.max !== undefined && num > field.max) {\n errors[field.key] = `Maximum value is ${field.max}.`;\n continue;\n }\n continue;\n }\n\n if (field.type === \"date\") {\n if (!value || value === \"\") {\n errors[field.key] = \"Please enter a date.\";\n continue;\n }\n if (isNaN(new Date(value as string).getTime())) {\n errors[field.key] = \"Please enter a valid date.\";\n }\n continue;\n }\n\n if (!value || value === \"\") {\n const isChoice = field.type === \"radio\" || field.type === \"select\";\n errors[field.key] = isChoice ? \"Please make a selection.\" : \"This field is required.\";\n }\n }\n\n return errors;\n}\n"],"mappings":"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","names":["exports","groupLineItems","presentQuote","main","exports","exports","value","exports","evaluateCondition","exports","exports","exports","applyDefaults","engineGroupLineItems","enginePresentQuote"]}
1
+ {"version":3,"sources":["../../engine/dist/presentation.js","../../types/dist/config.js","../../engine/dist/expression.js","../../engine/dist/resolver.js","../../engine/dist/date-derival.js","../../engine/dist/variables.js","../../engine/dist/engine.js","../src/index.ts","../src/client.ts","../src/errors.ts","../src/presentation.ts","../src/form-state.ts"],"sourcesContent":["\"use strict\";\n/**\n * The one way a quote breakdown is turned into rows.\n *\n * There were four: the dashboard, the customer quote page, the quote PDF, and\n * the invoice PDF (which had none at all and rendered separately-quoted work as\n * ordinary billable lines). Two of them carried comments claiming to mirror the\n * others; all four had already drifted — one filtered zero-amount rows, another\n * did not; one enforced showOnQuote, another leaked internal lines to customers.\n *\n * Pure derivation over LineItem and DisplayGroup. No I/O, no framework, no\n * currency formatting — callers format, because locale is theirs to decide.\n */\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.shareOfGroup = shareOfGroup;\nexports.groupLineItems = groupLineItems;\nexports.presentQuote = presentQuote;\n/** The share of a line item that belongs to a display group. */\nfunction shareOfGroup(item, tag) {\n return item.groupAmounts?.[tag] ?? (item.tag === tag ? item.amount : 0);\n}\nfunction labelWithFactor(item) {\n if (item.factor === undefined || item.factor === 1)\n return item.label;\n const percent = Math.abs(Math.round((item.factor - 1) * 100));\n return item.factor > 1 ? `${item.label} (+${percent}%)` : `${item.label} (${percent}% off)`;\n}\n/**\n * Splits visible line items into payable rows and separately-quoted sections.\n *\n * `showOnQuote` is enforced here and only here. Zero-amount rows are dropped —\n * a customer should not read a line that costs nothing.\n */\nfunction groupLineItems(lineItems, displayGroups) {\n const visible = lineItems.filter((item) => item.showOnQuote);\n const groupTotals = {};\n if (!displayGroups || displayGroups.length === 0) {\n const main = visible\n .filter((item) => item.amount !== 0)\n .map((item) => ({ key: item.ruleId, label: labelWithFactor(item), amount: item.amount, isGroup: false, sourceItem: item }));\n return { main, separateSections: [], groupTotals };\n }\n const main = [];\n const separateSections = [];\n // How much of each item has already been accounted for — either rendered in a\n // shown group, or removed from the payable total by an excluded one.\n //\n // Accounting per share rather than per item matters: an item split across two\n // groups is only partly handled by either, so claiming the whole item as soon\n // as one group touched it silently dropped the rest of its value from the\n // breakdown while leaving it in the total.\n const accounted = new Map();\n const account = (item, amount) => accounted.set(item.ruleId, (accounted.get(item.ruleId) ?? 0) + amount);\n for (const group of displayGroups) {\n const matching = visible.filter((item) => (item.groupAmounts && group.tag in item.groupAmounts) || item.tag === group.tag);\n const total = matching.reduce((sum, item) => sum + shareOfGroup(item, group.tag), 0);\n groupTotals[group.tag] = total;\n // Hiding a group hides the *grouping*, not the money. Its share stays\n // unaccounted and reappears as an ungrouped row below, so the breakdown\n // still adds up to what the customer is charged. An excluded group is\n // different: its money genuinely leaves the payable total, so its share is\n // accounted for whether or not the section is shown.\n if (group.excludeFromTotal)\n matching.forEach((item) => account(item, shareOfGroup(item, group.tag)));\n if (!group.showOnQuote || matching.length === 0 || total === 0)\n continue;\n if (!group.excludeFromTotal)\n matching.forEach((item) => account(item, shareOfGroup(item, group.tag)));\n const active = matching.filter((item) => shareOfGroup(item, group.tag) !== 0);\n const rowFor = (item) => ({\n key: `${group.tag}:${item.ruleId}`,\n label: item.label,\n amount: shareOfGroup(item, group.tag),\n isGroup: false,\n sourceItem: item,\n groupTag: group.tag,\n });\n let rows;\n if (group.displayMode === \"individual\") {\n rows = active.map(rowFor);\n }\n else if (group.displayMode === \"both\" || group.displayMode === \"both_cashless\") {\n // \"both_cashless\" carries its children like \"both\"; customer-facing\n // renderers omit the per-child amounts. The subtotal is still shown.\n rows = [{ key: group.tag, label: group.label, amount: total, isGroup: true, displayMode: group.displayMode, children: active.map(rowFor), groupTag: group.tag }];\n }\n else {\n // \"grouped\" — a single subtotal row, named after its only item when there is one\n const label = active.length === 1 ? (active[0]?.label ?? group.label) : group.label;\n rows = [{ key: group.tag, label, amount: total, isGroup: true, displayMode: \"grouped\", groupTag: group.tag }];\n }\n if (group.excludeFromTotal)\n separateSections.push({ group, rows, amount: total });\n else\n main.push(...rows);\n }\n // Whatever no group rendered or removed still belongs on the quote.\n for (const item of visible) {\n const remaining = Math.round((item.amount - (accounted.get(item.ruleId) ?? 0)) * 100) / 100;\n if (remaining === 0)\n continue;\n main.push({ key: item.ruleId, label: labelWithFactor(item), amount: remaining, isGroup: false, sourceItem: item });\n }\n return { main, separateSections, groupTotals };\n}\n/**\n * Builds the complete display model for a quote or invoice.\n *\n * The discount is always the difference between the two stored totals, never\n * re-derived from a percentage and a base. Re-deriving is how the invoice PDF\n * came to print a discount computed off the already-discounted figure, and how\n * both PDFs could show two discount lines when only one had been applied.\n */\nfunction presentQuote(input) {\n const { main, separateSections } = groupLineItems(input.lineItems, input.displayGroups);\n const subtotal = input.finalTotal;\n const discountAmount = Math.round((input.finalTotal - input.totalAfterDiscount) * 100) / 100;\n return {\n rows: main,\n separateSections,\n subtotal,\n discount: discountAmount > 0 ? { label: input.discountLabel ?? \"Discount\", amount: discountAmount } : null,\n total: input.totalAfterDiscount,\n };\n}\n","\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.isAndCondition = isAndCondition;\nfunction isAndCondition(c) {\n return c.operator === \"and\";\n}\n","\"use strict\";\n/**\n * The expression language shared by the pricing engine and the wizard's formula\n * builder.\n *\n * Previously there were two implementations: a hand-written parser here and\n * mathjs in the dashboard preview. They could — and did — disagree, so a tenant\n * saw one number while building and the customer was quoted another.\n * Everything now parses and evaluates through this module.\n *\n * Grammar:\n * expr → term (('+' | '-') term)*\n * term → factor (('*' | '/') factor)*\n * factor → '-'? primary\n * primary → NUMBER | '$' name | 'field:' name | 'lookup:' ref | '(' expr ')'\n *\n * Parentheses are the reason this module exists. Without them a tenant cannot\n * express \"(20 + 3) x 3\" at all, and the flat left-to-right chip UI silently\n * produced the BODMAS reading instead.\n *\n * Pure — no I/O, never throws. Errors are returned, matching engine convention.\n */\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.parseExpression = parseExpression;\nexports.evaluateNode = evaluateNode;\nexports.evaluateExpression = evaluateExpression;\nexports.printExpression = printExpression;\nexports.collectFieldKeys = collectFieldKeys;\nconst IDENT = /[\\w]/;\nfunction tokenise(source) {\n const lexemes = [];\n const src = source.trim();\n let i = 0;\n const readIdent = (from) => {\n let out = \"\";\n let j = from;\n while (j < src.length && IDENT.test(src[j]))\n out += src[j++];\n return out;\n };\n while (i < src.length) {\n const ch = src[i];\n if (ch === \" \" || ch === \"\\t\" || ch === \"\\n\") {\n i++;\n continue;\n }\n if (ch === \"$\") {\n const key = readIdent(i + 1);\n lexemes.push({ type: \"TOKEN\", value: key, position: i });\n i += key.length + 1;\n continue;\n }\n if (src.startsWith(\"field:\", i)) {\n const key = readIdent(i + 6);\n lexemes.push({ type: \"FIELD\", value: key, position: i });\n i += key.length + 6;\n continue;\n }\n if (src.startsWith(\"lookup:\", i)) {\n const ref = readIdent(i + 7);\n lexemes.push({ type: \"LOOKUP\", value: ref, position: i });\n i += ref.length + 7;\n continue;\n }\n if (/[0-9]/.test(ch) || (ch === \".\" && /[0-9]/.test(src[i + 1] ?? \"\"))) {\n let num = \"\";\n while (i < src.length && /[0-9.]/.test(src[i]))\n num += src[i++];\n lexemes.push({ type: \"NUMBER\", value: num, position: i - num.length });\n continue;\n }\n if (ch === \"+\" || ch === \"-\" || ch === \"*\" || ch === \"/\") {\n lexemes.push({ type: \"OP\", value: ch, position: i });\n i++;\n continue;\n }\n if (ch === \"(\") {\n lexemes.push({ type: \"LPAREN\", value: ch, position: i });\n i++;\n continue;\n }\n if (ch === \")\") {\n lexemes.push({ type: \"RPAREN\", value: ch, position: i });\n i++;\n continue;\n }\n lexemes.push({ type: \"UNKNOWN\", value: ch, position: i });\n i++;\n }\n lexemes.push({ type: \"EOF\", value: \"\", position: src.length });\n return lexemes;\n}\nfunction parseExpression(source) {\n const errors = [];\n if (!source || source.trim().length === 0) {\n return { node: null, errors: [{ ruleId: null, message: \"Empty expression\" }] };\n }\n const lexemes = tokenise(source);\n let pos = 0;\n const peek = () => lexemes[pos] ?? { type: \"EOF\", value: \"\", position: 0 };\n const next = () => lexemes[pos++] ?? { type: \"EOF\", value: \"\", position: 0 };\n const fail = (message) => {\n errors.push({ ruleId: null, message });\n };\n function parsePrimary() {\n const lexeme = next();\n switch (lexeme.type) {\n case \"NUMBER\": {\n const value = parseFloat(lexeme.value);\n if (Number.isNaN(value)) {\n fail(`Invalid number \"${lexeme.value}\"`);\n return null;\n }\n return { kind: \"number\", value };\n }\n case \"TOKEN\":\n if (lexeme.value === \"\") {\n fail(\"Malformed token reference — nothing after '$'\");\n return null;\n }\n return { kind: \"token\", key: lexeme.value };\n case \"FIELD\":\n if (lexeme.value === \"\") {\n fail(\"Malformed field reference — nothing after 'field:'\");\n return null;\n }\n return { kind: \"field\", key: lexeme.value };\n case \"LOOKUP\":\n if (lexeme.value === \"\") {\n fail(\"Malformed lookup reference — nothing after 'lookup:'\");\n return null;\n }\n return { kind: \"lookup\", ref: lexeme.value };\n case \"LPAREN\": {\n const inner = parseExpr();\n if (peek().type === \"RPAREN\") {\n next();\n }\n else {\n fail(\"Unclosed '(' — every opening bracket needs a closing one\");\n }\n return inner;\n }\n case \"EOF\":\n fail(\"Expression ended unexpectedly\");\n return null;\n default:\n fail(`Unexpected \"${lexeme.value}\" in expression`);\n return null;\n }\n }\n function parseFactor() {\n if (peek().type === \"OP\" && peek().value === \"-\") {\n next();\n const operand = parseFactor();\n return operand === null ? null : { kind: \"negate\", operand };\n }\n return parsePrimary();\n }\n function parseTerm() {\n let left = parseFactor();\n while (peek().type === \"OP\" && (peek().value === \"*\" || peek().value === \"/\")) {\n const op = next().value;\n const right = parseFactor();\n if (left === null || right === null)\n return null;\n left = { kind: \"binary\", op, left, right };\n }\n return left;\n }\n function parseExpr() {\n let left = parseTerm();\n while (peek().type === \"OP\" && (peek().value === \"+\" || peek().value === \"-\")) {\n const op = next().value;\n const right = parseTerm();\n if (left === null || right === null)\n return null;\n left = { kind: \"binary\", op, left, right };\n }\n return left;\n }\n const node = parseExpr();\n if (peek().type !== \"EOF\") {\n fail(`Unexpected \"${peek().value}\" after the end of the expression`);\n }\n return { node: errors.length > 0 ? null : node, errors };\n}\nfunction evaluateNode(node, scope) {\n const errors = [];\n function walk(n) {\n switch (n.kind) {\n case \"number\":\n return n.value;\n case \"token\": {\n if (!(n.key in scope.tokens)) {\n errors.push({ ruleId: null, message: `Undefined token: \"$${n.key}\"` });\n return 0;\n }\n return scope.tokens[n.key];\n }\n case \"field\": {\n const fields = scope.fields ?? {};\n if (!(n.key in fields)) {\n errors.push({ ruleId: null, message: `Unanswered field referenced in a price: \"${n.key}\"` });\n return 0;\n }\n const value = fields[n.key];\n if (!Number.isFinite(value)) {\n errors.push({ ruleId: null, message: `Field \"${n.key}\" is not a number` });\n return 0;\n }\n return value;\n }\n case \"lookup\": {\n const lookups = scope.lookups ?? {};\n if (!(n.ref in lookups)) {\n errors.push({ ruleId: null, message: `Unresolved lookup reference: \"lookup:${n.ref}\"` });\n return 0;\n }\n return lookups[n.ref];\n }\n case \"negate\":\n return -walk(n.operand);\n case \"binary\": {\n const left = walk(n.left);\n const right = walk(n.right);\n switch (n.op) {\n case \"+\":\n return left + right;\n case \"-\":\n return left - right;\n case \"*\":\n return left * right;\n case \"/\":\n if (right === 0) {\n errors.push({ ruleId: null, message: \"Division by zero in expression\" });\n return 0;\n }\n return left / right;\n }\n }\n }\n }\n const value = walk(node);\n return { value: Number.isFinite(value) ? value : 0, errors };\n}\n/** Parses and evaluates in one step — the common case. */\nfunction evaluateExpression(source, scope) {\n const { node, errors } = parseExpression(source);\n if (node === null)\n return { value: 0, errors };\n return evaluateNode(node, scope);\n}\n// ── Printing ─────────────────────────────────────────────────────────────────\nconst PRECEDENCE = { \"+\": 1, \"-\": 1, \"*\": 2, \"/\": 2 };\n/**\n * Renders an AST back to source, adding brackets only where precedence or\n * associativity requires them. Round-trips: parse(print(node)) equals node.\n */\nfunction printExpression(node) {\n // `+` and `*` are associative, so `a + (b + c)` and `a * (b * c)` mean exactly\n // what they mean without the brackets. `-` and `/` are not: dropping them in\n // `a - (b - c)` or `a / (b / c)` changes the value.\n const ASSOCIATIVE = { \"+\": true, \"*\": true, \"-\": false, \"/\": false };\n function render(n, parentPrecedence = 0, isRightOperand = false, parentOp = null) {\n switch (n.kind) {\n case \"number\":\n return String(n.value);\n case \"token\":\n return `$${n.key}`;\n case \"field\":\n return `field:${n.key}`;\n case \"lookup\":\n return `lookup:${n.ref}`;\n case \"negate\":\n return `-${render(n.operand, 3)}`;\n case \"binary\": {\n const precedence = PRECEDENCE[n.op];\n const body = `${render(n.left, precedence, false, n.op)} ${n.op} ${render(n.right, precedence, true, n.op)}`;\n const parentKeepsOrder = parentOp !== null && !ASSOCIATIVE[parentOp];\n const needsBrackets = precedence < parentPrecedence || (precedence === parentPrecedence && isRightOperand && parentKeepsOrder);\n return needsBrackets ? `(${body})` : body;\n }\n }\n }\n return render(node);\n}\n/** Collects every `field:` key an expression depends on. */\nfunction collectFieldKeys(node) {\n const keys = new Set();\n (function walk(n) {\n if (n.kind === \"field\")\n keys.add(n.key);\n else if (n.kind === \"binary\") {\n walk(n.left);\n walk(n.right);\n }\n else if (n.kind === \"negate\")\n walk(n.operand);\n })(node);\n return [...keys];\n}\n","\"use strict\";\n/**\n * packages/engine/src/resolver.ts\n *\n * Expression resolver and condition evaluator for the onabl pricing engine.\n *\n * resolveExpression() — evaluates an expression string against tokens, lookup\n * values and (optionally) customer answers. Grammar, parsing and evaluation all\n * live in ./expression, which the dashboard formula builder shares — so a\n * preview and a live quote can never disagree.\n *\n * evaluateCondition() — evaluates a single Condition against an AnswerMap.\n * Handles all seven operators including `includes` for multicheck (string[]) fields.\n *\n * Both functions are pure — no side effects, no external dependencies.\n */\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.resolveExpression = resolveExpression;\nexports.evaluateCondition = evaluateCondition;\nconst config_1 = require(\"@onabl/types/config\");\nconst expression_1 = require(\"./expression\");\n// ─── Public: resolveExpression ────────────────────────────────────────────────\n/**\n * Resolves an expression string to a numeric value.\n *\n * @param expr - Expression string e.g. \"$base_rate * 1.5\", \"500\", \"lookup:r02\"\n * @param variables - Flat variable store from FormConfig.variables\n * @param lookupValues - Pre-resolved lookup table outputs (built during phase 1)\n * @returns { value, errors } — errors is empty on success\n */\nfunction resolveExpression(expr, variables, lookupValues, fields) {\n return (0, expression_1.evaluateExpression)(expr, { tokens: variables, lookups: lookupValues, fields });\n}\n// ─── Public: evaluateCondition ────────────────────────────────────────────────\n/**\n * Evaluates a Condition against the current AnswerMap.\n *\n * Returns true if the condition is satisfied, false otherwise.\n * Returns false (safe default = rule suppressed) if the field is missing from answers.\n *\n * The `includes` operator is the only operator that expects a string[] answer.\n * All other operators expect a scalar (string | number | boolean).\n */\nfunction evaluateCondition(condition, answers) {\n if ((0, config_1.isAndCondition)(condition)) {\n return condition.clauses.every((c) => evaluateCondition(c, answers));\n }\n const { field, operator, value: condValue } = condition;\n const answer = answers[field];\n // Missing field — treat as condition not met (safe default: suppress the rule)\n if (answer === undefined || answer === null) {\n return false;\n }\n // `includes` — answer is string[] (multicheck) or string (radio fallback for legacy configs)\n if (operator === \"includes\") {\n if (Array.isArray(answer))\n return answer.includes(String(condValue));\n return String(answer) === String(condValue);\n }\n // `includes_any` — answer must be string[], condValue must be string[]\n if (operator === \"includes_any\") {\n if (!Array.isArray(answer) || !Array.isArray(condValue)) {\n return false;\n }\n return condValue.some((v) => answer.includes(v));\n }\n // `in` — answer must be scalar, condValue must be string[]\n if (operator === \"in\") {\n if (Array.isArray(answer) || !Array.isArray(condValue)) {\n return false;\n }\n return condValue.includes(String(answer));\n }\n // All remaining operators work on scalars\n // Array answers are not valid for scalar operators\n if (Array.isArray(answer)) {\n return false;\n }\n const op = operator;\n switch (op) {\n case \"eq\":\n return answer === condValue;\n case \"neq\":\n return answer !== condValue;\n case \"gt\":\n case \"gte\":\n case \"lt\":\n case \"lte\": {\n const numAnswer = Number(answer);\n const numValue = Number(condValue);\n if (isNaN(numAnswer) || isNaN(numValue)) {\n return false;\n }\n if (op === \"gt\")\n return numAnswer > numValue;\n if (op === \"gte\")\n return numAnswer >= numValue;\n if (op === \"lt\")\n return numAnswer < numValue;\n if (op === \"lte\")\n return numAnswer <= numValue;\n return false;\n }\n default: {\n // Exhaustive check — TypeScript should catch unknown operators at compile time\n const _exhaustive = op;\n void _exhaustive;\n return false;\n }\n }\n}\n","\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.injectDateDerivals = injectDateDerivals;\n/**\n * Injects derived date fields into answers based on FormConfig.\n *\n * For each date field with derivedFields config, computes:\n * - isWeekend: `__is_weekend__<key>` = true if Sat/Sun\n * - isPeakSeason: `__is_peak_season__<key>` = true if month matches config\n * - daysUntil: `__days_until__<key>` = integer days from today (can be negative)\n *\n * Uses local date parsing (YYYY-MM-DD split + new Date(y, m-1, d)) to avoid UTC-offset bugs.\n *\n * `now` defaults to the current time but is an explicit parameter so this\n * function stays a pure function of its inputs — callers needing determinism\n * (e.g. tests) can pass a fixed date.\n */\nfunction injectDateDerivals(config, raw, now = new Date()) {\n const augmented = { ...raw };\n for (const field of config.fields) {\n if (field.type !== \"date\" || !field.derivedFields)\n continue;\n const value = raw[field.key];\n if (!value || typeof value !== \"string\")\n continue;\n const [year, month, day] = value.split(\"-\").map(Number);\n if (!year || !month || !day)\n continue;\n // Local date: new Date(y, m-1, d) avoids UTC-offset bugs\n // (new Date(\"2025-01-01\") is midnight UTC, which may be Dec 31 UTC-5)\n const date = new Date(year, month - 1, day);\n const { isWeekend, isPeakSeason, daysUntil } = field.derivedFields;\n if (isWeekend) {\n const d = date.getDay();\n augmented[`__is_weekend__${field.key}`] = d === 0 || d === 6;\n }\n if (isPeakSeason?.length) {\n augmented[`__is_peak_season__${field.key}`] = isPeakSeason.includes(date.getMonth() + 1);\n }\n if (daysUntil) {\n const today = new Date(now);\n today.setHours(0, 0, 0, 0);\n const diff = Math.round((date.getTime() - today.getTime()) / 86_400_000);\n augmented[`__days_until__${field.key}`] = diff;\n }\n }\n return augmented;\n}\n","\"use strict\";\n/**\n * packages/engine/src/variables.ts\n *\n * Resolves FormConfig.tokens — where a value may be a literal number or an\n * expression string referencing other tokens (e.g. \"$hourly_rate * 1.5\") —\n * down to a flat Record<string, number> that the rest of the engine consumes\n * exactly as it always has.\n *\n * Pure — no side effects. Never throws; a broken token (undefined ref,\n * circular ref) resolves to 0 and reports an EngineError instead.\n */\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.resolveTokens = resolveTokens;\nconst resolver_1 = require(\"./resolver\");\nfunction extractTokenRefs(expr) {\n const refs = new Set();\n for (const match of expr.matchAll(/\\$(\\w+)/g)) {\n refs.add(match[1]);\n }\n return Array.from(refs);\n}\n/**\n * Resolves raw tokens (literals + expressions) into a flat numeric map.\n *\n * Resolution order is dependency-driven (a token referencing another is\n * resolved after its dependency), not insertion order. Circular references\n * are detected and reported as an EngineError; the cyclic token resolves\n * to 0 rather than infinite-looping.\n */\nfunction resolveTokens(rawTokens) {\n const errors = [];\n const resolved = {};\n const resolving = new Set();\n const done = new Set();\n function resolveKey(key) {\n if (done.has(key))\n return resolved[key] ?? 0;\n const raw = rawTokens[key];\n if (raw === undefined)\n return 0; // referencing expression will surface \"Undefined variable\" itself\n if (typeof raw === \"number\") {\n resolved[key] = raw;\n done.add(key);\n return raw;\n }\n if (resolving.has(key)) {\n errors.push({ ruleId: null, message: `Circular reference detected in token \"$${key}\"` });\n resolved[key] = 0;\n done.add(key);\n return 0;\n }\n resolving.add(key);\n for (const dep of extractTokenRefs(raw)) {\n resolveKey(dep);\n }\n resolving.delete(key);\n const { value, errors: exprErrors } = (0, resolver_1.resolveExpression)(raw, resolved, {});\n errors.push(...exprErrors.map((e) => ({ ...e, message: `Token \"$${key}\": ${e.message}` })));\n resolved[key] = value;\n done.add(key);\n return value;\n }\n for (const key of Object.keys(rawTokens)) {\n resolveKey(key);\n }\n return { variables: resolved, errors };\n}\n","\"use strict\";\n/**\n * Core pricing engine for onabl.\n *\n * applyDefaults() — fills missing answers with field defaultValues from config.\n *\n * calculate() — runs the three-phase pricing calculation against a FormConfig\n * and a fully-populated AnswerMap. Returns an EngineResult.\n *\n * Both functions are pure — no side effects, no I/O, no external dependencies.\n * calculate() never throws — all errors are captured in EngineResult.errors.\n *\n * IMPORTANT: finalTotal is always pre-discount. Discount codes are applied at\n * the API layer after calculate() returns. The engine has no knowledge of discounts.\n */\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.resolveTokens = exports.injectDateDerivals = void 0;\nexports.applyDefaults = applyDefaults;\nexports.calculate = calculate;\nconst resolver_1 = require(\"./resolver\");\nconst date_derival_1 = require(\"./date-derival\");\nObject.defineProperty(exports, \"injectDateDerivals\", { enumerable: true, get: function () { return date_derival_1.injectDateDerivals; } });\nconst variables_1 = require(\"./variables\");\nObject.defineProperty(exports, \"resolveTokens\", { enumerable: true, get: function () { return variables_1.resolveTokens; } });\nconst presentation_1 = require(\"./presentation\");\n// ─── Group assignment helper ──────────────────────────────────────────────────\n/**\n * Computes groupAmounts for a rule's groupAssignments.\n * For each assignment:\n * - If expression is set, evaluate it to get the per-group amount\n * - Otherwise, use the baseAmount (the primary computed value for the rule)\n *\n * Returns a Record<tag, amount> mapping. Errors are pre-stamped with ruleId so\n * every call site doesn't have to repeat `.map(e => ({...e, ruleId}))`.\n */\nfunction computeGroupAmounts(groupAssignments, baseAmount, variables, lookupValues, ruleId) {\n if (!groupAssignments || groupAssignments.length === 0) {\n return { errors: [] };\n }\n const groupAmounts = {};\n const errors = [];\n for (const assignment of groupAssignments) {\n if (assignment.expression) {\n // Evaluate the custom expression for this group\n const { value, errors: exprErrors } = (0, resolver_1.resolveExpression)(assignment.expression, variables, lookupValues);\n errors.push(...exprErrors.map((e) => ({ ...e, ruleId })));\n groupAmounts[assignment.tag] = roundCents(value);\n }\n else {\n // Use the base amount (the rule's primary computed value)\n groupAmounts[assignment.tag] = baseAmount;\n }\n }\n return { groupAmounts: Object.keys(groupAmounts).length > 0 ? groupAmounts : undefined, errors };\n}\n// ─── Rounding helper ──────────────────────────────────────────────────────────\n/**\n * Rounds to 2 decimal places (cents) with IEEE 754 midpoint correction.\n * The Number.EPSILON addend nudges true 0.5 values above the representation\n * that would round incorrectly due to float imprecision.\n */\nfunction roundCents(n) {\n return Math.round((n + Number.EPSILON) * 100) / 100;\n}\n// ─── applyDefaults ────────────────────────────────────────────────────────────\n/**\n * Returns a new AnswerMap with any missing field keys filled in from\n * field.defaultValue. Fields with a null defaultValue are omitted if absent\n * (they remain missing — required field validation is the form renderer's job).\n *\n * Does not mutate the input answers object.\n *\n * Takes `Pick<FormConfig, \"fields\">` rather than the full FormConfig — this\n * only ever reads `.fields`, and requiring the whole config (with its\n * `rules`/`tokens`) made it uncallable against @onabl/contracts's public-safe\n * form shape, which deliberately excludes those. A full FormConfig still\n * satisfies this narrower type, so existing callers are unaffected.\n */\nfunction applyDefaults(config, answers) {\n const result = { ...answers };\n for (const field of config.fields) {\n if (result[field.key] === undefined || result[field.key] === null) {\n if (field.defaultValue !== null && field.defaultValue !== undefined) {\n result[field.key] = field.defaultValue;\n }\n else {\n // Safe type-based fallback when no explicit default is set\n if (field.type === \"number\")\n result[field.key] = 0;\n if (field.type === \"toggle\")\n result[field.key] = false;\n }\n }\n }\n return result;\n}\n// ─── Phase 1 helpers ─────────────────────────────────────────────────────────\nfunction processUnitRate(rule, answers, variables, lookupValues, fieldValues, quantityUnit) {\n const errors = [];\n const quantityRaw = answers[rule.quantityField];\n const quantity = Number(quantityRaw);\n if (quantityRaw === undefined || quantityRaw === null) {\n errors.push({\n ruleId: rule.id,\n message: `unit_rate rule \"${rule.id}\": field \"${rule.quantityField}\" not found in answers`,\n });\n return { lineItem: null, amount: 0, errors };\n }\n if (isNaN(quantity)) {\n errors.push({\n ruleId: rule.id,\n message: `unit_rate rule \"${rule.id}\": field \"${rule.quantityField}\" is not a number (got \"${quantityRaw}\")`,\n });\n return { lineItem: null, amount: 0, errors };\n }\n const { value: rate, errors: rateErrors } = (0, resolver_1.resolveExpression)(rule.rateExpr, variables, lookupValues, fieldValues);\n // Stamp ruleId onto resolver errors\n const stampedErrors = rateErrors.map((e) => ({ ...e, ruleId: rule.id }));\n errors.push(...stampedErrors);\n const amount = roundCents(quantity * rate);\n const { groupAmounts, errors: groupErrors } = computeGroupAmounts(rule.groupAssignments, amount, variables, lookupValues, rule.id);\n errors.push(...groupErrors);\n const lineItem = {\n ruleId: rule.id,\n label: rule.label,\n amount,\n type: \"unit_rate\",\n showOnQuote: rule.showOnQuote,\n ...(rule.tag !== undefined && { tag: rule.tag }),\n ...(groupAmounts !== undefined && { groupAmounts }),\n quantity,\n ...(quantityUnit !== undefined && { quantityUnit }),\n ratePerUnit: rate,\n };\n return { lineItem, amount, errors };\n}\nfunction processConditionalAddon(rule, variables, lookupValues, fieldValues) {\n const { value: rawAmount, errors: resolveErrors } = (0, resolver_1.resolveExpression)(rule.amountExpr, variables, lookupValues, fieldValues);\n const amount = roundCents(rawAmount);\n const errors = resolveErrors.map((e) => ({ ...e, ruleId: rule.id }));\n const { groupAmounts, errors: groupErrors } = computeGroupAmounts(rule.groupAssignments, amount, variables, lookupValues, rule.id);\n errors.push(...groupErrors);\n const lineItem = {\n ruleId: rule.id,\n label: rule.label,\n amount,\n type: \"conditional_addon\",\n showOnQuote: rule.showOnQuote,\n ...(rule.tag !== undefined && { tag: rule.tag }),\n ...(groupAmounts !== undefined && { groupAmounts }),\n };\n return { lineItem, amount, errors };\n}\nfunction processLookupTable(rule, answers, variables, lookupValues) {\n const errors = [];\n const rowAnswer = String(answers[rule.rowField] ?? \"\");\n const colAnswer = String(answers[rule.colField] ?? \"\");\n if (answers[rule.rowField] === undefined) {\n errors.push({\n ruleId: rule.id,\n message: `lookup_table rule \"${rule.id}\": row field \"${rule.rowField}\" not found in answers`,\n });\n }\n if (answers[rule.colField] === undefined) {\n errors.push({\n ruleId: rule.id,\n message: `lookup_table rule \"${rule.id}\": col field \"${rule.colField}\" not found in answers`,\n });\n }\n if (errors.length > 0) {\n return { lineItem: null, amount: 0, errors };\n }\n const row = rule.table[rowAnswer];\n if (row === undefined) {\n errors.push({\n ruleId: rule.id,\n message: `lookup_table rule \"${rule.id}\": no row for value \"${rowAnswer}\"`,\n });\n return { lineItem: null, amount: 0, errors };\n }\n const rawAmount = row[colAnswer];\n if (rawAmount === undefined) {\n errors.push({\n ruleId: rule.id,\n message: `lookup_table rule \"${rule.id}\": no column \"${colAnswer}\" in row \"${rowAnswer}\"`,\n });\n return { lineItem: null, amount: 0, errors };\n }\n const amount = roundCents(rawAmount);\n const { groupAmounts, errors: groupErrors } = computeGroupAmounts(rule.groupAssignments, amount, variables, lookupValues, rule.id);\n errors.push(...groupErrors);\n const lineItem = {\n ruleId: rule.id,\n label: rule.label,\n amount,\n type: \"lookup_table\",\n showOnQuote: rule.showOnQuote,\n ...(rule.tag !== undefined && { tag: rule.tag }),\n ...(groupAmounts !== undefined && { groupAmounts }),\n };\n return { lineItem, amount, errors };\n}\n// ─── Phase 2 helpers ──────────────────────────────────────────────────────────\nfunction processSelectionMultiplier(rule, answers, runningTotal, variables, lookupValues) {\n const errors = [];\n const selection = String(answers[rule.field] ?? \"\");\n if (answers[rule.field] === undefined) {\n // Field not answered yet — treat as neutral (1.0), same as an option with no multiplier entry\n return { lineItem: null, newTotal: runningTotal, errors };\n }\n const factor = rule.multipliers[selection];\n if (factor === undefined) {\n // Selection has no multiplier entry — treat as 1.0 (neutral), not an error.\n // Some options may intentionally not have a multiplier.\n return { lineItem: null, newTotal: runningTotal, errors };\n }\n const appliedTo = runningTotal;\n const newTotal = runningTotal * factor;\n const amount = roundCents(newTotal - appliedTo); // the delta — positive = markup, negative = discount\n const { groupAmounts, errors: groupErrors } = computeGroupAmounts(rule.groupAssignments, amount, variables, lookupValues, rule.id);\n errors.push(...groupErrors);\n const lineItem = {\n ruleId: rule.id,\n label: rule.label,\n amount,\n type: \"selection_multiplier\",\n showOnQuote: rule.showOnQuote,\n ...(rule.tag !== undefined && { tag: rule.tag }),\n ...(groupAmounts !== undefined && { groupAmounts }),\n factor,\n appliedTo,\n };\n return { lineItem, newTotal, errors };\n}\nfunction processConditionalMultiplier(rule, variables, lookupValues, fieldValues, runningTotal) {\n const { value: factor, errors: resolveErrors } = (0, resolver_1.resolveExpression)(rule.factorExpr, variables, lookupValues, fieldValues);\n const errors = resolveErrors.map((e) => ({ ...e, ruleId: rule.id }));\n const appliedTo = runningTotal;\n const newTotal = runningTotal * factor;\n const amount = roundCents(newTotal - appliedTo);\n const { groupAmounts, errors: groupErrors } = computeGroupAmounts(rule.groupAssignments, amount, variables, lookupValues, rule.id);\n errors.push(...groupErrors);\n const lineItem = {\n ruleId: rule.id,\n label: rule.label,\n amount,\n type: \"conditional_multiplier\",\n showOnQuote: rule.showOnQuote,\n ...(rule.tag !== undefined && { tag: rule.tag }),\n ...(groupAmounts !== undefined && { groupAmounts }),\n factor,\n appliedTo,\n };\n return { lineItem, newTotal, errors };\n}\n// ─── Phase 3 helper ───────────────────────────────────────────────────────────\nfunction processFloorMinimum(rule, variables, lookupValues, fieldValues, currentTotal) {\n const { value: minimum, errors: resolveErrors } = (0, resolver_1.resolveExpression)(rule.minimumExpr, variables, lookupValues, fieldValues);\n const errors = resolveErrors.map((e) => ({ ...e, ruleId: rule.id }));\n if (currentTotal < minimum) {\n const amount = roundCents(minimum - currentTotal); // the top-up amount\n const { groupAmounts, errors: groupErrors } = computeGroupAmounts(rule.groupAssignments, amount, variables, lookupValues, rule.id);\n errors.push(...groupErrors);\n const lineItem = {\n ruleId: rule.id,\n label: rule.label,\n amount,\n type: \"floor_minimum\",\n showOnQuote: rule.showOnQuote,\n ...(rule.tag !== undefined && { tag: rule.tag }),\n ...(groupAmounts !== undefined && { groupAmounts }),\n };\n return { lineItem, finalTotal: minimum, minimumApplied: true, minimumAmount: minimum, errors };\n }\n return { lineItem: null, finalTotal: currentTotal, minimumApplied: false, minimumAmount: minimum, errors };\n}\n// ─── Totals authority ─────────────────────────────────────────────────────────\n/**\n * Builds the reconciled QuoteTotals and checks that the parts add up.\n *\n * Two invariants, both enforced as errors rather than tolerances:\n *\n * 1. An item allocated across display groups must allocate its whole amount\n * and no more — sum(groupAmounts) === amount. Without this a breakdown can\n * silently double-count an item that belongs to two groups, or drop part of\n * one whose group expressions do not add up.\n *\n * 2. Visible line items must sum to gross. This is the check that would have\n * caught every reconciliation defect in the audit at authoring time.\n *\n * Amounts are compared in integer cents, so this is exact — no epsilon.\n */\nfunction buildTotals(lineItems, finalTotal, displayGroups, minimumApplied) {\n const errors = [];\n const cents = (n) => Math.round(n * 100);\n for (const item of lineItems) {\n if (!item.groupAmounts)\n continue;\n const allocated = Object.values(item.groupAmounts).reduce((a, b) => a + b, 0);\n if (cents(allocated) !== cents(item.amount)) {\n errors.push({\n ruleId: item.ruleId,\n message: `\"${item.label}\" is split across groups totalling ${allocated.toFixed(2)}, but the item is ${item.amount.toFixed(2)} — the split must account for the whole amount`,\n });\n }\n }\n // Grouped through the shared presenter, so the totals the engine states and\n // the rows every renderer draws come from one implementation.\n const { groupTotals: rawGroupTotals } = (0, presentation_1.groupLineItems)(lineItems, displayGroups);\n const groupTotals = {};\n let separatelyQuoted = 0;\n for (const group of displayGroups ?? []) {\n const total = rawGroupTotals[group.tag] ?? 0;\n groupTotals[group.tag] = roundCents(total);\n if (group.excludeFromTotal)\n separatelyQuoted += total;\n }\n // A floor minimum tops the total up to a fixed figure, so the line items\n // deliberately do not sum to it. Every other configuration must reconcile.\n if (!minimumApplied) {\n const visible = lineItems.filter((i) => i.showOnQuote).reduce((a, i) => a + i.amount, 0);\n const hidden = lineItems.filter((i) => !i.showOnQuote).reduce((a, i) => a + i.amount, 0);\n if (cents(visible + hidden) !== cents(finalTotal)) {\n errors.push({\n ruleId: null,\n message: `Line items sum to ${(visible + hidden).toFixed(2)} but the quote total is ${finalTotal.toFixed(2)} — the breakdown does not reconcile`,\n });\n }\n }\n return {\n totals: {\n gross: roundCents(finalTotal),\n separatelyQuoted: roundCents(separatelyQuoted),\n payable: roundCents(finalTotal - separatelyQuoted),\n groupTotals,\n },\n errors,\n };\n}\n// ─── calculate ────────────────────────────────────────────────────────────────\n/**\n * Runs the full three-phase pricing calculation.\n *\n * Phase 1 — ADD UP: unit_rate, conditional_addon, lookup_table\n * Phase 2 — SCALE: selection_multiplier, conditional_multiplier\n * Phase 3 — MINIMUM: floor_minimum\n *\n * Rules with a condition are skipped if the condition evaluates to false.\n * Skipped rule IDs are collected in EngineResult.suppressedRuleIds.\n *\n * Never throws. All errors are collected in EngineResult.errors.\n * Partial results with errors are returned — the caller decides how to handle them.\n *\n * finalTotal is always pre-discount. The API layer applies discount codes after\n * this function returns to produce Quote.totalAfterDiscount.\n */\nfunction calculate(config, answers) {\n const allErrors = [];\n const lineItems = [];\n const suppressedRuleIds = [];\n // lookupValues accumulates resolved lookup_table outputs during phase 1\n // so that downstream unit_rate rules can reference them via \"lookup:rXX\"\n const lookupValues = {};\n // config.tokens can be absent on a form whose stored config predates the\n // tokens feature (or was never migrated) — calculate() is documented to\n // never throw, so this can't be assumed present.\n const { variables, errors: variableErrors } = (0, variables_1.resolveTokens)(config.tokens ?? {});\n allErrors.push(...variableErrors);\n // Numeric view of the answers, so a rule expression can reference a customer\n // answer directly via `field:key` rather than only through unit_rate.\n const fieldValues = {};\n for (const [key, answer] of Object.entries(answers)) {\n const numeric = typeof answer === \"boolean\" ? (answer ? 1 : 0) : Number(answer);\n if (typeof answer !== \"object\" && Number.isFinite(numeric))\n fieldValues[key] = numeric;\n }\n // ── Phase 1 — ADD UP ───────────────────────────────────────────────────────\n let phase1Total = 0;\n function ruleConditionsMet(rule) {\n if (rule.condition !== undefined && !(0, resolver_1.evaluateCondition)(rule.condition, answers))\n return false;\n if (rule.scopeCondition !== undefined && !(0, resolver_1.evaluateCondition)(rule.scopeCondition, answers))\n return false;\n return true;\n }\n // Phase 1a: Process all Phase 1 rules EXCEPT conditional_addon with feeType === 'percent'\n for (const rule of config.rules.phase1) {\n // Skip percentage-based fixed fees — process them in phase 1b\n if (rule.type === \"conditional_addon\" && rule.feeType === \"percent\") {\n continue;\n }\n // Evaluate condition — skip rule if condition is present and not met\n if (!ruleConditionsMet(rule)) {\n suppressedRuleIds.push(rule.id);\n continue;\n }\n if (rule.type === \"unit_rate\") {\n const quantityUnit = config.meta.tokenLabels?.[rule.quantityField]?.unit;\n const { lineItem, amount, errors } = processUnitRate(rule, answers, variables, lookupValues, fieldValues, quantityUnit);\n allErrors.push(...errors);\n if (lineItem !== null) {\n lineItems.push(lineItem);\n phase1Total += amount;\n }\n continue;\n }\n if (rule.type === \"conditional_addon\") {\n const { lineItem, amount, errors } = processConditionalAddon(rule, variables, lookupValues, fieldValues);\n allErrors.push(...errors);\n if (lineItem !== null) {\n lineItems.push(lineItem);\n phase1Total += amount;\n }\n continue;\n }\n if (rule.type === \"lookup_table\") {\n const { lineItem, amount, errors } = processLookupTable(rule, answers, variables, lookupValues);\n allErrors.push(...errors);\n if (lineItem !== null) {\n // Register in lookupValues so downstream rules can reference \"lookup:<rule.id>\"\n lookupValues[rule.id] = amount;\n lineItems.push(lineItem);\n phase1Total += amount;\n }\n continue;\n }\n }\n // Phase 1b: Process percentage-based fixed fees using the phase1 subtotal\n const phase1SubTotal = phase1Total;\n for (const rule of config.rules.phase1) {\n // Only process conditional_addon rules with feeType === 'percent'\n if (!(rule.type === \"conditional_addon\" && rule.feeType === \"percent\")) {\n continue;\n }\n if (!ruleConditionsMet(rule)) {\n suppressedRuleIds.push(rule.id);\n continue;\n }\n // Resolve the percentage value from amountExpr\n const { value: percent, errors: resolveErrors } = (0, resolver_1.resolveExpression)(rule.amountExpr, variables, lookupValues, fieldValues);\n const errors = resolveErrors.map((e) => ({ ...e, ruleId: rule.id }));\n allErrors.push(...errors);\n // Calculate amount as percentage of phase1SubTotal\n const amount = roundCents(phase1SubTotal * (percent / 100));\n const { groupAmounts, errors: groupErrors } = computeGroupAmounts(rule.groupAssignments, amount, variables, lookupValues, rule.id);\n errors.push(...groupErrors);\n allErrors.push(...errors);\n const lineItem = {\n ruleId: rule.id,\n label: rule.label,\n amount,\n type: \"conditional_addon\",\n showOnQuote: rule.showOnQuote,\n ...(rule.tag !== undefined && { tag: rule.tag }),\n ...(groupAmounts !== undefined && { groupAmounts }),\n };\n lineItems.push(lineItem);\n phase1Total += amount;\n }\n // ── Phase 2 — SCALE ────────────────────────────────────────────────────────\n let runningTotal = phase1Total;\n for (const rule of config.rules.phase2) {\n if (!ruleConditionsMet(rule)) {\n suppressedRuleIds.push(rule.id);\n continue;\n }\n if (rule.type === \"selection_multiplier\") {\n const { lineItem, newTotal, errors } = processSelectionMultiplier(rule, answers, runningTotal, variables, lookupValues);\n allErrors.push(...errors);\n if (lineItem !== null) {\n lineItems.push(lineItem);\n }\n runningTotal = newTotal;\n continue;\n }\n if (rule.type === \"conditional_multiplier\") {\n const { lineItem, newTotal, errors } = processConditionalMultiplier(rule, variables, lookupValues, fieldValues, runningTotal);\n allErrors.push(...errors);\n if (lineItem !== null) {\n lineItems.push(lineItem);\n }\n runningTotal = newTotal;\n continue;\n }\n }\n const phase2Total = runningTotal;\n // ── Phase 3 — CHECK MINIMUM ────────────────────────────────────────────────\n let finalTotal = phase2Total;\n let minimumApplied = false;\n let minimumAmount = 0;\n for (const rule of config.rules.phase3) {\n if (!ruleConditionsMet(rule)) {\n suppressedRuleIds.push(rule.id);\n continue;\n }\n if (rule.type === \"floor_minimum\") {\n const result = processFloorMinimum(rule, variables, lookupValues, fieldValues, finalTotal);\n allErrors.push(...result.errors);\n if (result.lineItem !== null) {\n lineItems.push(result.lineItem);\n }\n // Last floor_minimum rule wins if multiple are present (rare but valid config)\n finalTotal = result.finalTotal;\n if (result.minimumApplied) {\n minimumApplied = true;\n minimumAmount = result.minimumAmount;\n }\n continue;\n }\n }\n const { totals, errors: totalsErrors } = buildTotals(lineItems, roundCents(finalTotal), config.meta.displayGroups, minimumApplied);\n allErrors.push(...totalsErrors);\n return {\n phase1Total: roundCents(phase1Total),\n phase2Total: roundCents(phase2Total),\n finalTotal: roundCents(finalTotal),\n minimumApplied,\n minimumAmount: roundCents(minimumAmount),\n lineItems,\n suppressedRuleIds,\n totals,\n errors: allErrors,\n };\n}\n","export {createOnablClient} from \"./client\";\nexport type {OnablClient, OnablClientConfig, CallOpts, TokenOpts} from \"./client\";\n\nexport {OnablError, OnablNotFound, OnablUnauthorized, OnablValidation, OnablNetwork} from \"./errors\";\n\nexport {presentQuote, groupLineItems} from \"./presentation\";\nexport type {PresentQuoteInput, QuotePresentation, QuoteRow, SeparateSection, GroupedItems} from \"./presentation\";\n\nexport {getVisibleSteps, getAllFields, getInitialAnswers, validateFields} from \"./form-state\";\nexport type {VisibleStep} from \"./form-state\";\n\nexport type {PublicForm, PublicFormConfig, PublicFormField, Quote, Invoice, InvoiceStatus, ValidateCodeResponse} from \"@onabl/contracts/public-api\";\n","import {\n PublicFormSchema,\n ValidateCodeResponseSchema,\n SubmissionCreateResponseSchema,\n QuoteSchema,\n QuoteAcceptResponseSchema,\n QuoteDeclineResponseSchema,\n InvoiceSchema,\n PopUrlUpdateResponseSchema,\n PresignResponseSchema,\n type PublicForm,\n type ValidateCodeResponse,\n type Quote,\n type Invoice,\n type PresignResponse,\n} from \"@onabl/contracts/public-api\";\nimport type {AnswerMap} from \"@onabl/types/config\";\n\nimport {OnablError, OnablNetwork, OnablNotFound, OnablUnauthorized, OnablValidation} from \"./errors\";\n\n/**\n * Pinned to the API version this @onabl/js release was built against — see\n * docs/API-BASELINE-2026-09-01.md and PHASE-14 §14.2. Bump alongside a real\n * SDK release once a new dated API version needs adopting; the developer\n * never sets this themselves (SDK-DESIGN.md §4, \"The API version is sent\n * automatically\").\n */\nconst BUILT_AGAINST_API_VERSION = \"2026-09-01\";\n\n/**\n * Production default. Onabl has no dedicated api.onabl.com subdomain — the\n * API is path-routed under the main domain by the Caddy reverse proxy\n * (onabl.com/api/* -> the api container), same pattern as staging\n * (staging.onabl.com/api/*). There is no single default that covers staging\n * too, since it's a genuinely different host — callers targeting staging\n * (or any non-production environment) must always pass baseUrl explicitly.\n */\nconst DEFAULT_BASE_URL = \"https://onabl.com/api/v1\";\n\n/** Default quote-view path template on the integrator's own site, substituting `:uuid`. Overridable via config.quotePath. */\nconst DEFAULT_QUOTE_PATH = \"/quote/:uuid\";\n\nexport interface OnablClientConfig {\n handle: string;\n secretKey: string;\n baseUrl?: string;\n apiVersion?: string;\n /** Path template for the quote view page on the integrator's own site — see submissions.create()'s returned quoteUrl. */\n quotePath?: string;\n}\n\nexport interface CallOpts {\n /** Slug of a specific form, for tenants running more than one. Omitted, resolves to the tenant's dashboard-configured default. */\n slug?: string;\n}\n\n/**\n * Customer-token-scoped calls need a bearer token — @onabl/next supplies one\n * automatically from its managed cookie (SDK-DESIGN.md §3, \"Access cookie\").\n * Used directly (e.g. a Vite/plain-React app per SDK-DESIGN.md §4, \"Route\n * handler only\" decision), the caller supplies it explicitly.\n */\nexport interface TokenOpts {\n token: string;\n}\n\nexport interface OnablClient {\n forms: {\n get(opts?: CallOpts): Promise<PublicForm>;\n validateDiscountCode(code: string, opts?: CallOpts): Promise<ValidateCodeResponse>;\n };\n quotes: {\n get(uuid: string, opts: TokenOpts): Promise<Quote>;\n accept(uuid: string, opts: TokenOpts): Promise<void>;\n decline(uuid: string, reason: string, note: string | undefined, opts: TokenOpts): Promise<void>;\n };\n invoices: {\n get(uuid: string, opts: TokenOpts): Promise<Invoice>;\n /** milestone \"deposit\" saves the deposit POP; \"balance\"/\"full\" save the balance/full-payment POP. */\n savePopUrl(uuid: string, key: string, milestone: \"deposit\" | \"balance\" | \"full\", opts: TokenOpts): Promise<void>;\n };\n storage: {\n /** Presigns an upload for a customer-facing flow (currently only invoice POP uploads — pathPrefix is always \"pop\"). */\n presignPop(resourceId: string, filename: string, contentType: string, fileSize: number, opts: TokenOpts): Promise<PresignResponse>;\n };\n submissions: {\n /** isTenantSource marks a submission taken by the tenant on the customer's behalf (the on-site quote tool) rather than the customer directly — see docs/ROADMAP.md Phase 2.11. */\n create(\n answers: AnswerMap,\n opts?: CallOpts & {consentGiven?: boolean; discountCode?: string; isTenantSource?: boolean},\n ): Promise<{quoteId: string; quoteUrl: string; token: string}>;\n };\n}\n\nexport function createOnablClient(config: OnablClientConfig): OnablClient {\n const baseUrl = config.baseUrl ?? DEFAULT_BASE_URL;\n const apiVersion = config.apiVersion ?? BUILT_AGAINST_API_VERSION;\n const quotePath = config.quotePath ?? DEFAULT_QUOTE_PATH;\n\n async function request<T>(path: string, init: RequestInit & {auth: \"secret\" | TokenOpts}): Promise<T> {\n const headers = new Headers(init.headers);\n headers.set(\"Onabl-Version\", apiVersion);\n if (init.auth === \"secret\") {\n headers.set(\"x-api-key\", config.secretKey);\n } else {\n headers.set(\"Authorization\", `Bearer ${init.auth.token}`);\n }\n if (init.body) headers.set(\"Content-Type\", \"application/json\");\n\n let response: Response;\n try {\n response = await fetch(`${baseUrl}${path}`, {...init, headers});\n } catch (cause) {\n throw new OnablNetwork(\"Request to onabl failed\", cause);\n }\n\n if (response.ok) {\n if (response.status === 204) return undefined as T;\n try {\n return (await response.json()) as T;\n } catch (cause) {\n throw new OnablNetwork(\"Received an unparseable response from onabl\", cause);\n }\n }\n\n const body = await response.json().catch(() => undefined);\n if (response.status === 404) throw new OnablNotFound(body?.message ?? \"Not found\");\n if (response.status === 401) throw new OnablUnauthorized(body?.message ?? \"Unauthorized\");\n if (response.status === 400) throw new OnablValidation(body?.message ?? \"Validation failed\", body?.fieldErrors);\n throw new OnablError(body?.message ?? `Request failed with status ${response.status}`, response.status);\n }\n\n function formPath(opts?: CallOpts): string {\n return opts?.slug ? `/forms/q/${config.handle}/${opts.slug}` : `/forms/q/${config.handle}`;\n }\n\n function submissionPath(opts?: CallOpts): string {\n return opts?.slug ? `/submissions/q/${config.handle}/${opts.slug}` : `/submissions/q/${config.handle}`;\n }\n\n return {\n forms: {\n async get(opts) {\n const raw = await request(formPath(opts), {method: \"GET\", auth: \"secret\"});\n return PublicFormSchema.parse(raw);\n },\n async validateDiscountCode(code, opts) {\n const raw = await request(`${formPath(opts)}/validate-code?code=${encodeURIComponent(code)}`, {method: \"GET\", auth: \"secret\"});\n return ValidateCodeResponseSchema.parse(raw);\n },\n },\n quotes: {\n async get(uuid, opts) {\n const raw = await request(`/quotes/${uuid}`, {method: \"GET\", auth: opts});\n return QuoteSchema.parse(raw);\n },\n async accept(uuid, opts) {\n const raw = await request(`/quotes/${uuid}/accept`, {method: \"POST\", auth: opts});\n QuoteAcceptResponseSchema.parse(raw);\n },\n async decline(uuid, reason, note, opts) {\n const raw = await request(`/quotes/${uuid}/decline`, {method: \"POST\", auth: opts, body: JSON.stringify({declineReason: reason, declineNote: note})});\n QuoteDeclineResponseSchema.parse(raw);\n },\n },\n invoices: {\n async get(uuid, opts) {\n const raw = await request(`/invoices/${uuid}`, {method: \"GET\", auth: opts});\n return InvoiceSchema.parse(raw);\n },\n async savePopUrl(uuid, key, milestone, opts) {\n const path = milestone === \"deposit\" ? `/invoices/${uuid}/deposit-pop-url` : `/invoices/${uuid}/pop-url`;\n const raw = await request(path, {method: \"PATCH\", auth: opts, body: JSON.stringify({key})});\n PopUrlUpdateResponseSchema.parse(raw);\n },\n },\n storage: {\n async presignPop(resourceId, filename, contentType, fileSize, opts) {\n const raw = await request(\"/storage/presign/public\", {\n method: \"POST\",\n auth: opts,\n body: JSON.stringify({resourceId, filename, contentType, fileSize, pathPrefix: \"pop\"}),\n });\n return PresignResponseSchema.parse(raw);\n },\n },\n submissions: {\n async create(answers, opts) {\n const path = opts?.isTenantSource ? `${submissionPath(opts)}?source=tenant` : submissionPath(opts);\n const raw = await request<{uuid: string; reference: string; token: string}>(path, {\n method: \"POST\",\n auth: \"secret\",\n body: JSON.stringify({answers, consentGiven: opts?.consentGiven, discountCode: opts?.discountCode}),\n });\n const parsed = SubmissionCreateResponseSchema.parse(raw);\n return {quoteId: parsed.uuid, quoteUrl: quotePath.replace(\":uuid\", parsed.uuid), token: parsed.token};\n },\n },\n };\n}\n","/**\n * Typed error classes so a catch block can discriminate without matching on\n * HTTP status numbers or string messages. See docs/SDK-DESIGN.md §3.\n */\n\nexport class OnablError extends Error {\n constructor(\n message: string,\n public readonly status?: number,\n ) {\n super(message);\n this.name = \"OnablError\";\n }\n}\n\n/** 404, or a customer token that doesn't grant access to this resource. */\nexport class OnablNotFound extends OnablError {\n constructor(message = \"Not found\") {\n super(message, 404);\n this.name = \"OnablNotFound\";\n }\n}\n\n/** Missing or invalid secret key / customer token. */\nexport class OnablUnauthorized extends OnablError {\n constructor(message = \"Unauthorized\") {\n super(message, 401);\n this.name = \"OnablUnauthorized\";\n }\n}\n\n/** 400 — carries field-level detail from the API's Zod validation errors. */\nexport class OnablValidation extends OnablError {\n constructor(\n message: string,\n public readonly fieldErrors?: Record<string, string[]>,\n ) {\n super(message, 400);\n this.name = \"OnablValidation\";\n }\n}\n\n/** Transport failure — network error, timeout, or an unparseable response. */\nexport class OnablNetwork extends OnablError {\n constructor(message = \"Network error\", cause?: unknown) {\n super(message);\n this.name = \"OnablNetwork\";\n if (cause !== undefined) this.cause = cause;\n }\n}\n","/**\n * Re-exported from @onabl/engine (§14.5.2b) rather than left for every\n * integrator to reimplement — see tsup.config.ts for why this code is\n * bundled into @onabl/js's own output instead of left as an external\n * \"@onabl/engine\" import: @onabl/engine is never published on its own.\n *\n * This is what finally lets visualcreme delete quote-presentation.ts, a\n * 180-line verbatim hand-copy of this same file that carried a comment\n * instructing the reader to keep it manually in sync with the engine.\n *\n * The five interfaces below are declared locally rather than imported from\n * \"@onabl/engine/presentation\" — tsup's DTS bundler (rollup-plugin-dts)\n * preserves an external type import/re-export verbatim regardless of\n * `dts.resolve`, so the published .d.ts ended up pointing at\n * \"@onabl/engine/presentation\" itself, a module every external consumer's\n * tsc then fails to find (E2307) since @onabl/engine is never published.\n * Found and fixed 2026-08-24 when visualcreme adopted this package\n * (§14.5.6) — the 0.1.0 release shipped with this bug.\n *\n * Unlike the logic visualcreme used to hand-copy, this is just the display\n * *shape* — small and stable — and the `as` casts on presentQuote/\n * groupLineItems below mean any future drift between this shape and the\n * engine's real return type fails to compile right here, in this package,\n * rather than silently diverging at a caller three repos away.\n */\nimport {presentQuote as enginePresentQuote, groupLineItems as engineGroupLineItems} from \"@onabl/engine/presentation\";\nimport type {DisplayGroup} from \"@onabl/types/config\";\nimport type {LineItem} from \"@onabl/types/engine\";\n\nexport interface QuoteRow {\n key: string;\n label: string;\n amount: number;\n isGroup: boolean;\n displayMode?: DisplayGroup[\"displayMode\"];\n children?: QuoteRow[];\n sourceItem?: LineItem;\n groupTag?: string;\n}\n\nexport interface SeparateSection {\n group: DisplayGroup;\n rows: QuoteRow[];\n amount: number;\n}\n\nexport interface GroupedItems {\n main: QuoteRow[];\n separateSections: SeparateSection[];\n groupTotals: Record<string, number>;\n}\n\nexport interface PresentQuoteInput {\n lineItems: LineItem[];\n displayGroups?: DisplayGroup[];\n finalTotal: number;\n totalAfterDiscount: number;\n discountLabel?: string | null;\n}\n\nexport interface QuotePresentation {\n rows: QuoteRow[];\n separateSections: SeparateSection[];\n subtotal: number;\n discount: {label: string; amount: number} | null;\n total: number;\n}\n\nexport function groupLineItems(lineItems: LineItem[], displayGroups?: DisplayGroup[]): GroupedItems {\n return engineGroupLineItems(lineItems, displayGroups) as GroupedItems;\n}\n\nexport function presentQuote(input: PresentQuoteInput): QuotePresentation {\n return enginePresentQuote(input) as QuotePresentation;\n}\n","/**\n * The form state machine, extracted from apps/web/components/form/MultiStepForm.tsx\n * (§14.5.2, part 2). Pure functions only — no React, no framework of any kind —\n * so any UI layer (a React hook in @onabl/react, or something else entirely)\n * can drive the same tested logic. Renders nothing; every function here takes\n * a snapshot of state and returns a value, never mutates.\n *\n * Deliberately excludes three things apps/web's current implementation\n * handles that the documented useOnablForm surface (docs/SDK-DESIGN.md §3)\n * does not — decided 2026-08-24, see docs/INTEGRATION-LAYER-TODO.md:\n *\n * - Intro screen: not modeled as a step here at all. It's pure presentation\n * (config.meta.intro) with no fields to collect or validate — the\n * integrator reads it directly and renders it before ever touching this\n * module's step navigation.\n * - Auto-advance (single radio/toggle field steps skipping the Continue\n * click): not built in here. It's a UI/interaction choice, not form logic —\n * the render layer calls next() itself after setAnswer() when it wants\n * that behavior, using visibleFields to detect the single-field case.\n * - Discount code: folded in as ordinary state here (getDiscountCode-style\n * handling lives in @onabl/react's hook, not this module) rather than\n * modeled as a synthetic step the way apps/web's current buildSteps() does.\n * Where to render the discount input within the step flow (inline on the\n * last step, or as a separate screen before submit) is left to the\n * integrator — this module has no opinion on it.\n */\n\nimport type {PublicForm, PublicFormField} from \"@onabl/contracts/public-api\";\nimport {applyDefaults} from \"@onabl/engine/engine\";\nimport {evaluateCondition} from \"@onabl/engine/resolver\";\nimport type {AnswerMap, FormStep} from \"@onabl/types/config\";\n\n/** A step that currently has at least one visible field — steps a conditional field emptied out entirely are skipped. */\nexport interface VisibleStep extends FormStep {\n fields: PublicFormField[];\n}\n\nconst UNGROUPED_STEP_ID = \"__ungrouped\";\n\n/**\n * Every step the visitor can currently navigate to, in order, filtered to\n * only those with ≥1 visible field. Ungrouped fields (stepId: null) are\n * collected into a synthetic trailing step, matching apps/web's current\n * behavior — labeled \"Details\" there today; integrators using this directly\n * can relabel as they see fit since this is just a FormStep-shaped value.\n */\nexport function getVisibleSteps(form: PublicForm, answers: AnswerMap): VisibleStep[] {\n const config = form.config;\n const steps: VisibleStep[] = [];\n\n for (const step of config.steps) {\n const fields = fieldsForStep(config.fields, step.id, answers);\n if (fields.length > 0) steps.push({...step, fields});\n }\n\n const ungroupedFields = fieldsForStep(config.fields, null, answers);\n if (ungroupedFields.length > 0) {\n steps.push({id: UNGROUPED_STEP_ID, label: \"Details\", fields: ungroupedFields});\n }\n\n return steps;\n}\n\n/** Fields visible for one step id (or `null` for ungrouped fields), given the current answers. */\nfunction fieldsForStep(fields: PublicFormField[], stepId: string | null, answers: AnswerMap): PublicFormField[] {\n return fields.filter((f) => f.stepId === stepId && f.type !== \"hidden\" && conditionMet(f.condition, answers) && conditionMet(f.scopeCondition, answers));\n}\n\nfunction conditionMet(condition: PublicFormField[\"condition\"], answers: AnswerMap): boolean {\n if (!condition) return true;\n return evaluateCondition(condition, answers);\n}\n\n/** Every field on the form, regardless of visibility — for debugging a field that won't appear. */\nexport function getAllFields(form: PublicForm): PublicFormField[] {\n return form.config.fields;\n}\n\n/**\n * Seeds the initial AnswerMap from field defaults, using @onabl/engine's\n * canonical applyDefaults — including its type-based fallback (unset number\n * fields → 0, unset toggle → false). This is a deliberate choice for this\n * new implementation, not a port of apps/web's current (leaner) local\n * version — see docs/INTEGRATION-LAYER-TODO.md's Stage 3 pre-work note for\n * why apps/web wasn't swapped onto this same behavior directly. Verify this\n * during apps/web's own SDK migration (§14.5.5), since it is a real,\n * intentional behavior difference from what's live today.\n */\nexport function getInitialAnswers(form: PublicForm): AnswerMap {\n return applyDefaults(form.config, {});\n}\n\n/**\n * Validates one step's fields against the current answers. Same rules as\n * apps/web's current validateStep(), generalized to a plain field list\n * rather than coupled to a Step union type.\n */\nexport function validateFields(fields: PublicFormField[], answers: AnswerMap): Record<string, string> {\n const errors: Record<string, string> = {};\n\n for (const field of fields) {\n if (!field.required) continue;\n const value = answers[field.key];\n\n if (field.type === \"multicheck\") {\n if (!Array.isArray(value) || value.length === 0) {\n errors[field.key] = \"Please select at least one option.\";\n }\n continue;\n }\n\n if (field.type === \"toggle\") {\n if (value === undefined || value === null || value === \"\") {\n errors[field.key] = \"Please make a selection.\";\n }\n continue;\n }\n\n if (field.type === \"number\") {\n if (value === undefined || value === null || value === \"\") {\n errors[field.key] = \"Please enter a value.\";\n continue;\n }\n const num = Number(value);\n if (isNaN(num)) {\n errors[field.key] = \"Please enter a valid number.\";\n continue;\n }\n if (field.min !== undefined && num < field.min) {\n errors[field.key] = `Minimum value is ${field.min}.`;\n continue;\n }\n if (field.max !== undefined && num > field.max) {\n errors[field.key] = `Maximum value is ${field.max}.`;\n continue;\n }\n continue;\n }\n\n if (field.type === \"date\") {\n if (!value || value === \"\") {\n errors[field.key] = \"Please enter a date.\";\n continue;\n }\n if (isNaN(new Date(value as string).getTime())) {\n errors[field.key] = \"Please enter a valid date.\";\n }\n continue;\n }\n\n if (!value || value === \"\") {\n const isChoice = field.type === \"radio\" || field.type === \"select\";\n errors[field.key] = isChoice ? \"Please make a selection.\" : \"This field is required.\";\n }\n }\n\n return errors;\n}\n"],"mappings":"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","names":["exports","groupLineItems","presentQuote","main","exports","exports","value","exports","evaluateCondition","exports","exports","exports","applyDefaults","engineGroupLineItems","enginePresentQuote"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onabl/js",
3
- "version": "0.3.0",
3
+ "version": "0.3.2",
4
4
  "description": "Framework-agnostic onabl SDK core — typed API client, error classes, condition evaluator, form state machine, and quote presentation. No React, no DOM assumptions. See docs/SDK-DESIGN.md.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -29,13 +29,13 @@
29
29
  "tsup": "^8.0.0",
30
30
  "vitest": "^1.6.0",
31
31
  "typescript": "^5.4.0",
32
- "@onabl/eslint-config": "0.0.1",
33
32
  "@onabl/engine": "0.0.1",
34
- "@onabl/typescript-config": "0.0.1"
33
+ "@onabl/typescript-config": "0.0.1",
34
+ "@onabl/eslint-config": "0.0.1"
35
35
  },
36
36
  "dependencies": {
37
- "@onabl/contracts": "0.3.0",
38
- "@onabl/types": "0.4.0"
37
+ "@onabl/contracts": "0.3.2",
38
+ "@onabl/types": "0.5.0"
39
39
  },
40
40
  "scripts": {
41
41
  "build": "tsup",