@ixo/editor 5.20.2 → 5.25.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1255,6 +1255,505 @@ registerAction({
1255
1255
  }
1256
1256
  });
1257
1257
 
1258
+ // src/core/lib/xeroWorkItems.ts
1259
+ function getXeroWorkItemsMap(editor) {
1260
+ return editor?._yXeroWorkItems || null;
1261
+ }
1262
+ function readMapItems(map) {
1263
+ if (!map) return [];
1264
+ const items = [];
1265
+ map.forEach((value) => {
1266
+ if (value && typeof value === "object" && "id" in value) {
1267
+ items.push({ ...value });
1268
+ }
1269
+ });
1270
+ return items;
1271
+ }
1272
+ function mergeItem(existing, next) {
1273
+ if (existing.status === "completed") {
1274
+ return existing;
1275
+ }
1276
+ return {
1277
+ ...existing,
1278
+ ...next,
1279
+ id: existing.id,
1280
+ attempts: existing.attempts ?? [],
1281
+ originalPayload: existing.originalPayload,
1282
+ submittedPayload: existing.submittedPayload,
1283
+ result: existing.result,
1284
+ completedAt: existing.completedAt,
1285
+ completedByDid: existing.completedByDid
1286
+ };
1287
+ }
1288
+ function buildXeroInvoiceWorkKey(params) {
1289
+ return ["xero", "invoice.create", params.flowId, params.evaluationBlockId, params.claimId, params.invoiceBlockId].join(":");
1290
+ }
1291
+ function buildXeroPaymentWorkKey(params) {
1292
+ return ["xero", "payment.create", params.flowId, params.evaluationBlockId, params.claimId, params.paymentBlockId, params.invoiceWorkItemId].join(":");
1293
+ }
1294
+ function findXeroWorkItemsForEditor(editor, filter) {
1295
+ return readMapItems(getXeroWorkItemsMap(editor)).filter((item) => {
1296
+ if (filter.kind && item.kind !== filter.kind) return false;
1297
+ if (filter.assignedBlockId && item.assignedBlockId !== filter.assignedBlockId) return false;
1298
+ if (filter.statuses && !filter.statuses.includes(item.status)) return false;
1299
+ return true;
1300
+ });
1301
+ }
1302
+ function upsertXeroWorkItemForEditor(editor, next) {
1303
+ const map = getXeroWorkItemsMap(editor);
1304
+ if (!map) {
1305
+ return next;
1306
+ }
1307
+ let existing;
1308
+ map.forEach((item) => {
1309
+ if (item?.idempotencyKey === next.idempotencyKey) existing = item;
1310
+ });
1311
+ const stored = existing ? mergeItem(existing, next) : next;
1312
+ map.set(stored.id, stored);
1313
+ return stored;
1314
+ }
1315
+ function updateXeroWorkReviewPayloadForEditor(editor, itemId, reviewPayload) {
1316
+ const map = getXeroWorkItemsMap(editor);
1317
+ if (!map) return null;
1318
+ const item = map.get(itemId);
1319
+ if (!item) return null;
1320
+ const updatedItem = { ...item, reviewPayload };
1321
+ map.set(itemId, updatedItem);
1322
+ return updatedItem;
1323
+ }
1324
+ function markXeroWorkFailedForEditor(editor, itemId, params) {
1325
+ const map = getXeroWorkItemsMap(editor);
1326
+ if (!map) return null;
1327
+ const item = map.get(itemId);
1328
+ if (!item) return null;
1329
+ const at = params.at ?? Date.now();
1330
+ const updatedItem = {
1331
+ ...item,
1332
+ status: "failed",
1333
+ reviewPayload: params.payload,
1334
+ error: { message: params.error, at },
1335
+ attempts: [...item.attempts ?? [], { at, byDid: params.byDid, payload: params.payload, error: params.error }]
1336
+ };
1337
+ map.set(itemId, updatedItem);
1338
+ return updatedItem;
1339
+ }
1340
+ function markXeroWorkCompletedForEditor(editor, itemId, params) {
1341
+ const map = getXeroWorkItemsMap(editor);
1342
+ if (!map) return null;
1343
+ const item = map.get(itemId);
1344
+ if (!item) return null;
1345
+ const at = params.at ?? Date.now();
1346
+ const updatedItem = {
1347
+ ...item,
1348
+ status: "completed",
1349
+ reviewPayload: params.payload,
1350
+ submittedPayload: params.payload,
1351
+ result: params.result,
1352
+ error: void 0,
1353
+ completedAt: at,
1354
+ completedByDid: params.byDid,
1355
+ attempts: [...item.attempts ?? [], { at, byDid: params.byDid, payload: params.payload, result: params.result }]
1356
+ };
1357
+ map.set(itemId, updatedItem);
1358
+ return updatedItem;
1359
+ }
1360
+
1361
+ // src/core/lib/actionRegistry/actions/xero/invoiceCreate.types.ts
1362
+ var LINE_ITEM_FIELD_KEYS = ["Description", "Quantity", "UnitAmount", "AccountCode", "TaxType", "ItemCode", "DiscountRate"];
1363
+ function emptyLineItemCells() {
1364
+ return {
1365
+ Description: "",
1366
+ Quantity: "1",
1367
+ UnitAmount: "",
1368
+ AccountCode: "",
1369
+ TaxType: "",
1370
+ ItemCode: "",
1371
+ DiscountRate: ""
1372
+ };
1373
+ }
1374
+ function emptyLineItems() {
1375
+ return { mode: "manual", rows: [emptyLineItemCells()] };
1376
+ }
1377
+ function coerceCells(raw) {
1378
+ const base = emptyLineItemCells();
1379
+ if (!raw || typeof raw !== "object") return base;
1380
+ for (const key of LINE_ITEM_FIELD_KEYS) {
1381
+ const v = raw[key];
1382
+ if (typeof v === "string") base[key] = v;
1383
+ else if (typeof v === "number") base[key] = String(v);
1384
+ else if (typeof v === "boolean") base[key] = v ? "true" : "false";
1385
+ }
1386
+ return base;
1387
+ }
1388
+ function normaliseLineItems(raw) {
1389
+ if (raw && typeof raw === "object") {
1390
+ const candidate = raw;
1391
+ if (candidate.mode === "iterative") {
1392
+ return {
1393
+ mode: "iterative",
1394
+ source: typeof candidate.source === "string" ? candidate.source : "",
1395
+ map: coerceCells(candidate.map)
1396
+ };
1397
+ }
1398
+ if (candidate.mode === "manual") {
1399
+ const rows = Array.isArray(candidate.rows) ? candidate.rows.map(coerceCells) : [];
1400
+ return { mode: "manual", rows: rows.length > 0 ? rows : [emptyLineItemCells()] };
1401
+ }
1402
+ }
1403
+ if (typeof raw === "string") {
1404
+ const trimmed = raw.trim();
1405
+ if (!trimmed) return emptyLineItems();
1406
+ try {
1407
+ const parsed = JSON.parse(trimmed);
1408
+ if (Array.isArray(parsed) && parsed.length > 0) {
1409
+ return { mode: "manual", rows: parsed.map(coerceCells) };
1410
+ }
1411
+ } catch {
1412
+ }
1413
+ }
1414
+ return emptyLineItems();
1415
+ }
1416
+ function parseXeroInvoiceCreateInputs(raw) {
1417
+ try {
1418
+ const parsed = typeof raw === "string" ? JSON.parse(raw || "{}") : raw || {};
1419
+ const conn = parsed.connection;
1420
+ const connection = conn && typeof conn === "object" && typeof conn.connectedAccountId === "string" && typeof conn.entityDid === "string" ? { connectedAccountId: conn.connectedAccountId, entityDid: conn.entityDid } : null;
1421
+ return {
1422
+ connection,
1423
+ tenant_id: typeof parsed.tenant_id === "string" ? parsed.tenant_id : "",
1424
+ Type: typeof parsed.Type === "string" && parsed.Type ? parsed.Type : "ACCREC",
1425
+ Status: typeof parsed.Status === "string" ? parsed.Status : "DRAFT",
1426
+ Date: typeof parsed.Date === "string" ? parsed.Date : "",
1427
+ DueDate: typeof parsed.DueDate === "string" ? parsed.DueDate : "",
1428
+ ContactID: typeof parsed.ContactID === "string" ? parsed.ContactID : "",
1429
+ ContactName: typeof parsed.ContactName === "string" ? parsed.ContactName : "",
1430
+ Reference: typeof parsed.Reference === "string" ? parsed.Reference : "",
1431
+ InvoiceNumber: typeof parsed.InvoiceNumber === "string" ? parsed.InvoiceNumber : "",
1432
+ CurrencyCode: typeof parsed.CurrencyCode === "string" ? parsed.CurrencyCode : "",
1433
+ LineItems: normaliseLineItems(parsed.LineItems)
1434
+ };
1435
+ } catch {
1436
+ return {
1437
+ connection: null,
1438
+ tenant_id: "",
1439
+ Type: "ACCREC",
1440
+ Status: "DRAFT",
1441
+ Date: "",
1442
+ DueDate: "",
1443
+ ContactID: "",
1444
+ ContactName: "",
1445
+ Reference: "",
1446
+ InvoiceNumber: "",
1447
+ CurrencyCode: "",
1448
+ LineItems: emptyLineItems()
1449
+ };
1450
+ }
1451
+ }
1452
+ function serializeXeroInvoiceCreateInputs(inputs) {
1453
+ return JSON.stringify(inputs);
1454
+ }
1455
+ var NUMERIC_LINE_ITEM_FIELDS = ["Quantity", "UnitAmount", "DiscountRate"];
1456
+ function finaliseLineItem(cells) {
1457
+ const out = {};
1458
+ for (const key of LINE_ITEM_FIELD_KEYS) {
1459
+ const raw = (cells[key] ?? "").trim();
1460
+ if (!raw) continue;
1461
+ if (NUMERIC_LINE_ITEM_FIELDS.includes(key)) {
1462
+ const n = Number(raw);
1463
+ if (!Number.isFinite(n)) {
1464
+ throw new Error(`Line item field ${key} must be a number; got "${raw}"`);
1465
+ }
1466
+ out[key] = n;
1467
+ } else {
1468
+ out[key] = raw;
1469
+ }
1470
+ }
1471
+ if (!out.Description) {
1472
+ out.Description = "payment";
1473
+ }
1474
+ return out;
1475
+ }
1476
+
1477
+ // src/core/lib/actionRegistry/actions/xero/paymentCreate.types.ts
1478
+ function parseXeroPaymentCreateInputs(raw) {
1479
+ try {
1480
+ const parsed = typeof raw === "string" ? JSON.parse(raw || "{}") : raw || {};
1481
+ const conn = parsed.connection;
1482
+ const connection = conn && typeof conn === "object" && typeof conn.connectedAccountId === "string" && typeof conn.entityDid === "string" ? { connectedAccountId: conn.connectedAccountId, entityDid: conn.entityDid } : null;
1483
+ return {
1484
+ connection,
1485
+ tenant_id: typeof parsed.tenant_id === "string" ? parsed.tenant_id : "",
1486
+ InvoiceID: typeof parsed.InvoiceID === "string" ? parsed.InvoiceID : "",
1487
+ AccountID: typeof parsed.AccountID === "string" ? parsed.AccountID : "",
1488
+ Date: typeof parsed.Date === "string" ? parsed.Date : "",
1489
+ Amount: typeof parsed.Amount === "string" ? parsed.Amount : typeof parsed.Amount === "number" ? String(parsed.Amount) : "",
1490
+ Reference: typeof parsed.Reference === "string" ? parsed.Reference : "",
1491
+ CurrencyRate: typeof parsed.CurrencyRate === "string" ? parsed.CurrencyRate : ""
1492
+ };
1493
+ } catch {
1494
+ return {
1495
+ connection: null,
1496
+ tenant_id: "",
1497
+ InvoiceID: "",
1498
+ AccountID: "",
1499
+ Date: "",
1500
+ Amount: "",
1501
+ Reference: "",
1502
+ CurrencyRate: ""
1503
+ };
1504
+ }
1505
+ }
1506
+ function serializeXeroPaymentCreateInputs(inputs) {
1507
+ return JSON.stringify(inputs);
1508
+ }
1509
+
1510
+ // src/mantine/utils/referenceResolver.ts
1511
+ var REFERENCE_REGEX = /\{\{([a-zA-Z0-9_-]+)\.([a-zA-Z0-9_.:]+)\}\}/g;
1512
+ function parseReferences(input) {
1513
+ const references = [];
1514
+ const regex = new RegExp(REFERENCE_REGEX);
1515
+ let match;
1516
+ while ((match = regex.exec(input)) !== null) {
1517
+ references.push({
1518
+ fullMatch: match[0],
1519
+ blockId: match[1],
1520
+ propPath: match[2],
1521
+ startIndex: match.index,
1522
+ endIndex: match.index + match[0].length
1523
+ });
1524
+ }
1525
+ return references;
1526
+ }
1527
+ function getNestedValue(obj, path) {
1528
+ return path.split(".").reduce((current, key) => {
1529
+ return current?.[key];
1530
+ }, obj);
1531
+ }
1532
+ function resolveSingleReference(blockId, propPath, editorDocument, yRuntime, scope) {
1533
+ if (scope && Object.prototype.hasOwnProperty.call(scope, blockId)) {
1534
+ const root = scope[blockId];
1535
+ if (root == null) return void 0;
1536
+ return getNestedValue(root, propPath);
1537
+ }
1538
+ if (!editorDocument || !Array.isArray(editorDocument)) {
1539
+ return void 0;
1540
+ }
1541
+ const block = editorDocument.find((b) => b.id === blockId);
1542
+ if (!block) {
1543
+ return void 0;
1544
+ }
1545
+ if (propPath.startsWith("output.")) {
1546
+ if (!yRuntime) return void 0;
1547
+ const runtimeState = yRuntime.get(blockId);
1548
+ if (!runtimeState?.output) return void 0;
1549
+ const innerPath = propPath.substring("output.".length);
1550
+ const direct = getNestedValue(runtimeState.output, innerPath);
1551
+ if (direct !== void 0) return direct;
1552
+ if (runtimeState.output.data !== void 0) {
1553
+ return getNestedValue(runtimeState.output.data, innerPath);
1554
+ }
1555
+ if (runtimeState.output.http?.data !== void 0) {
1556
+ return getNestedValue(runtimeState.output.http.data, innerPath);
1557
+ }
1558
+ return void 0;
1559
+ }
1560
+ if (propPath.startsWith("response.")) {
1561
+ const responseData = block.props.response;
1562
+ if (!responseData) {
1563
+ return void 0;
1564
+ }
1565
+ try {
1566
+ const parsedResponse = typeof responseData === "string" ? JSON.parse(responseData) : responseData;
1567
+ const innerPath = propPath.substring("response.".length);
1568
+ const value2 = getNestedValue(parsedResponse, innerPath);
1569
+ return value2;
1570
+ } catch (error) {
1571
+ return void 0;
1572
+ }
1573
+ }
1574
+ const value = getNestedValue(block.props, propPath);
1575
+ return value;
1576
+ }
1577
+ function resolveReferences(input, editorDocument, options = {}) {
1578
+ const { fallback = "", stringifyObjects = true, yRuntime, scope } = options;
1579
+ if (input == null) {
1580
+ return "";
1581
+ }
1582
+ const inputStr = String(input);
1583
+ const references = parseReferences(inputStr);
1584
+ if (references.length === 0) {
1585
+ return inputStr;
1586
+ }
1587
+ let result = inputStr;
1588
+ for (let i = references.length - 1; i >= 0; i--) {
1589
+ const ref = references[i];
1590
+ const resolvedValue = resolveSingleReference(ref.blockId, ref.propPath, editorDocument, yRuntime, scope);
1591
+ let replacementStr;
1592
+ if (resolvedValue === void 0 || resolvedValue === null) {
1593
+ replacementStr = fallback;
1594
+ } else if (typeof resolvedValue === "object") {
1595
+ replacementStr = stringifyObjects ? JSON.stringify(resolvedValue) : fallback;
1596
+ } else {
1597
+ replacementStr = String(resolvedValue);
1598
+ }
1599
+ result = result.substring(0, ref.startIndex) + replacementStr + result.substring(ref.endIndex);
1600
+ }
1601
+ return result;
1602
+ }
1603
+ function hasReferences(input) {
1604
+ if (input == null) return false;
1605
+ return parseReferences(String(input)).length > 0;
1606
+ }
1607
+ function createReference(blockId, propPath) {
1608
+ return `{{${blockId}.${propPath}}}`;
1609
+ }
1610
+
1611
+ // src/core/lib/xeroWorkItemPayloads.ts
1612
+ function resolveXeroBindings(editorDocument, invoiceBlockId, paymentBlockId) {
1613
+ if (!Array.isArray(editorDocument)) return { invoiceCreateBlock: null, paymentCreateBlock: null, evaluateBlockId: null };
1614
+ const findById = (id, expectedActionType) => {
1615
+ const trimmed = String(id || "").trim();
1616
+ if (!trimmed) return null;
1617
+ const block = editorDocument.find((b) => b?.id === trimmed);
1618
+ if (!block || block.type !== "action" || block.props?.actionType !== expectedActionType) return null;
1619
+ return block;
1620
+ };
1621
+ return {
1622
+ invoiceCreateBlock: findById(invoiceBlockId, "qi/xero.invoice.create"),
1623
+ paymentCreateBlock: findById(paymentBlockId, "qi/xero.payment.create"),
1624
+ evaluateBlockId: null
1625
+ };
1626
+ }
1627
+ function buildClaimScope(claim, claimData, evaluateBlockId, evaluateContext) {
1628
+ const surveyAnswers = claimData && typeof claimData === "object" ? claimData.credentialSubject ?? claimData.surveyAnswers ?? claimData : {};
1629
+ const evaluationOutput = evaluateContext?.evaluationOutput ?? {};
1630
+ const scope = {
1631
+ claim: {
1632
+ claimId: claim?.claimId || evaluationOutput.claimId || "",
1633
+ agentDid: claim?.agentDid || "",
1634
+ agentAddress: claim?.agentAddress || "",
1635
+ submissionDate: claim?.submissionDate || "",
1636
+ surveyAnswers,
1637
+ ...surveyAnswers
1638
+ },
1639
+ evaluation: {
1640
+ transactionHash: evaluationOutput.transactionHash || "",
1641
+ amount: evaluationOutput.amount || "",
1642
+ date: (/* @__PURE__ */ new Date()).toISOString().slice(0, 10)
1643
+ }
1644
+ };
1645
+ const trimmedId = String(evaluateBlockId || "").trim();
1646
+ if (trimmedId) {
1647
+ scope[trimmedId] = {
1648
+ output: {
1649
+ claimId: claim?.claimId || evaluationOutput.claimId || "",
1650
+ collectionId: evaluateContext?.collectionId || "",
1651
+ deedDid: evaluateContext?.deedDid || "",
1652
+ surveyAnswers,
1653
+ ...evaluationOutput
1654
+ }
1655
+ };
1656
+ }
1657
+ return scope;
1658
+ }
1659
+ function resolveIterativeSource(source, editorDocument, opts) {
1660
+ const refs = parseReferences(source || "");
1661
+ if (refs.length === 0) return [];
1662
+ const ref = refs[0];
1663
+ const value = resolveSingleReference(ref.blockId, ref.propPath, editorDocument, opts.yRuntime, opts.scope);
1664
+ return Array.isArray(value) ? value : [];
1665
+ }
1666
+ function resolveCells(cells, editorDocument, opts) {
1667
+ const out = {};
1668
+ for (const key of LINE_ITEM_FIELD_KEYS) {
1669
+ out[key] = resolveReferences(cells[key] || "", editorDocument, opts);
1670
+ }
1671
+ return out;
1672
+ }
1673
+ function buildLineItemsArray(config, editorDocument, opts) {
1674
+ if (config.mode === "manual") {
1675
+ if (config.rows.length === 0) throw new Error("At least one line item is required.");
1676
+ return config.rows.map((row) => finaliseLineItem(resolveCells(row, editorDocument, opts)));
1677
+ }
1678
+ const elements = resolveIterativeSource(config.source, editorDocument, opts);
1679
+ if (elements.length === 0) throw new Error("The bound source list is empty or could not be resolved.");
1680
+ return elements.map((element) => {
1681
+ const perItemOpts = { ...opts, scope: { ...opts.scope || {}, item: element } };
1682
+ return finaliseLineItem(resolveCells(config.map, editorDocument, perItemOpts));
1683
+ });
1684
+ }
1685
+ async function resolveInvoiceWorkPayload(block, editorDocument, scope) {
1686
+ const parsed = parseXeroInvoiceCreateInputs(block?.props?.inputs);
1687
+ const opts = { scope };
1688
+ const resolveStr = (v) => resolveReferences(v || "", editorDocument, opts);
1689
+ const payload = {
1690
+ connection: parsed.connection,
1691
+ tenant_id: resolveStr(parsed.tenant_id),
1692
+ Type: resolveStr(parsed.Type) || "ACCREC",
1693
+ Status: resolveStr(parsed.Status) || "DRAFT",
1694
+ Date: resolveStr(parsed.Date),
1695
+ DueDate: resolveStr(parsed.DueDate),
1696
+ ContactID: resolveStr(parsed.ContactID),
1697
+ ContactName: resolveStr(parsed.ContactName),
1698
+ Reference: resolveStr(parsed.Reference),
1699
+ InvoiceNumber: resolveStr(parsed.InvoiceNumber),
1700
+ CurrencyCode: resolveStr(parsed.CurrencyCode),
1701
+ LineItems: buildLineItemsArray(parsed.LineItems, editorDocument, opts)
1702
+ };
1703
+ let preview = [];
1704
+ const resolver = getDiffResolver("qi/xero.invoice.create");
1705
+ if (resolver) {
1706
+ try {
1707
+ preview = await resolver.resolver({ ...payload, LineItems: parsed.LineItems }, {});
1708
+ } catch {
1709
+ preview = [];
1710
+ }
1711
+ }
1712
+ return { payload, preview };
1713
+ }
1714
+ async function resolvePaymentWorkPayload(block, editorDocument, baseScope, settlement) {
1715
+ const parsed = parseXeroPaymentCreateInputs(block?.props?.inputs);
1716
+ const scope = {
1717
+ ...baseScope,
1718
+ invoice: { invoiceId: settlement.invoiceId, InvoiceID: settlement.invoiceId },
1719
+ evaluation: {
1720
+ transactionHash: settlement.transactionHash,
1721
+ amount: settlement.amount,
1722
+ date: settlement.date || (/* @__PURE__ */ new Date()).toISOString().slice(0, 10)
1723
+ }
1724
+ };
1725
+ const opts = { scope };
1726
+ const resolveStr = (v) => resolveReferences(v || "", editorDocument, opts);
1727
+ const currencyRateRaw = resolveStr(parsed.CurrencyRate);
1728
+ const currencyRate = currencyRateRaw ? Number(currencyRateRaw) : void 0;
1729
+ const amountRaw = resolveStr(parsed.Amount);
1730
+ const amount = Number.isFinite(Number(amountRaw)) && Number(amountRaw) > 0 ? Number(amountRaw) : settlement.amount;
1731
+ const payload = {
1732
+ connection: parsed.connection,
1733
+ tenant_id: resolveStr(parsed.tenant_id),
1734
+ InvoiceID: resolveStr(parsed.InvoiceID) || settlement.invoiceId,
1735
+ AccountID: resolveStr(parsed.AccountID),
1736
+ Date: resolveStr(parsed.Date) || settlement.date || (/* @__PURE__ */ new Date()).toISOString().slice(0, 10),
1737
+ Amount: amount,
1738
+ Reference: resolveStr(parsed.Reference) || settlement.transactionHash,
1739
+ CurrencyRate: typeof currencyRate === "number" && Number.isFinite(currencyRate) ? currencyRate : void 0
1740
+ };
1741
+ let preview = [];
1742
+ const resolver = getDiffResolver("qi/xero.payment.create");
1743
+ if (resolver) {
1744
+ try {
1745
+ preview = await resolver.resolver({ ...payload, Amount: String(payload.Amount) }, {});
1746
+ } catch {
1747
+ preview = [];
1748
+ }
1749
+ }
1750
+ return { payload, preview };
1751
+ }
1752
+ function getInvoiceTotal(output) {
1753
+ const total = typeof output.total === "number" ? output.total : Number(output.total);
1754
+ return Number.isFinite(total) && total > 0 ? total : 0;
1755
+ }
1756
+
1258
1757
  // src/core/lib/actionRegistry/actions/evaluateClaim/evaluateClaim.ts
