busabase-sdk 0.10.0 → 0.10.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.
Files changed (3) hide show
  1. package/dist/index.d.ts +4352 -11219
  2. package/dist/index.js +161 -229
  3. package/package.json +4 -4
package/dist/index.js CHANGED
@@ -220,6 +220,15 @@ var restoreFieldChangeRequestInputSchema = z.object({
220
220
  message: z.string().optional(),
221
221
  submittedBy: z.string().optional().default("local-editor")
222
222
  });
223
+ var withBaseId = { baseId: z.string().min(1) };
224
+ var fieldChangeRequestInputSchema = z.discriminatedUnion("operation", [
225
+ createFieldChangeRequestInputSchema.extend({ operation: z.literal("create"), ...withBaseId }),
226
+ updateFieldChangeRequestInputSchema.extend({ operation: z.literal("update"), ...withBaseId }),
227
+ deleteFieldChangeRequestInputSchema.extend({ operation: z.literal("delete"), ...withBaseId }),
228
+ convertFieldChangeRequestInputSchema.extend({ operation: z.literal("convert"), ...withBaseId }),
229
+ reorderFieldsChangeRequestInputSchema.extend({ operation: z.literal("reorder"), ...withBaseId }),
230
+ restoreFieldChangeRequestInputSchema.extend({ operation: z.literal("restore"), ...withBaseId })
231
+ ]);
223
232
 
224
233
  // ../../packages/busabase-contract/src/domains/filetree/definition.ts
225
234
  var fileTreeOperations = (type) => [
@@ -521,7 +530,13 @@ var listNodesInputSchema = z.object({
521
530
  parentId: z.string().nullable().optional().describe("Node to start from. Omit or null to start from the space root."),
522
531
  depth: z.coerce.number().int().min(1).max(5).optional().describe(
523
532
  "How many levels beneath the start point to eagerly include (default 2 once either field is set). Capped at 5."
524
- )
533
+ ),
534
+ /**
535
+ * `active` (default) walks the live tree. `archived` returns the flat set of
536
+ * soft-archived nodes for the Trash view — no `parentId`/`depth` walk, since
537
+ * archived nodes are shown as a list, not a tree.
538
+ */
539
+ status: z.enum(["active", "archived"]).optional().default("active")
525
540
  }).optional();
