@proteos/sdk 0.51.1 → 0.53.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/meta/types.ts CHANGED
@@ -1,6 +1,12 @@
1
1
  import { z } from 'zod'
2
2
  import type { AuditFields, ListOptions } from '../types/common.js'
3
3
  import { AuditFieldsSchema } from '../types/common.js'
4
+ import {
5
+ type LayoutElement,
6
+ LayoutElementSchema,
7
+ type LayoutTab,
8
+ LayoutTabSchema,
9
+ } from './layout/elements.js'
4
10
  import { type PageLayout, PageLayoutSchema } from './layout/page-layout.js'
5
11
 
6
12
  export type { PageLayout } from './layout/page-layout.js'
@@ -42,6 +48,7 @@ export type AttributeType =
42
48
  | 'currency'
43
49
  | 'knowledge-text'
44
50
  | 'file'
51
+ | 'contact-address'
45
52
 
46
53
  /**
47
54
  * Attribute-level permissions: restricting a FIELD rather than a record — a
@@ -281,6 +288,32 @@ export const CurrencyAttributeMetaSchema = z.object({
281
288
  allowed_currency_codes: z.array(z.string()).optional(),
282
289
  })
283
290
 
291
+ /**
292
+ * Which endpoint a `contact-address` attribute holds. The record-capable
293
+ * subset of the conversation contact-address kinds — what a human types.
294
+ */
295
+ export type ContactAddressAttributeKind = 'email' | 'phone' | 'linkedin_public_identifier'
296
+
297
+ /**
298
+ * Metadata for a `contact-address`-typed attribute: ONE canonical reachable
299
+ * address of the person the record represents. The stored value is a plain
300
+ * string canonicalized on write (lowercased email, E.164 phone with a leading
301
+ * `+`, LinkedIn public identifier — a pasted profile URL is reduced to its
302
+ * `/in/<slug>`; displayed as https://www.linkedin.com/in/<slug>; LinkedIn
303
+ * profile ids such as ACoAA… are refused — the platform learns them itself).
304
+ * Records carrying such values bind to exactly one conversation contact;
305
+ * `kind` is REQUIRED. Mirror of the Go `metamodel.ContactAddressAttributeMeta`.
306
+ */
307
+ export interface ContactAddressAttributeMeta {
308
+ kind: ContactAddressAttributeKind
309
+ description?: string
310
+ }
311
+
312
+ export const ContactAddressAttributeMetaSchema = z.object({
313
+ kind: z.enum(['email', 'phone', 'linkedin_public_identifier']),
314
+ description: z.string().optional(),
315
+ })
316
+
284
317
  /**
285
318
  * The value of a `knowledge-text`-typed attribute: a reference to the
286
319
  * knowledge node (knowledge-service) that owns the text body. The record
@@ -348,6 +381,7 @@ export type AttributeMeta =
348
381
  | CurrencyAttributeMeta
349
382
  | KnowledgeTextAttributeMeta
350
383
  | FileAttributeMeta
384
+ | ContactAddressAttributeMeta
351
385
 
352
386
  /**
353
387
  * Entity attribute definition. Mirrors `model.Attribute` in the Go SDK.
@@ -368,6 +402,13 @@ export interface Attribute {
368
402
  * Mirrors `IsPlatformManaged` in the Go `metamodel.Attribute`.
369
403
  */
370
404
  is_platform_managed?: boolean