1259
1758
  var BASELINE_OUTPUT2 = [
1260
1759
  { path: "claimId", displayName: "Claim ID", type: "string", description: "Evaluated claim identifier" },
@@ -1463,11 +1962,12 @@ registerAction({
1463
1962
  amount: normalizedCoin
1464
1963
  });
1465
1964
  const transactionHash = String(broadcastResult?.transactionHash || "");
1965
+ let claimData = null;
1466
1966
  let surveyAnswers = {};
1467
1967
  try {
1468
1968
  const getClaimData = handlers?.getClaimData;
1469
1969
  if (typeof getClaimData === "function") {
1470
- const claimData = await getClaimData(collectionId, claimId, { entityDid: deedDid });
1970
+ claimData = await getClaimData(collectionId, claimId, { entityDid: deedDid });
1471
1971
  const candidate = claimData?.credentialSubject ?? claimData?.surveyAnswers ?? claimData;
1472
1972
  if (candidate && typeof candidate === "object" && !Array.isArray(candidate)) {
1473
1973
  surveyAnswers = candidate;
@@ -1489,6 +1989,56 @@ registerAction({
1489
1989
  evaluatedAt,
1490
1990
  surveyAnswers
1491
1991
  };
1992
+ const xeroInvoiceBlockId = String(inputs.xeroInvoiceBlockId || "").trim();
1993
+ if (decision === "approve" && xeroInvoiceBlockId) {
1994
+ const editorDoc = ctx.editor?.document || [];
1995
+ const runtime = ctx.runtime;
1996
+ if (!runtime) {
1997
+ throw new Error("Cannot queue Xero invoice work: runtime state manager is unavailable");
1998
+ }
1999
+ const bindings = resolveXeroBindings(editorDoc, xeroInvoiceBlockId, String(inputs.xeroPaymentBlockId || ""));
2000
+ const invoiceBlock = bindings.invoiceCreateBlock;
2001
+ if (!invoiceBlock) {
2002
+ throw new Error("Cannot queue Xero invoice work: bound invoice block was not found");
2003
+ }
2004
+ const flowId = String(ctx.flowId || ctx.flowUri || "flow");
2005
+ const scope = buildClaimScope(inputs.claimSnapshot || { claimId }, claimData || surveyAnswers, ctx.nodeId, {
2006
+ deedDid,
2007
+ collectionId,
2008
+ evaluationOutput: output
2009
+ });
2010
+ const { payload } = await resolveInvoiceWorkPayload(invoiceBlock, editorDoc, scope);
2011
+ const idempotencyKey = buildXeroInvoiceWorkKey({
2012
+ flowId,
2013
+ evaluationBlockId: ctx.nodeId,
2014
+ claimId,
2015
+ invoiceBlockId: invoiceBlock.id
2016
+ });
2017
+ upsertXeroWorkItemForEditor(ctx.editor, {
2018
+ id: idempotencyKey,
2019
+ kind: "invoice.create",
2020
+ status: "pending",
2021
+ assignedBlockId: invoiceBlock.id,
2022
+ idempotencyKey,
2023
+ source: {
2024
+ claimId,
2025
+ evaluationBlockId: ctx.nodeId,
2026
+ deedDid,
2027
+ collectionId
2028
+ },
2029
+ originalPayload: payload,
2030
+ reviewPayload: payload,
2031
+ provenance: {
2032
+ createdAt: Date.now(),
2033
+ createdByDid: ctx.actorDid,
2034
+ templateBlockId: invoiceBlock.id,
2035
+ templateInputsSnapshot: invoiceBlock.props?.inputs,
2036
+ evaluationOutput: output,
2037
+ claimSnapshot: inputs.claimSnapshot
2038
+ },
2039
+ attempts: []
2040
+ });
2041
+ }
1492
2042
  const eventName = decision === "approve" ? "approved" : "rejected";
1493
2043
  const eventPayload = decision === "approve" ? {
1494
2044
  claimId,
@@ -4889,7 +5439,7 @@ registerAction({
4889
5439
  }
4890
5440
  const invoiceId = String(inputs.InvoiceID || "").trim();
4891
5441
  if (!invoiceId) {
4892
- throw new Error("InvoiceID is required \u2014 usually wired from the upstream Capture Bill step.");
5442
+ throw new Error("InvoiceID is required; work items usually supply it from invoice.create completion.");
4893
5443
  }
4894
5444
  const accountId = String(inputs.AccountID || "").trim();
4895
5445
  if (!accountId) {
@@ -6422,6 +6972,8 @@ var buildFlowNodeFromBlock = (block) => {
6422
6972
  };
6423
6973
 
6424
6974
  // src/core/lib/flowEngine/runtime.ts
6975
+ var XERO_WORK_ITEMS_MAP_NAME = "xeroWorkItems";
6976
+ var XERO_CONNECTION_MAP_NAME = "xeroConnection";
6425
6977
  var ensureStateObject = (value) => {
6426
6978
  if (!value || typeof value !== "object") {
6427
6979
  return {};
@@ -6466,6 +7018,8 @@ function clearRuntimeForTemplateClone(yDoc) {
6466
7018
  const agentOutbox = yDoc.getMap("agentOutbox");
6467
7019
  const agentLeases = yDoc.getMap("agentLeases");
6468
7020
  const auditTrail = yDoc.getMap("auditTrail");
7021
+ const xeroWorkItems = yDoc.getMap(XERO_WORK_ITEMS_MAP_NAME);
7022
+ const xeroConnection = yDoc.getMap(XERO_CONNECTION_MAP_NAME);
6469
7023
  yDoc.transact(() => {
6470
7024
  runtime.forEach((_, key) => runtime.delete(key));
6471
7025
  invocations.forEach((_, key) => invocations.delete(key));
@@ -6473,6 +7027,8 @@ function clearRuntimeForTemplateClone(yDoc) {
6473
7027
  agentOutbox.forEach((_, key) => agentOutbox.delete(key));
6474
7028
  agentLeases.forEach((_, key) => agentLeases.delete(key));
6475
7029
  auditTrail.forEach((_, key) => auditTrail.delete(key));
7030
+ xeroWorkItems.forEach((_, key) => xeroWorkItems.delete(key));
7031
+ xeroConnection.forEach((_, key) => xeroConnection.delete(key));
6476
7032
  });
6477
7033
  }
6478
7034
 
@@ -6507,7 +7063,7 @@ function resolveRef(ref, getNodeOutput2, triggerContext) {
6507
7063
  throw new Error(`Trigger ref "${ref}" used outside of a listener invocation context. trigger.payload.* refs are only valid on block.event-triggered blocks.`);
6508
7064
  }
6509
7065
  const fieldPath2 = ref.slice("trigger.payload.".length);
6510
- return getNestedValue(triggerContext.payload, fieldPath2);
7066
+ return getNestedValue2(triggerContext.payload, fieldPath2);
6511
7067
  }
6512
7068
  if (triggerContext && Object.prototype.hasOwnProperty.call(triggerContext.refSnapshots, ref)) {
6513
7069
  return triggerContext.refSnapshots[ref];
@@ -6522,9 +7078,9 @@ function resolveRef(ref, getNodeOutput2, triggerContext) {
6522
7078
  if (!output) {
6523
7079
  return void 0;
6524
7080
  }
6525
- return getNestedValue(output, fieldPath);
7081
+ return getNestedValue2(output, fieldPath);
6526
7082
  }
6527
- function getNestedValue(obj, path) {
7083
+ function getNestedValue2(obj, path) {
6528
7084
  const parts = path.split(".");
6529
7085
  let current = obj;
6530
7086
  for (const part of parts) {
@@ -6762,7 +7318,7 @@ function snapshotInputRefs(inputs, getNodeOutput2) {
6762
7318
  if (!parsed) return;
6763
7319
  const output = getNodeOutput2(parsed.nodeId);
6764
7320
  if (!output) return;
6765
- snapshots[ref.$ref] = getNestedValue2(output, parsed.fieldPath);
7321
+ snapshots[ref.$ref] = getNestedValue3(output, parsed.fieldPath);
6766
7322
  });
6767
7323
  return snapshots;
6768
7324
  }
@@ -6787,7 +7343,7 @@ function parseOutputRef(ref) {
6787
7343
  fieldPath: ref.slice(outputIndex + ".output.".length)
6788
7344
  };
6789
7345
  }
6790
- function getNestedValue2(obj, path) {
7346
+ function getNestedValue3(obj, path) {
6791
7347
  const parts = path.split(".");
6792
7348
  let current = obj;
6793
7349
  for (const part of parts) {
@@ -7119,7 +7675,9 @@ function processBarrierRunRecord(yDoc, sourceBlockId, record, barrierListenersBy
7119
7675
  }
7120
7676
  const allSources = trigger.sources || [];
7121
7677
  const currentState = readBarrierState(yDoc, listenerBlockId);
7122
- const allFired = allSources.length > 0 && allSources.every((s) => currentState.some((e) => e.sourceBlockId === s.sourceBlockId && e.eventName === s.eventName));
7678
+ const requiredSources = allSources.filter((s) => s.optional !== true);
7679
+ const gatingSources = requiredSources.length > 0 ? requiredSources : allSources;
7680
+ const allFired = gatingSources.length > 0 && gatingSources.every((s) => currentState.some((e) => e.sourceBlockId === s.sourceBlockId && e.eventName === s.eventName));
7123
7681
  if (!allFired) continue;
7124
7682
  const assigneeDid = resolveAssignee(listenerBlock) || "unassigned";
7125
7683
  const id = computeBarrierInvocationId(currentState, listenerBlockId);
@@ -10127,6 +10685,28 @@ export {
10127
10685
  hasDiffResolver,
10128
10686
  extractDid,
10129
10687
  extractSurveyAnswerSchema,
10688
+ buildXeroPaymentWorkKey,
10689
+ findXeroWorkItemsForEditor,
10690
+ upsertXeroWorkItemForEditor,
10691
+ updateXeroWorkReviewPayloadForEditor,
10692
+ markXeroWorkFailedForEditor,
10693
+ markXeroWorkCompletedForEditor,
10694
+ LINE_ITEM_FIELD_KEYS,
10695
+ emptyLineItemCells,
10696
+ parseXeroInvoiceCreateInputs,
10697
+ serializeXeroInvoiceCreateInputs,
10698
+ finaliseLineItem,
10699
+ parseXeroPaymentCreateInputs,
10700
+ serializeXeroPaymentCreateInputs,
10701
+ parseReferences,
10702
+ resolveSingleReference,
10703
+ resolveReferences,
10704
+ hasReferences,
10705
+ createReference,
10706
+ resolveXeroBindings,
10707
+ buildClaimScope,
10708
+ resolvePaymentWorkPayload,
10709
+ getInvoiceTotal,
10130
10710
  transformSurveyToCredentialSubject,
10131
10711
  buildVerifiableCredential,
10132
10712
  buildDomainCardLinkedResource,
@@ -10219,4 +10799,4 @@ export {
10219
10799
  executeQueuedFlowAgentCoreCommands,
10220
10800
  FlowAgentService
10221
10801
  };
10222
- //# sourceMappingURL=chunk-HETRTQWL.mjs.map
10802
+ //# sourceMappingURL=chunk-UMS6GCME.mjs.map