@stndrds/schema 0.1.0-alpha.15 → 0.1.0-alpha.16

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/runtime.js CHANGED
@@ -121,6 +121,7 @@ __export(runtime_exports, {
121
121
  AuditService: () => AuditService,
122
122
  DEFAULT_LABEL_FALLBACK: () => DEFAULT_LABEL_FALLBACK,
123
123
  FileService: () => FileService,
124
+ FlowService: () => FlowService,
124
125
  GeocodingService: () => GeocodingService,
125
126
  GlobalSearchService: () => GlobalSearchService,
126
127
  NoopGeocodingAdapter: () => NoopGeocodingAdapter,
@@ -1533,6 +1534,273 @@ var FileService = class {
1533
1534
  }
1534
1535
  };
1535
1536
 
1537
+ // src/runtime/services/flow.service.ts
1538
+ var FlowService = class {
1539
+ constructor(adapter, systemFlows = []) {
1540
+ this.adapter = adapter;
1541
+ this.systemFlows = new Map(systemFlows.map((f) => [f.name, f]));
1542
+ }
1543
+ /**
1544
+ * Get all flows for a tenant (system + custom)
1545
+ */
1546
+ async getAllFlows(tenantId) {
1547
+ const systemFlowsList = Array.from(this.systemFlows.values());
1548
+ if (!this.adapter.flows) {
1549
+ return systemFlowsList;
1550
+ }
1551
+ const dbFlows = await this.adapter.flows.findAllForTenant(tenantId);
1552
+ const customFlows = dbFlows.filter((f) => !f.system).map(this.convertDBFlowToDefinition);
1553
+ return [...systemFlowsList, ...customFlows];
1554
+ }
1555
+ /**
1556
+ * Get published flows only
1557
+ */
1558
+ async getPublishedFlows(tenantId) {
1559
+ const allFlows = await this.getAllFlows(tenantId);
1560
+ return allFlows.filter((f) => f.status === "published");
1561
+ }
1562
+ /**
1563
+ * Get a specific flow by name
1564
+ */
1565
+ async getFlow(name, tenantId) {
1566
+ const systemFlow = this.systemFlows.get(name);
1567
+ if (systemFlow) {
1568
+ return systemFlow;
1569
+ }
1570
+ if (!this.adapter.flows) {
1571
+ return null;
1572
+ }
1573
+ const dbFlow = await this.adapter.flows.findByName(tenantId, name);
1574
+ if (dbFlow) {
1575
+ return this.convertDBFlowToDefinition(dbFlow);
1576
+ }
1577
+ return null;
1578
+ }
1579
+ /**
1580
+ * Get a flow by ID
1581
+ */
1582
+ async getFlowById(flowId) {
1583
+ if (!this.adapter.flows) {
1584
+ return null;
1585
+ }
1586
+ const dbFlow = await this.adapter.flows.findById(flowId);
1587
+ if (dbFlow) {
1588
+ return this.convertDBFlowToDefinition(dbFlow);
1589
+ }
1590
+ return null;
1591
+ }
1592
+ /**
1593
+ * Create a new custom flow (as draft)
1594
+ */
1595
+ async createFlow(input, tenantId) {
1596
+ if (!this.adapter.flows) {
1597
+ throw new Error("Flows feature is not enabled. Database adapter does not support flows.");
1598
+ }
1599
+ this.validateFlowName(input.name);
1600
+ const existing = await this.adapter.flows.findByName(tenantId, input.name);
1601
+ if (existing) {
1602
+ throw new Error(`Flow "${input.name}" already exists`);
1603
+ }
1604
+ if (this.systemFlows.has(input.name)) {
1605
+ throw new Error(
1606
+ `Cannot create flow "${input.name}": a system flow with this name already exists`
1607
+ );
1608
+ }
1609
+ this.validateFlowStructure(input);
1610
+ const dbFlow = await this.adapter.flows.create({
1611
+ tenantId,
1612
+ name: input.name,
1613
+ label: input.label,
1614
+ description: input.description,
1615
+ icon: input.icon,
1616
+ status: "draft",
1617
+ version: 1,
1618
+ slots: input.slots,
1619
+ pages: input.pages,
1620
+ relations: input.relations,
1621
+ system: false,
1622
+ metadata: input.metadata
1623
+ });
1624
+ return this.convertDBFlowToDefinition(dbFlow);
1625
+ }
1626
+ /**
1627
+ * Update a custom flow
1628
+ */
1629
+ async updateFlow(flowId, input) {
1630
+ if (!this.adapter.flows) {
1631
+ throw new Error("Flows feature is not enabled.");
1632
+ }
1633
+ const dbFlow = await this.adapter.flows.findById(flowId);
1634
+ if (!dbFlow) {
1635
+ throw new Error(`Flow with id "${flowId}" not found`);
1636
+ }
1637
+ if (dbFlow.system) {
1638
+ throw new Error("Cannot modify system flows. System flows are protected.");
1639
+ }
1640
+ if (input.slots || input.pages || input.relations) {
1641
+ this.validateFlowStructure({
1642
+ name: dbFlow.name,
1643
+ label: input.label ?? dbFlow.label,
1644
+ slots: input.slots ?? dbFlow.slots,
1645
+ pages: input.pages ?? dbFlow.pages,
1646
+ relations: input.relations ?? dbFlow.relations
1647
+ });
1648
+ }
1649
+ const updated = await this.adapter.flows.update(flowId, {
1650
+ label: input.label,
1651
+ description: input.description,
1652
+ icon: input.icon,
1653
+ slots: input.slots,
1654
+ pages: input.pages,
1655
+ relations: input.relations,
1656
+ metadata: input.metadata
1657
+ });
1658
+ return this.convertDBFlowToDefinition(updated);
1659
+ }
1660
+ /**
1661
+ * Publish a flow
1662
+ */
1663
+ async publishFlow(flowId) {
1664
+ if (!this.adapter.flows) {
1665
+ throw new Error("Flows feature is not enabled.");
1666
+ }
1667
+ const dbFlow = await this.adapter.flows.findById(flowId);
1668
+ if (!dbFlow) {
1669
+ throw new Error(`Flow with id "${flowId}" not found`);
1670
+ }
1671
+ if (dbFlow.system) {
1672
+ throw new Error("Cannot publish system flows. They are always published.");
1673
+ }
1674
+ if (dbFlow.status === "published") {
1675
+ return this.convertDBFlowToDefinition(dbFlow);
1676
+ }
1677
+ this.validateFlowStructure({
1678
+ name: dbFlow.name,
1679
+ label: dbFlow.label,
1680
+ slots: dbFlow.slots,
1681
+ pages: dbFlow.pages,
1682
+ relations: dbFlow.relations
1683
+ });
1684
+ const updated = await this.adapter.flows.update(flowId, {
1685
+ status: "published",
1686
+ version: dbFlow.version + 1
1687
+ });
1688
+ return this.convertDBFlowToDefinition(updated);
1689
+ }
1690
+ /**
1691
+ * Archive a flow
1692
+ */
1693
+ async archiveFlow(flowId) {
1694
+ if (!this.adapter.flows) {
1695
+ throw new Error("Flows feature is not enabled.");
1696
+ }
1697
+ const dbFlow = await this.adapter.flows.findById(flowId);
1698
+ if (!dbFlow) {
1699
+ throw new Error(`Flow with id "${flowId}" not found`);
1700
+ }
1701
+ if (dbFlow.system) {
1702
+ throw new Error("Cannot archive system flows.");
1703
+ }
1704
+ const updated = await this.adapter.flows.update(flowId, {
1705
+ status: "archived"
1706
+ });
1707
+ return this.convertDBFlowToDefinition(updated);
1708
+ }
1709
+ /**
1710
+ * Delete a custom flow
1711
+ */
1712
+ async deleteFlow(flowId) {
1713
+ if (!this.adapter.flows) {
1714
+ throw new Error("Flows feature is not enabled.");
1715
+ }
1716
+ const dbFlow = await this.adapter.flows.findById(flowId);
1717
+ if (!dbFlow) {
1718
+ throw new Error(`Flow with id "${flowId}" not found`);
1719
+ }
1720
+ if (dbFlow.system) {
1721
+ throw new Error("Cannot delete system flows. System flows are protected.");
1722
+ }
1723
+ await this.adapter.flows.delete(flowId);
1724
+ }
1725
+ // ============================================================================
1726
+ // PRIVATE HELPERS
1727
+ // ============================================================================
1728
+ /**
1729
+ * Validate flow name format (kebab-case)
1730
+ */
1731
+ validateFlowName(name) {
1732
+ if (!name || name.length === 0) {
1733
+ throw new Error("Flow name cannot be empty");
1734
+ }
1735
+ if (name.length > 63) {
1736
+ throw new Error("Flow name is too long (max 63 characters)");
1737
+ }
1738
+ const kebabCaseRegex = /^[a-z][a-z0-9-]*$/;
1739
+ if (!kebabCaseRegex.test(name)) {
1740
+ throw new Error(
1741
+ "Invalid flow name format. Name must be in kebab-case (e.g., 'couple-creation', 'new-contact')"
1742
+ );
1743
+ }
1744
+ }
1745
+ /**
1746
+ * Validate flow structure (slots, pages, relations)
1747
+ */
1748
+ validateFlowStructure(input) {
1749
+ if (!input.slots || input.slots.length === 0) {
1750
+ throw new Error("Flow must have at least one slot");
1751
+ }
1752
+ if (!input.pages || input.pages.length === 0) {
1753
+ throw new Error("Flow must have at least one page");
1754
+ }
1755
+ const slotIds = new Set(input.slots.map((s) => s.id));
1756
+ if (slotIds.size !== input.slots.length) {
1757
+ throw new Error("Duplicate slot IDs detected");
1758
+ }
1759
+ for (const page of input.pages) {
1760
+ for (const row of page.rows) {
1761
+ for (const field of row.fields) {
1762
+ if (!slotIds.has(field.slotId)) {
1763
+ throw new Error(`Field "${field.id}" references unknown slot "${field.slotId}"`);
1764
+ }
1765
+ }
1766
+ }
1767
+ }
1768
+ for (const relation of input.relations) {
1769
+ if (!slotIds.has(relation.sourceSlotId)) {
1770
+ throw new Error(`Relation references unknown source slot "${relation.sourceSlotId}"`);
1771
+ }
1772
+ if (!slotIds.has(relation.targetSlotId)) {
1773
+ throw new Error(`Relation references unknown target slot "${relation.targetSlotId}"`);
1774
+ }
1775
+ if (relation.sourceSlotId === relation.targetSlotId) {
1776
+ throw new Error(`Relation cannot link a slot to itself: "${relation.sourceSlotId}"`);
1777
+ }
1778
+ }
1779
+ }
1780
+ /**
1781
+ * Convert database flow to FlowDefinition
1782
+ */
1783
+ convertDBFlowToDefinition(dbFlow) {
1784
+ return {
1785
+ id: dbFlow.id,
1786
+ name: dbFlow.name,
1787
+ label: dbFlow.label,
1788
+ description: dbFlow.description,
1789
+ icon: dbFlow.icon,
1790
+ status: dbFlow.status,
1791
+ version: dbFlow.version,
1792
+ slots: dbFlow.slots,
1793
+ pages: dbFlow.pages,
1794
+ relations: dbFlow.relations,
1795
+ system: dbFlow.system,
1796
+ tenantId: dbFlow.tenantId,
1797
+ metadata: dbFlow.metadata,
1798
+ createdAt: dbFlow.createdAt,
1799
+ updatedAt: dbFlow.updatedAt
1800
+ };
1801
+ }
1802
+ };
1803
+
1536
1804
  // src/runtime/services/geocoding.service.ts
1537
1805
  var GeocodingService = class {
1538
1806
  constructor(adapter) {
@@ -1652,8 +1920,11 @@ var GlobalSearchService = class {
1652
1920
  var import_constants = require("@stndrds/constants");
1653
1921
  var VALID_ICONS = new Set(import_constants.ICONS);
1654
1922
 
1923
+ // src/builders/flow-builder.ts
1924
+ var import_zod = require("zod");
1925
+
1655
1926
  // src/builders/object-builder.ts
1656
- var import_zod = __toESM(require("zod"));
1927
+ var import_zod2 = __toESM(require("zod"));
1657
1928
  var ObjectBuilder = class {
1658
1929
  constructor(config) {
1659
1930
  this.validateName(config.name);
@@ -1786,14 +2057,14 @@ The labelExpression defines how records are displayed in lists and relations.
1786
2057
  if (name === void 0) {
1787
2058
  return;
1788
2059
  }
1789
- const objectNameSchema = import_zod.default.string().min(1, "Object name cannot be empty").max(63, "Object name is too long (max 63 characters)").regex(/^[a-z][a-z0-9-]*$/, {
2060
+ const objectNameSchema = import_zod2.default.string().min(1, "Object name cannot be empty").max(63, "Object name is too long (max 63 characters)").regex(/^[a-z][a-z0-9-]*$/, {
1790
2061
  message: "Invalid object name format.\nName must be in kebab-case (slug format):\n \u2705 Valid: 'products', 'user-profiles', 'order-items'\n \u274C Invalid: 'Products', 'userProfiles', 'user_profiles'"
1791
2062
  });
1792
2063
  try {
1793
2064
  objectNameSchema.parse(name);
1794
2065
  } catch (error) {
1795
- if (error instanceof import_zod.default.ZodError) {
1796
- throw new Error(`[ObjectBuilder] ${error.errors[0].message}`);
2066
+ if (error instanceof import_zod2.default.ZodError) {
2067
+ throw new Error(`[ObjectBuilder] ${error.issues[0].message}`);
1797
2068
  }
1798
2069
  throw error;
1799
2070
  }
@@ -1804,7 +2075,7 @@ function object(config) {
1804
2075
  }
1805
2076
 
1806
2077
  // src/builders/view-builder.ts
1807
- var import_zod2 = require("zod");
2078
+ var import_zod3 = require("zod");
1808
2079
 
1809
2080
  // src/types/errors.ts
1810
2081
  var RecordReferencedError = class extends Error {
@@ -1839,35 +2110,35 @@ var ObjectReferencedError = class extends Error {
1839
2110
  };
1840
2111
 
1841
2112
  // src/validation/validators.ts
1842
- var import_zod3 = require("zod");
1843
- var baseConfigSchema = import_zod3.z.object({
1844
- disabled: import_zod3.z.boolean().optional(),
1845
- placeholder: import_zod3.z.string().optional(),
1846
- description: import_zod3.z.string().optional(),
1847
- defaultValue: import_zod3.z.unknown().optional(),
1848
- icon: import_zod3.z.string().optional(),
1849
- order: import_zod3.z.number().int().optional(),
1850
- hidden: import_zod3.z.boolean().optional(),
1851
- archived: import_zod3.z.boolean().optional(),
1852
- deprecated: import_zod3.z.boolean().optional(),
1853
- metadata: import_zod3.z.record(import_zod3.z.unknown()).optional()
2113
+ var import_zod4 = require("zod");
2114
+ var baseConfigSchema = import_zod4.z.object({
2115
+ disabled: import_zod4.z.boolean().optional(),
2116
+ placeholder: import_zod4.z.string().optional(),
2117
+ description: import_zod4.z.string().optional(),
2118
+ defaultValue: import_zod4.z.unknown().optional(),
2119
+ icon: import_zod4.z.string().optional(),
2120
+ order: import_zod4.z.number().int().optional(),
2121
+ hidden: import_zod4.z.boolean().optional(),
2122
+ archived: import_zod4.z.boolean().optional(),
2123
+ deprecated: import_zod4.z.boolean().optional(),
2124
+ metadata: import_zod4.z.record(import_zod4.z.string(), import_zod4.z.unknown()).optional()
1854
2125
  });
1855
- var optionSchema = import_zod3.z.object({
1856
- id: import_zod3.z.string().min(1),
1857
- label: import_zod3.z.string().min(1),
1858
- value: import_zod3.z.string().min(1),
1859
- color: import_zod3.z.string().optional(),
1860
- icon: import_zod3.z.string().optional(),
1861
- description: import_zod3.z.string().optional(),
1862
- group: import_zod3.z.enum(["idle", "in_progress", "finished"]).optional()
2126
+ var optionSchema = import_zod4.z.object({
2127
+ id: import_zod4.z.string().min(1),
2128
+ label: import_zod4.z.string().min(1),
2129
+ value: import_zod4.z.string().min(1),
2130
+ color: import_zod4.z.string().optional(),
2131
+ icon: import_zod4.z.string().optional(),
2132
+ description: import_zod4.z.string().optional(),
2133
+ group: import_zod4.z.enum(["idle", "in_progress", "finished"]).optional()
1863
2134
  });
1864
- var relationTargetSchema = import_zod3.z.object({
1865
- object: import_zod3.z.string().min(1),
1866
- displayTemplate: import_zod3.z.string().optional(),
1867
- filter: import_zod3.z.record(import_zod3.z.unknown()).optional()
2135
+ var relationTargetSchema = import_zod4.z.object({
2136
+ object: import_zod4.z.string().min(1),
2137
+ displayTemplate: import_zod4.z.string().optional(),
2138
+ filter: import_zod4.z.record(import_zod4.z.string(), import_zod4.z.unknown()).optional()
1868
2139
  });
1869
- var documentTypeConfigSchema = import_zod3.z.object({
1870
- type: import_zod3.z.enum([
2140
+ var documentTypeConfigSchema = import_zod4.z.object({
2141
+ type: import_zod4.z.enum([
1871
2142
  "id_card",
1872
2143
  "passport",
1873
2144
  "incorporation_certificate",
@@ -1878,86 +2149,86 @@ var documentTypeConfigSchema = import_zod3.z.object({
1878
2149
  "proof_of_address",
1879
2150
  "custom"
1880
2151
  ]),
1881
- label: import_zod3.z.string(),
1882
- faces: import_zod3.z.array(import_zod3.z.enum(["front", "back", "single"])),
1883
- attributeMapping: import_zod3.z.array(
1884
- import_zod3.z.object({
1885
- attributeId: import_zod3.z.string(),
1886
- extractedKey: import_zod3.z.string(),
1887
- face: import_zod3.z.enum(["front", "back", "single"]).optional(),
1888
- required: import_zod3.z.boolean().optional()
2152
+ label: import_zod4.z.string(),
2153
+ faces: import_zod4.z.array(import_zod4.z.enum(["front", "back", "single"])),
2154
+ attributeMapping: import_zod4.z.array(
2155
+ import_zod4.z.object({
2156
+ attributeId: import_zod4.z.string(),
2157
+ extractedKey: import_zod4.z.string(),
2158
+ face: import_zod4.z.enum(["front", "back", "single"]).optional(),
2159
+ required: import_zod4.z.boolean().optional()
1889
2160
  })
1890
2161
  ).optional()
1891
2162
  });
1892
- var fileVerificationConfigSchema = import_zod3.z.object({
1893
- enabled: import_zod3.z.boolean(),
1894
- documentTypes: import_zod3.z.array(documentTypeConfigSchema),
1895
- autoExtract: import_zod3.z.boolean().optional(),
1896
- autoValidate: import_zod3.z.boolean().optional()
2163
+ var fileVerificationConfigSchema = import_zod4.z.object({
2164
+ enabled: import_zod4.z.boolean(),
2165
+ documentTypes: import_zod4.z.array(documentTypeConfigSchema),
2166
+ autoExtract: import_zod4.z.boolean().optional(),
2167
+ autoValidate: import_zod4.z.boolean().optional()
1897
2168
  });
1898
2169
  var textConfigSchema = baseConfigSchema.extend({
1899
- minLength: import_zod3.z.number().int().min(0).optional(),
1900
- maxLength: import_zod3.z.number().int().min(1).optional(),
1901
- pattern: import_zod3.z.string().optional()
2170
+ minLength: import_zod4.z.number().int().min(0).optional(),
2171
+ maxLength: import_zod4.z.number().int().min(1).optional(),
2172
+ pattern: import_zod4.z.string().optional()
1902
2173
  });
1903
2174
  var textareaConfigSchema = baseConfigSchema;
1904
2175
  var numberConfigSchema = baseConfigSchema.extend({
1905
- min: import_zod3.z.number().optional(),
1906
- max: import_zod3.z.number().optional(),
1907
- unit: import_zod3.z.enum(["integer", "decimal", "percentage"]).optional(),
1908
- decimals: import_zod3.z.number().int().min(0).optional()
2176
+ min: import_zod4.z.number().optional(),
2177
+ max: import_zod4.z.number().optional(),
2178
+ unit: import_zod4.z.enum(["integer", "decimal", "percentage"]).optional(),
2179
+ decimals: import_zod4.z.number().int().min(0).optional()
1909
2180
  });
1910
2181
  var checkboxConfigSchema = baseConfigSchema;
1911
2182
  var dateConfigSchema = baseConfigSchema.extend({
1912
- dateFormat: import_zod3.z.enum(["short", "long", "full", "relative"]).optional(),
1913
- minDate: import_zod3.z.string().optional(),
1914
- maxDate: import_zod3.z.string().optional()
2183
+ dateFormat: import_zod4.z.enum(["short", "long", "full", "relative"]).optional(),
2184
+ minDate: import_zod4.z.string().optional(),
2185
+ maxDate: import_zod4.z.string().optional()
1915
2186
  });
1916
2187
  var phoneConfigSchema = baseConfigSchema.extend({
1917
- defaultCountryCode: import_zod3.z.string().length(3).optional()
2188
+ defaultCountryCode: import_zod4.z.string().length(3).optional()
1918
2189
  });
1919
2190
  var currencyConfigSchema = baseConfigSchema.extend({
1920
- defaultCurrency: import_zod3.z.string().length(3).optional(),
1921
- allowedCurrencies: import_zod3.z.array(import_zod3.z.string().length(3)).optional()
2191
+ defaultCurrency: import_zod4.z.string().length(3).optional(),
2192
+ allowedCurrencies: import_zod4.z.array(import_zod4.z.string().length(3)).optional()
1922
2193
  });
1923
2194
  var statusConfigSchema = baseConfigSchema.extend({
1924
- options: import_zod3.z.array(optionSchema).min(1)
2195
+ options: import_zod4.z.array(optionSchema).min(1)
1925
2196
  });
1926
2197
  var locationConfigSchema = baseConfigSchema.extend({
1927
- granularity: import_zod3.z.enum(["full", "address", "city", "state", "country", "coordinates"]),
1928
- enableAutocomplete: import_zod3.z.boolean().optional(),
1929
- enableMap: import_zod3.z.boolean().optional(),
1930
- defaultCountry: import_zod3.z.string().length(3).optional(),
1931
- allowedCountries: import_zod3.z.array(import_zod3.z.string().length(3)).optional(),
1932
- displayFormat: import_zod3.z.enum(["single_line", "multi_line", "compact"]).optional()
2198
+ granularity: import_zod4.z.enum(["full", "address", "city", "state", "country", "coordinates"]),
2199
+ enableAutocomplete: import_zod4.z.boolean().optional(),
2200
+ enableMap: import_zod4.z.boolean().optional(),
2201
+ defaultCountry: import_zod4.z.string().length(3).optional(),
2202
+ allowedCountries: import_zod4.z.array(import_zod4.z.string().length(3)).optional(),
2203
+ displayFormat: import_zod4.z.enum(["single_line", "multi_line", "compact"]).optional()
1933
2204
  });
1934
2205
  var timestampConfigSchema = baseConfigSchema.extend({
1935
- autoUpdate: import_zod3.z.boolean().optional()
2206
+ autoUpdate: import_zod4.z.boolean().optional()
1936
2207
  });
1937
2208
  var selectConfigSchema = baseConfigSchema.extend({
1938
- options: import_zod3.z.array(optionSchema).min(1)
2209
+ options: import_zod4.z.array(optionSchema).min(1)
1939
2210
  });
1940
2211
  var multiselectConfigSchema = baseConfigSchema.extend({
1941
- options: import_zod3.z.array(optionSchema).min(1)
2212
+ options: import_zod4.z.array(optionSchema).min(1)
1942
2213
  });
1943
2214
  var fileConfigSchema = baseConfigSchema.extend({
1944
- maxFiles: import_zod3.z.number().int().min(1).optional(),
1945
- maxSize: import_zod3.z.number().int().min(1).optional(),
1946
- allowedTypes: import_zod3.z.array(import_zod3.z.string()).optional(),
2215
+ maxFiles: import_zod4.z.number().int().min(1).optional(),
2216
+ maxSize: import_zod4.z.number().int().min(1).optional(),
2217
+ allowedTypes: import_zod4.z.array(import_zod4.z.string()).optional(),
1947
2218
  verification: fileVerificationConfigSchema.optional()
1948
2219
  });
1949
2220
  var userConfigSchema = baseConfigSchema.extend({
1950
- allowedRoles: import_zod3.z.array(import_zod3.z.string()).optional()
2221
+ allowedRoles: import_zod4.z.array(import_zod4.z.string()).optional()
1951
2222
  });
1952
2223
  var relationConfigSchema = baseConfigSchema.extend({
1953
- targets: import_zod3.z.array(relationTargetSchema).min(1),
1954
- cardinality: import_zod3.z.enum(["one", "many"]),
1955
- minItems: import_zod3.z.number().int().min(0).optional(),
1956
- maxItems: import_zod3.z.number().int().min(1).optional()
2224
+ targets: import_zod4.z.array(relationTargetSchema).min(1),
2225
+ cardinality: import_zod4.z.enum(["one", "many"]),
2226
+ minItems: import_zod4.z.number().int().min(0).optional(),
2227
+ maxItems: import_zod4.z.number().int().min(1).optional()
1957
2228
  });
1958
2229
  var ratingConfigSchema = baseConfigSchema.extend({
1959
- max: import_zod3.z.number().int().min(1).optional(),
1960
- iconType: import_zod3.z.enum(["star", "heart", "thumbs", "number"]).optional()
2230
+ max: import_zod4.z.number().int().min(1).optional(),
2231
+ iconType: import_zod4.z.enum(["star", "heart", "thumbs", "number"]).optional()
1961
2232
  });
1962
2233
  var attributeConfigSchemas = {
1963
2234
  text: textConfigSchema,
@@ -1985,7 +2256,7 @@ function parseAttributeConfig(type, config) {
1985
2256
  return schema.strip().parse(config);
1986
2257
  }
1987
2258
  function createTextValidator(attr) {
1988
- let schema = import_zod3.z.string();
2259
+ let schema = import_zod4.z.string();
1989
2260
  if (attr.minLength !== void 0) {
1990
2261
  schema = schema.min(
1991
2262
  attr.minLength,
@@ -2004,7 +2275,7 @@ function createTextValidator(attr) {
2004
2275
  return schema;
2005
2276
  }
2006
2277
  function createNumberValidator(attr) {
2007
- let schema = import_zod3.z.number();
2278
+ let schema = import_zod4.z.number();
2008
2279
  if (attr.min !== void 0) {
2009
2280
  schema = schema.min(attr.min, `${attr.label} must be at least ${attr.min}`);
2010
2281
  }
@@ -2017,81 +2288,75 @@ function createNumberValidator(attr) {
2017
2288
  return schema;
2018
2289
  }
2019
2290
  function createCheckboxValidator(_attr) {
2020
- return import_zod3.z.boolean();
2291
+ return import_zod4.z.boolean();
2021
2292
  }
2022
2293
  function createDateValidator(attr) {
2023
- return import_zod3.z.string().datetime({ message: `${attr.label} must be a valid ISO date` });
2294
+ return import_zod4.z.string().datetime({ message: `${attr.label} must be a valid ISO date` });
2024
2295
  }
2025
2296
  function createPhoneValidator(_attr) {
2026
- return import_zod3.z.object({
2027
- countryCode: import_zod3.z.string().length(3),
2028
- phoneNumber: import_zod3.z.string().min(1)
2297
+ return import_zod4.z.object({
2298
+ countryCode: import_zod4.z.string().length(3),
2299
+ phoneNumber: import_zod4.z.string().min(1)
2029
2300
  });
2030
2301
  }
2031
2302
  function createCurrencyValidator(_attr) {
2032
- return import_zod3.z.object({
2033
- code: import_zod3.z.string().length(3),
2034
- value: import_zod3.z.number().min(0)
2303
+ return import_zod4.z.object({
2304
+ code: import_zod4.z.string().length(3),
2305
+ value: import_zod4.z.number().min(0)
2035
2306
  });
2036
2307
  }
2037
2308
  function createStatusValidator(attr) {
2038
2309
  const validValues = attr.options.map((opt) => opt.value);
2039
- return import_zod3.z.enum(validValues, {
2040
- errorMap: () => ({
2041
- message: `${attr.label} must be one of: ${validValues.join(", ")}`
2042
- })
2310
+ return import_zod4.z.enum(validValues, {
2311
+ error: `${attr.label} must be one of: ${validValues.join(", ")}`
2043
2312
  });
2044
2313
  }
2045
2314
  function createSelectValidator(attr) {
2046
2315
  const validValues = attr.options.map((opt) => opt.value);
2047
- return import_zod3.z.enum(validValues, {
2048
- errorMap: () => ({
2049
- message: `${attr.label} must be one of: ${validValues.join(", ")}`
2050
- })
2316
+ return import_zod4.z.enum(validValues, {
2317
+ error: `${attr.label} must be one of: ${validValues.join(", ")}`
2051
2318
  });
2052
2319
  }
2053
2320
  function createMultiselectValidator(attr) {
2054
2321
  const validValues = attr.options.map((opt) => opt.value);
2055
- return import_zod3.z.array(
2056
- import_zod3.z.enum(validValues, {
2057
- errorMap: () => ({
2058
- message: `Each value must be one of: ${validValues.join(", ")}`
2059
- })
2322
+ return import_zod4.z.array(
2323
+ import_zod4.z.enum(validValues, {
2324
+ error: `Each value must be one of: ${validValues.join(", ")}`
2060
2325
  })
2061
2326
  );
2062
2327
  }
2063
2328
  function createLocationValidator(_attr) {
2064
- return import_zod3.z.object({
2065
- address: import_zod3.z.string().optional(),
2066
- address2: import_zod3.z.string().optional(),
2067
- city: import_zod3.z.string().optional(),
2068
- state: import_zod3.z.string().optional(),
2069
- postalCode: import_zod3.z.string().optional(),
2070
- country: import_zod3.z.string().length(3).optional(),
2071
- latitude: import_zod3.z.number().optional(),
2072
- longitude: import_zod3.z.number().optional()
2329
+ return import_zod4.z.object({
2330
+ address: import_zod4.z.string().optional(),
2331
+ address2: import_zod4.z.string().optional(),
2332
+ city: import_zod4.z.string().optional(),
2333
+ state: import_zod4.z.string().optional(),
2334
+ postalCode: import_zod4.z.string().optional(),
2335
+ country: import_zod4.z.string().length(3).optional(),
2336
+ latitude: import_zod4.z.number().optional(),
2337
+ longitude: import_zod4.z.number().optional()
2073
2338
  });
2074
2339
  }
2075
2340
  function createTimestampValidator(_attr) {
2076
- return import_zod3.z.number().int().positive();
2341
+ return import_zod4.z.number().int().positive();
2077
2342
  }
2078
2343
  function createFileValidator(_attr) {
2079
- return import_zod3.z.string().uuid();
2344
+ return import_zod4.z.string().uuid();
2080
2345
  }
2081
2346
  function createUserValidator(_attr) {
2082
- return import_zod3.z.string().uuid();
2347
+ return import_zod4.z.string().uuid();
2083
2348
  }
2084
2349
  function createSingleRelationValidator(attr) {
2085
- const uuidSchema = import_zod3.z.string().uuid({
2350
+ const uuidSchema = import_zod4.z.string().uuid({
2086
2351
  message: `${attr.label} must be a valid record ID`
2087
2352
  });
2088
- return import_zod3.z.union([uuidSchema, import_zod3.z.null()]);
2353
+ return import_zod4.z.union([uuidSchema, import_zod4.z.null()]);
2089
2354
  }
2090
2355
  function createMultiRelationValidator(attr) {
2091
- const uuidSchema = import_zod3.z.string().uuid({
2356
+ const uuidSchema = import_zod4.z.string().uuid({
2092
2357
  message: `Each ${attr.label} item must be a valid record ID`
2093
2358
  });
2094
- let arraySchema = import_zod3.z.array(uuidSchema);
2359
+ let arraySchema = import_zod4.z.array(uuidSchema);
2095
2360
  if (attr.minItems !== void 0) {
2096
2361
  arraySchema = arraySchema.min(
2097
2362
  attr.minItems,
@@ -2113,7 +2378,7 @@ function createRelationValidator(attr) {
2113
2378
  return createSingleRelationValidator(attr);
2114
2379
  }
2115
2380
  function createRatingValidator(attr) {
2116
- let schema = import_zod3.z.number().int().min(0);
2381
+ let schema = import_zod4.z.number().int().min(0);
2117
2382
  if (attr.max !== void 0) {
2118
2383
  schema = schema.max(attr.max, `${attr.label} must be at most ${attr.max}`);
2119
2384
  }
@@ -2152,7 +2417,7 @@ function createAttributeValidator(attr) {
2152
2417
  case "rating":
2153
2418
  return createRatingValidator(attr);
2154
2419
  default:
2155
- return import_zod3.z.unknown();
2420
+ return import_zod4.z.unknown();
2156
2421
  }
2157
2422
  }
2158
2423
  function createObjectValidator(objectDef) {
@@ -2164,7 +2429,7 @@ function createObjectValidator(objectDef) {
2164
2429
  }
2165
2430
  shape[attr.name] = validator;
2166
2431
  }
2167
- return import_zod3.z.object(shape);
2432
+ return import_zod4.z.object(shape);
2168
2433
  }
2169
2434
  function validateObject(objectDef, data) {
2170
2435
  const validator = createObjectValidator(objectDef);
@@ -2177,7 +2442,7 @@ function validateObject(objectDef, data) {
2177
2442
  }
2178
2443
  return {
2179
2444
  success: false,
2180
- errors: result.error.errors.map((err) => ({
2445
+ errors: result.error.issues.map((err) => ({
2181
2446
  path: err.path.map(String),
2182
2447
  message: err.message
2183
2448
  }))
@@ -2198,7 +2463,7 @@ function createDraftValidator(objectDef) {
2198
2463
  const validator = createAttributeValidator(attr).optional();
2199
2464
  shape[attr.name] = validator;
2200
2465
  }
2201
- return import_zod3.z.object(shape);
2466
+ return import_zod4.z.object(shape);
2202
2467
  }
2203
2468
  function validateDraft(objectDef, data) {
2204
2469
  const validator = createDraftValidator(objectDef);
@@ -2211,7 +2476,7 @@ function validateDraft(objectDef, data) {
2211
2476
  }
2212
2477
  return {
2213
2478
  success: false,
2214
- errors: result.error.errors.map((err) => ({
2479
+ errors: result.error.issues.map((err) => ({
2215
2480
  path: err.path.map(String),
2216
2481
  message: err.message
2217
2482
  }))
@@ -4683,9 +4948,6 @@ var ViewService = class {
4683
4948
  `Cannot create view "${input.name}": a system view with this name already exists`
4684
4949
  );
4685
4950
  }
4686
- if (!input.tabs || input.tabs.length === 0) {
4687
- throw new Error("View must have at least one tab");
4688
- }
4689
4951
  const dbView = await this.adapter.views.create({
4690
4952
  tenantId,
4691
4953
  objectName: input.objectName,
@@ -4693,7 +4955,7 @@ var ViewService = class {
4693
4955
  label: input.label,
4694
4956
  description: input.description,
4695
4957
  icon: input.icon,
4696
- tabs: input.tabs,
4958
+ tabs: input.tabs ?? [],
4697
4959
  default: input.default ?? false,
4698
4960
  system: false,
4699
4961
  // Custom views are never system
@@ -4716,9 +4978,6 @@ var ViewService = class {
4716
4978
  if (dbView.system) {
4717
4979
  throw new Error("Cannot modify system views. System views are protected.");
4718
4980
  }
4719
- if (input.tabs && input.tabs.length === 0) {
4720
- throw new Error("View must have at least one tab");
4721
- }
4722
4981
  const updated = await this.adapter.views.update(viewId, {
4723
4982
  label: input.label,
4724
4983
  description: input.description,
@@ -5149,6 +5408,7 @@ var NoopGeocodingAdapter = class {
5149
5408
  AuditService,
5150
5409
  DEFAULT_LABEL_FALLBACK,
5151
5410
  FileService,
5411
+ FlowService,
5152
5412
  GeocodingService,
5153
5413
  GlobalSearchService,
5154
5414
  NoopGeocodingAdapter,