405
+ /**
406
+ * Server-stamped back-reference to the entity extension that contributes
407
+ * this attribute to its host entity. Present only on a host's merged
408
+ * attribute list; ignored (stripped and re-derived) on writes. Mirrors
409
+ * `ExtensionKey` in the Go `metamodel.Attribute`.
410
+ */
411
+ extension_key?: string
371
412
  /**
372
413
  * Attribute-level permissions. Absent means unrestricted (today's behaviour).
373
414
  * Platform-managed attributes cannot carry restrictions.
@@ -485,6 +526,7 @@ export const AttributeSchema = z.object({
485
526
  is_nullable: z.boolean().optional(),
486
527
  is_unique: z.boolean(),
487
528
  is_read_only: z.boolean().optional(),
529
+ extension_key: z.string().optional(),
488
530
  restrictions: AttributeRestrictionsSchema.optional(),
489
531
  default_value: z.unknown().optional(),
490
532
  meta: z.unknown().optional(),
@@ -558,6 +600,18 @@ export function parseFileMeta(attr: Attribute): FileAttributeMeta | null {
558
600
  return parsed.success ? parsed.data : {}
559
601
  }
560
602
 
603
+ /**
604
+ * Returns the typed `ContactAddressAttributeMeta` when `attr` is a
605
+ * contact-address attribute with a valid kind; null otherwise. Unlike the
606
+ * `{}`-defaulting parsers, `kind` is required — an attribute without one
607
+ * cannot be canonicalized, so it resolves to null (shape of parseRelationMeta).
608
+ */
609
+ export function parseContactAddressMeta(attr: Attribute): ContactAddressAttributeMeta | null {
610
+ if (attr.type !== 'contact-address') return null
611
+ const parsed = ContactAddressAttributeMetaSchema.safeParse(attr.meta)
612
+ return parsed.success ? parsed.data : null
613
+ }
614
+
561
615
  /**
562
616
  * A single operation a resource may be publicly exposed for. Independent set
563
617
  * (not a level): a resource can be public for `write` without `read`. Only
@@ -571,6 +625,27 @@ export const PublicAccessOperationSchema = z.enum(['read', 'write', 'delete'])
571
625
  * Entity definition.
572
626
  * Note: Entity uses `slug` as its primary identifier, not `id`.
573
627
  */