526
541
  var isDescendantInputSchema = z.object({
527
542
  nodeId: z.string(),
@@ -850,6 +865,9 @@ var createCommentInputSchema = commentSubjectInputSchema.extend({
850
865
  var listInputSchema = z.object({
851
866
  limit: z.coerce.number().int().min(1).max(100).optional().default(50)
852
867
  }).optional().default({ limit: 50 });
868
+ var listByStatusInputSchema = z.object({
869
+ status: z.enum(["active", "archived"]).optional().default("active")
870
+ });
853
871
  var listChangeRequestsPagedInputSchema = z.object({
854
872
  limit: z.coerce.number().int().min(1).max(100).optional().default(50),
855
873
  /** Opaque base64 cursor (`createdAt|id`) for keyset pagination. */
@@ -1032,74 +1050,75 @@ var createFileTreeChangeRequestInputSchema = z.object({
1032
1050
  submittedBy: z.string().optional().default("local-producer"),
1033
1051
  operations: z.array(fileTreeFileOperationInputSchema).min(1)
1034
1052
  });
1035
- var makeFileTreeContract = (routeBase, tag) => {
1036
- const label = tag.endsWith("s") ? tag.slice(0, -1) : tag;
1037
- const basePath = `/${routeBase}`;
1038
- return {
1039
- list: oc.route({
1040
- method: "GET",
1041
- path: basePath,
1042
- tags: [tag],
1043
- summary: `List ${label} nodes`,
1044
- successDescription: `${label} nodes with their Asset-backed file trees.`
1045
- }).output(z.array(fileTreeNodeSchema)),
1046
- create: oc.route({
1047
- method: "POST",
1048
- path: basePath,
1049
- tags: [tag],
1050
- summary: `Create ${label} node`,
1051
- successDescription: `Review-first by default: a pending ChangeRequest proposing the ${label} node (\`materialized: false\`). Returns the materialized ${label} node instead (\`materialized: true\`) when \`autoMerge: true\` is passed.`
1052
- }).input(createFileTreeInputSchema).output(
1053
- z.union([
1054
- fileTreeNodeSchema.extend({ materialized: z.literal(true) }),
1055
- changeRequestSchema.extend({ materialized: z.literal(false) })
1056
- ])
1057
- ),
1058
- get: oc.route({
1059
- method: "GET",
1060
- path: `${basePath}/{nodeId}`,
1061
- tags: [tag],
1062
- summary: `Get ${label} node`,
1063
- successDescription: `${label} node detail and file tree.`
1064
- }).input(z.object({ nodeId: z.string() })).output(fileTreeNodeSchema),
1065
- listFiles: oc.route({
1066
- method: "GET",
1067
- path: `${basePath}/{nodeId}/files`,
1068
- tags: [tag],
1069
- summary: `List ${label} files`,
1070
- successDescription: `Asset-backed files mounted under the ${label} node.`
1071
- }).input(z.object({ nodeId: z.string() })).output(z.array(fileTreeFileSchema)),
1072
- readFile: oc.route({
1073
- method: "GET",
1074
- path: `${basePath}/{nodeId}/files/{+filePath}`,
1075
- tags: [tag],
1076
- summary: `Read ${label} file`,
1077
- successDescription: `${label} file content and content hash.`
1078
- }).input(z.object({ nodeId: z.string(), filePath: z.string() })).output(
1079
- z.object({
1080
- nodeId: z.string(),
1081
- path: z.string(),
1082
- encoding: z.enum(["utf8", "url"]),
1083
- content: z.string(),
1084
- mimeType: z.string(),
1085
- assetId: z.string(),
1086
- displayName: z.string().nullable(),
1087
- assetUrl: z.string().nullable(),
1088
- contentHash: z.string()
1089
- })
1090
- ),
1091
- createChangeRequest: oc.route({
1092
- method: "POST",
1093
- path: `${basePath}/{nodeId}/change-requests`,
1094
- tags: [tag, "Change Requests"],
1095
- summary: `Create ${label} change request`,
1096
- successDescription: `Created file-tree change request for a ${label} node.`
1097
- }).input(createFileTreeChangeRequestInputSchema.extend({ nodeId: z.string() })).output(changeRequestSchema)
1098
- };
1053
+ var FILE_TREE_NODE_TYPES = ["skill", "drive", "airapp"];
1054
+ var fileTreeNodeTypeSchema = z.enum(FILE_TREE_NODE_TYPES);
1055
+ var fileTreeRefSchema = z.object({
1056
+ nodeId: z.string(),
1057
+ type: fileTreeNodeTypeSchema.optional()
1058
+ });
1059
+ var fileTreeContract = {
1060
+ list: oc.route({
1061
+ method: "GET",
1062
+ path: "/file-trees",
1063
+ tags: ["File Trees"],
1064
+ summary: "List file-tree nodes",
1065
+ successDescription: "Skill, Drive, and AirApp nodes with their Asset-backed file trees. Pass `type` to narrow to one kind."
1066
+ }).input(z.object({ type: fileTreeNodeTypeSchema.optional() })).output(z.array(fileTreeNodeSchema)),
1067
+ create: oc.route({
1068
+ method: "POST",
1069
+ path: "/file-trees",
1070
+ tags: ["File Trees"],
1071
+ summary: "Create file-tree node",
1072
+ successDescription: "Review-first by default: a pending ChangeRequest proposing the node (`materialized: false`). Returns the materialized node instead (`materialized: true`) when `autoMerge: true` is passed."
1073
+ }).input(createFileTreeInputSchema.extend({ type: fileTreeNodeTypeSchema })).output(
1074
+ z.union([
1075
+ fileTreeNodeSchema.extend({ materialized: z.literal(true) }),
1076
+ changeRequestSchema.extend({ materialized: z.literal(false) })
1077
+ ])
1078
+ ),
1079
+ get: oc.route({
1080
+ method: "GET",
1081
+ path: "/file-trees/{nodeId}",
1082
+ tags: ["File Trees"],
1083
+ summary: "Get file-tree node",
1084
+ successDescription: "File-tree node detail and its file list."
1085
+ }).input(fileTreeRefSchema).output(fileTreeNodeSchema),
1086
+ listFiles: oc.route({
1087
+ method: "GET",
1088
+ path: "/file-trees/{nodeId}/files",
1089
+ tags: ["File Trees"],
1090
+ summary: "List file-tree files",
1091
+ successDescription: "Asset-backed files mounted under the node."
1092
+ }).input(fileTreeRefSchema).output(z.array(fileTreeFileSchema)),
1093
+ readFile: oc.route({
1094
+ method: "GET",
1095
+ path: "/file-trees/{nodeId}/files/{+filePath}",
1096
+ tags: ["File Trees"],
1097
+ summary: "Read file-tree file",
1098
+ successDescription: "File content and content hash."
1099
+ }).input(fileTreeRefSchema.extend({ filePath: z.string() })).output(
1100
+ z.object({
1101
+ nodeId: z.string(),
1102
+ path: z.string(),
1103
+ encoding: z.enum(["utf8", "url"]),
1104
+ content: z.string(),
1105
+ mimeType: z.string(),
1106
+ assetId: z.string(),
1107
+ displayName: z.string().nullable(),
1108
+ assetUrl: z.string().nullable(),
1109
+ contentHash: z.string()
1110
+ })
1111
+ ),
1112
+ createChangeRequest: oc.route({
1113
+ method: "POST",
1114
+ path: "/file-trees/{nodeId}/change-requests",
1115
+ tags: ["File Trees", "Change Requests"],
1116
+ summary: "Create file-tree change request",
1117
+ successDescription: "Created file-tree change request for the node."
1118
+ }).input(createFileTreeChangeRequestInputSchema.extend(fileTreeRefSchema.shape)).output(changeRequestSchema)
1099
1119
  };
1100
1120
 
1101
1121
  // ../../packages/busabase-contract/src/domains/airapp/contract.ts
1102
- var airappContract = makeFileTreeContract("airapps", "AirApps");
1103
1122
  var airAppRunLocalNodeInputSchema = z.object({
1104
1123
  nodeId: z.string(),
1105
1124
  /** Text files to mount into the sandbox workdir before installing, keyed by
@@ -1531,6 +1550,24 @@ var restoreViewInputSchema = z.object({
1531
1550
  message: z.string().optional().default("Restore view"),
1532
1551
  submittedBy: z.string().optional().default("local-producer")
1533
1552
  });
1553
+ var viewChangeRequestInputSchema = z.discriminatedUnion("operation", [
1554
+ createViewInputSchema.extend({
1555
+ operation: z.literal("create"),
1556
+ baseId: z.string().min(1).describe("Base the new view belongs to.")
1557
+ }),
1558
+ updateViewInputSchema.extend({
1559
+ operation: z.literal("update"),
1560
+ viewId: z.string().min(1)
1561
+ }),
1562
+ deleteViewInputSchema.extend({
1563
+ operation: z.literal("delete"),
1564
+ viewId: z.string().min(1)
1565
+ }),
1566
+ restoreViewInputSchema.extend({
1567
+ operation: z.literal("restore"),
1568
+ viewId: z.string().min(1)
1569
+ })
1570
+ ]);
1534
1571
 
1535
1572
  // ../../packages/busabase-contract/src/domains/base/contract/record-schemas.ts
1536
1573
  var recordSchema = z.object({
@@ -1564,21 +1601,21 @@ var listRecordsInputSchema = z.object({
1564
1601
  baseId: z.string().optional(),
1565
1602
  /** Opaque base64 cursor for keyset pagination (createdAt-keyed, or sort-keyed when `sort` is set). */
1566
1603
  cursor: z.string().optional(),
1604
+ /**
1605
+ * `active` (default) is the live table; `archived` is the Base's trash — the
1606
+ * same keyset pagination either way, which is why these are one endpoint
1607
+ * rather than a `/records/archived` twin.
1608
+ */
1609
+ status: z.enum(["active", "archived"]).optional().default("active"),
1567
1610
  /** View filters for server-side push-down (superset; client still narrows). */
1568
1611
  filters: z.array(listRecordsFilterSchema).optional(),
1569
1612
  /** View sort for server-side push-down (number/date fields only). */
1570
1613
  sort: listRecordsSortSchema.optional()
1571
- }).optional().default({ limit: 50 });
1614
+ }).optional().default({ limit: 50, status: "active" });
1572
1615
  var listRecordsResponseSchema = z.object({
1573
1616
  records: z.array(recordSchema),
1574
1617
  nextCursor: z.string().nullable()
1575
1618
  });
1576
- var listArchivedRecordsPagedInputSchema = z.object({
1577
- baseId: z.string(),
1578
- limit: z.coerce.number().int().min(1).max(100).optional().default(50),
1579
- /** Opaque base64 cursor (createdAt-keyed) for keyset pagination. */
1580
- cursor: z.string().optional()
1581
- });
1582
1619
  var countRecordsInputSchema = z.object({
1583
1620
  baseId: z.string().optional()
1584
1621
  }).optional().default({});
@@ -1633,6 +1670,16 @@ var restoreRecordInputSchema = z.object({
1633
1670
  message: z.string().optional(),
1634
1671
  submittedBy: z.string().optional().default("local-editor")
1635
1672
  });
1673
+ var withRecordId = { recordId: z.string().min(1) };
1674
+ var recordChangeRequestInputSchema = z.discriminatedUnion("operation", [
1675
+ reviseOperationInputSchema.extend({
1676
+ operation: z.literal("update"),
1677
+ autoMerge: z.boolean().optional(),
1678
+ ...withRecordId
1679
+ }),
1680
+ createDeleteChangeRequestInputSchema.extend({ operation: z.literal("delete"), ...withRecordId }),
1681
+ restoreRecordInputSchema.extend({ operation: z.literal("restore"), ...withRecordId })
1682
+ ]);
1636
1683
  var recordLinkSchema = z.object({
1637
1684
  id: z.string(),
1638
1685
  baseId: z.string(),
@@ -1652,22 +1699,15 @@ var baseContract = {
1652
1699
  path: "/bases",
1653
1700
  tags: ["Bases"],
1654
1701
  summary: "List Bases",
1655
- successDescription: "Flat list of developer-facing Bases."
1656
- }).output(z.array(baseSchema)),
1657
- listArchived: oc.route({
1658
- method: "GET",
1659
- path: "/bases/archived",
1660
- tags: ["Bases"],
1661
- summary: "List archived bases",
1662
- successDescription: "Bases that have been archived."
1663
- }).output(z.array(baseSchema)),
1702
+ successDescription: "Developer-facing Bases. `status=archived` returns the archived ones instead of the active ones."
1703
+ }).input(listByStatusInputSchema).output(z.array(baseSchema)),
1664
1704
  get: oc.route({
1665
1705
  method: "GET",
1666
1706
  path: "/bases/{baseId}",
1667
1707
  tags: ["Bases"],
1668
1708
  summary: "Get Base",
1669
- successDescription: "Single Base by id or slug."
1670
- }).input(z.object({ baseId: z.string() })).output(baseSchema.nullable()),
1709
+ successDescription: "Single Base by id or slug, or 404 when it does not exist or is not visible."
1710
+ }).input(z.object({ baseId: z.string() })).output(baseSchema),
1671
1711
  listDeletedFields: oc.route({
1672
1712
  method: "GET",
1673
1713
  path: "/bases/{baseId}/fields/deleted",
@@ -1679,30 +1719,9 @@ var baseContract = {
1679
1719
  method: "GET",
1680
1720
  path: "/bases/{baseId}/views",
1681
1721
  tags: ["Views"],
1682
- summary: "List active views for a Base",
1683
- successDescription: "Saved table views for a Base."
1684
- }).input(z.object({ baseId: z.string() })).output(z.array(viewSchema)),
1685
- listArchivedViews: oc.route({
1686
- method: "GET",
1687
- path: "/bases/{baseId}/views/archived",
1688
- tags: ["Views"],
1689
- summary: "List archived views for a Base",
1690
- successDescription: "Views that have been archived (soft-deleted) from a Base."
1691
- }).input(z.object({ baseId: z.string() })).output(z.array(viewSchema)),
1692
- listArchivedRecords: oc.route({
1693
- method: "GET",
1694
- path: "/bases/{baseId}/records/archived",
1695
- tags: ["Records"],
1696
- summary: "List archived records for a Base",
1697
- successDescription: "Records that have been archived (soft-deleted) from a Base."
1698
- }).input(z.object({ baseId: z.string() })).output(z.array(recordSchema)),
1699
- listArchivedRecordsPaged: oc.route({
1700
- method: "GET",
1701
- path: "/bases/{baseId}/records/archived/paged",
1702
- tags: ["Records"],
1703
- summary: "List archived records for a Base with keyset pagination",
1704
- successDescription: "A page of archived (soft-deleted) records plus an opaque nextCursor (null at the end)."
1705
- }).input(listArchivedRecordsPagedInputSchema).output(listRecordsResponseSchema),
1722
+ summary: "List views for a Base",
1723
+ successDescription: "Saved table views for a Base. `status=archived` returns the soft-deleted ones instead."
1724
+ }).input(listByStatusInputSchema.extend({ baseId: z.string() })).output(z.array(viewSchema)),
1706
1725
  create: oc.route({
1707
1726
  method: "POST",
1708
1727
  path: "/bases",
@@ -1741,34 +1760,13 @@ var baseContract = {
1741
1760
  summary: "Create Base field",
1742
1761
  successDescription: "Created Base field."
1743
1762
  }).input(createBaseFieldInputSchema.extend({ baseId: z.string() })).output(baseSchema),
1744
- createFieldChangeRequest: oc.route({
1763
+ fieldChangeRequest: oc.route({
1745
1764
  method: "POST",
1746
1765
  path: "/bases/{baseId}/fields/change-requests",
1747
1766
  tags: ["Bases", "Change Requests"],
1748
- summary: "Create Add Field change request",
1749
- successDescription: "Created change request that proposes a new field."
1750
- }).input(createFieldChangeRequestInputSchema.extend({ baseId: z.string() })).output(changeRequestSchema),
1751
- createViewChangeRequest: oc.route({
1752
- method: "POST",
1753
- path: "/bases/{baseId}/views/change-requests",
1754
- tags: ["Views", "Change Requests"],
1755
- summary: "Create View change request",
1756
- successDescription: "Created change request that proposes a new View."
1757
- }).input(createViewInputSchema.extend({ baseId: z.string() })).output(changeRequestSchema),
1758
- deleteFieldChangeRequest: oc.route({
1759
- method: "DELETE",
1760
- path: "/bases/{baseId}/fields/change-requests",
1761
- tags: ["Bases", "Change Requests"],
1762
- summary: "Create Delete Field change request",
1763
- successDescription: "Created change request that soft-deletes a field."
1764
- }).input(deleteFieldChangeRequestInputSchema.extend({ baseId: z.string() })).output(changeRequestSchema),
1765
- updateFieldChangeRequest: oc.route({
1766
- method: "PATCH",
1767
- path: "/bases/{baseId}/fields/change-requests",
1768
- tags: ["Bases", "Change Requests"],
1769
- summary: "Create Update Field change request",
1770
- successDescription: "Created change request that updates field metadata (name, required, options)."
1771
- }).input(updateFieldChangeRequestInputSchema.extend({ baseId: z.string() })).output(changeRequestSchema),
1767
+ summary: "Create field change request",
1768
+ successDescription: "Created change request proposing a field change. `operation` selects what to propose: `create`, `update`, `delete`, `convert` (change type), `reorder`, or `restore` (undo a soft delete)."
1769
+ }).input(fieldChangeRequestInputSchema).output(changeRequestSchema),
1772
1770
  previewFieldConversion: oc.route({
1773
1771
  method: "POST",
1774
1772
  path: "/bases/{baseId}/fields/convert/preview",
@@ -1776,20 +1774,6 @@ var baseContract = {
1776
1774
  summary: "Preview field type conversion",
1777
1775
  successDescription: "Dry-run statistics for converting a field to a different type."
1778
1776
  }).input(previewFieldConversionInputSchema.extend({ baseId: z.string() })).output(previewFieldConversionOutputSchema),
1779
- convertFieldChangeRequest: oc.route({
1780
- method: "POST",
1781
- path: "/bases/{baseId}/fields/convert/change-requests",
1782
- tags: ["Bases", "Change Requests"],
1783
- summary: "Create Convert Field change request",
1784
- successDescription: "Created change request that converts a field to a different type."
1785
- }).input(convertFieldChangeRequestInputSchema.extend({ baseId: z.string() })).output(changeRequestSchema),
1786
- reorderFieldsChangeRequest: oc.route({
1787
- method: "POST",
1788
- path: "/bases/{baseId}/fields/reorder/change-requests",
1789
- tags: ["Bases", "Change Requests"],
1790
- summary: "Reorder fields",
1791
- successDescription: "Created change request that reorders fields."
1792
- }).input(reorderFieldsChangeRequestInputSchema.extend({ baseId: z.string() })).output(changeRequestSchema),
1793
1777
  archiveChangeRequest: oc.route({
1794
1778
  method: "POST",
1795
1779
  path: "/bases/{baseId}/archive/change-requests",
@@ -1803,29 +1787,19 @@ var baseContract = {
1803
1787
  tags: ["Bases", "Change Requests"],
1804
1788
  summary: "Restore base",
1805
1789
  successDescription: "Created change request that restores an archived base."
1806
- }).input(restoreBaseInputSchema.extend({ baseId: z.string() })).output(changeRequestSchema),
1807
- restoreFieldChangeRequest: oc.route({
1808
- method: "POST",
1809
- path: "/bases/{baseId}/fields/restore/change-requests",
1810
- tags: ["Bases", "Change Requests"],
1811
- summary: "Restore deleted field",
1812
- successDescription: "Created change request that restores a soft-deleted field."
1813
- }).input(restoreFieldChangeRequestInputSchema.extend({ baseId: z.string() })).output(changeRequestSchema)
1790
+ }).input(restoreBaseInputSchema.extend({ baseId: z.string() })).output(changeRequestSchema)
1814
1791
  };
1815
1792
  var recordContract = {
1793
+ // One listing for records: always keyset-paginated, `baseId` always honoured,
1794
+ // `status` picking live rows or the trash. The old unpaginated `/records`
1795
+ // silently dropped `baseId` (its schema had no such field), so a caller
1796
+ // scoping to one Base quietly got the whole space back.
1816
1797
  list: oc.route({
1817
1798
  method: "GET",
1818
1799
  path: "/records",
1819
1800
  tags: ["Records"],
1820
1801
  summary: "List records",
1821
- successDescription: "Canonical records created from merged change requests."
1822
- }).input(listInputSchema).output(z.array(recordSchema)),
1823
- listPaged: oc.route({
1824
- method: "GET",
1825
- path: "/records/paged",
1826
- tags: ["Records"],
1827
- summary: "List records with keyset pagination",
1828
- successDescription: "A page of canonical records plus an opaque nextCursor (null at the end)."
1802
+ successDescription: "A page of canonical records plus an opaque nextCursor (null at the end). `status=archived` lists the Base's trash instead of its live rows."
1829
1803
  }).input(listRecordsInputSchema).output(listRecordsResponseSchema),
1830
1804
  count: oc.route({
1831
1805
  method: "GET",
@@ -1855,20 +1829,18 @@ var recordContract = {
1855
1829
  summary: "Get record by field value",
1856
1830
  successDescription: "Single canonical record whose field value exactly matches, or null when none does \u2014 a scoped point lookup (e.g. by a unique slug or path field), not a list."
1857
1831
  }).input(recordFieldGetInputSchema).output(recordSchema.nullable()),
1858
- updateChangeRequest: oc.route({
1859
- method: "PUT",
1860
- path: "/records/{recordId}/change-requests",
1861
- tags: ["Records", "Change Requests"],
1862
- summary: "Create record update change request",
1863
- successDescription: "Created change request that proposes updating a canonical record."
1864
- }).input(reviseOperationInputSchema.extend({ recordId: z.string() })).output(changeRequestSchema),
1865
- deleteChangeRequest: oc.route({
1866
- method: "DELETE",
1832
+ changeRequest: oc.route({
1833
+ method: "POST",
1867
1834
  path: "/records/{recordId}/change-requests",
1868
1835
  tags: ["Records", "Change Requests"],
1869
- summary: "Create record delete change request",
1870
- successDescription: "Created change request that proposes archiving or deleting a record."
1871
- }).input(createDeleteChangeRequestInputSchema.extend({ recordId: z.string() })).output(changeRequestSchema),
1836
+ summary: "Create record change request",
1837
+ successDescription: "Creates a record change request selected by `operation`. Updates auto-merge when the actor has write access unless `autoMerge: false`; delete and restore remain review-first."
1838
+ }).input(recordChangeRequestInputSchema).output(
1839
+ z.union([
1840
+ recordSchema.extend({ materialized: z.literal(true) }),
1841
+ changeRequestSchema.extend({ materialized: z.literal(false) })
1842
+ ])
1843
+ ),
1872
1844
  listChangeRequests: oc.route({
1873
1845
  method: "GET",
1874
1846
  path: "/records/{recordId}/change-requests",
@@ -1876,13 +1848,6 @@ var recordContract = {
1876
1848
  summary: "List record change request history",
1877
1849
  successDescription: "Change requests and operations connected to the canonical record."
1878
1850
  }).input(z.object({ recordId: z.string() })).output(z.array(changeRequestSchema)),
1879
- restoreChangeRequest: oc.route({
1880
- method: "POST",
1881
- path: "/records/{recordId}/restore/change-requests",
1882
- tags: ["Records", "Change Requests"],
1883
- summary: "Create record restore change request",
1884
- successDescription: "Created change request that restores an archived record."
1885
- }).input(restoreRecordInputSchema.extend({ recordId: z.string() })).output(changeRequestSchema),
1886
1851
  listLinks: oc.route({
1887
1852
  method: "GET",
1888
1853
  path: "/records/{recordId}/links",
@@ -1892,27 +1857,13 @@ var recordContract = {
1892
1857
  }).input(z.object({ recordId: z.string() })).output(z.array(recordLinkSchema))
1893
1858
  };
1894
1859
  var viewContract = {
1895
- updateChangeRequest: oc.route({
1896
- method: "PUT",
1897
- path: "/views/{viewId}/change-requests",
1898
- tags: ["Views", "Change Requests"],
1899
- summary: "Create View update change request",
1900
- successDescription: "Created change request that proposes updating a View."
1901
- }).input(updateViewInputSchema.extend({ viewId: z.string() })).output(changeRequestSchema),
1902
- deleteChangeRequest: oc.route({
1903
- method: "DELETE",
1904
- path: "/views/{viewId}/change-requests",
1905
- tags: ["Views", "Change Requests"],
1906
- summary: "Create View delete change request",
1907
- successDescription: "Created change request that proposes archiving a View."
1908
- }).input(deleteViewInputSchema.extend({ viewId: z.string() })).output(changeRequestSchema),
1909
- restoreChangeRequest: oc.route({
1860
+ changeRequest: oc.route({
1910
1861
  method: "POST",
1911
- path: "/views/{viewId}/restore/change-requests",
1862
+ path: "/views/change-requests",
1912
1863
  tags: ["Views", "Change Requests"],
1913
- summary: "Create View restore change request",
1914
- successDescription: "Created change request that restores an archived View."
1915
- }).input(restoreViewInputSchema.extend({ viewId: z.string() })).output(changeRequestSchema)
1864
+ summary: "Create view change request",
1865
+ successDescription: "Created change request proposing a view change. `operation` selects what to propose: `create` (addressed by `baseId`), or `update` / `delete` / `restore` (addressed by `viewId`)."
1866
+ }).input(viewChangeRequestInputSchema).output(changeRequestSchema)
1916
1867
  };
1917
1868
  var ReadDocLinesInputSchema = z.object({
1918
1869
  nodeId: z.string(),
@@ -1999,9 +1950,6 @@ var docContract = {
1999
1950
  successDescription: "Created a change request that proposes a new Doc body."
2000
1951
  }).input(createDocChangeRequestInputSchema.extend({ nodeId: z.string() })).output(changeRequestSchema)
2001
1952
  };
2002
-
2003
- // ../../packages/busabase-contract/src/domains/drive/contract.ts
2004
- var driveContract = makeFileTreeContract("drives", "Drives");
2005
1953
  var DumpTableSchema = z.enum([
2006
1954
  "nodes",
2007
1955
  /** Node-level access grants (permissions). Not secret — restore must keep them
@@ -2456,9 +2404,6 @@ var installContract = {
2456
2404
  successDescription: "Created counts plus the number of change requests left for review. Structure (folders, Bases, fields, views) is created immediately \u2014 a pending Base has no id to attach a view or record to; content (records, docs, skills, AirApps) lands as change requests unless `autoMerge` is set."
2457
2405
  }).input(InstallFromGithubDTOSchema).output(InstallResultVOSchema)
2458
2406
  };
2459
-
2460
- // ../../packages/busabase-contract/src/domains/skill/contract.ts
2461
- var skillContract = makeFileTreeContract("skills", "Skills");
2462
2407
  var VaultItemKeySchema = z.string().trim().min(1).max(128).regex(/^[A-Z_][A-Z0-9_]*$/, "Use uppercase letters, numbers, and underscores");
2463
2408
  var VaultItemValueSchema = z.string().max(8192);
2464
2409
  var VaultItemKindSchema = z.enum(["secret", "variable"]);
@@ -2895,13 +2840,6 @@ var busabaseContractRoutes = {
2895
2840
  summary: "Check whether a node is a descendant of another",
2896
2841
  successDescription: "Server-authoritative parentId-chain walk from nodeId up to potentialAncestorId. Used to gate cross-branch drag-and-drop drops in the sidebar, since the full tree is no longer guaranteed to be loaded client-side (depth-bounded lazy load) \u2014 a purely local walk could wrongly allow dropping a folder into its own unloaded descendant."
2897
2842
  }).input(isDescendantInputSchema).output(isDescendantOutputSchema),
2898
- listArchived: oc.route({
2899
- method: "GET",
2900
- path: "/nodes/archived",
2901
- tags: ["Nodes"],
2902
- summary: "List archived nodes",
2903
- successDescription: "Soft-archived folders, docs, and skills (for the Trash view)."
2904
- }).output(z.array(nodeSchema)),
2905
2843
  createChangeRequest: oc.route({
2906
2844
  method: "POST",
2907
2845
  path: "/nodes/change-requests",
@@ -3083,9 +3021,10 @@ var busabaseContractRoutes = {
3083
3021
  subscribe: oc.output(eventIterator(liveEventSchema))
3084
3022
  },
3085
3023
  bases: baseContract,
3086
- skills: skillContract,
3087
- drives: driveContract,
3088
- airapps: { ...airappContract, ...airappRuntimeContract },
3024
+ // Skills, Drives, and AirApps share one transport surface — they differ only
3025
+ // in seed files and entry file, which is a server-side config concern.
3026
+ fileTrees: fileTreeContract,
3027
+ airapps: airappRuntimeContract,
3089
3028
  files: fileContract,
3090
3029
  docs: docContract,
3091
3030
  folders: folderContract,
@@ -3096,18 +3035,13 @@ var busabaseContractRoutes = {
3096
3035
  dump: dumpContract,
3097
3036
  install: installContract,
3098
3037
  changeRequests: {
3038
+ // Always keyset-paginated — the unpaginated twin returned a bare array that
3039
+ // silently truncated at `limit` with no way to ask for the next page.
3099
3040
  list: oc.route({
3100
3041
  method: "GET",
3101
3042
  path: "/change-requests",
3102
3043
  tags: ["Change Requests"],
3103
3044
  summary: "List change requests",
3104
- successDescription: "Change requests waiting for review or ready to merge."
3105
- }).input(listInputSchema).output(z.array(changeRequestSchema)),
3106
- listPaged: oc.route({
3107
- method: "GET",
3108
- path: "/change-requests/paged",
3109
- tags: ["Change Requests"],
3110
- summary: "List change requests with keyset pagination",
3111
3045
  successDescription: "A page of change requests plus an opaque nextCursor (null at the end). Filter with `status` and/or `mine`."
3112
3046
  }).input(listChangeRequestsPagedInputSchema).output(listChangeRequestsResponseSchema),
3113
3047
  counts: oc.route({
@@ -3542,11 +3476,9 @@ var Busabase = class {
3542
3476
  get assets() {
3543
3477
  return this.client.assets;
3544
3478
  }
3545
- get skills() {
3546
- return this.client.skills;
3547
- }
3548
- get drives() {
3549
- return this.client.drives;
3479
+ /** Skills, Drives, and AirApps — one surface, discriminated by `type`. */
3480
+ get fileTrees() {
3481
+ return this.client.fileTrees;
3550
3482
  }
3551
3483
  get files() {
3552
3484
  return this.client.files;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "busabase-sdk",
3
- "version": "0.10.0",
3
+ "version": "0.10.2",
4
4
  "description": "Typed TypeScript/JavaScript SDK for the Busabase OpenAPI REST API. Talks to a local or remote `busabase server` (or Busabase Cloud).",
5
5
  "license": "MIT",
6
6
  "homepage": "https://github.com/busabase/busabase/tree/main/apps/busabase-sdk",
@@ -41,9 +41,9 @@
41
41
  "tsx": "^4.20.5",
42
42
  "typescript": "^5.9.3",
43
43
  "vitest": "^2.1.8",
44
- "openlib": "0.1.1",
45
- "busabase-contract": "0.10.0",
46
- "open-domains": "0.0.2"
44
+ "busabase-contract": "0.10.2",
45
+ "open-domains": "0.0.2",
46
+ "openlib": "0.1.1"
47
47
  },
48
48
  "engines": {
49
49
  "node": ">=24.18.0"