busabase-sdk 0.10.3 → 0.11.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -1
- package/dist/index.d.ts +18768 -18496
- package/dist/index.js +262 -124
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -254,6 +254,10 @@ var fieldChangeRequestInputSchema = z.discriminatedUnion("operation", [
|
|
|
254
254
|
reorderFieldsChangeRequestInputSchema.extend({ operation: z.literal("reorder"), ...withBaseId }),
|
|
255
255
|
restoreFieldChangeRequestInputSchema.extend({ operation: z.literal("restore"), ...withBaseId })
|
|
256
256
|
]);
|
|
257
|
+
var baseLifecycleChangeRequestInputSchema = z.discriminatedUnion("operation", [
|
|
258
|
+
archiveBaseInputSchema.extend({ operation: z.literal("archive"), ...withBaseId }),
|
|
259
|
+
restoreBaseInputSchema.extend({ operation: z.literal("restore"), ...withBaseId })
|
|
260
|
+
]);
|
|
257
261
|
|
|
258
262
|
// ../../packages/busabase-contract/src/domains/filetree/definition.ts
|
|
259
263
|
var fileTreeOperations = (type) => [
|
|
@@ -561,7 +565,33 @@ var listNodesInputSchema = z.object({
|
|
|
561
565
|
* soft-archived nodes for the Trash view — no `parentId`/`depth` walk, since
|
|
562
566
|
* archived nodes are shown as a list, not a tree.
|
|
563
567
|
*/
|
|
564
|
-
status: z.enum(["active", "archived"]).optional().default("active")
|
|
568
|
+
status: z.enum(["active", "archived"]).optional().default("active"),
|
|
569
|
+
/**
|
|
570
|
+
* Narrow to specific node types and return a FLAT list of lightweight node
|
|
571
|
+
* summaries (`children: []`) instead of walking the tree. This is what
|
|
572
|
+
* replaced the four retired narrow listings (`GET /docs`, `/files`,
|
|
573
|
+
* `/folders`, `/file-trees`); file-trees are selected with their real
|
|
574
|
+
* discriminators `skill` / `drive` / `airapp`, since there is no synthetic
|
|
575
|
+
* "file-tree" node type.
|
|
576
|
+
*
|
|
577
|
+
* Omitting `types` leaves every existing caller on exactly today's
|
|
578
|
+
* behaviour (full tree, or a `parentId`/`depth`-bounded walk, or the
|
|
579
|
+
* archived flat list) — the two modes never interfere.
|
|
580
|
+
*
|
|
581
|
+
* NOTE — no `projection` parameter, deliberately. The consolidation roadmap
|
|
582
|
+
* sketched `?projection=summary`, but it also rules out adding
|
|
583
|
+
* `projection=detail` in this batch (the retired detail lists were the
|
|
584
|
+
* N+1 payloads this change exists to remove). That would leave a parameter
|
|
585
|
+
* with exactly one legal value, which is noise in OpenAPI/MCP/CLI rather
|
|
586
|
+
* than a decision a caller gets to make. Detail is `GET /nodes/{nodeId}`.
|
|
587
|
+
*
|
|
588
|
+
* A GET query param that occurs exactly once (`?types=doc`) arrives as a
|
|
589
|
+
* bare string, not a 1-element array — only a REPEATED occurrence
|
|
590
|
+
* (`?types=doc&types=file`) becomes an array. Accept both and normalize.
|
|
591
|
+
*/
|
|
592
|
+
types: z.union([z.array(z.enum(NODE_TYPES)), z.enum(NODE_TYPES)]).transform((value) => Array.isArray(value) ? value : [value]).optional().describe(
|
|
593
|
+
"Return a flat list of lightweight summaries for these node types instead of the tree. Read one node's full detail with GET /nodes/{nodeId}."
|
|
594
|
+
)
|
|
565
595
|
}).optional();
|
|
566
596
|
var isDescendantInputSchema = z.object({
|
|
567
597
|
nodeId: z.string(),
|
|
@@ -729,11 +759,19 @@ var liveEventSchema = z.object({
|
|
|
729
759
|
// via the audit funnel, but nothing needs reviewing). Consumed by
|
|
730
760
|
// `use-live-sync.ts` to pop a desktop Notification, and by
|
|
731
761
|
// busabase-cloud's host hook to persist an inbox notification row.
|
|
732
|
-
"change_request.pending_review"
|
|
762
|
+
"change_request.pending_review",
|
|
763
|
+
// A node's metadata was written directly, outside the change-request flow
|
|
764
|
+
// (`PATCH /api/v1/nodes/{nodeId}/metadata` — agents, the SDK, an MCP tool,
|
|
765
|
+
// and every rich-node editor's own Save). Carries the touched node in
|
|
766
|
+
// `nodeIds` so open dashboards refetch the node tree instead of showing a
|
|
767
|
+
// stale whiteboard/workflow/HTML document until the next reload.
|
|
768
|
+
"node.metadata_updated"
|
|
733
769
|
]),
|
|
734
770
|
spaceId: z.string(),
|
|
735
771
|
actorId: z.string(),
|
|
736
|
-
|
|
772
|
+
// Null for events that aren't about a change request at all
|
|
773
|
+
// (`node.metadata_updated`), which is every direct, auto-audited write.
|
|
774
|
+
changeRequestId: z.string().nullable(),
|
|
737
775
|
baseId: z.string().nullable(),
|
|
738
776
|
nodeIds: z.array(z.string()),
|
|
739
777
|
recordIds: z.array(z.string()),
|
|
@@ -904,6 +942,19 @@ var listChangeRequestsResponseSchema = z.object({
|
|
|
904
942
|
changeRequests: z.array(changeRequestSchema),
|
|
905
943
|
nextCursor: z.string().nullable()
|
|
906
944
|
});
|
|
945
|
+
var listChangeRequestsPageInputSchema = z.object({
|
|
946
|
+
page: z.coerce.number().int().min(1).optional().default(1),
|
|
947
|
+
pageSize: z.coerce.number().int().min(1).max(100).optional().default(50),
|
|
948
|
+
status: z.array(changeRequestStatusSchema).optional(),
|
|
949
|
+
mine: z.boolean().optional()
|
|
950
|
+
}).optional().default({ page: 1, pageSize: 50 });
|
|
951
|
+
var listChangeRequestsPageResponseSchema = z.object({
|
|
952
|
+
changeRequests: z.array(changeRequestSchema),
|
|
953
|
+
total: z.number().int().nonnegative(),
|
|
954
|
+
totalPages: z.number().int().nonnegative(),
|
|
955
|
+
page: z.number().int().min(1),
|
|
956
|
+
pageSize: z.number().int().min(1).max(100)
|
|
957
|
+
});
|
|
907
958
|
var changeRequestCountsSchema = z.object({
|
|
908
959
|
review: z.number().int().nonnegative(),
|
|
909
960
|
changes: z.number().int().nonnegative(),
|
|
@@ -1082,13 +1133,6 @@ var fileTreeRefSchema = z.object({
|
|
|
1082
1133
|
type: fileTreeNodeTypeSchema.optional()
|
|
1083
1134
|
});
|
|
1084
1135
|
var fileTreeContract = {
|
|
1085
|
-
list: oc.route({
|
|
1086
|
-
method: "GET",
|
|
1087
|
-
path: "/file-trees",
|
|
1088
|
-
tags: ["File Trees"],
|
|
1089
|
-
summary: "List file-tree nodes",
|
|
1090
|
-
successDescription: "Skill, Drive, and AirApp nodes with their Asset-backed file trees. Pass `type` to narrow to one kind."
|
|
1091
|
-
}).input(z.object({ type: fileTreeNodeTypeSchema.optional() })).output(z.array(fileTreeNodeSchema)),
|
|
1092
1136
|
create: oc.route({
|
|
1093
1137
|
method: "POST",
|
|
1094
1138
|
path: "/file-trees",
|
|
@@ -1101,13 +1145,6 @@ var fileTreeContract = {
|
|
|
1101
1145
|
changeRequestSchema.extend({ materialized: z.literal(false) })
|
|
1102
1146
|
])
|
|
1103
1147
|
),
|
|
1104
|
-
get: oc.route({
|
|
1105
|
-
method: "GET",
|
|
1106
|
-
path: "/file-trees/{nodeId}",
|
|
1107
|
-
tags: ["File Trees"],
|
|
1108
|
-
summary: "Get file-tree node",
|
|
1109
|
-
successDescription: "File-tree node detail and its file list."
|
|
1110
|
-
}).input(fileTreeRefSchema).output(fileTreeNodeSchema),
|
|
1111
1148
|
listFiles: oc.route({
|
|
1112
1149
|
method: "GET",
|
|
1113
1150
|
path: "/file-trees/{nodeId}/files",
|
|
@@ -1543,6 +1580,9 @@ var viewSchema = z.object({
|
|
|
1543
1580
|
createdAt: z.string(),
|
|
1544
1581
|
updatedAt: z.string()
|
|
1545
1582
|
});
|
|
1583
|
+
var autoMergeSchema = z.boolean().optional().describe(
|
|
1584
|
+
"Whether to approve and merge this view change immediately. Omitted defaults to merging immediately if the actor has write access on the Base's node, otherwise falling back to a pending Change Request; pass explicit false to force review even with write access."
|
|
1585
|
+
);
|
|
1546
1586
|
var createViewInputSchema = z.object({
|
|
1547
1587
|
config: viewConfigSchema.optional().default({ filters: [], sorts: [] }),
|
|
1548
1588
|
description: z.string().optional().default(""),
|
|
@@ -1550,7 +1590,8 @@ var createViewInputSchema = z.object({
|
|
|
1550
1590
|
name: z.string().min(1),
|
|
1551
1591
|
type: viewTypeSchema.optional().default("table"),
|
|
1552
1592
|
slug: z.string().min(1).regex(/^[a-z0-9-]+$/).optional(),
|
|
1553
|
-
submittedBy: z.string().optional().default("local-producer")
|
|
1593
|
+
submittedBy: z.string().optional().default("local-producer"),
|
|
1594
|
+
autoMerge: autoMergeSchema
|
|
1554
1595
|
});
|
|
1555
1596
|
var updateViewInputSchema = z.object({
|
|
1556
1597
|
config: viewConfigSchema.optional(),
|
|
@@ -1558,15 +1599,18 @@ var updateViewInputSchema = z.object({
|
|
|
1558
1599
|
message: z.string().optional().default("Update view"),
|
|
1559
1600
|
name: z.string().min(1).optional(),
|
|
1560
1601
|
type: viewTypeSchema.optional(),
|
|
1561
|
-
submittedBy: z.string().optional().default("local-producer")
|
|
1602
|
+
submittedBy: z.string().optional().default("local-producer"),
|
|
1603
|
+
autoMerge: autoMergeSchema
|
|
1562
1604
|
});
|
|
1563
1605
|
var deleteViewInputSchema = z.object({
|
|
1564
1606
|
message: z.string().optional().default("Delete view"),
|
|
1565
|
-
submittedBy: z.string().optional().default("local-producer")
|
|
1607
|
+
submittedBy: z.string().optional().default("local-producer"),
|
|
1608
|
+
autoMerge: autoMergeSchema
|
|
1566
1609
|
});
|
|
1567
1610
|
var restoreViewInputSchema = z.object({
|
|
1568
1611
|
message: z.string().optional().default("Restore view"),
|
|
1569
|
-
submittedBy: z.string().optional().default("local-producer")
|
|
1612
|
+
submittedBy: z.string().optional().default("local-producer"),
|
|
1613
|
+
autoMerge: autoMergeSchema
|
|
1570
1614
|
});
|
|
1571
1615
|
var viewChangeRequestInputSchema = z.discriminatedUnion("operation", [
|
|
1572
1616
|
createViewInputSchema.extend({
|
|
@@ -1811,20 +1855,13 @@ var baseContract = {
|
|
|
1811
1855
|
summary: "Preview field type conversion",
|
|
1812
1856
|
successDescription: "Dry-run statistics for converting a field to a different type."
|
|
1813
1857
|
}).input(previewFieldConversionInputSchema.extend({ baseId: z.string() })).output(previewFieldConversionOutputSchema),
|
|
1814
|
-
|
|
1858
|
+
lifecycleChangeRequest: oc.route({
|
|
1815
1859
|
method: "POST",
|
|
1816
|
-
path: "/bases/{baseId}/
|
|
1860
|
+
path: "/bases/{baseId}/lifecycle/change-requests",
|
|
1817
1861
|
tags: ["Bases", "Change Requests"],
|
|
1818
|
-
summary: "
|
|
1819
|
-
successDescription: "Created change request that
|
|
1820
|
-
}).input(
|
|
1821
|
-
restoreChangeRequest: oc.route({
|
|
1822
|
-
method: "POST",
|
|
1823
|
-
path: "/bases/{baseId}/restore/change-requests",
|
|
1824
|
-
tags: ["Bases", "Change Requests"],
|
|
1825
|
-
summary: "Restore base",
|
|
1826
|
-
successDescription: "Created change request that restores an archived base."
|
|
1827
|
-
}).input(restoreBaseInputSchema.extend({ baseId: z.string() })).output(changeRequestSchema)
|
|
1862
|
+
summary: "Create Base lifecycle change request",
|
|
1863
|
+
successDescription: "Created change request that moves a Base between its lifecycle states. `operation` selects the direction: `archive` (soft-delete a live Base) or `restore` (bring an archived Base back)."
|
|
1864
|
+
}).input(baseLifecycleChangeRequestInputSchema).output(changeRequestSchema)
|
|
1828
1865
|
};
|
|
1829
1866
|
var recordContract = {
|
|
1830
1867
|
// One listing for records: always keyset-paginated, `baseId` always honoured,
|
|
@@ -1903,8 +1940,13 @@ var viewContract = {
|
|
|
1903
1940
|
path: "/views/change-requests",
|
|
1904
1941
|
tags: ["Views", "Change Requests"],
|
|
1905
1942
|
summary: "Create view change request",
|
|
1906
|
-
successDescription: "
|
|
1907
|
-
}).input(viewChangeRequestInputSchema).output(
|
|
1943
|
+
successDescription: "Proposes a view change. `operation` selects what to propose: `create` (addressed by `baseId`), or `update` / `delete` / `restore` (addressed by `viewId`). Review-first when the actor lacks write access or passes `autoMerge: false` \u2014 a pending ChangeRequest (`materialized: false`). Otherwise the change is approved and merged in the same call and the materialized View comes back instead (`materialized: true`)."
|
|
1944
|
+
}).input(viewChangeRequestInputSchema).output(
|
|
1945
|
+
z.union([
|
|
1946
|
+
viewSchema.extend({ materialized: z.literal(true) }),
|
|
1947
|
+
changeRequestSchema.extend({ materialized: z.literal(false) })
|
|
1948
|
+
])
|
|
1949
|
+
)
|
|
1908
1950
|
};
|
|
1909
1951
|
var ReadDocLinesInputSchema = z.object({
|
|
1910
1952
|
nodeId: z.string(),
|
|
@@ -1943,13 +1985,6 @@ var createDocChangeRequestInputSchema = z.object({
|
|
|
1943
1985
|
submittedBy: z.string().optional().default("local-producer")
|
|
1944
1986
|
});
|
|
1945
1987
|
var docContract = {
|
|
1946
|
-
list: oc.route({
|
|
1947
|
-
method: "GET",
|
|
1948
|
-
path: "/docs",
|
|
1949
|
-
tags: ["Docs"],
|
|
1950
|
-
summary: "List Doc nodes",
|
|
1951
|
-
successDescription: "Doc nodes with their storage-backed bodies."
|
|
1952
|
-
}).output(z.array(docSchema)),
|
|
1953
1988
|
create: oc.route({
|
|
1954
1989
|
method: "POST",
|
|
1955
1990
|
path: "/docs",
|
|
@@ -1962,19 +1997,12 @@ var docContract = {
|
|
|
1962
1997
|
changeRequestSchema.extend({ materialized: z.literal(false) })
|
|
1963
1998
|
])
|
|
1964
1999
|
),
|
|
1965
|
-
get: oc.route({
|
|
1966
|
-
method: "GET",
|
|
1967
|
-
path: "/docs/{nodeId}",
|
|
1968
|
-
tags: ["Docs"],
|
|
1969
|
-
summary: "Get Doc node",
|
|
1970
|
-
successDescription: "Doc node detail and body."
|
|
1971
|
-
}).input(z.object({ nodeId: z.string() })).output(docSchema),
|
|
1972
2000
|
readLines: oc.route({
|
|
1973
2001
|
method: "GET",
|
|
1974
2002
|
path: "/docs/{nodeId}/lines",
|
|
1975
2003
|
tags: ["Docs"],
|
|
1976
2004
|
summary: "Read an exact line range from a Doc body",
|
|
1977
|
-
successDescription: "Lines [startLine, endLine] (range capped at 2000 lines / ~2MB response) sliced from the Doc's full body \u2014 Docs are KB-scale, so the whole body is read in memory; no byte-range/checkpoint machinery like assets.readTextLines uses for potentially multi-GB files. The Doc-domain follow-up to a Unified Grep match with `source: \"docs\"`, so an agent can read just the lines around a match instead of `get`'s entire body."
|
|
2005
|
+
successDescription: "Lines [startLine, endLine] (range capped at 2000 lines / ~2MB response) sliced from the Doc's full body \u2014 Docs are KB-scale, so the whole body is read in memory; no byte-range/checkpoint machinery like assets.readTextLines uses for potentially multi-GB files. The Doc-domain follow-up to a Unified Grep match with `source: \"docs\"`, so an agent can read just the lines around a match instead of `nodes.get`'s entire body."
|
|
1978
2006
|
}).input(ReadDocLinesInputSchema).output(ReadLinesVOSchema),
|
|
1979
2007
|
updateBody: oc.route({
|
|
1980
2008
|
method: "PUT",
|
|
@@ -2140,13 +2168,6 @@ var createFileNodeInputSchema = z.object({
|
|
|
2140
2168
|
autoMerge: z.boolean().optional()
|
|
2141
2169
|
});
|
|
2142
2170
|
var fileContract = {
|
|
2143
|
-
list: oc.route({
|
|
2144
|
-
method: "GET",
|
|
2145
|
-
path: "/files",
|
|
2146
|
-
tags: ["Files"],
|
|
2147
|
-
summary: "List File nodes",
|
|
2148
|
-
successDescription: "Workspace File nodes with their backing Asset metadata."
|
|
2149
|
-
}).output(z.array(FileNodeVOSchema)),
|
|
2150
2171
|
create: oc.route({
|
|
2151
2172
|
method: "POST",
|
|
2152
2173
|
path: "/files",
|
|
@@ -2158,34 +2179,7 @@ var fileContract = {
|
|
|
2158
2179
|
FileNodeVOSchema.extend({ materialized: z.literal(true) }),
|
|
2159
2180
|
changeRequestSchema.extend({ materialized: z.literal(false) })
|
|
2160
2181
|
])
|
|
2161
|
-
)
|
|
2162
|
-
get: oc.route({
|
|
2163
|
-
method: "GET",
|
|
2164
|
-
path: "/files/{nodeId}",
|
|
2165
|
-
tags: ["Files"],
|
|
2166
|
-
summary: "Get File node",
|
|
2167
|
-
successDescription: "File node detail and backing Asset metadata."
|
|
2168
|
-
}).input(z.object({ nodeId: z.string() })).output(FileNodeVOSchema)
|
|
2169
|
-
};
|
|
2170
|
-
var folderSchema = z.object({
|
|
2171
|
-
node: nodeSchema,
|
|
2172
|
-
children: z.array(nodeSchema)
|
|
2173
|
-
});
|
|
2174
|
-
var folderContract = {
|
|
2175
|
-
list: oc.route({
|
|
2176
|
-
method: "GET",
|
|
2177
|
-
path: "/folders",
|
|
2178
|
-
tags: ["Folders"],
|
|
2179
|
-
summary: "List Folder nodes",
|
|
2180
|
-
successDescription: "Folder nodes with their direct children."
|
|
2181
|
-
}).output(z.array(folderSchema)),
|
|
2182
|
-
get: oc.route({
|
|
2183
|
-
method: "GET",
|
|
2184
|
-
path: "/folders/{nodeId}",
|
|
2185
|
-
tags: ["Folders"],
|
|
2186
|
-
summary: "Get Folder node",
|
|
2187
|
-
successDescription: "Folder node and its direct children."
|
|
2188
|
-
}).input(z.object({ nodeId: z.string() })).output(folderSchema)
|
|
2182
|
+
)
|
|
2189
2183
|
};
|
|
2190
2184
|
var FormFieldBindingSchema = z.object({
|
|
2191
2185
|
inputName: z.string().min(1),
|
|
@@ -2818,16 +2812,86 @@ var UnifiedGrepResultVOSchema = z.object({
|
|
|
2818
2812
|
/** True when any source truncated, or any source has `notReached > 0`. */
|
|
2819
2813
|
truncated: z.boolean()
|
|
2820
2814
|
});
|
|
2815
|
+
var folderSchema = z.object({
|
|
2816
|
+
node: nodeSchema,
|
|
2817
|
+
children: z.array(nodeSchema)
|
|
2818
|
+
});
|
|
2819
|
+
|
|
2820
|
+
// ../../packages/busabase-contract/src/contract/node-detail-schemas.ts
|
|
2821
|
+
var genericNodeDetailSchema = (type) => z.object({
|
|
2822
|
+
type: z.literal(type),
|
|
2823
|
+
node: nodeSchema
|
|
2824
|
+
});
|
|
2825
|
+
var NODE_DETAIL_VARIANTS = {
|
|
2826
|
+
folder: folderSchema.extend({ type: z.literal("folder") }),
|
|
2827
|
+
doc: docSchema.extend({ type: z.literal("doc") }),
|
|
2828
|
+
file: FileNodeVOSchema.extend({ type: z.literal("file") }),
|
|
2829
|
+
// Skills, Drives, and AirApps are one server-side shape (`fileTreeNodeSchema`)
|
|
2830
|
+
// but three real node types — there is no synthetic "file-tree" node type, so
|
|
2831
|
+
// each gets its own discriminated variant rather than a shared alias.
|
|
2832
|
+
skill: fileTreeNodeSchema.extend({ type: z.literal("skill") }),
|
|
2833
|
+
drive: fileTreeNodeSchema.extend({ type: z.literal("drive") }),
|
|
2834
|
+
airapp: fileTreeNodeSchema.extend({ type: z.literal("airapp") }),
|
|
2835
|
+
base: genericNodeDetailSchema("base"),
|
|
2836
|
+
form: genericNodeDetailSchema("form"),
|
|
2837
|
+
whiteboard: genericNodeDetailSchema("whiteboard"),
|
|
2838
|
+
workflow: genericNodeDetailSchema("workflow"),
|
|
2839
|
+
html: genericNodeDetailSchema("html")
|
|
2840
|
+
};
|
|
2841
|
+
var NodeDetailVOSchema = z.discriminatedUnion("type", [
|
|
2842
|
+
NODE_DETAIL_VARIANTS.folder,
|
|
2843
|
+
NODE_DETAIL_VARIANTS.doc,
|
|
2844
|
+
NODE_DETAIL_VARIANTS.file,
|
|
2845
|
+
NODE_DETAIL_VARIANTS.skill,
|
|
2846
|
+
NODE_DETAIL_VARIANTS.drive,
|
|
2847
|
+
NODE_DETAIL_VARIANTS.airapp,
|
|
2848
|
+
NODE_DETAIL_VARIANTS.base,
|
|
2849
|
+
NODE_DETAIL_VARIANTS.form,
|
|
2850
|
+
NODE_DETAIL_VARIANTS.whiteboard,
|
|
2851
|
+
NODE_DETAIL_VARIANTS.workflow,
|
|
2852
|
+
NODE_DETAIL_VARIANTS.html
|
|
2853
|
+
]);
|
|
2854
|
+
var getNodeInputSchema = z.object({
|
|
2855
|
+
nodeId: z.string().describe("Node id, or a slug that is unique within its type."),
|
|
2856
|
+
type: z.enum(NODE_TYPES).optional().describe(
|
|
2857
|
+
"Optional disambiguation hint, only needed when `nodeId` is a slug that exists under more than one node type."
|
|
2858
|
+
)
|
|
2859
|
+
});
|
|
2821
2860
|
|
|
2822
2861
|
// ../../packages/busabase-contract/src/contract/busabase.ts
|
|
2823
|
-
var
|
|
2862
|
+
var changeRequestBatchFailureSchema = z.object({
|
|
2863
|
+
changeRequestId: z.string(),
|
|
2864
|
+
ok: z.literal(false),
|
|
2865
|
+
error: z.string(),
|
|
2866
|
+
code: z.string().optional(),
|
|
2867
|
+
data: z.unknown().optional()
|
|
2868
|
+
});
|
|
2869
|
+
var changeRequestReviewBatchResultSchema = z.object({
|
|
2824
2870
|
results: z.array(
|
|
2825
|
-
z.
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2871
|
+
z.discriminatedUnion("ok", [
|
|
2872
|
+
z.object({
|
|
2873
|
+
changeRequestId: z.string(),
|
|
2874
|
+
ok: z.literal(true),
|
|
2875
|
+
status: z.string(),
|
|
2876
|
+
changeRequest: changeRequestSchema
|
|
2877
|
+
}),
|
|
2878
|
+
changeRequestBatchFailureSchema
|
|
2879
|
+
])
|
|
2880
|
+
)
|
|
2881
|
+
});
|
|
2882
|
+
var changeRequestMergeBatchResultSchema = z.object({
|
|
2883
|
+
results: z.array(
|
|
2884
|
+
z.discriminatedUnion("ok", [
|
|
2885
|
+
z.object({
|
|
2886
|
+
changeRequestId: z.string(),
|
|
2887
|
+
ok: z.literal(true),
|
|
2888
|
+
status: z.string(),
|
|
2889
|
+
changeRequest: changeRequestSchema,
|
|
2890
|
+
record: recordSchema.nullable(),
|
|
2891
|
+
view: viewSchema.nullable()
|
|
2892
|
+
}),
|
|
2893
|
+
changeRequestBatchFailureSchema
|
|
2894
|
+
])
|
|
2831
2895
|
)
|
|
2832
2896
|
});
|
|
2833
2897
|
var busabaseContractRoutes = {
|
|
@@ -2862,8 +2926,8 @@ var busabaseContractRoutes = {
|
|
|
2862
2926
|
method: "GET",
|
|
2863
2927
|
path: "/nodes",
|
|
2864
2928
|
tags: ["Nodes"],
|
|
2865
|
-
summary: "List
|
|
2866
|
-
successDescription: "Workspace node tree including folders, Bases, files, and agents. With no `parentId`/`depth`, returns the FULL tree (legacy behavior, still what every non-sidebar caller gets). Passing `parentId` and/or `depth` switches to a depth-bounded fetch: `parentId` omitted/null starts from the space root and returns it wrapped exactly like the legacy call (just depth-limited); an explicit `parentId` returns that node's children directly, ready to merge into its `NodeVO.children` for a sidebar's lazy per-folder expand. See `NodeVO.hasChildren` for how a depth boundary is surfaced."
|
|
2929
|
+
summary: "List nodes (workspace tree, or a flat summary list by type)",
|
|
2930
|
+
successDescription: "Workspace node tree including folders, Bases, files, and agents. With no `parentId`/`depth`, returns the FULL tree (legacy behavior, still what every non-sidebar caller gets). Passing `parentId` and/or `depth` switches to a depth-bounded fetch: `parentId` omitted/null starts from the space root and returns it wrapped exactly like the legacy call (just depth-limited); an explicit `parentId` returns that node's children directly, ready to merge into its `NodeVO.children` for a sidebar's lazy per-folder expand. See `NodeVO.hasChildren` for how a depth boundary is surfaced. Passing `types` instead returns a FLAT, ACL-filtered list of lightweight summaries (`children: []`) for just those node types \u2014 this is what replaced `GET /docs`, `/files`, `/folders`, and `/file-trees`, and it deliberately hydrates nothing heavy (no Doc bodies, backing Assets, folder children, or file inventories). Open one item with `GET /nodes/{nodeId}`."
|
|
2867
2931
|
}).input(listNodesInputSchema).output(z.array(nodeSchema)),
|
|
2868
2932
|
searchByName: oc.route({
|
|
2869
2933
|
method: "GET",
|
|
@@ -2933,6 +2997,21 @@ var busabaseContractRoutes = {
|
|
|
2933
2997
|
summary: "List the current actor's favorited nodes",
|
|
2934
2998
|
successDescription: "The acting user's favorited nodes, newest-favorited first, filtered through the same archived/deleted/visibility rules as the main tree \u2014 a favorited node that's later archived, purged, or (cloud) hidden from this actor silently drops out rather than erroring."
|
|
2935
2999
|
}).output(z.array(nodeSchema)),
|
|
3000
|
+
// Registered LAST among the `/nodes/...` GETs on purpose. `GET /nodes/search`
|
|
3001
|
+
// and `GET /nodes/favorites` are literal paths that now share a prefix with
|
|
3002
|
+
// this template. The oRPC OpenAPI matcher is a rou3 radix trie, which
|
|
3003
|
+
// prefers a static segment over a param segment independently of insertion
|
|
3004
|
+
// order — but keeping the literals declared first means the source order
|
|
3005
|
+
// matches the resolution order, so nobody has to know that to read this
|
|
3006
|
+
// file. `tests/openapi-node-routes.test.ts` proves the literals still win
|
|
3007
|
+
// against a real handler rather than resolving as `nodeId: "search"`.
|
|
3008
|
+
get: oc.route({
|
|
3009
|
+
method: "GET",
|
|
3010
|
+
path: "/nodes/{nodeId}",
|
|
3011
|
+
tags: ["Nodes"],
|
|
3012
|
+
summary: "Get one node's typed detail",
|
|
3013
|
+
successDescription: "The node's full detail, discriminated by its `type`. One entry point for every node type, so a caller holding an id never has to discover the type first: `folder` carries its direct `children`, `doc` its storage-backed `body`, `file` its backing `asset`, and `skill`/`drive`/`airapp` their Asset-backed `files`. Types with no richer detail yet (`base`, `form`, `whiteboard`, `workflow`, `html`) return just `node`. `nodeId` accepts an id or a slug; pass `type` when a slug exists under more than one type. Archived nodes are not returned (404), matching the typed gets this replaced."
|
|
3014
|
+
}).input(getNodeInputSchema).output(NodeDetailVOSchema),
|
|
2936
3015
|
principals: {
|
|
2937
3016
|
list: oc.route({
|
|
2938
3017
|
method: "GET",
|
|
@@ -3066,7 +3145,9 @@ var busabaseContractRoutes = {
|
|
|
3066
3145
|
airapps: airappRuntimeContract,
|
|
3067
3146
|
files: fileContract,
|
|
3068
3147
|
docs: docContract,
|
|
3069
|
-
folders:
|
|
3148
|
+
// No `folders` key: the Folder domain's only two operations were `GET /folders`
|
|
3149
|
+
// and `GET /folders/{nodeId}`, both now served by the unified Node surface
|
|
3150
|
+
// (`nodes.list({ types: ["folder"] })` / `nodes.get`).
|
|
3070
3151
|
forms: formContract,
|
|
3071
3152
|
assets: assetsContract,
|
|
3072
3153
|
vault: vaultContract,
|
|
@@ -3083,6 +3164,16 @@ var busabaseContractRoutes = {
|
|
|
3083
3164
|
summary: "List change requests",
|
|
3084
3165
|
successDescription: "A page of change requests plus an opaque nextCursor (null at the end). Filter with `status` and/or `mine`."
|
|
3085
3166
|
}).input(listChangeRequestsPagedInputSchema).output(listChangeRequestsResponseSchema),
|
|
3167
|
+
// Numbered paging alongside the cursor listing, mirroring records.listPage.
|
|
3168
|
+
// Keyset is right for "keep scrolling"; a reviewer working a 2,000-item tab
|
|
3169
|
+
// needs to jump to page 30 and to see how many pages there are at all.
|
|
3170
|
+
listPage: oc.route({
|
|
3171
|
+
method: "GET",
|
|
3172
|
+
path: "/change-requests/page",
|
|
3173
|
+
tags: ["Change Requests"],
|
|
3174
|
+
summary: "List a numbered change request page",
|
|
3175
|
+
successDescription: "A random-access page of change requests plus the total across the whole filter. Same `status` / `mine` filters as the cursor listing."
|
|
3176
|
+
}).input(listChangeRequestsPageInputSchema).output(listChangeRequestsPageResponseSchema),
|
|
3086
3177
|
counts: oc.route({
|
|
3087
3178
|
method: "GET",
|
|
3088
3179
|
path: "/change-requests/counts",
|
|
@@ -3098,23 +3189,16 @@ var busabaseContractRoutes = {
|
|
|
3098
3189
|
successDescription: "Change Request detail."
|
|
3099
3190
|
}).input(z.object({ changeRequestId: z.string() })).output(changeRequestSchema),
|
|
3100
3191
|
review: oc.route({
|
|
3101
|
-
method: "POST",
|
|
3102
|
-
path: "/change-requests/{changeRequestId}/reviews",
|
|
3103
|
-
tags: ["Change Requests"],
|
|
3104
|
-
summary: "Review change request",
|
|
3105
|
-
successDescription: "Reviewed change request."
|
|
3106
|
-
}).input(reviewChangeRequestInputSchema.extend({ changeRequestId: z.string() })).output(changeRequestSchema),
|
|
3107
|
-
reviewMany: oc.route({
|
|
3108
3192
|
method: "POST",
|
|
3109
3193
|
path: "/change-requests/reviews",
|
|
3110
3194
|
tags: ["Change Requests"],
|
|
3111
|
-
summary: "Review
|
|
3195
|
+
summary: "Review change requests",
|
|
3112
3196
|
successDescription: "Per-change-request review results (failures isolated \u2014 one bad id does not abort the rest)."
|
|
3113
3197
|
}).input(
|
|
3114
3198
|
reviewChangeRequestInputSchema.extend({
|
|
3115
3199
|
changeRequestIds: z.array(z.string()).min(1).max(100)
|
|
3116
3200
|
})
|
|
3117
|
-
).output(
|
|
3201
|
+
).output(changeRequestReviewBatchResultSchema),
|
|
3118
3202
|
close: oc.route({
|
|
3119
3203
|
method: "POST",
|
|
3120
3204
|
path: "/change-requests/{changeRequestId}/close",
|
|
@@ -3123,25 +3207,12 @@ var busabaseContractRoutes = {
|
|
|
3123
3207
|
successDescription: "Closed change request (terminal \u2014 distinct from request changes)."
|
|
3124
3208
|
}).input(z.object({ changeRequestId: z.string(), reason: z.string().optional() })).output(changeRequestSchema),
|
|
3125
3209
|
merge: oc.route({
|
|
3126
|
-
method: "POST",
|
|
3127
|
-
path: "/change-requests/{changeRequestId}/merge",
|
|
3128
|
-
tags: ["Change Requests"],
|
|
3129
|
-
summary: "Merge change request into Base",
|
|
3130
|
-
successDescription: "Merged change request and canonical record."
|
|
3131
|
-
}).input(z.object({ changeRequestId: z.string() })).output(
|
|
3132
|
-
z.object({
|
|
3133
|
-
changeRequest: changeRequestSchema,
|
|
3134
|
-
record: recordSchema.nullable(),
|
|
3135
|
-
view: viewSchema.nullable()
|
|
3136
|
-
})
|
|
3137
|
-
),
|
|
3138
|
-
mergeMany: oc.route({
|
|
3139
3210
|
method: "POST",
|
|
3140
3211
|
path: "/change-requests/merge",
|
|
3141
3212
|
tags: ["Change Requests"],
|
|
3142
|
-
summary: "Merge
|
|
3213
|
+
summary: "Merge change requests",
|
|
3143
3214
|
successDescription: "Per-change-request merge results (each merged in its own transaction; failures isolated)."
|
|
3144
|
-
}).input(z.object({ changeRequestIds: z.array(z.string()).min(1).max(100) })).output(
|
|
3215
|
+
}).input(z.object({ changeRequestIds: z.array(z.string()).min(1).max(100) })).output(changeRequestMergeBatchResultSchema)
|
|
3145
3216
|
},
|
|
3146
3217
|
operations: {
|
|
3147
3218
|
revise: oc.route({
|
|
@@ -3482,6 +3553,10 @@ var getRecordByField = async (client, input) => {
|
|
|
3482
3553
|
};
|
|
3483
3554
|
|
|
3484
3555
|
// src/index.ts
|
|
3556
|
+
var batchItemError = (result) => Object.assign(new Error(result?.error ?? "Change request action returned no result"), {
|
|
3557
|
+
...result?.code ? { code: result.code } : {},
|
|
3558
|
+
...result?.data === void 0 ? {} : { data: result.data }
|
|
3559
|
+
});
|
|
3485
3560
|
var Busabase = class {
|
|
3486
3561
|
/** The underlying fully-typed oRPC client. Use it for anything not surfaced here. */
|
|
3487
3562
|
client;
|
|
@@ -3509,11 +3584,55 @@ var Busabase = class {
|
|
|
3509
3584
|
return this.client.views;
|
|
3510
3585
|
}
|
|
3511
3586
|
get changeRequests() {
|
|
3512
|
-
|
|
3587
|
+
const review = async (input) => {
|
|
3588
|
+
if ("changeRequestIds" in input) return this.client.changeRequests.review(input);
|
|
3589
|
+
const { changeRequestId, ...reviewInput } = input;
|
|
3590
|
+
const { results } = await this.client.changeRequests.review({
|
|
3591
|
+
...reviewInput,
|
|
3592
|
+
changeRequestIds: [changeRequestId]
|
|
3593
|
+
});
|
|
3594
|
+
const result = results[0];
|
|
3595
|
+
if (!result?.ok) throw batchItemError(result);
|
|
3596
|
+
return result.changeRequest;
|
|
3597
|
+
};
|
|
3598
|
+
const merge = async (input) => {
|
|
3599
|
+
if ("changeRequestIds" in input) return this.client.changeRequests.merge(input);
|
|
3600
|
+
const { results } = await this.client.changeRequests.merge({
|
|
3601
|
+
changeRequestIds: [input.changeRequestId]
|
|
3602
|
+
});
|
|
3603
|
+
const result = results[0];
|
|
3604
|
+
if (!result?.ok) throw batchItemError(result);
|
|
3605
|
+
return {
|
|
3606
|
+
changeRequest: result.changeRequest,
|
|
3607
|
+
record: result.record,
|
|
3608
|
+
view: result.view
|
|
3609
|
+
};
|
|
3610
|
+
};
|
|
3611
|
+
return new Proxy(this.client.changeRequests, {
|
|
3612
|
+
get(target, property, receiver) {
|
|
3613
|
+
if (property === "review") return review;
|
|
3614
|
+
if (property === "merge") return merge;
|
|
3615
|
+
return Reflect.get(target, property, receiver);
|
|
3616
|
+
}
|
|
3617
|
+
});
|
|
3513
3618
|
}
|
|
3514
3619
|
get operations() {
|
|
3515
3620
|
return this.client.operations;
|
|
3516
3621
|
}
|
|
3622
|
+
/**
|
|
3623
|
+
* The workspace node surface, and the single entry point for reading ONE node
|
|
3624
|
+
* of any type: `bb.nodes.get({ nodeId })` returns a `NodeDetailVO`
|
|
3625
|
+
* discriminated by `type` (`folder` carries `children`, `doc` a `body`, `file`
|
|
3626
|
+
* its `asset`, `skill`/`drive`/`airapp` their `files`). It replaced the four
|
|
3627
|
+
* typed gets (`docs`/`files`/`folders`/`fileTrees`), so a caller holding an id
|
|
3628
|
+
* no longer has to know the node's type before it can read it.
|
|
3629
|
+
*
|
|
3630
|
+
* `bb.nodes.list({ types })` is the matching list: a flat array of lightweight
|
|
3631
|
+
* summaries for just those types. Without `types` it still returns the full
|
|
3632
|
+
* workspace tree.
|
|
3633
|
+
*
|
|
3634
|
+
* There is no `bb.folders` any more — folders are `type: "folder"` here.
|
|
3635
|
+
*/
|
|
3517
3636
|
get nodes() {
|
|
3518
3637
|
return this.client.nodes;
|
|
3519
3638
|
}
|
|
@@ -3535,19 +3654,38 @@ var Busabase = class {
|
|
|
3535
3654
|
}
|
|
3536
3655
|
});
|
|
3537
3656
|
}
|
|
3538
|
-
/**
|
|
3657
|
+
/**
|
|
3658
|
+
* Skills, Drives, and AirApps — one surface, discriminated by `type`.
|
|
3659
|
+
*
|
|
3660
|
+
* Creation and per-file reads/writes live here. Listing them and reading one
|
|
3661
|
+
* node's detail moved to the unified Node surface:
|
|
3662
|
+
* `bb.nodes.list({ types: ["skill", "drive", "airapp"] })` and
|
|
3663
|
+
* `bb.nodes.get({ nodeId, type })`.
|
|
3664
|
+
*/
|
|
3539
3665
|
get fileTrees() {
|
|
3540
3666
|
return this.client.fileTrees;
|
|
3541
3667
|
}
|
|
3668
|
+
/**
|
|
3669
|
+
* File nodes. `create` only — list with `bb.nodes.list({ types: ["file"] })`
|
|
3670
|
+
* and read one (backing Asset included) with `bb.nodes.get({ nodeId })`.
|
|
3671
|
+
*/
|
|
3542
3672
|
get files() {
|
|
3543
3673
|
return this.client.files;
|
|
3544
3674
|
}
|
|
3675
|
+
/**
|
|
3676
|
+
* Docs. Create / read a line range / update the body / open a Change Request.
|
|
3677
|
+
* List with `bb.nodes.list({ types: ["doc"] })` and read one (body included)
|
|
3678
|
+
* with `bb.nodes.get({ nodeId })`.
|
|
3679
|
+
*
|
|
3680
|
+
* There is deliberately no `bb.docs.list()` shim. The retired `GET /docs`
|
|
3681
|
+
* returned every Doc *with its body*; the one-call replacement returns
|
|
3682
|
+
* lightweight summaries, and the only way to keep the old shape would be a
|
|
3683
|
+
* detail request per Doc. An SDK convenience that quietly turns one call into
|
|
3684
|
+
* N is worse than a compile error that points at `bb.nodes`.
|
|
3685
|
+
*/
|
|
3545
3686
|
get docs() {
|
|
3546
3687
|
return this.client.docs;
|
|
3547
3688
|
}
|
|
3548
|
-
get folders() {
|
|
3549
|
-
return this.client.folders;
|
|
3550
|
-
}
|
|
3551
3689
|
get agentTasks() {
|
|
3552
3690
|
return this.client.agentTasks;
|
|
3553
3691
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "busabase-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.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",
|
|
@@ -49,9 +49,9 @@
|
|
|
49
49
|
"tsx": "^4.20.5",
|
|
50
50
|
"typescript": "^5.9.3",
|
|
51
51
|
"vitest": "^2.1.8",
|
|
52
|
-
"busabase-contract": "0.10.3",
|
|
53
52
|
"open-domains": "0.0.2",
|
|
54
|
-
"openlib": "0.1.1"
|
|
53
|
+
"openlib": "0.1.1",
|
|
54
|
+
"busabase-contract": "0.11.2"
|
|
55
55
|
},
|
|
56
56
|
"engines": {
|
|
57
57
|
"node": ">=24.18.0"
|