628
+ /**
629
+ * What happens when a record's contact-address value already belongs to a
630
+ * contact linked to ANOTHER record of the same entity: `reject` fails the
631
+ * write (409 `record_duplicate`); `flag` (default) accepts it and raises a
632
+ * record duplicate pair for review.
633
+ */
634
+ export type ContactBindingDuplicatePolicy = 'reject' | 'flag'
635
+
636
+ /**
637
+ * The entity-level contact-binding setting — meaningful only for entities
638
+ * with `contact-address` attributes; absent on the wire means `flag`. Mirror
639
+ * of the Go `metamodel.ContactBinding`.
640
+ */
641
+ export interface EntityContactBinding {
642
+ duplicate_policy: ContactBindingDuplicatePolicy
643
+ }
644
+
645
+ export const EntityContactBindingSchema = z.object({
646
+ duplicate_policy: z.enum(['reject', 'flag']),
647
+ })
648
+
574
649
  export interface Entity extends AuditFields {
575
650
  slug: string
576
651
  name: string
@@ -584,6 +659,11 @@ export interface Entity extends AuditFields {
584
659
  * (default).
585
660
  */
586
661
  public_record_access: PublicAccessOperation[]
662
+ /**
663
+ * Contact-binding setting (see `EntityContactBinding`). Optional: a Go
664
+ * build that predates the setting omits it, which means `flag`.
665
+ */
666
+ contact_binding?: EntityContactBinding
587
667
  module_slug: string
588
668
  /**
589
669
  * Liquid template that renders a human-readable title for an instance
@@ -606,6 +686,7 @@ export const EntitySchema = AuditFieldsSchema.extend({
606
686
  // Default keeps older API responses (pre-`public_record_access` rollout)
607
687
  // parsing cleanly.
608
688
  public_record_access: z.array(PublicAccessOperationSchema).default([]),
689
+ contact_binding: EntityContactBindingSchema.optional(),
609
690
  module_slug: z.string(),
610
691
  // Default keeps older API responses (pre-`title_template` rollout) parsing
611
692
  // cleanly — the field is non-optional in the TS surface but tolerant on
@@ -648,6 +729,10 @@ export interface CreateEntityRequest {
648
729
  * the field resets it to private.
649
730
  */
650
731
  public_record_access?: PublicAccessOperation[]
732
+ /**
733
+ * Contact-binding setting; full-replacement on upsert (omitted = `flag`).
734
+ */
735
+ contact_binding?: EntityContactBinding
651
736
  module_slug: string
652
737
  description: string
653
738
  title_template?: string
@@ -661,6 +746,7 @@ export interface UpdateEntityRequest {
661
746
  name?: string
662
747
  is_remote?: boolean
663
748
  public_record_access?: PublicAccessOperation[]
749
+ contact_binding?: EntityContactBinding
664
750
  module_slug?: string
665
751
  description?: string
666
752
  title_template?: string
@@ -882,6 +968,12 @@ export interface Column {
882
968
  attribute: string
883
969
  label: string
884
970
  width: number
971
+ /**
972
+ * Server-stamped back-reference to the list extension that contributes this
973
+ * column to its host list. Present only on a host's merged column list;
974
+ * ignored (stripped and re-derived) on writes.
975
+ */
976
+ extension_key?: string
885
977
  }
886
978
 
887
979
  /**
@@ -948,6 +1040,8 @@ export interface PageAction {
948
1040
  params?: Record<string, string>
949
1041
  inputs?: Record<string, string>
950
1042
  skip_confirmation?: boolean
1043
+ /** List-extension stamp on a toolbar action a list extension appended to its host list. */
1044
+ extension_key?: string
951
1045
  }
952
1046
 
953
1047
  export const PageActionSchema = z.object({
@@ -959,6 +1053,7 @@ export const PageActionSchema = z.object({
959
1053
  params: z.record(z.string()).optional(),
960
1054
  inputs: z.record(z.string()).optional(),
961
1055
  skip_confirmation: z.boolean().optional(),
1056
+ extension_key: z.string().optional(),
962
1057
  })
963
1058
 
964
1059
  /**
@@ -1002,6 +1097,7 @@ export const ColumnSchema = z.object({
1002
1097
  attribute: z.string(),
1003
1098
  label: z.string(),
1004
1099
  width: z.number(),
1100
+ extension_key: z.string().optional(),
1005
1101
  })
1006
1102
 
1007
1103
  export const SortConfigSchema = z.object({
@@ -1250,6 +1346,7 @@ export type MenuItemType = (typeof MenuItemType)[keyof typeof MenuItemType]
1250
1346
  * Menu item definition. Matches the backend JSON shape for nested menus.
1251
1347
  */
1252
1348
  export interface MenuItem {
1349
+ /** Stable within the menu; the menu's extension API (menu-configuration extensions anchor on it). */
1253
1350
  id: string
1254
1351
  order: number
1255
1352
  label: string
@@ -1257,6 +1354,12 @@ export interface MenuItem {
1257
1354
  icon: string
1258
1355
  reference?: string
1259
1356
  children: MenuItem[] | null
1357
+ /** Server stamp: the item was contributed by this menu-configuration extension. Never authored. */
1358
+ extension_key?: string
1359
+ /** Server stamp: a `remove` tombstone — consumers skip the item. Never authored. */
1360
+ is_hidden?: boolean
1361
+ /** Server stamp: the host's own item this stamped item displaced (`replace` / `remove`). Never authored. */
1362
+ replaced_item?: MenuItem
1260
1363
  }
1261
1364
 
1262
1365
  /**
@@ -1280,6 +1383,9 @@ export const MenuItemSchema = z.lazy(() =>
1280
1383
  icon: z.string(),
1281
1384
  reference: z.string().optional(),
1282
1385
  children: z.array(MenuItemSchema).nullable(),
1386
+ extension_key: z.string().optional(),
1387
+ is_hidden: z.boolean().optional(),
1388
+ replaced_item: z.lazy(() => MenuItemSchema).optional(),
1283
1389
  }),
1284
1390
  ) as unknown as z.ZodType<MenuItem>
1285
1391
 
@@ -1325,6 +1431,370 @@ export interface UpdateMenuConfigurationRequest {
1325
1431
  is_default?: boolean
1326
1432
  }
1327
1433
 
1434
+ // ============================================================================
1435
+ // EntityExtension Types
1436
+ // ============================================================================
1437
+
1438
+ /**
1439
+ * EntityExtension — attributes contributed to ONE existing host entity by a
1440
+ * resource that does not own it (typically a second module). The host's
1441
+ * `attributes` are the materialized merge: its own attributes plus every
1442
+ * extension's, each stamped with `extension_key`. The row itself stores the
1443
+ * author's list unstamped. `key` is the identity; `entity_slug` is immutable
1444
+ * after create (delete and recreate to re-host).
1445
+ */
1446
+ export interface EntityExtension extends AuditFields {
1447
+ key: string
1448
+ org_id: string
1449
+ name: string
1450
+ description: string
1451
+ /** The host entity the attributes are merged into. */
1452
+ entity_slug: string
1453
+ module_slug: string
1454
+ /** The contributed definitions, exactly as authored (no `extension_key`). */
1455
+ attributes: Attribute[]
1456
+ }
1457
+
1458
+ export const EntityExtensionSchema = AuditFieldsSchema.extend({
1459
+ key: z.string(),
1460
+ org_id: z.string(),
1461
+ name: z.string(),
1462
+ description: z.string(),
1463
+ entity_slug: z.string(),
1464
+ module_slug: z.string(),
1465
+ attributes: z.array(AttributeSchema),
1466
+ })
1467
+
1468
+ export interface ListEntityExtensionsOptions extends MetaListOptions {
1469
+ key?: string
1470
+ name?: string
1471
+ entity_slug?: string
1472
+ module_slug?: string
1473
+ }
1474
+
1475
+ /**
1476
+ * Request to create an entity extension: at least one attribute, no platform
1477
+ * attribute names, no `extension_key` (the server stamps it on the host).
1478
+ */
1479
+ export interface CreateEntityExtensionRequest {
1480
+ key: string
1481
+ name?: string
1482
+ description?: string
1483
+ entity_slug: string
1484
+ module_slug?: string
1485
+ attributes: Attribute[]
1486
+ }
1487
+
1488
+ /**
1489
+ * Partial update. `attributes`, when present, replaces the whole contributed
1490
+ * list. `entity_slug` is immutable — delete and recreate to re-host.
1491
+ */
1492
+ export interface UpdateEntityExtensionRequest {
1493
+ name?: string
1494
+ description?: string
1495
+ module_slug?: string
1496
+ attributes?: Attribute[]
1497
+ }
1498
+
1499
+ // ============================================================================
1500
+ // PageExtension Types
1501
+ // ============================================================================
1502
+
1503
+ /**
1504
+ * Where a placement's block goes relative to its anchor. `first` / `last`
1505
+ * mean "inside this container", `before` / `after` mean "next to this node"
1506
+ * (a sibling of the same kind: element next to element, tab next to tab).
1507
+ */
1508
+ export type ExtensionPosition = 'before' | 'after' | 'first' | 'last'
1509
+
1510
+ export const ExtensionPositionSchema = z.enum(['before', 'after', 'first', 'last'])
1511
+
1512
+ /**
1513
+ * Virtual anchors naming the layout roots (`first` / `last` only). Dots keep
1514
+ * them out of the kebab-case authored-id namespace.
1515
+ */
1516
+ export const PAGE_EXTENSION_ANCHOR_MAIN = 'layout.main'
1517
+ export const PAGE_EXTENSION_ANCHOR_SIDE_PANEL = 'layout.side_panel'
1518
+
1519
+ /**
1520
+ * One anchored block: the anchor (an element id, a tab id, or a virtual root
1521
+ * anchor) in the host's OWN layout, a position, and the payload. Exactly one
1522
+ * of `elements` / `tabs` is set; which one is right follows from the anchor —
1523
+ * a tabs element (`first` / `last`) or a tab id (`before` / `after`) takes
1524
+ * `tabs`, everything else takes `elements`. The payload lands as ONE
1525
+ * contiguous run in author order. Every element and tab needs an authored id.
1526
+ */
1527
+ export interface PageExtensionPlacement {
1528
+ anchor_id: string
1529
+ position: ExtensionPosition
1530
+ elements?: LayoutElement[]
1531
+ tabs?: LayoutTab[]
1532
+ }
1533
+
1534
+ export const PageExtensionPlacementSchema = z.object({
1535
+ anchor_id: z.string().min(1),
1536
+ position: ExtensionPositionSchema,
1537
+ elements: z.array(LayoutElementSchema).optional(),
1538
+ tabs: z.array(LayoutTabSchema).optional(),
1539
+ })
1540
+
1541
+ /**
1542
+ * PageExtension — anchored layout blocks contributed to ONE existing host page
1543
+ * by a resource that does not own it (typically a second module). The host's
1544
+ * `layout` is the materialized merge: its own tree plus every extension's
1545
+ * placements, each contributed element and tab stamped with `extension_key`.
1546
+ * The row itself stores the author's placements unstamped. `key` is the
1547
+ * identity; `page_slug` is immutable after create (delete and recreate to
1548
+ * re-host).
1549
+ */
1550
+ export interface PageExtension extends AuditFields {
1551
+ key: string
1552
+ org_id: string
1553
+ name: string
1554
+ description: string
1555
+ /** The host page the placements are merged into. */
1556
+ page_slug: string
1557
+ module_slug: string
1558
+ /** The contributed blocks, exactly as authored (no `extension_key`). */
1559
+ placements: PageExtensionPlacement[]
1560
+ }
1561
+
1562
+ export const PageExtensionSchema = AuditFieldsSchema.extend({
1563
+ key: z.string(),
1564
+ org_id: z.string(),
1565
+ name: z.string(),
1566
+ description: z.string(),
1567
+ page_slug: z.string(),
1568
+ module_slug: z.string(),
1569
+ placements: z.array(PageExtensionPlacementSchema),
1570
+ })
1571
+
1572
+ export interface ListPageExtensionsOptions extends MetaListOptions {
1573
+ key?: string
1574
+ name?: string
1575
+ page_slug?: string
1576
+ module_slug?: string
1577
+ }
1578
+
1579
+ /**
1580
+ * Request to create a page extension: at least one placement, an authored id
1581
+ * on every contributed element and tab, no `extension_key` (the server stamps
1582
+ * it on the host).
1583
+ */
1584
+ export interface CreatePageExtensionRequest {
1585
+ key: string
1586
+ name?: string
1587
+ description?: string
1588
+ page_slug: string
1589
+ module_slug?: string
1590
+ placements: PageExtensionPlacement[]
1591
+ }
1592
+
1593
+ /**
1594
+ * Partial update. `placements`, when present, replaces the whole contributed
1595
+ * list. `page_slug` is immutable — delete and recreate to re-host.
1596
+ */
1597
+ export interface UpdatePageExtensionRequest {
1598
+ name?: string
1599
+ description?: string
1600
+ module_slug?: string
1601
+ placements?: PageExtensionPlacement[]
1602
+ }
1603
+
1604
+ // ============================================================================
1605
+ // MenuConfigurationExtension Types
1606
+ // ============================================================================
1607
+
1608
+ /**
1609
+ * Where a menu placement's block goes relative to its anchor. The four insert
1610
+ * positions are the shared `ExtensionPosition`; `replace` swaps the anchor
1611
+ * (whole subtree) for the block, `remove` hides it. Both keep the host's
1612
+ * original under `replaced_item` on the materialized tree.
1613
+ */
1614
+ export type MenuConfigurationExtensionPosition = ExtensionPosition | 'replace' | 'remove'
1615
+
1616
+ export const MenuConfigurationExtensionPositionSchema = z.enum([
1617
+ 'before',
1618
+ 'after',
1619
+ 'first',
1620
+ 'last',
1621
+ 'replace',
1622
+ 'remove',
1623
+ ])
1624
+
1625
+ /** Virtual anchor naming the menu's root item list (`first` / `last` only). */
1626
+ export const MENU_CONFIGURATION_EXTENSION_ANCHOR_ITEMS = 'menu.items'
1627
+
1628
+ /**
1629
+ * One anchored block: the anchor (an item id in the host's OWN tree, or the
1630
+ * virtual root `menu.items`), a position, and the contributed items (one
1631
+ * contiguous run in author order). `remove` carries no items; every other
1632
+ * position needs at least one. `first` / `last` on an item go into its
1633
+ * children (groups only). Every contributed item needs an authored id.
1634
+ */
1635
+ export interface MenuConfigurationExtensionPlacement {
1636
+ anchor_id: string
1637
+ position: MenuConfigurationExtensionPosition
1638
+ items?: MenuItem[]
1639
+ }
1640
+
1641
+ export const MenuConfigurationExtensionPlacementSchema = z.object({
1642
+ anchor_id: z.string().min(1),
1643
+ position: MenuConfigurationExtensionPositionSchema,
1644
+ items: z.array(MenuItemSchema).optional(),
1645
+ })
1646
+
1647
+ /**
1648
+ * MenuConfigurationExtension — items contributed to ONE existing host menu
1649
+ * configuration by a resource that does not own it (typically a second
1650
+ * module). The host's `items` are the materialized merge: its own tree plus
1651
+ * every extension's placements, each contributed item stamped with
1652
+ * `extension_key` (a replaced / removed host item kept under `replaced_item`).
1653
+ * The row itself stores the author's placements unstamped. `key` is the
1654
+ * identity; `menu_slug` is immutable after create (delete and recreate to
1655
+ * re-host).
1656
+ */
1657
+ export interface MenuConfigurationExtension extends AuditFields {
1658
+ key: string
1659
+ org_id: string
1660
+ name: string
1661
+ description: string
1662
+ /** The host menu configuration the placements are merged into. */
1663
+ menu_slug: string
1664
+ module_slug: string
1665
+ /** The contributed blocks, exactly as authored (no `extension_key`). */
1666
+ placements: MenuConfigurationExtensionPlacement[]
1667
+ }
1668
+
1669
+ export const MenuConfigurationExtensionSchema = AuditFieldsSchema.extend({
1670
+ key: z.string(),
1671
+ org_id: z.string(),
1672
+ name: z.string(),
1673
+ description: z.string(),
1674
+ menu_slug: z.string(),
1675
+ module_slug: z.string(),
1676
+ placements: z.array(MenuConfigurationExtensionPlacementSchema),
1677
+ })
1678
+
1679
+ export interface ListMenuConfigurationExtensionsOptions extends MetaListOptions {
1680
+ key?: string
1681
+ name?: string
1682
+ menu_slug?: string
1683
+ module_slug?: string
1684
+ }
1685
+
1686
+ /**
1687
+ * Request to create a menu-configuration extension: at least one placement,
1688
+ * an authored id on every contributed item, no `extension_key` (the server
1689
+ * stamps it on the host).
1690
+ */
1691
+ export interface CreateMenuConfigurationExtensionRequest {
1692
+ key: string
1693
+ name?: string
1694
+ description?: string
1695
+ menu_slug: string
1696
+ module_slug?: string
1697
+ placements: MenuConfigurationExtensionPlacement[]
1698
+ }
1699
+
1700
+ /**
1701
+ * Partial update. `placements`, when present, replaces the whole contributed
1702
+ * list. `menu_slug` is immutable — delete and recreate to re-host.
1703
+ */
1704
+ export interface UpdateMenuConfigurationExtensionRequest {
1705
+ name?: string
1706
+ description?: string
1707
+ module_slug?: string
1708
+ placements?: MenuConfigurationExtensionPlacement[]
1709
+ }
1710
+
1711
+ // ============================================================================
1712
+ // ListExtension Types
1713
+ // ============================================================================
1714
+
1715
+ /**
1716
+ * One anchored run of columns. `anchor_attribute` names a column of the host's
1717
+ * OWN column list by its attribute path (a column's identity); required for
1718
+ * `before` / `after`, must be empty for `first` / `last` (the ends of the
1719
+ * list). The columns land as one contiguous run in author order.
1720
+ */
1721
+ export interface ListExtensionColumnPlacement {
1722
+ anchor_attribute?: string
1723
+ position: ExtensionPosition
1724
+ columns: Column[]
1725
+ }
1726
+
1727
+ export const ListExtensionColumnPlacementSchema = z.object({
1728
+ anchor_attribute: z.string().optional(),
1729
+ position: ExtensionPositionSchema,
1730
+ columns: z.array(ColumnSchema).min(1),
1731
+ })
1732
+
1733
+ /**
1734
+ * ListExtension — columns and toolbar actions contributed to ONE existing host
1735
+ * list by a resource that does not own it. The host's `columns` / `actions`
1736
+ * are the materialized merge, each contributed one stamped `extension_key`;
1737
+ * the row stores the author's payload unstamped. `key` is the identity;
1738
+ * `list_slug` is immutable after create. Sorting, filters and selection mode
1739
+ * stay the owner's.
1740
+ */
1741
+ export interface ListExtension extends AuditFields {
1742
+ key: string
1743
+ org_id: string
1744
+ name: string
1745
+ description: string
1746
+ /** The host list the columns and actions are merged into. */
1747
+ list_slug: string
1748
+ module_slug: string
1749
+ columns: ListExtensionColumnPlacement[]
1750
+ /** Appended after the host's own toolbar actions (no anchor). */
1751
+ actions: PageAction[]
1752
+ }
1753
+
1754
+ export const ListExtensionSchema = AuditFieldsSchema.extend({
1755
+ key: z.string(),
1756
+ org_id: z.string(),
1757
+ name: z.string(),
1758
+ description: z.string(),
1759
+ list_slug: z.string(),
1760
+ module_slug: z.string(),
1761
+ columns: z.array(ListExtensionColumnPlacementSchema),
1762
+ actions: z.array(PageActionSchema),
1763
+ })
1764
+
1765
+ export interface ListListExtensionsOptions extends MetaListOptions {
1766
+ key?: string
1767
+ name?: string
1768
+ list_slug?: string
1769
+ module_slug?: string
1770
+ }
1771
+
1772
+ /**
1773
+ * Request to create a list extension: at least one column placement or
1774
+ * action, no `extension_key` (the server stamps it on the host).
1775
+ */
1776
+ export interface CreateListExtensionRequest {
1777
+ key: string
1778
+ name?: string
1779
+ description?: string
1780
+ list_slug: string
1781
+ module_slug?: string
1782
+ columns?: ListExtensionColumnPlacement[]
1783
+ actions?: PageAction[]
1784
+ }
1785
+
1786
+ /**
1787
+ * Partial update. `columns` / `actions`, when present, each replace their
1788
+ * whole list. `list_slug` is immutable — delete and recreate to re-host.
1789
+ */
1790
+ export interface UpdateListExtensionRequest {
1791
+ name?: string
1792
+ description?: string
1793
+ module_slug?: string
1794
+ columns?: ListExtensionColumnPlacement[]
1795
+ actions?: PageAction[]
1796
+ }
1797
+
1328
1798
  // ============================================================================
1329
1799
  // AppConfiguration Types
1330
1800
  // ============================================================================